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.

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: xxxxx@lists.osr.com on behalf of xxxxx@gmail.com
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: http:

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

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

use NdisGetDataBuffer and traverse NBL in the loop

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.

}

}
}

http://www.osronline.com/showThread.cfm?link=262465