Using Layer 2 Filtering
Layer 2 filtering is supported in Windows 8 and later versions of Windows.
This WFP feature allows filtering on fields of the layer 2 MAC header. These layers are invoked on a per-packet basis for all packets that are sent or received by the host machine. The layers are invoked prior to packet reassembly on the inbound path and after packet fragmentation on the outbound path. These layers are accessed from an NDIS lightweight filter (LWF) driver.
A callout should not inject packets at a layer if it does not already have a corresponding filter at that layer. The injection of the NET_BUFFER_LIST structures should be coordinated with the filter addition and removal so that injection is only performed when the filter exists in the corresponding layer. In addition, providers should not remove filters that belong to other providers.
This section includes the following topics:
Injecting MAC Frames
A callback driver calls the FwpsInjectMacReceiveAsync0 function to reinject a previously absorbed MAC frame (or a clone of the frame) back to the layer 2 inbound data path it was intercepted from, or to inject an invented MAC frame in the inbound data path.
A callback driver calls the FwpsInjectMacSendAsync0 function to reinject a previously absorbed MAC frame (or a clone of the frame) back to the layer 2 outbound data path it was intercepted from, or to inject an invented MAC frame in the outbound data path.
The netBufferLists parameter can be a NET_BUFFER_LIST chain. However the completion function could be invoked multiple times each, completing a segment (or single NET_BUFFER_LIST) of the chain.
Injected frames could get classified again if the packets match the same filter as originally classified. Therefore, as with callouts at IP layers, layer 2 callouts must also protect against infinite packet inspection by calling FwpsQueryPacketInjectionState0.
Also, you must have callouts at the layer where you inject. Otherwise, your injected NET_BUFFER_LIST will not be completed to your completion function, and the NET_BUFFER_LIST will go further up the stack. In this case, the behavior is undefined, because NDIS will try to pass the injected NET_BUFFER_LIST to the next component in the stack.
The NET_BUFFER_LISTStatus member contains the stack injection’s status result. The stack injection’s status result is the status that the stack puts in the NET_BUFFER_LIST after a WFP injection function returns STATUS_SUCCESS. You should use the NT_SUCCESS macro to check the stack injection's status in the Status member. If the Status value is STATUS_SUCCESS, the injection succeeded with no further information. Status member values that are greater than STATUS_SUCCESS mean that the injection succeeded, but there might be more information about the injection that should be considered. Status member values that are less than STATUS_SUCCESS mean that the injection failed for the reason specified in the Status member.
Classifying Chained Network Buffer Lists
By default, a callout driver can only classify network buffer lists individually. However, a callout driver can classify NET_BUFFER_LIST chains for better performance, if it does both of the following:
- Specifies the FWP_CALLOUT_FLAG_ALLOW_L2_BATCH_CLASSIFY flag in the Flags member of the FWPS_CALLOUT2 structure.
- Registers a classifyFn2 function that can classify NET_BUFFER_LIST chains.
However, if a callout driver does set the FWP_CALLOUT_FLAG_ALLOW_L2_BATCH_CLASSIFY flag, it cannot use the following functions to modify NET_BUFFER_LISTs.
With this flag set, FwpsAllocateCloneNetBufferList0 will always return an INVALID_PARAMETER error. This may unexpectedly cause a 3rd party callout driver to fail to manage the reference count of NET_BUFFER_LISTs, causing send and receive operations to stop.
WFP Layer 2 Layers and Fields
Run-time Filtering Layer Identifiers for virtual switch filtering include:
Data Field Identifiers for virtual switch filtering include: