How to handle TCP checksum, if adapter support TCP checksum offloading?

Discussion in 'Windows Vista Drivers' started by Rajesh Gupta, Aug 3, 2004.

  1. Rajesh Gupta

    Rajesh Gupta Guest

    Hi Everyone,
    I am writting a IM driver, where i am modifing the Source Ip and Destonation
    IP in the outgoing packets.

    I am not sure what to do with the TCP checksum, if adapter supports TCP
    checksum offloading.

    I have tested my driver with adapter, which does not support TCP checksum
    offloading. It works fine. My checksum calculations are fine. When i am
    testing my IM driver on adapter which supports TCP checksum offloading, its
    not working.

    I am not sure, ho to handle TCp checksum offloading in IM driver. Here are
    the strange things i have noticed.

    1. If i do not change anything, then it does not work. Understood.

    2. If i calculate the TCP checksum (using TCp psuedo header and TCP segment)
    and insert this checksum in the TCP header. It works for the first TCp
    packet. For rest of the packets, its incorrect. I have written simple server
    and client socket application. So this checksum works for first packet i.e.
    SYN packet. Thats strange to me, why it worked for SYN and after that its
    incorrect for all other packets.

    NOTE: I am checking my packets on another machine. So i am seeing the
    correct data send on wire using etherreal.

    3. I read somewhere, that sometimes TCP calculate the checksum of
    psudoheader and fill this in the TCP header. So hardware only calculate the
    TCP segment checksum and does not have to touch the IP header. I tried that.
    Nothing works after that.

    I am not sure, why SYN worked and how should i handle this in my IM driver?

    Thanks a lot in advance.

    Rajesh Gupta, Aug 3, 2004
    1. Advertisements

  2. Stephan Wolf [MVP], Aug 3, 2004
    1. Advertisements

  3. I think that the OP is really interested in how to systematically account
    for NDIS checksum task offload when sending modified packets of his own. He
    has the situation where there is no NDIS checksum offload under control. Now
    how to deal with the presence (or absence) fo this feature.

    1.) Microsoft makes this recommendation in the MPQueryInformation handler of
    the PassThru sample:

    "NOTE on OID_TCP_TASK_OFFLOAD - if this IM driver modifies the contents of
    data it passes through such that a lower miniport may not be able to perform
    TCP task offload, then it should not forward this OID down, but fail it here
    with the status NDIS_STATUS_NOT_SUPPORTED. This is to avoid performing
    incorrect transformations on data."

    2.) Here is another approach that may work:

    I believe that it will work, but I have only tested it partially and those
    tests were not recent.

    Allocate a separate NDIS packet pool for your modified packets. Allocate by
    calling NdisAllocatePacketPool. After allocating the pool, but before you
    actually allocate any packets from the pool, call NdisSetPacketPoolId with
    NDIS_PROTOCOL_ID_DEFAULT, defined in ntddndis.h. (This is probably the
    default, but do it anyway to be safe...).

    When you are sending your modified packets, use this pool instead of the
    existing send pool that you use for re-wrapping passthru packets.

    Do not copy OOB data, etc, into your modified packets.

    In completion routines you can identify packets that came from this special
    pool using NdisGetPoolFromPacket (XP and later only..) or some other scheme
    on W2K. (Why in the world does Microsoft add features that are not back
    fitted into other current OS's like W2K. It really makes them useless since
    you can't count on them being present...).

    In any case, in completion routines always return the packet to the pool it
    was allocated from.

    When you build your modified packet build the checksums correctly yourself
    for all modified packets. Don't care whether there is NDIS Task Offload or

    Send the packet...

    In the adapter miniport what actually happens if NDIS Task Offload is
    enabled is that the miniport will check the NDIS packet flags using
    then it will do the checksum in its hardware.

    HOWEVER, your modified packets are allocated from the pool with
    NDIS_PROTOCOL_ID_DEFAULT. For this protocol id the adapter will NOT do any

    Hope this makes sense. Please let me know if this works as I think it does.

    Thomas F. Divine, Windows DDK MVP,

    Thomas F. Divine [DDK MVP], Aug 4, 2004
  4. Rajesh Gupta

    Stephan Wolf Guest

    IIRC, for Checksum Task Offload (CTO), the TCP/IP stack calculates the
    TCP pseudo header checksum and places this value in the TCP packet's
    checksum field. Hardware can then calculate the checksum over TCP
    header + data (that is, *including* the already calculated pesudo
    header csum) and place the result in (i.e. overwrite) the TCP header.

    Now if an IM makes changes to the TCP header or data, the IM must not
    do anything and CTO will take care of calculating the csum (in

    Otherwise, if the underlying miniport does not support CTO, the IM
    must adjust the TCP header checksum accordingly.

    If, however, the IM makes changes to any fields in the IP header and
    these fields also appear in the pesudo header, then the IM must
    *always* adjust the TCP header checksum accordingly.

    That should work.

    [Note: An IM must not modify any packet data directly but can only
    modify such data in a (local) copy (local NDIS_BUFFER that points to
    local copy of original data)].

    See also RFC 1624 "Computation of the Internet Checksum via
    Incremental Update":

    Stephan Wolf, Aug 4, 2004
  5. Rajesh Gupta

    Rajesh Gupta Guest

    Hi Stephan,

    Thanks a lot for your reply. There is really strange thing i noticed while i
    was debugging my IM driver.

    As you mentioned, the TCP/IP stack calculates the TCP pseudo header checksum
    and places this value in the TCP packet's
    checksum field. I understood it. But this is what i observed while

    Testing Scenario:

    I have server running on
    I have another machine with IP
    I have one more machine just to check the network packets.
    I am trying to run the client on My client connects to the
    server There is no physical machine with address.
    So my IM driver modify the NDIS packet, so i can forward all the packets
    from to

    Everything is working fine without TCP checksum offloading. I have tested
    it. i.e. my checksum calculations are correct.

    Observation with TCP checksum offloading on:

    When i run my client on, the very first packet (which is SYN,
    seq=0 ack =0) has the full TCP checksum (i.e. checksum of IP pseudo header +
    TCP header + TCP segment).
    So when i calculate the full checksum and update the NDIS packet with TCP
    checksum, first packet is fine. I get the response from the server.

    After first packet, rest of the packets does not have the full TCP checksum.
    It has only the sum of TCP pseudo header (Not even the one's compliment.).
    As per the documentation from Microsoft, TCP/IP stack calculate the checksum
    of the pseudo header and fills in the TCP packet checksum field. But what i
    have seen while debugging, its only the SUM of pseudo header, not the one's
    compliment of the pseudo header sum, which i was expecting.

    So i am not sure, what i am missing here. Why only the first packet has full
    checksum and every packet after that has only the SUm of pseudo header?

    May be misunderstood something or i need to take care of something else.

    Thanks in advance.

    Rajesh Gupta, Aug 4, 2004
  6. Rajesh Gupta

    Stephan Wolf Guest

    Note that while general CTO support is propagated via OIDs, CTO can
    still ne enabled or disabled on a per-packet basis. That is, The
    TCP/IP stack may choose to not use CTO but instead calculate the
    complete checksum itself.

    Your IM should inspect the 'NdisPacketTcpChecksum' flag in the
    description of CTO is here:

    Stephan Wolf, Aug 5, 2004
  7. Rajesh Gupta

    Rajesh Gupta Guest

    According to DDK

    "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."

    Is this correct? What i understood from this statement is.

    Calculate the 16 bit sum of TCP Psuedo Header.

    Then calculate the one's compliment of the sum.

    For example.


    ULONG sum=0;

    PUSHORT pbuf;

    while(len > 1){

    sum += *pbuf++;

    len -= sizeof(USHORT);



    sum += *(UCHAR*)pbuf;


    after adding the 16 bit sum. To calculate the one's compliment of Psuedo
    header sum i am doing the following.

    sum = (sum >> 16) + (sum & 0xffff);

    sum += (sum >> 16);

    sum = ~sum;

    Thats what i understood from the above statement.

    But what i have observed while debugging my IM driver.

    TCP checksum field is only the 16 bit sum of the TCp psuedo header. When i
    am doing so, my IM driver is working fine. If i add above 3 lines to do the
    one's compliment of the sum (Which is correct according to Microsoft
    statement), then My IM driver does not work.

    Am i missing something here? I am not sure, if i understood the above
    statement incorrect?


    Rajesh Gupta, Aug 6, 2004
  8. Rajesh Gupta

    Stephan Wolf Guest

    1. Calculation of Internet checksums (IP/UDP/TCP etc.), i.e. the
    calculation of "the one's complement sum", has been discussed
    intensively in many forums. It is also clearly specified in the
    respective RFCs along with examples.

    It is important to understand the csum calculation algorithm. I have
    seen CTO implementations in hardware that caused wrong checksums due
    to not taking correct care of the carry bit.

    2. The TCP/IP stack usually makes use of CTO (if available), but
    sometimes it does not. Thus, any miniport/IM must inspect the CTO
    flags for each packet individually.

    If CTO flags of a packet say that CTO is being used for TCP, software
    needs to provide the pseudo header checksum and hardware will add the
    TCP payload checksum.

    If CTO is not used for a packet, software must provide the complete

    3. You can try and *always* clear the CTO flags in send packets. Then
    calculate the complete checksum (pseudo header + payload) and store in
    the packet.

    I guess you see the first packet succeeding because it does not use
    CTO (i.e. respective CTO flags are clear). But following packets do
    use CTO and you incorrectly update their checksum.

    Stephan Wolf, Aug 6, 2004
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.