NDIS6 bug or IEEE 802.1Q specification?

Hi,

A while ago I ported our old NDIS5 protocol driver to NDIS6. Our driver was based on a Microsoft example. I can no longer find the NDIS5 example but the updated NDIS6 example is here:
https://github.com/microsoft/Windows-driver-samples/tree/master/network/ndis/ndisprot/6x

I followed the NDIS6 example to port our driver and it’s working fine. The problem I’m having is when a Hyper-V virtual adapter is created. At this point the driver can no longer read QoS packets on the physical adapter (only the virtual adapter). You might be tempted to say this is normal, the QoS packets should go to the VLAN however the old NDIS5 driver can read the QoS packets from both the physical adapter and the virtual adapter. Wireshark can also see the QoS packets on the physical adapter. The only way I can make NDIS6 see the packets on the physical adapter is by enabling promiscuous mode.

NDIS5 and NDIS6 are still very similar in the way they open and bind to an adapter - the biggest difference being NdisOpenAdapter() vs NdisOpenAdapterEx(). I suspect NdisOpenAdapterEx() is causing the reception issue (unintentionally or by design). I can’t prove this because NdisOpenAdapter() is no longer available for NDIS6.

Does anyone have any clue how to solve this issue without enabling promiscuous mode? Is this a bug or is NDIS6 simply complying with the 802.1Q specification?

At this point the driver can no longer read QoS packets on the physical adapter (only the virtual adapter

What are “QoS packets” - 802.1Q or IP with diffserv info?
So it does not get any packet with 802.1Q tag at all, or it gets packets with the tags stripped off/moved to OOB info?

– pa

Sorry, when I say QoS I mean Quality of Service which is the priority setting of the 802.1Q tag. To answer your question, the driver does not receive any packets with the 802.1Q tag at all on the physical adapter. They appear to be forwarded to the virtual adapter even when the VLAN id is not set.

Powershell commands:
New-VMSwitch -Name ETH1 -NetAdapterName ETH1 -AllowManagementOS $False
Add-VMNetworkAdapter -Name ‘ETH1’ -ManagementOS -SwitchName ETH1

Anyway, it looks like I found the answer to my problem here:
https://marc.info/?l=wireshark-dev&m=143444451202831&w=2

In the thread he says, “WinPcap cannot capture 802.1Q tagged VLAN headers received by NDIS 6.x” and later he says, “I also add the code to capture 802.1Q VLAN tags correctly”

So I downloaded his code to see how he was calling NdisOpenAdapterEx(). Sure enough I found a difference. He sets the OpenParameters.FrameTypeArray = NULL. I was setting this like the Microsoft example. When I set this option to NULL it works. The driver can now see 802.1Q tags on the physical adapter when a VLAN is defined. Problem solved.

Maybe it would be nice to understand exactly what the option does.

1 Like

I should rephrase my statement “the driver can now see 802.1Q tags”. The tag is actually stripped off when the packet is received but at least I’m getting packets. Previously any packets with the 802.1Q tags were not received.

The tag is actually stripped off when the packet is received but at least I’m getting packets.
Do you see the missing bits in OOB info?
– pa

Setting the OpenParameters.FrameTypeArray to NULL is not ideal, since that can put the miniport stack into a low performance mode. Setting the array to NULL means that you want all EtherTypes to be delivered to your protocol.

If there is any other protocol driver on the NIC, then that puts NDIS into an awkward position: the other protocol wants some packets, and you want all packets. When NDIS sees two protocols that overlap on their EtherTypes, NDIS doesn’t try to efficiently sort the NBLs by EtherType anymore; it just gives all NBLs to all protocols with the NDIS_RECEIVE_FLAGS_RESOURCES flag. That’s not great for perf.

(Yes, with some significant effort, NDIS could probably be a little bit smarter here. But really it’s a rare case that 2 protocols want the same EtherTypes – usually they all want disjoint sets, so that’s what NDIS has optimized for.)

NDIS generally requires miniports to strip the 802.1Q tag and put the tag’s value into the NBL’s Ieee8021QNetBufferListInfo. NDIS also requires miniports to drop traffic that’s not destined to the currently-configured VLAN (Set-NetAdapter -VlanID). As a special exception, setting the packet filter to NDIS_PACKET_TYPE_PROMISCUOUS instructs the NIC to not do any VLAN filtering.

After the Q header is removed by the miniport, NDIS parses out the EtherType. The packet is given to the protocol(s) that asked for that EtherType. As discussed above, if a protocol provides a NULL FrameTypeArray, that’s equivalent to a wildcard for EtherType matching.

There are a few cases where NDIS gives up on FrameType matching, and just dumps all NBLs onto all protocols. It sort of sounds like you were accidentally relying on this behavior? Make sure you specify exactly the EtherType(s) you care about. If you need to see all VLANs, then you do have to enable promiscuous mode.

It’s by design that the vSwitch consumes the Q tags and, well, switches traffic based on the Q tag. So you probably can’t get full fidelity Q tags from above the vswitch. Think about the vswitch as a real hardware switch. If your protocol attaches to a host vNIC, then you’re on another switch port from the physical NIC. The vswitch can be configured to put a port into Trunk mode, which might help (Set-VMNetworkAdapterVlan).

Otherwise, if your protocol is really tied to the external physical NIC, it should just bind to that directly, rather than trying to reach through the vswitch. Creating an external vswitch automatically unbinds all other protocols from the external NIC, but you can just bind it back again (Enable-NetAdapterBinding).

Footnote on Q-in-Q: if there is more than one Q tag, then the NIC strips only the outermost one. We are currently considering an extension to NDIS to instruct the NIC strip out the 2nd outermost one too. After the NIC has stripped one (or someday, two) tags, that leaves the remaining Q header(s) intact in the packet payload. NDIS currently knows how to read the EtherType if there’s exactly zero or one Q tag remaining. So in summary, you can currently rely on EtherTypes if you have no Q tags, 1 Q tag, or 2 Q tags. If there’s 2 Q tags, then you’ll have the outermost tag in the NBL’s OOB data, and the inner tag will still be intact. If there’s more than 2 Q tags, it all sort of falls apart.