Search code examples
windowskerneldevice-driverndiswindows-kernel

NdisChainBufferAtBack substitution in NDIS 6


I am building a filter driver in NDIS 6. I want to add some data at the back of my NET_BUFFER. To add data I have allocated an MDL through the NdisAllocateMdl API. Now I want to know, is there any wrapper to add this MDL to the existing MDL chain?

If not, is it correct to make the last MDL's Next pointer to point to my new allocated MDL, as I was able to do so? Also what are the fields in NET_BUFFER I have to change to make it recognize the added MDL?


Solution

  • The actual packet payload of an NET_BUFFER is a subset of the payload of the entire MDL chain. The packet might not start at the beginning of the MDL chain, and the packet might not end at the end of the MDL chain.

    Therefore, in the most general case, you'll actually need to remove some MDLs from the end of the NET_BUFFER, before you append your new MDL. Let me give a specific example:

    NET_BUFFER
        * DataOffset=300 bytes
        * DataLength=200 bytes
        * MdlChain=[200 bytes]->[200 bytes]->[300 bytes]->[200 bytes]
    

    So in this example, the NET_BUFFER points to an MDL chain with 4 MDLs in it. Let's look at the buffers in ASCII-art:

        0     100    200    300    400    500    600    700    800    900
        |      |      |      |      |      |      |      |      |      |
    
        [  First MDL ][ Second MDL ][    Third MDL      ][ Fourth MDL ]
    
    
        ↑             ↑      [   Packet   ]                           ↑
        |             |                                               |
        |             |      ↑            ↑                           |
        |             |      |            |                           |
    MdlChain          |  DataOffset   DataLength             End-of-MDL-chain
                      |
                  CurrentMdl
    

    As hopefully the diagram illustrates, the actual packet payload is only spread across the second & third MDLs. Both the first & fourth MDLs are completely ignored. So if you want to append data to the packet, you need to:

    1. Remove all MDLs from the end of the MDL chain, where the last byte of the MDL's buffer isn't part of the logical packet buffer. (In the example above, remove both the third & fourth MDLs).
    2. Allocate a new buffer that's big enough to hold your data, plus any actual packet payload you deleted from step #1 above. (In the example, you'd have to allocate an extra 100 bytes, to hold the first 100 bytes from the third MDL.)
    3. Chain your new MDL to the end of the chain.
    4. Increment NET_BUFFER::DataLength.
    5. Give the packet to NDIS.

    Here's a diagram of what the packet will look like after finishing step 3:

        0     100    200    300    400    500    600    700    800    900
        |      |      |      |      |      |      |      |      |      |
    
        [  First MDL ][ Second MDL ][  Your MDL  ]
    
    
        ↑             ↑      [   Packet   ]      ↑
        |             |                          |
        |             |      ↑            ↑      |
        |             |      |            |      |
    MdlChain          |  DataOffset   DataLength |
                      |                          |
                  CurrentMdl               End-of-MDL-chain
    

    Then after step #4:

        0     100    200    300    400    500    600    700    800    900
        |      |      |      |      |      |      |      |      |      |
    
        [  First MDL ][ Second MDL ][  Your MDL  ]
    
    
        ↑             ↑      [   Packet          ]
        |             |
        |             |      ↑                   ↑
        |             |      |                   |
    MdlChain          |  DataOffset          DataLength             
                      |                          |
                  CurrentMdl               End-of-MDL-chain
    

    When the packet is completed back to your driver, you need to undo the modifications you made earlier:

    1. Decrement DataLength.
    2. Remove the MDL you added.
    3. Free the MDL you added.
    4. Restore the original MDLs you removed.