Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV
Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


NET_BUFFER_List Re-package in LWF

Rami_Reddy_VangaRami_Reddy_Vanga Member Posts: 18
we receive PNET_BUFFER_LIST as a parameter on SendNetBufferListsHandler. Need clarification on understanding or questions I have.

Is the NET_Buffer_list we received on Send path represent a single Ethernet frame containing on one NBL or list of NBL's linked together.
If it is single Ethernet frame containing one NBL, then it can also have single NB or multiple NB's, I assume one NBL represent a Ethernet frame where Header part will be only on First NB, remaining NB's represent the payload data (MAC->IP->TCP/UDP->Payload->Checksum).

If each NBL represent a single Ethernet Frame, then I wanted to group all the NB's (list of NB's) into a large array for me to make the processing on frame starting with MAC header, IP header, TCP/UDP header, Once I complete the processing on these frames, Would like to send this Ethernet frame down as if it is initiated by FD (NdisSendNetBufferLists)

Can I send one NBL separately using NdisSendNetBufferLists after my processing on the Ethernet packet (NBL), even though PNET_BUFFER_LIST it is multiple NBL's, Is this type of send break any NDIS design.

Once I process each NBL in the linked list of NBL's I will just return the original PNET_BUFFER_LIST by calling NdisFSendNetBufferListsComplete.

In the NDIS 5.x, we have few functions we can use to get a Entire packet/ Ethernet frame into a large array of buffer, such as NdisQueryPacket (for size),NdisQueryBufferSafe , NdisGetNextBuffer. Do we have any such NDIS calls in the 6.x for getting the information about NBL or NB to form a Complete Ethernet Frame received (fragmented or un-fragmented).

Appreciate your help.

Comments

  • Jan_BottorffJan_Bottorff Member - All Emails Posts: 471
    Each NET_BUFFER_LIST can be multiple Ethernet frames with related properties, like are on the same vlan. The send function also gets a chain of NBLs. NBLs have chains of NET_BUFFERs each of which a packet, except if large segment offload is happening in which case the NB is the buffer to be segmented, so may be much larger than a frame. The different memory fragments that make up the packet are the MDLs attached to the NB. Note that memory fragments can be shared between packets, like a group of TCP packets with the same mac and IP header might have multiple NBs with MDL chains that the first MDLs point to the same memory. This matters if you are modifying the header data. Also note the docs say LSO NBLs will have a single NB, except the WHQL tests generate LSO NBLs with multiple NBs and the offload spans them. Other fun details are that when checksum offload is enabled, the TCP stack precomputes the pseudo header checksum and stores it in the checksum field. There also might be encapsulation headers, and the offset of the TCP header is passed as a parameter, which combined with the precomputed pseudo header means you can do TCP checksum offload without understanding the encapsulation headers. This also means if you modify anything in the headers you will be responsible for parsing the headers and recomputing the pseudo header checksum.

    Received packed are required to be a single NBL with a single NB, with the MDL chain first fragment at least as large as the lookahead value. This allows higher layers to parse headers without having to span fragments. The lookahead value is typically 512 + Mac header size bytes. Also note the OS never gives you vlan headers in packets, and expects the hardware/driver to stuff/strip them, using vlan metadata in the NBL list info fields.

    Some encapsulations can have nested checksums offloaded, so the hardware/driver may need to compute the wrapper checksum and the payload checksum. You also get to tell the OS what you can support, and it will run in software if needed. To pass certification tests, and deliver optimal performance, you generally need a pretty rich feature set that is not left for the OS to do in software.

    Jan

    ________________________________
    From: [email protected] on behalf of [email protected]
    Sent: Wednesday, February 1, 2017 9:57:07 PM
    To: Windows System Software Devs Interest List
    Subject: [ntdev] NET_BUFFER_List Re-package in LWF

    we receive PNET_BUFFER_LIST as a parameter on SendNetBufferListsHandler. Need clarification on understanding or questions I have.

    Is the NET_Buffer_list we received on Send path represent a single Ethernet frame containing on one NBL or list of NBL's linked together.
    If it is single Ethernet frame containing one NBL, then it can also have single NB or multiple NB's, I assume one NBL represent a Ethernet frame where Header part will be only on First NB, remaining NB's represent the payload data (MAC->IP->TCP/UDP->Payload->Checksum).

    If each NBL represent a single Ethernet Frame, then I wanted to group all the NB's (list of NB's) into a large array for me to make the processing on frame starting with MAC header, IP header, TCP/UDP header, Once I complete the processing on these frames, Would like to send this Ethernet frame down as if it is initiated by FD (NdisSendNetBufferLists)

    Can I send one NBL separately using NdisSendNetBufferLists after my processing on the Ethernet packet (NBL), even though PNET_BUFFER_LIST it is multiple NBL's, Is this type of send break any NDIS design.

    Once I process each NBL in the linked list of NBL's I will just return the original PNET_BUFFER_LIST by calling NdisFSendNetBufferListsComplete.

    In the NDIS 5.x, we have few functions we can use to get a Entire packet/ Ethernet frame into a large array of buffer, such as NdisQueryPacket (for size),NdisQueryBufferSafe , NdisGetNextBuffer. Do we have any such NDIS calls in the 6.x for getting the information about NBL or NB to form a Complete Ethernet Frame received (fragmented or un-fragmented).

    Appreciate your help.

    ---
    NTDEV is sponsored by OSR

    Visit the list online at:

    MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
    Details at

    To unsubscribe, visit the List Server section of OSR Online at
  • way_techway_tech Member - All Emails Posts: 5
    use NdisGetDataBuffer and traverse NBL in the loop
  • Rami_Reddy_VangaRami_Reddy_Vanga Member Posts: 18
    Hi way, I will try to use GetDataBuffer API, As of today I have implemented a code to traverse NBL in loop and get the MDL data and combine in to one array, Can you take a look at this code and let me know if my approach is on right path.

    // When the control receives here means, we are Good to go on NBL processing.
    CurrNbl = NetBufferLists;
    while (CurrNbl != NULL)
    {
    pAdapt->OutstandingSends++;

    // When we have Multiple NBL in the linked list, Can we send each NBL as a seperate Ethernet frame.
    // compute the pacakge length.

    // Start with each NB in the NBL
    currNB = NET_BUFFER_LIST_FIRST_NB(CurrNbl);
    total_nb_length = 0;
    while (currNB != NULL)
    {
    currNBoffset = NET_BUFFER_DATA_OFFSET(currNB);
    total_nb_length += (NET_BUFFER_DATA_LENGTH(currNB) - currNBoffset);
    currNB = NET_BUFFER_NEXT_NB(currNB);
    }

    // We get Total Ethernet Frame of Single NBL, Combined NB and MDL's
    // Allocate memory for packetData (Ethernet Frame)
    packetData = (PUCHAR)NdisAllocateMemoryWithTagPriority(pAdapt->FilterHandle,
    total_nb_length,
    TAG,
    HighPoolPriority);

    // Start with each NB in the NBL
    currNB = NET_BUFFER_LIST_FIRST_NB(CurrNbl);
    dataOffset = 0;
    while (currNB != NULL)
    {
    // Get the details of each NB
    currentMBL = NET_BUFFER_CURRENT_MDL(currNB);
    bufferLength = 0;
    while (currentMBL != NULL)
    {
    // Retrive the data in the MDL
    NdisQueryMdl(currentMBL,
    bufferAddress,
    &bufferLength,
    HighPagePriority);

    NdisQueryMdlOffset(currentMBL, &MBLOffset, &Offset_length);

    if (bufferAddress == NULL)
    {
    break;
    }
    bufferAddress = ((PUCHAR)bufferAddress + MBLOffset);
    bufferLength = bufferLength - MBLOffset;
    NdisMoveMemory(&packetData[dataOffset],
    bufferAddress,
    bufferLength);

    dataOffset += bufferLength;

    NdisGetNextMdl(currentMBL,
    &nextMBL);

    currentMBL = nextMBL;
    }
    // Retrive the next NB
    currNB = NET_BUFFER_NEXT_NB(currNB);
    }

    // Check if
    if (total_nb_length != dataOffset)
    {
    NdisReleaseSpinLock(&pAdapt->Lock, DispatchLevel);
    // Free Memory allocated for PacketData
    NdisFreeMemory(packetData, 0, 0);
    NdisFSendNetBufferListsComplete(pAdapt->FilterHandle, NetBufferLists, DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
    break;
    }
    // Need to Create a NBL and copy the contents of CurrNB to NBL_to_Send
    NBL_to_send = currNB;
    SendPckt(FilterModuleContext, packetData, NBL_to_send, SendFlags);

    // Retrive the Next NBL in the Network Buffer List
    // Conitue with Loop until we get to Last NBL in the List.
    CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
    }

    Also, for re-creating the NBL for sending to Lower layer (NIC), I have implemented below code, Let me know if this is wrong approach.

    buffer_memory = NdisAllocateMemoryWithTagPriority(pAdapt->FilterHandle,
    frameLength,
    TAG,
    HighPoolPriority);

    if (buffer_memory != NULL)
    {
    NdisMoveMemory(buffer_memory,
    packetData, // Acutal Data we wanted to send to NIC
    packetLength);

    new_buffer = NdisAllocateMdl(pAdapt->SendBufferPoolHandle,
    buffer_memory,
    frameLength);

    if (new_buffer != NULL)
    {
    queueEntry = NdisAllocateNetBufferAndNetBufferList(pAdapt->SendPacketPoolHandle,
    0,
    0,
    new_buffer,
    0,
    frameLength);

    if (queueEntry!= NULL)
    {
    queueEntry = NULL;
    // queueEntry Memory is allocated with Data needed.
    // How do we set the parameters of Original Packet into the newly created packet.

    }

    }
    }
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 30 Mar 2020 OSR Seminar Space
Developing Minifilters 15 Jun 2020 LIVE ONLINE
Writing WDF Drivers 22 June 2020 LIVE ONLINE
Internals & Software Drivers 28 Sept 2020 Dulles, VA