Offloading Checksum Tasks
NDIS supports offloading TCP/IP checksum tasks at run time.
Note
Checksum offload out-of-band (OOB) data is stored in the NET_BUFFER_LIST information array. For more information about OOB data, see Accessing TCP/IP Offload NET_BUFFER_LIST Information.
Before passing to the miniport driver a NET_BUFFER_LIST structure for a packet on which the miniport driver will perform checksum tasks, the TCP/IP transport specifies the checksum information that is associated with the NET_BUFFER_LIST structure. This information is specified by an NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure, which is part of the NET_BUFFER_LIST information (out-of-band data) that is associated with the NET_BUFFER_LIST structure.
Before offloading the checksum calculation for a TCP packet, the TCP/IP transport calculates the one's complement sum for the TCP pseudoheader. The TCP/IP transport calculates the one's complement sum across all fields in the pseudoheader, including Source IP Address, Destination IP Address, Protocol, and the TCP length for TCP packets. The TCP/IP transport enters the one's complement sum for the pseudoheader in the Checksum field of the TCP header.
The one's complement sum for the pseudoheader provided by the TCP/IP transport gives the NIC an early start in calculating the real TCP checksum for the send packet. To calculate the actual TCP checksum, the NIC calculates the variable part of the TCP checksum (for the TCP header and payload), adds this checksum to the one's complement sum for the pseudoheader calculated by the TCP/IP transport, and calculates the 16-bit one's complement for the checksum. For more information about calculating such checksums, see RFC 793 and RFC 1122.
Note
The TCP/IP transport computes the one's complement sum for the pseudoheader of a UDP packet using the same steps as it does for a TCP packet, and stores the value in the Checksum field of the UDP header.
Note that the TCP/IP transport always ensures that the checksum field in the IP header of a packet is set to zero before passing the packet to an underlying miniport driver. The miniport driver should ignore the checksum field in an IP header. The miniport driver does not need to verify that the checksum field is set to zero and does not need to set this field to zero.
After it receives the NET_BUFFER_LIST structure in its MiniportSendNetBufferLists or MiniportCoSendNetBufferLists function, a miniport driver typically does the following checksum processing:
The miniport driver calls the NET_BUFFER_LIST_INFO macro with an _Id of TcpIpChecksumNetBufferListInfo to obtain an NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure.
The miniport driver tests the IsIPv4 and IsIPv6 flags in the NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure. If both the IsIPv4 and IsIPv6 flags are not set, the NIC should not perform any checksum operations on the packet.
If the IsIPv4 or IsIPv6 flag is set, the miniport driver tests the TcpChecksum, UdpChecksum, and IpHeaderChecksum flags to determine which checksums the NIC should calculate for the packet.
The miniport driver passes the packet to the NIC, which calculates the appropriate checksums for the packet. If a packet has both a tunnel IP header and a transport IP header, a NIC that supports IP checksum offloads performs IP checksum tasks only on the tunnel header. The TCP/IP transport performs IP checksum tasks on the transport IP header.
Before indicating a NET_BUFFER_LIST structure for a receive packet on which it performs checksum tasks, the miniport driver validates the appropriate checksums and sets the appropriate XxxChecksumFailed or XxxChecksumSucceeded flags in the NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO structure.
Turning off Address Checksum Offloads when Large Send Offload (LSO) is enabled does not prevent the miniport driver from computing and inserting checksums in the packets generated by the LSO feature. To disable Address Checksum Offloads in this case the user must also disable LSO.