Offloading the Segmentation of Large TCP Packets (NDIS 5.1)
Note NDIS 5. x has been deprecated and is superseded by NDIS 6. x. For new NDIS driver development, see Network Drivers Starting with Windows Vista. For information about porting NDIS 5. x drivers to NDIS 6. x, see Porting NDIS 5.x Drivers to NDIS 6.0.
A NIC that supports the segmentation of large TCP packets (TCP packets that are larger than the maximum transmission unit of the network medium), must also be able to:
Calculate IP checksums for send packets that contain IP options.
Calculate TCP checksums for send packets that contain TCP options.
The TCP/IP transport offloads only those large TCP packets that meet the following criteria:
The packet is a TCP packet. The TCP/IP transport does not offload large UDP packets for segmentation.
The packet must be divisible by at least the minimum number of segments specified by the miniport driver. For more information, see Reporting a NIC's TCP-Packet-Segmentation Capabilities.
The packet is not a loopback packet.
The packet will not be sent through a tunnel.
The packet will not be sent to a load-balancing miniport driver. For more information about load balancing, see Load Balancing and Failover.
Before offloading a large TCP packet for segmentation, the TCP/IP transport:
Updates the large-packet segmentation information that is associated with the packet descriptor. This information is a ULONG value that is part of the per-packet information that is associated with the packet descriptor. For more information about per-packet information, see NDIS_PACKET_EXTENSION. The TCP/IP transport sets this ULONG value to the maximum segment size (MSS), which is equivalent to the current maximum transmission unit (MTU). The MTU is the maximum number of user data bytes that the miniport driver can currently include in a single packet.
Writes the total length of the large TCP packet to the Total Length field of the packet's IP header. The total length includes the length of the IP header, the length of the IP options if they are present, the length of the TCP header, the length of the TCP options if they are present, and the length of the TCP payload.
Calculates a one's complement sum for the TCP pseudoheader and writes this sum to the Checksum field of the TCP header. The TCP/IP transport calculates the one's complement sum over the following fields in the pseudoheader: Source IP Address, Destination IP Address, and Protocol. 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 each packet that the NIC derives from the large TCP packet without having to examine the IP header.
Note RFC 793 stipulates that the pseudo-header checksum is calculated over the Source IP Address, Destination IP Address, Protocol, and TCP Length. (The TCP Length is the length of the TCP header plus the length of the TCP payload. The TCP Length does not include the length of the pseudo-header.)
However, because the underlying miniport driver and NIC generate TCP segments from the large packet that the TCP/IP transport passes down, the transport does not know the size of the TCP payload for each TCP segment and therefore cannot include the TCP Length in the pseudo-header. Instead, as described below, the NIC extends the pseudo-header checksum that was supplied by the TCP/IP transport to cover the TCP Length of each generated TCP segment.
Writes the correct sequence number to the Sequence Number field of the TCP header. The sequence number identifies the first byte of the TCP payload.
After the miniport driver obtains the packet descriptor in its MiniportSend, MiniportSendPackets, or MiniportCoSendPacketsfunction, it can call the NDIS_PER_PACKET_INFO_FROM_PACKETmacro with an InfoTypeof TcpLargeSendPacketInfoto obtain the MSS value written by the TCP/IP transport. Alternatively, the miniport driver can call the NDIS_PACKET_EXTENSION_FROM_PACKETmacro to obtain a pointer to the NDIS_PACKET_EXTENSION structure. The miniport driver can then use the TcpLargeSendPacketInfoarray index to obtain the MSS value.
The miniport driver obtains the total length of the large packet from the packet's IP header and uses the MSS value to divide the large TCP packet into smaller packets. Each of the smaller packets contains MSS or less user data bytes. Note that only the last packet that was created from the segmented large packet should contain less than MSS user data bytes. All other packets that were created from the segmented packet should contain MSS user data bytes. If you do not follow this rule, the creation and transmission of unnecessary extra packets could degrade performance.
The miniport driver affixes MAC, IP, and TCP headers to each segment that is derived from the large packet. The miniport driver must calculate the IP and TCP checksums for these derived packets. To calculate the TCP checksum for each packet that was derived from the large TCP packet, the NIC calculates the variable part of the TCP checksum (for the TCP header and TCP payload), adds this checksum to the one's complement sum for the pseudoheader calculated by the TCP/IP transport, and then calculates the 16-bit one's complement for the checksum. For more information about calculating such checksums, see RFC 793 and RFC 1122.
The following figure shows the segmentation of a large packet.
The length of the TCP user data in the large TCP packet should be equal to or less than the value that the miniport driver assigns to the MaxOffLoadSize. For more information, see Reporting a NIC's TCP-Packet-Segmentation Capabilities.
The length of the TCP user data in a segment packet must be less than or equal to the MSS. The MSS is the ULONG value that the TCP transport passes down by using the per-packet information that is associated with the large TCP packet descriptor. Note that only the last packet that was created from the segmented large packet should contain less than MSS user data bytes. All other packets that were created from the segmented packet should contain MSS user data bytes. If you do not follow this rule, the creation and transmission of unnecessary extra packets could degrade performance.
The number of segment packets that were derived from the large TCP packet must be equal to or greater than the MinSegmentCountspecified by the miniport driver. For more information, see Reporting a NIC's TCP-Packet-Segmentation Capabilities.
The following assumptions and restrictions apply to processing IP and TCP headers:
The MF bit in the IP header of the large TCP packet that the TCP/IP transport offloaded will not be set, and the Fragment Offset in the IP header will be zero.
The URG, RST, and SYN flags in the TCP header of the large TCP packet will not be set, and the urgent offset (pointer) in the TCP header will be zero.
If the FIN bit in the TCP header of the large packet is set, the miniport driver must set this bit in the TCP header of the last packet that it creates from the large TCP packet.
If the PSH bit in the TCP header of the large TCP packet is set, the miniport driver must set this bit in the TCP header of the last packet that it creates from the large TCP packet.
If the large TCP packet contains IP options and/or TCP options, the miniport driver copies these options, unaltered, to each packet that it derived from the large TCP packet. Specifically, the NIC will not increment the Time Stamp option.
The miniport driver must send packets in the order that it receives them from the TCP/IP transport. However, the miniport driver can interleave packets that were created from a large TCP packet with other packets.
The miniport driver must also preserve the order of the ACKs that it receives in response to the transmission of packets that were derived from the large TCP packet. The miniport driver must indicate up packets that contain such ACKs in the order that it receives them so that the fast retransmit algorithms, fast recovery algorithms, and selective ACK algorithms performed by the TCP/IP transport work correctly.
When processing a large TCP packet, the miniport driver is responsible only for segmenting the packet and affixing MAC, IP, and TCP headers to the packets that are derived from the large TCP packet. The TCP/IP transport performs all other tasks (such as adjusting the send window size based on the remote host's receive window size).
Before completing the send operation for the large packet (such as with NdisMSendCompleteor NdisMCoSendComplete), the miniport driver writes the ULONG value (the per-packet information for large-TCP-packet offloads) with the total number of TCP user data bytes sent successfully in all packets that were created from the large TCP packet.