Detecting 802.1p Priority Tags: Part 2

In Gabe’s last post on detecting 802.1p priority tags, he described at a relatively high-level why it is difficult to detect a priority tag using packet tracing applications, as well as the proper way to determine whether a tag was present in a packet that was sent onto the wire (or air). In this post, I’ll describe how to programmatically access this information by modifying the NDIS Light Weight Filter (LWF) sample driver found in the Windows Driver Kit (WDK). To begin, download and install the WDK and navigate to the LWF sample found in the WinDDK\6000\src\network\ndis\filter directory. The remainder of this post will describe how to modify this sample to gain access to the UserPriority value in the out-of-band (OOB) data of a Net Buffer List (NBL) structure, and whether the miniport driver actually stripped the 1Q tag from the Ethernet header like it was supposed to. Based on what part-1 of this series describes about driver (miniport/LWF) layering and framing details, the modified driver will inspect received packets (meaning the sender added the tag to outgoing traffic).

The source file in the LWF sample of particular interest is filter.c, where we’ll modify the FilterReceiveNetBufferLists() function. FilterReceiveNetBufferLists() is an optional function for filter drivers, which if provided, processes receive indications made by the underlying miniport or filter drivers beneath in the stack. If this handler is NULL, NDIS will skip calling this filter when processing a receive indication and will call the next filter (or protocol driver) above in the stack with a non-NULL FilterReceiveNetBufferLists handler. The remainder of this post goes into detail about which areas of filter.c need to be modified.

To begin, let’s explore how to access the received packets in this function so they can be inspected. The second parameter to the function, NetBufferLists, is a linked list of NetBufferList structures allocated by the underlying driver. Each NetBufferList contains one NetBuffer structure, which represents a received packet. This means, in order to inspect each packet in the NetBufferLists linked list, we need a loop of the following kind within FilterReceiveNetBufferLists():

if (pFilter->TrackReceives)

{

     FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

     pFilter->OutstandingRcvs += NumberOfNetBufferLists;

     Ref = pFilter->OutstandingRcvs;

     currNbl = NetBufferLists;

     while(currNbl)

     {

          // Call the function to parse the packet in each

          // NetBufferList (one net buffer per NBL )

          inspectNetBuffer(currNbl, pFilter);

          currNbl = currNbl->Next;

     }

     FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);

     FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

}

In the above code snippet, observe that the loop is run only if pFilter->TrackReceives is TRUE. The idea here is to only inspect packets if the user requests the driver to do receive-side inspections (our focus is on a debugging tool). The TrackReceives flag can be set to FALSE at FilterAttach and can be set to TRUE through an IOCTL. Look at the FilterDeviceIoControl() function in device.c for defining IOCTLs.

Now that we have a pointer to the NetBufferList structure which holds the packet information, let’s explore how to inspect the packet for the 802.1p tag (note you could also inspect the IPv4 or IPv6 header for DSCP here if you really wanted). The inspectNetBuffer function in the above code snippet starts by extracting the NetBuffer pointer from the NetBufferList. Please see the bottom of this post for instructions on where to download the full implementation of this function. Next, if an 802.1p tag is available in the OOB data, it is extracted and stored in the variable called UserPriority as follows:

if (NET_BUFFER_LIST_INFO

(pNetBufferList, Ieee8021QNetBufferListInfo) != 0)

{

     Ndis8021QInfo.Value = NET_BUFFER_LIST_INFO(pNetBufferList, Ieee8021QNetBufferListInfo);

     UserPriority = (UCHAR)Ndis8021QInfo.TagHeader.UserPriority;

}

At this point, a pointer to the start of the packet is obtained and stored in packetBuffer. The Ethernet header is parsed and RecdUnStrippedPackets (which is initialized to zero at the beginning before starting to track received packets) is incremented if it is found that the Ethernet header still contains the 802.1p tag - indicating the underlying miniport did not strip the tag as per NDIS documentation.

To download the full implementation of inspectNetBuffer() , as used to do the majority of parsing work, go to Microsoft Connect website and login using your passport account (create one if you don’t already have one). Once you have logged in, choose Available Connections on the left-hand side of the page, and select Windows Networking from the available connections (bottom half of the page). On the left-hand side of the Windows Networking page, choose Downloads, and select NDIS LWF Sample With Packet Priority Detection.

-- Hemant Banavar