[ovs-dev] [PATCH 1/4] datapath-windows: Base code for developing the Hyper-V switch entension.

Saurabh Shah ssaurabh at vmware.com
Tue Jun 24 00:34:56 UTC 2014


This is the "Hyper-V Extensible Switch extension filter driver" sample code
available at:
http://code.msdn.microsoft.com/windowshardware/Hyper-V-Extensible-Virtual-e4b31fbb

The sample code is licensed under Microsoft Limited Public License version
1.1. The license is available here -
http://msdn.microsoft.com/en-us/cc300389.aspx (Exhibit B).

Our core Hyper-V switch extension builds on top of this sample code to develop
the forwarding engine.

Signed-off-by: Eitan Eliahu <eliahue at vmware.com>
Signed-off-by: Guolin Yang <gyang at vmware.com>
Signed-off-by: Linda Sun <lsun at vmware.com>
Signed-off-by: Nithin Raju <nithin at vmware.com>
Signed-off-by: Saurabh Shah <ssaurabh at vmware.com>
---
 AUTHORS                            |    2 +
 COPYING                            |    4 +
 datapath-windows/base/SxApi.h      | 1196 +++++++++++++++++++++++++++++++
 datapath-windows/base/SxBase.c     | 1395 ++++++++++++++++++++++++++++++++++++
 datapath-windows/base/SxBase.h     |  168 +++++
 datapath-windows/base/SxLibrary.c  |  839 ++++++++++++++++++++++
 datapath-windows/base/SxLibrary.h  |  464 ++++++++++++
 datapath-windows/base/precomp.h    |   11 +
 datapath-windows/base/precompsrc.c |    1 +
 debian/copyright.in                |   74 ++
 10 files changed, 4154 insertions(+)
 create mode 100644 datapath-windows/base/SxApi.h
 create mode 100644 datapath-windows/base/SxBase.c
 create mode 100644 datapath-windows/base/SxBase.h
 create mode 100644 datapath-windows/base/SxLibrary.c
 create mode 100644 datapath-windows/base/SxLibrary.h
 create mode 100644 datapath-windows/base/precomp.h
 create mode 100644 datapath-windows/base/precompsrc.c

diff --git a/AUTHORS b/AUTHORS
index 08646d3..11ccdc7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -46,6 +46,7 @@ Duffie Cooley           dcooley at nicira.com
 Ed Maste                emaste at freebsd.org
 Edouard Bourguignon     madko at linuxed.net
 Edward Tomasz Napierała trasz at freebsd.org
+Eitan Eliahu            eliahue at vmware.com
 Ethan Jackson           ethan at nicira.com
 Flavio Leitner          fbl at redhat.com
 Francesco Fusco         ffusco at redhat.com
@@ -93,6 +94,7 @@ Murphy McCauley         murphy.mccauley at gmail.com
 Natasha Gude            natasha at nicira.com
 Neil McKee              neil.mckee at inmon.com
 Neil Zhu                zhuj at centecnetworks.com
+Nithin Raju             nithin at vmware.com
 Padmanabhan Krishnan    kprad1 at yahoo.com
 Paraneetharan Chandrasekaran    paraneetharanc at gmail.com
 Paul Fazzone            pfazzone at nicira.com
diff --git a/COPYING b/COPYING
index 9d6fc48..06adace 100644
--- a/COPYING
+++ b/COPYING
@@ -91,3 +91,7 @@ Foundation License, version 2:
    8. By copying, installing or otherwise using Python, Licensee
    agrees to be bound by the terms and conditions of this License
    Agreement.
+
+Files unders datapath-windows/base are licensed under Microsoft Limited Public
+License version 1.1, that is available at:
+http://msdn.microsoft.com/en-us/cc300389.aspx (Exhibit B).
diff --git a/datapath-windows/base/SxApi.h b/datapath-windows/base/SxApi.h
new file mode 100644
index 0000000..6ee52c9
--- /dev/null
+++ b/datapath-windows/base/SxApi.h
@@ -0,0 +1,1196 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+    SxApi.h
+
+Abstract:
+
+    This file contains the API that must be implemented to
+    create a switch extension using the SxBase library.
+
+
+--*/
+
+//
+// The major version of NDIS the driver is using.
+// For NDIS 6.30, use NDIS_FILTER_MAJOR_VERSION.
+//
+extern UCHAR  SxExtMajorNdisVersion;
+
+//
+// The minor version of NDIS the driver is using.
+// For NDIS 6.30, use NDIS_FILTER_MINOR_VERSION.
+//
+extern UCHAR  SxExtMinorNdisVersion;
+
+//
+// The friendly name of the extension.
+//
+extern PWCHAR SxExtFriendlyName;
+
+//
+// The unique name of the extension.
+//
+extern PWCHAR SxExtUniqueName;
+
+//
+// The service name of the extension from the INF.
+//
+extern PWCHAR SxExtServiceName;
+
+//
+// The memory pool tag using in the extension.
+//
+extern ULONG  SxExtAllocationTag;
+
+//
+// The request ID used to identify OIDs initiated from this extension. 
+//
+extern ULONG  SxExtOidRequestId;
+
+
+/*++
+
+SxExtInitialize
+  
+Routine Description:
+    This function is called from the SxBase Library during DriverEntry.
+    An extension should allocate/initalize all global data in this function.
+      
+Arguments:
+    NULL
+    
+Return Value:
+    NDIS_STATUS_SUCCESS succeeds driver entry.
+    
+    NDIS_STATUS_*** fails driver entry.
+   
+--*/
+NDIS_STATUS
+SxExtInitialize();
+
+
+/*++
+
+SxExtUninitialize
+  
+Routine Description:
+    This function is called from the SxBase Library during DriverUnload.
+    An extension should free/reset all global data in this function.
+      
+Arguments:
+    NULL
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxExtUninitialize();
+
+
+/*++
+
+SxExtCreateSwitch
+  
+Routine Description:
+    This function is called when an extension binds to a new switch.
+    All switch specific data should be allocated during this function.
+    OIDs cannot be sent from this function, and both the control
+    and data paths are inactive.
+      
+Arguments:
+    Switch - the Switch Object currently being created
+    
+    ExtensionContext -  Extension context specific to the switch being
+                        createf. This context will be passed back to the
+                        extension for all function calls in SxApi
+    
+Return Value:
+    NDIS_STATUS_SUCCESS succeeds switch creation.
+    
+    NDIS_STATUS_RESOURCES fails switch creation because of insufficient
+                          resources.
+                          
+    NDIS_STATUS_FAILURE fails switch creation.
+   
+--*/
+NDIS_STATUS
+SxExtCreateSwitch(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Outptr_result_maybenull_ PNDIS_HANDLE *ExtensionContext
+    );
+
+    
+/*++
+
+SxExtDeleteSwitch
+  
+Routine Description:
+    This function is called when an extension binds to a new switch.
+    All switch specific data should be allocated/initialized during
+    this function.
+      
+Arguments:
+    Switch - the Switch being deleted
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch being deleted.
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxExtDeleteSwitch(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext
+    );
+
+    
+/*++
+
+SxExtActivateSwitch
+  
+Routine Description:
+    This function is called to activate a switch. The function can be called
+    while the switch is Running or Paused and should be used to bootstrap
+    the switch if it was not Active when it was created.
+      
+Arguments:
+    Switch - the Switch being activated
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch being restarted.
+    
+Return Value:
+    VOID
+   
+--*/   
+VOID
+SxExtActivateSwitch(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext
+    );
+
+    
+/*++
+
+SxExtRestartSwitch
+  
+Routine Description:
+    This function is called to restart a switch from a paused state.
+      
+Arguments:
+    Switch - the Switch being restarted
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch being restarted.
+    
+Return Value:
+    NDIS_STATUS_SUCCESS succeeds switch restart.
+    
+    NDIS_STATUS_RESOURCES fails switch restart because of insufficient
+                          resources.
+                          
+    NDIS_STATUS_FAILURE fails switch restart.
+   
+--*/
+NDIS_STATUS
+SxExtRestartSwitch(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext
+    );
+
+
+/*++
+
+SxExtPauseSwitch
+  
+Routine Description:
+    This function is called to pause a switch from a running state.
+      
+Arguments:
+    Switch - the Switch being paused
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch being paused
+    
+Return Value:
+    VOID
+   
+--*/    
+VOID
+SxExtPauseSwitch(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext
+    );
+
+
+/*++
+
+SxExtCreatePort
+  
+Routine Description:
+    This function is called to create a new port on a switch.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Port - the Port being created
+    
+Return Value:
+    NDIS_STATUS_SUCCESS to succeed port creation
+    
+    NDIS_STATUS_*** to fail port creation
+   
+--*/  
+NDIS_STATUS
+SxExtCreatePort(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PARAMETERS Port
+    );
+
+  
+/*++
+
+SxExtUpdatePort
+  
+Routine Description:
+    This function is called to update an already created port.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Port - the port being updated
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxExtUpdatePort(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PARAMETERS Port
+    );
+
+    
+/*++
+
+SxExtCreateNic
+  
+Routine Description:
+    This function is called to create a new NIC to be connected
+    to a switch.
+    The extension may allocate context for this NIC, and traffic may
+    start to flow from this NIC, but it may not be used as a destination
+    until SxExtConnectNic has been called.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Nic - the NIC being created
+    
+Return Value:
+    NDIS_STATUS_SUCCESS to succeed NIC creation
+    
+    NDIS_STATUS_*** to fail NIC creation
+   
+--*/  
+NDIS_STATUS
+SxExtCreateNic(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_PARAMETERS Nic
+    );
+
+    
+/*++
+
+SxExtConnectNic
+  
+Routine Description:
+    This function is called to connect a NIC to a switch.
+    After returning from this function the extension can use this NIC
+    as a destination.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Nic - the NIC being connected
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxExtConnectNic(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_PARAMETERS Nic
+    );
+
+    
+/*++
+
+SxExtUpdateNic
+  
+Routine Description:
+    This function is called to update an already created NIC.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Nic - the NIC being updated
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxExtUpdateNic(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_PARAMETERS Nic
+    );
+
+    
+/*++
+
+SxExtDisconnectNic
+  
+Routine Description:
+    This function is called to disconnect a NIC from a switch.
+    After returning from this function the extension cannot use
+    this NIC as a destination.
+      
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Nic - the NIC being disconnected
+    
+Return Value:
+    VOID
+   
+--*/ 
+VOID
+SxExtDisconnectNic(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_PARAMETERS Nic
+    );
+
+    
+/*++
+
+SxExtDeleteNic
+  
+Routine Description:
+    This function is called to delete a NIC from a switch.
+    No futher traffic/control will be recieved for this NIC.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Nic - the NIC being deleted
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxExtDeleteNic(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_PARAMETERS Nic
+    );
+
+    
+/*++
+
+SxExtTeardownPort
+  
+Routine Description:
+    This function is called to start deletion of a port on a switch.
+    Upon recieving this call, no further references may be taken
+    on the given port.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Port - the Port being deleted
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxExtTeardownPort(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PARAMETERS Port
+    );
+
+
+/*++
+
+SxExtDeletePort
+  
+Routine Description:
+    This function is called to finish deletion of a port on a switch.
+    Upon recieving this call, no traffic/control will be recieved
+    for this port.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    Port - the Port being deleted
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxExtDeletePort(  
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PARAMETERS Port
+    );
+
+    
+/*++
+
+SxExtSaveNic
+  
+Routine Description:
+    This function is called to retrieve save data for a given NIC.
+    This function will be called until all extensions have finished
+    saving data.
+    
+    An new save for this NIC will not start until SxExtSaveNicComplete
+    has been received.
+    
+    If returning NDIS_STATUS_SUCCESS from this function, and
+    BytesWritten > 0 you must write to the ExtensionId,
+    ExtensionFriendlyName, SaveDataSize and SaveData fields in
+    SaveState. SxExtUniqueName MUST be written to ExtensionId.
+    SxExtFriendlyName should be written to ExtensionFriendlyName.
+    
+    If returning NDIS_STATUS_SUCCESS with BytesWritten == 0,
+    DO NOT write any data to any fields.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SaveState - the save information and buffer to save to
+    
+    BytesWritten - the # of bytes written to the save buffer
+    
+    BytesNeeded - the length of the save buffer needed
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if the buffer was successfully written, or not
+                          needed and BytesWritten is set to 0
+                          
+    NDIS_STATUS_BUFFER_TOO_SHORT - if the buffer is too short for the
+                                   necessary save, write the length needed
+                                   in BytesNeeded
+
+    NDIS_STATUS_*** - to fail the save operation
+   
+--*/
+NDIS_STATUS
+SxExtSaveNic(  
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _Inout_ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+    _Out_ PULONG BytesWritten,
+    _Out_ PULONG BytesNeeded
+    );
+
+
+/*++
+
+SxExtSaveNicComplete
+  
+Routine Description:
+    This function is called to notify the extension that saving
+    the given NIC has been completed by all extensions.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SaveState - the save information
+    
+Return Value:
+    VOID
+   
+--*/    
+VOID
+SxExtSaveNicComplete(  
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+    );
+
+    
+/*++
+
+SxExtNicRestore
+  
+Routine Description:
+    This function is called to restore previously saved data.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SaveState - the save information
+    
+    BytesRestored - the number of bytes restored from the saved data
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if this data belongs to this extension, and was
+                          successfully restored (BytesRestored written)
+                          OR
+                          this data does not belong to this extension
+                          (BytesRestored == 0)    
+                              
+    NDIS_STATUS_*** - there was an error while attempting to restore
+                      this data
+   
+--*/    
+NDIS_STATUS
+SxExtNicRestore(  
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+    _Out_ PULONG BytesRestored
+    );
+
+    
+/*++
+
+SxExtNicRestoreComplete
+  
+Routine Description:
+    This function is called to signify the end of a restore operation.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SaveState - the save information
+        
+Return Value:
+    VOID
+   
+--*/    
+VOID
+SxExtNicRestoreComplete(  
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+    );
+    
+    
+/*++
+
+SxExtAddSwitchProperty
+  
+Routine Description:
+    This function is called to add a property on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SwitchProperty - the property to be applied
+    
+Return Value:
+    NDIS_STATUS_NOT_SUPPORTED - if the policy is not consumed by this extension
+    
+    NDIS_STATUS_SUCCESS - if the policy is consumed by this extension, and
+                          can successfully be enforced
+                          
+    STATUS_DATA_NOT_ACCEPTED - if the policy is consumed by this
+                               extension, but cannot be enforced
+                               
+    NDIS_STATUS_*** - if the policy is consumed by this extension, and
+                      setting the valid policy failed
+   
+--*/ 
+NDIS_STATUS
+SxExtAddSwitchProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+    );
+
+
+/*++
+
+SxExtUpdateSwitchProperty
+  
+Routine Description:
+    This function is called to update a property on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SwitchProperty - the property to be updated
+    
+Return Value:
+    NDIS_STATUS_NOT_SUPPORTED - if the policy is not consumed by this extension
+    
+    NDIS_STATUS_SUCCESS - if the policy is consumed by this extension, and
+                          can successfully be enforced
+                          
+    STATUS_DATA_NOT_ACCEPTED - if the policy is consumed by this
+                               extension, but cannot be enforced
+                               
+    NDIS_STATUS_*** - if the policy is consumed by this extension, and
+                      setting the valid policy failed
+   
+--*/ 
+NDIS_STATUS
+SxExtUpdateSwitchProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+    );
+
+    
+/*++
+
+SxExtDeleteSwitchProperty
+  
+Routine Description:
+    This function is called to delete a property on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SwitchProperty - the property to be deleted
+    
+Return Value:
+    TRUE - if the policy belongs to this extension
+    
+    FALSE - otherwise
+   
+--*/ 
+BOOLEAN
+SxExtDeleteSwitchProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PROPERTY_DELETE_PARAMETERS SwitchProperty
+    );
+
+
+/*++
+
+SxExtAddPortProperty
+  
+Routine Description:
+    This function is called to add a property on the given port,
+    on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    PortProperty - the property to be applied
+    
+Return Value:
+    NDIS_STATUS_NOT_SUPPORTED - if the policy is not consumed by this extension
+    
+    NDIS_STATUS_SUCCESS - if the policy is consumed by this extension, and
+                          can successfully be enforced
+                          
+    STATUS_DATA_NOT_ACCEPTED - if the policy is consumed by this
+                               extension, but cannot be enforced
+                               
+    NDIS_STATUS_*** - if the policy is consumed by this extension, and
+                      setting the valid policy failed
+   
+--*/ 
+NDIS_STATUS
+SxExtAddPortProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+    );
+
+
+/*++
+
+SxExtUpdatePortProperty
+  
+Routine Description:
+    This function is called to update a property on the given port,
+    on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    PortProperty - the property to be applied
+    
+Return Value:
+    NDIS_STATUS_NOT_SUPPORTED - if the policy is not consumed by this extension
+    
+    NDIS_STATUS_SUCCESS - if the policy is consumed by this extension, and
+                          can successfully be enforced
+                          
+    STATUS_DATA_NOT_ACCEPTED - if the policy is consumed by this
+                               extension, but cannot be enforced
+                               
+    NDIS_STATUS_*** - if the policy is consumed by this extension, and
+                      setting the valid policy failed
+   
+--*/     
+NDIS_STATUS
+SxExtUpdatePortProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+    );
+
+    
+/*++
+
+SxExtDeletePortProperty
+  
+Routine Description:
+    This function is called to delete a property on the given port,
+    on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SwitchProperty - the property to be deleted
+    
+Return Value:
+    TRUE - if the policy is not consumed by this extension
+    
+    FALSE - otherwise
+   
+--*/ 
+BOOLEAN
+SxExtDeletePortProperty(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS PortProperty
+    );
+
+    
+/*++
+
+SxExtQuerySwitchFeatureStatus
+  
+Routine Description:
+    This function is called to query the status of a custom property
+    on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    SwitchFeatureStatus - the property buffer
+    
+    BytesNeeded - if SwitchFeatureStatus is too small, this should be set
+                  to the size buffer needed
+    
+Return Value:
+    TRUE - return true if this property belongs to this extension, if
+           BytesNeeded > 0, the buffer will be reallocated and
+           this function will be called again
+    
+    FALSE - otherwise
+   
+--*/
+BOOLEAN
+SxExtQuerySwitchFeatureStatus(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _Inout_ PNDIS_SWITCH_FEATURE_STATUS_PARAMETERS SwitchFeatureStatus,
+    _Inout_ PULONG BytesNeeded
+    );
+
+
+/*++
+
+SxExtQueryPortFeatureStatus
+  
+Routine Description:
+    This function is called to query the status of a custom property
+    on the given port, on the given switch.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    PortFeatureStatus - the property buffer
+    
+    BytesNeeded - if PortFeatureStatus is too small, this should be set
+                  to the size buffer needed
+    
+Return Value:
+    TRUE - return true if this property belongs to this extension, if
+           BytesNeeded > 0, the buffer will be reallocated and
+           this function will be called again
+    
+    FALSE - otherwise
+   
+--*/
+BOOLEAN
+SxExtQueryPortFeatureStatus(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _Inout_ PNDIS_SWITCH_PORT_FEATURE_STATUS_PARAMETERS PortFeatureStatus,
+    _Inout_ PULONG BytesNeeded
+    );
+    
+    
+/*++
+
+SxExtProcessNicRequest
+  
+Routine Description:
+    This function is called upon the reciept of an OID_SWITCH_NIC_REQUEST
+    to the extension.
+    If an extension wishes to redirect the OID, it must return a valid
+    DestinationPortId and DestinationNicIndex, which it has taken a
+    reference on.
+    If an extension wishes to set source information, it must return
+    a valid SourcePortId and SourceNicIndex, which it has taken a
+    reference on.
+    The extension can change the OidRequest if it needs to.
+    
+    !! This function should only be used by forwarding extensions. !!
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    OidRequest - the OID wrapped by the NIC request
+    
+    SourcePortId - the source PortId to set
+    
+    SourceNicIndex - the source NicIndex to set
+    
+    DestinationPortId - the destination PortId to set
+    
+    DestinationNicIndex - the destination NicIndex to set
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - sends OID
+    
+    NDIS_STATUS_*** - complete OID with given status
+   
+--*/
+NDIS_STATUS
+SxExtProcessNicRequest(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _Inout_ PNDIS_OID_REQUEST OidRequest,
+    _Inout_ PNDIS_SWITCH_PORT_ID SourcePortId,
+    _Inout_ PNDIS_SWITCH_NIC_INDEX SourceNicIndex,
+    _Inout_ PNDIS_SWITCH_PORT_ID DestinationPortId,
+    _Inout_ PNDIS_SWITCH_NIC_INDEX DestinationNicIndex
+    );
+
+
+/*++
+
+SxExtProcessNicRequestComplete
+  
+Routine Description:
+    This function is called upon the completion of an OID_SWITCH_NIC_REQUEST
+    that this extension has previously altered.
+    The extension must derefernce all NICs it had previously taken references
+    on.
+    If the OidRequest buffer was changed (along with underlying buffers),
+    the previous data must be replaced.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    NicOidRequest - the OID buffer, encapsulated with source/destination info
+    
+    Status - the status the OID completed with
+    
+Return Value:
+    NDIS_STATUS - the status to complete the OID request with
+   
+--*/    
+NDIS_STATUS
+SxExtProcessNicRequestComplete(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _Inout_ PNDIS_OID_REQUEST OidRequest,
+    _In_ NDIS_SWITCH_PORT_ID SourcePortId,
+    _In_ NDIS_SWITCH_NIC_INDEX SourceNicIndex,
+    _In_ NDIS_SWITCH_PORT_ID DestinationPortId,
+    _In_ NDIS_SWITCH_NIC_INDEX DestinationNicIndex,
+    _In_ NDIS_STATUS Status
+    );
+    
+
+/*++
+
+SxExtProcessNicStatus
+  
+Routine Description:
+    This function is called upon the reciept of an NDIS_STATUS_SWITCH_NIC_STATUS
+    to the extension.
+    If the extension wishes to modify the status indication, it should
+    send its own status indication using NdisFIndicateStatus and return a
+    failure status.
+    If the extension wishes to drop the status indiction, it should return
+    failure status, though this should be done very sparingly and carefully.
+    
+    !! This function should only be used by forwarding extensions. !!
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    StatusIndication - the indication wrapped by the NIC status indication
+    
+    SourcePortId - the source PortId of the indication
+    
+    SourceNicIndex - the source NicIndex of the indication
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - return to continue forwarding this indication
+    
+    NDIS_STATUS_*** - if the extension wants to modify the status
+                      if modifying the status the extension should indicate
+                      its own modified status using
+                      SxLibIssueNicStatusIndicationUnsafe as soon as possible
+   
+--*/
+NDIS_STATUS
+SxExtProcessNicStatus(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNDIS_STATUS_INDICATION StatusIndication,
+    _In_ NDIS_SWITCH_PORT_ID SourcePortId,
+    _In_ NDIS_SWITCH_NIC_INDEX SourceNicIndex
+    );
+
+    
+/*++
+
+SxExtStartNetBufferListsIngress
+  
+Routine Description:
+    This function is called upon the receipt on an NBL on ingress.
+    The extension should call SxLibSendNetBufferListsIngress to continue
+    the send of the NBL on ingress.
+    The extension should call SxLibCompleteNetBufferListsIngress to
+    drop the NBL.
+    This function may also be call from egress to inject an NBL.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    NetBufferLists - the NBL to be sent
+        
+    SendFlags - the send flags from NDIS, equivalent to NDIS send flags for
+                NdisFSendNetBufferLists
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxExtStartNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendFlags
+    );
+
+
+/*++
+
+SxExtStartNetBufferListsEgress
+  
+Routine Description:
+    This function is called upon the receipt on an NBL on egress.
+    The extension should call SxLibSendNetBufferListsEgress to continue
+    the send of the NBL on egress.
+    The extension should call SxLibSendNetBufferListsEgressComplete to
+    drop the NBL.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    NetBufferLists - the NBL to be sent
+        
+    NumberOfNetBufferLists - the number of NBLs in NetBufferLists
+    
+    ReceiveFlags - the receive flags from NDIS, equivalent to NDIS receive flags for
+                   NdisFIndicateReceiveNetBufferLists
+    
+Return Value:
+    VOID
+   
+--*/     
+VOID
+SxExtStartNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG NumberOfNetBufferLists,
+    _In_ ULONG ReceiveFlags
+    );
+
+    
+/*++
+
+SxExtStartCompleteNetBufferListsEgress
+  
+Routine Description:
+    This function is called upon the completion of an NBL on egress.
+    The extension must call SxLibCompleteNetBufferListsEgress
+    once it has finished processing the NBL.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    NetBufferLists - the NBL being completed
+    
+    ReturnFlags - the return flags from NDIS, equivalent to NDIS return flags for
+                  NdisFReturnNetBufferLists
+    
+Return Value:
+    VOID
+   
+--*/ 
+VOID
+SxExtStartCompleteNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG ReturnFlags
+    );
+
+    
+/*++
+
+SxExtStartCompleteNetBufferListsIngress
+  
+Routine Description:
+    This function is called upon the completion of an NBL on ingress.
+    The extension must call SxLibCompleteNetBufferListsIngress
+    once it has finished processing the NBL.
+    
+    If there are NBLs injected by this extension in NetBufferLists,
+    the extension must NOT call SxLibCompleteNetBufferListsIngress, and
+    instead call SxLibCompletedInjectedNetBufferLists with the number
+    of injected NBLs completed.
+
+Arguments:
+    Switch - the Switch context
+    
+    ExtensionContext - The extension context allocated in SxExtCreateSwitch
+                       for the switch
+                       
+    NetBufferLists - the NBL being completed
+        
+    SendCompleteFlags - the send complete flags from NDIS, equivalent to
+                        NDIS send complete flags for
+                        NdisFSendNetBufferListsComplete
+    
+Return Value:
+    VOID
+   
+--*/ 
+VOID
+SxExtStartCompleteNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_HANDLE ExtensionContext,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendCompleteFlags
+    );
+    
diff --git a/datapath-windows/base/SxBase.c b/datapath-windows/base/SxBase.c
new file mode 100644
index 0000000..57fabd8
--- /dev/null
+++ b/datapath-windows/base/SxBase.c
@@ -0,0 +1,1395 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+    SxBase.c
+
+Abstract:
+
+    This file contains the common code for building a switch extension. This
+    file includes all the standard NDIS handling and exposes a function based
+    interface for the control path and data path. This also has reusable code
+    for basic operations such as pause/resume handling etc.
+
+
+--*/
+
+#include "precomp.h"
+
+ULONG SxDebugLevel;
+NDIS_HANDLE SxDriverHandle = NULL;
+NDIS_HANDLE SxDriverObject;
+NDIS_SPIN_LOCK SxExtensionListLock;
+LIST_ENTRY SxExtensionList;
+
+NDIS_STRING SxExtensionFriendlyName;
+NDIS_STRING SxExtensionGuid;
+
+NDIS_STATUS
+SxpNdisProcessSetOid(
+    __in PSX_SWITCH_OBJECT Switch,
+    __inout PNDIS_OID_REQUEST OidRequest,
+    __out PBOOLEAN Complete
+    );
+
+NDIS_STATUS
+SxpNdisProcessMethodOid(
+    __in PSX_SWITCH_OBJECT Switch,
+    __inout PNDIS_OID_REQUEST OidRequest,
+    __out PBOOLEAN Complete,
+    __out PULONG BytesNeeded
+    );
+
+    
+//
+// DriverEntry
+// http://msdn.microsoft.com/en-us/library/ff544113(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NTSTATUS
+DriverEntry(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath
+    )
+{
+    NDIS_STATUS status;
+    NDIS_FILTER_DRIVER_CHARACTERISTICS fChars;
+    NDIS_STRING serviceName;
+
+    UNREFERENCED_PARAMETER(RegistryPath);
+    
+    //
+    // Initialize extension specific data.
+    //
+    status = SxExtInitialize();
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        goto Cleanup;
+    }
+
+    RtlInitUnicodeString(&serviceName, SxExtServiceName);
+    RtlInitUnicodeString(&SxExtensionFriendlyName, SxExtFriendlyName);
+    RtlInitUnicodeString(&SxExtensionGuid, SxExtUniqueName);
+    SxDriverObject = DriverObject;
+
+    NdisZeroMemory(&fChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
+    fChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
+    fChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
+    fChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2;
+    fChars.MajorNdisVersion = SxExtMajorNdisVersion;
+    fChars.MinorNdisVersion = SxExtMinorNdisVersion;
+    fChars.MajorDriverVersion = 1;
+    fChars.MinorDriverVersion = 0;
+    fChars.Flags = 0;
+    fChars.FriendlyName = SxExtensionFriendlyName;
+    fChars.UniqueName = SxExtensionGuid;
+    fChars.ServiceName = serviceName;
+    
+    fChars.SetOptionsHandler = SxNdisSetOptions;
+    fChars.SetFilterModuleOptionsHandler = SxNdisSetFilterModuleOptions;
+    
+    fChars.AttachHandler = SxNdisAttach;
+    fChars.DetachHandler = SxNdisDetach;
+    fChars.PauseHandler = SxNdisPause;
+    fChars.RestartHandler = SxNdisRestart;
+
+    fChars.SendNetBufferListsHandler = SxNdisSendNetBufferLists;
+    fChars.SendNetBufferListsCompleteHandler = SxNdisSendNetBufferListsComplete;
+    fChars.CancelSendNetBufferListsHandler = SxNdisCancelSendNetBufferLists;
+    fChars.ReceiveNetBufferListsHandler = SxNdisReceiveNetBufferLists;
+    fChars.ReturnNetBufferListsHandler = SxNdisReturnNetBufferLists;
+    
+    fChars.OidRequestHandler = SxNdisOidRequest;
+    fChars.OidRequestCompleteHandler = SxNdisOidRequestComplete;
+    fChars.CancelOidRequestHandler = SxNdisCancelOidRequest;
+    
+    fChars.NetPnPEventHandler = SxNdisNetPnPEvent;
+    fChars.StatusHandler = SxNdisStatus;
+    
+    NdisAllocateSpinLock(&SxExtensionListLock);
+    InitializeListHead(&SxExtensionList);
+
+    DriverObject->DriverUnload = SxNdisUnload;
+
+    status = NdisFRegisterFilterDriver(DriverObject,
+                                       (NDIS_HANDLE)SxDriverObject,
+                                       &fChars,
+                                       &SxDriverHandle);
+
+Cleanup:
+
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        if (SxDriverHandle != NULL)
+        {
+            NdisFDeregisterFilterDriver(SxDriverHandle);
+            SxDriverHandle = NULL;
+        }
+
+        NdisFreeSpinLock(&SxExtensionListLock);
+        
+        SxExtUninitialize();
+    }
+
+    return status;
+}
+
+
+//
+// Unload Routine
+// http://msdn.microsoft.com/en-us/library/ff564886(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisUnload(
+    PDRIVER_OBJECT DriverObject
+    )
+{
+    UNREFERENCED_PARAMETER(DriverObject);
+
+    SxExtUninitialize();
+    
+    NdisFDeregisterFilterDriver(SxDriverHandle);
+    NdisFreeSpinLock(&SxExtensionListLock);
+}
+
+
+//
+// FilterSetOptions Function
+// http://msdn.microsoft.com/en-us/library/ff549972(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisSetOptions(
+    NDIS_HANDLE NdisDriverHandle,
+    NDIS_HANDLE DriverContext
+    )
+{
+    UNREFERENCED_PARAMETER(NdisDriverHandle);
+    UNREFERENCED_PARAMETER(DriverContext);
+    return NDIS_STATUS_SUCCESS;
+}
+    
+
+//
+// FilterSetModuleOptions Function
+// http://msdn.microsoft.com/en-us/library/ff549970(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisSetFilterModuleOptions(
+    NDIS_HANDLE FilterModuleContext
+    )
+{
+    UNREFERENCED_PARAMETER(FilterModuleContext);
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+//
+// FilterAttach Function
+// http://msdn.microsoft.com/en-us/library/ff549905(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisAttach(
+    NDIS_HANDLE NdisFilterHandle,
+    NDIS_HANDLE SxDriverContext,
+    PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
+    )
+{
+    NDIS_STATUS status;
+    NDIS_FILTER_ATTRIBUTES sxAttributes;
+    ULONG switchObjectSize;
+    NDIS_SWITCH_CONTEXT switchContext;
+    NDIS_SWITCH_OPTIONAL_HANDLERS switchHandler;
+    PSX_SWITCH_OBJECT switchObject;
+    
+    UNREFERENCED_PARAMETER(SxDriverContext);
+
+    DEBUGP(DL_TRACE, ("===>SxAttach: NdisFilterHandle %p\n", NdisFilterHandle));
+
+    status = NDIS_STATUS_SUCCESS;
+    switchObject = NULL;
+
+    NT_ASSERT(SxDriverContext == (NDIS_HANDLE)SxDriverObject);
+
+    if (AttachParameters->MiniportMediaType != NdisMedium802_3)
+    {
+        status = NDIS_STATUS_INVALID_PARAMETER;
+        goto Cleanup;
+    }
+
+    switchHandler.Header.Type = NDIS_OBJECT_TYPE_SWITCH_OPTIONAL_HANDLERS;
+    switchHandler.Header.Size = NDIS_SIZEOF_SWITCH_OPTIONAL_HANDLERS_REVISION_1;
+    switchHandler.Header.Revision = NDIS_SWITCH_OPTIONAL_HANDLERS_REVISION_1;
+
+    status = NdisFGetOptionalSwitchHandlers(NdisFilterHandle,
+                                            &switchContext,
+                                            &switchHandler);
+
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        DEBUGP(DL_ERROR,
+               ("SxAttach: Extension is running in non-switch environment.\n"));
+        goto Cleanup;
+    }
+
+    switchObjectSize = sizeof(SX_SWITCH_OBJECT);
+    switchObject = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                         switchObjectSize,
+                                         SxExtAllocationTag);
+
+    if (switchObject == NULL)
+    {
+        status = NDIS_STATUS_RESOURCES;
+        goto Cleanup;
+    }
+
+    RtlZeroMemory(switchObject, switchObjectSize);
+
+    //
+    // Initialize NDIS related information.
+    //
+    switchObject->NdisFilterHandle = NdisFilterHandle;
+    switchObject->NdisSwitchContext = switchContext;
+    RtlCopyMemory(&switchObject->NdisSwitchHandlers,
+                  &switchHandler,
+                  sizeof(NDIS_SWITCH_OPTIONAL_HANDLERS));
+
+    //
+    // Let the extension create its own context.
+    //
+    status = SxExtCreateSwitch(switchObject,
+                               &(switchObject->ExtensionContext));
+
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        goto Cleanup;
+    }
+
+    //
+    // Register the object with NDIS because NDIS passes this object when it
+    // calls into the driver.
+    //
+    NdisZeroMemory(&sxAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
+    sxAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
+    sxAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
+    sxAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
+    sxAttributes.Flags = 0;
+
+    NDIS_DECLARE_FILTER_MODULE_CONTEXT(SX_SWITCH_OBJECT);
+    status = NdisFSetAttributes(NdisFilterHandle, switchObject, &sxAttributes);
+
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        DEBUGP(DL_ERROR, ("SxBase: Failed to set attributes.\n"));
+        goto Cleanup;
+    }
+
+    switchObject->ControlFlowState = SxSwitchAttached;
+    switchObject->DataFlowState = SxSwitchPaused;
+    
+    NdisAcquireSpinLock(&SxExtensionListLock);
+    InsertHeadList(&SxExtensionList, &switchObject->Link);
+    NdisReleaseSpinLock(&SxExtensionListLock);
+    
+Cleanup:
+
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        if (switchObject != NULL)
+        {
+            ExFreePool(switchObject);
+        }
+    }
+
+    DEBUGP(DL_TRACE, ("<===SxAttach: status %x\n", status));
+
+    return status;
+}
+
+
+//
+// FilterDetach Function
+// http://msdn.microsoft.com/en-us/library/ff549918(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisDetach(
+    NDIS_HANDLE FilterModuleContext
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+
+    DEBUGP(DL_TRACE, ("===>SxDetach: SxInstance %p\n", FilterModuleContext));
+
+    //
+    // The extension must be in paused state.
+    //
+    NT_ASSERT(switchObject->DataFlowState == SxSwitchPaused);
+    switchObject->ControlFlowState = SxSwitchDetached;
+    
+    KeMemoryBarrier();
+    
+    while(switchObject->PendingOidCount > 0)
+    {
+        NdisMSleep(1000);
+    }
+    
+    SxExtDeleteSwitch(switchObject, switchObject->ExtensionContext);
+
+    NdisAcquireSpinLock(&SxExtensionListLock);
+    RemoveEntryList(&switchObject->Link);
+    NdisReleaseSpinLock(&SxExtensionListLock);
+    
+    ExFreePool(switchObject);
+
+    //
+    // Alway return success.
+    //
+    DEBUGP(DL_TRACE, ("<===SxDetach Successfully\n"));
+
+    return;
+}
+
+
+//
+// FilterRestart Function
+// http://msdn.microsoft.com/en-us/library/ff549962(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisPause(
+    NDIS_HANDLE FilterModuleContext,
+    PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)(FilterModuleContext);
+
+    UNREFERENCED_PARAMETER(PauseParameters);
+
+    DEBUGP(DL_TRACE,
+           ("===>NDISLWF SxPause: SxInstance %p\n", FilterModuleContext));
+
+    SxExtPauseSwitch(switchObject, switchObject->ExtensionContext);
+           
+    //
+    // Set the flag that the filter is going to pause.
+    //
+    NT_ASSERT(switchObject->DataFlowState == SxSwitchRunning);
+    switchObject->DataFlowState = SxSwitchPaused;
+    
+    KeMemoryBarrier();
+    
+    while(switchObject->PendingInjectedNblCount > 0)
+    {
+        NdisMSleep(1000);
+    }
+
+    DEBUGP(DL_TRACE, ("<===SxPause: status %x\n", NDIS_STATUS_SUCCESS));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+//
+// FilterPause Function
+// http://msdn.microsoft.com/en-us/library/ff549957(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisRestart(
+    NDIS_HANDLE FilterModuleContext,
+    PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+    UNREFERENCED_PARAMETER(RestartParameters);
+
+    DEBUGP(DL_TRACE,
+           ("===>SxRestart: FilterModuleContext %p\n", FilterModuleContext));
+           
+    status = SxExtRestartSwitch(switchObject,
+                                switchObject->ExtensionContext);
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        status = NDIS_STATUS_RESOURCES;
+        goto Cleanup;
+    }
+
+    NT_ASSERT(switchObject->DataFlowState == SxSwitchPaused);
+    switchObject->DataFlowState = SxSwitchRunning;
+    
+    DEBUGP(DL_TRACE,
+           ("<===SxRestart: FilterModuleContext %p, status %x\n",
+            FilterModuleContext,
+            NDIS_STATUS_SUCCESS));
+
+Cleanup:
+    return status;
+}
+
+
+//
+// FilterOidRequest Function
+// http://msdn.microsoft.com/en-us/library/ff549954(v=VS.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisOidRequest(
+    NDIS_HANDLE FilterModuleContext,
+    PNDIS_OID_REQUEST OidRequest
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    NDIS_STATUS status;
+    PNDIS_OID_REQUEST clonedRequest=NULL;
+    PVOID *cloneRequestContext;
+    BOOLEAN completeOid = FALSE;
+    ULONG bytesNeeded = 0;
+   
+    status = NDIS_STATUS_SUCCESS;
+
+    DEBUGP(DL_TRACE, ("===>SxOidRequest: OidRequest %p.\n", OidRequest));
+    
+    NdisInterlockedIncrement(&switchObject->PendingOidCount);
+
+    status = NdisAllocateCloneOidRequest(switchObject->NdisFilterHandle,
+                                         OidRequest,
+                                         SxExtAllocationTag,
+                                         &clonedRequest);
+    if (status != NDIS_STATUS_SUCCESS)
+    {
+        DEBUGP(DL_WARN, ("FilerOidRequest: Cannot Clone OidRequest\n"));
+        goto Cleanup;
+    }
+
+    cloneRequestContext = (PVOID*)(&clonedRequest->SourceReserved[0]);
+    *cloneRequestContext = OidRequest;
+    
+    switch (clonedRequest->RequestType)
+    {           
+        case NdisRequestSetInformation:
+            status = SxpNdisProcessSetOid(switchObject,
+                                          clonedRequest,
+                                          &completeOid);
+            break;
+        
+        case NdisRequestMethod:
+            status = SxpNdisProcessMethodOid(switchObject,
+                                             clonedRequest,
+                                             &completeOid,
+                                             &bytesNeeded);
+
+            break;
+    }
+    
+    if (completeOid)
+    {
+        NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, clonedRequest);
+        OidRequest->DATA.METHOD_INFORMATION.BytesNeeded = bytesNeeded;
+        NdisInterlockedDecrement(&switchObject->PendingOidCount);
+        goto Cleanup;
+    }
+
+    status = NdisFOidRequest(switchObject->NdisFilterHandle, clonedRequest);
+
+    if (status != NDIS_STATUS_PENDING)
+    {
+        SxNdisOidRequestComplete(switchObject, clonedRequest, status);
+
+        //
+        // We must still return status as pending because we complete the
+        // request using NdisFOidRequestComplete() in SxOidRequestComplete().
+        //
+        status = NDIS_STATUS_PENDING;
+    }
+
+Cleanup:
+
+    DEBUGP(DL_TRACE, ("<===SxOidRequest: status %8x.\n", status));
+    return status;
+}
+
+
+//
+// FilterCancelOidRequest Function
+// http://msdn.microsoft.com/en-us/library/ff549911(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisCancelOidRequest(
+    NDIS_HANDLE FilterModuleContext,
+    PVOID RequestId
+    )
+{
+    UNREFERENCED_PARAMETER(FilterModuleContext);
+    UNREFERENCED_PARAMETER(RequestId);
+}
+
+
+//
+// FilterOidRequestComplete Function
+// http://msdn.microsoft.com/en-us/library/ff549956(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisOidRequestComplete(
+    NDIS_HANDLE FilterModuleContext,
+    PNDIS_OID_REQUEST NdisOidRequest,
+    NDIS_STATUS Status
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    PNDIS_OID_REQUEST originalRequest;
+    PVOID *oidRequestContext;
+    PNDIS_SWITCH_NIC_OID_REQUEST nicOidRequestBuf;
+    PNDIS_OBJECT_HEADER header;
+
+    DEBUGP(DL_TRACE,
+           ("===>SxOidRequestComplete, NdisOidRequest %p.\n", NdisOidRequest));
+
+    oidRequestContext = (PVOID*)(&NdisOidRequest->SourceReserved[0]);
+    originalRequest = (*oidRequestContext);
+
+    //
+    // This is the internal request
+    //
+    if (originalRequest == NULL)
+    {
+        SxpNdisCompleteInternalOidRequest(switchObject, NdisOidRequest, Status);
+        goto Cleanup;
+    }
+
+    //
+    // Copy the information from the returned request to the original request
+    //
+    switch(NdisOidRequest->RequestType)
+    {
+    case NdisRequestMethod:
+        originalRequest->DATA.METHOD_INFORMATION.OutputBufferLength =
+            NdisOidRequest->DATA.METHOD_INFORMATION.OutputBufferLength;
+        originalRequest->DATA.METHOD_INFORMATION.BytesRead =
+            NdisOidRequest->DATA.METHOD_INFORMATION.BytesRead;
+        originalRequest->DATA.METHOD_INFORMATION.BytesNeeded =
+            NdisOidRequest->DATA.METHOD_INFORMATION.BytesNeeded;
+        originalRequest->DATA.METHOD_INFORMATION.BytesWritten =
+            NdisOidRequest->DATA.METHOD_INFORMATION.BytesWritten;
+            
+        if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_NIC_REQUEST &&
+                switchObject->OldNicRequest != NULL)
+        {
+            nicOidRequestBuf = NdisOidRequest->DATA.METHOD_INFORMATION.InformationBuffer;
+            Status = SxExtProcessNicRequestComplete(switchObject,
+                                                    switchObject->ExtensionContext,
+                                                    nicOidRequestBuf->OidRequest,
+                                                    nicOidRequestBuf->SourcePortId,
+                                                    nicOidRequestBuf->SourceNicIndex,
+                                                    nicOidRequestBuf->DestinationPortId,
+                                                    nicOidRequestBuf->DestinationNicIndex,
+                                                    Status);
+            
+            originalRequest->DATA.METHOD_INFORMATION.InformationBuffer =
+                                                    switchObject->OldNicRequest;
+            switchObject->OldNicRequest = NULL;
+            ExFreePoolWithTag(nicOidRequestBuf, SxExtAllocationTag);
+        }
+        
+        break;
+
+    case NdisRequestSetInformation:
+        header = originalRequest->DATA.SET_INFORMATION.InformationBuffer;
+        
+        originalRequest->DATA.SET_INFORMATION.BytesRead =
+            NdisOidRequest->DATA.SET_INFORMATION.BytesRead;
+        originalRequest->DATA.SET_INFORMATION.BytesNeeded =
+            NdisOidRequest->DATA.SET_INFORMATION.BytesNeeded;
+            
+        if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_PORT_CREATE &&
+            Status != NDIS_STATUS_SUCCESS)
+        {
+            SxExtDeletePort(switchObject,
+                            switchObject->ExtensionContext,
+                            (PNDIS_SWITCH_PORT_PARAMETERS)header);
+        }
+        else if (NdisOidRequest->DATA.METHOD_INFORMATION.Oid == OID_SWITCH_PORT_CREATE &&
+                 Status != NDIS_STATUS_SUCCESS)
+        {
+            SxExtDeleteNic(switchObject,
+                           switchObject->ExtensionContext,
+                           (PNDIS_SWITCH_NIC_PARAMETERS)header);
+            
+        }
+
+        break;
+
+    case NdisRequestQueryInformation:
+    case NdisRequestQueryStatistics:
+    default:
+        originalRequest->DATA.QUERY_INFORMATION.BytesWritten =
+            NdisOidRequest->DATA.QUERY_INFORMATION.BytesWritten;
+        originalRequest->DATA.QUERY_INFORMATION.BytesNeeded =
+            NdisOidRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+        break;
+    }
+
+    (*oidRequestContext) = NULL;
+
+    NdisFreeCloneOidRequest(switchObject->NdisFilterHandle, NdisOidRequest);
+
+    NdisFOidRequestComplete(switchObject->NdisFilterHandle,
+                            originalRequest,
+                            Status);
+
+    DEBUGP(DL_TRACE, ("<===SxOidRequestComplete.\n"));
+    
+Cleanup:
+    NdisInterlockedDecrement(&switchObject->PendingOidCount);
+}
+
+
+//
+// FilterSendNetBufferLists Function
+// http://msdn.microsoft.com/en-us/library/ff549966(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisSendNetBufferLists(
+    NDIS_HANDLE FilterModuleContext,
+    PNET_BUFFER_LIST NetBufferLists,
+    NDIS_PORT_NUMBER PortNumber,
+    ULONG SendFlags
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    
+    UNREFERENCED_PARAMETER(PortNumber);
+
+    SxExtStartNetBufferListsIngress(switchObject,
+                                    switchObject->ExtensionContext,
+                                    NetBufferLists,
+                                    SendFlags);
+}
+
+
+//
+// FilterSendNetBufferListsComplete Function
+// http://msdn.microsoft.com/en-us/library/ff549967(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisSendNetBufferListsComplete(
+    NDIS_HANDLE FilterModuleContext,
+    PNET_BUFFER_LIST NetBufferLists,
+    ULONG SendCompleteFlags
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+
+    SxExtStartCompleteNetBufferListsIngress(switchObject,
+                                            switchObject->ExtensionContext,
+                                            NetBufferLists,
+                                            SendCompleteFlags);
+}
+
+
+//
+// FilterReceiveNetBufferLists Function
+// http://msdn.microsoft.com/en-us/library/ff549960(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisReceiveNetBufferLists(
+    NDIS_HANDLE FilterModuleContext,
+    PNET_BUFFER_LIST NetBufferLists,
+    NDIS_PORT_NUMBER PortNumber,
+    ULONG NumberOfNetBufferLists,
+    ULONG ReceiveFlags
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    
+    UNREFERENCED_PARAMETER(PortNumber);
+
+    SxExtStartNetBufferListsEgress(switchObject,
+                                   switchObject->ExtensionContext,
+                                   NetBufferLists,
+                                   NumberOfNetBufferLists,
+                                   ReceiveFlags);
+}
+
+
+//
+// FilterReturnNetBufferLists Function
+// http://msdn.microsoft.com/en-us/library/ff549964(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisReturnNetBufferLists(
+    NDIS_HANDLE FilterModuleContext,
+    PNET_BUFFER_LIST NetBufferLists,
+    ULONG ReturnFlags
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+
+    SxExtStartCompleteNetBufferListsEgress(switchObject,
+                                           switchObject->ExtensionContext,
+                                           NetBufferLists,
+                                           ReturnFlags);
+}
+
+
+//
+// FilterCancelSendNetBufferLists Function
+// http://msdn.microsoft.com/en-us/library/ff549915(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisCancelSendNetBufferLists(
+    NDIS_HANDLE FilterModuleContext,
+    PVOID CancelId
+    )
+{
+    UNREFERENCED_PARAMETER(FilterModuleContext);
+    UNREFERENCED_PARAMETER(CancelId);
+}
+
+
+//
+// FilterNetPnPEvent Function
+// http://msdn.microsoft.com/en-us/library/ff549952(v=vs.85).aspx
+//
+_Use_decl_annotations_
+NDIS_STATUS
+SxNdisNetPnPEvent(
+    NDIS_HANDLE FilterModuleContext,
+    PNET_PNP_EVENT_NOTIFICATION NetPnPEvent
+    )
+{
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    
+    if (NetPnPEvent->NetPnPEvent.NetEvent == NetEventSwitchActivate)
+    {   
+        //
+        // Switch Activation must be passed along regardless of successful
+        // initialization.
+        //
+        SxExtActivateSwitch(switchObject,
+                            switchObject->ExtensionContext);
+    }
+    
+    return NdisFNetPnPEvent(switchObject->NdisFilterHandle,
+                            NetPnPEvent);
+}
+
+
+//
+// FilterStatus Function
+// http://msdn.microsoft.com/en-us/library/ff549973(v=VS.85).aspx
+//
+_Use_decl_annotations_
+VOID
+SxNdisStatus(
+    NDIS_HANDLE FilterModuleContext,
+    PNDIS_STATUS_INDICATION StatusIndication
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    PSX_SWITCH_OBJECT switchObject = (PSX_SWITCH_OBJECT)FilterModuleContext;
+    PNDIS_SWITCH_NIC_STATUS_INDICATION nicIndication;
+    PNDIS_STATUS_INDICATION originalIndication;
+    
+    if (StatusIndication->Header.Type != NDIS_OBJECT_TYPE_STATUS_INDICATION ||
+        StatusIndication->Header.Revision != NDIS_STATUS_INDICATION_REVISION_1 ||
+        StatusIndication->Header.Size < NDIS_SIZEOF_STATUS_INDICATION_REVISION_1)
+    {
+        goto Cleanup;
+    }
+    
+    //
+    // Only NDIS_STATUS_SWITCH_NIC_STAUTUS indications need to be processed
+    // by switch extensions.
+    //
+    if (StatusIndication->StatusCode != NDIS_STATUS_SWITCH_NIC_STATUS)
+    {
+        goto Cleanup;
+    }
+    
+    nicIndication = StatusIndication->StatusBuffer;
+    
+    if (nicIndication->Header.Type != NDIS_OBJECT_TYPE_STATUS_INDICATION ||
+        nicIndication->Header.Revision != NDIS_SWITCH_NIC_STATUS_INDICATION_REVISION_1 ||
+        nicIndication->Header.Size < NDIS_SIZEOF_SWITCH_NIC_STATUS_REVISION_1)
+    {
+        goto Cleanup;
+    }
+    
+    originalIndication = nicIndication->StatusIndication;
+    
+    status = SxExtProcessNicStatus(switchObject,
+                                   switchObject->ExtensionContext,
+                                   originalIndication,
+                                   nicIndication->SourcePortId,
+                                   nicIndication->SourceNicIndex);
+                                   
+Cleanup:
+    if (status == NDIS_STATUS_SUCCESS)
+    {
+        NdisFIndicateStatus(switchObject->NdisFilterHandle,
+                            StatusIndication);
+    }
+
+    return;
+                           
+}
+
+
+NDIS_STATUS
+SxpNdisProcessSetOid(
+    __in PSX_SWITCH_OBJECT Switch,
+    __inout PNDIS_OID_REQUEST OidRequest,
+    __out PBOOLEAN Complete
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    NDIS_OID oid = OidRequest->DATA.SET_INFORMATION.Oid;
+    PNDIS_OBJECT_HEADER header;
+    ULONG bytesRestored = 0;
+    
+    *Complete = FALSE;
+    
+    header = OidRequest->DATA.SET_INFORMATION.InformationBuffer;
+    
+    if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != 0 &&
+        OidRequest->DATA.SET_INFORMATION.InformationBufferLength < 
+            sizeof(NDIS_OBJECT_HEADER))
+    {
+        status = NDIS_STATUS_NOT_SUPPORTED;
+        *Complete = TRUE;
+        goto Cleanup;
+    }
+    
+    if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength == 0)
+    {
+        *Complete = FALSE;
+        goto Cleanup;
+    }
+    
+    switch(oid)
+    {
+        case OID_SWITCH_PROPERTY_ADD:
+        case OID_SWITCH_PROPERTY_UPDATE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_PROPERTY_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PROPERTY_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            if (oid == OID_SWITCH_PROPERTY_ADD)
+            {
+                status = SxExtAddSwitchProperty(Switch,
+                                                Switch->ExtensionContext,
+                                                (PNDIS_SWITCH_PROPERTY_PARAMETERS)header);
+            }
+            else
+            {
+                status = SxExtUpdateSwitchProperty(Switch,
+                                                   Switch->ExtensionContext,
+                                                   (PNDIS_SWITCH_PROPERTY_PARAMETERS)header);
+            }
+            
+            if (status == NDIS_STATUS_NOT_SUPPORTED)
+            {
+                status = NDIS_STATUS_SUCCESS;
+            }
+            else
+            {
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            break;
+        case OID_SWITCH_PROPERTY_DELETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_PROPERTY_DELETE_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PROPERTY_DELETE_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            *Complete = SxExtDeleteSwitchProperty(Switch,
+                                                  Switch->ExtensionContext,
+                                                 (PNDIS_SWITCH_PROPERTY_DELETE_PARAMETERS)header);
+                                                 
+            break;
+        
+        case OID_SWITCH_PORT_PROPERTY_ADD:
+        case OID_SWITCH_PORT_PROPERTY_UPDATE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PROPERTY_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+        
+            if (oid == OID_SWITCH_PORT_PROPERTY_ADD)
+            {
+                status = SxExtAddPortProperty(Switch,
+                                              Switch->ExtensionContext,
+                                              (PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS)header);
+            }
+            else
+            {
+                status = SxExtUpdatePortProperty(Switch,
+                                                 Switch->ExtensionContext,
+                                                 (PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS)header);
+            }
+            
+            if (status == NDIS_STATUS_NOT_SUPPORTED)
+            {
+                status = NDIS_STATUS_SUCCESS;
+            }
+            else
+            {
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            break;
+        
+        case OID_SWITCH_PORT_PROPERTY_DELETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            *Complete = SxExtDeletePortProperty(Switch,
+                                                Switch->ExtensionContext,
+                                                (PNDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS)header);
+            
+            break;
+            
+        case OID_SWITCH_PORT_CREATE:
+        case OID_SWITCH_PORT_UPDATED:
+        case OID_SWITCH_PORT_TEARDOWN:
+        case OID_SWITCH_PORT_DELETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_PORT_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_PORT_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+        
+            if (oid == OID_SWITCH_PORT_CREATE)
+            {
+                status = SxExtCreatePort(Switch,
+                                         Switch->ExtensionContext,
+                                         (PNDIS_SWITCH_PORT_PARAMETERS)header);
+                                       
+                if (status != NDIS_STATUS_SUCCESS)
+                {
+                    *Complete = TRUE;
+                }
+            }
+            else if (oid == OID_SWITCH_PORT_UPDATED)
+            {   
+                SxExtUpdatePort(Switch,
+                                Switch->ExtensionContext,
+                                (PNDIS_SWITCH_PORT_PARAMETERS)header);
+            }
+            else if (oid == OID_SWITCH_PORT_TEARDOWN)
+            {   
+                SxExtTeardownPort(Switch,
+                                  Switch->ExtensionContext,
+                                  (PNDIS_SWITCH_PORT_PARAMETERS)header);
+            }
+            else
+            {
+                SxExtDeletePort(Switch,
+                                Switch->ExtensionContext,
+                                (PNDIS_SWITCH_PORT_PARAMETERS)header);
+            }
+        
+            break;
+        
+        case OID_SWITCH_NIC_CREATE:
+        case OID_SWITCH_NIC_CONNECT:
+        case OID_SWITCH_NIC_UPDATED:
+        case OID_SWITCH_NIC_DISCONNECT:
+        case OID_SWITCH_NIC_DELETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            if (oid == OID_SWITCH_NIC_CREATE)
+            {
+                status = SxExtCreateNic(Switch,
+                                        Switch->ExtensionContext,
+                                        (PNDIS_SWITCH_NIC_PARAMETERS)header);
+                if (status != NDIS_STATUS_SUCCESS)
+                {
+                    *Complete = TRUE;
+                }
+            }
+            else if (oid == OID_SWITCH_NIC_CONNECT)
+            {   
+                SxExtConnectNic(Switch,
+                                Switch->ExtensionContext,
+                                (PNDIS_SWITCH_NIC_PARAMETERS)header);
+            }
+            else if (oid == OID_SWITCH_NIC_UPDATED)
+            {
+                SxExtUpdateNic(Switch,
+                               Switch->ExtensionContext,
+                               (PNDIS_SWITCH_NIC_PARAMETERS)header);
+            }
+            else if (oid == OID_SWITCH_NIC_DISCONNECT)
+            {
+                SxExtDisconnectNic(Switch,
+                                   Switch->ExtensionContext,
+                                   (PNDIS_SWITCH_NIC_PARAMETERS)header);
+            }
+            else
+            {
+                SxExtDeleteNic(Switch,
+                               Switch->ExtensionContext,
+                               (PNDIS_SWITCH_NIC_PARAMETERS)header);
+            }
+            
+            break;
+        
+        case OID_SWITCH_NIC_RESTORE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                goto Cleanup;
+            }
+            
+            status = SxExtNicRestore(Switch,
+                                     Switch->ExtensionContext,
+                                     (PNDIS_SWITCH_NIC_SAVE_STATE)header,
+                                     &bytesRestored);
+                                     
+            if (status != NDIS_STATUS_SUCCESS)
+            {
+                *Complete = TRUE;
+            }
+            else if (bytesRestored > 0)
+            {
+                *Complete = TRUE;
+            }
+                                      
+            break;    
+
+        case OID_SWITCH_NIC_SAVE_COMPLETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            SxExtSaveNicComplete(Switch,
+                                 Switch->ExtensionContext,
+                                 (PNDIS_SWITCH_NIC_SAVE_STATE)header);    
+
+            break;
+            
+        case OID_SWITCH_NIC_RESTORE_COMPLETE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            SxExtNicRestoreComplete(Switch,
+                                    Switch->ExtensionContext,
+                                    (PNDIS_SWITCH_NIC_SAVE_STATE)header);    
+
+            break;
+            
+        default:
+            break;
+    }
+    
+Cleanup:
+    return status;
+}
+
+
+NDIS_STATUS
+SxpNdisProcessMethodOid(
+    __in PSX_SWITCH_OBJECT Switch,
+    __inout PNDIS_OID_REQUEST OidRequest,
+    __out PBOOLEAN Complete,
+    __out PULONG BytesNeeded
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    NDIS_OID oid = OidRequest->DATA.SET_INFORMATION.Oid;
+    PNDIS_OBJECT_HEADER header;
+    PNDIS_SWITCH_NIC_OID_REQUEST nicOidRequest;
+    PNDIS_SWITCH_NIC_OID_REQUEST newNicOidRequest = NULL;
+    NDIS_SWITCH_PORT_ID destPort, sourcePort;
+    NDIS_SWITCH_NIC_INDEX destNic, sourceNic;
+    ULONG bytesWritten = 0;
+    ULONG bytesNeeded = 0;
+    
+    *Complete = FALSE;
+    *BytesNeeded = 0;
+    
+    header = OidRequest->DATA.METHOD_INFORMATION.InformationBuffer;
+    
+    switch(oid)
+    {
+        case OID_SWITCH_FEATURE_STATUS_QUERY:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            *Complete = SxExtQuerySwitchFeatureStatus(Switch,
+                                                      Switch->ExtensionContext,
+                                                      (PNDIS_SWITCH_FEATURE_STATUS_PARAMETERS)header,
+                                                      BytesNeeded);
+                                                      
+            if (*BytesNeeded > 0)
+            {
+                status = NDIS_STATUS_BUFFER_TOO_SHORT;
+            }
+        
+            break;
+            
+        case OID_SWITCH_PORT_FEATURE_STATUS_QUERY:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            *Complete = SxExtQueryPortFeatureStatus(Switch,
+                                                    Switch->ExtensionContext,
+                                                    (PNDIS_SWITCH_PORT_FEATURE_STATUS_PARAMETERS)header,
+                                                    BytesNeeded);
+                                                    
+            if (*BytesNeeded > 0)
+            {
+                status = NDIS_STATUS_BUFFER_TOO_SHORT;
+            }
+        
+            break;
+            
+        case OID_SWITCH_NIC_REQUEST:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_OID_REQUEST_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            nicOidRequest = (PNDIS_SWITCH_NIC_OID_REQUEST)header;
+            
+            sourcePort = nicOidRequest->SourcePortId;
+            sourceNic = nicOidRequest->SourceNicIndex;
+            destPort = nicOidRequest->DestinationPortId;
+            destNic = nicOidRequest->DestinationNicIndex;
+            
+            status = SxExtProcessNicRequest(Switch,
+                                            Switch->ExtensionContext,
+                                            nicOidRequest->OidRequest,
+                                            &sourcePort,
+                                            &sourceNic,
+                                            &destPort,
+                                            &destNic);
+                                           
+            if (status != NDIS_STATUS_SUCCESS)
+            {
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+                                           
+            if (sourcePort != nicOidRequest->SourcePortId ||
+                sourceNic != nicOidRequest->SourceNicIndex ||
+                destPort != nicOidRequest->DestinationPortId ||
+                destNic != nicOidRequest->DestinationNicIndex)
+            {
+                ASSERT(Switch->OldNicRequest == NULL);
+                Switch->OldNicRequest = nicOidRequest;
+                
+                newNicOidRequest = (PNDIS_SWITCH_NIC_OID_REQUEST)ExAllocatePoolWithTag(
+                                                                    NonPagedPoolNx,
+                                                                    sizeof(NDIS_SWITCH_NIC_OID_REQUEST),
+                                                                    SxExtAllocationTag);
+                                                                    
+                if (newNicOidRequest == NULL)
+                {
+                    status = NDIS_STATUS_RESOURCES;
+                    *Complete = TRUE;
+                    goto Cleanup;
+                }
+                                                                    
+                newNicOidRequest->Header = nicOidRequest->Header;
+                newNicOidRequest->SourcePortId = sourcePort;
+                newNicOidRequest->SourceNicIndex = sourceNic;
+                newNicOidRequest->DestinationPortId = destPort;
+                newNicOidRequest->DestinationNicIndex = destNic;
+                newNicOidRequest->OidRequest = nicOidRequest->OidRequest;
+                        
+                OidRequest->DATA.METHOD_INFORMATION.InformationBuffer = newNicOidRequest;
+            }
+        
+            break;
+            
+        case OID_SWITCH_NIC_SAVE:
+            if (header->Type != NDIS_OBJECT_TYPE_DEFAULT ||
+                header->Revision < NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1 ||
+                header->Size < NDIS_SIZEOF_NDIS_SWITCH_NIC_SAVE_STATE_REVISION_1)
+            {
+                status = NDIS_STATUS_NOT_SUPPORTED;
+                *Complete = TRUE;
+                goto Cleanup;
+            }
+            
+            status = SxExtSaveNic(Switch,
+                                  Switch->ExtensionContext,
+                                  (PNDIS_SWITCH_NIC_SAVE_STATE)header,
+                                  &bytesWritten,
+                                  &bytesNeeded);
+                                       
+            if (status == NDIS_STATUS_SUCCESS &&
+                bytesWritten > 0)
+            {
+                *Complete = TRUE;
+            }
+            else if (status == NDIS_STATUS_BUFFER_TOO_SHORT)
+            {
+                *BytesNeeded = ((PNDIS_SWITCH_NIC_SAVE_STATE)header)->SaveDataOffset +
+                                bytesNeeded;
+                *Complete = TRUE;
+            }
+            else if (status != NDIS_STATUS_SUCCESS)
+            {
+                *Complete = TRUE;
+            }
+            
+            break;
+            
+        default:
+            break;
+    }
+    
+Cleanup:
+    return status;
+}
+
+
+VOID
+SxpNdisCompleteInternalOidRequest(
+    __in PSX_SWITCH_OBJECT Switch,
+    __in PNDIS_OID_REQUEST NdisRequest,
+    __in NDIS_STATUS Status
+    )
+/*++
+
+Routine Description:
+
+    NDIS entry point indicating completion of a pended NDIS_OID_REQUEST.
+
+Arguments:
+
+    Switch - pointer to switch object.
+
+    NdisRequest - pointer to NDIS request
+
+    Status - Status of request completion
+
+Return Value:
+
+    None
+
+--*/
+{
+    PSX_OID_REQUEST oidRequest;
+    ULONG bytesNeeded;
+    
+    UNREFERENCED_PARAMETER(Switch);
+
+    bytesNeeded = 0;
+    oidRequest = NULL;
+
+    switch (NdisRequest->RequestType)
+    {
+    case NdisRequestSetInformation:
+        bytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
+        break;
+
+    case NdisRequestQueryInformation:
+        bytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+        break;
+
+    case NdisRequestMethod:
+        bytesNeeded = NdisRequest->DATA.METHOD_INFORMATION.BytesNeeded;
+        break;
+    }
+
+    //
+    // Get at the request context.
+    //
+    oidRequest = CONTAINING_RECORD(NdisRequest, SX_OID_REQUEST, NdisOidRequest);
+
+    //
+    // Save away the completion status.
+    //
+    oidRequest->Status = Status;
+    
+    //
+    // Save bytesNeeded
+    //
+    oidRequest->BytesNeeded = bytesNeeded;
+
+    //
+    // Wake up the thread blocked for this request to complete.
+    //
+    NdisSetEvent(&oidRequest->ReqEvent);
+}
+
diff --git a/datapath-windows/base/SxBase.h b/datapath-windows/base/SxBase.h
new file mode 100644
index 0000000..98bcf01
--- /dev/null
+++ b/datapath-windows/base/SxBase.h
@@ -0,0 +1,168 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+    SxBase.c
+
+Abstract:
+
+    This file contains the common code for building a switch extension. This
+    file includes all the standard NDIS handling and exposes a function based
+    interface for the control path and data path. This also has reusable code
+    for basic operations such as pause/resume handling etc.
+
+
+--*/
+
+extern NDIS_STRING SxExtensionFriendlyName;
+extern NDIS_STRING SxExtensionGuid;
+
+typedef enum _SX_SWITCH_DATAFLOW_STATE
+{
+    SxSwitchPaused,
+    SxSwitchRunning
+} SX_SWITCH_DATAFLOW_STATE, *PSX_SWITCH_DATAFLOW_STATE;
+
+typedef enum _SX_SWITCH_CONTROFLOW_STATE
+{
+    SxSwitchUnknown,
+    SxSwitchAttached,
+    SxSwitchDetached
+} SX_SWITCH_CONTROLFLOW_STATE, *PSX_SWITCH_CONTROLFLOW_STATE;
+
+typedef struct _SX_SWITCH_OBJECT
+{
+    //
+    // The Link *must* always be the first field.
+    //
+    LIST_ENTRY Link;
+
+    //
+    // The extension context is the context used in the specific logic
+    // of this extension.
+    // This is allocated and returned in SxExtSwitchCreate
+    //
+    PNDIS_HANDLE ExtensionContext;
+
+    //
+    // Ndis related fields.
+    //
+    NDIS_HANDLE NdisFilterHandle;
+    NDIS_SWITCH_CONTEXT NdisSwitchContext;
+    NDIS_SWITCH_OPTIONAL_HANDLERS NdisSwitchHandlers;
+
+    //
+    // Switch state.
+    //
+    SX_SWITCH_DATAFLOW_STATE DataFlowState;
+    SX_SWITCH_CONTROLFLOW_STATE ControlFlowState;
+    
+    //
+    // Management fields.
+    //
+    volatile LONG PendingInjectedNblCount;
+    volatile LONG PendingOidCount;
+    
+    //
+    // Control Path Management.
+    //
+    PNDIS_SWITCH_NIC_OID_REQUEST OldNicRequest;
+    
+} SX_SWITCH_OBJECT, *PSX_SWITCH_OBJECT;
+
+typedef struct _SX_OID_REQUEST
+{
+    NDIS_OID_REQUEST NdisOidRequest;
+    NDIS_EVENT ReqEvent;
+    NDIS_STATUS Status;
+    ULONG BytesNeeded;
+
+} SX_OID_REQUEST, *PSX_OID_REQUEST;
+
+typedef struct _FILTER_DEVICE_EXTENSION
+{
+    ULONG            Signature;
+    NDIS_HANDLE      Handle;
+} FILTER_DEVICE_EXTENSION, *PFILTER_DEVICE_EXTENSION;
+
+
+//
+// Function prototypes
+//
+DRIVER_INITIALIZE DriverEntry;
+
+DRIVER_UNLOAD SxNdisUnload;
+
+FILTER_SET_OPTIONS SxNdisSetOptions;
+
+FILTER_SET_MODULE_OPTIONS SxNdisSetFilterModuleOptions;
+
+FILTER_ATTACH SxNdisAttach;
+
+FILTER_DETACH SxNdisDetach;
+
+FILTER_PAUSE SxNdisPause;
+
+FILTER_RESTART SxNdisRestart;
+
+FILTER_OID_REQUEST SxNdisOidRequest;
+
+FILTER_CANCEL_OID_REQUEST SxNdisCancelOidRequest;
+
+FILTER_OID_REQUEST_COMPLETE SxNdisOidRequestComplete;
+
+FILTER_SEND_NET_BUFFER_LISTS SxNdisSendNetBufferLists;
+
+FILTER_RETURN_NET_BUFFER_LISTS SxNdisReturnNetBufferLists;
+
+FILTER_SEND_NET_BUFFER_LISTS_COMPLETE SxNdisSendNetBufferListsComplete;
+
+FILTER_RECEIVE_NET_BUFFER_LISTS SxNdisReceiveNetBufferLists;
+
+FILTER_CANCEL_SEND_NET_BUFFER_LISTS SxNdisCancelSendNetBufferLists;
+
+FILTER_STATUS SxNdisStatus;
+
+FILTER_NET_PNP_EVENT SxNdisNetPnPEvent;
+
+VOID
+SxpNdisCompleteInternalOidRequest(
+    __in PSX_SWITCH_OBJECT Switch,
+    __in PNDIS_OID_REQUEST NdisRequest,
+    __in NDIS_STATUS Status
+    );
+
+
+//
+// Some debug stuff.
+//
+#define DL_EXTRA_LOUD       20
+#define DL_VERY_LOUD        10
+#define DL_LOUD             8
+#define DL_INFO             6
+#define DL_TRACE            5
+#define DL_WARN             4
+#define DL_ERROR            2
+#define DL_FATAL            0
+
+#if DBG
+
+extern ULONG SxDebugLevel;
+
+#define DEBUGP(lev, stmt)                                               \
+        {                                                               \
+            if ((lev) <= SxDebugLevel)                                  \
+            {                                                           \
+                DbgPrint("%S: ",SxExtServiceName); DbgPrint stmt;       \
+            }                                                           \
+        }
+
+#else
+
+#define DEBUGP(lev, stmt)
+
+#endif
+
+
diff --git a/datapath-windows/base/SxLibrary.c b/datapath-windows/base/SxLibrary.c
new file mode 100644
index 0000000..5beb73d
--- /dev/null
+++ b/datapath-windows/base/SxLibrary.c
@@ -0,0 +1,839 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+    SxLibrary.c
+
+Abstract:
+
+    This file contains the common library functions that can be used
+    by any extension using the SxBase library.
+
+
+--*/
+
+#include "precomp.h"
+
+VOID
+SxLibSendNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendFlags,
+    _In_ ULONG NumInjectedNetBufferLists
+    )
+{
+    BOOLEAN dispatch;
+    BOOLEAN sameSource;
+    ULONG sendCompleteFlags;
+    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
+    PNET_BUFFER_LIST curNbl, nextNbl;
+    ULONG numNbls = 0;
+    PNET_BUFFER_LIST dropNbl = NULL;
+    PNET_BUFFER_LIST *curDropNbl = &dropNbl;
+    NDIS_SWITCH_PORT_ID curSourcePort;
+    NDIS_STRING filterReason;
+    
+    dispatch = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
+    sameSource = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_SWITCH_SINGLE_SOURCE);
+    
+    InterlockedAdd(&Switch->PendingInjectedNblCount, NumInjectedNetBufferLists);
+    KeMemoryBarrier();
+    
+    if (Switch->DataFlowState != SxSwitchRunning)
+    {
+        RtlInitUnicodeString(&filterReason, L"Extension Paused");
+        
+        sendCompleteFlags = (dispatch) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0;
+        sendCompleteFlags |= (sameSource) ? NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE : 0;
+        
+        fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists);
+    
+        if (sameSource)
+        {
+            for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next)
+            {
+                ++numNbls;
+            }
+            
+            Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                         Switch->NdisSwitchContext,
+                                         &SxExtensionGuid,
+                                         &SxExtensionFriendlyName,
+                                         fwdDetail->SourcePortId,
+                                         NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                         numNbls,
+                                         NetBufferLists,
+                                         &filterReason);
+                                         
+            SxExtStartCompleteNetBufferListsIngress(Switch,
+                                                    Switch->ExtensionContext,
+                                                    NetBufferLists,
+                                                    sendCompleteFlags);    
+        }
+        else
+        {
+            curSourcePort = fwdDetail->SourcePortId;
+            for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl)
+            {
+                nextNbl = curNbl->Next;
+                curNbl->Next = NULL;
+                
+                fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
+                
+                if(curSourcePort == fwdDetail->SourcePortId)
+                {
+                    *curDropNbl = curNbl;
+                    curDropNbl = &(curNbl->Next);
+                    ++numNbls;
+                }
+                else
+                {
+                    Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                                 Switch->NdisSwitchContext,
+                                                 &SxExtensionGuid,
+                                                 &SxExtensionFriendlyName,
+                                                 curSourcePort,
+                                                 NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                                 numNbls,
+                                                 dropNbl,
+                                                 &filterReason);
+                     
+                    SxExtStartCompleteNetBufferListsIngress(Switch,
+                                                            Switch->ExtensionContext,
+                                                            dropNbl,
+                                                            sendCompleteFlags);
+
+                    numNbls = 1;
+                    dropNbl = curNbl;
+                    curDropNbl = &(curNbl->Next);
+                    curSourcePort = fwdDetail->SourcePortId;
+                }
+            }
+            
+            Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                             Switch->NdisSwitchContext,
+                                             &SxExtensionGuid,
+                                             &SxExtensionFriendlyName,
+                                             curSourcePort,
+                                             NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                             numNbls,
+                                             dropNbl,
+                                             &filterReason);
+                 
+            SxExtStartCompleteNetBufferListsIngress(Switch,
+                                                    Switch->ExtensionContext,
+                                                    dropNbl,
+                                                    sendCompleteFlags);
+        }                                
+                                            
+        goto Cleanup;
+    }
+    
+    NdisFSendNetBufferLists(Switch->NdisFilterHandle,
+                            NetBufferLists,
+                            NDIS_DEFAULT_PORT_NUMBER,
+                            SendFlags);
+                                
+Cleanup:
+    return;
+}
+
+
+VOID
+SxLibSendNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG NumberOfNetBufferLists,
+    _In_ ULONG ReceiveFlags
+    )
+{
+    BOOLEAN dispatch, sameSource;
+    NDIS_SWITCH_PORT_ID sourcePortId;
+    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
+    ULONG returnFlags;
+    NDIS_SWITCH_PORT_ID curSourcePort;
+    PNET_BUFFER_LIST curNbl, nextNbl;
+    ULONG numNbls;
+    PNET_BUFFER_LIST dropNbl = NULL;
+    PNET_BUFFER_LIST *curDropNbl = &dropNbl;
+    NDIS_STRING filterReason;
+    
+    dispatch = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
+    sameSource = NDIS_TEST_RECEIVE_FLAG(ReceiveFlags, NDIS_RECEIVE_FLAGS_SWITCH_SINGLE_SOURCE);
+                          
+    if (Switch->DataFlowState != SxSwitchRunning)
+    {
+        RtlInitUnicodeString(&filterReason, L"Extension Paused");
+        
+        returnFlags = (dispatch) ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0;
+        returnFlags |= NDIS_RETURN_FLAGS_SWITCH_SINGLE_SOURCE;
+        
+        fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists);
+        
+        if (sameSource)
+        {
+            sourcePortId = fwdDetail->SourcePortId;
+            
+            Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                                     Switch->NdisSwitchContext,
+                                                     &SxExtensionGuid,
+                                                     &SxExtensionFriendlyName,
+                                                     sourcePortId,
+                                                     NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                                     NumberOfNetBufferLists,
+                                                     NetBufferLists,
+                                                     &filterReason);
+                                                     
+            SxExtStartCompleteNetBufferListsEgress(Switch,
+                                                   Switch->ExtensionContext,
+                                                   NetBufferLists,
+                                                   returnFlags);
+        }
+        else
+        {
+            curSourcePort = fwdDetail->SourcePortId;
+            numNbls = 0;
+            for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl)
+            {
+                nextNbl = curNbl->Next;
+                curNbl->Next = NULL;
+                
+                fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
+                
+                if(curSourcePort == fwdDetail->SourcePortId)
+                {
+                    *curDropNbl = curNbl;
+                    curDropNbl = &(curNbl->Next);
+                    ++numNbls;
+                }
+                else
+                {
+                    Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                                 Switch->NdisSwitchContext,
+                                                 &SxExtensionGuid,
+                                                 &SxExtensionFriendlyName,
+                                                 curSourcePort,
+                                                 NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                                 numNbls,
+                                                 dropNbl,
+                                                 &filterReason);
+                     
+                    SxExtStartCompleteNetBufferListsEgress(Switch,
+                                                           Switch->ExtensionContext,
+                                                           dropNbl,
+                                                           returnFlags);
+
+                    numNbls = 1;
+                    dropNbl = curNbl;
+                    curDropNbl = &(curNbl->Next);
+                    curSourcePort = fwdDetail->SourcePortId;
+                }
+            }
+            
+            Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+                                             Switch->NdisSwitchContext,
+                                             &SxExtensionGuid,
+                                             &SxExtensionFriendlyName,
+                                             curSourcePort,
+                                             NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+                                             numNbls,
+                                             dropNbl,
+                                             &filterReason);
+                 
+            SxExtStartCompleteNetBufferListsEgress(Switch,
+                                                   Switch->ExtensionContext,
+                                                   dropNbl,
+                                                   returnFlags);
+        }             
+        
+        goto Cleanup;
+    }
+    
+    NdisFIndicateReceiveNetBufferLists(Switch->NdisFilterHandle,
+                                       NetBufferLists,
+                                       NDIS_DEFAULT_PORT_NUMBER,
+                                       NumberOfNetBufferLists,
+                                       ReceiveFlags);
+                                
+Cleanup:
+    return;
+}
+
+VOID
+SxLibCompleteNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG ReturnFlags
+    )
+{
+    NdisFReturnNetBufferLists(Switch->NdisFilterHandle,
+                              NetBufferLists,
+                              ReturnFlags);
+}
+
+
+VOID
+SxLibCompleteNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendCompleteFlags
+    )
+{
+    NdisFSendNetBufferListsComplete(Switch->NdisFilterHandle,
+                                    NetBufferLists,
+                                    SendCompleteFlags);
+}
+
+VOID
+SxLibCompletedInjectedNetBufferLists(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ ULONG NumInjectedNetBufferLists
+    )
+{
+    LONG subtract = -(LONG)NumInjectedNetBufferLists;
+    InterlockedAdd(&Switch->PendingInjectedNblCount, subtract);
+}
+
+
+NDIS_STATUS
+SxLibIssueOidRequest(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_REQUEST_TYPE RequestType,
+    _In_ NDIS_OID Oid,
+    _In_opt_ PVOID InformationBuffer,
+    _In_ ULONG InformationBufferLength,
+    _In_ ULONG OutputBufferLength,
+    _In_ ULONG MethodId,
+    _In_ UINT Timeout,
+    _Out_ PULONG BytesNeeded
+    )
+{
+    NDIS_STATUS status;
+    PSX_OID_REQUEST oidRequest;
+    PNDIS_OID_REQUEST ndisOidRequest;
+    ULONG bytesNeeded;
+    BOOLEAN asyncCompletion;
+
+    status = NDIS_STATUS_SUCCESS;
+    oidRequest = NULL;
+    bytesNeeded = 0;
+    asyncCompletion = FALSE;
+
+    NdisInterlockedIncrement(&Switch->PendingOidCount);
+
+    if (Switch->ControlFlowState != SxSwitchAttached)
+    {
+        status = NDIS_STATUS_CLOSING;
+        goto Cleanup;
+    }
+
+    //
+    // Dynamically allocate filter request so that we can handle asynchronous
+    // completion.
+    //
+    oidRequest = (PSX_OID_REQUEST)ExAllocatePoolWithTag(NonPagedPoolNx,
+                                                        sizeof(SX_OID_REQUEST),
+                                                        SxExtAllocationTag);
+    if (oidRequest == NULL)
+    {
+        goto Cleanup;
+    }
+
+    NdisZeroMemory(oidRequest, sizeof(SX_OID_REQUEST));
+    ndisOidRequest = &oidRequest->NdisOidRequest;
+    NdisInitializeEvent(&oidRequest->ReqEvent);
+
+    ndisOidRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+    ndisOidRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+    ndisOidRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
+    ndisOidRequest->RequestType = RequestType;
+    ndisOidRequest->Timeout = Timeout;
+
+    switch (RequestType)
+    {
+    case NdisRequestQueryInformation:
+         ndisOidRequest->DATA.QUERY_INFORMATION.Oid = Oid;
+         ndisOidRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+             InformationBuffer;
+         ndisOidRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+             InformationBufferLength;
+        break;
+
+    case NdisRequestSetInformation:
+         ndisOidRequest->DATA.SET_INFORMATION.Oid = Oid;
+         ndisOidRequest->DATA.SET_INFORMATION.InformationBuffer =
+             InformationBuffer;
+         ndisOidRequest->DATA.SET_INFORMATION.InformationBufferLength =
+             InformationBufferLength;
+        break;
+
+    case NdisRequestMethod:
+         ndisOidRequest->DATA.METHOD_INFORMATION.Oid = Oid;
+         ndisOidRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
+         ndisOidRequest->DATA.METHOD_INFORMATION.InformationBuffer =
+             InformationBuffer;
+         ndisOidRequest->DATA.METHOD_INFORMATION.InputBufferLength =
+             InformationBufferLength;
+         ndisOidRequest->DATA.METHOD_INFORMATION.OutputBufferLength =
+             OutputBufferLength;
+         break;
+
+    default:
+        NT_ASSERT(FALSE);
+        break;
+    }
+
+    ndisOidRequest->RequestId = (PVOID)SxExtOidRequestId;
+    status = NdisFOidRequest(Switch->NdisFilterHandle, ndisOidRequest);
+
+    if (status == NDIS_STATUS_PENDING)
+    {
+        asyncCompletion = TRUE;
+        NdisWaitEvent(&oidRequest->ReqEvent, 0);
+    }
+    else
+    {
+        SxpNdisCompleteInternalOidRequest(Switch, ndisOidRequest, status);
+    }
+
+    bytesNeeded = oidRequest->BytesNeeded;
+    status = oidRequest->Status;
+
+Cleanup:
+
+    if (BytesNeeded != NULL)
+    {
+        *BytesNeeded = bytesNeeded;
+    }
+    
+    if (!asyncCompletion)
+    {
+        NdisInterlockedDecrement(&Switch->PendingOidCount);
+    }
+    
+    if (oidRequest != NULL)
+    {
+        ExFreePoolWithTag(oidRequest, SxExtAllocationTag);
+    }
+    
+    return status;
+}
+
+
+NDIS_STATUS
+SxLibGetSwitchParametersUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Out_ PNDIS_SWITCH_PARAMETERS SwitchParameters
+    )
+{
+    NDIS_STATUS status;
+    
+    SwitchParameters->Header.Revision = NDIS_SWITCH_PARAMETERS_REVISION_1;
+    SwitchParameters->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+    SwitchParameters->Header.Size = sizeof(NDIS_SWITCH_PARAMETERS);
+    
+    status = SxLibIssueOidRequest(Switch,
+                                  NdisRequestQueryInformation,
+                                  OID_SWITCH_PARAMETERS,
+                                  SwitchParameters,
+                                  sizeof(NDIS_SWITCH_PARAMETERS),
+                                  0,
+                                  0,
+                                  0,
+                                  NULL);
+                                  
+    return status;
+}
+
+
+NDIS_STATUS
+SxLibGetPortArrayUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Out_ PNDIS_SWITCH_PORT_ARRAY *PortArray
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    ULONG BytesNeeded = 0;
+    PNDIS_SWITCH_PORT_ARRAY portArray = NULL;
+    ULONG arrayLength = 0;
+    
+    do 
+    {
+        if (portArray != NULL)
+        {
+            ExFreePoolWithTag(portArray, SxExtAllocationTag);
+        }
+        
+        if (BytesNeeded != 0)
+        {
+            arrayLength = BytesNeeded;
+            portArray = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                             arrayLength,
+                                             SxExtAllocationTag);
+            
+            if (portArray == NULL)
+            {
+                status = NDIS_STATUS_RESOURCES;
+                goto Cleanup;
+            }
+            
+            portArray->Header.Revision = NDIS_SWITCH_PORT_ARRAY_REVISION_1;
+            portArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+            portArray->Header.Size = (USHORT)arrayLength;
+        }
+    
+        status = SxLibIssueOidRequest(Switch,
+                                      NdisRequestQueryInformation,
+                                      OID_SWITCH_PORT_ARRAY,
+                                      portArray,
+                                      arrayLength,
+                                      0,
+                                      0,
+                                      0,
+                                      &BytesNeeded);
+        
+    } while(status == NDIS_STATUS_INVALID_LENGTH);
+    
+    *PortArray = portArray;
+Cleanup:
+    if (status != NDIS_STATUS_SUCCESS &&
+        portArray != NULL)
+    {
+        ExFreePoolWithTag(portArray, SxExtAllocationTag);
+    }
+    
+    return status;
+}
+
+
+NDIS_STATUS
+SxLibGetNicArrayUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Out_ PNDIS_SWITCH_NIC_ARRAY *NicArray
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    ULONG BytesNeeded = 0;
+    PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
+    ULONG arrayLength = 0;
+    
+    do 
+    {
+        if (nicArray != NULL)
+        {
+            ExFreePoolWithTag(nicArray, SxExtAllocationTag);
+        }
+        
+        if (BytesNeeded != 0)
+        {
+            arrayLength = BytesNeeded;
+            nicArray = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                             arrayLength,
+                                             SxExtAllocationTag);
+            
+            if (nicArray == NULL)
+            {
+                status = NDIS_STATUS_RESOURCES;
+                goto Cleanup;
+            }
+            
+            nicArray->Header.Revision = NDIS_SWITCH_PORT_ARRAY_REVISION_1;
+            nicArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+            nicArray->Header.Size = (USHORT)arrayLength;
+        }
+    
+        status = SxLibIssueOidRequest(Switch,
+                                      NdisRequestQueryInformation,
+                                      OID_SWITCH_NIC_ARRAY,
+                                      nicArray,
+                                      arrayLength,
+                                      0,
+                                      0,
+                                      0,
+                                      &BytesNeeded);
+        
+    } while(status == NDIS_STATUS_INVALID_LENGTH);
+    
+    *NicArray = nicArray;
+Cleanup:
+    if (status != NDIS_STATUS_SUCCESS &&
+        nicArray != NULL)
+    {
+        ExFreePoolWithTag(nicArray, SxExtAllocationTag);
+    }
+    
+    return status;
+}
+
+
+NDIS_STATUS
+SxLibGetSwitchPropertyUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PROPERTY_TYPE PropertyType,
+    _In_opt_ PNDIS_SWITCH_OBJECT_ID PropertyId,
+    _Outptr_ PNDIS_SWITCH_PROPERTY_ENUM_PARAMETERS *SwitchPropertyEnumParameters
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    NDIS_SWITCH_PROPERTY_ENUM_PARAMETERS propertyParameters;
+    ULONG bytesNeeded = 0;
+    PNDIS_SWITCH_PROPERTY_ENUM_PARAMETERS outputBuffer = NULL;
+    USHORT outputBufferLength = sizeof(NDIS_SWITCH_PROPERTY_ENUM_PARAMETERS);
+    
+    propertyParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+    propertyParameters.Header.Revision = NDIS_SWITCH_PROPERTY_ENUM_PARAMETERS_REVISION_1;
+    
+    propertyParameters.PropertyType = PropertyType;
+    propertyParameters.SerializationVersion = NDIS_SWITCH_OBJECT_SERIALIZATION_VERSION_1;
+    
+    //
+    // For Built-in properties, the ID is unnecessary.
+    //
+    if (PropertyId != NULL)
+    {
+        NdisMoveMemory(&propertyParameters.PropertyId,
+                       PropertyId,
+                       sizeof(NDIS_SWITCH_OBJECT_ID));
+    }
+    else
+    {
+        ASSERT(PropertyType != NdisSwitchPropertyTypeCustom);
+    }
+    
+    outputBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                         outputBufferLength,
+                                         SxExtAllocationTag);
+                                         
+    if (outputBuffer == NULL)
+    {
+        status = NDIS_STATUS_RESOURCES;
+        goto Cleanup;
+    }
+    
+    do 
+    {
+        if (bytesNeeded != 0)
+        {
+            ExFreePoolWithTag(outputBuffer, SxExtAllocationTag);
+
+            outputBufferLength = (USHORT)bytesNeeded;
+            outputBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                                 outputBufferLength,
+                                                 SxExtAllocationTag);
+            
+            if (outputBuffer == NULL)
+            {
+                status = NDIS_STATUS_RESOURCES;
+                goto Cleanup;
+            }
+        }
+        
+        if(outputBufferLength >= sizeof(propertyParameters))
+        {
+            NdisMoveMemory(outputBuffer, &propertyParameters, sizeof(propertyParameters));
+            
+        }
+    
+        status = SxLibIssueOidRequest(Switch,
+                                      NdisRequestMethod,
+                                      OID_SWITCH_PROPERTY_ENUM,
+                                      outputBuffer,
+                                      sizeof(propertyParameters),
+                                      outputBufferLength,
+                                      0,
+                                      0,
+                                      &bytesNeeded);
+        
+    } while(status == NDIS_STATUS_INVALID_LENGTH);
+    
+Cleanup:    
+    if (status != NDIS_STATUS_SUCCESS &&
+        outputBuffer != NULL)
+    {
+        ExFreePoolWithTag(outputBuffer, SxExtAllocationTag);
+        outputBuffer = NULL;
+    }
+    
+    *SwitchPropertyEnumParameters = outputBuffer;
+    
+    return status;
+}
+
+
+NDIS_STATUS
+SxLibGetPortPropertyUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PORT_ID PortId,
+    _In_ NDIS_SWITCH_PORT_PROPERTY_TYPE PropertyType,
+    _In_opt_ PNDIS_SWITCH_OBJECT_ID PropertyId,
+    _Outptr_ PNDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS *PortPropertyEnumParameters
+    )
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+    NDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS propertyParameters;
+    ULONG bytesNeeded = 0;
+    PNDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS outputBuffer = NULL;
+    USHORT outputBufferLength = sizeof(NDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS);
+    
+    propertyParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+    propertyParameters.Header.Revision = NDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS_REVISION_1;
+    
+    propertyParameters.PortId = PortId;
+    propertyParameters.PropertyType = PropertyType;
+    propertyParameters.SerializationVersion = NDIS_SWITCH_OBJECT_SERIALIZATION_VERSION_1;
+    
+    //
+    // For Built-in properties, the ID is unnecessary.
+    //
+    if (PropertyId != NULL)
+    {
+        NdisMoveMemory(&propertyParameters.PropertyId,
+                       PropertyId,
+                       sizeof(NDIS_SWITCH_OBJECT_ID));
+    }
+    else
+    {
+        ASSERT(PropertyType != NdisSwitchPortPropertyTypeCustom);
+    }
+    
+    outputBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                         outputBufferLength,
+                                         SxExtAllocationTag);
+                                         
+    if (outputBuffer == NULL)
+    {
+        status = NDIS_STATUS_RESOURCES;
+        goto Cleanup;
+    }
+    
+    do 
+    {
+        if (bytesNeeded != 0)
+        {
+            ExFreePoolWithTag(outputBuffer, SxExtAllocationTag);
+
+            outputBufferLength = (USHORT)bytesNeeded;
+            outputBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
+                                                 outputBufferLength,
+                                                 SxExtAllocationTag);
+            
+            if (outputBuffer == NULL)
+            {
+                status = NDIS_STATUS_RESOURCES;
+                goto Cleanup;
+            }
+        }
+        
+        if(outputBufferLength >= sizeof(propertyParameters))
+        {
+            outputBuffer->Header.Size = outputBufferLength;
+            NdisMoveMemory(outputBuffer, &propertyParameters, sizeof(propertyParameters));
+        }
+    
+        status = SxLibIssueOidRequest(Switch,
+                                      NdisRequestMethod,
+                                      OID_SWITCH_PORT_PROPERTY_ENUM,
+                                      outputBuffer,
+                                      sizeof(propertyParameters),
+                                      outputBufferLength,
+                                      0,
+                                      0,
+                                      &bytesNeeded);
+        
+    } while(status == NDIS_STATUS_INVALID_LENGTH);
+    
+Cleanup:
+    if (status != NDIS_STATUS_SUCCESS &&
+        outputBuffer != NULL)
+    {
+        ExFreePoolWithTag(outputBuffer, SxExtAllocationTag);
+        outputBuffer = NULL;
+    }
+    
+    *PortPropertyEnumParameters = outputBuffer;
+    
+    return status;
+}
+
+
+VOID
+SxLibRevokeVfUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PORT_ID PortId
+    )
+{
+    SxLibIssueNicStatusIndicationUnsafe(Switch,
+                                        NDIS_STATUS_SWITCH_PORT_REMOVE_VF,
+                                        PortId,
+                                        NDIS_SWITCH_DEFAULT_NIC_INDEX,
+                                        TRUE,
+                                        NULL,
+                                        0);
+}
+
+
+VOID
+SxLibIssueNicStatusIndicationUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_STATUS StatusCode,
+    _In_ NDIS_SWITCH_PORT_ID PortId,
+    _In_ NDIS_SWITCH_NIC_INDEX NicIndex,
+    _In_ BOOLEAN IsDestination,
+    _In_opt_ PVOID StatusBuffer,
+    _In_ ULONG StatusBufferSize
+    )
+{
+    NDIS_STATUS_INDICATION statusIndication;
+    NDIS_STATUS_INDICATION wrappedIndication;
+    NDIS_SWITCH_NIC_STATUS_INDICATION nicIndication;
+    
+    NdisZeroMemory(&wrappedIndication, sizeof(wrappedIndication));
+    
+    wrappedIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+    wrappedIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+    wrappedIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+    
+    wrappedIndication.SourceHandle = Switch->NdisFilterHandle;
+    wrappedIndication.PortNumber = NDIS_DEFAULT_PORT_NUMBER;
+    
+    wrappedIndication.StatusCode = StatusCode;
+    wrappedIndication.StatusBuffer = StatusBuffer;
+    wrappedIndication.StatusBufferSize = StatusBufferSize;
+    
+    NdisZeroMemory(&nicIndication, sizeof(nicIndication));
+    
+    nicIndication.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+    nicIndication.Header.Revision = NDIS_SWITCH_NIC_STATUS_INDICATION_REVISION_1;
+    nicIndication.Header.Size = NDIS_SIZEOF_SWITCH_NIC_STATUS_REVISION_1;
+    nicIndication.StatusIndication = &wrappedIndication;
+    
+    if (IsDestination)
+    {
+        nicIndication.DestinationPortId = PortId;
+        nicIndication.DestinationNicIndex = NicIndex;
+    }
+    else
+    {
+        nicIndication.SourcePortId = PortId;
+        nicIndication.SourceNicIndex = NicIndex;
+    }
+    
+    NdisZeroMemory(&statusIndication, sizeof(statusIndication));
+    
+    statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+    statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+    statusIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+    
+    statusIndication.SourceHandle = Switch->NdisFilterHandle;
+    statusIndication.PortNumber = NDIS_DEFAULT_PORT_NUMBER;
+    
+    statusIndication.StatusCode = NDIS_STATUS_SWITCH_NIC_STATUS;
+    statusIndication.StatusBuffer = &nicIndication;
+    statusIndication.StatusBufferSize = sizeof(nicIndication);
+    
+    NdisFIndicateStatus(Switch->NdisFilterHandle,
+                        &statusIndication);
+}
+
diff --git a/datapath-windows/base/SxLibrary.h b/datapath-windows/base/SxLibrary.h
new file mode 100644
index 0000000..b5f9b14
--- /dev/null
+++ b/datapath-windows/base/SxLibrary.h
@@ -0,0 +1,464 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+    SxLibrary.h
+
+Abstract:
+
+    This file contains the common library function headers that can be
+    used by any extension using the SxBase library.
+
+
+--*/
+
+
+/*++
+
+SxLibSendNetBufferListsIngress
+  
+Routine Description:
+    This function is called to forward NBLs on ingress.
+    The extension MUST call this function, or call
+    SxLibCompleteNetBufferListsIngress for every NBL in NetBufferLists,
+    recieved in SxExtStartNetBufferListsIngress.
+    
+    This function can also be called to inject NBLs.
+    If there are NBLs in NetBufferLists that are initiated by the
+    extension, NumInjectedNetBufferLists must be the number of new NBLs.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NetBufferLists - the NBLs to send
+    
+    SendFlags - the SendFlags equivalent to NDIS flags for
+                NdisFSendNetBufferLists
+   
+    NumInjectedNetBufferLists - the number of NBLs in NetBufferLists initiated
+                                by the extension
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxLibSendNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendFlags,
+    _In_ ULONG NumInjectedNetBufferLists
+    );
+
+    
+/*++
+
+SxLibSendNetBufferListsEgress
+  
+Routine Description:
+    This function is called to forward NBLs on egress.
+    The extension MUST call this function, or call
+    SxLibCompleteNetBufferListsEgress for every NBL in NetBufferLists
+    recieved in SxExtStartNetBufferListsEgress.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NetBufferLists - the NBLs to send
+    
+    NumberOfNetBufferLists - the number of NBLs in NetBufferLists
+    
+    ReceiveFlags - the ReceiveFlags equivalent to NDIS flags for
+                   NdisFIndicateReceiveNetBufferLists
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxLibSendNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG NumberOfNetBufferLists,
+    _In_ ULONG ReceiveFlags
+    );
+
+    
+/*++
+
+SxLibCompleteNetBufferListsEgress
+  
+Routine Description:
+    This function is called to complete NBLs on egress.
+    The extension MUST call this function for all NBLs recieved
+    in SxExtStartCompleteNetBufferListsEgress.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NetBufferLists - the NBLs to send
+    
+    ReturnFlags - the ReceiveFlags equivalent to NDIS flags for
+                  NdisFReturnNetBufferLists
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxLibCompleteNetBufferListsEgress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG ReturnFlags
+    );
+
+/*++
+
+SxLibCompleteNetBufferListsIngress
+  
+Routine Description:
+    This function is called to complete NBLs on ingress.
+    The extension MUST call this function, or
+    SxLibCompletedInjectedNetBufferLists for all NBLs recieved in
+    SxExtStartCompleteNetBufferListsEgress.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NetBufferLists - the NBLs to send
+    
+    SendCompleteFlags - the ReceiveFlags equivalent to NDIS flags for
+                        NdisFSendNetBufferListsComplete
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxLibCompleteNetBufferListsIngress(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ PNET_BUFFER_LIST NetBufferLists,
+    _In_ ULONG SendCompleteFlags
+    );
+
+    
+/*++
+
+SxLibCompletedInjectedNetBufferLists
+  
+Routine Description:
+    This function is called after completing NBLs injected
+    by the extension.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NumInjectedNetBufferLists - the number of NBLs completed
+    
+Return Value:
+    VOID
+   
+--*/
+VOID
+SxLibCompletedInjectedNetBufferLists(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ ULONG NumInjectedNetBufferLists
+    );    
+
+    
+/*++
+
+SxLibIssueOidRequest
+
+Routine Description:
+
+    Utility routine that forms and sends an NDIS_OID_REQUEST to the
+    miniport, waits for it to complete, and returns status
+    to the caller.
+
+    NOTE: this assumes that the calling routine ensures validity
+    of the filter handle until this returns.
+    
+    This function can only be called at PASSIVE_LEVEL.
+
+Arguments:
+
+    Switch - pointer to our switch object.
+
+    RequestType - NdisRequest[Set|Query|method]Information.
+
+    Oid - the object being set/queried.
+
+    InformationBuffer - data for the request.
+
+    InformationBufferLength - length of the above.
+
+    OutputBufferLength - valid only for method request.
+
+    MethodId - valid only for method request.
+    
+    Timeout - The timeout in seconds for the OID. 
+
+    BytesNeeded - place to return bytes read/written.
+
+Return Value:
+
+    NDIS_STATUS_***
+
+--*/
+NDIS_STATUS
+SxLibIssueOidRequest(
+    _In_ PSX_SWITCH_OBJECT SxSwitch,
+    _In_ NDIS_REQUEST_TYPE RequestType,
+    _In_ NDIS_OID Oid,
+    _In_opt_ PVOID InformationBuffer,
+    _In_ ULONG InformationBufferLength,
+    _In_ ULONG OutputBufferLength,
+    _In_ ULONG MethodId,
+    _In_ UINT Timeout,
+    _Out_ PULONG BytesNeeded
+    );
+  
+
+/*++
+
+SxLibGetSwitchParametersUnsafe
+  
+Routine Description:
+    This function is called to get the current state of the switch.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    SwitchParameters - the returned switch parameters
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if SwitchParameters was successfully returned
+                          
+    NDIS_STATUS_*** - otherwise
+   
+--*/   
+NDIS_STATUS
+SxLibGetSwitchParametersUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Out_ PNDIS_SWITCH_PARAMETERS SwitchParameters
+    );
+
+    
+/*++
+
+SxLibGetPortArrayUnsafe
+  
+Routine Description:
+    This function is called to get the current array
+    of ports.
+    
+    NOTE: It is necessary to synchonize this with SxExtPortCreate
+    and SxExtPortTeardown.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    PortArray - the returned port array
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if PortArray was successfully allocated
+                          and returned
+                          
+    NDIS_STATUS_*** - otherwise
+   
+--*/
+NDIS_STATUS
+SxLibGetPortArrayUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _Out_ PNDIS_SWITCH_PORT_ARRAY *PortArray
+    );    
+
+    
+/*++
+
+SxLibGetNicArrayUnsafe
+  
+Routine Description:
+    This function is called to get the current array
+    of NICs.
+    
+    NOTE: It is necessary to synchonize this with SxExtNicConnect
+    and SxExtNicDisconnect.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    NicArray - the returned NIC array
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if NicArray was successfully allocated
+                          and returned
+                          
+    NDIS_STATUS_*** - otherwise
+   
+--*/
+NDIS_STATUS
+SxLibGetNicArrayUnsafe(
+    _In_ PSX_SWITCH_OBJECT SxSwitch,
+    _Out_ PNDIS_SWITCH_NIC_ARRAY *NicArray
+    );
+
+/*++
+
+SxLibGetSwitchPropertyUnsafe
+  
+Routine Description:
+    This function is called to get the current array of the switch
+    property queried.
+    
+    NOTE: It is necessary to synchonize this with SxExtAddSwitchProperty
+    and SxExtDeleteSwitchProperty.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    PropertyType - the PropertyType to query for
+    
+    PropertyId - the GUID of the property (from mof file)
+    
+    PropertyVersion - the version of the property
+    
+    SwitchPropertyEnumParameters - the returned property enum
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if SwitchPropertyEnumParameters was
+                          successfully allocated and returned
+                          
+    NDIS_STATUS_*** - otherwise
+   
+--*/
+NDIS_STATUS
+SxLibGetSwitchPropertyUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PROPERTY_TYPE PropertyType,
+    _In_opt_ PNDIS_SWITCH_OBJECT_ID PropertyId,
+    _Outptr_ PNDIS_SWITCH_PROPERTY_ENUM_PARAMETERS *SwitchPropertyEnumParameters
+    );
+
+/*++
+
+SxLibGetPortPropertyUnsafe
+  
+Routine Description:
+    This function is called to get the current array of the switch
+    property queried.
+    
+    NOTE: It is necessary to synchonize this with SxExtAddPortProperty
+    and SxExtDeletePortProperty.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    PortId - the port to query from
+    
+    PropertyType - the PropertyType to query for
+    
+    PropertyId - the GUID of the property (from mof file)
+        
+    PortPropertyEnumParameters - the returned property enum
+    
+Return Value:
+    NDIS_STATUS_SUCCESS - if PortPropertyEnumParameters was
+                          successfully allocated and returned
+                          
+    NDIS_STATUS_*** - otherwise
+   
+--*/
+NDIS_STATUS
+SxLibGetPortPropertyUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PORT_ID PortId,
+    _In_ NDIS_SWITCH_PORT_PROPERTY_TYPE PropertyType,
+    _In_opt_ PNDIS_SWITCH_OBJECT_ID PropertyId,
+    _Outptr_ PNDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS *PortPropertyEnumParameters
+    );
+
+/*++
+
+SxLibRevokeVfUnsafe
+  
+Routine Description:
+    This function is called revoke the VF assignment for the
+    given VM.
+    
+    NOTE: This must be synchonized with SxExtNicConnect and
+    SxExtNicDisconnect for the PortId given, and ReferenceSwitchNic
+    must have been successfully called.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    PortId - the port the VM is connected to
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxLibRevokeVfUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_SWITCH_PORT_ID PortId
+    );
+
+/*++
+
+SxLibIssueNicStatusIndicationUnsafe
+  
+Routine Description:
+    This function is called issue a NIC status indication.
+    
+    NOTE: This must be synchonized with SxExtNicConnect and
+    SxExtNicDisconnect for the PortId given, and ReferenceSwitchNic
+    must have been successfully called.
+    
+Arguments:
+
+    Switch - the Switch context
+    
+    StatusCode - the status code to indicate
+    
+    PortId - the port to indicate to/from
+    
+    NicIndex - the nic index to indicate to/from
+    
+    IsDestination - TRUE if PortId/NicIndex is destination info
+                    FALSE if PortId/NicIndex is source info
+                    
+    StatusBuffer - the StatusBuffer for the indication
+    
+    StatusBufferSize - the size of StatusBuffer
+    
+Return Value:
+    VOID
+   
+--*/  
+VOID
+SxLibIssueNicStatusIndicationUnsafe(
+    _In_ PSX_SWITCH_OBJECT Switch,
+    _In_ NDIS_STATUS StatusCode,
+    _In_ NDIS_SWITCH_PORT_ID PortId,
+    _In_ NDIS_SWITCH_NIC_INDEX NicIndex,
+    _In_ BOOLEAN IsDestination,
+    _In_opt_ PVOID StatusBuffer,
+    _In_ ULONG StatusBufferSize
+    );
+    
diff --git a/datapath-windows/base/precomp.h b/datapath-windows/base/precomp.h
new file mode 100644
index 0000000..2b75778
--- /dev/null
+++ b/datapath-windows/base/precomp.h
@@ -0,0 +1,11 @@
+//
+// Copyright (c) Microsoft Corporation. All Rights Reserved.
+//
+
+#include <ndis.h>
+#include <netiodef.h>
+#include <intsafe.h>
+#include <ntintsafe.h>
+#include "SxBase.h"
+#include "SxApi.h"
+#include "SxLibrary.h"
diff --git a/datapath-windows/base/precompsrc.c b/datapath-windows/base/precompsrc.c
new file mode 100644
index 0000000..5944cf5
--- /dev/null
+++ b/datapath-windows/base/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h"
\ No newline at end of file
diff --git a/debian/copyright.in b/debian/copyright.in
index 89cd2d2..9ef763e 100644
--- a/debian/copyright.in
+++ b/debian/copyright.in
@@ -17,6 +17,7 @@ Upstream Copyright Holders:
 	Copyright (C) 2000 The NetBSD Foundation, Inc.
 	Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
 	Copyright (c) 1982, 1986, 1990, 1993 The Regents of the University of California.
+	Copyright (c) Microsoft Corporation. All Rights Reserved.
 
 License:
 
@@ -204,6 +205,9 @@ License:
     gives unlimited permission to copy and/or distribute it,
     with or without modifications, as long as this notice is preserved.
 
+* The files unders datapath-windows/base are licensed under Microsoft Limited
+  Public License version 1.1.
+
 * All other components of this package are licensed under
   The Apache License Version 2.0.
 
@@ -700,3 +704,73 @@ Phone: (415) 283-3260
 URL:   www.inmon.com
 Email: info at inmon.com
 
+----------------------------------------------------------------------
+
+Retrieved from http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL, 2014-06-18:
+
+Microsoft Limited Public License
+
+This license governs use of code marked as “sample” or “example” available on
+this web site without a license agreement, as provided under the section above
+titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use
+such code (the “software”), you accept this license. If you do not accept the
+license, do not use the software.
+
+1. Definitions
+
+The terms “reproduce,” “reproduction,” “derivative works,” and “distribution”
+have the same meaning here as under U.S. copyright law.
+
+A “contribution” is the original software, or any additions or changes to the
+software.
+
+A “contributor” is any person that distributes its contribution under this
+license.
+
+“Licensed patents” are a contributor’s patent claims that read directly on its
+contribution.
+
+2. Grant of Rights
+
+(A) Copyright Grant - Subject to the terms of this license, including the
+license conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free copyright license to reproduce its
+contribution, prepare derivative works of its contribution, and distribute its
+contribution or any derivative works that you create.
+
+(B) Patent Grant - Subject to the terms of this license, including the license
+conditions and limitations in section 3, each contributor grants you a
+non-exclusive, worldwide, royalty-free license under its licensed patents to
+make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
+its contribution in the software or derivative works of the contribution in the
+software.
+
+3. Conditions and Limitations
+
+(A) No Trademark License- This license does not grant you rights to use any
+contributors’ name, logo, or trademarks.
+
+(B) If you bring a patent claim against any contributor over patents that you
+claim are infringed by the software, your patent license from such contributor
+to the software ends automatically.
+
+(C) If you distribute any portion of the software, you must retain all
+copyright, patent, trademark, and attribution notices that are present in the
+software.
+
+(D) If you distribute any portion of the software in source code form, you may
+do so only under this license by including a complete copy of this license with
+    your distribution. If you distribute any portion of the software in
+    compiled or object code form, you may only do so under a license that
+    complies with this license.
+
+    (E) The software is licensed “as-is.” You bear the risk of using it. The
+    contributors give no express warranties, guarantees or conditions. You may
+    have additional consumer rights under your local laws which this license
+    cannot change. To the extent permitted under your local laws, the
+    contributors exclude the implied warranties of merchantability, fitness for
+    a particular purpose and non-infringement.
+
+    (F) Platform Limitation - The licenses granted in sections 2(A) and 2(B)
+    extend only to the software or derivative works that you create that run on
+    a Microsoft Windows operating system product.
-- 
1.7.9.5




More information about the dev mailing list