summaryrefslogtreecommitdiff
path: root/network
diff options
context:
space:
mode:
Diffstat (limited to 'network')
-rw-r--r--network/config/bindview/BINDING.CPP827
-rw-r--r--network/config/bindview/BINDVIEW.CPP2336
-rw-r--r--network/config/bindview/BINDVIEW.H250
-rw-r--r--network/config/bindview/BINDVIEW.ICObin0 -> 766 bytes
-rw-r--r--network/config/bindview/BindView.rc194
-rw-r--r--network/config/bindview/Component.cpp897
-rw-r--r--network/config/bindview/NetCfgAPI.cpp878
-rw-r--r--network/config/bindview/NetCfgAPI.h92
-rw-r--r--network/config/bindview/RESOURCE.H43
-rw-r--r--network/config/bindview/ReadMe.md7
-rw-r--r--network/config/bindview/bindview.htm345
-rw-r--r--network/config/bindview/bindview.sln28
-rw-r--r--network/config/bindview/bindview.vcxproj211
-rw-r--r--network/config/bindview/bindview.vcxproj.Filters36
-rw-r--r--network/modem/fakemodem/ReadMe.md8
-rw-r--r--network/modem/fakemodem/driver.c474
-rw-r--r--network/modem/fakemodem/fakemodem.h156
-rw-r--r--network/modem/fakemodem/fakemodem.sln28
-rw-r--r--network/modem/fakemodem/fakemodem.vcxproj168
-rw-r--r--network/modem/fakemodem/fakemodem.vcxproj.Filters40
-rw-r--r--network/modem/fakemodem/ioctl.c790
-rw-r--r--network/modem/fakemodem/mdmfake.inx267
-rw-r--r--network/modem/fakemodem/readwrit.c465
-rw-r--r--network/ndis/extension/ReadMe.md21
-rw-r--r--network/ndis/extension/base/SxApi.h1196
-rw-r--r--network/ndis/extension/base/SxBase.c1395
-rw-r--r--network/ndis/extension/base/SxBase.h168
-rw-r--r--network/ndis/extension/base/SxLibrary.c839
-rw-r--r--network/ndis/extension/base/SxLibrary.h464
-rw-r--r--network/ndis/extension/base/precomp.h11
-rw-r--r--network/ndis/extension/base/precompsrc.c1
-rw-r--r--network/ndis/extension/base/sxbase.vcxproj130
-rw-r--r--network/ndis/extension/base/sxbase.vcxproj.Filters32
-rw-r--r--network/ndis/extension/extensions.sln55
-rw-r--r--network/ndis/extension/samples/forward/MSForwardExtPolicy.mof32
-rw-r--r--network/ndis/extension/samples/forward/MSForwardExtPolicyStatus.mof31
-rw-r--r--network/ndis/extension/samples/forward/MsForwardExt.c2584
-rw-r--r--network/ndis/extension/samples/forward/MsForwardExt.h219
-rw-r--r--network/ndis/extension/samples/forward/MsForwardExt.rc24
-rw-r--r--network/ndis/extension/samples/forward/install.cmd6
-rw-r--r--network/ndis/extension/samples/forward/msforwardext.inf85
-rw-r--r--network/ndis/extension/samples/forward/msforwardext.vcxproj127
-rw-r--r--network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters34
-rw-r--r--network/ndis/extension/samples/forward/precomp.h11
-rw-r--r--network/ndis/extension/samples/forward/precompsrc.c1
-rw-r--r--network/ndis/extension/samples/forward/removeRoute.ps112
-rw-r--r--network/ndis/extension/samples/forward/setRoute.ps154
-rw-r--r--network/ndis/extension/samples/forward/uninstall.cmd3
-rw-r--r--network/ndis/extension/samples/passthrough/MsPassthroughExt.c597
-rw-r--r--network/ndis/extension/samples/passthrough/MsPassthroughExt.rc24
-rw-r--r--network/ndis/extension/samples/passthrough/install.cmd1
-rw-r--r--network/ndis/extension/samples/passthrough/mspassthroughext.inf89
-rw-r--r--network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj127
-rw-r--r--network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters34
-rw-r--r--network/ndis/extension/samples/passthrough/precomp.h11
-rw-r--r--network/ndis/extension/samples/passthrough/precompsrc.c1
-rw-r--r--network/ndis/extension/samples/passthrough/uninstall.cmd1
-rw-r--r--network/ndis/filter/ReadMe.md117
-rw-r--r--network/ndis/filter/device.c289
-rw-r--r--network/ndis/filter/filter.c1903
-rw-r--r--network/ndis/filter/filter.h456
-rw-r--r--network/ndis/filter/filter.rc40
-rw-r--r--network/ndis/filter/filter.sln28
-rw-r--r--network/ndis/filter/filteruser.h89
-rw-r--r--network/ndis/filter/flt_dbg.c409
-rw-r--r--network/ndis/filter/flt_dbg.h195
-rw-r--r--network/ndis/filter/ndislwf.vcxproj283
-rw-r--r--network/ndis/filter/ndislwf.vcxproj.Filters40
-rw-r--r--network/ndis/filter/netlwf.inf202
-rw-r--r--network/ndis/filter/precomp.h6
-rw-r--r--network/ndis/filter/precompsrc.c1
-rw-r--r--network/ndis/mux/ReadMe.md174
-rw-r--r--network/ndis/mux/driver/60/miniport.c2953
-rw-r--r--network/ndis/mux/driver/60/mux.c516
-rw-r--r--network/ndis/mux/driver/60/mux.h963
-rw-r--r--network/ndis/mux/driver/60/mux.htm617
-rw-r--r--network/ndis/mux/driver/60/mux.rc50
-rw-r--r--network/ndis/mux/driver/60/mux_mp.inf69
-rw-r--r--network/ndis/mux/driver/60/muxp.inf100
-rw-r--r--network/ndis/mux/driver/60/novlan/mux.vcxproj287
-rw-r--r--network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters40
-rw-r--r--network/ndis/mux/driver/60/novlan/precompsrc.c1
-rw-r--r--network/ndis/mux/driver/60/precomp.h14
-rw-r--r--network/ndis/mux/driver/60/protocol.c3353
-rw-r--r--network/ndis/mux/driver/60/public.h46
-rw-r--r--network/ndis/mux/driver/60/vlan/muxvlan.vcxproj299
-rw-r--r--network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters40
-rw-r--r--network/ndis/mux/driver/60/vlan/precompsrc.c1
-rw-r--r--network/ndis/mux/mux.sln66
-rw-r--r--network/ndis/mux/notifyob/adapter.cpp965
-rw-r--r--network/ndis/mux/notifyob/adapter.h99
-rw-r--r--network/ndis/mux/notifyob/common.cpp624
-rw-r--r--network/ndis/mux/notifyob/common.h103
-rw-r--r--network/ndis/mux/notifyob/dllmain.cpp117
-rw-r--r--network/ndis/mux/notifyob/implinc.cpp31
-rw-r--r--network/ndis/mux/notifyob/list.h241
-rw-r--r--network/ndis/mux/notifyob/mux.def6
-rw-r--r--network/ndis/mux/notifyob/mux.vcxproj274
-rw-r--r--network/ndis/mux/notifyob/mux.vcxproj.Filters48
-rw-r--r--network/ndis/mux/notifyob/notify.RC47
-rw-r--r--network/ndis/mux/notifyob/notify.RGS14
-rw-r--r--network/ndis/mux/notifyob/notify.cpp2139
-rw-r--r--network/ndis/mux/notifyob/notify.h282
-rw-r--r--network/ndis/mux/notifyob/notify.htm552
-rw-r--r--network/ndis/mux/notifyob/notifyn.idl34
-rw-r--r--network/ndis/mux/notifyob/public.h47
-rw-r--r--network/ndis/mux/notifyob/resource.h12
-rw-r--r--network/ndis/mux/notifyob/virtual.cpp512
-rw-r--r--network/ndis/mux/notifyob/virtual.h68
-rw-r--r--network/ndis/ndisprot/6x/ReadMe.md84
-rw-r--r--network/ndis/ndisprot/6x/ndisprot60.sln63
-rw-r--r--network/ndis/ndisprot/6x/sys/60/ndisprot60.inf90
-rw-r--r--network/ndis/ndisprot/6x/sys/60/ndisprot60.rc49
-rw-r--r--network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj265
-rw-r--r--network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters49
-rw-r--r--network/ndis/ndisprot/6x/sys/60/precompsrc.c1
-rw-r--r--network/ndis/ndisprot/6x/sys/630/ndisprot630.inf109
-rw-r--r--network/ndis/ndisprot/6x/sys/630/ndisprot630.rc49
-rw-r--r--network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj265
-rw-r--r--network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters49
-rw-r--r--network/ndis/ndisprot/6x/sys/630/precompsrc.c1
-rw-r--r--network/ndis/ndisprot/6x/sys/debug.c425
-rw-r--r--network/ndis/ndisprot/6x/sys/debug.h220
-rw-r--r--network/ndis/ndisprot/6x/sys/excallbk.c195
-rw-r--r--network/ndis/ndisprot/6x/sys/macros.h234
-rw-r--r--network/ndis/ndisprot/6x/sys/ndisbind.c2061
-rw-r--r--network/ndis/ndisprot/6x/sys/ndisprot.h567
-rw-r--r--network/ndis/ndisprot/6x/sys/ntdisp.c916
-rw-r--r--network/ndis/ndisprot/6x/sys/precomp.h18
-rw-r--r--network/ndis/ndisprot/6x/sys/protuser.h92
-rw-r--r--network/ndis/ndisprot/6x/sys/recv.c1119
-rw-r--r--network/ndis/ndisprot/6x/sys/send.c463
-rw-r--r--network/ndis/ndisprot/6x/test/prottest.c665
-rw-r--r--network/ndis/ndisprot/6x/test/prottest.vcxproj243
-rw-r--r--network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters22
-rw-r--r--network/ndis/netvmini/6x/60/netvmini60.infbin0 -> 8200 bytes
-rw-r--r--network/ndis/netvmini/6x/60/netvmini60.rc51
-rw-r--r--network/ndis/netvmini/6x/60/netvmini60.vcxproj218
-rw-r--r--network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters46
-rw-r--r--network/ndis/netvmini/6x/620/netvmini620.infbin0 -> 12946 bytes
-rw-r--r--network/ndis/netvmini/6x/620/netvmini620.rc51
-rw-r--r--network/ndis/netvmini/6x/620/netvmini620.vcxproj218
-rw-r--r--network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters49
-rw-r--r--network/ndis/netvmini/6x/630/netvmini630.infbin0 -> 15616 bytes
-rw-r--r--network/ndis/netvmini/6x/630/netvmini630.rc50
-rw-r--r--network/ndis/netvmini/6x/630/netvmini630.vcxproj218
-rw-r--r--network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters52
-rw-r--r--network/ndis/netvmini/6x/ReadMe.md15
-rw-r--r--network/ndis/netvmini/6x/adapter.c2318
-rw-r--r--network/ndis/netvmini/6x/adapter.h376
-rw-r--r--network/ndis/netvmini/6x/ctrlpath.c1755
-rw-r--r--network/ndis/netvmini/6x/ctrlpath.h28
-rw-r--r--network/ndis/netvmini/6x/datapath.c1740
-rw-r--r--network/ndis/netvmini/6x/datapath.h77
-rw-r--r--network/ndis/netvmini/6x/hardware.h321
-rw-r--r--network/ndis/netvmini/6x/miniport.c622
-rw-r--r--network/ndis/netvmini/6x/miniport.h255
-rw-r--r--network/ndis/netvmini/6x/mphal.c1002
-rw-r--r--network/ndis/netvmini/6x/mphal.h126
-rw-r--r--network/ndis/netvmini/6x/netvmin6.h45
-rw-r--r--network/ndis/netvmini/6x/netvmini.sln59
-rw-r--r--network/ndis/netvmini/6x/qos.c653
-rw-r--r--network/ndis/netvmini/6x/qos.h70
-rw-r--r--network/ndis/netvmini/6x/tcbrcb.c221
-rw-r--r--network/ndis/netvmini/6x/tcbrcb.h81
-rw-r--r--network/ndis/netvmini/6x/trace.h38
-rw-r--r--network/ndis/netvmini/6x/vmq.c3123
-rw-r--r--network/ndis/netvmini/6x/vmq.h393
-rw-r--r--network/trans/ddproxy/ReadMe.md66
-rw-r--r--network/trans/ddproxy/ddproxy.sln28
-rw-r--r--network/trans/ddproxy/sys/DD_drv.c1059
-rw-r--r--network/trans/ddproxy/sys/DD_proxy.c1039
-rw-r--r--network/trans/ddproxy/sys/DD_proxy.h251
-rw-r--r--network/trans/ddproxy/sys/ddproxy.inf63
-rw-r--r--network/trans/ddproxy/sys/ddproxy.vcxproj185
-rw-r--r--network/trans/ddproxy/sys/ddproxy.vcxproj.Filters29
-rw-r--r--network/trans/inspect/ReadMe.md55
-rw-r--r--network/trans/inspect/inspect.sln28
-rw-r--r--network/trans/inspect/sys/TL_drv.c927
-rw-r--r--network/trans/inspect/sys/inspect.c1418
-rw-r--r--network/trans/inspect/sys/inspect.h214
-rw-r--r--network/trans/inspect/sys/inspect.inf63
-rw-r--r--network/trans/inspect/sys/inspect.vcxproj186
-rw-r--r--network/trans/inspect/sys/inspect.vcxproj.Filters32
-rw-r--r--network/trans/inspect/sys/utils.c448
-rw-r--r--network/trans/inspect/sys/utils.h298
-rw-r--r--network/trans/msnmntr/ReadMe.md79
-rw-r--r--network/trans/msnmntr/exe/monitor.cpp715
-rw-r--r--network/trans/msnmntr/exe/monitor.vcxproj251
-rw-r--r--network/trans/msnmntr/exe/monitor.vcxproj.Filters22
-rw-r--r--network/trans/msnmntr/exe/mtrace.cmd288
-rw-r--r--network/trans/msnmntr/inc/ioctl.h36
-rw-r--r--network/trans/msnmntr/inc/mntrguid.h44
-rw-r--r--network/trans/msnmntr/msnmntr.sln46
-rw-r--r--network/trans/msnmntr/sys/ctl.c149
-rw-r--r--network/trans/msnmntr/sys/ctl.h19
-rw-r--r--network/trans/msnmntr/sys/init.c244
-rw-r--r--network/trans/msnmntr/sys/msnmntr.c883
-rw-r--r--network/trans/msnmntr/sys/msnmntr.h55
-rw-r--r--network/trans/msnmntr/sys/msnmntr.inf54
-rw-r--r--network/trans/msnmntr/sys/msnmntr.vcxproj194
-rw-r--r--network/trans/msnmntr/sys/msnmntr.vcxproj.Filters35
-rw-r--r--network/trans/msnmntr/sys/notify.c294
-rw-r--r--network/trans/msnmntr/sys/notify.h32
-rw-r--r--network/trans/stmedit/ReadMe.md60
-rw-r--r--network/trans/stmedit/stmedit.sln28
-rw-r--r--network/trans/stmedit/sys/inline_edit.c546
-rw-r--r--network/trans/stmedit/sys/inline_edit.h65
-rw-r--r--network/trans/stmedit/sys/oob_edit.c1363
-rw-r--r--network/trans/stmedit/sys/oob_edit.h83
-rw-r--r--network/trans/stmedit/sys/stmedit.inf66
-rw-r--r--network/trans/stmedit/sys/stmedit.vcxproj186
-rw-r--r--network/trans/stmedit/sys/stmedit.vcxproj.Filters32
-rw-r--r--network/trans/stmedit/sys/stream_callout.c772
-rw-r--r--network/trans/stmedit/sys/stream_callout.h79
-rw-r--r--network/wlan/ReadMe.md91
-rw-r--r--network/wlan/ihvsample/adapters.cpp439
-rw-r--r--network/wlan/ihvsample/adapters.h125
-rw-r--r--network/wlan/ihvsample/ihv1xext.xml52
-rw-r--r--network/wlan/ihvsample/ihvconn.xml48
-rw-r--r--network/wlan/ihvsample/ihvmachine.xml62
-rw-r--r--network/wlan/ihvsample/ihvonexext.cpp1113
-rw-r--r--network/wlan/ihvsample/ihvonexext.h108
-rw-r--r--network/wlan/ihvsample/ihvplapmachineoruser.xml64
-rw-r--r--network/wlan/ihvsample/ihvplapuser.xml64
-rw-r--r--network/wlan/ihvsample/ihvsample.cpp1554
-rw-r--r--network/wlan/ihvsample/ihvsample.def8
-rw-r--r--network/wlan/ihvsample/ihvsample.h261
-rw-r--r--network/wlan/ihvsample/ihvsample.vcxproj254
-rw-r--r--network/wlan/ihvsample/ihvsample.vcxproj.Filters43
-rw-r--r--network/wlan/ihvsample/ihvtimelymachineoruser.xml64
-rw-r--r--network/wlan/ihvsample/ihvtimelyuser.xml63
-rw-r--r--network/wlan/ihvsample/ihvwep.cpp837
-rw-r--r--network/wlan/ihvsample/ihvwep.h62
-rw-r--r--network/wlan/ihvsample/ihvwep1.xml54
-rw-r--r--network/wlan/ihvsample/ihvwep2.xml54
-rw-r--r--network/wlan/ihvsample/precomp.h36
-rw-r--r--network/wlan/ihvsample/precompsrc.c1
-rw-r--r--network/wlan/ihvsample/profile.cpp1222
-rw-r--r--network/wlan/ihvsample/profile.h108
-rw-r--r--network/wlan/ihvsample/rc4utils.h67
-rw-r--r--network/wlan/ihvsample/utils.cpp662
-rw-r--r--network/wlan/ihvsample/utils.h318
-rw-r--r--network/wlan/ihvsampleui/IHVClassFactory.cpp166
-rw-r--r--network/wlan/ihvsampleui/IHVClassFactory.h28
-rw-r--r--network/wlan/ihvsampleui/IHVRegistryHelper.cpp284
-rw-r--r--network/wlan/ihvsampleui/IHVRegistryHelper.h40
-rw-r--r--network/wlan/ihvsampleui/IHVSample.idl71
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUI.cpp971
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUI.h238
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUICon.cpp345
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUICon.h103
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUIKey.cpp462
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUIKey.h104
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUISec.cpp434
-rw-r--r--network/wlan/ihvsampleui/IHVSampleExtUISec.h105
-rw-r--r--network/wlan/ihvsampleui/IHVSampleProfile.cpp918
-rw-r--r--network/wlan/ihvsampleui/IHVSampleProfile.h296
-rw-r--r--network/wlan/ihvsampleui/IHVSampleUI.cpp122
-rw-r--r--network/wlan/ihvsampleui/IHVSampleUI.def7
-rw-r--r--network/wlan/ihvsampleui/IHVSampleUI.rc129
-rw-r--r--network/wlan/ihvsampleui/IHVSampleUI.vcxproj258
-rw-r--r--network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters60
-rw-r--r--network/wlan/ihvsampleui/IHVUIInc.idl1
-rw-r--r--network/wlan/ihvsampleui/iunk.h54
-rw-r--r--network/wlan/ihvsampleui/precomp.h43
-rw-r--r--network/wlan/ihvsampleui/resource.h31
-rw-r--r--network/wlan/ihvsampleui/utils.cpp408
-rw-r--r--network/wlan/ihvsampleui/utils.h98
-rw-r--r--network/wlan/wlan.sln46
-rw-r--r--network/wsk/echosrv/ReadMe.md58
-rw-r--r--network/wsk/echosrv/echosrv.ctl1
-rw-r--r--network/wsk/echosrv/echosrv.sln28
-rw-r--r--network/wsk/echosrv/echosrv.vcxproj188
-rw-r--r--network/wsk/echosrv/echosrv.vcxproj.Filters31
-rw-r--r--network/wsk/echosrv/wsksmple.c1361
-rw-r--r--network/wsk/echosrv/wsksmple.rc11
277 files changed, 87850 insertions, 0 deletions
diff --git a/network/config/bindview/BINDING.CPP b/network/config/bindview/BINDING.CPP
new file mode 100644
index 00000000..b3771004
--- /dev/null
+++ b/network/config/bindview/BINDING.CPP
@@ -0,0 +1,827 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: B I N D I N G . C P P
+//
+// Contents: Functions to illustrate
+// o How to enumerate binding paths.
+// o How to enumerate binding interfaces.
+// o How to enable/disable bindings.
+//
+// Notes:
+//
+// Author: Alok Sinha 15-May-01
+//
+//----------------------------------------------------------------------------
+
+#include "bindview.h"
+
+//
+// Function: WriteBindings
+//
+// Purpose: Write bindings to specified file.
+//
+// Arguments:
+// fp [in] File handle.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID WriteBindings (FILE *fp)
+{
+ INetCfg *pnc;
+ IEnumNetCfgComponent *pencc;
+ INetCfgComponent *pncc;
+ LPWSTR lpszApp;
+ HRESULT hr;
+ UINT i;
+
+
+ hr = HrGetINetCfg( FALSE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ for (i=CLIENTS_SELECTED; i <= PROTOCOLS_SELECTED; ++i) {
+
+ fwprintf( fp, L"--- Bindings of %s ---\n", lpszNetClass[i] );
+
+ //
+ // Get Component Enumerator Interface.
+ //
+
+ hr = HrGetComponentEnum( pnc,
+ pguidNetClass[i],
+ &pencc );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstComponent( pencc, &pncc );
+
+ while( hr == S_OK ) {
+
+ //
+ // Write bindings of the component.
+ //
+
+ WriteBindingPath( fp,
+ pncc );
+ ReleaseRef( pncc );
+
+ fwprintf( fp, L"\n" );
+
+ hr = HrGetNextComponent( pencc, &pncc );
+ }
+
+ fwprintf( fp, L"\n" );
+
+ //
+ // S_FALSE merely indicates that there are no more components.
+ //
+
+ if ( hr == S_FALSE ) {
+ hr = S_OK;
+ }
+
+ ReleaseRef( pencc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the component enumerator interface." );
+ }
+ }
+
+ HrReleaseINetCfg( pnc, FALSE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return;
+}
+
+//
+// Function: WriteBindingPath
+//
+// Purpose: Write binding paths of a component.
+//
+// Arguments:
+// fp [in] File handle.
+// pncc [in] Network component.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID WriteBindingPath (FILE *fp,
+ INetCfgComponent *pncc)
+{
+ IEnumNetCfgBindingPath *pencbp;
+ INetCfgBindingPath *pncbp;
+ LPWSTR lpszName;
+ HRESULT hr;
+
+ //
+ // Write the first component's name.
+ //
+
+ hr = pncc->GetDisplayName( &lpszName );
+
+ if ( hr == S_OK ) {
+ fwprintf( fp, L"\n%s", lpszName );
+ }
+ else {
+ ErrMsg( hr,
+ L"Unable to get the display name of a component, "
+ L" some binding paths will not be written." );
+
+ return;
+ }
+
+ //
+ // Get binding path enumerator.
+ //
+
+ hr = HrGetBindingPathEnum( pncc,
+ EBP_BELOW,
+ &pencbp );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstBindingPath( pencbp,
+ &pncbp );
+
+ while( hr == S_OK ) {
+
+ //
+ // Write interfaces of the binding path.
+ //
+
+ WriteInterfaces( fp,
+ pncbp );
+
+ ReleaseRef( pncbp );
+
+ hr = HrGetNextBindingPath( pencbp,
+ &pncbp );
+ if ( hr == S_OK ) {
+ fwprintf( fp, L"\n%s", lpszName );
+ }
+ }
+
+ ReleaseRef( pencbp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the binding path enumerator of %s. "
+ L"Its binding paths will not be written.",
+ lpszName );
+ }
+
+ CoTaskMemFree( lpszName );
+ return;
+}
+
+//
+// Function: WriteInterfaces
+//
+// Purpose: Write bindings to specified file.
+//
+// Arguments:
+// fp [in] File handle.
+// pncbp [in] Binding path.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID WriteInterfaces (FILE *fp,
+ INetCfgBindingPath *pncbp)
+{
+ IEnumNetCfgBindingInterface *pencbi;
+ INetCfgBindingInterface *pncbi;
+ INetCfgComponent *pnccLower;
+ LPWSTR lpszName;
+ HRESULT hr;
+
+ hr = HrGetBindingInterfaceEnum( pncbp,
+ &pencbi );
+
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstBindingInterface( pencbi,
+ &pncbi );
+
+ //
+ // Write lower component of each interface.
+ //
+
+ while( hr == S_OK ) {
+
+ hr = pncbi->GetLowerComponent ( &pnccLower );
+
+ if ( hr == S_OK ) {
+
+ hr = pnccLower->GetDisplayName( &lpszName );
+ if ( hr == S_OK ) {
+ fwprintf( fp, L"-->%s", lpszName );
+ CoTaskMemFree( lpszName );
+ }
+ }
+
+ ReleaseRef( pnccLower );
+ ReleaseRef( pncbi );
+
+ hr = HrGetNextBindingInterface( pencbi,
+ &pncbi );
+ }
+
+ ReleaseRef( pencbi );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the binding interface enumerator."
+ L"The binding interfaces will not be shown." );
+ }
+
+ return;
+}
+
+//
+// Function: EnumNetBindings
+//
+// Purpose: Enumerate components and their bindings.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// uiTypeSelected [in] Type of network component selected.
+//
+// Returns: TRUE on success.
+//
+// Notes:
+//
+
+BOOL EnumNetBindings (HWND hwndTree,
+ UINT uiTypeSelected)
+{
+ INetCfg *pnc;
+ IEnumNetCfgComponent *pencc;
+ INetCfgComponent *pncc;
+ LPWSTR lpszApp;
+ HTREEITEM hTreeItem;
+ HRESULT hr;
+
+
+ hr = HrGetINetCfg( FALSE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get Component Enumerator Interface.
+ //
+
+ hr = HrGetComponentEnum( pnc,
+ pguidNetClass[uiTypeSelected],
+ &pencc );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstComponent( pencc, &pncc );
+
+ while( hr == S_OK ) {
+
+ //
+ // Add the component's name to the tree.
+ //
+
+ hTreeItem = AddToTree( hwndTree,
+ TVI_ROOT,
+ pncc );
+ if ( hTreeItem ) {
+
+ //
+ // Enumerate bindings.
+ //
+
+ ListBindings( pncc,
+ hwndTree,
+ hTreeItem );
+ }
+
+ ReleaseRef( pncc );
+
+ hr = HrGetNextComponent( pencc, &pncc );
+ }
+
+ //
+ // S_FALSE merely indicates that there are no more components.
+ //
+
+ if ( hr == S_FALSE ) {
+ hr = S_OK;
+ }
+
+ ReleaseRef( pencc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the component enumerator interface." );
+ }
+
+ HrReleaseINetCfg( pnc, FALSE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return hr == S_OK;
+}
+
+//
+// Function: ListBindings
+//
+// Purpose: Enumerate bindings of network components.
+//
+// Arguments:
+// pncc [in] Network component.
+// hwndTree [in] Tree handle.
+// hTreeItemRoot [in] Parent item.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ListBindings (INetCfgComponent *pncc,
+ HWND hwndTree,
+ HTREEITEM hTreeItemRoot)
+{
+ IEnumNetCfgBindingPath *pencbp;
+ INetCfgBindingPath *pncbp;
+ HTREEITEM hTreeItem;
+ ULONG ulIndex;
+ HRESULT hr;
+
+ hr = HrGetBindingPathEnum( pncc,
+ EBP_BELOW,
+ &pencbp );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstBindingPath( pencbp,
+ &pncbp );
+
+ ulIndex = 1;
+
+ while( hr == S_OK ) {
+
+ //
+ // Add an item for the binding path.
+ //
+
+ hTreeItem = AddBindNameToTree( pncbp,
+ hwndTree,
+ hTreeItemRoot,
+ ulIndex );
+
+ if ( hTreeItem ) {
+
+ //
+ // Enumerate interfaces.
+ //
+
+ ListInterfaces( pncbp,
+ hwndTree,
+ hTreeItem );
+ }
+
+ ReleaseRef( pncbp );
+
+ hr = HrGetNextBindingPath( pencbp,
+ &pncbp );
+
+ ulIndex++;
+ }
+
+ ReleaseRef( pencbp );
+ }
+ else {
+ LPWSTR lpszName;
+
+ if ( pncc->GetDisplayName(&lpszName) == S_OK ) {
+
+ ErrMsg( hr,
+ L"Couldn't get the binding path enumerator of %s. "
+ L"Its binding paths will not be shown.",
+ lpszName );
+
+ CoTaskMemFree( lpszName );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the binding path enumerator of a "
+ L"network component. The binding paths will not "
+ L"be shown." );
+ }
+ }
+
+ return;
+}
+
+//
+// Function: ListInterfaces
+//
+// Purpose: Enumerate interfaces of a binding path.
+//
+// Arguments:
+// pncbp [in] Binding path.
+// hwndTree [in] Tree handle.
+// hTreeItemRoot [in] Parent item.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ListInterfaces (INetCfgBindingPath *pncbp,
+ HWND hwndTree,
+ HTREEITEM hTreeItemRoot)
+{
+ IEnumNetCfgBindingInterface *pencbi;
+ INetCfgBindingInterface *pncbi;
+ INetCfgComponent *pnccBound;
+ HTREEITEM hTreeItem;
+ HRESULT hr;
+
+ hr = HrGetBindingInterfaceEnum( pncbp,
+ &pencbi );
+
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstBindingInterface( pencbi,
+ &pncbi );
+ hTreeItem = hTreeItemRoot;
+
+ while( (hr == S_OK) && hTreeItem ) {
+
+ //
+ // Add lower component of every interface to the tree.
+ //
+
+ pncbi->GetLowerComponent( &pnccBound );
+
+ hTreeItem = AddToTree( hwndTree,
+ hTreeItem,
+ pnccBound );
+
+ ReleaseRef( pnccBound );
+ ReleaseRef( pncbi );
+
+ hr = HrGetNextBindingInterface( pencbi,
+ &pncbi );
+ }
+
+ //
+ // If hr is S_OK then, the loop terminated due to error in adding
+ // the binding path to the tree and pncbi has a reference to an
+ // interface.
+ //
+
+ if ( hr == S_OK ) {
+
+ ReleaseRef( pncbi );
+ }
+
+ ReleaseRef( pencbi );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the binding interface enumerator."
+ L"The binding interfaces will not be shown." );
+ }
+
+ return;
+}
+
+//
+// Function: HandleBindingPathOperation
+//
+// Purpose:
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// ulSelection [in] Option selected.
+// hItem [in] Item selected.
+// lParam [in] lParam of the item.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID HandleBindingPathOperation (HWND hwndOwner,
+ ULONG ulSelection,
+ HTREEITEM hItem,
+ LPARAM lParam)
+{
+ switch( ulSelection ) {
+
+ case IDI_ENABLE:
+ case IDI_DISABLE:
+
+ //
+ // Enable/disable binding path.
+ //
+
+ EnableBindingPath( hwndOwner,
+ hItem,
+ (LPWSTR)lParam,
+ ulSelection == IDI_ENABLE );
+ }
+
+ return;
+}
+
+//
+// Function: EnableBindingPath
+//
+// Purpose: Enable/disable binding path.
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// hItem [in] Item handle of the binding path.
+// lpszPathToken [in] Path token of the binding path.
+// fEnable [in] if TRUE, enable, otherwise disable.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID
+EnableBindingPath (
+ HWND hwndOwner,
+ HTREEITEM hItem,
+ _In_ LPWSTR lpszPathToken,
+ BOOL fEnable)
+{
+ INetCfg *pnc;
+ INetCfgBindingPath *pncbp;
+ LPWSTR lpszInfId;
+ LPWSTR lpszApp;
+ HRESULT hr;
+
+ //
+ // Get PnpID of the owner component.
+ //
+
+ lpszInfId = GetComponentId( hwndOwner,
+ hItem );
+
+ if ( lpszInfId ) {
+
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Find the binding path reference.
+ //
+
+ pncbp = FindBindingPath( pnc,
+ lpszInfId,
+ lpszPathToken );
+
+ if ( pncbp ) {
+
+ //
+ // Enable/disable.
+ //
+
+ hr = pncbp->Enable( fEnable );
+
+ if ( hr == S_OK ) {
+ hr = pnc->Apply();
+
+ if ( hr == S_OK ) {
+
+ //
+ // Refreshe the state of the item representing the
+ // binding path.
+ //
+
+ RefreshItemState( hwndOwner,
+ hItem,
+ fEnable );
+ }
+ else {
+ ErrMsg( hr,
+ L"Failed to apply changes to the binding path." );
+ }
+ }
+ else {
+ if ( fEnable ) {
+ ErrMsg( hr,
+ L"Failed to enable the binding path." );
+ }
+ else {
+ ErrMsg( hr,
+ L"Failed to disable the binding path." );
+ }
+ }
+
+ ReleaseRef( pncbp );
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+ }
+ else {
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't determine the owner of the binding path." );
+ }
+
+ return;
+}
+
+//
+// Function: GetComponentId
+//
+// Purpose: Find the PnpID of a network component.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// hItem [in] Item handle of the binding path.
+//
+// Returns: PnpID of the network component.
+//
+// Notes:
+//
+
+LPWSTR GetComponentId (HWND hwndTree,
+ HTREEITEM hItem)
+{
+ LPWSTR lpszInfId;
+ HTREEITEM hTreeItemParent;
+ TVITEMW tvItem;
+
+ lpszInfId = NULL;
+
+ //
+ // Get the item handle of the owner component.
+ //
+
+ hTreeItemParent = TreeView_GetParent( hwndTree,
+ hItem );
+ if ( hTreeItemParent ) {
+
+ //
+ // Get lParam of the owner component. lParam is the PnpID.
+ //
+
+ ZeroMemory( &tvItem,
+ sizeof(TVITEMW) );
+
+ tvItem.hItem = hTreeItemParent;
+ tvItem.mask = TVIF_PARAM;
+
+ if ( TreeView_GetItem(hwndTree,
+ &tvItem) ) {
+
+ lpszInfId = (LPWSTR)tvItem.lParam;
+ }
+ }
+
+ return lpszInfId;
+}
+
+//
+// Function: WriteBindings
+//
+// Purpose: Find the binding path with a give path token.
+//
+// Arguments:
+// pnc [in] INetCfg reference.
+// lpszInfId [in] PnpID of the network component.
+// lpszPathTokenSelected [in] Path token of the binding path to search.
+//
+// Returns: Reference to the binding path on success, otherwise NULL.
+//
+// Notes:
+//
+
+INetCfgBindingPath *
+FindBindingPath (
+ INetCfg *pnc,
+ _In_ LPWSTR lpszInfId,
+ _In_ LPWSTR lpszPathTokenSelected)
+{
+ INetCfgComponent *pncc = NULL;
+ IEnumNetCfgBindingPath *pencbp = NULL;
+ INetCfgBindingPath *pncbp = NULL;
+ LPWSTR lpszPathToken;
+ HRESULT hr;
+ BOOL fFound;
+
+
+ fFound = FALSE;
+
+ //
+ // Get the component reference.
+ //
+
+ hr = pnc->FindComponent( lpszInfId,
+ &pncc );
+
+ if ( hr == S_OK ) {
+
+ hr = HrGetBindingPathEnum( pncc,
+ EBP_BELOW,
+ &pencbp );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstBindingPath( pencbp,
+ &pncbp );
+
+ // Enumerate each binding path and find the one
+ // whose path token matches the specified one.
+ //
+
+ while ( !fFound && (hr == S_OK) ) {
+
+ hr = pncbp->GetPathToken( &lpszPathToken );
+
+ if ( hr == S_OK ) {
+ fFound = !wcscmp( lpszPathToken,
+ lpszPathTokenSelected );
+
+ CoTaskMemFree( lpszPathToken );
+ }
+
+ if ( !fFound ) {
+ ReleaseRef( pncbp );
+
+ hr = HrGetNextBindingPath( pencbp,
+ &pncbp );
+ }
+ }
+
+ ReleaseRef( pencbp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the binding path enumerator interface." );
+ }
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface pointer to %s.",
+ lpszInfId );
+ }
+
+ return (fFound) ? pncbp : NULL;
+}
diff --git a/network/config/bindview/BINDVIEW.CPP b/network/config/bindview/BINDVIEW.CPP
new file mode 100644
index 00000000..4231f7c4
--- /dev/null
+++ b/network/config/bindview/BINDVIEW.CPP
@@ -0,0 +1,2336 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: B I N D V I E W . C P P
+//
+// Contents:
+//
+// Notes:
+//
+// Author: Alok Sinha 15-Amy-01
+//
+//----------------------------------------------------------------------------
+
+
+#include "BindView.h"
+
+//----------------------------------------------------------------------------
+// Globals
+//
+
+//
+// Image list for devices of various setup class.
+//
+
+SP_CLASSIMAGELIST_DATA ClassImageListData;
+
+HINSTANCE hInstance;
+HMENU hMainMenu;
+HMENU hComponentSubMenu;
+HMENU hBindingPathSubMenu;
+
+//
+// Network components whose bindings are enumerated.
+//
+
+LPWSTR lpszNetClass[] = {
+ L"All Clients",
+ L"All Services",
+ L"All Protocols"
+ };
+
+//
+// GUIDs of network components.
+//
+
+const GUID *pguidNetClass [] = {
+ &GUID_DEVCLASS_NETCLIENT,
+ &GUID_DEVCLASS_NETSERVICE,
+ &GUID_DEVCLASS_NETTRANS,
+ &GUID_DEVCLASS_NET
+ };
+
+//
+// Program entry point.
+//
+
+int APIENTRY
+WinMain (
+ _In_ HINSTANCE hInst,
+ _In_opt_ HINSTANCE hPrevInstance,
+ _In_ LPSTR lpCmdLine,
+ _In_ int nCmdShow )
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+ UNREFERENCED_PARAMETER(nCmdShow);
+
+ //
+ // Make sure common control DLL is loaded.
+ //
+
+ hInstance = hInst;
+
+ InitCommonControls();
+
+ if ( DialogBoxW(hInst,
+ MAKEINTRESOURCEW(IDD_MAIN),
+ NULL,
+ MainDlgProc) == -1 ) {
+
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Failed to create the main dialog box, exiting..." );
+ }
+
+ return 0;
+}
+
+//
+// WndProc for the main dialog box.
+//
+
+INT_PTR CALLBACK MainDlgProc (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ HWND hwndBindingTree;
+ HICON hIcon;
+
+ switch (uMsg) {
+
+ case WM_INITDIALOG:
+
+ hIcon = LoadIcon( hInstance,
+ MAKEINTRESOURCE(IDI_BINDVIEW) );
+
+ if ( !hIcon ) {
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the program icon, exiting..." );
+
+ return FALSE;
+ }
+
+ SetClassLongPtr( hwndDlg,
+ GCLP_HICON,
+ (LONG_PTR)hIcon );
+
+ hMainMenu = LoadMenu( hInstance,
+ MAKEINTRESOURCE(IDM_OPTIONS) );
+
+ if ( !hMainMenu ) {
+
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the program menu, exiting..." );
+
+ return FALSE;
+ }
+
+ hComponentSubMenu = GetSubMenu( hMainMenu,
+ 0 );
+
+ hBindingPathSubMenu = GetSubMenu( hMainMenu,
+ 1 );
+
+ if ( !hComponentSubMenu || !hBindingPathSubMenu ) {
+
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the program menu, exiting..." );
+
+ DestroyMenu( hMainMenu );
+ return FALSE;
+ }
+
+ //
+ // Add the network components types whose bindings are shown.
+ //
+
+ UpdateComponentTypeList( GetDlgItem(hwndDlg,
+ IDL_COMPONENT_TYPES) );
+
+ //
+ // Load and associate the image list of all device classes with
+ // tree.
+ //
+
+ hwndBindingTree = GetDlgItem( hwndDlg,
+ IDT_BINDINGS );
+
+ ZeroMemory( &ClassImageListData, sizeof(SP_CLASSIMAGELIST_DATA) );
+ ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
+
+ if ( SetupDiGetClassImageList(&ClassImageListData) == TRUE ) {
+
+ TreeView_SetImageList( hwndBindingTree,
+ ClassImageListData.ImageList,
+ LVSIL_NORMAL );
+ }
+ else {
+
+ //
+ // In case, we failed to load the image list, abort.
+ //
+
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the image list of "
+ L"device classes, exiting..." );
+
+ DestroyMenu( hMainMenu );
+ return FALSE;
+ }
+
+ //
+ // Enumerate the bindings of the network component selected by default.
+ //
+
+ EnumNetBindings( hwndBindingTree,
+ DEFAULT_COMPONENT_SELECTED );
+
+ return TRUE; // Tell Windows to continue creating the dialog box.
+
+ case WM_COMMAND:
+
+ switch( LOWORD(wParam) ) {
+
+ case IDL_COMPONENT_TYPES:
+
+ if ( HIWORD(wParam) == CBN_SELCHANGE ) {
+
+ //
+ // User has selected a new network component type.
+ //
+
+ RefreshAll( hwndDlg );
+ }
+
+ break;
+
+ case IDB_EXPAND_ALL:
+ case IDB_COLLAPSE_ALL:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ HTREEITEM hItem;
+ //
+ // Expand/Collapse the entire tree.
+ //
+
+ hwndBindingTree = GetDlgItem( hwndDlg,
+ IDT_BINDINGS );
+
+ hItem = TreeView_GetSelection( hwndBindingTree );
+
+ ExpandCollapseAll( hwndBindingTree,
+ TVI_ROOT,
+ (LOWORD(wParam) == IDB_EXPAND_ALL) ?
+ TVE_EXPAND : TVE_COLLAPSE );
+
+ TreeView_SelectSetFirstVisible( hwndBindingTree,
+ hItem );
+ }
+
+ break;
+
+ case IDB_SAVE:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ //
+ // Save the binding information to a file.
+ //
+
+ WCHAR lpszFile[MAX_PATH+1];
+
+ if ( GetFileName(hwndDlg,
+ L"Text files (*.txt)\0*.txt\0",
+ L"Select a file name",
+ OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
+ lpszFile,
+ L"txt",
+ TRUE) ) {
+
+ DumpBindings( lpszFile );
+ }
+ }
+
+ break;
+
+ case IDB_INSTALL:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ //
+ // Install a network component.
+ //
+
+ if ( (BOOL)DialogBoxW(hInstance,
+ MAKEINTRESOURCEW(IDD_INSTALL),
+ hwndDlg,
+ InstallDlg) == TRUE ) {
+
+ RefreshAll( hwndDlg );
+ }
+ }
+
+ break;
+
+ case IDB_UNINSTALL:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ //
+ // Uninstall a network component.
+ //
+
+ if ( (BOOL)DialogBoxW(hInstance,
+ MAKEINTRESOURCEW(IDD_UNINSTALL),
+ hwndDlg,
+ UninstallDlg) == TRUE ) {
+
+ RefreshAll( hwndDlg );
+ }
+ }
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnm;
+
+ lpnm = (LPNMHDR)lParam;
+
+ if ( (lpnm->idFrom == IDT_BINDINGS) &&
+ (lpnm->code == NM_RCLICK) ) {
+
+ //
+ // A network component or a binding path is selected
+ // with a right-click.
+ //
+
+ ProcessRightClick( lpnm );
+
+ //
+ // Tell Windows that the right-click has been handled
+ // us.
+ //
+
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+
+ if ( (0xFFF0 & wParam) == SC_CLOSE ) {
+
+ //
+ // Before exiting, make sure to delete the image list
+ // and the buffers associated with each item in the tree.
+ //
+
+ SetupDiDestroyClassImageList( &ClassImageListData );
+
+ ReleaseMemory( GetDlgItem(hwndDlg, IDT_BINDINGS),
+ TVI_ROOT );
+
+ DestroyMenu( hMainMenu );
+ EndDialog( hwndDlg, 0 );
+ }
+ }
+
+ return FALSE;
+}
+
+//
+// WndProc of the dialog box for binding/unbinding components.
+//
+
+INT_PTR CALLBACK BindComponentDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ LPBIND_UNBIND_INFO lpBindUnbind;
+
+ switch (uMsg) {
+
+ case WM_INITDIALOG:
+ {
+ DWORD dwCount;
+
+ //
+ // Save the lParam which is an index to the selected network
+ // component.
+ //
+
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)lParam );
+
+ lpBindUnbind = (LPBIND_UNBIND_INFO)lParam;
+
+ //
+ // fBindTo is TRUE when the user wants to bind the selected
+ // component to other components. So, we list the components
+ // that are not bound and can bind.
+ //
+ //
+ // fBindTo is FALSE when the user wants to unbind the selected
+ // component from other components. So, we list the components
+ // that are bound to it.
+ //
+ //
+ // ListCompToBindUnbind returns number of components added to
+ // the list. Keep track of it. If it zero then, we don't want to
+ // show this dialog box.
+ //
+
+ dwCount = ListCompToBindUnbind(
+ lpBindUnbind->lpszInfId,
+ ADAPTERS_SELECTED,
+ GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ lpBindUnbind->fBindTo == FALSE );
+
+ dwCount += ListCompToBindUnbind(
+ lpBindUnbind->lpszInfId,
+ CLIENTS_SELECTED,
+ GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ lpBindUnbind->fBindTo == FALSE );
+
+ dwCount += ListCompToBindUnbind(
+ lpBindUnbind->lpszInfId,
+ SERVICES_SELECTED,
+ GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ lpBindUnbind->fBindTo == FALSE );
+
+ dwCount += ListCompToBindUnbind(
+ lpBindUnbind->lpszInfId,
+ PROTOCOLS_SELECTED,
+ GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ lpBindUnbind->fBindTo == FALSE );
+
+ if ( dwCount > 0 ) {
+
+ //
+ // Since the same dialog box is used for unbind operation,
+ // we need to update the text on the button to reflect that
+ // it is a bind operation.
+ //
+
+ if ( lpBindUnbind->fBindTo == FALSE ) {
+
+ SetWindowTextW( hwndDlg,
+ L"Unbind From Network Components" );
+
+ SetWindowTextW( GetDlgItem(hwndDlg, IDB_BIND_UNBIND),
+ L"Unbind" );
+
+ SetWindowTextW( GetDlgItem(hwndDlg, IDG_COMPONENT_LIST),
+ L"Select components to unbind from" );
+ }
+ }
+ else {
+ if ( lpBindUnbind->fBindTo == TRUE ) {
+ ErrMsg( 0,
+ L"There no network components that can "
+ L"bind to the selected component." );
+ }
+ else {
+ ErrMsg( 0,
+ L"There no network components that are "
+ L"bound to the selected component." );
+ }
+
+ PostMessage( hwndDlg, WM_NO_COMPONENTS, 0, 0 );
+ }
+
+ return TRUE;
+ }
+
+ case WM_NO_COMPONENTS:
+ EndDialog( hwndDlg, 0 );
+ break;
+
+ case WM_COMMAND:
+
+ if ( (LOWORD(wParam) == IDB_CLOSE) &&
+ (HIWORD(wParam) == BN_CLICKED) ) {
+
+ //
+ // Before deleting the list in the tree, free the buffer
+ // associated with each item. The buffer holds the
+ // INF Id of network components.
+ //
+
+ ReleaseMemory( GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ TVI_ROOT );
+
+ EndDialog( hwndDlg, 0 );
+ }
+ else {
+
+ //
+ // User wants to bind/unbind.
+ //
+
+ if ( (LOWORD(wParam) == IDB_BIND_UNBIND) &&
+ (HIWORD(wParam) == BN_CLICKED) ) {
+
+
+
+ lpBindUnbind = (LPBIND_UNBIND_INFO)GetWindowLongPtr( hwndDlg,
+ DWLP_USER );
+
+ if ( BindUnbind(lpBindUnbind->lpszInfId,
+ GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ lpBindUnbind->fBindTo) ) {
+
+ RefreshBindings( hwndDlg,
+ lpBindUnbind->lpszInfId );
+ }
+
+ ReleaseMemory( GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ TVI_ROOT );
+ EndDialog( hwndDlg, 0 );
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+
+ if ( (0xFFF0 & wParam) == SC_CLOSE ) {
+
+ //
+ // Before deleting the list in the tree, free the buffer
+ // associated with each item. The buffer holds the
+ // INF Id of network components.
+ //
+
+ ReleaseMemory( GetDlgItem(hwndDlg, IDT_COMPONENT_LIST),
+ TVI_ROOT );
+
+ EndDialog( hwndDlg, 0 );
+ }
+ }
+
+ return FALSE;
+}
+
+//
+//WndProc of the dialog box for installing network components.
+//
+
+INT_PTR CALLBACK InstallDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (uMsg) {
+
+ case WM_INITDIALOG:
+ {
+ HWND hwndTree;
+
+ //
+ // List types of network components e.g. client,
+ // protocol and service.
+ //
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+
+ TreeView_SetImageList( hwndTree,
+ ClassImageListData.ImageList,
+ LVSIL_NORMAL );
+
+ //
+ // Insert and select client by default.
+ //
+
+ TreeView_Select( hwndTree,
+ InsertItem(hwndTree,
+ CLIENTS_SELECTED),
+ TVGN_CARET );
+
+ InsertItem( hwndTree,
+ SERVICES_SELECTED );
+
+ InsertItem( hwndTree,
+ PROTOCOLS_SELECTED );
+
+ //
+ // Initialize it to FALSE. It will be set to TRUE when
+ // at least one component is installed.
+ //
+
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)FALSE );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD(wParam) ) {
+
+ case IDB_INSTALL:
+
+ //
+ // Install from Windows system directory.
+ //
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ InstallSelectedComponentType( hwndDlg, NULL );
+ }
+ break;
+
+ case IDB_BROWSE:
+
+ //
+ // User wants to specify an INF file for the network
+ // to install.
+ //
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ WCHAR lpszInfFile[MAX_PATH+1];
+
+ if ( GetFileName(hwndDlg,
+ L"INF files (*.inf)\0*.inf\0",
+ L"Select the INF file of the network component to install",
+ OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST,
+ lpszInfFile,
+ NULL,
+ FALSE) ) {
+
+ InstallSelectedComponentType( hwndDlg,
+ lpszInfFile );
+ }
+ }
+ break;
+
+ case IDB_CLOSE:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ //
+ // Return the value of DWLP_USER to indicate whether one or
+ // more components have been installed. Accordingly, the
+ // the list will be refreshed.
+ //
+
+ EndDialog( hwndDlg,
+ GetWindowLongPtr(hwndDlg, DWLP_USER) );
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnm;
+
+ lpnm = (LPNMHDR)lParam;
+
+ if ( (lpnm->idFrom == IDT_COMPONENT_LIST) &&
+ (lpnm->code == NM_DBLCLK) ) {
+
+ //
+ // On double-click, install from Windows system directory.
+ //
+
+ InstallSelectedComponentType( hwndDlg, NULL );
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+
+ if ( (0xFFF0 & wParam) == SC_CLOSE ) {
+
+ //
+ // Return the value of DWLP_USER to indicate whether one or
+ // more components have been installed. Accordingly, the
+ // the list will be refreshed.
+ //
+
+ EndDialog( hwndDlg,
+ GetWindowLongPtr(hwndDlg, DWLP_USER) );
+ }
+ }
+
+ return FALSE;
+}
+
+//
+// WndProc of the dialog box for uninstalling a network component.
+//
+
+INT_PTR CALLBACK UninstallDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ HWND hwndTree;
+
+ switch (uMsg) {
+
+ case WM_INITDIALOG:
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+ TreeView_SetImageList( hwndTree,
+ ClassImageListData.ImageList,
+ LVSIL_NORMAL );
+
+ //
+ // List all the components currently installed.
+ //
+
+ ListInstalledComponents( hwndTree,
+ &GUID_DEVCLASS_NETCLIENT);
+ ListInstalledComponents( hwndTree,
+ &GUID_DEVCLASS_NETSERVICE );
+ ListInstalledComponents( hwndTree,
+ &GUID_DEVCLASS_NETTRANS );
+
+ //
+ // Initialize it to FALSE. It will be set to TRUE when
+ // at least one component is installed.
+ //
+
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)FALSE );
+ return TRUE;
+
+ case WM_COMMAND:
+
+ switch( LOWORD(wParam) ) {
+
+ case IDB_REMOVE:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ //
+ // Uninstall the selected component.
+ //
+
+ UninstallSelectedComponent( hwndDlg );
+
+ }
+ break;
+
+ case IDB_CLOSE:
+
+ if ( HIWORD(wParam) == BN_CLICKED ) {
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+ ReleaseMemory( hwndTree,
+ TVI_ROOT );
+
+ //
+ // Return the value of DWLP_USER to indicate whether one or
+ // more components have been installed. Accordingly, the
+ // the list will be refreshed.
+ //
+
+ EndDialog( hwndDlg,
+ GetWindowLongPtr(hwndDlg, DWLP_USER) );
+ }
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnm;
+
+ lpnm = (LPNMHDR)lParam;
+
+ if ( (lpnm->idFrom == IDT_COMPONENT_LIST) &&
+ (lpnm->code == NM_DBLCLK) ) {
+
+ UninstallSelectedComponent( hwndDlg );
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+
+ if ( (0xFFF0 & wParam) == SC_CLOSE ) {
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+ ReleaseMemory( hwndTree,
+ TVI_ROOT );
+
+ //
+ // Return the value of DWLP_USER to indicate whether one or
+ // more components have been installed. Accordingly, the
+ // the list will be refreshed.
+ //
+
+ EndDialog( hwndDlg,
+ GetWindowLongPtr(hwndDlg, DWLP_USER) );
+ }
+ }
+
+ return FALSE;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DumpBindings
+//
+// Purpose: Write the binding information.
+//
+// Arguments:
+// lpszFile [in] Name of the file in which to write.
+//
+// Returns: None
+//
+// Notes:
+//
+
+VOID
+DumpBindings (
+ _In_ LPWSTR lpszFile)
+{
+ FILE *fp;
+ errno_t err;
+
+ err = _wfopen_s( &fp,
+ lpszFile,
+ L"w" );
+
+ if ( err != 0 || fp == NULL ) {
+
+ ErrMsg( 0,
+ L"Unable to open %s.",
+ lpszFile );
+ }
+ else {
+ WriteBindings( fp );
+
+ fclose( fp );
+ }
+
+ return;
+}
+
+//
+// Function: InstallSelectedComponentType
+//
+// Purpose: Install a network component.
+//
+// Arguments:
+// hwndDlg [in] Handle to Install dialog box.
+// lpszInfFile [in] Inf file of the network component.
+//
+// Returns: None
+//
+// Notes:
+// If lpszInfFile is NULL, network components are installed from the
+// system directory.
+//
+
+VOID
+InstallSelectedComponentType (
+ HWND hwndDlg,
+ _In_opt_ LPWSTR lpszInfFile)
+{
+ HWND hwndTree = NULL;
+ HTREEITEM hItem = NULL;
+ LPARAM lParam;
+ HCURSOR hPrevCursor = NULL;
+ HCURSOR hWaitCursor = NULL;
+ HWND hwndFocus = NULL;
+ DWORD dwType;
+ BOOL fEnable;
+ HRESULT hr;
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+
+ //
+ // Find out the type of component selected.
+ //
+
+ hItem = TreeView_GetSelection( hwndTree );
+
+ if ( hItem ) {
+ if ( GetItemInfo( hwndTree,
+ hItem,
+ &lParam,
+ &dwType,
+ &fEnable) ) {
+
+ //
+ // Disable the install dialog controls.
+ //
+
+ hwndFocus = GetFocus();
+
+ hWaitCursor = LoadCursor( NULL,
+ IDC_WAIT );
+ if ( hWaitCursor ) {
+ hPrevCursor = SetCursor( hWaitCursor );
+ }
+
+ EnableWindow( hwndTree, FALSE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_INSTALL),
+ FALSE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_BROWSE),
+ FALSE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_CLOSE),
+ FALSE );
+
+ if ( lpszInfFile ) {
+
+ LPWSTR lpszPnpID;
+
+ //
+ // Inf file name specified, install the network component
+ // from this file.
+ //
+
+ hr = GetPnpID( lpszInfFile, &lpszPnpID );
+
+ if ( hr == S_OK ) {
+
+ hr = InstallSpecifiedComponent( lpszInfFile,
+ lpszPnpID,
+ pguidNetClass[(UINT)lParam] );
+
+ CoTaskMemFree( lpszPnpID );
+ }
+ else {
+ ErrMsg( hr,
+ L"Error reading the INF file %s.",
+ lpszInfFile );
+ }
+ }
+ else {
+
+ //
+ // Install from system directory.
+ //
+
+ hr = InstallComponent( hwndTree,
+ pguidNetClass[(UINT)lParam] );
+ }
+
+ if ( hWaitCursor ) {
+ SetCursor( hPrevCursor );
+ }
+
+ switch( hr ) {
+
+ case S_OK:
+ MessageBoxW(
+ hwndDlg,
+ L"Component installed successfully.",
+ L"Network Component Installation",
+ MB_OK | MB_ICONINFORMATION );
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)TRUE );
+ break;
+
+ case NETCFG_S_REBOOT:
+ MessageBoxW(
+ hwndDlg,
+ L"Component installed successfully: "
+ L"Reboot required.",
+ L"Network Component Installation",
+ MB_OK | MB_ICONINFORMATION );
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)TRUE );
+
+ }
+
+ //
+ // Enable the install dialog controls.
+ //
+
+ EnableWindow( hwndTree, TRUE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_INSTALL),
+ TRUE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_BROWSE),
+ TRUE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_CLOSE),
+ TRUE );
+
+ SetFocus( hwndFocus );
+ }
+ }
+
+ return;
+}
+
+//
+// Function: GetPnpID
+//
+// Purpose: Retrieve PnpID from an inf file.
+//
+// Arguments:
+// lpszInfFile [in] Inf file to search.
+// lppszPnpID [out] PnpID found.
+//
+// Returns: TRUE on success.
+//
+// Notes:
+//
+
+HRESULT
+GetPnpID (
+ _In_ LPWSTR lpszInfFile,
+ _Outptr_ LPWSTR *lppszPnpID)
+{
+ HINF hInf;
+ LPWSTR lpszModelSection;
+ HRESULT hr;
+
+ *lppszPnpID = NULL;
+
+ hInf = SetupOpenInfFileW( lpszInfFile,
+ NULL,
+ INF_STYLE_WIN4,
+ NULL );
+
+ if ( hInf == INVALID_HANDLE_VALUE )
+ {
+
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ //
+ // Read the Model section name from Manufacturer section.
+ //
+
+ hr = GetKeyValue( hInf,
+ L"Manufacturer",
+ NULL,
+ 1,
+ &lpszModelSection );
+
+ if ( SUCCEEDED(hr) )
+ {
+
+ //
+ // Read PnpID from the Model section.
+ //
+
+ hr = GetKeyValue( hInf,
+ lpszModelSection,
+ NULL,
+ 2,
+ lppszPnpID );
+
+ CoTaskMemFree( lpszModelSection );
+ }
+
+ SetupCloseInfFile( hInf );
+
+ return hr;
+}
+
+//
+// Function: GetKeyValue
+//
+// Purpose: Retrieve the value of a key from the inf file.
+//
+// Arguments:
+// hInf [in] Inf file handle.
+// lpszSection [in] Section name.
+// lpszKey [in] Key name.
+// dwIndex [in] Key index.
+// lppszValue [out] Key value.
+//
+// Returns: S_OK on success, otherwise and error code.
+//
+// Notes:
+//
+
+HRESULT
+GetKeyValue (
+ HINF hInf,
+ _In_ LPCWSTR lpszSection,
+ _In_opt_ LPCWSTR lpszKey,
+ DWORD dwIndex,
+ _Outptr_ LPWSTR *lppszValue)
+{
+ INFCONTEXT infCtx;
+ __range(0, 512) DWORD dwSizeNeeded;
+ HRESULT hr;
+
+ *lppszValue = NULL;
+
+ if ( SetupFindFirstLineW(hInf,
+ lpszSection,
+ lpszKey,
+ &infCtx) == FALSE )
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if ( SetupGetStringFieldW(&infCtx,
+ dwIndex,
+ NULL,
+ 0,
+ &dwSizeNeeded) )
+ {
+ *lppszValue = (LPWSTR)CoTaskMemAlloc( sizeof(WCHAR) * dwSizeNeeded );
+
+ if ( !*lppszValue )
+ {
+ return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ if ( SetupGetStringFieldW(&infCtx,
+ dwIndex,
+ *lppszValue,
+ dwSizeNeeded,
+ NULL) == FALSE )
+ {
+
+ hr = HRESULT_FROM_WIN32(GetLastError());
+
+ CoTaskMemFree( *lppszValue );
+ *lppszValue = NULL;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ hr = HRESULT_FROM_WIN32(dwErr);
+ }
+
+ return hr;
+}
+
+//
+// Function: UninstallSelectedComponent
+//
+// Purpose: Uninstall the selected network component.
+//
+// Arguments:
+// hwndDlg [in] Window handle of the uninstall dialog box.
+//
+// Returns: TRUE on success.
+//
+// Notes:
+//
+
+VOID UninstallSelectedComponent (HWND hwndDlg)
+{
+ HWND hwndTree = NULL;
+ HTREEITEM hItem = NULL;
+ LPARAM lParam;
+ HCURSOR hPrevCursor = NULL;
+ HCURSOR hWaitCursor = NULL;
+ DWORD dwType;
+ BOOL fEnable;
+ HRESULT hr;
+
+ hwndTree = GetDlgItem( hwndDlg,
+ IDT_COMPONENT_LIST );
+
+ //
+ // Get the selected item to get its lParam which is the
+ // PnpID of the network component.
+ //
+
+ hItem = TreeView_GetSelection( hwndTree );
+
+ if ( hItem ) {
+ if ( GetItemInfo( hwndTree,
+ hItem,
+ &lParam,
+ &dwType,
+ &fEnable) ) {
+
+ hWaitCursor = LoadCursor( NULL,
+ IDC_WAIT );
+ if ( hWaitCursor ) {
+ hPrevCursor = SetCursor( hWaitCursor );
+ }
+
+ EnableWindow( hwndTree, FALSE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_REMOVE),
+ FALSE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_CLOSE),
+ FALSE );
+
+ //
+ // Uninstall the selected component.
+ //
+
+ hr = UninstallComponent( (LPWSTR)lParam );
+
+
+ if ( hWaitCursor ) {
+ SetCursor( hPrevCursor );
+ }
+
+ switch( hr ) {
+
+ case S_OK:
+ MessageBoxW(
+ hwndDlg,
+ L"Uninstallation successful.",
+ L"Network Component Uninstallation",
+ MB_OK | MB_ICONINFORMATION );
+
+ CoTaskMemFree( (LPVOID)lParam );
+ TreeView_DeleteItem( hwndTree,
+ hItem );
+
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)TRUE );
+ break;
+
+ case NETCFG_S_REBOOT:
+ MessageBoxW(
+ hwndDlg,
+ L"Uninstallation successful: "
+ L"Reboot required.",
+ L"Network Component Uninstallation",
+ MB_OK | MB_ICONINFORMATION );
+
+ CoTaskMemFree( (LPVOID)lParam );
+ TreeView_DeleteItem( hwndTree,
+ hItem );
+
+ SetWindowLongPtr( hwndDlg,
+ DWLP_USER,
+ (LONG_PTR)TRUE );
+ }
+
+ EnableWindow( hwndTree, TRUE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_REMOVE),
+ TRUE );
+ EnableWindow( GetDlgItem(hwndDlg,IDB_CLOSE),
+ TRUE );
+ }
+ }
+
+ return;
+}
+
+//
+// Function: ExpandCollapseAll
+//
+// Purpose: Expand or collapse a tree.
+//
+// Arguments:
+// hwndTree [in] Window handle of the tree.
+// hTreeItem [in] Handle of root item.
+// uiFlag [in] Flag indicating whether to expand or collapse.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ExpandCollapseAll (HWND hwndTree,
+ HTREEITEM hTreeItem,
+ UINT uiFlag)
+{
+ HTREEITEM hItemChild;
+
+ hItemChild = TreeView_GetChild( hwndTree,
+ hTreeItem );
+
+ if ( hItemChild ) {
+
+ //
+ // If the root has one or more children, expand/collapse the root.
+ //
+
+ TreeView_Expand( hwndTree,
+ hTreeItem,
+ uiFlag );
+ }
+
+ while ( hItemChild ) {
+
+ //
+ // Expand/collapse all the children.
+ //
+
+ ExpandCollapseAll( hwndTree,
+ hItemChild,
+ uiFlag );
+
+ //
+ // Expand/collapse all the siblings.
+ //
+
+ hItemChild = TreeView_GetNextSibling( hwndTree,
+ hItemChild );
+ }
+
+ return;
+}
+
+//
+// Function: GetFileName
+//
+// Purpose: Prompt for a filename.
+//
+// Arguments:
+// hwndDlg [in] Window handle of the parent.
+// lpszFilter [in] See documentation for GetOpenFileName.
+// lpszTitle [in] See documentation for GetOpenFileName.
+// dwFlags [in] See documentation for GetOpenFileName.
+// lpszFile [out] See documentation for GetOpenFileName.
+// Supplied buffer must be at least MAX_PATH+1 WCHARS
+//
+// Returns: See documentation for GetOpenFileName.
+//
+// Notes:
+//
+
+BOOL
+GetFileName (
+ HWND hwndDlg,
+ _In_opt_ LPWSTR lpszFilter,
+ _In_ LPWSTR lpszTitle,
+ DWORD dwFlags,
+ _Out_writes_(MAX_PATH+1) LPWSTR lpszFile,
+ _In_opt_ LPWSTR lpszDefExt,
+ BOOL fSave)
+{
+ OPENFILENAMEW ofn;
+
+ lpszFile[0] = NULL;
+
+ ZeroMemory( &ofn, sizeof(OPENFILENAMEW) );
+ ofn.lStructSize = sizeof(OPENFILENAMEW);
+ ofn.hwndOwner = hwndDlg;
+ ofn.lpstrFilter = lpszFilter;
+ ofn.lpstrFile = lpszFile;
+ ofn.lpstrDefExt = lpszDefExt;
+ ofn.nMaxFile = MAX_PATH+1;
+ ofn.lpstrTitle = lpszTitle;
+ ofn.Flags = dwFlags;
+
+ if ( fSave )
+ {
+ return GetSaveFileName( &ofn );
+ }
+ else
+ {
+ return GetOpenFileName( &ofn );
+ }
+}
+
+//
+// Function: ProcessRightClick
+//
+// Purpose: Handle righ mouse button click.
+//
+// Arguments:
+// lpnm [in] LPNMHDR info
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ProcessRightClick (LPNMHDR lpnm)
+{
+ HTREEITEM hItemSelected;
+ LPARAM lParam;
+ DWORD dwItemType;
+ BOOL fEnabled;
+
+ //
+ // Determine the item on which user clicked the right mouse button.
+ //
+
+ hItemSelected = TreeView_GetDropHilight( lpnm->hwndFrom );
+
+ if ( !hItemSelected ) {
+ hItemSelected = TreeView_GetSelection( lpnm->hwndFrom );
+ }
+ else {
+
+ //
+ // User has right-clicked an unselected item, make that a selected
+ // item.
+ //
+
+ TreeView_Select( lpnm->hwndFrom,
+ hItemSelected,
+ TVGN_CARET );
+ }
+
+ if ( hItemSelected ) {
+
+ //
+ // Get the lParam of the selected node in the tree which points to inf id or
+ // pathtoken name depending on if the node represents a network component or
+ // a binding path.
+ //
+
+ if ( GetItemInfo(lpnm->hwndFrom,
+ hItemSelected,
+ &lParam,
+ &dwItemType,
+ &fEnabled) ) {
+
+ if ( dwItemType & ITEM_NET_COMPONENTS ) {
+
+ //
+ // Show the shortcut menu of operations for a network component.
+ //
+
+ ShowComponentMenu( lpnm->hwndFrom,
+ hItemSelected,
+ lParam);
+ }
+ else {
+ if ( dwItemType & ITEM_NET_BINDINGS ) {
+
+ //
+ // Show the shortcut menu of operations for a binding path.
+ //
+
+ ShowBindingPathMenu( lpnm->hwndFrom,
+ hItemSelected,
+ lParam,
+ fEnabled );
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+//
+// Function: ShowComponentMenu
+//
+// Purpose: Show shortcut menu of options for a network component.
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// hItem [in] Selected item representing a network component.
+// lParam [in] PnpID of the network component.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ShowComponentMenu (HWND hwndOwner,
+ HTREEITEM hItem,
+ LPARAM lParam)
+{
+ ULONG ulSelection;
+ POINT pt;
+
+ GetCursorPos( &pt );
+ ulSelection = (ULONG)TrackPopupMenu( hComponentSubMenu,
+ TPM_RIGHTALIGN | TPM_BOTTOMALIGN |
+ TPM_NONOTIFY | TPM_RETURNCMD |
+ TPM_RIGHTBUTTON,
+ pt.x,
+ pt.y,
+ 0,
+ hwndOwner,
+ NULL );
+
+ if ( ulSelection ) {
+
+ //
+ // Do the selected action.
+ //
+
+ HandleComponentOperation( hwndOwner,
+ ulSelection,
+ hItem,
+ lParam );
+ }
+
+ return;
+}
+
+//
+// Function: ShowBindingPathMenu
+//
+// Purpose: Show shortcut menu of options for a network component.
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// hItem [in] Selected item representing a binding path.
+// lParam [in] PnpID of the network component.
+// fEnabled [in] TRUE when the path is enabled.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+
+VOID ShowBindingPathMenu (HWND hwndOwner,
+ HTREEITEM hItem,
+ LPARAM lParam,
+ BOOL fEnabled)
+{
+ MENUITEMINFOW menuItemInfo;
+ ULONG ulSelection;
+ POINT pt;
+
+ //
+ // Build the shortcut menu depending on whether path is
+ // disabled or enabled.
+ //
+
+ ZeroMemory( &menuItemInfo,
+ sizeof(MENUITEMINFOW) );
+
+ menuItemInfo.cbSize = sizeof( MENUITEMINFOW );
+ menuItemInfo.fMask = MIIM_TYPE | MIIM_ID;
+ menuItemInfo.fType = MFT_STRING;
+ menuItemInfo.fState = MFS_ENABLED;
+
+ if ( fEnabled ) {
+ menuItemInfo.dwTypeData = MENUITEM_DISABLE;
+ menuItemInfo.wID = IDI_DISABLE;
+ }
+ else {
+ menuItemInfo.dwTypeData = MENUITEM_ENABLE;
+ menuItemInfo.wID = IDI_ENABLE;
+ }
+
+ SetMenuItemInfoW( hBindingPathSubMenu,
+ 0,
+ TRUE,
+ &menuItemInfo );
+
+ GetCursorPos( &pt );
+ ulSelection = (ULONG)TrackPopupMenu( hBindingPathSubMenu,
+ TPM_RIGHTALIGN | TPM_BOTTOMALIGN |
+ TPM_NONOTIFY | TPM_RETURNCMD |
+ TPM_RIGHTBUTTON,
+ pt.x,
+ pt.y,
+ 0,
+ hwndOwner,
+ NULL );
+
+ if ( ulSelection ) {
+
+ //
+ // Do the selected action.
+ //
+
+ HandleBindingPathOperation( hwndOwner,
+ ulSelection,
+ hItem,
+ lParam );
+ }
+
+ return;
+}
+
+//
+// Function: GetItemInfo
+//
+// Purpose: Returns information about an item.
+//
+// Arguments:
+// hwndTree [in] Window handle of the tree.
+// hItem [in] Item handle.
+// lParam [out] lParam
+// lpdwItemType [out] Type, binding path or network component.
+// fEnabled [out] TRUE if the binding path or component is enabled.
+//
+// Returns: TRUE on sucess.
+//
+// Notes:
+//
+
+BOOL GetItemInfo (HWND hwndTree,
+ HTREEITEM hItem,
+ LPARAM *lParam,
+ LPDWORD lpdwItemType,
+ BOOL *fEnabled)
+{
+ TVITEMW tvItem;
+ int iImage;
+ BOOL fSuccess;
+
+
+ fSuccess = FALSE;
+
+ //
+ // Get item's information.
+ //
+
+ ZeroMemory( &tvItem,
+ sizeof(TVITEMW) );
+ tvItem.hItem = hItem;
+ tvItem.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_STATE;
+ tvItem.stateMask = TVIS_OVERLAYMASK ;
+
+ if ( TreeView_GetItem(hwndTree,
+ &tvItem) ) {
+
+ *lParam = tvItem.lParam;
+
+ if ( SetupDiGetClassImageIndex(&ClassImageListData,
+ &GUID_DEVCLASS_SYSTEM,
+ &iImage) ) {
+
+ //
+ // Is it a binding path?
+ //
+
+ if ( tvItem.iImage == iImage ) {
+ *lpdwItemType = ITEM_NET_BINDINGS;
+
+ *fEnabled = !(TVIS_OVERLAYMASK & tvItem.state);
+
+ fSuccess = TRUE;
+ }
+ else {
+
+ //
+ // Item is a network component.
+ //
+
+ if ( SetupDiGetClassImageIndex(&ClassImageListData,
+ &GUID_DEVCLASS_NET,
+ &iImage) ) {
+
+ if ( tvItem.iImage == iImage ) {
+ *lpdwItemType = ITEM_NET_ADAPTERS;
+ }
+ else {
+ *lpdwItemType = ITEM_NET_COMPONENTS;
+ }
+
+ *fEnabled = !(TVIS_OVERLAYMASK & tvItem.state);
+
+ fSuccess = TRUE;
+ }
+ else {
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the images of network adapters." );
+ }
+ }
+ }
+ else {
+ ErrMsg( HRESULT_FROM_WIN32(GetLastError()),
+ L"Couldn't load the images of system devices." );
+ }
+ }
+
+ return fSuccess;
+}
+
+//
+// Function: AddBindNameToTree
+//
+// Purpose: Adds an item representing the binding path.
+//
+// Arguments:
+// pncbp [in] Binding path to add.
+// hwndTree [in] Tree handle.
+// hParent [in] Parent item.
+// ulIndex [in] Index of the binding path.
+//
+// Returns: Handle of the item added on success, otherwise NULL.
+//
+// Notes:
+//
+
+HTREEITEM AddBindNameToTree (INetCfgBindingPath *pncbp,
+ HWND hwndTree,
+ HTREEITEM hParent,
+ ULONG ulIndex)
+{
+ WCHAR lpszBindName[40];
+ LPWSTR lpszPathToken;
+ HTREEITEM hTreeItem;
+ TV_INSERTSTRUCTW tvInsertStruc;
+ HRESULT hr;
+
+ hTreeItem = NULL;
+
+ //
+ // Store the path token as lParam.
+ //
+
+ hr = pncbp->GetPathToken( &lpszPathToken );
+
+ if ( hr == S_OK ) {
+
+ StringCchPrintfW (lpszBindName,
+ celems(lpszBindName),
+ L"Binding Path %d",
+ ulIndex );
+
+ ZeroMemory(
+ &tvInsertStruc,
+ sizeof(TV_INSERTSTRUCTW) );
+
+ tvInsertStruc.hParent = hParent;
+
+ tvInsertStruc.hInsertAfter = TVI_LAST;
+
+ tvInsertStruc.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE |
+ TVIF_SELECTEDIMAGE | TVIF_STATE;
+
+ tvInsertStruc.item.pszText = lpszBindName;
+
+ SetupDiGetClassImageIndex( &ClassImageListData,
+ &GUID_DEVCLASS_SYSTEM,
+ &tvInsertStruc.item.iImage );
+
+ tvInsertStruc.item.iSelectedImage = tvInsertStruc.item.iImage;
+
+ tvInsertStruc.item.stateMask = TVIS_OVERLAYMASK;
+
+ if ( pncbp->IsEnabled() == S_FALSE ) {
+ tvInsertStruc.item.state = INDEXTOOVERLAYMASK(
+ IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
+ }
+
+ tvInsertStruc.item.lParam = (LPARAM)lpszPathToken;
+
+ hTreeItem = TreeView_InsertItem( hwndTree,
+ &tvInsertStruc );
+
+ if ( !hTreeItem ) {
+ ErrMsg( hr,
+ L"Couldn't add the binding path %d to the list."
+ L" The binding path will not be shown.", ulIndex );
+
+ CoTaskMemFree( lpszPathToken );
+ }
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the PathToken of the binding path %d."
+ L" The binding path will not be shown.", ulIndex );
+ }
+
+ return hTreeItem;
+}
+
+//
+// Function: AddToTree
+//
+// Purpose: Adds an item representing the network component.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// hParent [in] Parent item.
+// pncc [in] Network component.
+//
+// Returns: Handle of the item added on success, otherwise NULL.
+//
+// Notes:
+//
+
+HTREEITEM AddToTree (HWND hwndTree,
+ HTREEITEM hParent,
+ INetCfgComponent *pncc)
+{
+ return AddToTreeEx( hwndTree,
+ hParent,
+ pncc,
+ FALSE );
+}
+
+//
+// Function: AddToTree
+//
+// Purpose: Adds an item representing the network component.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// hParent [in] Parent item.
+// pncc [in] Network component.
+// fUsePnpId [in] if TRUE, pnp device instance id is used to indentify the component, otherwise inf id.
+//
+// Returns: Handle of the item added on success, otherwise NULL.
+//
+// Notes:
+//
+
+HTREEITEM AddToTreeEx (HWND hwndTree,
+ HTREEITEM hParent,
+ INetCfgComponent *pncc,
+ BOOL fUsePnpId)
+{
+ LPWSTR lpszItemName;
+ LPWSTR lpszId;
+ GUID guidClass;
+ BOOL fEnabled;
+ ULONG ulStatus;
+ HTREEITEM hTreeItem;
+ TV_INSERTSTRUCTW tvInsertStruc;
+ HRESULT hr;
+
+ hTreeItem = NULL;
+
+ hr = pncc->GetDisplayName( &lpszItemName );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get the inf id or pnp instance id of the network component. We store it at lParam
+ // and use it later to retrieve its interface pointer.
+ //
+
+ if ( fUsePnpId )
+ {
+ hr = pncc->GetPnpDevNodeId( &lpszId );
+ }
+ else
+ {
+ hr = pncc->GetId( &lpszId );
+ }
+
+ if ( hr == S_OK ) {
+
+ //
+ // If it is a network adapter then, find out if it enabled/disabled.
+ //
+
+ hr = pncc->GetClassGuid( &guidClass );
+
+ if ( hr == S_OK ) {
+ if ( IsEqualGUID(guidClass, GUID_DEVCLASS_NET) ) {
+ hr = pncc->GetDeviceStatus( &ulStatus );
+ fEnabled = ulStatus == 0;
+ }
+ else {
+ fEnabled = TRUE;
+ }
+ }
+ else {
+
+ //
+ // We can't get the status, so assume that it is disabled.
+ //
+
+ fEnabled = FALSE;
+ }
+
+ ZeroMemory(
+ &tvInsertStruc,
+ sizeof(TV_INSERTSTRUCTW) );
+
+ tvInsertStruc.hParent = hParent;
+
+ tvInsertStruc.hInsertAfter = TVI_LAST;
+
+ tvInsertStruc.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE |
+ TVIF_SELECTEDIMAGE | TVIF_STATE;
+
+ tvInsertStruc.item.pszText = lpszItemName;
+
+ SetupDiGetClassImageIndex( &ClassImageListData,
+ &guidClass,
+ &tvInsertStruc.item.iImage );
+
+ tvInsertStruc.item.iSelectedImage = tvInsertStruc.item.iImage;
+
+ tvInsertStruc.item.stateMask = TVIS_OVERLAYMASK;
+
+ if ( fEnabled == FALSE ) {
+ tvInsertStruc.item.state = INDEXTOOVERLAYMASK(
+ IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
+ }
+
+ tvInsertStruc.item.lParam = (LPARAM)lpszId;
+
+ hTreeItem = TreeView_InsertItem( hwndTree,
+ &tvInsertStruc );
+ if ( !hTreeItem ) {
+ ErrMsg( hr,
+ L"Failed to add %s to the list.",
+ lpszItemName );
+
+ CoTaskMemFree( lpszId );
+ }
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the inf id of %s."
+ L" It will not be added to the list.",
+ lpszItemName );
+ }
+
+ CoTaskMemFree( lpszItemName );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the display name of a network component."
+ L" It will not be added to the list." );
+ }
+
+ return hTreeItem;
+}
+
+//
+// Function: RefreshAll
+//
+// Purpose: Refreshes the main dialog box.
+//
+// Arguments:
+// hwndDlg [in] Dialog box handle.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID RefreshAll (HWND hwndDlg)
+{
+ HWND hwndTypeList;
+ INT iSelected;
+
+ //
+ // Find the selected network component type.
+ //
+
+ hwndTypeList = GetDlgItem( hwndDlg,
+ IDL_COMPONENT_TYPES );
+
+ iSelected = (int)SendMessage( hwndTypeList,
+ CB_GETCURSEL,
+ 0,
+ 0 );
+
+ if ( iSelected != CB_ERR ) {
+
+ //
+ // Before deleting the list in the tree, free the buffer
+ // associated with each item. The buffer holds either the
+ // INF Id or the pathtoken depending on whether it is a
+ // network component or a binding path.
+ //
+
+ ReleaseMemory( GetDlgItem(hwndDlg, IDT_BINDINGS),
+ TVI_ROOT );
+
+ TreeView_DeleteItem (
+ GetDlgItem(hwndDlg, IDT_BINDINGS),
+ TVI_ROOT );
+
+ //
+ // Repopulate the tree with the selected network compnent
+ // type.
+ //
+
+ EnumNetBindings( GetDlgItem(hwndDlg, IDT_BINDINGS),
+ (UINT)iSelected );
+
+ }
+
+ return;
+}
+
+//
+// Function: RefreshItemState
+//
+// Purpose: Refreshes the specified item.
+//
+// Arguments:
+// hwndTree [in] Dialog box handle.
+// hItem [in] Item to refresh.
+// fEnable [in] TRUE if component is enabled.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID RefreshItemState (HWND hwndTree,
+ HTREEITEM hItem,
+ BOOL fEnable)
+{
+ TVITEMW tvItem;
+
+ ZeroMemory( &tvItem,
+ sizeof(TVITEMW) );
+
+ tvItem.hItem = hItem;
+ tvItem.mask = TVIF_STATE;
+ tvItem.stateMask = TVIS_OVERLAYMASK;
+
+ if ( fEnable )
+ tvItem.state = INDEXTOOVERLAYMASK( 0 );
+ else
+ tvItem.state = INDEXTOOVERLAYMASK(
+ IDI_DISABLED_OVL - IDI_CLASSICON_OVERLAYFIRST + 1);
+ TreeView_SetItem( hwndTree,
+ &tvItem );
+ return;
+}
+
+//
+// Function: RefreshBindings
+//
+// Purpose: Refreshes bindings of a specific component.
+//
+// Arguments:
+// hwndBindUnBindDlg [in] Dialog box handle.
+// lpszInfId [in] PnpID of the component whose bindings changed.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID
+RefreshBindings (
+ HWND hwndBindUnBindDlg,
+ _In_ LPWSTR lpszInfId)
+{
+ INetCfg *pnc;
+ INetCfgComponent *pncc;
+ HWND hwndParent;
+ HWND hwndTree;
+ HTREEITEM hItem;
+ HRESULT hr;
+
+
+ hwndParent = GetParent( hwndBindUnBindDlg );
+ hwndTree = GetDlgItem( hwndParent,
+ IDT_BINDINGS );
+
+ hItem = TreeView_GetSelection( hwndTree );
+
+ hr = HrGetINetCfg( FALSE,
+ APP_NAME,
+ &pnc,
+ NULL );
+
+ if ( hr == S_OK ) {
+
+ hr = pnc->FindComponent( lpszInfId,
+ &pncc );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Delete all the children.
+ //
+
+ ReleaseMemory( hwndTree,
+ hItem );
+
+ DeleteChildren( hwndTree,
+ hItem );
+
+ ListBindings( pncc,
+ hwndTree,
+ hItem );
+
+ ReleaseRef( pncc );
+ }
+
+ HrReleaseINetCfg( pnc,
+ FALSE );
+ }
+
+ return;
+}
+
+//
+// Function: ReleaseMemory
+//
+// Purpose: Free memory associated with each item in the tree.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// hTreeItem [in] Root item.
+//
+// Returns: None.
+//
+// Notes:
+//
+// Each node of the tree represents a network component or a binding path.
+// At each node, lParam points to an allocated buffer wherein we store the
+// inf id if it is a network component or pathtoken name if it is a binding
+// path.
+//
+//
+
+VOID ReleaseMemory (HWND hwndTree,
+ HTREEITEM hTreeItem)
+{
+ HTREEITEM hItemChild;
+ TVITEMW tvItem;
+
+ hItemChild = TreeView_GetChild( hwndTree,
+ hTreeItem );
+
+ while ( hItemChild ) {
+
+ ZeroMemory(
+ &tvItem,
+ sizeof(TVITEMW) );
+
+ tvItem.hItem = hItemChild;
+ tvItem.mask = TVIF_PARAM;
+
+ TreeView_GetItem( hwndTree,
+ &tvItem );
+
+ //
+ // It should never be NULL but just in case...
+ //
+
+ if ( tvItem.lParam ) {
+ CoTaskMemFree( (LPVOID)tvItem.lParam );
+
+ }
+
+ ReleaseMemory( hwndTree, hItemChild );
+
+ hItemChild = TreeView_GetNextSibling( hwndTree,
+ hItemChild );
+ }
+
+ return;
+}
+
+//
+// Function: DeleteChildren
+//
+// Purpose: Delete childen of a specific item.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// hTreeItem [in] Parent item.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID DeleteChildren (HWND hwndTree,
+ HTREEITEM hTreeItem)
+{
+ HTREEITEM hItemChild;
+ HTREEITEM hItemSibling;
+
+ hItemChild = TreeView_GetChild( hwndTree,
+ hTreeItem );
+
+ while ( hItemChild ) {
+
+ DeleteChildren( hwndTree,
+ hItemChild );
+
+ hItemSibling = TreeView_GetNextSibling( hwndTree,
+ hItemChild );
+ TreeView_DeleteItem( hwndTree,
+ hItemChild );
+
+ hItemChild = hItemSibling;
+ }
+
+ return;
+}
+
+//
+// Function: InsertItem
+//
+// Purpose: Insert text for each network component type.
+//
+// Arguments:
+// hwndTree [in] Tree handle.
+// uiType [in] Item type, protocol, client, service.
+//
+// Returns: Item handle on success, otherwise NULL.
+//
+// Notes:
+//
+
+HTREEITEM InsertItem (HWND hwndTree,
+ UINT uiType)
+{
+ TV_INSERTSTRUCTW tvInsertStruc;
+
+ ZeroMemory(
+ &tvInsertStruc,
+ sizeof(TV_INSERTSTRUCTW) );
+
+ tvInsertStruc.hParent = TVI_ROOT;
+
+ tvInsertStruc.hInsertAfter = TVI_LAST;
+
+ tvInsertStruc.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE |
+ TVIF_SELECTEDIMAGE;
+
+
+ switch( uiType ) {
+
+ case CLIENTS_SELECTED:
+ tvInsertStruc.item.pszText = L"Client";
+ break;
+
+ case SERVICES_SELECTED:
+ tvInsertStruc.item.pszText = L"Service";
+ break;
+
+ default:
+ tvInsertStruc.item.pszText = L"Protocol";
+ break;
+ }
+
+ SetupDiGetClassImageIndex( &ClassImageListData,
+ pguidNetClass[uiType],
+ &tvInsertStruc.item.iImage );
+
+ tvInsertStruc.item.iSelectedImage = tvInsertStruc.item.iImage;
+
+ tvInsertStruc.item.lParam = (LPARAM)uiType;
+
+ return TreeView_InsertItem( hwndTree,
+ &tvInsertStruc );
+
+}
+
+//
+// Function: UpdateComponentTypeList
+//
+// Purpose: Insert text for each network component type.
+//
+// Arguments:
+// hwndTypeList [in] ListView handle.
+//
+// Returns: TRUE on success.
+//
+// Notes:
+//
+
+BOOL UpdateComponentTypeList (HWND hwndTypeList)
+{
+ UINT i;
+
+ for (i=0; i < 3; ++i) {
+ SendMessage( hwndTypeList,
+ CB_ADDSTRING,
+ (WPARAM)0,
+ (LPARAM)lpszNetClass[i] );
+ }
+
+ SendMessage( hwndTypeList,
+ CB_SETCURSEL,
+ (WPARAM)DEFAULT_COMPONENT_SELECTED,
+ (LPARAM)0 );
+ return TRUE;
+}
+
+//
+// Function: ErrMsg
+//
+// Purpose: Insert text for each network component type.
+//
+// Arguments:
+// hr [in] Error code.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ErrMsg (HRESULT hr,
+ LPCWSTR lpFmt,
+ ...)
+{
+
+ LPWSTR lpSysMsg = NULL;
+ WCHAR buf[400];
+ size_t offset;
+ va_list vArgList;
+
+
+ if ( hr != 0 ) {
+ StringCchPrintfW ( buf,
+ celems(buf),
+ L"Error %#lx: ",
+ hr );
+ }
+ else {
+ buf[0] = 0;
+ }
+
+ offset = wcslen( buf );
+
+ va_start( vArgList,
+ lpFmt );
+ StringCchVPrintfW ( buf+offset,
+ celems(buf) - offset,
+ lpFmt,
+ vArgList );
+
+ va_end( vArgList );
+
+ if ( hr != 0 ) {
+ FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ hr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&lpSysMsg,
+ 0,
+ NULL );
+ if ( lpSysMsg ) {
+
+ offset = wcslen( buf );
+
+ StringCchPrintfW ( buf+offset,
+ celems(buf) - offset,
+ L"\n\nPossible cause:\n\n" );
+
+ offset = wcslen( buf );
+
+ StringCchCatW ( buf+offset,
+ celems(buf) - offset,
+ lpSysMsg );
+
+ LocalFree( (HLOCAL)lpSysMsg );
+ }
+
+ MessageBoxW( NULL,
+ buf,
+ L"Error",
+ MB_ICONERROR | MB_OK );
+ }
+ else {
+ MessageBoxW( NULL,
+ buf,
+ L"BindView",
+ MB_ICONINFORMATION | MB_OK );
+ }
+
+ return;
+}
diff --git a/network/config/bindview/BINDVIEW.H b/network/config/bindview/BINDVIEW.H
new file mode 100644
index 00000000..2753b753
--- /dev/null
+++ b/network/config/bindview/BINDVIEW.H
@@ -0,0 +1,250 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: B I N D V I E W . H
+//
+// Contents: Function Prototypes
+//
+// Notes:
+//
+// Author: Alok Sinha 15-May-01
+//
+//----------------------------------------------------------------------------
+
+#ifndef _BINDVIEW_H_INCLUDED
+
+#define _BINDVIEW_H_INCLUDED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <wchar.h>
+#include <commctrl.h> // For common controls, e.g. Tree
+#include <commdlg.h>
+#include <setupapi.h>
+#include <devguid.h>
+
+#include "NetCfgAPI.h"
+#include "resource.h"
+#include <strsafe.h>
+
+__user_code; // Annotation to specify PreFast analysis mode
+
+#define celems(_x) (sizeof(_x) / sizeof(_x[0]))
+
+#define ID_STATUS 100
+#define APP_NAME L"BindView"
+
+#define CLIENTS_SELECTED 0
+#define SERVICES_SELECTED 1
+#define PROTOCOLS_SELECTED 2
+#define ADAPTERS_SELECTED 3
+
+#define ITEM_NET_COMPONENTS 1
+#define ITEM_NET_BINDINGS 2
+#define ITEM_NET_ADAPTERS 4
+
+#define DEFAULT_COMPONENT_SELECTED CLIENTS_SELECTED
+
+#define WM_NO_COMPONENTS WM_USER+1
+
+#define MENUITEM_ENABLE L"Enable"
+#define MENUITEM_DISABLE L"Disable"
+
+extern HINSTANCE hInstance;
+extern const GUID *pguidNetClass [];
+extern LPWSTR lpszNetClass [];
+
+typedef struct _BIND_UNBIND_INFO {
+ LPWSTR lpszInfId;
+ BOOL fBindTo;
+} BIND_UNBIND_INFO, *LPBIND_UNBIND_INFO;
+
+//
+// Functions defined in bindview.cpp
+//
+
+INT_PTR CALLBACK MainDlgProc (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+INT_PTR CALLBACK BindComponentDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+INT_PTR CALLBACK InstallDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+INT_PTR CALLBACK UninstallDlg (HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+VOID DumpBindings ( _In_ LPWSTR lpszFile);
+
+VOID InstallSelectedComponentType (HWND hwndDlg,
+ _In_opt_ LPWSTR lpszInfFile);
+
+HRESULT GetPnpID ( _In_ LPWSTR lpszInfFile,
+ _Outptr_ LPWSTR *lppszPnpID);
+
+HRESULT GetKeyValue (HINF hInf,
+ _In_ LPCWSTR lpszSection,
+ _In_opt_ LPCWSTR lpszKey,
+ DWORD dwIndex,
+ _Outptr_ LPWSTR *lppszValue);
+
+VOID UninstallSelectedComponent (HWND hwndDlg);
+
+VOID ExpandCollapseAll (HWND hwndTree,
+ HTREEITEM hTreeItem,
+ UINT uiFlag);
+
+BOOL GetFileName (HWND hwndDlg,
+ _In_opt_ LPWSTR lpszFilter,
+ _In_ LPWSTR lpszTitle,
+ DWORD dwFlags,
+ _Out_writes_(MAX_PATH+1) LPWSTR lpszFile,
+ _In_opt_ LPWSTR lpszDefExt,
+ BOOL fSave);
+
+VOID ProcessRightClick (LPNMHDR lpnm);
+
+VOID ShowComponentMenu (HWND hwndOwner,
+ HTREEITEM hItem,
+ LPARAM lParam);
+
+VOID ShowBindingPathMenu (HWND hwndOwner,
+ HTREEITEM hItem,
+ LPARAM lParam,
+ BOOL fEnabled);
+
+BOOL GetItemInfo (HWND hwndTree,
+ HTREEITEM hItem,
+ LPARAM *lParam,
+ LPDWORD lpdwItemType,
+ BOOL *fEnabled);
+
+HTREEITEM AddBindNameToTree (INetCfgBindingPath *pncbp,
+ HWND hwndTree,
+ HTREEITEM hParent,
+ ULONG ulIndex);
+
+HTREEITEM AddToTree (HWND hwndTree,
+ HTREEITEM hParent,
+ INetCfgComponent *pncc);
+
+HTREEITEM AddToTreeEx (HWND hwndTree,
+ HTREEITEM hParent,
+ INetCfgComponent *pncc,
+ BOOL fUsePnpId);
+
+VOID RefreshAll (HWND hwndDlg);
+
+VOID RefreshItemState (HWND hwndTree,
+ HTREEITEM hItem,
+ BOOL fEnable);
+
+VOID RefreshBindings (HWND hwndTree,
+ _In_ LPWSTR lpszInfId);
+
+VOID ReleaseMemory (HWND hwndTree,
+ HTREEITEM hTreeItem);
+
+
+VOID DeleteChildren (HWND hwndTree,
+ HTREEITEM hTreeItem);
+
+HTREEITEM InsertItem (HWND hwndTree,
+ UINT uiType);
+
+BOOL UpdateComponentTypeList (HWND hwndTypeList);
+
+
+VOID ErrMsg (HRESULT hr,
+ LPCWSTR lpFmt,
+ ...);
+
+//
+// Functions defined in component.cpp
+//
+
+VOID HandleComponentOperation (HWND hwndOwner,
+ ULONG ulSelection,
+ HTREEITEM hItem,
+ LPARAM lParam);
+
+VOID BindUnbindComponents( HWND hwndOwner,
+ HTREEITEM hItem,
+ _In_ LPWSTR lpszInfId,
+ BOOL fBindTo);
+
+HRESULT InstallComponent (HWND hwndDlg,
+ const GUID *pguidClass);
+
+HRESULT InstallSpecifiedComponent ( _In_ LPWSTR lpszInfFile,
+ _In_ LPWSTR lpszPnpID,
+ const GUID *pguidClass);
+
+DWORD ListCompToBindUnbind ( _In_ LPWSTR lpszInfId,
+ UINT uiType,
+ HWND hwndTree,
+ BOOL fBound);
+
+BOOL BindUnbind ( _In_ LPWSTR lpszInfId,
+ HWND hwndTree,
+ BOOL fBind);
+
+VOID ListInstalledComponents (HWND hwndTree,
+ const GUID *pguidClass);
+
+HRESULT UninstallComponent ( _In_ LPWSTR lpszInfId);
+
+//
+// Functions defined in binding.cpp
+//
+
+VOID WriteBindings (FILE *fp);
+
+VOID WriteBindingPath (FILE *fp,
+ INetCfgComponent *pncc);
+
+VOID WriteInterfaces (FILE *fp,
+ INetCfgBindingPath *pncbp);
+
+BOOL EnumNetBindings (HWND hwndTree,
+ UINT uiTypeSelected);
+
+VOID ListBindings (INetCfgComponent *pncc,
+ HWND hwndTree,
+ HTREEITEM hTreeItemRoot);
+
+VOID ListInterfaces (INetCfgBindingPath *pncbp,
+ HWND hwndTree,
+ HTREEITEM hTreeItemRoot);
+
+VOID HandleBindingPathOperation (HWND hwndOwner,
+ ULONG ulSelection,
+ HTREEITEM hItem,
+ LPARAM lParam);
+
+VOID EnableBindingPath (HWND hwndOwner,
+ HTREEITEM hItem,
+ _In_ LPWSTR lpszTokenPath,
+ BOOL fEnable);
+
+LPWSTR GetComponentId (HWND hwndTree,
+ HTREEITEM hItem);
+
+INetCfgBindingPath *FindBindingPath (INetCfg *pnc,
+ _In_ LPWSTR lpszInfId,
+ _In_ LPWSTR lpszPathTokenSelected);
+
+#endif
diff --git a/network/config/bindview/BINDVIEW.ICO b/network/config/bindview/BINDVIEW.ICO
new file mode 100644
index 00000000..47c1d817
--- /dev/null
+++ b/network/config/bindview/BINDVIEW.ICO
Binary files differ
diff --git a/network/config/bindview/BindView.rc b/network/config/bindview/BindView.rc
new file mode 100644
index 00000000..71d8f894
--- /dev/null
+++ b/network/config/bindview/BindView.rc
@@ -0,0 +1,194 @@
+//Microsoft Developer Studio generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAIN DIALOGEX 0, 0, 400, 215
+STYLE DS_SETFOREGROUND | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "Network Bindings"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Tree1",IDT_BINDINGS,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS |
+ TVS_INFOTIP | WS_BORDER | WS_TABSTOP,7,28,385,148,
+ WS_EX_CLIENTEDGE
+ PUSHBUTTON "Install...",IDB_INSTALL,8,185,53,16
+ PUSHBUTTON "Collapse All",IDB_COLLAPSE_ALL,265,185,53,16
+ PUSHBUTTON "Expand All",IDB_EXPAND_ALL,177,185,53,16
+ PUSHBUTTON "Uninstall...",IDB_UNINSTALL,91,185,53,16
+ COMBOBOX IDL_COMPONENT_TYPES,109,7,146,61,CBS_DROPDOWNLIST |
+ CBS_DISABLENOSCROLL | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ CONTROL "Show Bindings For",IDS_COMPONENT,"Static",
+ SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,43,11,60,8
+ PUSHBUTTON "Save Bindings",IDB_SAVE,339,185,53,16
+END
+
+IDD_BIND_UNBIND DIALOG DISCARDABLE 0, 0, 269, 140
+STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Bind To Network Features"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Tree3",IDT_COMPONENT_LIST,"SysTreeView32",
+ TVS_CHECKBOXES | TVS_INFOTIP | TVS_FULLROWSELECT |
+ WS_BORDER | WS_GROUP | WS_TABSTOP,16,24,236,82
+ DEFPUSHBUTTON "Bind",IDB_BIND_UNBIND,19,120,50,14
+ DEFPUSHBUTTON "Close",IDB_CLOSE,201,119,50,14,WS_GROUP
+ GROUPBOX "Select features to bind to",IDG_COMPONENT_LIST,7,7,
+ 253,107,WS_GROUP
+END
+
+IDD_INSTALL DIALOG DISCARDABLE 0, 0, 234, 95
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "Select Network Feature Type"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Tree1",IDT_COMPONENT_LIST,"SysTreeView32",
+ TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | TVS_NOSCROLL |
+ WS_BORDER | WS_GROUP | WS_TABSTOP,13,20,207,36
+ DEFPUSHBUTTON "Install",IDB_INSTALL,17,73,50,14
+ PUSHBUTTON "Browse...",IDB_BROWSE,92,73,50,14
+ PUSHBUTTON "Close",IDB_CLOSE,173,72,50,14
+ GROUPBOX "Select type of feature to install",IDG_COMPONENT_LIST,
+ 7,7,221,57
+END
+
+IDD_UNINSTALL DIALOG DISCARDABLE 0, 0, 258, 141
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "Uninstall Network Feature"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Tree1",IDT_COMPONENT_LIST,"SysTreeView32",
+ TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER |
+ WS_GROUP | WS_TABSTOP,25,28,207,76
+ DEFPUSHBUTTON "Remove",IDB_REMOVE,33,120,50,14
+ PUSHBUTTON "Close",IDB_CLOSE,171,120,50,14
+ GROUPBOX "Select feature to uninstall",IDG_COMPONENT_LIST,15,15,
+ 227,97
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDM_OPTIONS MENU DISCARDABLE
+BEGIN
+ POPUP "Features"
+ BEGIN
+ MENUITEM "Bind To...", IDI_BIND_TO
+ MENUITEM "Unbind From...", IDI_UNBIND_FROM
+ MENUITEM SEPARATOR
+ MENUITEM "Cancel", IDI_CANCEL
+ END
+ POPUP "Bindings"
+ BEGIN
+ MENUITEM "Enable", IDI_ENABLE
+ MENUITEM SEPARATOR
+ MENUITEM "Cancel", IDI_CANCEL
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_BINDVIEW ICON DISCARDABLE "bindview.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resrc1.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""resource.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_MAIN, DIALOG
+ BEGIN
+ RIGHTMARGIN, 392
+ HORZGUIDE, 201
+ END
+
+ IDD_INSTALL, DIALOG
+ BEGIN
+ HORZGUIDE, 73
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/network/config/bindview/Component.cpp b/network/config/bindview/Component.cpp
new file mode 100644
index 00000000..3f42b56b
--- /dev/null
+++ b/network/config/bindview/Component.cpp
@@ -0,0 +1,897 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: C O M P O N E N T . C P P
+//
+// Contents: Functions to illustrate
+// o How to enumerate network components.
+// o How to install protocols, clients and services.
+// o How to uninstall protocols, clients and services.
+// o How to bind/unbind network components.
+//
+// Notes:
+//
+// Author: Alok Sinha 15-May-01
+//
+//----------------------------------------------------------------------------
+
+#include "bindview.h"
+
+//
+// Function: HandleComponentOperation
+//
+// Purpose: Do component specific functions.
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// ulSelection [in] Option selected.
+// hItem [in] Item selected.
+// lParam [in] lParam of the item.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID HandleComponentOperation (HWND hwndOwner,
+ ULONG ulSelection,
+ HTREEITEM hItem,
+ LPARAM lParam)
+{
+ switch( ulSelection ) {
+
+ case IDI_BIND_TO:
+ case IDI_UNBIND_FROM:
+
+ //
+ // Bind/unbind components.
+ //
+
+ BindUnbindComponents( hwndOwner,
+ hItem,
+ (LPWSTR)lParam,
+ ulSelection == IDI_BIND_TO );
+ }
+
+ return;
+}
+
+//
+// Function: BindUnbindComponents
+//
+// Purpose: Bind/unbind a network component.
+//
+// Arguments:
+// hwndOwner [in] Owner window.
+// hItem [in] Item handle of the network component.
+// lpszInfId [in] PnpID of the network component.
+// fBindTo [in] if TRUE, bind, otherwise unbind.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID BindUnbindComponents( HWND hwndOwner,
+ HTREEITEM hItem,
+ _In_ LPWSTR lpszInfId,
+ BOOL fBindTo)
+{
+ UNREFERENCED_PARAMETER(hItem);
+
+ BIND_UNBIND_INFO BindUnbind;
+
+ BindUnbind.lpszInfId = lpszInfId;
+ BindUnbind.fBindTo = fBindTo;
+
+ DialogBoxParam( hInstance,
+ MAKEINTRESOURCE(IDD_BIND_UNBIND),
+ hwndOwner,
+ BindComponentDlg,
+ (LPARAM)&BindUnbind );
+
+ return;
+}
+
+//
+// Function: InstallComponent
+//
+// Purpose: Install a network component.
+//
+// Arguments:
+// hwndDlg [in] Owner window.
+// pguidClass [in] Class GUID of type of network component to install.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT InstallComponent (HWND hwndDlg,
+ const GUID *pguidClass)
+{
+ INetCfg *pnc;
+ INetCfgClass *pncClass;
+ INetCfgClassSetup *pncClassSetup;
+ INetCfgComponent *pnccItem;
+ LPWSTR lpszApp;
+ OBO_TOKEN obo;
+ HRESULT hr;
+
+ //
+ // Get INetCfg reference.
+ //
+
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get network component's class reference.
+ //
+
+ hr = pnc->QueryNetCfgClass( pguidClass,
+ IID_INetCfgClass,
+ (PVOID *)&pncClass );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get Setup class reference.
+ //
+
+ hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+ (LPVOID *)&pncClassSetup );
+
+ if ( hr == S_OK ) {
+
+ ZeroMemory( &obo,
+ sizeof(OBO_TOKEN) );
+
+ obo.Type = OBO_USER;
+
+ //
+ // Let the network class installer prompt the user to select
+ // a network component to install.
+ //
+
+ hr = pncClassSetup->SelectAndInstall( hwndDlg,
+ &obo,
+ &pnccItem );
+
+ if ( (hr == S_OK) || (hr == NETCFG_S_REBOOT) ) {
+
+ hr = pnc->Apply();
+
+ if ( (hr != S_OK) && (hr != NETCFG_S_REBOOT) ) {
+
+ ErrMsg( hr,
+ L"Couldn't apply the changes after"
+ L" installing the network component." );
+ }
+
+ }
+ else {
+ if ( hr != HRESULT_FROM_WIN32(ERROR_CANCELLED) ) {
+ ErrMsg( hr,
+ L"Couldn't install the network component." );
+ }
+ }
+
+ ReleaseRef( pncClassSetup );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface to setup class." );
+ }
+
+ ReleaseRef( pncClass );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get a pointer to class interface." );
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't the get notify object interface." );
+ }
+ }
+
+ return hr;
+}
+
+//
+// Function: InstallSpecifiedComponent
+//
+// Purpose: Install a network component from an INF file.
+//
+// Arguments:
+// lpszInfFile [in] INF file.
+// lpszPnpID [in] PnpID of the network component to install.
+// pguidClass [in] Class GUID of the network component.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+HRESULT InstallSpecifiedComponent ( _In_ LPWSTR lpszInfFile,
+ _In_ LPWSTR lpszPnpID,
+ const GUID *pguidClass)
+{
+ INetCfg *pnc;
+ LPWSTR lpszApp;
+ HRESULT hr;
+
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Install the network component.
+ //
+
+ hr = HrInstallNetComponent( pnc,
+ lpszPnpID,
+ pguidClass,
+ lpszInfFile );
+ if ( (hr == S_OK) || (hr == NETCFG_S_REBOOT) ) {
+
+ hr = pnc->Apply();
+ }
+ else {
+ if ( hr != HRESULT_FROM_WIN32(ERROR_CANCELLED) ) {
+ ErrMsg( hr,
+ L"Couldn't install the network component." );
+ }
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't the get notify object interface." );
+ }
+ }
+
+ return hr;
+}
+
+//
+// Function: ListCompToBindUnbind
+//
+// Purpose: List all the components that are bound or bindable.
+//
+// Arguments:
+// lpszInfId [in] PnpID of the network component.
+// uiType [in] Type of network component.
+// hwndTree [in] Tree handle in which to list.
+// fBound [in] if TRUE, list components that are bound.
+//
+// Returns: Number of components listed.
+//
+// Notes:
+//
+
+DWORD ListCompToBindUnbind ( _In_ LPWSTR lpszInfId,
+ UINT uiType,
+ HWND hwndTree,
+ BOOL fBound)
+{
+ INetCfg *pnc;
+ INetCfgComponent *pncc;
+ IEnumNetCfgComponent *pencc;
+ INetCfgComponentBindings *pnccb;
+ INetCfgComponent *pnccToBindUnbind;
+ LPWSTR lpszApp;
+ DWORD dwCount;
+ HRESULT hr;
+
+
+ dwCount = 0;
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get a reference to the network component selected.
+ //
+
+ hr = pnc->FindComponent( lpszInfId,
+ &pncc );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get Component Enumerator Interface.
+ //
+
+ hr = HrGetComponentEnum( pnc,
+ pguidNetClass[uiType],
+ &pencc );
+ if ( hr == S_OK ) {
+
+ hr = pncc->QueryInterface( IID_INetCfgComponentBindings,
+ (PVOID *)&pnccb );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstComponent( pencc, &pnccToBindUnbind );
+
+ while( hr == S_OK ) {
+
+ hr = pnccb->IsBoundTo( pnccToBindUnbind );
+
+ //
+ // fBound = TRUE ==> Want to list components that are
+ // bound.
+ //
+
+ if ( fBound ) {
+
+ if ( hr == S_OK ) {
+ if ( IsEqualIID( *pguidNetClass[uiType], GUID_DEVCLASS_NET) )
+ {
+ AddToTreeEx( hwndTree,
+ TVI_ROOT,
+ pnccToBindUnbind,
+ TRUE );
+ }
+ else
+ {
+ AddToTreeEx( hwndTree,
+ TVI_ROOT,
+ pnccToBindUnbind,
+ FALSE );
+ }
+
+ dwCount++;
+ }
+ }
+ else {
+
+ //
+ // fBound = FALSE ==> Want to list components that
+ // are not bound but are bindable.
+ //
+
+ if ( hr == S_FALSE ) {
+
+ hr = pnccb->IsBindableTo( pnccToBindUnbind );
+
+ if ( hr == S_OK ) {
+
+ if ( IsEqualIID( *pguidNetClass[uiType], GUID_DEVCLASS_NET) )
+ {
+ AddToTreeEx( hwndTree,
+ TVI_ROOT,
+ pnccToBindUnbind,
+ TRUE );
+ }
+ else
+ {
+ AddToTreeEx( hwndTree,
+ TVI_ROOT,
+ pnccToBindUnbind,
+ FALSE );
+ }
+
+ dwCount++;
+ }
+ }
+ }
+
+ ReleaseRef( pnccToBindUnbind );
+
+ hr = HrGetNextComponent( pencc, &pnccToBindUnbind );
+ }
+
+ ReleaseRef( pnccb );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the component binding interface "
+ L"of %s.",
+ lpszInfId );
+ }
+
+ ReleaseRef( pencc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the network component enumerator "
+ L"interface." );
+ }
+
+ ReleaseRef( pncc );
+
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface pointer to %s.",
+ lpszInfId );
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return dwCount;
+}
+
+//
+// Function: BindUnbind
+//
+// Purpose: Bind/unbind a network component.
+//
+// Arguments:
+// lpszInfId [in] PnpID of the network component to bind/unbind.
+// hwndTree [in] Tree handle.
+// fBind [in] if TRUE, bind, otherwise unbind.
+//
+// Returns: TRUE on success.
+//
+// Notes:
+//
+
+BOOL BindUnbind ( _In_ LPWSTR lpszInfId,
+ HWND hwndTree,
+ BOOL fBind)
+{
+ INetCfg *pnc;
+ INetCfgComponent *pncc;
+ INetCfgComponentBindings *pnccb;
+ INetCfgComponent *pnccToBindUnbind;
+ LPWSTR lpszApp;
+ HTREEITEM hTreeItem;
+ TVITEMW tvItem;
+ HRESULT hr;
+ BOOL fChange;
+
+
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ fChange = FALSE;
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get a reference to the network component.
+ //
+
+ hr = pnc->FindComponent( lpszInfId,
+ &pncc );
+ if ( hr == S_OK ) {
+
+ //
+ // Get a reference to the component's binding.
+ //
+
+ hr = pncc->QueryInterface( IID_INetCfgComponentBindings,
+ (PVOID *)&pnccb );
+ if ( hr == S_OK ) {
+
+ //
+ // Start with the root item.
+ //
+
+ hTreeItem = TreeView_GetRoot( hwndTree );
+
+ //
+ // Bind/unbind the network component with every component
+ // that is checked.
+ //
+
+ while ( hTreeItem ) {
+
+ ZeroMemory( &tvItem,
+ sizeof(TVITEMW) );
+
+ tvItem.hItem = hTreeItem;
+ tvItem.mask = TVIF_PARAM | TVIF_STATE;
+ tvItem.stateMask = TVIS_STATEIMAGEMASK;
+
+ if ( TreeView_GetItem(hwndTree,
+ &tvItem) ) {
+
+ //
+ // Is the network component selected?
+ //
+
+ if ( (tvItem.state >> 12) == 2 ) {
+
+ //
+ // Get a reference to the selected component.
+ //
+ // For adapters, lParam is pnp instance id. So, FindComponent will fail. In that case, search
+ // for a network adapter matching the pnp instance id. This will ensure that we get to the right
+ // network adapter in case there are multiple identical adapters in the system.
+
+ hr = pnc->FindComponent( (LPWSTR)tvItem.lParam,
+ &pnccToBindUnbind );
+ if ( hr != S_OK )
+ {
+ hr = HrFindNetComponentByPnpId( pnc,
+ (LPWSTR)tvItem.lParam,
+ &pnccToBindUnbind );
+ }
+
+ if ( hr == S_OK ) {
+
+ if ( fBind ) {
+
+ //
+ // Bind the component to the selected component.
+ //
+
+ hr = pnccb->BindTo( pnccToBindUnbind );
+
+ if ( !fChange ) {
+ fChange = hr == S_OK;
+ }
+
+ if ( hr != S_OK ) {
+ ErrMsg( hr,
+ L"%s couldn't be bound to %s.",
+ lpszInfId, (LPWSTR)tvItem.lParam );
+ }
+ }
+ else {
+ //
+ // Unbind the component from the selected component.
+ //
+
+ hr = pnccb->UnbindFrom( pnccToBindUnbind );
+
+ if ( !fChange ) {
+ fChange = hr == S_OK;
+ }
+
+ if ( hr != S_OK ) {
+ ErrMsg( hr,
+ L"%s couldn't be unbound from %s.",
+ lpszInfId, (LPWSTR)tvItem.lParam );
+ }
+ }
+
+ ReleaseRef( pnccToBindUnbind );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface pointer to %s. "
+ L"%s will not be bound to it.",
+ (LPWSTR)tvItem.lParam,
+ lpszInfId );
+ }
+ }
+ }
+
+ //
+ // Get the next item.
+ //
+
+ hTreeItem = TreeView_GetNextSibling( hwndTree,
+ hTreeItem );
+ }
+
+ ReleaseRef( pnccb );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get a binding interface of %s.",
+ lpszInfId );
+ }
+
+ ReleaseRef( pncc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface pointer to %s.",
+ lpszInfId );
+ }
+
+ //
+ // If one or more network components have been bound/unbound,
+ // apply the changes.
+ //
+
+ if ( fChange ) {
+ hr = pnc->Apply();
+
+ fChange = hr == S_OK;
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return fChange;
+}
+
+//
+// Function: ListInstalledComponents
+//
+// Purpose: List installed network components of specific class.
+//
+// Arguments:
+// hwndTree [in] Tree handle in which to list.
+// pguidClass [in] Class GUID of the network component class.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID ListInstalledComponents (HWND hwndTree,
+ const GUID *pguidClass)
+{
+ INetCfg *pnc;
+ IEnumNetCfgComponent *pencc;
+ INetCfgComponent *pncc;
+ LPWSTR lpszApp;
+ HRESULT hr;
+
+
+ hr = HrGetINetCfg( FALSE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get Component Enumerator Interface.
+ //
+
+ hr = HrGetComponentEnum( pnc,
+ pguidClass,
+ &pencc );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstComponent( pencc, &pncc );
+
+ while( hr == S_OK ) {
+
+ //
+ // Add an item to the tree for the network component.
+ //
+
+ AddToTree( hwndTree,
+ TVI_ROOT,
+ pncc );
+
+ ReleaseRef( pncc );
+
+ hr = HrGetNextComponent( pencc, &pncc );
+ }
+
+ ReleaseRef( pencc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Failed to get the network component enumerator." );
+ }
+
+ HrReleaseINetCfg( pnc, FALSE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return;
+}
+
+//
+// Function: UninstallComponent
+//
+// Purpose: Uninstall a network component.
+//
+// Arguments:
+// lpszInfId [in] PnpID of the network component to uninstall.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT UninstallComponent ( _In_ LPWSTR lpszInfId)
+{
+ INetCfg *pnc;
+ INetCfgComponent *pncc;
+ INetCfgClass *pncClass;
+ INetCfgClassSetup *pncClassSetup;
+ LPWSTR lpszApp;
+ GUID guidClass;
+ OBO_TOKEN obo;
+ HRESULT hr;
+
+ hr = HrGetINetCfg( TRUE,
+ APP_NAME,
+ &pnc,
+ &lpszApp );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get a reference to the network component to uninstall.
+ //
+
+ hr = pnc->FindComponent( lpszInfId,
+ &pncc );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get the class GUID.
+ //
+
+ hr = pncc->GetClassGuid( &guidClass );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get a reference to component's class.
+ //
+
+ hr = pnc->QueryNetCfgClass( &guidClass,
+ IID_INetCfgClass,
+ (PVOID *)&pncClass );
+ if ( hr == S_OK ) {
+
+ //
+ // Get the setup interface.
+ //
+
+ hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+ (LPVOID *)&pncClassSetup );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Uninstall the component.
+ //
+
+ ZeroMemory( &obo,
+ sizeof(OBO_TOKEN) );
+
+ obo.Type = OBO_USER;
+
+ hr = pncClassSetup->DeInstall( pncc,
+ &obo,
+ NULL );
+ if ( (hr == S_OK) || (hr == NETCFG_S_REBOOT) ) {
+
+ hr = pnc->Apply();
+
+ if ( (hr != S_OK) && (hr != NETCFG_S_REBOOT) ) {
+ ErrMsg( hr,
+ L"Couldn't apply the changes after"
+ L" uninstalling %s.",
+ lpszInfId );
+ }
+ }
+ else {
+ ErrMsg( hr,
+ L"Failed to uninstall %s.",
+ lpszInfId );
+ }
+
+ ReleaseRef( pncClassSetup );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface to setup class." );
+ }
+
+ ReleaseRef( pncClass );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get a pointer to class interface "
+ L"of %s.",
+ lpszInfId );
+ }
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the class guid of %s.",
+ lpszInfId );
+ }
+
+ ReleaseRef( pncc );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get an interface pointer to %s.",
+ lpszInfId );
+ }
+
+ HrReleaseINetCfg( pnc,
+ TRUE );
+ }
+ else {
+ if ( (hr == NETCFG_E_NO_WRITE_LOCK) && lpszApp ) {
+ ErrMsg( hr,
+ L"%s currently holds the lock, try later.",
+ lpszApp );
+
+ CoTaskMemFree( lpszApp );
+ }
+ else {
+ ErrMsg( hr,
+ L"Couldn't get the notify object interface." );
+ }
+ }
+
+ return hr;
+}
diff --git a/network/config/bindview/NetCfgAPI.cpp b/network/config/bindview/NetCfgAPI.cpp
new file mode 100644
index 00000000..5080bb41
--- /dev/null
+++ b/network/config/bindview/NetCfgAPI.cpp
@@ -0,0 +1,878 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: N E T C F G A P I . C P P
+//
+// Contents: Functions to illustrate INetCfg API
+//
+// Notes:
+//
+// Author: Alok Sinha 15-May-01
+//
+//----------------------------------------------------------------------------
+
+#include "NetCfgAPI.h"
+
+//
+// Function: HrGetINetCfg
+//
+// Purpose: Get a reference to INetCfg.
+//
+// Arguments:
+// fGetWriteLock [in] If TRUE, Write lock.requested.
+// lpszAppName [in] Application name requesting the reference.
+// ppnc [out] Reference to INetCfg.
+// lpszLockedBy [in] Optional. Application who holds the write lock.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetINetCfg (IN BOOL fGetWriteLock,
+ IN LPCWSTR lpszAppName,
+ OUT INetCfg** ppnc,
+ _Outptr_opt_result_maybenull_ LPWSTR *lpszLockedBy)
+{
+ INetCfg *pnc = NULL;
+ INetCfgLock *pncLock = NULL;
+ HRESULT hr = S_OK;
+
+ //
+ // Initialize the output parameters.
+ //
+
+ *ppnc = NULL;
+
+ if ( lpszLockedBy )
+ {
+ *lpszLockedBy = NULL;
+ }
+ //
+ // Initialize COM
+ //
+
+ hr = CoInitialize( NULL );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Create the object implementing INetCfg.
+ //
+
+ hr = CoCreateInstance( CLSID_CNetCfg,
+ NULL, CLSCTX_INPROC_SERVER,
+ IID_INetCfg,
+ (void**)&pnc );
+ if ( hr == S_OK ) {
+
+ if ( fGetWriteLock ) {
+
+ //
+ // Get the locking reference
+ //
+
+ hr = pnc->QueryInterface( IID_INetCfgLock,
+ (LPVOID *)&pncLock );
+ if ( hr == S_OK ) {
+
+ //
+ // Attempt to lock the INetCfg for read/write
+ //
+
+ hr = pncLock->AcquireWriteLock( LOCK_TIME_OUT,
+ lpszAppName,
+ lpszLockedBy);
+ if (hr == S_FALSE ) {
+ hr = NETCFG_E_NO_WRITE_LOCK;
+ }
+ }
+ }
+
+ if ( hr == S_OK ) {
+
+ //
+ // Initialize the INetCfg object.
+ //
+
+ hr = pnc->Initialize( NULL );
+
+ if ( hr == S_OK ) {
+ *ppnc = pnc;
+ pnc->AddRef();
+ }
+ else {
+
+ //
+ // Initialize failed, if obtained lock, release it
+ //
+
+ if ( pncLock ) {
+ pncLock->ReleaseWriteLock();
+ }
+ }
+ }
+
+ ReleaseRef( pncLock );
+ ReleaseRef( pnc );
+ }
+
+ //
+ // In case of error, uninitialize COM.
+ //
+
+ if ( hr != S_OK ) {
+ CoUninitialize();
+ }
+ }
+
+ return hr;
+}
+
+//
+// Function: HrReleaseINetCfg
+//
+// Purpose: Get a reference to INetCfg.
+//
+// Arguments:
+// pnc [in] Reference to INetCfg to release.
+// fHasWriteLock [in] If TRUE, reference was held with write lock.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrReleaseINetCfg (IN INetCfg* pnc,
+ IN BOOL fHasWriteLock)
+{
+ INetCfgLock *pncLock = NULL;
+ HRESULT hr = S_OK;
+
+ //
+ // Uninitialize INetCfg
+ //
+
+ hr = pnc->Uninitialize();
+
+ //
+ // If write lock is present, unlock it
+ //
+
+ if ( hr == S_OK && fHasWriteLock ) {
+
+ //
+ // Get the locking reference
+ //
+
+ hr = pnc->QueryInterface( IID_INetCfgLock,
+ (LPVOID *)&pncLock);
+ if ( hr == S_OK ) {
+ hr = pncLock->ReleaseWriteLock();
+ ReleaseRef( pncLock );
+ }
+ }
+
+ ReleaseRef( pnc );
+
+ //
+ // Uninitialize COM.
+ //
+
+ CoUninitialize();
+
+ return hr;
+}
+
+//
+// Function: HrInstallNetComponent
+//
+// Purpose: Install a network component(protocols, clients and services)
+// given its INF file.
+//
+// Arguments:
+// pnc [in] Reference to INetCfg.
+// lpszComponentId [in] PnpID of the network component.
+// pguidClass [in] Class GUID of the network component.
+// lpszInfFullPath [in] INF file to install from.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrInstallNetComponent (IN INetCfg *pnc,
+ IN LPCWSTR lpszComponentId,
+ IN const GUID *pguidClass,
+ IN LPCWSTR lpszInfFullPath)
+{
+ DWORD dwError;
+ HRESULT hr = S_OK;
+ WCHAR* Drive = NULL;
+ WCHAR* Dir = NULL;
+ WCHAR* DirWithDrive = NULL;
+
+ do
+ {
+ //
+ // If full path to INF has been specified, the INF
+ // needs to be copied using Setup API to ensure that any other files
+ // that the primary INF copies will be correctly found by Setup API
+ //
+
+ if ( lpszInfFullPath ) {
+
+ //
+ // Allocate memory to hold the strings
+ //
+ Drive = (WCHAR*)CoTaskMemAlloc(_MAX_DRIVE * sizeof(WCHAR));
+ if (NULL == Drive)
+ {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ ZeroMemory(Drive, _MAX_DRIVE * sizeof(WCHAR));
+
+ Dir = (WCHAR*)CoTaskMemAlloc(_MAX_DIR * sizeof(WCHAR));
+ if (NULL == Dir)
+ {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ ZeroMemory(Dir, _MAX_DRIVE * sizeof(WCHAR));
+
+ DirWithDrive = (WCHAR*)CoTaskMemAlloc((_MAX_DRIVE + _MAX_DIR) * sizeof(WCHAR));
+ if (NULL == DirWithDrive)
+ {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ ZeroMemory(DirWithDrive, (_MAX_DRIVE + _MAX_DIR) * sizeof(WCHAR));
+
+ //
+ // Get the path where the INF file is.
+ //
+
+ _wsplitpath_s ( lpszInfFullPath,
+ Drive,
+ _MAX_DRIVE,
+ Dir,
+ _MAX_DIR,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ StringCchCopyW ( DirWithDrive,
+ _MAX_DRIVE + _MAX_DIR,
+ Drive );
+ StringCchCatW ( DirWithDrive,
+ _MAX_DRIVE + _MAX_DIR,
+ Dir );
+
+ //
+ // Copy the INF file and other files referenced in the INF file.
+ //
+
+ if ( !SetupCopyOEMInfW(lpszInfFullPath,
+ DirWithDrive, // Other files are in the
+ // same dir. as primary INF
+ SPOST_PATH, // First param is path to INF
+ 0, // Default copy style
+ NULL, // Name of the INF after
+ // it's copied to %windir%\inf
+ 0, // Max buf. size for the above
+ NULL, // Required size if non-null
+ NULL) ) { // Optionally get the filename
+ // part of Inf name after it is copied.
+ dwError = GetLastError();
+
+ hr = HRESULT_FROM_WIN32( dwError );
+ }
+ }
+
+ if ( S_OK == hr ) {
+
+ //
+ // Install the network component.
+ //
+
+ hr = HrInstallComponent( pnc,
+ lpszComponentId,
+ pguidClass );
+ if ( hr == S_OK ) {
+
+ //
+ // On success, apply the changes
+ //
+
+ hr = pnc->Apply();
+ }
+ }
+
+ #pragma warning(disable:4127) /* Conditional expression is constant */
+ } while (false);
+
+ if (Drive != NULL)
+ {
+ CoTaskMemFree(Drive);
+ Drive = NULL;
+ }
+ if (Dir != NULL)
+ {
+ CoTaskMemFree(Dir);
+ Dir = NULL;
+ }
+ if (DirWithDrive != NULL)
+ {
+ CoTaskMemFree(DirWithDrive);
+ DirWithDrive = NULL;
+ }
+
+ return hr;
+}
+
+//
+// Function: HrInstallComponent
+//
+// Purpose: Install a network component(protocols, clients and services)
+// given its INF file.
+// Arguments:
+// pnc [in] Reference to INetCfg.
+// lpszComponentId [in] PnpID of the network component.
+// pguidClass [in] Class GUID of the network component.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrInstallComponent(IN INetCfg* pnc,
+ IN LPCWSTR szComponentId,
+ IN const GUID* pguidClass)
+{
+ INetCfgClassSetup *pncClassSetup = NULL;
+ INetCfgComponent *pncc = NULL;
+ OBO_TOKEN OboToken;
+ HRESULT hr = S_OK;
+
+ //
+ // OBO_TOKEN specifies on whose behalf this
+ // component is being installed.
+ // Set it to OBO_USER so that szComponentId will be installed
+ // on behalf of the user.
+ //
+
+ ZeroMemory( &OboToken,
+ sizeof(OboToken) );
+ OboToken.Type = OBO_USER;
+
+ //
+ // Get component's setup class reference.
+ //
+
+ hr = pnc->QueryNetCfgClass ( pguidClass,
+ IID_INetCfgClassSetup,
+ (void**)&pncClassSetup );
+ if ( hr == S_OK ) {
+
+ hr = pncClassSetup->Install( szComponentId,
+ &OboToken,
+ 0,
+ 0, // Upgrade from build number.
+ NULL, // Answerfile name
+ NULL, // Answerfile section name
+ &pncc ); // Reference after the component
+ if ( S_OK == hr ) { // is installed.
+
+ //
+ // we don't need to use pncc (INetCfgComponent), release it
+ //
+
+ ReleaseRef( pncc );
+ }
+
+ ReleaseRef( pncClassSetup );
+ }
+
+ return hr;
+}
+
+//
+// Function: HrUninstallNetComponent
+//
+// Purpose: Uninstall a network component(protocols, clients and services).
+//
+// Arguments:
+// pnc [in] Reference to INetCfg.
+// szComponentId [in] PnpID of the network component to uninstall.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrUninstallNetComponent(IN INetCfg* pnc,
+ IN LPCWSTR szComponentId)
+{
+ INetCfgComponent *pncc = NULL;
+ INetCfgClass *pncClass = NULL;
+ INetCfgClassSetup *pncClassSetup = NULL;
+ OBO_TOKEN OboToken;
+ GUID guidClass;
+ HRESULT hr = S_OK;
+
+ //
+ // OBO_TOKEN specifies on whose behalf this
+ // component is being installed.
+ // Set it to OBO_USER so that szComponentId will be installed
+ // on behalf of the user.
+ //
+
+ ZeroMemory( &OboToken,
+ sizeof(OboToken) );
+ OboToken.Type = OBO_USER;
+
+ //
+ // Get the component's reference.
+ //
+
+ hr = pnc->FindComponent( szComponentId,
+ &pncc );
+
+ if (S_OK == hr) {
+
+ //
+ // Get the component's class GUID.
+ //
+
+ hr = pncc->GetClassGuid( &guidClass );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get component's class reference.
+ //
+
+ hr = pnc->QueryNetCfgClass( &guidClass,
+ IID_INetCfgClass,
+ (void**)&pncClass );
+ if ( hr == S_OK ) {
+
+ //
+ // Get Setup reference.
+ //
+
+ hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+ (void**)&pncClassSetup );
+ if ( hr == S_OK ) {
+
+ hr = pncClassSetup->DeInstall( pncc,
+ &OboToken,
+ NULL);
+ if ( hr == S_OK ) {
+
+ //
+ // Apply the changes
+ //
+
+ hr = pnc->Apply();
+ }
+
+ ReleaseRef( pncClassSetup );
+ }
+
+ ReleaseRef( pncClass );
+ }
+ }
+
+ ReleaseRef( pncc );
+ }
+
+ return hr;
+}
+
+//
+// Function: HrGetComponentEnum
+//
+// Purpose: Get network component enumerator reference.
+//
+// Arguments:
+// pnc [in] Reference to INetCfg.
+// pguidClass [in] Class GUID of the network component.
+// ppencc [out] Enumerator reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetComponentEnum (INetCfg* pnc,
+ IN const GUID* pguidClass,
+ OUT IEnumNetCfgComponent **ppencc)
+{
+ INetCfgClass *pncclass;
+ HRESULT hr;
+
+ *ppencc = NULL;
+
+ //
+ // Get the class reference.
+ //
+
+ hr = pnc->QueryNetCfgClass( pguidClass,
+ IID_INetCfgClass,
+ (PVOID *)&pncclass );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get the enumerator reference.
+ //
+
+ hr = pncclass->EnumComponents( ppencc );
+
+ //
+ // We don't need the class reference any more.
+ //
+
+ ReleaseRef( pncclass );
+ }
+
+ return hr;
+}
+
+//
+// Function: HrGetFirstComponent
+//
+// Purpose: Enumerates the first network component.
+//
+// Arguments:
+// pencc [in] Component enumerator reference.
+// ppncc [out] Network component reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetFirstComponent (IN IEnumNetCfgComponent* pencc,
+ OUT INetCfgComponent **ppncc)
+{
+ HRESULT hr;
+ ULONG ulCount;
+
+ *ppncc = NULL;
+
+ pencc->Reset();
+
+ hr = pencc->Next( 1,
+ ppncc,
+ &ulCount );
+ return hr;
+}
+
+//
+// Function: HrGetNextComponent
+//
+// Purpose: Enumerate the next network component.
+//
+// Arguments:
+// pencc [in] Component enumerator reference.
+// ppncc [out] Network component reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes: The function behaves just like HrGetFirstComponent if
+// it is called right after HrGetComponentEnum.
+//
+//
+
+HRESULT HrGetNextComponent (IN IEnumNetCfgComponent* pencc,
+ OUT INetCfgComponent **ppncc)
+{
+ HRESULT hr;
+ ULONG ulCount;
+
+ *ppncc = NULL;
+
+ hr = pencc->Next( 1,
+ ppncc,
+ &ulCount );
+ return hr;
+}
+
+//
+// Function: HrFindNetComponentByPnpId
+//
+// Purpose: Get network adapter identified by a particular pnp device instance id.
+//
+// Arguments:
+// pncc [in] Network component reference.
+// lpszPnpDevNodeId [in] pnp device instance id.
+// ppncc [out] pointer to network adapter reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrFindNetComponentByPnpId (IN INetCfg *pnc,
+ IN _In_ LPWSTR lpszPnpDevNodeId,
+ OUT INetCfgComponent **ppncc)
+{
+ IEnumNetCfgComponent *pencc;
+ LPWSTR pszPnpId;
+ HRESULT hr;
+ BOOL fFound;
+
+ hr = HrGetComponentEnum( pnc,
+ &GUID_DEVCLASS_NET,
+ &pencc );
+ if ( hr == S_OK ) {
+
+ hr = HrGetFirstComponent( pencc, ppncc );
+ fFound = FALSE;
+ while( hr == S_OK ) {
+ hr = (*ppncc)->GetPnpDevNodeId( &pszPnpId );
+ if ( hr == S_OK ) {
+ fFound = wcscmp( pszPnpId, lpszPnpDevNodeId ) == 0;
+ CoTaskMemFree( pszPnpId );
+ if ( fFound ) {
+ break;
+ }
+ }
+ else {
+ hr = S_OK;
+ }
+
+ ReleaseRef( *ppncc );
+ hr = HrGetNextComponent( pencc, ppncc );
+ }
+
+ ReleaseRef( pencc );
+ }
+
+ return hr;
+}
+
+//
+// Function: HrGetBindingPathEnum
+//
+// Purpose: Get network component's binding path enumerator reference.
+//
+// Arguments:
+// pncc [in] Network component reference.
+// dwBindingType [in] EBP_ABOVE or EBP_BELOW.
+// ppencbp [out] Enumerator reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetBindingPathEnum (IN INetCfgComponent *pncc,
+ IN DWORD dwBindingType,
+ OUT IEnumNetCfgBindingPath **ppencbp)
+{
+ INetCfgComponentBindings *pnccb = NULL;
+ HRESULT hr;
+
+ *ppencbp = NULL;
+
+ //
+ // Get component's binding.
+ //
+
+ hr = pncc->QueryInterface( IID_INetCfgComponentBindings,
+ (PVOID *)&pnccb );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Get binding path enumerator reference.
+ //
+
+ hr = pnccb->EnumBindingPaths( dwBindingType,
+ ppencbp );
+
+ ReleaseRef( pnccb );
+ }
+
+ return hr;
+}
+
+//
+// Function: HrGetFirstBindingPath
+//
+// Purpose: Enumerates the first binding path.
+//
+// Arguments:
+// pencc [in] Binding path enumerator reference.
+// ppncc [out] Binding path reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetFirstBindingPath (IN IEnumNetCfgBindingPath *pencbp,
+ OUT INetCfgBindingPath **ppncbp)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbp = NULL;
+
+ pencbp->Reset();
+
+ hr = pencbp->Next( 1,
+ ppncbp,
+ &ulCount );
+
+ return hr;
+}
+
+//
+// Function: HrGetNextBindingPath
+//
+// Purpose: Enumerate the next binding path.
+//
+// Arguments:
+// pencbp [in] Binding path enumerator reference.
+// ppncbp [out] Binding path reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes: The function behaves just like HrGetFirstBindingPath if
+// it is called right after HrGetBindingPathEnum.
+//
+//
+
+HRESULT HrGetNextBindingPath (IN IEnumNetCfgBindingPath *pencbp,
+ OUT INetCfgBindingPath **ppncbp)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbp = NULL;
+
+ hr = pencbp->Next( 1,
+ ppncbp,
+ &ulCount );
+
+ return hr;
+}
+
+//
+// Function: HrGetBindingInterfaceEnum
+//
+// Purpose: Get binding interface enumerator reference.
+//
+// Arguments:
+// pncbp [in] Binding path reference.
+// ppencbp [out] Enumerator reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetBindingInterfaceEnum (IN INetCfgBindingPath *pncbp,
+ OUT IEnumNetCfgBindingInterface **ppencbi)
+{
+ HRESULT hr;
+
+ *ppencbi = NULL;
+
+ hr = pncbp->EnumBindingInterfaces( ppencbi );
+
+ return hr;
+}
+
+//
+// Function: HrGetFirstBindingInterface
+//
+// Purpose: Enumerates the first binding interface.
+//
+// Arguments:
+// pencbi [in] Binding interface enumerator reference.
+// ppncbi [out] Binding interface reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT HrGetFirstBindingInterface (IN IEnumNetCfgBindingInterface *pencbi,
+ OUT INetCfgBindingInterface **ppncbi)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbi = NULL;
+
+ pencbi->Reset();
+
+ hr = pencbi->Next( 1,
+ ppncbi,
+ &ulCount );
+
+ return hr;
+}
+
+//
+// Function: HrGetNextBindingInterface
+//
+// Purpose: Enumerate the next binding interface.
+//
+// Arguments:
+// pencbi [in] Binding interface enumerator reference.
+// ppncbi [out] Binding interface reference.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes: The function behaves just like HrGetFirstBindingInterface if
+// it is called right after HrGetBindingInterfaceEnum.
+//
+//
+
+HRESULT HrGetNextBindingInterface (IN IEnumNetCfgBindingInterface *pencbi,
+ OUT INetCfgBindingInterface **ppncbi)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbi = NULL;
+
+ hr = pencbi->Next( 1,
+ ppncbi,
+ &ulCount );
+
+ return hr;
+}
+
+//
+// Function: ReleaseRef
+//
+// Purpose: Release reference.
+//
+// Arguments:
+// punk [in] IUnknown reference to release.
+//
+// Returns: Reference count.
+//
+// Notes:
+//
+
+VOID ReleaseRef (IN IUnknown* punk)
+{
+ if ( punk ) {
+ punk->Release();
+ }
+
+ return;
+}
+
diff --git a/network/config/bindview/NetCfgAPI.h b/network/config/bindview/NetCfgAPI.h
new file mode 100644
index 00000000..b4d6f552
--- /dev/null
+++ b/network/config/bindview/NetCfgAPI.h
@@ -0,0 +1,92 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 2001.
+//
+// File: N E T C F G A P I . H
+//
+// Contents: Functions Prototypes
+//
+// Notes:
+//
+// Author: Alok Sinha 15-May-01
+//
+//----------------------------------------------------------------------------
+
+#ifndef _NETCFGAPI_H_INCLUDED
+
+#define _NETCFGAPI_H_INCLUDED
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <wchar.h>
+#include <netcfgx.h>
+#include <netcfgn.h>
+#include <setupapi.h>
+#include <devguid.h>
+#include <objbase.h>
+#include <strsafe.h>
+
+#define celems(_x) (sizeof(_x) / sizeof(_x[0]))
+
+#define LOCK_TIME_OUT 5000
+
+HRESULT HrGetINetCfg (IN BOOL fGetWriteLock,
+ IN LPCWSTR lpszAppName,
+ OUT INetCfg** ppnc,
+ _Outptr_opt_result_maybenull_ LPWSTR *lpszLockedBy);
+
+HRESULT HrReleaseINetCfg (INetCfg* pnc,
+ BOOL fHasWriteLock);
+
+HRESULT HrInstallNetComponent (IN INetCfg *pnc,
+ IN LPCWSTR szComponentId,
+ IN const GUID *pguildClass,
+ IN LPCWSTR lpszInfFullPath);
+
+HRESULT HrInstallComponent(IN INetCfg* pnc,
+ IN LPCWSTR szComponentId,
+ IN const GUID* pguidClass);
+
+HRESULT HrUninstallNetComponent(IN INetCfg* pnc,
+ IN LPCWSTR szComponentId);
+
+HRESULT HrGetComponentEnum (INetCfg* pnc,
+ IN const GUID* pguidClass,
+ IEnumNetCfgComponent **ppencc);
+
+HRESULT HrGetFirstComponent (IEnumNetCfgComponent* pencc,
+ INetCfgComponent **ppncc);
+
+HRESULT HrGetNextComponent (IEnumNetCfgComponent* pencc,
+ INetCfgComponent **ppncc);
+
+HRESULT HrFindNetComponentByPnpId (IN INetCfg *pnc,
+ IN _In_ LPWSTR lpszPnpDevNodeId,
+ OUT INetCfgComponent **ppncc);
+
+HRESULT HrGetBindingPathEnum (INetCfgComponent *pncc,
+ DWORD dwBindingType,
+ IEnumNetCfgBindingPath **ppencbp);
+
+HRESULT HrGetFirstBindingPath (IEnumNetCfgBindingPath *pencbp,
+ INetCfgBindingPath **ppncbp);
+
+HRESULT HrGetNextBindingPath (IEnumNetCfgBindingPath *pencbp,
+ INetCfgBindingPath **ppncbp);
+
+HRESULT HrGetBindingInterfaceEnum (INetCfgBindingPath *pncbp,
+ IEnumNetCfgBindingInterface **ppencbi);
+
+HRESULT HrGetFirstBindingInterface (IEnumNetCfgBindingInterface *pencbi,
+ INetCfgBindingInterface **ppncbi);
+
+HRESULT HrGetNextBindingInterface (IEnumNetCfgBindingInterface *pencbi,
+ INetCfgBindingInterface **ppncbi);
+
+VOID ReleaseRef (IUnknown* punk);
+
+#endif
+
diff --git a/network/config/bindview/RESOURCE.H b/network/config/bindview/RESOURCE.H
new file mode 100644
index 00000000..3fb76696
--- /dev/null
+++ b/network/config/bindview/RESOURCE.H
@@ -0,0 +1,43 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by BindView.rc
+//
+#define IDD_MAIN 101
+#define IDM_OPTIONS 101
+#define IDI_BINDVIEW 105
+#define IDD_BIND_UNBIND 106
+#define IDD_INSTALL 107
+#define IDD_UNINSTALL 108
+#define IDT_BINDINGS 1000
+#define IDB_INSTALL 1001
+#define IDB_UNINSTALL 1002
+#define IDS_COMPONENT 1003
+#define IDL_COMPONENT_TYPES 1004
+#define IDB_EXPAND_ALL 1005
+#define IDB_COLLAPSE_ALL 1006
+#define IDB_BROWSE 1007
+#define IDS_ENABLE 1012
+#define IDE_OWNER 1013
+#define IDE_DEPTH 1014
+#define IDB_BIND_UNBIND 1016
+#define IDG_COMPONENT_LIST 1018
+#define IDB_CLOSE 1021
+#define IDB_REMOVE 1022
+#define IDT_COMPONENT_LIST 1024
+#define IDB_SAVE 1025
+#define IDI_ENABLE 40001
+#define IDI_UNBIND_FROM 40004
+#define IDI_BIND_TO 40005
+#define IDI_CANCEL 40006
+#define IDI_DISABLE 40007
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 109
+#define _APS_NEXT_COMMAND_VALUE 40008
+#define _APS_NEXT_CONTROL_VALUE 1028
+#define _APS_NEXT_SYMED_VALUE 102
+#endif
+#endif
diff --git a/network/config/bindview/ReadMe.md b/network/config/bindview/ReadMe.md
new file mode 100644
index 00000000..01e1cd8d
--- /dev/null
+++ b/network/config/bindview/ReadMe.md
@@ -0,0 +1,7 @@
+Bindview Network Configuration Utility
+======================================
+
+The Bindview sample demonstrates how to use INetCfg APIs to enumerate, install, uninstall, bind and unbind network components.
+
+For more information on the INetCfg interface, see [Network Configuration Interfaces](http://msdn.microsoft.com/en-us/library/windows/hardware/ff559080).
+
diff --git a/network/config/bindview/bindview.htm b/network/config/bindview/bindview.htm
new file mode 100644
index 00000000..c28f6190
--- /dev/null
+++ b/network/config/bindview/bindview.htm
@@ -0,0 +1,345 @@
+<html xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 11">
+<meta name=Originator content="Microsoft Word 11">
+<link rel=File-List href="bindview_files/filelist.xml">
+<title>BINDVIEW: Network Configuration/Installation Sample</title>
+<!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:SpellingState>Clean</w:SpellingState>
+ <w:GrammarState>Clean</w:GrammarState>
+ <w:ValidateAgainstSchemas/>
+ <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
+ <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
+ <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
+ <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
+ </w:WordDocument>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:LatentStyles DefLockedState="false" LatentStyleCount="156">
+ </w:LatentStyles>
+</xml><![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+ @font-face
+ {font-family:Verdana;
+ panose-1:2 11 6 4 3 5 4 4 2 4;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:536871559 0 0 0 415 0;}
+@font-face
+ {font-family:"MS Sans Serif";
+ panose-1:0 0 0 0 0 0 0 0 0 0;
+ mso-font-alt:"Times New Roman";
+ mso-font-charset:0;
+ mso-generic-font-family:roman;
+ mso-font-format:other;
+ mso-font-pitch:auto;
+ mso-font-signature:0 0 0 0 0 0;}
+ /* Style Definitions */
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+h1
+ {mso-style-next:Normal;
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ page-break-after:avoid;
+ mso-outline-level:1;
+ font-size:10.0pt;
+ font-family:Verdana;
+ mso-font-kerning:0pt;
+ font-weight:bold;}
+h2
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:2;
+ font-size:18.0pt;
+ font-family:"Times New Roman";
+ font-weight:bold;}
+h3
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:3;
+ font-size:13.5pt;
+ font-family:"Times New Roman";
+ font-weight:bold;}
+h4
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:4;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ font-weight:bold;}
+a:link, span.MsoHyperlink
+ {color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+a:visited, span.MsoHyperlinkFollowed
+ {color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+p
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+pre
+ {margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt;
+ font-size:10.0pt;
+ font-family:"Courier New";
+ mso-fareast-font-family:"Courier New";}
+span.SpellE
+ {mso-style-name:"";
+ mso-spl-e:yes;}
+span.GramE
+ {mso-style-name:"";
+ mso-gram-e:yes;}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.25in 1.0in 1.25in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+ /* List Definitions */
+ @list l0
+ {mso-list-id:149904795;
+ mso-list-type:hybrid;
+ mso-list-template-ids:2069783722 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
+@list l0:level1
+ {mso-level-number-format:bullet;
+ mso-level-text:\F0B7;
+ mso-level-tab-stop:.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;
+ font-family:Symbol;}
+@list l0:level2
+ {mso-level-number-format:bullet;
+ mso-level-text:o;
+ mso-level-tab-stop:1.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;
+ font-family:"Courier New";}
+@list l0:level3
+ {mso-level-tab-stop:1.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level4
+ {mso-level-tab-stop:2.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level5
+ {mso-level-tab-stop:2.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level6
+ {mso-level-tab-stop:3.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level7
+ {mso-level-tab-stop:3.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level8
+ {mso-level-tab-stop:4.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level9
+ {mso-level-tab-stop:4.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1
+ {mso-list-id:1493059929;
+ mso-list-template-ids:703913330;}
+@list l1:level1
+ {mso-level-number-format:bullet;
+ mso-level-text:\F0B7;
+ mso-level-tab-stop:.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;
+ mso-ansi-font-size:10.0pt;
+ font-family:Symbol;}
+@list l1:level2
+ {mso-level-number-format:bullet;
+ mso-level-text:o;
+ mso-level-tab-stop:1.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;
+ mso-ansi-font-size:10.0pt;
+ font-family:"Courier New";
+ mso-bidi-font-family:"Times New Roman";}
+ol
+ {margin-bottom:0in;}
+ul
+ {margin-bottom:0in;}
+-->
+</style>
+<!--[if gte mso 10]>
+<style>
+ /* Style Definitions */
+ table.MsoNormalTable
+ {mso-style-name:"Table Normal";
+ mso-tstyle-rowband-size:0;
+ mso-tstyle-colband-size:0;
+ mso-style-noshow:yes;
+ mso-style-parent:"";
+ mso-padding-alt:0in 5.4pt 0in 5.4pt;
+ mso-para-margin:0in;
+ mso-para-margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:10.0pt;
+ font-family:"Times New Roman";
+ mso-ansi-language:#0400;
+ mso-fareast-language:#0400;
+ mso-bidi-language:#0400;}
+</style>
+<![endif]-->
+</head>
+
+<body lang=EN-US link=blue vlink=blue style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<h2><a name="_top"></a><span style='font-family:Verdana'>BINDVIEW: Network
+Configuration/Installation Sample<o:p></o:p></span></h2>
+
+<h3><span style='font-family:Verdana'>SUMMARY<o:p></o:p></span></h3>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>This sample demonstrates
+how to use <span class=SpellE>INetCfg</span> APIs to enumerate, install,
+uninstall, bind and unbind network components.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The sample compiles
+properly for 64-bit systems and builds properly with Microsoft� Visual C� 6.0. <o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>BUILDING THE SAMPLE<o:p></o:p></span></h3>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>To build the sample, <span
+class=GramE>type <b>build</b></span>. This command produces the binary
+bindview.exe.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>INSTALLING THE SAMPLE<o:p></o:p></span></h3>
+
+<p class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'>Copy the
+binary bindview.exe to the directory from which you want to run the sample. <o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>RUNNING THE SAMPLE<o:p></o:p></span></h3>
+
+<p class=MsoNormal><span class=GramE><span style='font-size:10.0pt;font-family:
+Verdana'>Type bindview.exe at the command prompt to run the program.</span></span><span
+style='font-size:10.0pt;font-family:Verdana'> You can perform the following
+operations.<o:p></o:p></span></p>
+
+<p class=MsoNormal><span style='font-size:10.0pt;font-family:Verdana'><o:p>&nbsp;</o:p></span></p>
+
+<ul style='margin-top:0in' type=disc>
+ <li class=MsoNormal style='mso-list:l0 level1 lfo3;tab-stops:list .5in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Install a network protocol,
+ service or client component.<o:p></o:p></span></li>
+ <li class=MsoNormal style='mso-list:l0 level1 lfo3;tab-stops:list .5in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Uninstall a network protocol,
+ service or client component.<o:p></o:p></span></li>
+ <li class=MsoNormal style='mso-list:l0 level1 lfo3;tab-stops:list .5in'><span
+ style='font-size:10.0pt;font-family:Verdana'>By clicking the right mouse
+ button on a network protocol, service or client, you can perform the
+ following operations.<o:p></o:p></span></li>
+ <ul style='margin-top:0in' type=circle>
+ <li class=MsoNormal style='mso-list:l0 level2 lfo3;tab-stops:list 1.0in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Bind the network component
+ to another component.<o:p></o:p></span></li>
+ <li class=MsoNormal style='mso-list:l0 level2 lfo3;tab-stops:list 1.0in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Unbind the network component
+ from another component that is bound to it.<o:p></o:p></span></li>
+ </ul>
+ <li class=MsoNormal style='mso-list:l0 level1 lfo3;tab-stops:list .5in'><span
+ style='font-size:10.0pt;font-family:Verdana'>By clicking the right mouse
+ button on a binding path, you can perform the following operations.<o:p></o:p></span></li>
+ <ul style='margin-top:0in' type=circle>
+ <li class=MsoNormal style='mso-list:l0 level2 lfo3;tab-stops:list 1.0in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Disable the binding path if
+ it is enabled.<o:p></o:p></span></li>
+ <li class=MsoNormal style='mso-list:l0 level2 lfo3;tab-stops:list 1.0in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Enable the binding path if
+ it is disabled.<o:p></o:p></span></li>
+ </ul>
+ <li class=MsoNormal style='mso-list:l0 level1 lfo3;tab-stops:list .5in'><span
+ style='font-size:10.0pt;font-family:Verdana'>Save the binding information
+ to a file.<o:p></o:p></span></li>
+</ul>
+
+<h3><span style='font-family:Verdana'>CODE TOUR<o:p></o:p></span></h3>
+
+<h4><span style='font-family:Verdana'>File Manifest<o:p></o:p></span></h4>
+
+<pre><u>File<span style='mso-tab-count:2'>���������� </span>Description<o:p></o:p></u></pre><pre><span
+style='text-transform:uppercase'>BINDVIEW.CPP</span><span style='mso-tab-count:
+1'>�� </span>Contains <span class=SpellE>WinMain</span> and dialog box related functions.</pre><pre><span
+style='text-transform:uppercase'>NetCfgAPI.cpp</span><span style='mso-tab-count:
+1'>� </span>Contains <span class=SpellE>INetCfg</span> functions.</pre><pre>BINDING.CPP<span
+style='mso-tab-count:1'>��� </span>Contains binding path related functions. </pre><pre><span
+style='text-transform:uppercase'>Component.cpp</span><span style='mso-tab-count:
+1'>� </span>Contains network component related functions.</pre><pre><span
+class=GramE>RESOURCE.H<span style='mso-tab-count:1'>���� </span>Resource header.</span></pre><pre>BINDVIEW.H<span
+style='mso-tab-count:1'>���� </span>Contains function prototypes.</pre><pre><span
+style='text-transform:uppercase'>NetCfgAPI.h</span><span style='mso-tab-count:
+1'>��� </span>Contains function prototypes for <span class=SpellE>NetCfgAPI.cpp</span></pre><pre><span
+style='text-transform:uppercase'>BindView.rc</span><span style='mso-tab-count:
+1'>��� </span>Resources for <span class=SpellE>Bindview</span></pre><pre><span
+class=GramE><span style='text-transform:uppercase'>BindView.ico</span><span
+style='mso-tab-count:1'>�� </span>Icon for the sample.</span></pre><pre><o:p>&nbsp;</o:p></pre><pre><o:p>&nbsp;</o:p></pre><pre><o:p>&nbsp;</o:p></pre>
+
+<p align=center style='text-align:center;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><a
+href="#_top"><span style='font-size:10.0pt;font-family:Verdana'>Top of page</span></a><span
+style='font-size:10.0pt;font-family:Verdana'> <o:p></o:p></span></p>
+
+<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=624
+ style='width:6.5in;mso-cellspacing:0in;mso-padding-alt:0in 0in 0in 0in'>
+ <tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes;
+ height:1.5pt'>
+ <td style='background:aqua;padding:.75pt .75pt .75pt .75pt;height:1.5pt'>
+ <p class=MsoNormal><o:p>&nbsp;</o:p></p>
+ </td>
+ </tr>
+</table>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:7.5pt;font-family:"MS Sans Serif"'>� 2004</span><span
+style='font-size:10.0pt;font-family:Verdana'> </span><span style='font-size:
+7.5pt;font-family:"MS Sans Serif"'>Microsoft Corporation </span><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+</div>
+
+</body>
+
+</html>
diff --git a/network/config/bindview/bindview.sln b/network/config/bindview/bindview.sln
new file mode 100644
index 00000000..021f4efb
--- /dev/null
+++ b/network/config/bindview/bindview.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bindview", "bindview.vcxproj", "{C8EC04C0-EF77-4CD4-8072-F7F8A9125822}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|Win32.Build.0 = Debug|Win32
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|Win32.ActiveCfg = Release|Win32
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|Win32.Build.0 = Release|Win32
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|x64.ActiveCfg = Debug|x64
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Debug|x64.Build.0 = Debug|x64
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|x64.ActiveCfg = Release|x64
+ {C8EC04C0-EF77-4CD4-8072-F7F8A9125822}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/config/bindview/bindview.vcxproj b/network/config/bindview/bindview.vcxproj
new file mode 100644
index 00000000..767d2a89
--- /dev/null
+++ b/network/config/bindview/bindview.vcxproj
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C8EC04C0-EF77-4CD4-8072-F7F8A9125822}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{224CF8FD-5538-4B7E-81AF-44805B4722EA}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>bindview</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>bindview</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>bindview</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>bindview</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4127</DisableSpecificWarnings>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;comctl32.lib;comdlg32.lib;setupapi.lib;user32.lib;kernel32.lib;gdi32.lib;uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4127</DisableSpecificWarnings>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;comctl32.lib;comdlg32.lib;setupapi.lib;user32.lib;kernel32.lib;gdi32.lib;uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4127</DisableSpecificWarnings>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;comctl32.lib;comdlg32.lib;setupapi.lib;user32.lib;kernel32.lib;gdi32.lib;uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4127</DisableSpecificWarnings>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;UNICODE;_UNICODE</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;comctl32.lib;comdlg32.lib;setupapi.lib;user32.lib;kernel32.lib;gdi32.lib;uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="binding.cpp" />
+ <ClCompile Include="bindview.cpp" />
+ <ClCompile Include="component.cpp" />
+ <ClCompile Include="netcfgapi.cpp" />
+ <ResourceCompile Include="bindview.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/config/bindview/bindview.vcxproj.Filters b/network/config/bindview/bindview.vcxproj.Filters
new file mode 100644
index 00000000..964d777e
--- /dev/null
+++ b/network/config/bindview/bindview.vcxproj.Filters
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{4372001E-614D-43C8-ACA0-0ACF46A23F6E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{98620252-1A3C-4A35-8A10-A2376A0D90BF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{CC73B9F9-A9E1-4AA1-88AE-951314EA9903}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="binding.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="bindview.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="component.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="netcfgapi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="bindview.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/modem/fakemodem/ReadMe.md b/network/modem/fakemodem/ReadMe.md
new file mode 100644
index 00000000..6d6cdbc1
--- /dev/null
+++ b/network/modem/fakemodem/ReadMe.md
@@ -0,0 +1,8 @@
+Fakemodem Driver
+================
+
+The Fakemodem sample demonstrates a simple controller-less modem driver. This driver supports sending and receiving AT commands using the `ReadFile`/`WriteFile` calls or via a TAPI interface using an application such as *HyperTerminal.*
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
diff --git a/network/modem/fakemodem/driver.c b/network/modem/fakemodem/driver.c
new file mode 100644
index 00000000..f482c890
--- /dev/null
+++ b/network/modem/fakemodem/driver.c
@@ -0,0 +1,474 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Driver.c
+
+Abstract:
+
+ This is a simple form of function driver for fakemodem device. The driver
+ doesn't handle any PnP and Power events because the framework provides
+ default behaviour for those events. This driver has enough support to
+ allow an user application (toast/notify.exe) to open the device
+ interface registered by the driver and send read, write or ioctl requests.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "fakemodem.h"
+
+#ifdef ALLOC_PRAGMA
+ #pragma alloc_text (INIT, DriverEntry)
+ #pragma alloc_text (PAGE, FmEvtDeviceAdd)
+ #pragma alloc_text (PAGE, FmCreateDosDevicesSymbolicLink)
+ #pragma alloc_text (PAGE, FmDeviceCleanup)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry specifies the other entry
+ points in the function driver, such as FmAddDevice and FmUnload.
+
+Parameters Description:
+
+ DriverObject - represents the instance of the function driver that is loaded
+ into memory. DriverEntry must initialize members of DriverObject before it
+ returns to the caller. DriverObject is allocated by the system before the
+ driver is loaded, and it is released by the system after the system unloads
+ the function driver from memory.
+
+ RegistryPath - represents the driver specific path in the Registry.
+ The function driver can use the path to store driver related data between
+ reboots. The path does not store hardware instance specific data.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ WDF_DRIVER_CONFIG config;
+
+ KdPrint(("Fakemode Function Driver Sample - Driver Framework Edition.\n"));
+ KdPrint(("Built %s %s\n", __DATE__, __TIME__));
+
+ WDF_DRIVER_CONFIG_INIT( &config, FmEvtDeviceAdd );
+
+ //
+ // Create a framework driver object to represent our driver.
+ //
+ status = WdfDriverCreate(
+ DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config, // Driver Config Info
+ WDF_NO_HANDLE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status));
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+FmEvtDeviceAdd(
+ IN WDFDRIVER Driver,
+ IN PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ FmEvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of Fm device.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PFM_DEVICE_DATA fmDeviceData;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+ WDF_OBJECT_ATTRIBUTES fdoAttributes;
+ WDFDEVICE hDevice;
+ WDFQUEUE defQueue;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ KdPrint( ("FmEvtDeviceAdd routine \n"));
+
+ PAGED_CODE();
+
+ //
+ // Modem type is serial port.
+ //
+ WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT);
+
+ //
+ // Use Buffered IO.
+ //
+ WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);
+
+ //
+ // Specify the size of device extension where we track per device
+ // context.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FM_DEVICE_DATA);
+ //
+ // Register a cleanup callback on the device to free up some resources at the
+ // time the device is deleted.
+ //
+ fdoAttributes.EvtCleanupCallback = FmDeviceCleanup;
+ //
+ // By opting for SynchronizationScopeDevice, we tell the framework to
+ // synchronize callbacks events of all the objects directly associated
+ // with the device. In this driver, we will associate queues.
+ // By doing that we don't have to worrry about synchronizing
+ // access to device-context by various io Events.
+ // Framework will serialize them by using an internal device-lock.
+ //
+ fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;
+ //
+ // Create a framework device object.This call will inturn create
+ // a WDM deviceobject, attach to the lower stack and set the
+ // appropriate flags and attributes.
+ //
+
+ status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice);
+
+ if (!NT_SUCCESS(status)) {
+ KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status));
+ return status;
+ }
+
+ //
+ // Get the DeviceExtension and initialize it.
+ //
+ fmDeviceData = FmDeviceDataGet(hDevice);
+
+ //
+ // Tell the Framework that this device will need an interface
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ hDevice,
+ (LPGUID) &GUID_DEVINTERFACE_MODEM,
+ NULL
+ );
+
+ if (!NT_SUCCESS (status)) {
+ KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status));
+ return status;
+ }
+
+ fmDeviceData->Flags = 0;
+ status = FmCreateDosDevicesSymbolicLink(hDevice, fmDeviceData);
+
+ if (!NT_SUCCESS(status)) {
+ KdPrint( ("FmCreateDosDevicesSymbolicLink failed with Status code 0x%x\n", status));
+ return status;
+ }
+
+ //
+ // Initialize the context
+ //
+ fmDeviceData->BaudRate=1200;
+ fmDeviceData->LineControl = SERIAL_7_DATA | SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY;
+
+ //
+ // Register I/O callbacks to tell the framework that you are interested
+ // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests.
+ // In case a specific handler is not specified for one of these,
+ // the request will be dispatched to the EvtIoDefault handler, if any.
+ // If there is no EvtIoDefault handler, the request will be failed with
+ // STATUS_INVALID_DEVICE_REQUEST.
+ // WdfIoQueueDispatchParallel means that we are capable of handling
+ // all the I/O request simultaneously and we are responsible for protecting
+ // data that could be accessed by these callbacks simultaneously.
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
+ WdfIoQueueDispatchParallel);
+
+ queueConfig.EvtIoRead = FmEvtIoRead;
+ queueConfig.EvtIoWrite = FmEvtIoWrite;
+ queueConfig.EvtIoDeviceControl = FmEvtIoDeviceControl;
+
+ __analysis_assume(queueConfig.EvtIoStop != 0);
+ status = WdfIoQueueCreate(
+ hDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &defQueue // pointer to default queue
+ );
+ __analysis_assume(queueConfig.EvtIoStop == 0);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // We don't need to cleanup symbolic link here. The destroy callback for
+ // the device object will do it.
+ //
+ return status;
+ }
+
+ //
+ // Create a manual queue to hold pending read requests. By keeping
+ // them in the queue, framework takes care of cancelling them if the app exits
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
+ WdfIoQueueDispatchManual);
+
+ __analysis_assume(queueConfig.EvtIoStop != 0);
+ status = WdfIoQueueCreate(hDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &fmDeviceData->FmReadQueue
+ );
+ __analysis_assume(queueConfig.EvtIoStop == 0);
+
+ if (!NT_SUCCESS (status)) {
+ KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status));
+ return status;
+ }
+
+ //
+ // Create a manual queue to hold pending ioctl wait mask requests. By keeping
+ // them in the queue, framework takes care of cancelling them if the app exits
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(&queueConfig,
+ WdfIoQueueDispatchManual);
+
+ __analysis_assume(queueConfig.EvtIoStop != 0);
+ status = WdfIoQueueCreate(hDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &fmDeviceData->FmMaskWaitQueue
+ );
+ __analysis_assume(queueConfig.EvtIoStop == 0);
+
+ if (!NT_SUCCESS (status)) {
+ KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status));
+ return status;
+ }
+
+ return status;
+}
+
+
+VOID
+FmDeviceCleanup(
+ WDFOBJECT Device
+ )
+/*++
+Routine Description:
+
+ This event is called when the device object is destroyed.
+ Cleanup any associated data.
+
+Arguments:
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFM_DEVICE_DATA fmData;
+
+ PAGED_CODE();
+
+ fmData = FmDeviceDataGet((WDFDEVICE)Device);
+
+ if (fmData->Flags & REG_VALUE_CREATED_FLAG) {
+ RtlDeleteRegistryValue(
+ RTL_REGISTRY_DEVICEMAP,
+ L"SERIALCOMM",
+ fmData->PdoName.Buffer
+ );
+ }
+}
+
+NTSTATUS
+FmCreateDosDevicesSymbolicLink(
+ WDFDEVICE Device,
+ PFM_DEVICE_DATA FmDeviceData
+ )
+{
+ NTSTATUS status;
+ UNICODE_STRING comPort;
+ UNICODE_STRING pdoName;
+ UNICODE_STRING symbolicLink;
+ WDFKEY hKey = NULL;
+ DECLARE_CONST_UNICODE_STRING(valueName, L"PortName");
+ WDFSTRING string = NULL;
+ WDFMEMORY memory;
+ WDF_OBJECT_ATTRIBUTES memoryAttributes;
+ size_t bufferLength;
+
+
+ PAGED_CODE();
+
+ symbolicLink.Buffer = NULL;
+
+ //
+ // Open the device registry and read the "PortName" value written by the
+ // class installer.
+ //
+ status = WdfDeviceOpenRegistryKey(Device,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ NULL, // PWDF_OBJECT_ATTRIBUTES
+ &hKey);
+
+ if (!NT_SUCCESS (status)) {
+ goto Error;
+ }
+ status = WdfStringCreate(
+ NULL,
+ WDF_NO_OBJECT_ATTRIBUTES ,
+ &string
+ );
+
+ if (!NT_SUCCESS(status)) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the value of ValueName from registry
+ //
+ status = WdfRegistryQueryString(
+ hKey,
+ &valueName,
+ string
+ );
+
+
+ if (!NT_SUCCESS (status)) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the UNICODE_STRING from string object
+ //
+ WdfStringGetUnicodeString(
+ string,
+ &comPort
+ );
+
+ WdfRegistryClose(hKey);
+ hKey = NULL;
+
+ symbolicLink.Length=0;
+ symbolicLink.MaximumLength = sizeof(OBJECT_DIRECTORY) + comPort.MaximumLength;
+
+ symbolicLink.Buffer = ExAllocatePoolWithTag(PagedPool,
+ symbolicLink.MaximumLength + sizeof(WCHAR),
+ 'wkaF');
+
+ if (symbolicLink.Buffer == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error;
+ }
+ RtlZeroMemory(symbolicLink.Buffer, symbolicLink.MaximumLength);
+ RtlAppendUnicodeToString(&symbolicLink, OBJECT_DIRECTORY);
+ RtlAppendUnicodeStringToString(&symbolicLink, &comPort);
+ //
+ // This DDI will get the underlying PDO name and create a symbolic to that
+ // because our FDO doesn't have a name.
+ //
+ status = WdfDeviceCreateSymbolicLink(Device,
+ &symbolicLink);
+
+ if (!NT_SUCCESS(status)) {
+ goto Error;
+ }
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = Device;
+
+ status = WdfDeviceAllocAndQueryProperty(Device,
+ DevicePropertyPhysicalDeviceObjectName,
+ PagedPool,
+ &memoryAttributes,
+ &memory);
+ if (!NT_SUCCESS(status)) {
+ //
+ // We expect a zero length buffer. Anything else is fatal.
+ //
+ goto Error;
+ }
+
+ pdoName.Buffer = WdfMemoryGetBuffer(memory, &bufferLength);
+
+ if (pdoName.Buffer == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error;
+
+ }
+ pdoName.MaximumLength = (USHORT) bufferLength;
+ pdoName.Length = (USHORT) bufferLength - sizeof(UNICODE_NULL);
+
+ status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+ L"SERIALCOMM",
+ pdoName.Buffer,
+ REG_SZ,
+ comPort.Buffer,
+ comPort.Length);
+
+ if (!NT_SUCCESS(status)) {
+ goto Error;
+ }
+ FmDeviceData->Flags |= REG_VALUE_CREATED_FLAG;
+ //
+ // Store it so it can be deleted later.
+ //
+
+ FmDeviceData->PdoName = pdoName;
+
+ Error:
+
+ if (symbolicLink.Buffer != NULL) {
+ ExFreePool(symbolicLink.Buffer);
+ }
+
+ if (hKey != NULL) {
+ WdfRegistryClose(hKey);
+ }
+ if (string != NULL) {
+ WdfObjectDelete(string);
+ }
+
+ return status;
+}
+
diff --git a/network/modem/fakemodem/fakemodem.h b/network/modem/fakemodem/fakemodem.h
new file mode 100644
index 00000000..bb06c2fe
--- /dev/null
+++ b/network/modem/fakemodem/fakemodem.h
@@ -0,0 +1,156 @@
+/*++
+
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ fakemodem.h
+
+Abstract:
+
+ Header file for the toaster driver modules.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#if !defined(_FAKEMODEM_H_)
+#define _FAKEMODEM_H_
+
+#include <NTDDK.h>
+#include <wdf.h>
+#include <ntddser.h>
+#include <initguid.h>
+#define NTSTRSAFE_LIB
+#include <ntstrsafe.h>
+#include <ntintsafe.h>
+
+#ifdef DEFINE_GUID
+
+DEFINE_GUID(GUID_DEVINTERFACE_MODEM,0x2c7089aa, 0x2e0e,0x11d1,0xb1, 0x14, 0x00, 0xc0, 0x4f, 0xc2, 0xaa, 0xe4);
+
+#endif //DEFINE_GUID
+
+
+#define OBJECT_DIRECTORY L"\\DosDevices\\"
+
+#define READ_BUFFER_SIZE 128
+
+#define COMMAND_MATCH_STATE_IDLE 0
+#define COMMAND_MATCH_STATE_GOT_A 1
+#define COMMAND_MATCH_STATE_GOT_T 2
+
+//
+// This defines the bit used to control whether the device is sending
+// a break. When this bit is set the device is sending a space (logic 0).
+//
+// Most protocols will assume that this is a hangup.
+
+
+#define SERIAL_LCR_BREAK 0x40
+
+//
+// These defines are used to define the line control register
+//
+
+#define SERIAL_5_DATA ((UCHAR)0x00)
+#define SERIAL_6_DATA ((UCHAR)0x01)
+#define SERIAL_7_DATA ((UCHAR)0x02)
+#define SERIAL_8_DATA ((UCHAR)0x03)
+#define SERIAL_DATA_MASK ((UCHAR)0x03)
+
+#define SERIAL_1_STOP ((UCHAR)0x00)
+#define SERIAL_1_5_STOP ((UCHAR)0x04) // Only valid for 5 data bits
+#define SERIAL_2_STOP ((UCHAR)0x04) // Not valid for 5 data bits
+#define SERIAL_STOP_MASK ((UCHAR)0x04)
+
+#define SERIAL_NONE_PARITY ((UCHAR)0x00)
+#define SERIAL_ODD_PARITY ((UCHAR)0x08)
+#define SERIAL_EVEN_PARITY ((UCHAR)0x18)
+#define SERIAL_MARK_PARITY ((UCHAR)0x28)
+#define SERIAL_SPACE_PARITY ((UCHAR)0x38)
+#define SERIAL_PARITY_MASK ((UCHAR)0x38)
+
+#define REG_VALUE_CREATED_FLAG 0x1
+//
+// The device extension for the device object
+//
+typedef struct _FM_DEVICE_DATA
+{
+
+ UNICODE_STRING PdoName; //save this so that we can use it to delete the registry value later
+ WDFQUEUE FmReadQueue; // Staging area for pending Read requests
+ WDFQUEUE FmMaskWaitQueue;
+ ULONG CurrentMask;
+ SERIAL_TIMEOUTS CurrentTimeouts;
+ ULONG ReadBufferBegin;
+ ULONG ReadBufferEnd;
+ ULONG BytesInReadBuffer;
+ UCHAR CommandMatchState;
+ BOOLEAN ConnectCommand;
+ BOOLEAN IgnoreNextChar;
+ BOOLEAN CapsQueried;
+ ULONG ModemStatus;
+ BOOLEAN CurrentlyConnected;
+ BOOLEAN ConnectionStateChanged;
+ UCHAR ReadBuffer[READ_BUFFER_SIZE];
+ ULONG BaudRate;
+ UCHAR LineControl;
+ UCHAR ValidDataMask;
+ UCHAR Flags;
+
+} FM_DEVICE_DATA, *PFM_DEVICE_DATA;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FM_DEVICE_DATA, FmDeviceDataGet)
+
+#define FM_COM_PORT_STRING_LENGTH 80
+
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD FmEvtDeviceAdd;
+EVT_WDF_DEVICE_CONTEXT_CLEANUP FmDeviceCleanup;
+
+EVT_WDF_IO_QUEUE_IO_READ FmEvtIoRead;
+EVT_WDF_IO_QUEUE_IO_WRITE FmEvtIoWrite;
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FmEvtIoDeviceControl;
+
+NTSTATUS
+FmCreateDosDevicesSymbolicLink(
+ WDFDEVICE Device,
+ PFM_DEVICE_DATA FmDeviceData
+ );
+
+VOID
+ProcessConnectionStateChange(
+ IN PFM_DEVICE_DATA FmDeviceData
+ );
+VOID
+ProcessWriteBytes(
+ PFM_DEVICE_DATA FmDeviceData,
+ PUCHAR Characters,
+ ULONG Length
+ );
+
+
+VOID
+PutCharInReadBuffer(
+ PFM_DEVICE_DATA FmDeviceData,
+ UCHAR Character
+ );
+
+
+
+VOID
+ProcessReadBuffer(
+ IN PFM_DEVICE_DATA FmDeviceData,
+ IN PUCHAR SystemBuffer,
+ IN ULONG Length,
+ OUT PULONG ByesToMove
+ );
+
+#endif // _FAKEMODEM_H
+
+
diff --git a/network/modem/fakemodem/fakemodem.sln b/network/modem/fakemodem/fakemodem.sln
new file mode 100644
index 00000000..6804feb5
--- /dev/null
+++ b/network/modem/fakemodem/fakemodem.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakemodem", "fakemodem.vcxproj", "{3744C5BD-A12A-429F-9312-DFD04AC69078}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|Win32.Build.0 = Debug|Win32
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.ActiveCfg = Release|Win32
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|Win32.Build.0 = Release|Win32
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.ActiveCfg = Debug|x64
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Debug|x64.Build.0 = Debug|x64
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.ActiveCfg = Release|x64
+ {3744C5BD-A12A-429F-9312-DFD04AC69078}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/modem/fakemodem/fakemodem.vcxproj b/network/modem/fakemodem/fakemodem.vcxproj
new file mode 100644
index 00000000..c2a2dd8d
--- /dev/null
+++ b/network/modem/fakemodem/fakemodem.vcxproj
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3744C5BD-A12A-429F-9312-DFD04AC69078}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{74C5BB58-0CB8-4E8E-8FD7-065CBE6051A7}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <Inf Include=".\mdmfake.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\mdmfake.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>fakemodem</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>fakemodem</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>fakemodem</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>fakemodem</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="driver.c" />
+ <ClCompile Include="ioctl.c" />
+ <ClCompile Include="readwrit.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/modem/fakemodem/fakemodem.vcxproj.Filters b/network/modem/fakemodem/fakemodem.vcxproj.Filters
new file mode 100644
index 00000000..7c8d71ab
--- /dev/null
+++ b/network/modem/fakemodem/fakemodem.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{66A2BE8B-87F0-4F4B-AB28-9C66471A8B7B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{F31D838F-78A7-4140-B15C-4C9485DDB150}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{8A726BCF-D9F0-4948-8219-B0CCAC8AA786}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A5962758-E097-4C00-A4FB-3A630B0E5405}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\mdmfake.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include=".\mdmfake.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="driver.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ioctl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="readwrit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/modem/fakemodem/ioctl.c b/network/modem/fakemodem/ioctl.c
new file mode 100644
index 00000000..445910bd
--- /dev/null
+++ b/network/modem/fakemodem/ioctl.c
@@ -0,0 +1,790 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ioctl.c
+
+Abstract:
+
+ This is the ioctl handler for the fakemodem.
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "fakemodem.h"
+
+
+
+VOID
+FmEvtIoDeviceControl(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t OutputBufferLength,
+ IN size_t InputBufferLength,
+ IN ULONG IoControlCode
+ )
+/*++
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
+ requests from the system.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+
+ OutputBufferLength - length of the request's output buffer,
+ if an output buffer is available.
+ InputBufferLength - length of the request's input buffer,
+ if an input buffer is available.
+
+ IoControlCode - the driver-defined or system-defined I/O control code
+ (IOCTL) that is associated with the request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+
+ PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue));
+ NTSTATUS status ;
+ PVOID requestBuffer;
+ ULONG information = 0;
+ size_t bufSize;
+
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ status = STATUS_SUCCESS;
+
+ switch (IoControlCode) {
+
+ case IOCTL_SERIAL_GET_WAIT_MASK: {
+
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(ULONG),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+ *((PULONG)requestBuffer)= fmDeviceData->CurrentMask;
+
+ information = sizeof(ULONG);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_WAIT_MASK: {
+
+ WDFREQUEST currentWaitRequest=NULL;
+ ULONG newMask;
+
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(ULONG),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+
+ }
+ else {
+ NTSTATUS tempStatus;
+ //
+ // get rid of the current wait
+ //
+
+ newMask = *((ULONG *)requestBuffer);
+
+ fmDeviceData->CurrentMask = newMask;
+
+ KdPrint(("FAKEMODEM: set wait mask, %08lx\n", newMask));
+
+ tempStatus = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmMaskWaitQueue,
+ &currentWaitRequest);
+ // save the new mask
+
+ if (NT_SUCCESS(tempStatus)) {//currentWaitRequest != NULL) {
+
+ PULONG outBuffer;
+
+ KdPrint(("FAKEMODEM: set wait mask- complete wait\n"));
+
+ //
+ // The length was validated already.
+ //
+ tempStatus = WdfRequestRetrieveOutputBuffer(currentWaitRequest,
+ sizeof(ULONG),
+ &outBuffer,
+ &bufSize);
+ if (NT_SUCCESS(tempStatus)) {
+ if (outBuffer) { // FIXME SAL
+ *outBuffer = 0;
+ }
+
+ WdfRequestCompleteWithInformation(currentWaitRequest,
+ STATUS_SUCCESS,
+ sizeof(ULONG));
+ } else {
+ WdfRequestComplete(currentWaitRequest, tempStatus);
+ }
+ }
+ information = sizeof(ULONG);
+ }
+ break;
+ }
+
+ case IOCTL_SERIAL_WAIT_ON_MASK: {
+
+ WDFREQUEST currentWaitRequest = NULL;
+ NTSTATUS tempStatus;
+
+ status = WdfRequestRetrieveOutputBuffer (Request,
+ sizeof(ULONG),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ KdPrint(("FAKEMODEM: wait on mask\n"));
+ //
+ // remove the current request if any
+ //
+ tempStatus = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmMaskWaitQueue,
+ &currentWaitRequest);
+
+ if (NT_SUCCESS(tempStatus)) { //currentWaitRequest != NULL) {
+
+ PULONG outBuffer;
+
+ KdPrint(("FAKEMODEM: wait on mask- complete wait\n"));
+
+ //
+ // The length was validated already.
+ //
+
+ tempStatus = WdfRequestRetrieveOutputBuffer(currentWaitRequest,
+ sizeof(ULONG),
+ &outBuffer,
+ &bufSize);
+ if(NT_SUCCESS(tempStatus)) {
+ if (outBuffer) { // FIXME SAL
+ *((PULONG)outBuffer) = 0;
+ }
+
+ WdfRequestCompleteWithInformation(currentWaitRequest,
+ STATUS_SUCCESS,
+ sizeof(ULONG));
+ } else {
+ WdfRequestComplete(currentWaitRequest, tempStatus);
+ }
+
+ }
+
+ if (fmDeviceData->CurrentMask == 0) {
+ //
+ // can only set if mask is not zero
+ //
+ status=STATUS_UNSUCCESSFUL;
+
+ } else {
+
+ //
+ // add the current request to the wait queue
+ //
+ status = WdfRequestForwardToIoQueue(Request, fmDeviceData->FmMaskWaitQueue);
+ if (!NT_SUCCESS(status)) {
+ WdfRequestCompleteWithInformation(Request, STATUS_UNSUCCESSFUL, 0);
+ return;
+ }
+
+ status=STATUS_PENDING;
+ }
+
+ break;
+ }
+
+ case IOCTL_SERIAL_PURGE: {
+
+ ULONG mask;
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(ULONG),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+
+ }
+ mask=*((PULONG)requestBuffer);
+
+ if (mask & SERIAL_PURGE_RXABORT) {
+
+ WdfIoQueuePurge( fmDeviceData->FmReadQueue,
+ WDF_NO_EVENT_CALLBACK,
+ WDF_NO_CONTEXT );
+
+ WdfIoQueueStart(fmDeviceData->FmReadQueue);
+ }
+ information = sizeof(ULONG);
+ break;
+ }
+
+
+ case IOCTL_SERIAL_GET_MODEMSTATUS: {
+
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(ULONG),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+ information = sizeof(ULONG);
+
+ *((PULONG)requestBuffer) = fmDeviceData->ModemStatus;
+
+ break;
+ }
+
+
+ case IOCTL_SERIAL_SET_TIMEOUTS: {
+ PSERIAL_TIMEOUTS NewTimeouts;
+
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(SERIAL_TIMEOUTS),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+
+ }
+ NewTimeouts= ((PSERIAL_TIMEOUTS)(requestBuffer));
+
+ if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) &&
+ (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
+ (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG))
+ {
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ information = sizeof(SERIAL_TIMEOUTS);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_TIMEOUTS: {
+
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(SERIAL_TIMEOUTS),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+ *((PSERIAL_TIMEOUTS)requestBuffer) =
+ fmDeviceData->CurrentTimeouts;
+
+ information = sizeof(SERIAL_TIMEOUTS);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_COMMSTATUS: {
+
+ PSERIAL_STATUS serialStatus ;
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(SERIAL_STATUS),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+ serialStatus = (PSERIAL_STATUS) requestBuffer;
+
+ RtlZeroMemory( serialStatus, sizeof(*serialStatus) ); // FIXME SAL
+
+ serialStatus->AmountInInQueue = fmDeviceData->BytesInReadBuffer;
+
+ information = sizeof(SERIAL_STATUS);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_DTR:
+ case IOCTL_SERIAL_CLR_DTR: {
+
+ if (IoControlCode == IOCTL_SERIAL_SET_DTR) {
+
+ //
+ // raising DTR
+ //
+
+ fmDeviceData->ModemStatus=SERIAL_DTR_STATE | SERIAL_DSR_STATE;
+
+ KdPrint(("FAKEMODEM: Set DTR\n"));
+
+ } else {
+ //
+ // dropping DTR, drop connection if there is one
+ //
+ KdPrint(("FAKEMODEM: Clear DTR\n"));
+
+ if (fmDeviceData->CurrentlyConnected == TRUE) {
+ //
+ // not connected any more
+ //
+ fmDeviceData->CurrentlyConnected=FALSE;
+
+ fmDeviceData->ConnectionStateChanged=TRUE;
+ }
+ }
+
+ ProcessConnectionStateChange( fmDeviceData);
+
+ information = sizeof(ULONG);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_QUEUE_SIZE: {
+
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(SERIAL_QUEUE_SIZE),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+
+ }
+
+ //
+ // This ioctl doesn't do anyhing except test for the size of the
+ // buffer passed in.
+ //
+ information = sizeof(SERIAL_QUEUE_SIZE);
+ break;
+ }
+
+
+ case IOCTL_SERIAL_SET_BAUD_RATE: {
+
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(SERIAL_BAUD_RATE),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+ else {
+ fmDeviceData->BaudRate = ((PSERIAL_BAUD_RATE)requestBuffer)->BaudRate;
+ }
+ information = sizeof(SERIAL_BAUD_RATE);
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_BAUD_RATE: {
+
+ PSERIAL_BAUD_RATE pBaudRate ;
+
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(SERIAL_BAUD_RATE),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+ pBaudRate = (PSERIAL_BAUD_RATE)requestBuffer;
+ pBaudRate->BaudRate = fmDeviceData->BaudRate;
+ information = sizeof(SERIAL_BAUD_RATE);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_LINE_CONTROL: {
+
+ PSERIAL_LINE_CONTROL pLineControl ;
+ UCHAR LData = 0;
+ UCHAR LStop = 0;
+ UCHAR LParity = 0;
+ UCHAR Mask = 0xff;
+
+ status = WdfRequestRetrieveInputBuffer (Request,
+ sizeof(SERIAL_LINE_CONTROL),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(("Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+
+ }
+ pLineControl = ((PSERIAL_LINE_CONTROL)requestBuffer);
+
+ switch(pLineControl->WordLength)
+ {
+ case 5: {
+
+ LData = SERIAL_5_DATA;
+ Mask = 0x1f;
+ break;
+
+ }
+ case 6: {
+
+ LData = SERIAL_6_DATA;
+ Mask = 0x3f;
+ break;
+
+ }
+ case 7: {
+
+ LData = SERIAL_7_DATA;
+ Mask = 0x7f;
+ break;
+
+ }
+ case 8: {
+
+ LData = SERIAL_8_DATA;
+ break;
+
+ }
+ default: {
+
+ status = STATUS_INVALID_PARAMETER;
+
+ }
+ }
+
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ switch (pLineControl->Parity) {
+
+ case NO_PARITY: {
+ LParity = SERIAL_NONE_PARITY;
+ break;
+
+ }
+ case EVEN_PARITY: {
+ LParity = SERIAL_EVEN_PARITY;
+ break;
+
+ }
+ case ODD_PARITY: {
+ LParity = SERIAL_ODD_PARITY;
+ break;
+
+ }
+ case SPACE_PARITY: {
+ LParity = SERIAL_SPACE_PARITY;
+ break;
+
+ }
+ case MARK_PARITY: {
+ LParity = SERIAL_MARK_PARITY;
+ break;
+
+ }
+ default: {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ }
+
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ switch (pLineControl->StopBits) {
+
+ case STOP_BIT_1: {
+
+ LStop = SERIAL_1_STOP;
+ break;
+ }
+
+ case STOP_BITS_1_5: {
+
+ if (LData != SERIAL_5_DATA) {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ LStop = SERIAL_1_5_STOP;
+ break;
+
+ }
+ case STOP_BITS_2: {
+
+ if (LData == SERIAL_5_DATA) {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ LStop = SERIAL_2_STOP;
+ break;
+ }
+
+ default: {
+
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ }
+
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ fmDeviceData->LineControl =
+ (UCHAR)((fmDeviceData->LineControl & SERIAL_LCR_BREAK) |
+ (LData | LParity | LStop));
+
+ fmDeviceData->ValidDataMask = Mask;
+ information = sizeof(SERIAL_LINE_CONTROL);
+ break;
+ }
+
+ case IOCTL_SERIAL_GET_LINE_CONTROL: {
+ PSERIAL_LINE_CONTROL pLineControl ;
+
+ status = WdfRequestRetrieveOutputBuffer ( Request,
+ sizeof(SERIAL_LINE_CONTROL),
+ &requestBuffer,
+ &bufSize );
+ if( !NT_SUCCESS(status) ) {
+ KdPrint(( "Could not get request memory buffer status %X\n", status));
+ information = 0;
+ break;
+ }
+
+
+ pLineControl =
+ (PSERIAL_LINE_CONTROL)requestBuffer;
+
+ RtlZeroMemory(requestBuffer,
+ bufSize);
+
+
+ switch (fmDeviceData->LineControl & SERIAL_DATA_MASK) {
+ case SERIAL_5_DATA:
+ pLineControl->WordLength = 5;
+ break;
+ case SERIAL_6_DATA:
+ pLineControl->WordLength = 6;
+ break;
+ case SERIAL_7_DATA:
+ pLineControl->WordLength = 7;
+ break;
+ case SERIAL_8_DATA:
+ pLineControl->WordLength = 8;
+ break;
+ default:
+ break;
+
+ }
+
+ switch (fmDeviceData->LineControl & SERIAL_PARITY_MASK) {
+ case SERIAL_NONE_PARITY:
+ pLineControl->Parity = NO_PARITY;
+ break;
+ case SERIAL_ODD_PARITY:
+ pLineControl->Parity = ODD_PARITY;
+ break;
+ case SERIAL_EVEN_PARITY:
+ pLineControl->Parity = EVEN_PARITY;
+ break;
+ case SERIAL_MARK_PARITY:
+ pLineControl->Parity = MARK_PARITY;
+ break;
+ case SERIAL_SPACE_PARITY:
+ pLineControl->Parity = SPACE_PARITY;
+ break;
+ default:
+ break;
+
+ }
+
+ if (fmDeviceData->LineControl & SERIAL_2_STOP) {
+
+ if (pLineControl->WordLength == 5) {
+
+ pLineControl->StopBits = STOP_BITS_1_5;
+
+ } else {
+
+ pLineControl->StopBits = STOP_BITS_2;
+
+ }
+
+ } else {
+
+ pLineControl->StopBits = STOP_BIT_1;
+ }
+
+ information = sizeof(SERIAL_LINE_CONTROL);
+
+ break;
+ }
+
+ case IOCTL_SERIAL_SET_RTS:
+ case IOCTL_SERIAL_CLR_RTS:
+ case IOCTL_SERIAL_SET_XON:
+ case IOCTL_SERIAL_SET_XOFF:
+ case IOCTL_SERIAL_SET_CHARS:
+ case IOCTL_SERIAL_GET_CHARS:
+ case IOCTL_SERIAL_GET_HANDFLOW:
+ case IOCTL_SERIAL_SET_HANDFLOW:
+ case IOCTL_SERIAL_RESET_DEVICE: {
+ //
+ // NOTE: The application expects STATUS_SUCCESS for these ioctsl.
+ // so don't merge this with default.
+ //
+ break;
+ }
+ default:
+ status=STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ if (status != STATUS_PENDING) {
+ //
+ // complete now if not pending
+ //
+ WdfRequestCompleteWithInformation(Request, status, information);
+ }
+}
+
+
+
+VOID
+ProcessConnectionStateChange(
+ IN PFM_DEVICE_DATA FmDeviceData
+ )
+{
+ WDFREQUEST currentWaitRequest = NULL;
+ NTSTATUS status;
+
+ if (FmDeviceData->ConnectionStateChanged) {
+
+ //
+ // state changed
+ //
+
+ FmDeviceData->ConnectionStateChanged=FALSE;
+
+ if (FmDeviceData->CurrentlyConnected) {
+ //
+ // now it is connected, raise CD
+ //
+ FmDeviceData->ModemStatus |= SERIAL_DCD_STATE;
+
+
+ } else {
+ //
+ // not connected any more, clear CD
+ //
+ FmDeviceData->ModemStatus &= ~(SERIAL_DCD_STATE);
+
+ }
+
+
+ if (FmDeviceData->CurrentMask & SERIAL_EV_RLSD) {
+
+ //
+ // app want's to know about these changes, tell it
+ //
+ status = WdfIoQueueRetrieveNextRequest(FmDeviceData->FmMaskWaitQueue,
+ &currentWaitRequest);
+ if(!NT_SUCCESS(status)){
+ ASSERT(status == STATUS_NO_MORE_ENTRIES);
+ }
+ }
+
+ }
+
+
+ if (currentWaitRequest != NULL) {
+
+ PULONG outBuffer;
+ size_t bufSize;
+
+ KdPrint(("FAKEMODEM: ProcessConectionState\n"));
+
+ //
+ // The length was validated already.
+ //
+
+ (VOID)WdfRequestRetrieveOutputBuffer(currentWaitRequest,
+ sizeof(ULONG),
+ &outBuffer,
+ &bufSize);
+
+ if (outBuffer) { // FIXME SAL
+ *outBuffer = SERIAL_EV_RLSD;
+ }
+
+ WdfRequestCompleteWithInformation(currentWaitRequest,
+ STATUS_SUCCESS,
+ sizeof(ULONG));
+
+ }
+
+ return;
+
+}
+
+
diff --git a/network/modem/fakemodem/mdmfake.inx b/network/modem/fakemodem/mdmfake.inx
new file mode 100644
index 00000000..4342404a
--- /dev/null
+++ b/network/modem/fakemodem/mdmfake.inx
@@ -0,0 +1,267 @@
+;
+; "Fakemodem" Controllerless driver illustrative example
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; *******************************************************************
+; * *
+; * The following INF is used in order to load this sample driver. *
+; * Further information about INF design can be found in the DDK *
+; * *
+; *******************************************************************
+
+; ------------------------------------------------------------------------------
+; Check final modem INF with CINF tool then test with
+; NDIS Test prior to final distribution.
+;-------------------------------------------------------------------------------
+
+;------------------------------------------------------------------------------------------------------
+;This section must specify the following entries with the indicated values:
+;Signature entry as the $Windows NT$ value. This value indicates that the INF is only valid for NT-based operating systems.
+;Class entry as "MODEM".
+;ClassGUID entry as {4D36E96D-E325-11CE-BFC1-08002BE10318}.
+;Provider is the company responsible for the provision of the INF.
+;DriverVer must be in the following format = mm/dd/yyyy[,x.y.v.z]
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Modem
+ClassGUID={4D36E96D-E325-11CE-BFC1-08002BE10318}
+Provider=%Mfg%
+DriverVer=11/11/2002,5.1.3711
+
+;INF files that are not distributed with the OS should contain the following line:
+CatalogFile=KmdfSamples.cat
+
+;INF files that are to be distributed with the OS that load a service and or files on the CD, should contain the following line:
+;Layoutfile=layout.inf
+
+;----------------------------------------------------------------------------------------------------------------------------; Below is list of manufacturers that will appear in the
+; Install New Modem wizard's list of manufacturers as well as define what sections to install ID's from
+; The vendor will be required to change the provider key before a
+; driver submission is made
+
+[Manufacturer]
+%Generic% = Generic,NT$ARCH$
+
+
+;-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+;This section references the INF-writer-defined DDInstall and DDInstall.Services sections for the Modem device, and specifies the hardware identifier for the Modem device.
+
+[Generic.NT$ARCH$]
+%ModemX% = ModemX, {b85b7c50-6a01-11d2-b841-00c04fad5171}\fakemodem
+
+;-------------------------------------------------------------------------------------------------------
+; For detailed explanation of DDInstall.Services section, please reference DDK.
+; Installation section references other INF sections to be installed for a specific modem.
+; The AddReg line points to sections of the INF file that list registry entries to be added when
+; installing this modem. For example, the line below instructs the installer to add the registry
+; entries listed in the following sections of this INF file:
+; [All], [MfgAddReg], [ExtraCRLFResponses], [ModemX.AddReg], [INTERNAL]
+; It is not necessary to break up the registry additions into different sections in the
+; INF. However, breaking out common entries into sections can help to reduce the size of
+; the INF if multiple modems are installed from the same INF and have common registry
+; entries.
+
+[ModemX.NT]
+CopyFiles = CopyFileSection
+AddReg = All, MfgAddReg, ExtraCRLFResponses, ModemX.AddReg, INTERNAL
+
+[ModemX.NT.Services]
+AddService = fakemdm, 0x00000000, FakeModm_Service_Inst, FakeModm_Logging_Inst
+
+[ModemX.NT.HW]
+AddReg = LowerFilterAddReg
+
+[LowerFilterAddReg]
+HKR,,"LowerFilters",0x00010000,fakemdm
+
+[FakeModm_Service_Inst]
+DisplayName = %ModemX%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\fakemodem.sys
+
+;--------------------------------------------------------------------------------------------------------------------
+; An event-log-install-section
+
+[FakeModm_Logging_Inst]
+AddReg = FakeModm_Logging_Inst_AddReg
+
+[FakeModm_Logging_Inst_AddReg]
+HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\Fakemodem.sys"
+HKR,,TypesSupported,0x00010001,7
+
+[SourceDisksNames]
+99=%FakeDisk%, disk1,,""
+
+[SourceDisksFiles]
+fakemodem.sys = 99
+
+;-------------------------------------------------------------------------------------------------------------------
+; Section used to copy files required for device to function
+
+[CopyFileSection]
+fakemodem.sys
+
+;--------------------------------------------------------------------------------------------------------------------------
+; This section lists the Default location to copy the files listed in the copyfiles directive
+; 12 = %Windows%\System32\Drivers
+
+[DestinationDirs]
+CopyFileSection=12
+DefaultDestDir=12
+
+
+;
+;--- ModemX Coinstaller installation ------
+;
+[DestinationDirs]
+ModemX_CoInstaller_CopyFiles = 11
+
+[ModemX.NT.CoInstallers]
+AddReg=ModemX_CoInstaller_AddReg
+CopyFiles=ModemX_CoInstaller_CopyFiles
+
+[ModemX_CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[ModemX_CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[SourceDisksFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=99 ; make sure the number matches with SourceDisksNames
+
+[ModemX.NT.Wdf]
+KmdfService = fakemdm, fakemdm_wdfsect
+[fakemdm_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+
+
+;-------------------------------------------------------------------------------------------------------
+; DDK procalc tool can be used to check properties settings which describes modem' properties.
+; Generally, customization entries are added here which override commands from the All section
+
+[ModemX.AddReg]
+HKR,,Properties, 1, 80,01,00,00, ff,00,00,00, ff,00,00,00, 07,00,00,00, 0f,00,00,00, f7,03,00,00, 00,c2,01,00, 40,38,00,00
+HKR,,InactivityScale, 1, 0a,00,00,00
+HKR, Settings, InactivityTimeout,, "S30=<#>"
+HKR, Settings, ErrorControl_On,, "\N3"
+HKR, Settings, ErrorControl_Forced,, "\N2"
+HKR, Settings, Compression_On,, "%%C3"
+HKR, Settings, SpeedNegotiation_Off,, "N0"
+HKR, Settings, SpeedNegotiation_On,, "N1"
+
+;--------------------------------------------------------------------------------------------------------------------------
+;This section will define the type of modem and thus present the appropriate icon in the Device manager
+
+[INTERNAL]
+HKR,, DeviceType, 1, 02
+
+;-------------------------------------------------------------------------------------------------------------------------
+; Responses section contains all of the appropriate and required responses in order for the O/S to understand the
+; Modem responses to system queries.
+
+[All]
+HKR,,ConfigDialog,,modemui.dll
+HKR,,EnumPropPages,,"modemui.dll,EnumPropPages"
+HKR,,PortSubClass,1,02
+HKR,Init,1,,"AT<cr>"
+HKR,Init, 2,, "AT &F E0 V1 &D2 &C1 S0=0 W2 S95=47<cr>"
+
+[MfgAddReg]
+HKR,, InactivityScale, 1, 01,00,00,00
+HKR, Monitor, 1,, "ATS0=0<cr>"
+HKR, Monitor, 2,, "None"
+HKR, Hangup, 1,, "ATH<cr>"
+HKR, Answer, 1,, "ATA<cr>"
+HKR,, Reset,, "ATZ<cr>"
+HKR, Settings, Prefix,, "AT"
+HKR, Settings, Terminator,, "<cr>"
+HKR, Settings, DialPrefix,, "D"
+HKR, Settings, DialSuffix,, ";"
+HKR, Settings, SpeakerVolume_Low,, "L1"
+HKR, Settings, SpeakerVolume_Med,, "L2"
+HKR, Settings, SpeakerVolume_High,, "L3"
+HKR, Settings, SpeakerMode_Off,, "M0"
+HKR, Settings, SpeakerMode_Dial,, "M1"
+HKR, Settings, SpeakerMode_On,, "M2"
+HKR, Settings, SpeakerMode_Setup,, "M3"
+HKR, Settings, FlowControl_Off,, "&K0"
+HKR, Settings, FlowControl_Hard,, "&K3"
+HKR, Settings, FlowControl_Soft,, "&K4"
+HKR, Settings, ErrorControl_On,, "\N5"
+HKR, Settings, ErrorControl_Off,, "\N0"
+HKR, Settings, ErrorControl_Forced,, "\N4"
+HKR, Settings, Compression_On,, "%%C1"
+HKR, Settings, Compression_Off,, "%%C0"
+HKR, Settings, Modulation_CCITT,, "B0 "
+HKR, Settings, Modulation_Bell,, "B1 "
+HKR, Settings, SpeedNegotiation_Off,, "*S0"
+HKR, Settings, SpeedNegotiation_On,, "*S1"
+HKR, Settings, Pulse,, "P"
+HKR, Settings, Tone,, "T"
+HKR, Settings, Blind_Off,, "X4"
+HKR, Settings, Blind_On,, "X3"
+HKR, Settings, CallSetupFailTimer,, "S7=<#>"
+
+HKR, Responses, "<cr><lf>+FCERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>BLACKLISTED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00
+
+HKR, Responses, "<cr><lf>CONNECT<cr><lf>", 1, 02, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>DATA<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>DELAYED<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+
+HKR, Responses, "<cr><lf>FAX<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>NOTUSED<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>RING<cr><lf>", 1, 08, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf>RINGING<cr><lf>", 1, 01, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "0<cr>", 1, 00, 00, 00,00,00,00, 00,00,00,00 ; OK
+HKR, Responses, "1<cr>", 1, 02, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "10<cr>", 1, 02, 00, 60,09,00,00, 00,00,00,00
+HKR, Responses, "11<cr>", 1, 02, 00, c0,12,00,00, 00,00,00,00
+HKR, Responses, "12<cr>", 1, 02, 00, 80,25,00,00, 00,00,00,00
+HKR, Responses, "13<cr>", 1, 02, 00, 20,1c,00,00, 00,00,00,00
+HKR, Responses, "14<cr>", 1, 02, 00, e0,2e,00,00, 00,00,00,00
+HKR, Responses, "15<cr>", 1, 02, 00, 40,38,00,00, 00,00,00,00 ; connect at 14400
+HKR, Responses, "2<cr>", 1, 08, 00, 00,00,00,00, 00,00,00,00 ; RING
+HKR, Responses, "3<cr>", 1, 04, 00, 00,00,00,00, 00,00,00,00 ; NO CARRIER
+HKR, Responses, "4<cr>", 1, 03, 00, 00,00,00,00, 00,00,00,00 ; ERROR
+HKR, Responses, "5<cr>", 1, 02, 00, b0,04,00,00, 00,00,00,00
+HKR, Responses, "6<cr>", 1, 05, 00, 00,00,00,00, 00,00,00,00 ; NO DIALTONE
+HKR, Responses, "69<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00
+HKR, Responses, "7<cr>", 1, 06, 00, 00,00,00,00, 00,00,00,00 ; BUSY
+HKR, Responses, "70<cr>", 1, 01, 01, 00,00,00,00, 00,00,00,00 ; Protocol:None
+HKR, Responses, "77<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:LAPM
+HKR, Responses, "78<cr>", 1, 01, 03, 00,00,00,00, 00,00,00,00 ; Connect V42BIS
+HKR, Responses, "8<cr>", 1, 07, 00, 00,00,00,00, 00,00,00,00 ; NO ANSWER
+HKR, Responses, "80<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00 ; Protocol:ALT
+HKR, Responses, "81<cr>", 1, 01, 02, 00,00,00,00, 00,00,00,00
+
+[ExtraCRLFResponses]
+HKR, Responses, "<cr><lf><cr><lf>OK<cr><lf>", 1, 00, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>ERROR<cr><lf>", 1, 03, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>BUSY<cr><lf>", 1, 06, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO ANSWER<cr><lf>", 1, 07, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO CARRIER<cr><lf>", 1, 04, 00, 00,00,00,00, 00,00,00,00
+HKR, Responses, "<cr><lf><cr><lf>NO DIALTONE<cr><lf>", 1, 05, 00, 00,00,00,00, 00,00,00,00
+
+;-------------------------------------------------------------------------------------------------------
+;This section defines each %strkey% token specified in the INF and lists strings that are used by the Modems
+;control panel applet and the Install New Modem wizard.
+; For example, ModemX will appear as "FakeModem DDK Sample controllerless driver"
+
+[Strings]
+mfg = "Microsoft"
+FakeDisk = "Fake Modem Install Disk"
+Generic = "(Standard Modem Types)"
+ModemX = "FakeModem DDK Sample controllerless driver"
+ServiceName = "Fakemodem"
diff --git a/network/modem/fakemodem/readwrit.c b/network/modem/fakemodem/readwrit.c
new file mode 100644
index 00000000..af6da937
--- /dev/null
+++ b/network/modem/fakemodem/readwrit.c
@@ -0,0 +1,465 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ioctl.c
+
+Abstract:
+
+ This is a simple form of function driver for Fm device. The driver
+ doesn't handle any PnP and Power events because the framework provides
+ default behaviour for those events. This driver has enough support to
+ allow an user application (toast/notify.exe) to open the device
+ interface registered by the driver and send read, write or ioctl requests.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "fakemodem.h"
+
+
+VOID
+FmEvtIoRead(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_READ
+ requests from the system.
+ This routines defers read for later processing if there is no data to read.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+
+ Length - Length of the IO operation
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue));
+ ULONG information;
+ NTSTATUS status;
+ PUCHAR systemBuffer;
+ size_t bufLen;
+
+ status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &bufLen);
+ if (!NT_SUCCESS(status)) {
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ if (fmDeviceData->BytesInReadBuffer > 0) {
+
+ ProcessReadBuffer(fmDeviceData,
+ systemBuffer,
+ (ULONG) Length,
+ &information);
+
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, information);
+
+ return;
+
+ } else {
+
+ //
+ // No data to read. Queue the request for later processing.
+ //
+
+ status = WdfRequestForwardToIoQueue(Request, fmDeviceData->FmReadQueue);
+ if (!NT_SUCCESS(status)) {
+ WdfRequestCompleteWithInformation(Request, status, 0);
+ return;
+ }
+ }
+}
+
+VOID
+FmEvtIoWrite(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_WRITE
+ requests from the system.
+ This routine will also drain the read queue if there are pending reads.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+
+ Length - Length of the IO operation
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFM_DEVICE_DATA fmDeviceData = FmDeviceDataGet(WdfIoQueueGetDevice(Queue));
+ PUCHAR systemBuffer;
+ NTSTATUS status;
+ size_t length;
+ WDFREQUEST readRequest;
+
+ status = WdfRequestRetrieveInputBuffer(Request, Length, &systemBuffer, &length);
+ if (!NT_SUCCESS(status)) {
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ ProcessWriteBytes( fmDeviceData, systemBuffer, (ULONG) Length);
+
+ //
+ // Process read requests and complete them here.
+ //
+
+ while (fmDeviceData->BytesInReadBuffer > 0) {
+ ULONG bytesToMove = 0;
+
+ status = WdfIoQueueRetrieveNextRequest(fmDeviceData->FmReadQueue, &readRequest);
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(readRequest, 0, &systemBuffer, &length);
+ if (NT_SUCCESS(status)) {
+ ProcessReadBuffer(fmDeviceData,
+ systemBuffer,
+ (ULONG) length,
+ &bytesToMove);
+ }
+ WdfRequestCompleteWithInformation(readRequest, status, bytesToMove);
+ }
+
+ ProcessConnectionStateChange( fmDeviceData);
+
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length);
+}
+
+VOID
+ProcessWriteBytes(
+ PFM_DEVICE_DATA FmDeviceData,
+ PUCHAR Characters,
+ ULONG Length
+ )
+/*++
+Routine Description:
+
+ This function is called when the framework receives IRP_MJ_WRITE
+ requests from the system. The write event handler(FmEvtIoWrite) calls ProcessWriteBytes.
+ It parses the Characters passed in and looks for the for sequences "AT" -ok ,
+ "ATA" --CONNECT, ATD<number> -- CONNECT and sets the state of the device appropriately.
+ These bytes are placed in the read Buffer to be processed later since this device
+ works in a loopback fashion.
+
+
+Arguments:
+
+ FmDeviceData - Handle to the framework queue object that is associated
+ with the I/O request.
+ Characters - Pointer to the write IRP's system buffer.
+
+ Length - Length of the IO operation
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+ VOID
+
+--*/
+
+{
+
+ UCHAR currentCharacter;
+
+ while (Length != 0) {
+
+ currentCharacter=*Characters++;
+ Length--;
+
+ if(currentCharacter == '\0')
+ {
+ continue;
+ }
+
+ PutCharInReadBuffer( FmDeviceData, currentCharacter);
+
+ switch (FmDeviceData->CommandMatchState) {
+
+ case COMMAND_MATCH_STATE_IDLE:
+
+ if ((currentCharacter == 'a') || (currentCharacter == 'A')) {
+ // got an A
+ FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_GOT_A;
+
+ FmDeviceData->ConnectCommand=FALSE;
+
+ FmDeviceData->IgnoreNextChar=FALSE;
+
+ }
+
+ break;
+
+ case COMMAND_MATCH_STATE_GOT_A:
+
+ if ((currentCharacter == 't') || (currentCharacter == 'T')) {
+ // got an T
+ FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_GOT_T;
+
+ } else {
+
+ if (currentCharacter == '\r') {
+
+ FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_IDLE;
+ }
+ }
+
+ break;
+
+ case COMMAND_MATCH_STATE_GOT_T:
+
+ if (!FmDeviceData->IgnoreNextChar) {
+ // the last char was not a special char
+ // check for CONNECT command
+ if ((currentCharacter == 'A') || (currentCharacter == 'a')) {
+
+ FmDeviceData->ConnectCommand=TRUE;
+ }
+
+ if ((currentCharacter == 'D') || (currentCharacter == 'd')) {
+
+ FmDeviceData->ConnectCommand=TRUE;
+ }
+ }
+
+ FmDeviceData->IgnoreNextChar=TRUE;
+
+ if (currentCharacter == '\r') {
+ //
+ // got a CR, send a response to the command
+ //
+ FmDeviceData->CommandMatchState=COMMAND_MATCH_STATE_IDLE;
+
+ if (FmDeviceData->ConnectCommand) {
+ //
+ // place <cr><lf>CONNECT<cr><lf> in the buffer
+ //
+ PutCharInReadBuffer(FmDeviceData,'\r');
+ PutCharInReadBuffer(FmDeviceData,'\n');
+
+ PutCharInReadBuffer(FmDeviceData,'C');
+ PutCharInReadBuffer(FmDeviceData,'O');
+ PutCharInReadBuffer(FmDeviceData,'N');
+ PutCharInReadBuffer(FmDeviceData,'N');
+ PutCharInReadBuffer(FmDeviceData,'E');
+ PutCharInReadBuffer(FmDeviceData,'C');
+ PutCharInReadBuffer(FmDeviceData,'T');
+
+ PutCharInReadBuffer(FmDeviceData,'\r');
+ PutCharInReadBuffer(FmDeviceData,'\n');
+
+ //
+ // connected now raise CD
+ //
+ FmDeviceData->CurrentlyConnected=TRUE;
+
+ FmDeviceData->ConnectionStateChanged=TRUE;
+
+ } else {
+
+ // place <cr><lf>OK<cr><lf> in the buffer
+
+ PutCharInReadBuffer(FmDeviceData,'\r');
+ PutCharInReadBuffer(FmDeviceData,'\n');
+ PutCharInReadBuffer(FmDeviceData,'O');
+ PutCharInReadBuffer(FmDeviceData,'K');
+ PutCharInReadBuffer(FmDeviceData,'\r');
+ PutCharInReadBuffer(FmDeviceData,'\n');
+ }
+ }
+
+
+ break;
+
+ default:
+
+ break;
+
+ }
+ }
+
+ return;
+
+}
+
+VOID
+PutCharInReadBuffer(
+ PFM_DEVICE_DATA FmDeviceData,
+ UCHAR Character
+ )
+/*++
+Routine Description:
+
+ This routine puts the charcter into the circular read buffer checking for overflows while doing it.
+
+Arguments:
+
+ FmDeviceData - Handle to the framework queue object that is associated
+ with the I/O request.
+ Characters - Handle to a framework request object.
+
+
+Return Value:
+
+ VOID
+
+--*/
+
+{
+
+ if (FmDeviceData->BytesInReadBuffer < READ_BUFFER_SIZE) {
+
+ // room in buffer
+ FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferEnd]=Character;
+ FmDeviceData->ReadBufferEnd++;
+ FmDeviceData->ReadBufferEnd %= READ_BUFFER_SIZE;
+ FmDeviceData->BytesInReadBuffer++;
+
+ }
+
+ return;
+
+}
+
+VOID
+ProcessReadBuffer(
+ IN PFM_DEVICE_DATA FmDeviceData,
+ IN PUCHAR SystemBuffer,
+ IN ULONG Length,
+ OUT PULONG BytesToMove
+ )
+/*++
+Routine Description:
+
+ This event is called when the framework receives IRP_MJ_READ
+ requests from the system. It is called by the read event handler.
+ It copies data from the IRp's system buffer to the device read buffer.
+ if the size of data from the Irp's system buffer is greater than the size of the
+ read buffer the number of bytes remaining is passed back in BytesToMove.
+
+
+Arguments:
+
+ FmDeviceData - Handle to the framework queue object that is associated
+ with the I/O request.
+ SystemBuffer - The buffer passed in the IRP which contains the read data.
+
+ Length - Length of data in the systembuffer
+ BytesToMove - Remaining bytes not copied into the read buffer.
+Return Value:
+
+ VOID
+
+--*/
+{
+ ULONG firstHalf;
+ ULONG secondHalf;
+ ULONG bytesToMove;
+ NTSTATUS status;
+ ULONG safeBoundsCheck;
+
+ //
+ // there is an IRP and there are characters waiting
+ //
+
+
+ bytesToMove = (Length < FmDeviceData->BytesInReadBuffer) ? Length
+ : FmDeviceData->BytesInReadBuffer;
+
+ status = RtlULongAdd (FmDeviceData->ReadBufferBegin,
+ bytesToMove,
+ &safeBoundsCheck);
+
+ if (!NT_SUCCESS(status)) {
+ return;
+ }
+
+ if (safeBoundsCheck > READ_BUFFER_SIZE) {
+
+ //
+ // the buffer is wrapped around, have move in two pieces
+ //
+
+ firstHalf = READ_BUFFER_SIZE - FmDeviceData->ReadBufferBegin;
+
+ secondHalf= bytesToMove - firstHalf;
+
+ RtlCopyMemory(
+ SystemBuffer,
+ &FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferBegin],
+ firstHalf);
+
+ RtlCopyMemory(
+ (SystemBuffer + firstHalf),
+ &FmDeviceData->ReadBuffer[0],
+ secondHalf);
+
+ } else {
+
+ //
+ // can do it all at once
+ //
+
+ RtlCopyMemory(
+ SystemBuffer,
+ &FmDeviceData->ReadBuffer[FmDeviceData->ReadBufferBegin],
+ bytesToMove);
+ }
+
+ //
+ // fix up queue pointers
+ //
+ FmDeviceData->BytesInReadBuffer -= bytesToMove;
+
+ FmDeviceData->ReadBufferBegin += bytesToMove;
+
+ FmDeviceData->ReadBufferBegin %= READ_BUFFER_SIZE;
+
+ *BytesToMove = bytesToMove;
+}
+
diff --git a/network/ndis/extension/ReadMe.md b/network/ndis/extension/ReadMe.md
new file mode 100644
index 00000000..dc3b6b92
--- /dev/null
+++ b/network/ndis/extension/ReadMe.md
@@ -0,0 +1,21 @@
+Hyper-V Extensible Switch extension filter driver
+=================================================
+
+This sample contains a base library used to implement a Hyper-V Extensible Switch extension filter driver. This sample also contains two different extension filter drivers that were developed by using the library.
+
+Hyper-V Extensible Switch extension filter drivers use the NDIS filter model. Every Hyper-V Extensible Switch has a corresponding Extension Protocol and Miniport instance. NDIS OIDs are leveraged to inform filter drivers on the driver stack about switch/port/NIC information. All packets originating from a switch port (External NIC, Synthetic NIC, Emulated NIC and Internal NIC) are first issued as a send from the Extension Protocol, which populates the packet with source information. This corresponds to the ingress data flow. Source based filtering, packet modification, packet queuing, and destination definition can occur at this stage. If the packets arrive at the Extension Miniport, they pass through the built in filtering/forwarding logic. If the packets pass filtering and must be delivered to any destination ports, they are issued as an indication (receive) from the Extension Miniport, which populate the packet with the source and destination information. This corresponds to the egress data flow. Destination based filtering can occur at this stage. If the packets arrive at the Extension Protocol, they are delivered to the defined destinations that were not marked as excluded by filtering logic. The packets then are completed back in the reverse order, as a receive completion first and then a send completion. Extension filter drivers are free to generate new packets on the ingress data path by issuing a send from their filter.
+
+The base library provided, *SxBase.lib*, implements the necessary NDIS functionality common to all types of extension filter drivers. It is not necessary to make any changes to this base library. To implement your own extension filter driver, you only need to define all global variables and implement all functions that are found in *SxApi.h*.
+
+MsPassthroughExt is a basic filtering extension filter driver that is implemented by using SxBase.lib. This demonstrates the bare minimum that must be implemented to use *SxBase.lib*. Installing and enabling MsPassthroughExt on the Hyper-V Extensible Switch does not affect switch behavior.
+
+MsForwardExt is a basic forwarding extension filter driver that is implemented by using *SxBase.lib*. MsForwardExt uses basic MAC forwarding and custom switch policy to allow sends from given MAC addresses. This forwarding sample implements Hybrid Forwarding, which means that the destination table is not populated by this sample if the packet is flagged as a Hyper-V Network Virtualization (HNV) packet. HNV flagged packets' destination tables are computed by the vSwitch HNV policies instead. If this extension filter driver is unconfigured, it will block sends from all VMs, but will maintain connectivity to the host. Each switch policy, which is defined in *MsForwardExtPolicy.mof*, is a MAC address. Applying a switch policy to MsForwardExt allows packets to be sent from the MAC address that is defined in the policy.
+
+
+Installation
+------------
+
+Use the *install.cmd* script provided with each extension filter driver. The *install.cmd* uses **netcfg** to install the extension and **mofcomp** to register any required mof files. The PowerShell cmdlet *Enable-VmSwitchExtension* can then be used to enable the extension filter driver on a Hyper-V Extensible Switch.
+
+For more information on Hyper-V Extensible Switch extensions, see [Hyper-V Extensible Switch](http://msdn.microsoft.com/en-us/library/windows/hardware/hh598161).
+
diff --git a/network/ndis/extension/base/SxApi.h b/network/ndis/extension/base/SxApi.h
new file mode 100644
index 00000000..64dca5f7
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/SxBase.c b/network/ndis/extension/base/SxBase.c
new file mode 100644
index 00000000..b76ef7a4
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/SxBase.h b/network/ndis/extension/base/SxBase.h
new file mode 100644
index 00000000..1e57b0f1
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/SxLibrary.c b/network/ndis/extension/base/SxLibrary.c
new file mode 100644
index 00000000..ea2f53b6
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/SxLibrary.h b/network/ndis/extension/base/SxLibrary.h
new file mode 100644
index 00000000..2d9a30af
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/precomp.h b/network/ndis/extension/base/precomp.h
new file mode 100644
index 00000000..b0bd41c8
--- /dev/null
+++ b/network/ndis/extension/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/network/ndis/extension/base/precompsrc.c b/network/ndis/extension/base/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/extension/base/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/extension/base/sxbase.vcxproj b/network/ndis/extension/base/sxbase.vcxproj
new file mode 100644
index 00000000..4c81ea79
--- /dev/null
+++ b/network/ndis/extension/base/sxbase.vcxproj
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{63FF1428-95CA-4751-A701-244D54A31BD9}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">x64</Platform>
+ <SampleGuid>{8C4C832A-4638-47E9-B2AC-6FA6FC1D958B}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>sxbase</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>sxbase</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630=1;NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SxBase.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SxLibrary.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/base/sxbase.vcxproj.Filters b/network/ndis/extension/base/sxbase.vcxproj.Filters
new file mode 100644
index 00000000..1291527a
--- /dev/null
+++ b/network/ndis/extension/base/sxbase.vcxproj.Filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{74637802-97A6-4EEE-A780-7AFC24D63060}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{7417E375-1992-4C4B-A4AB-C0C8E00F9AAA}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{73A4206C-20D4-4AB0-B133-03D222981702}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{CB4FE68B-83B4-4336-A241-94F6955D198A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SxBase.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SxLibrary.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/extensions.sln b/network/ndis/extension/extensions.sln
new file mode 100644
index 00000000..cc6ab362
--- /dev/null
+++ b/network/ndis/extension/extensions.sln
@@ -0,0 +1,55 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{1C3E1DE9-A703-46CB-B4E4-8CD906C9E6FE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Forward", "Forward", "{433D0832-2B1B-46AB-94E8-0A7979ACA4CA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BC0A3E55-CAE0-4CCE-BA15-0784AEF76215}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Passthrough", "Passthrough", "{7C717732-18C9-4892-A6FF-B4DD1D72C12B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sxbase", "base\sxbase.vcxproj", "{63FF1428-95CA-4751-A701-244D54A31BD9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msforwardext", "samples\forward\msforwardext.vcxproj", "{404E1399-EA48-4CEE-A59E-EA0D4C01928A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {63FF1428-95CA-4751-A701-244D54A31BD9} = {63FF1428-95CA-4751-A701-244D54A31BD9}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mspassthroughext", "samples\passthrough\mspassthroughext.vcxproj", "{2339B4A8-60AF-4172-AC68-3159E6D001EC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {63FF1428-95CA-4751-A701-244D54A31BD9} = {63FF1428-95CA-4751-A701-244D54A31BD9}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {63FF1428-95CA-4751-A701-244D54A31BD9}.Debug|x64.ActiveCfg = Debug|x64
+ {63FF1428-95CA-4751-A701-244D54A31BD9}.Debug|x64.Build.0 = Debug|x64
+ {63FF1428-95CA-4751-A701-244D54A31BD9}.Release|x64.ActiveCfg = Release|x64
+ {63FF1428-95CA-4751-A701-244D54A31BD9}.Release|x64.Build.0 = Release|x64
+ {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Debug|x64.ActiveCfg = Debug|x64
+ {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Debug|x64.Build.0 = Debug|x64
+ {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Release|x64.ActiveCfg = Release|x64
+ {404E1399-EA48-4CEE-A59E-EA0D4C01928A}.Release|x64.Build.0 = Release|x64
+ {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Debug|x64.ActiveCfg = Debug|x64
+ {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Debug|x64.Build.0 = Debug|x64
+ {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Release|x64.ActiveCfg = Release|x64
+ {2339B4A8-60AF-4172-AC68-3159E6D001EC}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {63FF1428-95CA-4751-A701-244D54A31BD9} = {1C3E1DE9-A703-46CB-B4E4-8CD906C9E6FE}
+ {404E1399-EA48-4CEE-A59E-EA0D4C01928A} = {433D0832-2B1B-46AB-94E8-0A7979ACA4CA}
+ {2339B4A8-60AF-4172-AC68-3159E6D001EC} = {7C717732-18C9-4892-A6FF-B4DD1D72C12B}
+ {433D0832-2B1B-46AB-94E8-0A7979ACA4CA} = {BC0A3E55-CAE0-4CCE-BA15-0784AEF76215}
+ {7C717732-18C9-4892-A6FF-B4DD1D72C12B} = {BC0A3E55-CAE0-4CCE-BA15-0784AEF76215}
+ EndGlobalSection
+EndGlobal
diff --git a/network/ndis/extension/samples/forward/MSForwardExtPolicy.mof b/network/ndis/extension/samples/forward/MSForwardExtPolicy.mof
new file mode 100644
index 00000000..88105b2f
--- /dev/null
+++ b/network/ndis/extension/samples/forward/MSForwardExtPolicy.mof
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Microsoft Corporation. All Rights Reserved.
+//
+// Custom property for MsForwardExt
+// MAC Address Allow Policy
+//
+#pragma namespace("\\\\.\\root\\virtualization\\v2")
+
+[ Dynamic,
+ UUID("EB29F0F2-F5DC-45C6-81BB-3CD9F219BBBB"),
+ ExtensionId("37d9eae6-5bae-48c5-bff1-63a7cdd7e4f4"),
+ Provider("VmmsWmiInstanceAndMethodProvider"),
+ Locale(0x409),
+ InterfaceVersion("1"),
+ InterfaceRevision("0"),
+DisplayName("MSForwardExt MAC Address Policy") : Amended,
+Description("Source MAC Addresses to allow sends on MSForwardExt.") : Amended]
+class MSForwardExt_MacAddressRule : Msvm_EthernetSwitchFeatureSettingData {
+
+ //
+ // MAC Address set on switch to allow sends from.
+ //
+ [ Read,
+ Write,
+ WmiDataId(1),
+ Max(6),
+ InterfaceVersion(1),
+ InterfaceRevision(0),
+ Description (
+ "Mac Address") : Amended]
+ uint8 MacAddress[] = {};
+};
diff --git a/network/ndis/extension/samples/forward/MSForwardExtPolicyStatus.mof b/network/ndis/extension/samples/forward/MSForwardExtPolicyStatus.mof
new file mode 100644
index 00000000..c9d509e8
--- /dev/null
+++ b/network/ndis/extension/samples/forward/MSForwardExtPolicyStatus.mof
@@ -0,0 +1,31 @@
+//
+// Copyright (c) Microsoft Corporation. All Rights Reserved.
+//
+// Custom property status for MSForwardExt
+// MAC Address Allow Policy Status
+//
+#pragma namespace("\\\\.\\root\\virtualization\\v2")
+
+[ Dynamic,
+ UUID("A3E2AFF5-E6FA-4E52-AB74-13250BF7E8CF"),
+ ExtensionId("37d9eae6-5bae-48c5-bff1-63a7cdd7e4f4"),
+ Provider("VmmsWmiInstanceAndMethodProvider"),
+ Applicability("2"),
+ Locale(0x409),
+ InterfaceVersion("1"),
+ InterfaceRevision("0"),
+DisplayName("MSForwardExt MAC Address Policy Status") : Amended,
+Description("The current array of PortIds with policy set to allow sends") : Amended]
+class MSForwardExt_MacAddressRuleStatus : Msvm_EthernetSwitchData {
+
+ //
+ // Array of PortId's currently allowing sends.
+ //
+ [ Read,
+ WmiDataId(1),
+ InterfaceVersion(1),
+ InterfaceRevision(0),
+ Description (
+ "Currently Allowed Port Ids") : Amended]
+ uint32 AllowedPortIds[] = {};
+};
diff --git a/network/ndis/extension/samples/forward/MsForwardExt.c b/network/ndis/extension/samples/forward/MsForwardExt.c
new file mode 100644
index 00000000..147a3694
--- /dev/null
+++ b/network/ndis/extension/samples/forward/MsForwardExt.c
@@ -0,0 +1,2584 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+ MsForwardExt.c
+
+Abstract:
+
+ This file contains the implementation of a forwarding extension
+ (MSForardExt) using the SxBase library.
+ The forwarding extension does basic MAC forwarding, blocking and allowing
+ source MAC addresses based on custom set policy.
+
+
+--*/
+
+#include "precomp.h"
+#include "MsForwardExt.h"
+
+UCHAR SxExtMajorNdisVersion = NDIS_FILTER_MAJOR_VERSION;
+UCHAR SxExtMinorNdisVersion = NDIS_FILTER_MINOR_VERSION;
+PWCHAR SxExtFriendlyName = L"Microsoft Sample Forwarding Extension";
+PWCHAR SxExtUniqueName = L"{37d9eae6-5bae-48c5-bff1-63a7cdd7e4f4}";
+PWCHAR SxExtServiceName = L"MSForwardExt";
+ULONG SxExtAllocationTag = 'wSxS';
+ULONG SxExtOidRequestId = 'wSxS';
+
+// {37d9eae6-5bae-48c5-bff1-63a7cdd7e4f4}
+const GUID MsForwardExtGuid = {
+ 0x37d9eae6,
+ 0x5bae,
+ 0x48c5,
+ {0xbf, 0xf1, 0x63, 0xa7, 0xcd, 0xd7, 0xe4, 0xf4}
+ };
+
+// {EB29F0F2-F5DC-45C6-81BB-3CD9F219BBBB}
+const NDIS_SWITCH_OBJECT_ID MacAddressPolicyGuid = {
+ 0xEB29F0F2,
+ 0xF5DC,
+ 0x45C6,
+ {0x81, 0xBB, 0x3C, 0xD9, 0xF2, 0x19, 0xBB, 0xBB}
+ };
+
+// {A3E2AFF5-E6FA-4E52-AB74-13250BF7E8CF}
+const NDIS_SWITCH_OBJECT_ID MacAddressPolicyStatusGuid = {
+ 0xA3E2AFF5,
+ 0xE6FA,
+ 0x4E52,
+ {0xAB, 0x74, 0x13, 0x25, 0x0B, 0xF7, 0xE8, 0xCF}
+ };
+
+
+NDIS_STATUS
+SxExtInitialize()
+/*++
+
+Routine Description:
+ No global information needed.
+
+--*/
+{
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+SxExtUninitialize()
+/*++
+
+Routine Description:
+ No global information needed.
+
+--*/
+{
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreateSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ PNDIS_HANDLE *ExtensionContext
+ )
+/*++
+
+Routine Description:
+ This function allocated the switch context, and initializes
+ its necessary members.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PMSFORWARD_CONTEXT switchContext;
+
+ switchContext = ExAllocatePoolWithTag(NonPagedPoolNx,
+ sizeof(MSFORWARD_CONTEXT),
+ SxExtAllocationTag);
+
+ if (switchContext == NULL)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ NdisZeroMemory(switchContext, sizeof(MSFORWARD_CONTEXT));
+ InitializeListHead(&switchContext->NicList);
+ InitializeListHead(&switchContext->PropertyList);
+
+ switchContext->DispatchLock = NdisAllocateRWLock(Switch->NdisFilterHandle);
+ if (switchContext->DispatchLock == NULL)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ switchContext->IsInitialRestart = TRUE;
+
+ *ExtensionContext = (NDIS_HANDLE)switchContext;
+
+Cleanup:
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ if (switchContext != NULL)
+ {
+ ExFreePoolWithTag(switchContext, SxExtAllocationTag);
+ }
+ }
+
+ return status;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeleteSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+/*++
+
+Routine Description:
+ This function deletes the switch by freeing all memory
+ previously allocated.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ MsForwardClearNicListUnsafe(switchContext);
+ MsForwardClearPropertyListUnsafe(switchContext);
+ NdisFreeRWLock(switchContext->DispatchLock);
+ ExFreePoolWithTag(ExtensionContext, SxExtAllocationTag);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtActivateSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ MsForwardInitSwitch(Switch, switchContext);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtRestartSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+/*++
+
+Routine Description:
+ This function initializes the switch if it is the first restart.
+ First it queries all of the MAC addresses set as custom
+ switch policy to allow sends from, and adds tme to the property
+ list.
+ Then it queries the NIC list and verifies it can support
+ all of the NICs currently connected to the switch, and
+ adds the NICs to the NIC list.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ NDIS_SWITCH_PARAMETERS switchParameters;
+
+ if (switchContext->IsInitialRestart)
+ {
+ status = SxLibGetSwitchParametersUnsafe(Switch, &switchParameters);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ if (switchParameters.IsActive)
+ {
+ status = MsForwardInitSwitch(Switch, switchContext);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto Cleanup;
+ }
+ }
+
+ switchContext->IsInitialRestart = FALSE;
+ }
+
+Cleanup:
+ return status;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtPauseSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+/*++
+
+Routine Description:
+ No pause funtionality required.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreatePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+/*++
+
+Routine Description:
+ This extension does not track ports, only NICs.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtUpdatePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+/*++
+
+Routine Description:
+ This extension does not track ports, only NICs.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreateNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+/*++
+
+Routine Description:
+ Allocate NIC, add to NIC list, and correlate with policy.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+
+ status = MsForwardAddNicUnsafe(switchContext,
+ Nic->PermanentMacAddress,
+ Nic->PortId,
+ Nic->NicIndex,
+ Nic->NicType,
+ FALSE);
+
+
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+
+ return status;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtConnectNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+/*++
+
+Routine Description:
+ Mark already created NIC as connected.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ PMSFORWARD_NIC_LIST_ENTRY nicEntry = NULL;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+ if (Nic->NicType == NdisSwitchNicTypeExternal &&
+ Nic->NicIndex != 0 &&
+ switchContext->ExternalPortId == 0)
+ {
+ switchContext->ExternalPortId = Nic->PortId;
+ switchContext->ExternalNicIndex = Nic->NicIndex;
+ switchContext->ExternalNicConnected = TRUE;
+ ++(switchContext->NumDestinations);
+ }
+ else if (Nic->NicType != NdisSwitchNicTypeExternal)
+ {
+ nicEntry = MsForwardFindNicByPortIdUnsafe(switchContext,
+ Nic->PortId,
+ Nic->NicIndex);
+
+ if(nicEntry != NULL)
+ {
+ nicEntry->Connected = TRUE;
+ ++(switchContext->NumDestinations);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+ }
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtUpdateNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+/*++
+
+Routine Description:
+ This extension doesn't use any of the fields that can be updated.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDisconnectNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+/*++
+
+Routine Description:
+ Mark already created NIC as disconnected.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ PMSFORWARD_NIC_LIST_ENTRY nicEntry = NULL;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+ if (Nic->NicType == NdisSwitchNicTypeExternal)
+ {
+ if (Nic->NicIndex == switchContext->ExternalNicIndex)
+ {
+ --(switchContext->NumDestinations);
+ switchContext->ExternalNicConnected = FALSE;
+ }
+ }
+ else
+ {
+ nicEntry = MsForwardFindNicByPortIdUnsafe(switchContext,
+ Nic->PortId,
+ Nic->NicIndex);
+
+ if(nicEntry != NULL)
+ {
+ nicEntry->Connected = FALSE;
+ --(switchContext->NumDestinations);
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+ }
+
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeleteNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+/*++
+
+Routine Description:
+ Delete created NIC, free related memory and remove
+ from NIC list.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+ if (Nic->NicType == NdisSwitchNicTypeExternal &&
+ Nic->NicIndex == switchContext->ExternalNicIndex)
+ {
+ ASSERT(switchContext->ExternalNicConnected == FALSE);
+ switchContext->ExternalPortId = 0;
+ switchContext->ExternalNicIndex = 0;
+ }
+ else if (Nic->NicType != NdisSwitchNicTypeExternal)
+ {
+ MsForwardDeleteNicUnsafe(switchContext,
+ Nic->PortId,
+ Nic->NicIndex);
+ }
+
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtTeardownPort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+/*++
+
+Routine Description:
+ This extension does not track port state.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeletePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+/*++
+
+Routine Description:
+ This extension does not track port state.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtSaveNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+ This extension does not save any data.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtSaveNicComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+ )
+/*++
+
+Routine Description:
+ This extension does not save any data.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtNicRestore(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+ PULONG BytesRestored
+ )
+/*++
+
+Routine Description:
+ This extension does not save any data.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ *BytesRestored = 0;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtNicRestoreComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+ )
+/*++
+
+Routine Description:
+ This extension does not save any data.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtAddSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+ )
+/*++
+
+Routine Description:
+ This extension enforces one custom switch policy.
+ The function verifies the switch property is our MAC policy
+ and then adds it to the property list.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
+ PNDIS_SWITCH_PROPERTY_CUSTOM customPolicy;
+ PMSFORWARD_MAC_ADDRESS_POLICY macPolicy;
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ if (SwitchProperty->PropertyType != NdisSwitchPropertyTypeCustom)
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Check if MAC Address Policy for this extension.
+ //
+ if (!RtlEqualMemory(&SwitchProperty->PropertyId,
+ &MacAddressPolicyGuid,
+ sizeof(NDIS_SWITCH_OBJECT_ID)))
+ {
+ goto Cleanup;
+ }
+
+ if (SwitchProperty->PropertyVersion != MAC_ADDRESS_POLICY_VERSION)
+ {
+ goto Cleanup;
+ }
+
+ if (SwitchProperty->SerializationVersion != MAC_ADDRESS_POLICY_SERIALIZATION_VERSION)
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ customPolicy = NDIS_SWITCH_PROPERTY_PARAMETERS_GET_PROPERTY(SwitchProperty);
+ macPolicy = NDIS_SWITCH_PROPERTY_CUSTOM_GET_BUFFER(customPolicy);
+
+ if (macPolicy->MacAddressLength != 6)
+ {
+ status = NDIS_STATUS_DATA_NOT_ACCEPTED;
+ }
+ else
+ {
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+
+ status = MsForwardAddMacPolicyUnsafe(switchContext,
+ macPolicy,
+ &SwitchProperty->PropertyInstanceId);
+
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+ }
+
+Cleanup:
+ return status;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtUpdateSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+ )
+/*++
+
+Routine Description:
+ This extension enforces one custom switch policy, but
+ does not allow updates for that policy.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
+
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ if (SwitchProperty->PropertyType != NdisSwitchPropertyTypeCustom)
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Check if MAC Address Policy for this extension.
+ //
+ if (!RtlEqualMemory(&SwitchProperty->PropertyId,
+ &MacAddressPolicyGuid,
+ sizeof(NDIS_SWITCH_OBJECT_ID)))
+ {
+ goto Cleanup;
+ }
+
+ if (SwitchProperty->PropertyVersion != MAC_ADDRESS_POLICY_VERSION)
+ {
+ goto Cleanup;
+ }
+
+ if (SwitchProperty->SerializationVersion != MAC_ADDRESS_POLICY_SERIALIZATION_VERSION)
+ {
+ goto Cleanup;
+ }
+
+ status = NDIS_STATUS_DATA_NOT_ACCEPTED;
+
+Cleanup:
+ return status;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtDeleteSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_DELETE_PARAMETERS SwitchProperty
+ )
+/*++
+
+Routine Description:
+ This extension enforces one custom switch policy.
+ The function verifies the switch property is our MAC policy
+ and then deletes it from the property list.
+
+--*/
+{
+ BOOLEAN delete = FALSE;
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ LOCK_STATE_EX lockState;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ if (SwitchProperty->PropertyType != NdisSwitchPropertyTypeCustom)
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Check if MAC Address Policy for this extension.
+ //
+ if (!RtlEqualMemory(&SwitchProperty->PropertyId,
+ &MacAddressPolicyGuid,
+ sizeof(NDIS_SWITCH_OBJECT_ID)))
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+
+ delete = TRUE;
+
+ NdisAcquireRWLockWrite(switchContext->DispatchLock, &lockState, 0);
+
+ MsForwardDeleteMacPolicyUnsafe(switchContext,
+ &SwitchProperty->PropertyInstanceId);
+
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+
+Cleanup:
+ return delete;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtAddPortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+ )
+/*++
+
+Routine Description:
+ This extension does not enforce VLAN. Because of this
+ the extension fails the adding of these policies.
+
+ !! REAL FORWARDING EXTENSIONS SHOULD SUPPORT THESE PROPERTIES !!
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
+
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ switch(PortProperty->PropertyType)
+ {
+ case NdisSwitchPortPropertyTypeCustom:
+ //
+ // No Custom Port Properties.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeSecurity:
+ //
+ // This extension does need to look at security policy, pass it down.
+ // An extension must always pass through Hyper-V security policy.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeVlan:
+ //
+ // Forwarding extensions must either enforce VLAN, or fail
+ // setting VLAN policy.
+ // This extension does not enforce VLAN.
+ //
+ status = NDIS_STATUS_DATA_NOT_ACCEPTED;
+ break;
+
+ case NdisSwitchPortPropertyTypeProfile:
+ //
+ // No Processing of Port Profile.
+ //
+ break;
+ }
+
+ return status;
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtUpdatePortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+ )
+/*++
+
+Routine Description:
+ This extension does not enforce VLAN. Because of this
+ the extension fails the updating of these policies.
+
+ !! REAL FORWARDING EXTENSIONS SHOULD SUPPORT THESE PROPERTIES !!
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_NOT_SUPPORTED;
+
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ switch(PortProperty->PropertyType)
+ {
+ case NdisSwitchPortPropertyTypeCustom:
+ //
+ // No Custom Port Properties.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeSecurity:
+ //
+ // This extension does need to look at security policy, pass it down.
+ // An extension must always pass through Hyper-V security policy.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeVlan:
+ //
+ // Forwarding extensions must either enforce VLAN, or fail
+ // setting VLAN policy.
+ // This extension does not enforce VLAN.
+ //
+ status = NDIS_STATUS_DATA_NOT_ACCEPTED;
+ break;
+
+ case NdisSwitchPortPropertyTypeProfile:
+ //
+ // No Processing of Port Profile.
+ //
+ break;
+ }
+
+ return status;
+}
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtDeletePortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS PortProperty
+ )
+/*++
+
+Routine Description:
+ This extension does not enforce VLAN.
+ These policies are policies that should be supported by this
+ extension, so it returns TRUE to complete the deletion.
+
+ !! REAL FORWARDING EXTENSIONS SHOULD SUPPORT THESE PROPERTIES !!
+
+--*/
+{
+ BOOLEAN delete = FALSE;
+
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ switch(PortProperty->PropertyType)
+ {
+ case NdisSwitchPortPropertyTypeCustom:
+ //
+ // No Custom Port Properties.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeSecurity:
+ //
+ // This extension does need to look at security policy, pass it down.
+ // An extension must always pass through Hyper-V security policy.
+ //
+ break;
+
+ case NdisSwitchPortPropertyTypeVlan:
+ //
+ // Forwarding extensions must either enforce VLAN, or fail
+ // setting VLAN policy.
+ // This extension does not enforce VLAN.
+ //
+ delete = TRUE;
+ break;
+
+ case NdisSwitchPortPropertyTypeProfile:
+ //
+ // No Processing of Port Profile.
+ //
+ break;
+ }
+
+ return delete;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtQuerySwitchFeatureStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_FEATURE_STATUS_PARAMETERS SwitchFeatureStatus,
+ PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+ This extension reports the status of its custom MAC policy
+ by returning the list of PortId's currently allowing sends.
+
+--*/
+{
+ BOOLEAN consumed = FALSE;
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ LOCK_STATE_EX lockState;
+ BOOLEAN lockHeld = FALSE;
+ ULONG sizeNeeded = 0;
+ ULONG numAllowedSourcePorts = 0;
+ PLIST_ENTRY nicList = &switchContext->NicList;
+ PLIST_ENTRY curEntry = NULL;
+ PMSFORWARD_NIC_LIST_ENTRY nic = NULL;
+ PNDIS_SWITCH_FEATURE_STATUS_CUSTOM customStatusBuffer;
+ PMSFORWARD_MAC_ADDRESS_POLICY_STATUS macAddressPolicyBuffer;
+ PNDIS_SWITCH_PORT_ID portIdArray;
+ ULONG arrayIndex = 0;
+ ULONG customBufferLength = 0;
+
+ UNREFERENCED_PARAMETER(Switch);
+
+ if (SwitchFeatureStatus->FeatureStatusType != NdisSwitchFeatureStatusTypeCustom)
+ {
+ goto Cleanup;
+ }
+
+ if (!RtlEqualMemory(&SwitchFeatureStatus->FeatureStatusId,
+ &MacAddressPolicyStatusGuid,
+ sizeof(NDIS_SWITCH_OBJECT_ID)))
+ {
+ goto Cleanup;
+ }
+
+ if (SwitchFeatureStatus->SerializationVersion != MAC_ADDRESS_POLICY_STATUS_SERIALIZATION_VERSION)
+ {
+ goto Cleanup;
+ }
+
+ //
+ // Wait for lists to be initialized.
+ //
+ while (switchContext->IsInitialRestart)
+ {
+ NdisMSleep(100);
+ }
+
+ NdisAcquireRWLockRead(switchContext->DispatchLock, &lockState, 0);
+ lockHeld = TRUE;
+
+ if (switchContext->ExternalPortId != NDIS_SWITCH_DEFAULT_PORT_ID)
+ {
+ ++numAllowedSourcePorts;
+ }
+
+ if (!IsListEmpty(nicList))
+ {
+ curEntry = nicList->Flink;
+
+ do {
+ nic = CONTAINING_RECORD(curEntry,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ if (nic->AllowSends)
+ {
+ ++numAllowedSourcePorts;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != nicList);
+ }
+
+ customBufferLength = sizeof(MSFORWARD_MAC_ADDRESS_POLICY_STATUS) +
+ (sizeof(NDIS_SWITCH_PORT_ID) * numAllowedSourcePorts);
+ sizeNeeded = NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_PARAMETERS_REVISION_1 +
+ NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_CUSTOM_REVISION_1 +
+ customBufferLength;
+
+ consumed = TRUE;
+
+ if (SwitchFeatureStatus->FeatureStatusBufferLength < sizeof(NDIS_SWITCH_FEATURE_STATUS_CUSTOM))
+ {
+ *BytesNeeded = sizeNeeded;
+ goto Cleanup;
+ }
+
+ customStatusBuffer = (PNDIS_SWITCH_FEATURE_STATUS_CUSTOM)
+ (((PUINT8)SwitchFeatureStatus) +
+ SwitchFeatureStatus->FeatureStatusBufferOffset);
+
+ if (customStatusBuffer->Header.Type != NDIS_OBJECT_TYPE_DEFAULT ||
+ customStatusBuffer->Header.Revision != NDIS_SWITCH_FEATURE_STATUS_CUSTOM_REVISION_1 ||
+ customStatusBuffer->Header.Size != NDIS_SIZEOF_NDIS_SWITCH_FEATURE_STATUS_CUSTOM_REVISION_1)
+ {
+ consumed = FALSE;
+ goto Cleanup;
+ }
+
+
+
+ if (customStatusBuffer->FeatureStatusCustomBufferLength < customBufferLength)
+ {
+ *BytesNeeded = sizeNeeded;
+ goto Cleanup;
+ }
+
+ macAddressPolicyBuffer = (PMSFORWARD_MAC_ADDRESS_POLICY_STATUS)
+ (((PUINT8)customStatusBuffer) +
+ customStatusBuffer->FeatureStatusCustomBufferOffset);
+
+ macAddressPolicyBuffer->PortArrayLength = numAllowedSourcePorts;
+ macAddressPolicyBuffer->PortArrayOffset = sizeof(MSFORWARD_MAC_ADDRESS_POLICY_STATUS);
+
+ portIdArray = (PNDIS_SWITCH_PORT_ID)
+ (((PUINT8)macAddressPolicyBuffer) +
+ macAddressPolicyBuffer->PortArrayOffset);
+
+
+ if (switchContext->ExternalPortId != NDIS_SWITCH_DEFAULT_PORT_ID)
+ {
+ portIdArray[arrayIndex] = switchContext->ExternalPortId;
+ ++arrayIndex;
+ }
+
+ if (!IsListEmpty(nicList))
+ {
+ curEntry = nicList->Flink;
+
+ do {
+ nic = CONTAINING_RECORD(curEntry,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ if (nic->AllowSends)
+ {
+ portIdArray[arrayIndex] = nic->PortId;
+ ++arrayIndex;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != nicList);
+ }
+
+ SwitchFeatureStatus->FeatureStatusVersion = MAC_ADDRESS_POLICY_STATUS_VERSION;
+
+Cleanup:
+ if (lockHeld)
+ {
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+ }
+
+ return consumed;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtQueryPortFeatureStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_FEATURE_STATUS_PARAMETERS PortFeatureStatus,
+ PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+ This extension has no custom port properties.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(PortFeatureStatus);
+ UNREFERENCED_PARAMETER(BytesNeeded);
+
+ return FALSE;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicRequest(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_OID_REQUEST OidRequest,
+ PNDIS_SWITCH_PORT_ID SourcePortId,
+ PNDIS_SWITCH_NIC_INDEX SourceNicIndex,
+ PNDIS_SWITCH_PORT_ID DestinationPortId,
+ PNDIS_SWITCH_NIC_INDEX DestinationNicIndex
+ )
+/*++
+
+Routine Description:
+ The only NIC request this extension cares about is
+ OID_NIC_SWITCH_ALLOCATE_VF. We must fail all VF allocations
+ so that traffic flows through the extension and we can enforce
+ policy.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+ UNREFERENCED_PARAMETER(DestinationPortId);
+ UNREFERENCED_PARAMETER(DestinationNicIndex);
+
+ //
+ // Do not allow VF allocations, as all VM traffic must flow
+ // through our extension.
+ //
+ if (OidRequest->RequestType == NdisRequestSetInformation &&
+ OidRequest->DATA.SET_INFORMATION.Oid == OID_NIC_SWITCH_ALLOCATE_VF)
+ {
+ status = NDIS_STATUS_FAILURE;
+ }
+
+ return status;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicRequestComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_OID_REQUEST OidRequest,
+ NDIS_SWITCH_PORT_ID SourcePortId,
+ NDIS_SWITCH_NIC_INDEX SourceNicIndex,
+ NDIS_SWITCH_PORT_ID DestinationPortId,
+ NDIS_SWITCH_NIC_INDEX DestinationNicIndex,
+ NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+ This function will never be called because we do not
+ redirect or edit any NIC requests.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(OidRequest);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+ UNREFERENCED_PARAMETER(DestinationPortId);
+ UNREFERENCED_PARAMETER(DestinationNicIndex);
+ UNREFERENCED_PARAMETER(Status);
+
+ //
+ // This function should never be called as we don't set any
+ // source/destination info in SxExtProcessNicRequest.
+ //
+ ASSERT(FALSE);
+
+ return Status;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_STATUS_INDICATION StatusIndication,
+ NDIS_SWITCH_PORT_ID SourcePortId,
+ NDIS_SWITCH_NIC_INDEX SourceNicIndex
+ )
+/*++
+
+Routine Description:
+ This extension does not need to process any status
+ indications.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(StatusIndication);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartNetBufferListsIngress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+ The function sets the destination lists of the NBLs forwarded
+ through the switch.
+ The extension only set destinations for NBLs originated from the External NIC,
+ Internal NIC, or NICs with MAC Policy set.
+ The extension determines the source by searching for the source
+ MAC address in the NIC list.
+
+ The extension sets destinations by looking at the destination MAC address.
+ If the destination MAC address is a multicast or broadcast address,
+ the extension broadcasts the NBL to all ports, except the source.
+ If the destination MAC is a VM, the extension sets the VM as the destitation.
+ Otherwise the extension sets the External port as the destination.
+
+--*/
+{
+ PMSFORWARD_CONTEXT switchContext = (PMSFORWARD_CONTEXT)ExtensionContext;
+ NDIS_SWITCH_PORT_ID sourcePort = 0, prevDestinationPort = 0, curDestinationPort = 0;
+ NDIS_SWITCH_NIC_INDEX sourceIndex = 0, prevDestinationIndex = 0, curDestinationIndex = 0;
+ PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
+ PMSFORWARD_NIC_LIST_ENTRY sourceNicEntry = NULL;
+ PMSFORWARD_NIC_LIST_ENTRY destinationNicEntry = NULL;
+ BOOLEAN sameSource;
+ PNET_BUFFER_LIST curNbl = NULL, nextNbl = NULL;
+ PNET_BUFFER_LIST sendNbl = NULL, dropNbl = NULL;
+ PNET_BUFFER_LIST *nextDropNbl = &dropNbl;
+ PNET_BUFFER_LIST *nextSendNbl = &sendNbl;
+ PMSFORWARD_ETHERNET_HEADER curHeader;
+ UINT8 prevMacAddress[6] = {0};
+ ULONG sendCompleteFlags = 0;
+ BOOLEAN dispatch;
+ PMDL curMdl;
+ PUINT8 curBuffer;
+ BOOLEAN broadcast = FALSE;
+ NDIS_SWITCH_PORT_DESTINATION newDestination = {0};
+ PNDIS_SWITCH_FORWARDING_DESTINATION_ARRAY broadcastArray;
+ LOCK_STATE_EX lockState;
+ NDIS_STATUS status;
+ NDIS_STRING filterReason;
+ ULONG numDropNbls;
+ PNET_BUFFER_LIST extForwardedNbls = NULL;
+ PNET_BUFFER_LIST nativeForwardedNbls = NULL;
+ PNET_BUFFER_LIST *nextExtForwardNbl = &extForwardedNbls;
+ PNET_BUFFER_LIST *nextNativeForwardedNbl = &nativeForwardedNbls;
+
+ dispatch = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_DISPATCH_LEVEL);
+ sameSource = NDIS_TEST_SEND_FLAG(SendFlags, NDIS_SEND_FLAGS_SWITCH_SINGLE_SOURCE);
+
+ sendCompleteFlags |= (dispatch) ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0;
+ SendFlags |= NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP;
+
+ //
+ // Take DispatchLock so no NICs disconnect while we're setting destinations.
+ //
+ NdisAcquireRWLockRead(switchContext->DispatchLock, &lockState, dispatch);
+ if (sameSource)
+ {
+ fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(NetBufferLists);
+ sourcePort = fwdDetail->SourcePortId;
+ sourceIndex = (NDIS_SWITCH_NIC_INDEX)fwdDetail->SourceNicIndex;
+
+ sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE;
+
+ sourceNicEntry = MsForwardFindNicByPortIdUnsafe(switchContext,
+ sourcePort,
+ sourceIndex);
+
+ if (sourceNicEntry != NULL && !sourceNicEntry->AllowSends)
+ {
+ numDropNbls = 0;
+ for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next)
+ {
+ ++numDropNbls;
+ }
+
+ *nextDropNbl = NetBufferLists;
+
+ RtlInitUnicodeString(&filterReason, L"Blocked by Source MAC Policy");
+
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ numDropNbls,
+ dropNbl,
+ &filterReason);
+
+ goto Cleanup;
+ }
+
+ //
+ // If nicEntry is not found, and is not external port,
+ // we must have failed to allocate this port.
+ //
+ else if(sourceNicEntry == NULL &&
+ sourcePort != switchContext->ExternalPortId)
+ {
+ numDropNbls = 0;
+ for (curNbl = NetBufferLists; curNbl != NULL; curNbl = curNbl->Next)
+ {
+ ++numDropNbls;
+ }
+
+ *nextDropNbl = NetBufferLists;
+
+ RtlInitUnicodeString(&filterReason, L"Low Resources");
+
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ numDropNbls,
+ dropNbl,
+ &filterReason);
+
+ goto Cleanup;
+ }
+ }
+
+ //
+ // Split NBL list into NBLs to be forwarded by us, and those that require
+ // native forwarding.
+ //
+ for (curNbl = NetBufferLists; curNbl != NULL; curNbl = nextNbl)
+ {
+ nextNbl = curNbl->Next;
+ curNbl->Next = NULL;
+ fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
+ if (fwdDetail->NativeForwardingRequired)
+ {
+ *nextNativeForwardedNbl = curNbl;
+ nextNativeForwardedNbl = &(curNbl->Next);
+ }
+ else
+ {
+ *nextExtForwardNbl = curNbl;
+ nextExtForwardNbl = &(curNbl->Next);
+ }
+ }
+
+ for (curNbl = extForwardedNbls; curNbl != NULL; curNbl = nextNbl)
+ {
+ nextNbl = curNbl->Next;
+ curNbl->Next = NULL;
+
+ fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
+
+ //
+ // First check for allowed source if not same source.
+ //
+ if (!sameSource)
+ {
+ sourcePort = fwdDetail->SourcePortId;
+ sourceIndex = (NDIS_SWITCH_NIC_INDEX)fwdDetail->SourceNicIndex;
+
+ sourceNicEntry = MsForwardFindNicByPortIdUnsafe(switchContext,
+ sourcePort,
+ sourceIndex);
+
+ if (sourceNicEntry != NULL && !sourceNicEntry->AllowSends)
+ {
+ RtlInitUnicodeString(&filterReason, L"Blocked by Source MAC Policy");
+
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+ else if(sourceNicEntry == NULL &&
+ sourcePort != switchContext->ExternalPortId)
+ {
+ RtlInitUnicodeString(&filterReason, L"Low Resources");
+
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+ }
+
+ //
+ // Ethernet Header is a guaranteed safe access.
+ //
+ curMdl = (NET_BUFFER_LIST_FIRST_NB(curNbl))->CurrentMdl;
+ curBuffer = MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
+ curHeader = (PMSFORWARD_ETHERNET_HEADER)
+ (curBuffer + (NET_BUFFER_LIST_FIRST_NB(curNbl))->CurrentMdlOffset);
+
+ //
+ // Check for broadcast. (Broadcast if multicast)
+ //
+ if (ETH_IS_BROADCAST(curHeader->Destination) ||
+ ETH_IS_MULTICAST(curHeader->Destination))
+ {
+ if(sendNbl != NULL && !broadcast)
+ {
+ //
+ // Send first nbl list, set destinations of this one, continue to work on next.
+ //
+ SxLibSendNetBufferListsIngress(Switch,
+ sendNbl,
+ SendFlags,
+ 0);
+
+ sendNbl = NULL;
+ nextSendNbl = &sendNbl;
+ }
+
+ if (fwdDetail->NumAvailableDestinations < (switchContext->NumDestinations - 1))
+ {
+ status = Switch->NdisSwitchHandlers.GrowNetBufferListDestinations(
+ Switch->NdisSwitchContext,
+ curNbl,
+ (switchContext->NumDestinations - 1 - fwdDetail->NumAvailableDestinations),
+ &broadcastArray);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ RtlInitUnicodeString(&filterReason, L"Failed to grow destination list.");
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+ }
+ else
+ {
+ Switch->NdisSwitchHandlers.GetNetBufferListDestinations(
+ Switch->NdisSwitchContext,
+ curNbl,
+ &broadcastArray);
+ }
+
+ MsForwardMakeBroadcastArrayUnsafe(switchContext,
+ broadcastArray,
+ sourcePort,
+ sourceIndex);
+
+ if (switchContext->NumDestinations == 1)
+ {
+ RtlInitUnicodeString(&filterReason, L"Zero destinations for broadcast.");
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+
+ status = Switch->NdisSwitchHandlers.UpdateNetBufferListDestinations(
+ Switch->NdisSwitchContext,
+ curNbl,
+ (switchContext->NumDestinations - 1),
+ broadcastArray);
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+
+ *nextSendNbl = curNbl;
+ nextSendNbl = &(curNbl->Next);
+ broadcast = TRUE;
+
+ continue;
+ }
+
+
+ if (RtlEqualMemory(prevMacAddress,
+ curHeader->Destination,
+ sizeof(prevMacAddress)))
+ {
+ curDestinationPort = prevDestinationPort;
+ curDestinationIndex = prevDestinationIndex;
+ }
+ else
+ {
+ destinationNicEntry = MsForwardFindNicByMacAddressUnsafe(switchContext,
+ curHeader->Destination);
+ //
+ // Not a VM or host, send to external.
+ //
+ if (destinationNicEntry == NULL)
+ {
+ //
+ // If no external, or source is external, drop.
+ //
+ if (switchContext->ExternalPortId == 0)
+ {
+ RtlInitUnicodeString(&filterReason, L"No external NIC");
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+
+ if (sourcePort == switchContext->ExternalPortId)
+ {
+ RtlInitUnicodeString(&filterReason, L"Destination == Source");
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+
+ curDestinationPort = switchContext->ExternalPortId;
+ curDestinationIndex = switchContext->ExternalNicIndex;
+ }
+ else if (destinationNicEntry->Connected)
+ {
+ curDestinationPort = destinationNicEntry->PortId;
+ curDestinationIndex = destinationNicEntry->NicIndex;
+ }
+ else
+ {
+ RtlInitUnicodeString(&filterReason, L"Destination is NOT connected.");
+ Switch->NdisSwitchHandlers.ReportFilteredNetBufferLists(
+ Switch->NdisSwitchContext,
+ &SxExtensionGuid,
+ &SxExtensionFriendlyName,
+ sourcePort,
+ NDIS_SWITCH_REPORT_FILTERED_NBL_FLAGS_IS_INCOMING,
+ 1,
+ curNbl,
+ &filterReason);
+
+ *nextDropNbl = curNbl;
+ nextDropNbl = &curNbl->Next;
+ continue;
+ }
+ }
+
+ RtlMoveMemory(prevMacAddress, curHeader->Destination, sizeof(prevMacAddress));
+
+ newDestination.PortId = curDestinationPort;
+ newDestination.NicIndex = curDestinationIndex;
+ newDestination.PreserveVLAN = 0;
+
+ ASSERT(fwdDetail->NumAvailableDestinations > 0);
+ status = Switch->NdisSwitchHandlers.AddNetBufferListDestination(
+ Switch->NdisSwitchContext,
+ curNbl,
+ &newDestination);
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+
+ if(sendNbl != NULL &&
+ (broadcast ||
+ (prevDestinationPort != curDestinationPort ||
+ prevDestinationIndex != curDestinationIndex)))
+ {
+ SxLibSendNetBufferListsIngress(Switch,
+ sendNbl,
+ SendFlags,
+ 0);
+
+ sendNbl = NULL;
+ nextSendNbl = &sendNbl;
+ }
+
+ *nextSendNbl = curNbl;
+ nextSendNbl = &(curNbl->Next);
+
+ //
+ // Done processing this NBL.
+ //
+ prevDestinationPort = curDestinationPort;
+ prevDestinationIndex = curDestinationIndex;
+ broadcast = FALSE;
+ }
+
+Cleanup:
+ NdisReleaseRWLock(switchContext->DispatchLock, &lockState);
+
+ if (sendNbl != NULL)
+ {
+ SxLibSendNetBufferListsIngress(Switch,
+ sendNbl,
+ SendFlags,
+ 0);
+ }
+
+ if (nativeForwardedNbls != NULL)
+ {
+ SxLibSendNetBufferListsIngress(Switch,
+ nativeForwardedNbls,
+ SendFlags,
+ 0);
+ }
+
+ if (dropNbl != NULL)
+ {
+ SxLibCompleteNetBufferListsIngress(Switch,
+ dropNbl,
+ sendCompleteFlags);
+ }
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartNetBufferListsEgress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG NumberOfNetBufferLists,
+ ULONG ReceiveFlags
+ )
+/*++
+
+Routine Description:
+ No egress processing necessary.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibSendNetBufferListsEgress(Switch,
+ NetBufferLists,
+ NumberOfNetBufferLists,
+ ReceiveFlags);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartCompleteNetBufferListsEgress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG ReturnFlags
+ )
+/*++
+
+Routine Description:
+ No egress processing necessary.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibCompleteNetBufferListsEgress(Switch,
+ NetBufferLists,
+ ReturnFlags);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartCompleteNetBufferListsIngress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendCompleteFlags
+ )
+/*++
+
+Routine Description:
+ No ingress complete processing necessary.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibCompleteNetBufferListsIngress(Switch,
+ NetBufferLists,
+ SendCompleteFlags);
+}
+
+
+NDIS_STATUS
+MsForwardAddNicUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex,
+ _In_ NDIS_SWITCH_NIC_TYPE NicType,
+ _In_ BOOLEAN Connected
+ )
+/*++
+
+Routine Description:
+ Add given NIC to the NIC list and correlate with
+ MAC policy.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PMSFORWARD_NIC_LIST_ENTRY nicEntry = NULL;
+ PLIST_ENTRY nicList = &SwitchContext->NicList;
+
+ if (NicType == NdisSwitchNicTypeExternal)
+ {
+ goto Cleanup;
+ }
+
+ nicEntry = MsForwardFindNicByPortIdUnsafe(SwitchContext,
+ PortId,
+ NicIndex);
+
+ if (nicEntry == NULL)
+ {
+ nicEntry = ExAllocatePoolWithTag(NonPagedPoolNx,
+ sizeof(MSFORWARD_NIC_LIST_ENTRY),
+ SxExtAllocationTag);
+
+ if (nicEntry == NULL)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ NdisZeroMemory(nicEntry, sizeof(MSFORWARD_NIC_LIST_ENTRY));
+ NdisMoveMemory(nicEntry->MacAddress, MacAddress, MSFORWARD_MAC_LENGTH);
+
+ nicEntry->PortId = PortId;
+ nicEntry->NicIndex = NicIndex;
+ nicEntry->NicType = NicType;
+ nicEntry->Connected = Connected;
+
+ if (NicType == NdisSwitchNicTypeInternal)
+ {
+ nicEntry->AllowSends = TRUE;
+ }
+ else
+ {
+ nicEntry->AllowSends = MsForwardNicHasPolicy(SwitchContext, MacAddress);
+ }
+
+ InsertHeadList(nicList, &nicEntry->ListEntry);
+ }
+
+Cleanup:
+ return status;
+}
+
+
+NDIS_STATUS
+MsForwardAddMacPolicyUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PMSFORWARD_MAC_ADDRESS_POLICY MacPolicyBuffer,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ )
+/*++
+
+Routine Description:
+ Add the given policy to the policy list and correlate with
+ the NIC list.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PMSFORWARD_MAC_POLICY_LIST_ENTRY newPolicy;
+ PMSFORWARD_NIC_LIST_ENTRY nic;
+
+ newPolicy = MsForwardFindPolicyByMacAddressUnsafe(SwitchContext,
+ MacPolicyBuffer->MacAddress);
+
+ if (newPolicy == NULL)
+ {
+ newPolicy = ExAllocatePoolWithTag(NonPagedPoolNx,
+ sizeof(MSFORWARD_MAC_POLICY_LIST_ENTRY),
+ SxExtAllocationTag);
+
+ if (newPolicy == NULL)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ NdisMoveMemory(&newPolicy->MacAddress,
+ MacPolicyBuffer->MacAddress,
+ sizeof(newPolicy->MacAddress));
+
+ NdisMoveMemory(&newPolicy->PropertyInstanceId,
+ PropertyInstanceId,
+ sizeof(NDIS_SWITCH_OBJECT_INSTANCE_ID));
+
+ InsertHeadList(&SwitchContext->PropertyList,
+ &newPolicy->ListEntry);
+
+ nic = MsForwardFindNicByMacAddressUnsafe(SwitchContext,
+ MacPolicyBuffer->MacAddress);
+
+ if (nic != NULL)
+ {
+ nic->AllowSends = TRUE;
+ }
+ }
+ else
+ {
+ status = NDIS_STATUS_DATA_NOT_ACCEPTED;
+ }
+
+Cleanup:
+ return status;
+}
+
+
+VOID
+MsForwardDeleteMacPolicyUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ )
+/*++
+
+Routine Description:
+ Delete the given MAC policy, and coorelate with
+ the NIC list.
+
+--*/
+{
+ PMSFORWARD_MAC_POLICY_LIST_ENTRY deletePolicy;
+ PMSFORWARD_NIC_LIST_ENTRY nic;
+
+ deletePolicy = MsForwardFindPolicyByPropertyInstanceIdUnsafe(
+ SwitchContext,
+ PropertyInstanceId);
+
+ if (deletePolicy != NULL)
+ {
+ nic = MsForwardFindNicByMacAddressUnsafe(SwitchContext,
+ deletePolicy->MacAddress);
+
+ if (nic != NULL)
+ {
+ nic->AllowSends = FALSE;
+ }
+
+ RemoveEntryList(&deletePolicy->ListEntry);
+ ExFreePoolWithTag(deletePolicy, SxExtAllocationTag);
+ }
+}
+
+
+PMSFORWARD_NIC_LIST_ENTRY
+MsForwardFindNicByPortIdUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex
+ )
+/*++
+
+Routine Description:
+ Search for the NIC needed by port ID.
+
+--*/
+{
+ PLIST_ENTRY nicList = &SwitchContext->NicList;
+ PLIST_ENTRY curEntry = nicList->Flink;
+ PMSFORWARD_NIC_LIST_ENTRY nic = NULL;
+
+ if (IsListEmpty(nicList))
+ {
+ goto Cleanup;
+ }
+
+ do {
+ nic = CONTAINING_RECORD(curEntry,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ if (nic->PortId == PortId &&
+ nic->NicIndex == NicIndex)
+ {
+ goto Cleanup;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != nicList);
+
+ nic = NULL;
+
+Cleanup:
+ return nic;
+}
+
+
+PMSFORWARD_NIC_LIST_ENTRY
+MsForwardFindNicByMacAddressUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ )
+/*++
+
+Routine Description:
+ Search for the NIC needed by MAC Address.
+
+--*/
+{
+ PLIST_ENTRY nicList = &SwitchContext->NicList;
+ PLIST_ENTRY curEntry = nicList->Flink;
+ PMSFORWARD_NIC_LIST_ENTRY nic = NULL;
+
+ if (IsListEmpty(nicList))
+ {
+ goto Cleanup;
+ }
+
+ do {
+ nic = CONTAINING_RECORD(curEntry,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ if (RtlEqualMemory(MacAddress,
+ nic->MacAddress,
+ sizeof(nic->MacAddress)))
+ {
+ goto Cleanup;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != nicList);
+
+ nic = NULL;
+
+Cleanup:
+ return nic;
+}
+
+
+PMSFORWARD_MAC_POLICY_LIST_ENTRY
+MsForwardFindPolicyByMacAddressUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ )
+/*++
+
+Routine Description:
+ Search for the policy needed by MAC address.
+
+--*/
+{
+ PLIST_ENTRY propertyList = &SwitchContext->PropertyList;
+ PLIST_ENTRY curEntry = propertyList->Flink;
+ PMSFORWARD_MAC_POLICY_LIST_ENTRY policy = NULL;
+
+ if (IsListEmpty(propertyList))
+ {
+ goto Cleanup;
+ }
+
+ do {
+ policy = CONTAINING_RECORD(curEntry,
+ MSFORWARD_MAC_POLICY_LIST_ENTRY,
+ ListEntry);
+
+ if (RtlEqualMemory(MacAddress,
+ policy->MacAddress,
+ sizeof(policy->MacAddress)))
+ {
+ goto Cleanup;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != propertyList);
+
+ policy = NULL;
+
+Cleanup:
+ return policy;
+}
+
+
+PMSFORWARD_MAC_POLICY_LIST_ENTRY
+MsForwardFindPolicyByPropertyInstanceIdUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ )
+/*++
+
+Routine Description:
+ Search for the policy needed by PropertyInstanceId.
+
+--*/
+{
+ PLIST_ENTRY propertyList = &SwitchContext->PropertyList;
+ PLIST_ENTRY curEntry = propertyList->Flink;
+ PMSFORWARD_MAC_POLICY_LIST_ENTRY policy = NULL;
+
+ if (IsListEmpty(propertyList))
+ {
+ goto Cleanup;
+ }
+
+ do {
+ policy = CONTAINING_RECORD(curEntry,
+ MSFORWARD_MAC_POLICY_LIST_ENTRY,
+ ListEntry);
+
+ if (RtlEqualMemory(PropertyInstanceId,
+ &policy->PropertyInstanceId,
+ sizeof(policy->PropertyInstanceId)))
+ {
+ goto Cleanup;
+ }
+
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != propertyList);
+
+ policy = NULL;
+
+Cleanup:
+ return policy;
+}
+
+
+NDIS_STATUS
+MsForwardDeleteNicUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex
+ )
+/*++
+
+Routine Description:
+ Remove the NIC represented by the PortId and NicIndex
+ from the NIC list and free its memory.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ PMSFORWARD_NIC_LIST_ENTRY nicEntry = MsForwardFindNicByPortIdUnsafe(SwitchContext,
+ PortId,
+ NicIndex);
+
+ if (nicEntry == NULL)
+ {
+ ASSERT(FALSE);
+ goto Cleanup;
+ }
+
+ RemoveEntryList(&nicEntry->ListEntry);
+ ExFreePoolWithTag(nicEntry, SxExtAllocationTag);
+
+Cleanup:
+ return status;
+}
+
+
+VOID
+MsForwardClearNicListUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ )
+/*++
+
+Routine Description:
+ Remove all NICs from the list and free all memory.
+
+--*/
+{
+ PMSFORWARD_NIC_LIST_ENTRY nic;
+ PLIST_ENTRY nicList = &SwitchContext->NicList;
+ PLIST_ENTRY headList = NULL;
+
+ while (!IsListEmpty(nicList))
+ {
+ headList = RemoveHeadList(nicList);
+
+ nic = CONTAINING_RECORD(headList,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ ExFreePoolWithTag(nic, SxExtAllocationTag);
+ }
+
+ return;
+}
+
+
+VOID
+MsForwardClearPropertyListUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ )
+/*++
+
+Routine Description:
+ Remove all properties from the list and free all memory.
+
+--*/
+{
+ PMSFORWARD_MAC_POLICY_LIST_ENTRY policy;
+ PLIST_ENTRY propertyList = &SwitchContext->PropertyList;
+ PLIST_ENTRY headList = NULL;
+
+ while (!IsListEmpty(propertyList))
+ {
+ headList = RemoveHeadList(propertyList);
+
+ policy = CONTAINING_RECORD(headList,
+ MSFORWARD_MAC_POLICY_LIST_ENTRY,
+ ListEntry);
+
+ ExFreePoolWithTag(policy, SxExtAllocationTag);
+ }
+
+ return;
+}
+
+
+BOOLEAN
+MsForwardNicHasPolicy(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ )
+/*++
+
+Routine Description:
+ Returns TRUE if there is a correlated policy to the MAC
+ address given.
+
+--*/
+{
+ return (MsForwardFindPolicyByMacAddressUnsafe(SwitchContext,
+ MacAddress) != NULL);
+}
+
+
+VOID
+MsForwardMakeBroadcastArrayUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_FORWARDING_DESTINATION_ARRAY BroadcastArray,
+ _In_ NDIS_SWITCH_PORT_ID SourcePortId,
+ _In_ NDIS_SWITCH_NIC_INDEX SourceNicIndex
+ )
+/*++
+
+Routine Description:
+ Creates the destination array of all connected NICs
+ excluding the source given.
+
+--*/
+{
+ PLIST_ENTRY nicList = &SwitchContext->NicList;
+ PLIST_ENTRY curEntry = nicList->Flink;
+ PMSFORWARD_NIC_LIST_ENTRY nic = NULL;
+ UINT32 index = BroadcastArray->NumDestinations;
+ PNDIS_SWITCH_PORT_DESTINATION destination;
+
+ if (IsListEmpty(nicList))
+ {
+ goto Cleanup;
+ }
+
+ do {
+ nic = CONTAINING_RECORD(curEntry,
+ MSFORWARD_NIC_LIST_ENTRY,
+ ListEntry);
+
+ if ((SourcePortId == nic->PortId &&
+ SourceNicIndex == nic->NicIndex) ||
+ !nic->Connected)
+ {
+ if(curEntry->Flink == nicList)
+ {
+ break;
+ }
+ else
+ {
+ curEntry = curEntry->Flink;
+ continue;
+ }
+ }
+
+ destination = NDIS_SWITCH_PORT_DESTINATION_AT_ARRAY_INDEX(BroadcastArray, index);
+ NdisZeroMemory(destination, sizeof(NDIS_SWITCH_PORT_DESTINATION));
+
+ destination->PortId = nic->PortId;
+ destination->NicIndex = nic->NicIndex;
+
+ ++index;
+ curEntry = curEntry->Flink;
+
+ } while(curEntry != nicList);
+
+ if (SourcePortId != SwitchContext->ExternalPortId &&
+ SwitchContext->ExternalNicConnected)
+ {
+ destination = NDIS_SWITCH_PORT_DESTINATION_AT_ARRAY_INDEX(BroadcastArray, index);
+ destination->PortId = SwitchContext->ExternalPortId;
+ destination->NicIndex = SwitchContext->ExternalNicIndex;
+ }
+
+Cleanup:
+ return;
+}
+
+
+NDIS_STATUS
+MsForwardInitSwitch(
+ _In_ PSX_SWITCH_OBJECT Switch,
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ )
+/*++
+
+Routine Description:
+ Initializes the switch state.
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PNDIS_SWITCH_NIC_ARRAY nicArray = NULL;
+ ULONG arrIndex;
+ PNDIS_SWITCH_NIC_PARAMETERS curNic;
+ PNDIS_SWITCH_PROPERTY_ENUM_PARAMETERS switchPropertyParameters = NULL;
+ PNDIS_SWITCH_PROPERTY_ENUM_INFO switchPropertyInfo = NULL;
+ PNDIS_SWITCH_PROPERTY_CUSTOM customPropertyInfo = NULL;
+ PMSFORWARD_MAC_ADDRESS_POLICY macAddressPolicy;
+ PNDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS portPropertyParameters = NULL;
+ PNDIS_SWITCH_PORT_PROPERTY_ENUM_INFO portPropertyInfo = NULL;
+ PNDIS_SWITCH_PORT_PROPERTY_VLAN vlanProperty;
+
+ ASSERT(!SwitchContext->IsActive);
+
+ //
+ // Get Property List.
+ //
+ status = SxLibGetSwitchPropertyUnsafe(Switch,
+ NdisSwitchPropertyTypeCustom,
+ (PNDIS_SWITCH_OBJECT_ID)&MacAddressPolicyGuid,
+ &switchPropertyParameters);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ switchPropertyInfo =
+ NDIS_SWITCH_PROPERTY_ENUM_PARAMETERS_GET_FIRST_INFO(switchPropertyParameters);
+
+ for (arrIndex = 0;
+ arrIndex < switchPropertyParameters->NumProperties;
+ ++arrIndex)
+ {
+ //
+ // Should always get back v1 or later. It is safe to access the
+ // v1 version of the structure if newer property is retrieved.
+ //
+ ASSERT(switchPropertyInfo->PropertyVersion >=
+ MAC_ADDRESS_POLICY_VERSION);
+
+ customPropertyInfo =
+ NDIS_SWITCH_PROPERTY_ENUM_INFO_GET_PROPERTY(switchPropertyInfo);
+
+ macAddressPolicy =
+ NDIS_SWITCH_PROPERTY_CUSTOM_GET_BUFFER(customPropertyInfo);
+
+ status = MsForwardAddMacPolicyUnsafe(SwitchContext,
+ macAddressPolicy,
+ &switchPropertyInfo->PropertyInstanceId);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ switchPropertyInfo =
+ NDIS_SWITCH_PROPERTY_ENUM_INFO_GET_NEXT(switchPropertyInfo);
+ }
+
+ //
+ // Now, get NIC list.
+ //
+ status = SxLibGetNicArrayUnsafe(Switch, &nicArray);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ for (arrIndex = 0; arrIndex < nicArray->NumElements; ++arrIndex)
+ {
+ curNic = NDIS_SWITCH_NIC_AT_ARRAY_INDEX(nicArray, arrIndex);
+
+ status = Switch->NdisSwitchHandlers.ReferenceSwitchPort(
+ Switch->NdisSwitchContext,
+ curNic->PortId);
+
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+
+ //
+ // Get VLAN Port property to ensure no VLAN set.
+ //
+ status = SxLibGetPortPropertyUnsafe(Switch,
+ curNic->PortId,
+ NdisSwitchPortPropertyTypeVlan,
+ NULL,
+ &portPropertyParameters);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ status = NDIS_STATUS_RESOURCES;
+ goto Cleanup;
+ }
+
+ portPropertyInfo =
+ NDIS_SWITCH_PORT_PROPERTY_ENUM_PARAMETERS_GET_FIRST_INFO(portPropertyParameters);
+
+ //
+ // Should always get back v1 or later. It is safe to access the v1
+ // version of the structure if newer property is retrieved.
+ //
+ ASSERT(portPropertyInfo->PropertyVersion >=
+ NDIS_SWITCH_PORT_PROPERTY_VLAN_REVISION_1);
+
+ vlanProperty =
+ NDIS_SWITCH_PORT_PROPERTY_ENUM_INFO_GET_PROPERTY(portPropertyInfo);
+
+ //
+ // Real production code should support VLAN,
+ // and not fail SxExtRestartSwitch.
+ //
+ if (vlanProperty->OperationMode != NdisSwitchPortVlanModeAccess ||
+ vlanProperty->VlanProperties.AccessVlanId != 0)
+ {
+ status = NDIS_STATUS_FAILURE;
+ goto Cleanup;
+ }
+
+ status = Switch->NdisSwitchHandlers.DereferenceSwitchPort(
+ Switch->NdisSwitchContext,
+ curNic->PortId);
+
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+
+ //
+ // If a VF is assigned to a NIC, then the traffic
+ // flows through the VF and not the switch. This means
+ // we have to revoke the VF to enforce our policy.
+ //
+ if (curNic->VFAssigned)
+ {
+ status = Switch->NdisSwitchHandlers.ReferenceSwitchNic(
+ Switch->NdisSwitchContext,
+ curNic->PortId,
+ curNic->NicIndex);
+
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+
+ SxLibRevokeVfUnsafe(Switch, curNic->PortId);
+
+ status = Switch->NdisSwitchHandlers.DereferenceSwitchNic(
+ Switch->NdisSwitchContext,
+ curNic->PortId,
+ curNic->NicIndex);
+
+ ASSERT(status == NDIS_STATUS_SUCCESS);
+ }
+
+ //
+ // Now we've verified we can support the NIC, so
+ // check if there's a property for it, and add it to
+ // the NIC list.
+ //
+ status = MsForwardAddNicUnsafe(SwitchContext,
+ curNic->PermanentMacAddress,
+ curNic->PortId,
+ curNic->NicIndex,
+ curNic->NicType,
+ (curNic->NicState == NdisSwitchNicStateConnected));
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ if (curNic->NicType == NdisSwitchNicTypeExternal &&
+ curNic->NicIndex != 0 &&
+ SwitchContext->ExternalPortId == 0)
+ {
+ SwitchContext->ExternalPortId = curNic->PortId;
+ SwitchContext->ExternalNicIndex = curNic->NicIndex;
+ SwitchContext->ExternalNicConnected = TRUE;
+ ++(SwitchContext->NumDestinations);
+ }
+ else if (curNic->NicType != NdisSwitchNicTypeExternal)
+ {
+ ++(SwitchContext->NumDestinations);
+ }
+ }
+
+ SwitchContext->IsActive = TRUE;
+
+Cleanup:
+ if (switchPropertyParameters != NULL)
+ {
+ ExFreePoolWithTag(switchPropertyParameters, SxExtAllocationTag);
+ }
+
+ if (portPropertyParameters != NULL)
+ {
+ ExFreePoolWithTag(portPropertyParameters, SxExtAllocationTag);
+ }
+
+ if (nicArray != NULL)
+ {
+ ExFreePoolWithTag(nicArray, SxExtAllocationTag);
+ }
+
+ return status;
+}
+
diff --git a/network/ndis/extension/samples/forward/MsForwardExt.h b/network/ndis/extension/samples/forward/MsForwardExt.h
new file mode 100644
index 00000000..ed6ac629
--- /dev/null
+++ b/network/ndis/extension/samples/forward/MsForwardExt.h
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+ MsForwardExt.h
+
+Abstract:
+
+ This file contains structures and function definitions
+ necessary for MsForwardExt.
+
+
+--*/
+
+
+#define MSFORWARD_MAC_LENGTH 6
+
+//
+// MSFORWARD_CONTEXT
+// The context allocated per switch.
+//
+typedef struct _MSFORWARD_CONTEXT
+{
+ BOOLEAN IsActive;
+
+ NDIS_SWITCH_PORT_ID ExternalPortId;
+ NDIS_SWITCH_NIC_INDEX ExternalNicIndex;
+ BOOLEAN ExternalNicConnected;
+
+ //
+ // This sample uses linked lists for the NICs and property
+ // lookup. THIS IS NOT RECOMMENDED.
+ //
+ LIST_ENTRY NicList;
+ LIST_ENTRY PropertyList;
+ PNDIS_RW_LOCK_EX DispatchLock;
+
+ UINT32 NumDestinations;
+ BOOLEAN IsInitialRestart;
+} MSFORWARD_CONTEXT, *PMSFORWARD_CONTEXT;
+
+//
+// MSFORWARD_NIC_LIST_ENTRY
+// The context allocated per NIC.
+//
+typedef struct _MSFORWARD_NIC_LIST_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ UINT8 MacAddress[MSFORWARD_MAC_LENGTH];
+ NDIS_SWITCH_PORT_ID PortId;
+ NDIS_SWITCH_NIC_INDEX NicIndex;
+ NDIS_SWITCH_NIC_TYPE NicType;
+ BOOLEAN AllowSends;
+ BOOLEAN Connected;
+} MSFORWARD_NIC_LIST_ENTRY, *PMSFORWARD_NIC_LIST_ENTRY;
+
+//
+// MSFORWARD_MAC_POLICY_LIST_ENTRY
+// The context allocated per switch policy.
+//
+typedef struct _MSFORWARD_MAC_POLICY_LIST_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ UINT8 MacAddress[MSFORWARD_MAC_LENGTH];
+ NDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId;
+} MSFORWARD_MAC_POLICY_LIST_ENTRY, *PMSFORWARD_MAC_POLICY_LIST_ENTRY;
+
+//
+// MSFORWARD_MAC_ADDRESS_POLICY
+// The serialization of the policy structure found
+// in MsForwardExtPolicy.mof
+//
+typedef struct _MSFORWARD_MAC_ADDRESS_POLICY
+{
+ UINT32 MacAddressLength;
+ UINT8 MacAddress[MSFORWARD_MAC_LENGTH];
+} MSFORWARD_MAC_ADDRESS_POLICY, *PMSFORWARD_MAC_ADDRESS_POLICY;
+
+//
+// MSFORWARD_MAC_ADDRESS_POLICY_STATUS
+// The serialization of the policy status structure
+// found in MsForwardExtPolicyStatus.mof
+//
+typedef struct _MSFORWARD_MAC_ADDRESS_POLICY_STATUS
+{
+ UINT32 PortArrayLength;
+ UINT32 PortArrayOffset;
+} MSFORWARD_MAC_ADDRESS_POLICY_STATUS, *PMSFORWARD_MAC_ADDRESS_POLICY_STATUS;
+
+//
+// MSFORWARD_ETHERNET_HEADER
+// Ethernet header definition.
+//
+typedef struct _MSFORWARD_ETHERNET_HEADER
+{
+ UINT8 Destination[MSFORWARD_MAC_LENGTH];
+ UINT8 Source[MSFORWARD_MAC_LENGTH];
+ UINT16 Type;
+} MSFORWARD_ETHERNET_HEADER, *PMSFORWARD_ETHERNET_HEADER;
+
+//
+// MacAddressPolicyGuid
+//
+// The GUID representing the switch policy owned
+// by MsForwardExt.
+//
+extern const NDIS_SWITCH_OBJECT_ID MacAddressPolicyGuid;
+
+//
+// MacAddressPolicyStatusGuid
+//
+// The GUID representing the switch policy status
+// indicated for the status of the switch policy
+// owned by MsForwardExt.
+//
+extern const NDIS_SWITCH_OBJECT_ID MacAddressPolicyStatusGuid;
+
+//
+// Switch Property Macros
+//
+#define MAC_ADDRESS_POLICY_VERSION 0x0100
+#define MAC_ADDRESS_POLICY_SERIALIZATION_VERSION NDIS_SWITCH_OBJECT_SERIALIZATION_VERSION_1
+
+//
+// Switch Property Status Macros
+//
+#define MAC_ADDRESS_POLICY_STATUS_VERSION 0x0100
+#define MAC_ADDRESS_POLICY_STATUS_SERIALIZATION_VERSION NDIS_SWITCH_OBJECT_SERIALIZATION_VERSION_1
+
+
+//
+// Private functions used by MsForwardExt
+//
+NDIS_STATUS
+MsForwardAddNicUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex,
+ _In_ NDIS_SWITCH_NIC_TYPE NicType,
+ _In_ BOOLEAN Connected
+ );
+
+NDIS_STATUS
+MsForwardDeleteNicUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex
+ );
+
+VOID
+MsForwardClearNicListUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ );
+
+PMSFORWARD_NIC_LIST_ENTRY
+MsForwardFindNicByPortIdUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ NDIS_SWITCH_PORT_ID PortId,
+ _In_ NDIS_SWITCH_NIC_INDEX NicIndex
+ );
+
+PMSFORWARD_NIC_LIST_ENTRY
+MsForwardFindNicByMacAddressUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ );
+
+NDIS_STATUS
+MsForwardAddMacPolicyUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PMSFORWARD_MAC_ADDRESS_POLICY MacPolicyBuffer,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ );
+
+VOID
+MsForwardDeleteMacPolicyUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ );
+
+VOID
+MsForwardClearPropertyListUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ );
+
+PMSFORWARD_MAC_POLICY_LIST_ENTRY
+MsForwardFindPolicyByMacAddressUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ );
+
+PMSFORWARD_MAC_POLICY_LIST_ENTRY
+MsForwardFindPolicyByPropertyInstanceIdUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_OBJECT_INSTANCE_ID PropertyInstanceId
+ );
+
+BOOLEAN
+MsForwardNicHasPolicy(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_reads_bytes_(6) PUCHAR MacAddress
+ );
+
+VOID
+MsForwardMakeBroadcastArrayUnsafe(
+ _In_ PMSFORWARD_CONTEXT SwitchContext,
+ _In_ PNDIS_SWITCH_FORWARDING_DESTINATION_ARRAY BroadcastArray,
+ _In_ NDIS_SWITCH_PORT_ID SourcePortId,
+ _In_ NDIS_SWITCH_NIC_INDEX SourceNicIndex
+ );
+
+NDIS_STATUS
+MsForwardInitSwitch(
+ _In_ PSX_SWITCH_OBJECT Switch,
+ _In_ PMSFORWARD_CONTEXT SwitchContext
+ );
diff --git a/network/ndis/extension/samples/forward/MsForwardExt.rc b/network/ndis/extension/samples/forward/MsForwardExt.rc
new file mode 100644
index 00000000..25e0b2db
--- /dev/null
+++ b/network/ndis/extension/samples/forward/MsForwardExt.rc
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Microsoft Corporation. All Rights Reserved.
+//
+
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Microsoft Sample Forwarding Extension"
+#define VER_INTERNALNAME_STR "msforwardext.SYS"
+#define VER_ORIGINALFILENAME_STR "msforwardext.SYS"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/extension/samples/forward/install.cmd b/network/ndis/extension/samples/forward/install.cmd
new file mode 100644
index 00000000..009eed36
--- /dev/null
+++ b/network/ndis/extension/samples/forward/install.cmd
@@ -0,0 +1,6 @@
+netcfg -l .\MSForwardExt.inf -c s -i ms_forwardext
+
+net stop vmms
+mofcomp -N:root\virtualization\v2 .\MSForwardExtPolicy.mof
+mofcomp -N:root\virtualization\v2 .\MSForwardExtPolicyStatus.mof
+net start vmms
diff --git a/network/ndis/extension/samples/forward/msforwardext.inf b/network/ndis/extension/samples/forward/msforwardext.inf
new file mode 100644
index 00000000..dd849d8b
--- /dev/null
+++ b/network/ndis/extension/samples/forward/msforwardext.inf
@@ -0,0 +1,85 @@
+;
+; Copyright (c) Microsoft Corporation. All Rights Reserved.
+;
+
+[version]
+Signature = "$Windows NT$"
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %Msft%
+CatalogFile = msforwardext.cat
+DriverVer = 07/29/2011,2.0
+
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64
+
+[MSFT.NTx86]
+%MSForwardExt_Desc%=Install, MS_forwardext
+
+[MSFT.NTia64]
+%MSForwardExt_Desc%=Install, MS_forwardext
+
+[MSFT.NTamd64]
+%MSForwardExt_Desc%=Install, MS_forwardext
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+Characteristics=0x40000
+NetCfgInstanceId="{37d9eae6-5bae-48c5-bff1-63a7cdd7e4f4}"
+Copyfiles = MSForwardExt.copyfiles.sys
+
+[SourceDisksNames]
+1=%MSForwardExt_Desc%,"",,
+
+[SourceDisksFiles]
+MSForwardExt.sys=1
+
+[DestinationDirs]
+DefaultDestDir=12
+MSForwardExt.copyfiles.sys=12
+
+[MSForwardExt.copyfiles.sys]
+MSForwardExt.sys,,,2
+
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+HKR, Ndi,Service,,"MSForwardExt"
+HKR, Ndi,CoServices,0x00010000,"MSForwardExt"
+HKR, Ndi,HelpText,,%MSForwardExt_HelpText%
+HKR, Ndi,FilterClass,,"ms_switch_forward"
+HKR, Ndi,FilterType,0x00010001,0x00000002
+HKR, Ndi\Interfaces,UpperRange,,"noupper"
+HKR, Ndi\Interfaces,LowerRange,,"nolower"
+HKR, Ndi\Interfaces, FilterMediaTypes,,"vmnetextension"
+HKR, Ndi,FilterRunType, 0x00010001, 2 ; optional
+
+;-------------------------------------------------------------------------
+; Service installation support, common.EventLog here is to demonstrate how to
+; write an enent log
+;-------------------------------------------------------------------------
+[Install.Services]
+AddService=MSForwardExt,,MSForwardExt_Service_Inst;, common.EventLog
+
+[MSForwardExt_Service_Inst]
+DisplayName = %MSForwardExt_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\MSForwardExt.sys
+LoadOrderGroup = NDIS
+Description = %MSForwardExt_Desc%
+AddReg = Common.Params.reg
+
+[Install.Remove.Services]
+DelService=MSForwardExt,0x200
+
+[Strings]
+Msft = "Microsoft"
+MSForwardExt_Desc = "Microsoft Sample Forwarding Extension"
+MSForwardExt_HelpText = "Sample for forwarding switch extension"
diff --git a/network/ndis/extension/samples/forward/msforwardext.vcxproj b/network/ndis/extension/samples/forward/msforwardext.vcxproj
new file mode 100644
index 00000000..af65e5ba
--- /dev/null
+++ b/network/ndis/extension/samples/forward/msforwardext.vcxproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{404E1399-EA48-4CEE-A59E-EA0D4C01928A}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">x64</Platform>
+ <SampleGuid>{E7755C69-DA3A-4E6B-9C38-0435AC07863F}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>msforwardext</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>msforwardext</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS640=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;.\..\..\base\$(IntDir)\sxbase.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;.\..\..\base\$(IntDir)\sxbase.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="MsForwardExt.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="MsForwardExt.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters b/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters
new file mode 100644
index 00000000..a4de6bd4
--- /dev/null
+++ b/network/ndis/extension/samples/forward/msforwardext.vcxproj.Filters
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{AE574627-04F4-423B-B254-44BD4A41BF5D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{50E67A30-537B-4C27-BDFD-110A25C9A725}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{83FDCB52-42AC-4B2D-9A09-F917F36CFA49}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{362EB8F8-E693-45BC-9EE5-1ED0A9776739}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="MsForwardExt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="MsForwardExt.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/samples/forward/precomp.h b/network/ndis/extension/samples/forward/precomp.h
new file mode 100644
index 00000000..ca260479
--- /dev/null
+++ b/network/ndis/extension/samples/forward/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 "..\..\base\SxBase.h"
+#include "..\..\base\SxApi.h"
+#include "..\..\base\SxLibrary.h" \ No newline at end of file
diff --git a/network/ndis/extension/samples/forward/precompsrc.c b/network/ndis/extension/samples/forward/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/extension/samples/forward/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/extension/samples/forward/removeRoute.ps1 b/network/ndis/extension/samples/forward/removeRoute.ps1
new file mode 100644
index 00000000..e03f9d9f
--- /dev/null
+++ b/network/ndis/extension/samples/forward/removeRoute.ps1
@@ -0,0 +1,12 @@
+#
+# Copyright (c) Microsoft Corporation. All Rights Reserved.
+#
+
+Import-Module Hyper-V
+
+$switch = Get-VmSwitch -Name "CorpNet"
+$features = Get-VmSwitchExtensionSwitchFeature -VmSwitch $switch -FeatureName "MSForwardExt Mac Address Policy"
+if ($features -ne $null)
+{
+ Remove-VmSwitchExtensionSwitchFeature -VmSwitch $switch -VmSwitchExtensionFeature $features
+} \ No newline at end of file
diff --git a/network/ndis/extension/samples/forward/setRoute.ps1 b/network/ndis/extension/samples/forward/setRoute.ps1
new file mode 100644
index 00000000..71899087
--- /dev/null
+++ b/network/ndis/extension/samples/forward/setRoute.ps1
@@ -0,0 +1,54 @@
+#
+# Copyright (c) Microsoft Corporation. All Rights Reserved.
+#
+
+function StringToMacAddress([String]$MacString)
+{
+ $zeroVal = [int]("0"[0]);
+ $aVal = [int]("A"[0]);
+
+ $macArray = @();
+ $byteOne = 0;
+ $byteTwo = 0;
+
+ for($i = 0; $i -lt 6; $i++)
+ {
+ $byteChars = $MacString.ToCharArray(2*$i, 2);
+
+ $byteOne = $byteChars[0] - $zeroVal;
+ $byteTwo = $byteChars[1] - $zeroVal;
+
+ if($byteOne -gt 9)
+ {
+ $byteOne = $byteChars[0] - $aVal + 10;
+ }
+ if($byteTwo -gt 9)
+ {
+ $byteTwo = $byteChars[1] - $aVal + 10;
+ }
+
+ $byteVal = 16*($byteOne) + ($byteTwo);
+ $macArray = $macArray + $byteVal;
+ }
+
+ return $macArray
+}
+
+Import-Module Hyper-V
+
+$vmArr = Get-VM
+$switch = Get-VmSwitch -Name "CorpNet"
+$policy = Get-VmSystemSwitchExtensionSwitchFeature -FeatureName "MSForwardExt Mac Address Policy"
+
+foreach($vm in $vmArr)
+{
+ $vmName = $vm.Name
+ $adapters = Get-VmNetworkAdapter -VmName $vmName
+
+ foreach($adapter in $adapters)
+ {
+ Write-Host "Setting Policy for $vmName..."
+ $policy.SettingData.MacAddress = StringToMacAddress($adapter.MacAddress)
+ Add-VmSwitchExtensionSwitchFeature -VmSwitch $switch -VMSwitchExtensionFeature $policy
+ }
+}
diff --git a/network/ndis/extension/samples/forward/uninstall.cmd b/network/ndis/extension/samples/forward/uninstall.cmd
new file mode 100644
index 00000000..fe8ffe28
--- /dev/null
+++ b/network/ndis/extension/samples/forward/uninstall.cmd
@@ -0,0 +1,3 @@
+powershell .\removeRoute.ps1
+
+netcfg -u ms_forwardext \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/MsPassthroughExt.c b/network/ndis/extension/samples/passthrough/MsPassthroughExt.c
new file mode 100644
index 00000000..e99eeac5
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/MsPassthroughExt.c
@@ -0,0 +1,597 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved.
+
+Module Name:
+
+ MsPassthroughExt.c
+
+Abstract:
+
+ This file contains the implementation of a passthrough filter
+ utilizing SxBase.lib.
+
+
+--*/
+
+#include "precomp.h"
+
+UCHAR SxExtMajorNdisVersion = NDIS_FILTER_MAJOR_VERSION;
+UCHAR SxExtMinorNdisVersion = NDIS_FILTER_MINOR_VERSION;
+PWCHAR SxExtFriendlyName = L"Microsoft Sample Passthrough Extension";
+PWCHAR SxExtUniqueName = L"{2A06F1CB-1B9B-43A8-ADF7-B7D44A9EE71C}";
+PWCHAR SxExtServiceName = L"MsPassthroughExt";
+ULONG SxExtAllocationTag = 'tPsM';
+ULONG SxExtOidRequestId = 'tPsM';
+
+
+NDIS_STATUS
+SxExtInitialize()
+{
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+SxExtUninitialize()
+{
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreateSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ PNDIS_HANDLE *ExtensionContext
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+
+ *ExtensionContext = NULL;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeleteSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtActivateSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtRestartSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtPauseSwitch(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreatePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtUpdatePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtCreateNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtConnectNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtUpdateNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDisconnectNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeleteNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_PARAMETERS Nic
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Nic);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtTeardownPort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtDeletePort(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PARAMETERS Port
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(Port);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtSaveNic(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+ PULONG BytesWritten,
+ PULONG BytesNeeded
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtSaveNicComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtNicRestore(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState,
+ PULONG BytesRestored
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ *BytesRestored = 0;
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtNicRestoreComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_NIC_SAVE_STATE SaveState
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SaveState);
+
+ return;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtAddSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SwitchProperty);
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtUpdateSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_PARAMETERS SwitchProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SwitchProperty);
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtDeleteSwitchProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PROPERTY_DELETE_PARAMETERS SwitchProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SwitchProperty);
+
+ return FALSE;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtAddPortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(PortProperty);
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtUpdatePortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_PARAMETERS PortProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(PortProperty);
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtDeletePortProperty(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_PROPERTY_DELETE_PARAMETERS PortProperty
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(PortProperty);
+
+ return FALSE;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtQuerySwitchFeatureStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_FEATURE_STATUS_PARAMETERS SwitchFeatureStatus,
+ PULONG BytesNeeded
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(SwitchFeatureStatus);
+ UNREFERENCED_PARAMETER(BytesNeeded);
+
+ return FALSE;
+}
+
+
+_Use_decl_annotations_
+BOOLEAN
+SxExtQueryPortFeatureStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_SWITCH_PORT_FEATURE_STATUS_PARAMETERS PortFeatureStatus,
+ PULONG BytesNeeded
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(PortFeatureStatus);
+ UNREFERENCED_PARAMETER(BytesNeeded);
+
+ return FALSE;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicRequest(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_OID_REQUEST OidRequest,
+ PNDIS_SWITCH_PORT_ID SourcePortId,
+ PNDIS_SWITCH_NIC_INDEX SourceNicIndex,
+ PNDIS_SWITCH_PORT_ID DestinationPortId,
+ PNDIS_SWITCH_NIC_INDEX DestinationNicIndex
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(OidRequest);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+ UNREFERENCED_PARAMETER(DestinationPortId);
+ UNREFERENCED_PARAMETER(DestinationNicIndex);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicRequestComplete(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_OID_REQUEST OidRequest,
+ NDIS_SWITCH_PORT_ID SourcePortId,
+ NDIS_SWITCH_NIC_INDEX SourceNicIndex,
+ NDIS_SWITCH_PORT_ID DestinationPortId,
+ NDIS_SWITCH_NIC_INDEX DestinationNicIndex,
+ NDIS_STATUS Status
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(OidRequest);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+ UNREFERENCED_PARAMETER(DestinationPortId);
+ UNREFERENCED_PARAMETER(DestinationNicIndex);
+ UNREFERENCED_PARAMETER(Status);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+SxExtProcessNicStatus(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNDIS_STATUS_INDICATION StatusIndication,
+ NDIS_SWITCH_PORT_ID SourcePortId,
+ NDIS_SWITCH_NIC_INDEX SourceNicIndex
+ )
+{
+ UNREFERENCED_PARAMETER(Switch);
+ UNREFERENCED_PARAMETER(ExtensionContext);
+ UNREFERENCED_PARAMETER(StatusIndication);
+ UNREFERENCED_PARAMETER(SourcePortId);
+ UNREFERENCED_PARAMETER(SourceNicIndex);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartNetBufferListsIngress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendFlags
+ )
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibSendNetBufferListsIngress(Switch,
+ NetBufferLists,
+ SendFlags,
+ 0);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartNetBufferListsEgress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG NumberOfNetBufferLists,
+ ULONG ReceiveFlags
+ )
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibSendNetBufferListsEgress(Switch,
+ NetBufferLists,
+ NumberOfNetBufferLists,
+ ReceiveFlags);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartCompleteNetBufferListsEgress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG ReturnFlags
+ )
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibCompleteNetBufferListsEgress(Switch,
+ NetBufferLists,
+ ReturnFlags);
+}
+
+
+_Use_decl_annotations_
+VOID
+SxExtStartCompleteNetBufferListsIngress(
+ PSX_SWITCH_OBJECT Switch,
+ NDIS_HANDLE ExtensionContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendCompleteFlags
+ )
+{
+ UNREFERENCED_PARAMETER(ExtensionContext);
+
+ SxLibCompleteNetBufferListsIngress(Switch,
+ NetBufferLists,
+ SendCompleteFlags);
+}
+
diff --git a/network/ndis/extension/samples/passthrough/MsPassthroughExt.rc b/network/ndis/extension/samples/passthrough/MsPassthroughExt.rc
new file mode 100644
index 00000000..c76ed707
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/MsPassthroughExt.rc
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Microsoft Corporation. All Rights Reserved.
+//
+
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "Microsoft Sample Passthrough Extension"
+#define VER_INTERNALNAME_STR "mspassthroughext.SYS"
+#define VER_ORIGINALFILENAME_STR "mspassthroughext.SYS"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/extension/samples/passthrough/install.cmd b/network/ndis/extension/samples/passthrough/install.cmd
new file mode 100644
index 00000000..0bacc039
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/install.cmd
@@ -0,0 +1 @@
+netcfg -l .\MSPassthroughExt.inf -c s -i ms_passthroughext \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/mspassthroughext.inf b/network/ndis/extension/samples/passthrough/mspassthroughext.inf
new file mode 100644
index 00000000..6a6b941d
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/mspassthroughext.inf
@@ -0,0 +1,89 @@
+;
+; Copyright (c) Microsoft Corporation. All Rights Reserved.
+;
+
+[version]
+Signature = "$Windows NT$"
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %Msft%
+CatalogFile = mspassthroughext.cat
+DriverVer = 08/29/2011,1.0
+
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64
+
+[MSFT.NTx86]
+%MSPassthroughExt_Desc%=Install, MS_passthroughext
+
+[MSFT.NTia64]
+%MSPassthroughExt_Desc%=Install, MS_passthroughext
+
+[MSFT.NTamd64]
+%MSPassthroughExt_Desc%=Install, MS_passthroughext
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+Characteristics=0x40000
+NetCfgInstanceId="{2A06F1CB-1B9B-43A8-ADF7-B7D44A9EE71C}"
+Copyfiles = MSPassthroughExt.copyfiles.sys
+
+[SourceDisksNames]
+1=%MSPassthroughExt_Desc%,"",,
+
+[SourceDisksFiles]
+MSPassthroughExt.sys=1
+
+[DestinationDirs]
+DefaultDestDir=12
+MSPassthroughExt.copyfiles.sys=12
+
+[MSPassthroughExt.copyfiles.sys]
+MSPassthroughExt.sys,,,2
+
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+HKR, Ndi,Service,,"MSPassthroughExt"
+HKR, Ndi,CoServices,0x00010000,"MSPassthroughExt"
+HKR, Ndi,HelpText,,%MSPassthroughExt_HelpText%
+HKR, Ndi,FilterClass,,"ms_switch_filter"
+HKR, Ndi,FilterType,0x00010001,0x00000002
+HKR, Ndi\Interfaces,UpperRange,,"noupper"
+HKR, Ndi\Interfaces,LowerRange,,"nolower"
+HKR, Ndi\Interfaces, FilterMediaTypes,,"vmnetextension"
+HKR, Ndi,FilterRunType, 0x00010001, 2 ; optional
+
+;-------------------------------------------------------------------------
+; Service installation support, common.EventLog here is to demonstrate how to
+; write an enent log
+;-------------------------------------------------------------------------
+[Install.Services]
+AddService=MSPassthroughExt,,MSPassthroughExt_Service_Inst;, common.EventLog
+
+[MSPassthroughExt_Service_Inst]
+DisplayName = %MSPassthroughExt_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\MSPassthroughExt.sys
+LoadOrderGroup = NDIS
+Description = %MSPassthroughExt_Desc%
+AddReg = Common.Params.reg
+
+[Install.Remove.Services]
+DelService=MSPassthroughExt,0x200
+
+[Strings]
+Msft = "Microsoft"
+MSPassthroughExt_Desc = "Microsoft Sample Passthrough Extension"
+MSPassthroughExt_HelpText = "Sample for filtering extension using SxBase"
+
+
+
+
diff --git a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj
new file mode 100644
index 00000000..cda7cbbf
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2339B4A8-60AF-4172-AC68-3159E6D001EC}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">x64</Platform>
+ <SampleGuid>{DA3F14BC-0746-46C8-99E7-339173543E27}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>mspassthroughext</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>mspassthroughext</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;.\..\..\base\$(IntDir)\sxbase.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;.\..\..\base\$(IntDir)\sxbase.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="MsPassthroughExt.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="MsPassthroughExt.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters
new file mode 100644
index 00000000..b43daf1e
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/mspassthroughext.vcxproj.Filters
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{555B7D63-D8B9-4382-8D6E-A97AC09CE282}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{797B07B8-0B76-4BA6-BDF4-45786B031900}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{D95F4A4C-E2E8-4108-86FB-C568FA437FA1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{F05BF5D9-0765-4293-B2AB-41B06C544956}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="MsPassthroughExt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="MsPassthroughExt.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/precomp.h b/network/ndis/extension/samples/passthrough/precomp.h
new file mode 100644
index 00000000..ca260479
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/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 "..\..\base\SxBase.h"
+#include "..\..\base\SxApi.h"
+#include "..\..\base\SxLibrary.h" \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/precompsrc.c b/network/ndis/extension/samples/passthrough/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/extension/samples/passthrough/uninstall.cmd b/network/ndis/extension/samples/passthrough/uninstall.cmd
new file mode 100644
index 00000000..369b6665
--- /dev/null
+++ b/network/ndis/extension/samples/passthrough/uninstall.cmd
@@ -0,0 +1 @@
+netcfg -u ms_passthroughext \ No newline at end of file
diff --git a/network/ndis/filter/ReadMe.md b/network/ndis/filter/ReadMe.md
new file mode 100644
index 00000000..4202c41a
--- /dev/null
+++ b/network/ndis/filter/ReadMe.md
@@ -0,0 +1,117 @@
+NDIS 6.0 Filter Driver
+======================
+
+The Ndislwf sample is a do-nothing pass-through NDIS 6 filter driver that demonstrates the basic principles underlying an NDIS 6.0 Filter driver. The sample replaces the NDIS 5 Sample Intermediate Driver (Passthru driver).
+
+Although this sample filter driver is installed as a modifying filter driver, it doesn't modify any packets; it only repackages and sends down all OID requests. You can modify this filter driver to change packets before passing them along. Or you can use the filter to originate new packets to send or receive. For example, the filter could encrypt/compress outgoing and decrypt/decompress incoming data.
+
+
+For more information, see [NDIS Filter Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff565492) in the network devices design guide.
+
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in **Visual Studio**, in **Solution Explorer**, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, open **Control Panel**. Click **Network and Internet** and then open **Network and Sharing Center**.
+5. Under **View your active networks**, click the connection listed under **Connections:** and click **Properties**. If you have previously installed this sample, highlight it in the list.
+6. Click **Install**, then **Service**, then **Add**.
+ **Note**  You may see multiple instances of the **NDIS Sample LightWeight Filter** service. If so, highlight the newest one.
+7. Click **Have Disk**.
+8. In the **Install from Disk** dialog, browse to the DriverTest\\Drivers directory. Highlight the netlwf.inf file and click **Open**, then click OK. This should show **NDIS Sample LightWeight Filter** in a list of **Network Services**. Highlight **NDIS Sample LightWeight Filter** and click **OK**. Click **OK**. Click **Close**. Click **Close**. This installs the Ndislwf filter driver service.
+
+**Note**  
+
+If you've installed the Ndislwf sample on the target computer before, you can use the [PnPUtil](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550419) tool to delete the older versions from the driver store.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571).
+
+Ndislwf is installed as a service (called **NDIS Sample LightWeight Filter** in the supplied INF). To install it, do the following:
+
+1. Prepare an installation directory on the target computer and copy these files from the host computer into the directory:
+ netlwf.cat
+ netlwf.inf
+ ndislwf.sys
+2. Open **Control Panel**.
+3. Click **Network and Internet** and then open **Network and Sharing Center**. Under **View your active networks**, click the connection listed under **Connections**: and click **Properties**.
+4. If you have previously installed this sample, highlight it in the list.
+5. Click **Install**, then **Service**, then **Add**, then **Have Disk**.
+6. Browse to the installation directory. Highlight the netlwf.inf file and click **Open**, then click OK. This should show **NDIS Sample LightWeight Filter** in a list of Network Services. Highlight this and click OK. Click OK. This installs the Ndislwf filter driver.
+
+**Note**  
+
+If you've installed the Ndislwf sample on the target computer before, you can use the [PnPUtil](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550419) tool to delete the older versions from the driver store.
+
+Viewing sample output in the debugger
+-------------------------------------
+
+### Setting up kernel-mode debugging automatically
+
+If you chose to deploy your driver automatically, then kernel debugging is already set up for you.
+
+On the host computer, in **Visual Studio**, in the **Debug** menu, choose **Attach to Process**. For **Transport**, choose **Windows Kernel Mode Debugger**. For **Qualifier**, choose the name of your target computer. Click **Attach**.
+
+**Note**  If you see a dialog box that asks you to allow the debugger to communicate through the firewall, click the boxes for all types of networks. Click **Allow Access**.
+
+For more information, see [Setting Up Kernel-Mode Debugging in Visual Studio](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439376).
+
+### Setting up kernel-mode debugging manually
+
+If you chose to deploy your driver manually, then you need to set up kernel debugging manually. For instructions, see [Setting Up Kernel-Mode Debugging Manually](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439378).
+
+The kernel-mode debuggers (WinDbg.exe and Kd.exe) are included in the WDK.
+
+On the host computer, locate and open a kernel-mode debugger (example: c:\\Program Files (x86)\\Windows Kits\\8.1\\Debuggers\\x64\\windbg.exe). Establish a kernel-mode debugging session between the host and target computers. The details of how to do this depend on the type of debug cable you are using. For information about how to start a debugging session, see [Setting Up Kernel-Mode Debugging Manually](http://msdn.microsoft.com/en-us/library/windows/hardware/hh439378).
+
+Setting kd\_default\_mask
+-------------------------
+
+This sample calls [**DbgPrint**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff543632) to send trace messages to the kernel-mode debugger. To see the trace messages, you must set the value of the **kd\_default\_mask** variable.
+
+On the host computer, break in to the debugger if you are not already broken in. (In the **Debug** menu, choose **Break** or **Break All**, or press **CTRL-Break**). At the debugger command line, enter this command: **ed kd\_default\_mask 0x8**.
+
+To resume execution of the target computer, enter the **g** command in the debugger. (In the **Debug** menu, choose **Continue**.)
+
+Viewing trace messages
+----------------------
+
+On the host computer, in the kernel-mode debugger, verify that you see trace messages similar to these:
+
+<table>
+<colgroup>
+<col width="100%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td align="left"><pre><code>NDISLWF: ===&gt;DriverEntry...
+NDISLWF: ===&gt;FilterRegisterOptions
+NDISLWF: &lt;===FilterRegisterOptions
+NDISLWF: ==&gt;FilterRegisterDevice
+NDISLWF: &lt;==FilterRegisterDevice: 0
+NDISLWF: &lt;===DriverEntry, Status = 0
+NDISLWF: ===&gt;FilterAttach: NdisFilterHandle FFFFE00000F73650
+NDISLWF: &lt;===FilterAttach: Status 0</code></pre></td>
+</tr>
+</tbody>
+</table>
+
+What the Ndislwf sample driver does:
+------------------------------------
+
+1. During [*DriverEntry*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544113), the ndislwf driver registers as an NDIS 6 filter driver.
+2. Later on, NDIS calls Ndislwf's [*FilterAttach*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549905) handler, for each underlying NDIS adapter on which it is configured to attach.
+3. In the context of [*FilterAttach*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549905) Handler, the filter driver calls [**NdisFSetAttributes**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562619) to register its filter module context with NDIS. After that, the filter driver can read its own setting in registry by calling [**NdisOpenConfigurationEx**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff563717), and call other `NdisXxx` functions.
+4. After [*FilterAttach*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549905) successfully returns, NDIS restarts the filter later by calling its [*FilterRestart*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549962) handler. *FilterRestart* should prepare to handle send/receive data. After restart return successfully, filter driver should be able to process send/receive.
+5. All requests and sends coming from overlying drivers for the Ndislwf filter driver are repackaged if necessary and sent down to NDIS, to be passed to the underlying NDIS driver.
+6. All indications arriving from an underlying NDIS driver are forwarded up by Ndislwf filter driver.
+7. NDIS calls the filter's [*FilterPause*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549957) handler when NDIS needs to detach the filter from the stack or there is some configuration changes in the stack. In processing the pause request from NDIS, the Ndislwf driver waits for all its own outstanding requests to be completed before it completes the pause request.
+8. NDIS calls the Ndislwf driver’s [*FilterDetach*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549918) entry point when NDIS needs to detach a filter module from NDIS stack. The *FilterDetach* handler should free all the memory allocation done in [*FilterAttach*](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549905), and undo the operations it did in *FilterAttach* Handler.
+
+
diff --git a/network/ndis/filter/device.c b/network/ndis/filter/device.c
new file mode 100644
index 00000000..48a04876
--- /dev/null
+++ b/network/ndis/filter/device.c
@@ -0,0 +1,289 @@
+/*++
+ *
+ * The file contains the routines to create a device and handle ioctls
+ *
+-- */
+
+#include "precomp.h"
+
+
+#pragma NDIS_INIT_FUNCTION(FilterRegisterDevice)
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+FilterRegisterDevice(
+ VOID
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UNICODE_STRING DeviceName;
+ UNICODE_STRING DeviceLinkUnicodeString;
+ PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceAttribute;
+ PFILTER_DEVICE_EXTENSION FilterDeviceExtension;
+
+ DEBUGP(DL_TRACE, "==>FilterRegisterDevice\n");
+
+ NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+ DispatchTable[IRP_MJ_CREATE] = FilterDispatch;
+ DispatchTable[IRP_MJ_CLEANUP] = FilterDispatch;
+ DispatchTable[IRP_MJ_CLOSE] = FilterDispatch;
+ DispatchTable[IRP_MJ_DEVICE_CONTROL] = FilterDeviceIoControl;
+
+
+ NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
+ NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
+
+ //
+ // Create a device object and register our dispatch handlers
+ //
+ NdisZeroMemory(&DeviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
+
+ DeviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+ DeviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ DeviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
+
+ DeviceAttribute.DeviceName = &DeviceName;
+ DeviceAttribute.SymbolicName = &DeviceLinkUnicodeString;
+ DeviceAttribute.MajorFunctions = &DispatchTable[0];
+ DeviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+ Status = NdisRegisterDeviceEx(
+ FilterDriverHandle,
+ &DeviceAttribute,
+ &DeviceObject,
+ &NdisFilterDeviceHandle
+ );
+
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ FilterDeviceExtension = NdisGetDeviceReservedExtension(DeviceObject);
+
+ FilterDeviceExtension->Signature = 'FTDR';
+ FilterDeviceExtension->Handle = FilterDriverHandle;
+ }
+
+
+ DEBUGP(DL_TRACE, "<==FilterRegisterDevice: %x\n", Status);
+
+ return (Status);
+
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+FilterDeregisterDevice(
+ VOID
+ )
+
+{
+ if (NdisFilterDeviceHandle != NULL)
+ {
+ NdisDeregisterDeviceEx(NdisFilterDeviceHandle);
+ }
+
+ NdisFilterDeviceHandle = NULL;
+
+}
+
+_Use_decl_annotations_
+NTSTATUS
+FilterDispatch(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpStack;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (IrpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ break;
+
+ case IRP_MJ_CLEANUP:
+ break;
+
+ case IRP_MJ_CLOSE:
+ break;
+
+ default:
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+FilterDeviceIoControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILTER_DEVICE_EXTENSION FilterDeviceExtension;
+ PUCHAR InputBuffer;
+ PUCHAR OutputBuffer;
+ ULONG InputBufferLength, OutputBufferLength;
+ PLIST_ENTRY Link;
+ PUCHAR pInfo;
+ ULONG InfoLength = 0;
+ PMS_FILTER pFilter = NULL;
+ BOOLEAN bFalse = FALSE;
+
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (IrpSp->FileObject == NULL)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+
+ FilterDeviceExtension = (PFILTER_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(DeviceObject);
+
+ ASSERT(FilterDeviceExtension->Signature == 'FTDR');
+
+ Irp->IoStatus.Information = 0;
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+
+ case IOCTL_FILTER_RESTART_ALL:
+ break;
+
+ case IOCTL_FILTER_RESTART_ONE_INSTANCE:
+ InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ pFilter = filterFindFilterModule (InputBuffer, InputBufferLength);
+
+ if (pFilter == NULL)
+ {
+
+ break;
+ }
+
+ NdisFRestartFilter(pFilter->FilterHandle);
+
+ break;
+
+ case IOCTL_FILTER_ENUERATE_ALL_INSTANCES:
+
+ InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+
+ pInfo = OutputBuffer;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+
+ Link = FilterModuleList.Flink;
+
+ while (Link != &FilterModuleList)
+ {
+ pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
+
+
+ InfoLength += (pFilter->FilterModuleName.Length + sizeof(USHORT));
+
+ if (InfoLength <= OutputBufferLength)
+ {
+ *(PUSHORT)pInfo = pFilter->FilterModuleName.Length;
+ NdisMoveMemory(pInfo + sizeof(USHORT),
+ (PUCHAR)(pFilter->FilterModuleName.Buffer),
+ pFilter->FilterModuleName.Length);
+
+ pInfo += (pFilter->FilterModuleName.Length + sizeof(USHORT));
+ }
+
+ Link = Link->Flink;
+ }
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ if (InfoLength <= OutputBufferLength)
+ {
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ //
+ // Buffer is small
+ //
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = InfoLength;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+
+
+}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PMS_FILTER
+filterFindFilterModule(
+ _In_reads_bytes_(BufferLength)
+ PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ )
+{
+
+ PMS_FILTER pFilter;
+ PLIST_ENTRY Link;
+ BOOLEAN bFalse = FALSE;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+
+ Link = FilterModuleList.Flink;
+
+ while (Link != &FilterModuleList)
+ {
+ pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
+
+ if (BufferLength >= pFilter->FilterModuleName.Length)
+ {
+ if (NdisEqualMemory(Buffer, pFilter->FilterModuleName.Buffer, pFilter->FilterModuleName.Length))
+ {
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ return pFilter;
+ }
+ }
+
+ Link = Link->Flink;
+ }
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+ return NULL;
+}
+
+
+
+
diff --git a/network/ndis/filter/filter.c b/network/ndis/filter/filter.c
new file mode 100644
index 00000000..0ab6f1ab
--- /dev/null
+++ b/network/ndis/filter/filter.c
@@ -0,0 +1,1903 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ Filter.c
+
+Abstract:
+
+ Sample NDIS Lightweight filter driver
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'PNPF'
+
+// This directive puts the DriverEntry function into the INIT segment of the
+// driver. To conserve memory, the code will be discarded when the driver's
+// DriverEntry function returns. You can declare other functions used only
+// during initialization here.
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+//
+// Global variables
+//
+NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
+NDIS_HANDLE FilterDriverObject;
+NDIS_HANDLE NdisFilterDeviceHandle = NULL;
+PDEVICE_OBJECT DeviceObject = NULL;
+
+FILTER_LOCK FilterListLock;
+LIST_ENTRY FilterModuleList;
+
+NDIS_FILTER_PARTIAL_CHARACTERISTICS DefaultChars = {
+{ 0, 0, 0},
+ 0,
+ FilterSendNetBufferLists,
+ FilterSendNetBufferListsComplete,
+ NULL,
+ FilterReceiveNetBufferLists,
+ FilterReturnNetBufferLists
+};
+
+
+_Use_decl_annotations_
+NTSTATUS
+DriverEntry(
+ PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ First entry point to be called, when this driver is loaded.
+ Register with NDIS as a filter driver and create a device
+ for communication with user-mode.
+
+Arguments:
+
+ DriverObject - pointer to the system's driver object structure
+ for this driver
+
+ RegistryPath - system's registry path for this driver
+
+Return Value:
+
+ STATUS_SUCCESS if all initialization is successful, STATUS_XXX
+ error code if not.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
+ NDIS_STRING ServiceName = RTL_CONSTANT_STRING(FILTER_SERVICE_NAME);
+ NDIS_STRING UniqueName = RTL_CONSTANT_STRING(FILTER_UNIQUE_NAME);
+ NDIS_STRING FriendlyName = RTL_CONSTANT_STRING(FILTER_FRIENDLY_NAME);
+ BOOLEAN bFalse = FALSE;
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ DEBUGP(DL_TRACE, "===>DriverEntry...\n");
+
+ FilterDriverObject = DriverObject;
+
+ do
+ {
+ NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS));
+ FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
+ FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
+#if NDIS_SUPPORT_NDIS61
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2;
+#else
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
+#endif
+
+ FChars.MajorNdisVersion = FILTER_MAJOR_NDIS_VERSION;
+ FChars.MinorNdisVersion = FILTER_MINOR_NDIS_VERSION;
+ FChars.MajorDriverVersion = 1;
+ FChars.MinorDriverVersion = 0;
+ FChars.Flags = 0;
+
+ FChars.FriendlyName = FriendlyName;
+ FChars.UniqueName = UniqueName;
+ FChars.ServiceName = ServiceName;
+
+ //
+ // TODO: Most handlers are optional, however, this sample includes them
+ // all for illustrative purposes. If you do not need a particular
+ // handler, set it to NULL and NDIS will more efficiently pass the
+ // operation through on your behalf.
+ //
+ FChars.SetOptionsHandler = FilterRegisterOptions;
+ FChars.AttachHandler = FilterAttach;
+ FChars.DetachHandler = FilterDetach;
+ FChars.RestartHandler = FilterRestart;
+ FChars.PauseHandler = FilterPause;
+ FChars.SetFilterModuleOptionsHandler = FilterSetModuleOptions;
+ FChars.OidRequestHandler = FilterOidRequest;
+ FChars.OidRequestCompleteHandler = FilterOidRequestComplete;
+ FChars.CancelOidRequestHandler = FilterCancelOidRequest;
+
+ FChars.SendNetBufferListsHandler = FilterSendNetBufferLists;
+ FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists;
+ FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete;
+ FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists;
+ FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify;
+ FChars.NetPnPEventHandler = FilterNetPnPEvent;
+ FChars.StatusHandler = FilterStatus;
+ FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists;
+
+ DriverObject->DriverUnload = FilterUnload;
+
+ FilterDriverHandle = NULL;
+
+ //
+ // Initialize spin locks
+ //
+ FILTER_INIT_LOCK(&FilterListLock);
+
+ InitializeListHead(&FilterModuleList);
+
+ Status = NdisFRegisterFilterDriver(DriverObject,
+ (NDIS_HANDLE)FilterDriverObject,
+ &FChars,
+ &FilterDriverHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "Register filter driver failed.\n");
+ break;
+ }
+
+ Status = FilterRegisterDevice();
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisFDeregisterFilterDriver(FilterDriverHandle);
+ FILTER_FREE_LOCK(&FilterListLock);
+ DEBUGP(DL_WARN, "Register device for the filter driver failed.\n");
+ break;
+ }
+
+
+ }
+ while(bFalse);
+
+
+ DEBUGP(DL_TRACE, "<===DriverEntry, Status = %8x\n", Status);
+ return Status;
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterRegisterOptions(
+ NDIS_HANDLE NdisFilterDriverHandle,
+ NDIS_HANDLE FilterDriverContext
+ )
+/*++
+
+Routine Description:
+
+ Register optional handlers with NDIS. This sample does not happen to
+ have any optional handlers to register, so this routine does nothing
+ and could simply have been omitted. However, for illustrative purposes,
+ it is presented here.
+
+Arguments:
+
+ NdisFilterDriverHandle - pointer the driver handle received from
+ NdisFRegisterFilterDriver
+
+ FilterDriverContext - pointer to our context passed into
+ NdisFRegisterFilterDriver
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ DEBUGP(DL_TRACE, "===>FilterRegisterOptions\n");
+
+ ASSERT(NdisFilterDriverHandle == FilterDriverHandle);
+ ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
+
+ if ((NdisFilterDriverHandle != (NDIS_HANDLE)FilterDriverHandle) ||
+ (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject))
+ {
+ return NDIS_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUGP(DL_TRACE, "<===FilterRegisterOptions\n");
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterAttach(
+ NDIS_HANDLE NdisFilterHandle,
+ NDIS_HANDLE FilterDriverContext,
+ PNDIS_FILTER_ATTACH_PARAMETERS AttachParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter attach routine.
+ Create filter's context, allocate NetBufferLists and NetBuffer pools and any
+ other resources, and read configuration if needed.
+
+Arguments:
+
+ NdisFilterHandle - Specify a handle identifying this instance of the filter. FilterAttach
+ should save this handle. It is a required parameter in subsequent calls
+ to NdisFxxx functions.
+ FilterDriverContext - Filter driver context passed to NdisFRegisterFilterDriver.
+
+ AttachParameters - attach parameters
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS: FilterAttach successfully allocated and initialize data structures
+ for this filter instance.
+ NDIS_STATUS_RESOURCES: FilterAttach failed due to insufficient resources.
+ NDIS_STATUS_FAILURE: FilterAttach could not set up this instance of this filter and it has called
+ NdisWriteErrorLogEntry with parameters specifying the reason for failure.
+
+N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
+ layer can send Irps to the filter.
+
+--*/
+{
+ PMS_FILTER pFilter = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_FILTER_ATTRIBUTES FilterAttributes;
+ ULONG Size;
+ BOOLEAN bFalse = FALSE;
+
+ DEBUGP(DL_TRACE, "===>FilterAttach: NdisFilterHandle %p\n", NdisFilterHandle);
+
+ do
+ {
+ ASSERT(FilterDriverContext == (NDIS_HANDLE)FilterDriverObject);
+ if (FilterDriverContext != (NDIS_HANDLE)FilterDriverObject)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ // Verify the media type is supported. This is a last resort; the
+ // the filter should never have been bound to an unsupported miniport
+ // to begin with. If this driver is marked as a Mandatory filter (which
+ // is the default for this sample; see the INF file), failing to attach
+ // here will leave the network adapter in an unusable state.
+ //
+ // Your setup/install code should not bind the filter to unsupported
+ // media types.
+ if ((AttachParameters->MiniportMediaType != NdisMedium802_3)
+ && (AttachParameters->MiniportMediaType != NdisMediumWan)
+ && (AttachParameters->MiniportMediaType != NdisMediumWirelessWan))
+ {
+ DEBUGP(DL_ERROR, "Unsupported media type.\n");
+
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ Size = sizeof(MS_FILTER) +
+ AttachParameters->FilterModuleGuidName->Length +
+ AttachParameters->BaseMiniportInstanceName->Length +
+ AttachParameters->BaseMiniportName->Length;
+
+ pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);
+ if (pFilter == NULL)
+ {
+ DEBUGP(DL_WARN, "Failed to allocate context structure.\n");
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NdisZeroMemory(pFilter, sizeof(MS_FILTER));
+
+ pFilter->FilterModuleName.Length = pFilter->FilterModuleName.MaximumLength = AttachParameters->FilterModuleGuidName->Length;
+ pFilter->FilterModuleName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER));
+ NdisMoveMemory(pFilter->FilterModuleName.Buffer,
+ AttachParameters->FilterModuleGuidName->Buffer,
+ pFilter->FilterModuleName.Length);
+
+
+
+ pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length;
+ pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter->FilterModuleName.Buffer + pFilter->FilterModuleName.Length);
+ NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer,
+ AttachParameters->BaseMiniportInstanceName->Buffer,
+ pFilter->MiniportFriendlyName.Length);
+
+
+ pFilter->MiniportName.Length = pFilter->MiniportName.MaximumLength = AttachParameters->BaseMiniportName->Length;
+ pFilter->MiniportName.Buffer = (PWSTR)((PUCHAR)pFilter->MiniportFriendlyName.Buffer +
+ pFilter->MiniportFriendlyName.Length);
+ NdisMoveMemory(pFilter->MiniportName.Buffer,
+ AttachParameters->BaseMiniportName->Buffer,
+ pFilter->MiniportName.Length);
+
+ pFilter->MiniportIfIndex = AttachParameters->BaseMiniportIfIndex;
+ //
+ // The filter should initialize TrackReceives and TrackSends properly. For this
+ // driver, since its default characteristic has both a send and a receive handler,
+ // these fields are initialized to TRUE.
+ //
+ pFilter->TrackReceives = TRUE;
+ pFilter->TrackSends = TRUE;
+ pFilter->FilterHandle = NdisFilterHandle;
+
+
+ NdisZeroMemory(&FilterAttributes, sizeof(NDIS_FILTER_ATTRIBUTES));
+ FilterAttributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
+ FilterAttributes.Header.Size = sizeof(NDIS_FILTER_ATTRIBUTES);
+ FilterAttributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
+ FilterAttributes.Flags = 0;
+
+ NDIS_DECLARE_FILTER_MODULE_CONTEXT(MS_FILTER);
+ Status = NdisFSetAttributes(NdisFilterHandle,
+ pFilter,
+ &FilterAttributes);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "Failed to set attributes.\n");
+ break;
+ }
+
+
+ pFilter->State = FilterPaused;
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ InsertHeadList(&FilterModuleList, &pFilter->FilterModuleLink);
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+ }
+ while (bFalse);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pFilter != NULL)
+ {
+ FILTER_FREE_MEM(pFilter);
+ }
+ }
+
+ DEBUGP(DL_TRACE, "<===FilterAttach: Status %x\n", Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterPause(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter pause routine.
+ Complete all the outstanding sends and queued sends,
+ wait for all the outstanding recvs to be returned
+ and return all the queued receives.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context stucture
+ PauseParameters - additional information about the pause
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if filter pauses successfully, NDIS_STATUS_PENDING
+ if not. No other return value is allowed (pause must succeed, eventually).
+
+N.B.: When the filter is in Pausing state, it can still process OID requests,
+ complete sending, and returning packets to NDIS, and also indicate status.
+ After this function completes, the filter must not attempt to send or
+ receive packets, but it may still process OID requests and status
+ indications.
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext);
+ NDIS_STATUS Status;
+ BOOLEAN bFalse = FALSE;
+
+ UNREFERENCED_PARAMETER(PauseParameters);
+
+ DEBUGP(DL_TRACE, "===>NDISLWF FilterPause: FilterInstance %p\n", FilterModuleContext);
+
+ //
+ // Set the flag that the filter is going to pause
+ //
+ FILTER_ASSERT(pFilter->State == FilterRunning);
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ pFilter->State = FilterPausing;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+ //
+ // Do whatever work is required to bring the filter into the Paused state.
+ //
+ // If you have diverted and queued any send or receive NBLs, return them
+ // now.
+ //
+ // If you send or receive original NBLs, stop doing that and wait for your
+ // NBLs to return to you now.
+ //
+
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ pFilter->State = FilterPaused;
+
+ DEBUGP(DL_TRACE, "<===FilterPause: Status %x\n", Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterRestart(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_FILTER_RESTART_PARAMETERS RestartParameters
+ )
+/*++
+
+Routine Description:
+
+ Filter restart routine.
+ Start the datapath - begin sending and receiving NBLs.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context stucture.
+ RestartParameters - additional information about the restart operation.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS: if filter restarts successfully
+ NDIS_STATUS_XXX: Otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_HANDLE ConfigurationHandle = NULL;
+
+
+ PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
+ PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
+ NDIS_CONFIGURATION_OBJECT ConfigObject;
+
+ DEBUGP(DL_TRACE, "===>FilterRestart: FilterModuleContext %p\n", FilterModuleContext);
+
+ FILTER_ASSERT(pFilter->State == FilterPaused);
+
+ ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ ConfigObject.NdisHandle = FilterDriverHandle;
+ ConfigObject.Flags = 0;
+
+ Status = NdisOpenConfigurationEx(&ConfigObject, &ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Filter driver can choose to fail the restart if it cannot open the configuration
+ //
+
+#if 0
+ //
+ // The code is here just to demonstrate how to call NDIS to write an
+ // event to the eventlog.
+ //
+ PWCHAR ErrorString = L"Ndislwf";
+
+ DEBUGP(DL_WARN, "FilterRestart: Cannot open configuration.\n");
+ NdisWriteEventLogEntry(FilterDriverObject,
+ EVENT_NDIS_DRIVER_FAILURE,
+ 0,
+ 1,
+ &ErrorString,
+ sizeof(Status),
+ &Status);
+#endif
+
+ }
+
+ //
+ // This sample doesn't actually do anything with the configuration handle;
+ // it is opened here for illustrative purposes. If you do not need to
+ // read configuration, you may omit the code manipulating the
+ // ConfigurationHandle.
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisCloseConfiguration(ConfigurationHandle);
+ }
+
+ NdisRestartAttributes = RestartParameters->RestartAttributes;
+
+ //
+ // If NdisRestartAttributes is not NULL, then the filter can modify generic
+ // attributes and add new media specific info attributes at the end.
+ // Otherwise, if NdisRestartAttributes is NULL, the filter should not try to
+ // modify/add attributes.
+ //
+ if (NdisRestartAttributes != NULL)
+ {
+ PNDIS_RESTART_ATTRIBUTES NextAttributes;
+
+ ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);
+
+ NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;
+
+ //
+ // Check to see if we need to change any attributes. For example, the
+ // driver can change the current MAC address here. Or the driver can add
+ // media specific info attributes.
+ //
+ NdisGeneralAttributes->LookaheadSize = 128;
+
+ //
+ // Check each attribute to see whether the filter needs to modify it.
+ //
+ NextAttributes = NdisRestartAttributes->Next;
+
+ while (NextAttributes != NULL)
+ {
+ //
+ // If somehow the filter needs to change a attributes which requires more space then
+ // the current attributes:
+ // 1. Remove the attribute from the Attributes list:
+ // TempAttributes = NextAttributes;
+ // NextAttributes = NextAttributes->Next;
+ // 2. Free the memory for the current attributes: NdisFreeMemory(TempAttributes, 0 , 0);
+ // 3. Dynamically allocate the memory for the new attributes by calling
+ // NdisAllocateMemoryWithTagPriority:
+ // NewAttributes = NdisAllocateMemoryWithTagPriority(Handle, size, Priority);
+ // 4. Fill in the new attribute
+ // 5. NewAttributes->Next = NextAttributes;
+ // 6. NextAttributes = NewAttributes; // Just to make the next statement work.
+ //
+ NextAttributes = NextAttributes->Next;
+ }
+
+ //
+ // Add a new attributes at the end
+ // 1. Dynamically allocate the memory for the new attributes by calling
+ // NdisAllocateMemoryWithTagPriority.
+ // 2. Fill in the new attribute
+ // 3. NextAttributes->Next = NewAttributes;
+ // 4. NewAttributes->Next = NULL;
+
+
+
+ }
+
+ //
+ // If everything is OK, set the filter in running state.
+ //
+ pFilter->State = FilterRunning; // when successful
+
+
+ Status = NDIS_STATUS_SUCCESS;
+
+
+ //
+ // Ensure the state is Paused if restart failed.
+ //
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ pFilter->State = FilterPaused;
+ }
+
+
+ DEBUGP(DL_TRACE, "<===FilterRestart: FilterModuleContext %p, Status %x\n", FilterModuleContext, Status);
+ return Status;
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterDetach(
+ NDIS_HANDLE FilterModuleContext
+ )
+/*++
+
+Routine Description:
+
+ Filter detach routine.
+ This is a required function that will deallocate all the resources allocated during
+ FilterAttach. NDIS calls FilterAttach to remove a filter instance from a filter stack.
+
+Arguments:
+
+ FilterModuleContext - pointer to the filter context area.
+
+Return Value:
+ None.
+
+NOTE: Called at PASSIVE_LEVEL and the filter is in paused state
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ BOOLEAN bFalse = FALSE;
+
+
+ DEBUGP(DL_TRACE, "===>FilterDetach: FilterInstance %p\n", FilterModuleContext);
+
+
+ //
+ // Filter must be in paused state
+ //
+ FILTER_ASSERT(pFilter->State == FilterPaused);
+
+
+ //
+ // Detach must not fail, so do not put any code here that can possibly fail.
+ //
+
+ //
+ // Free filter instance name if allocated.
+ //
+ if (pFilter->FilterName.Buffer != NULL)
+ {
+ FILTER_FREE_MEM(pFilter->FilterName.Buffer);
+ }
+
+
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ RemoveEntryList(&pFilter->FilterModuleLink);
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+
+ //
+ // Free the memory allocated
+ FILTER_FREE_MEM(pFilter);
+
+ DEBUGP(DL_TRACE, "<===FilterDetach Successfully\n");
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+FilterUnload(
+ PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ Filter driver's unload routine.
+ Deregister the driver from NDIS.
+
+Arguments:
+
+ DriverObject - pointer to the system's driver object structure
+ for this driver
+
+Return Value:
+
+ NONE
+
+--*/
+{
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ DEBUGP(DL_TRACE, "===>FilterUnload\n");
+
+ //
+ // Should free the filter context list
+ //
+ FilterDeregisterDevice();
+ NdisFDeregisterFilterDriver(FilterDriverHandle);
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);
+ ASSERT(IsListEmpty(&FilterModuleList));
+
+ FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
+
+#endif
+
+ FILTER_FREE_LOCK(&FilterListLock);
+
+ DEBUGP(DL_TRACE, "<===FilterUnload\n");
+
+ return;
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterOidRequest(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_OID_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ Request handler
+ Handle requests from upper layers
+
+Arguments:
+
+ FilterModuleContext - our filter
+ Request - the request passed down
+
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_XXX
+
+NOTE: Called at <= DISPATCH_LEVEL (unlike a miniport's MiniportOidRequest)
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_STATUS Status;
+ PNDIS_OID_REQUEST ClonedRequest=NULL;
+ BOOLEAN bSubmitted = FALSE;
+ PFILTER_REQUEST_CONTEXT Context;
+ BOOLEAN bFalse = FALSE;
+
+
+ DEBUGP(DL_TRACE, "===>FilterOidRequest: Request %p.\n", Request);
+
+ //
+ // Most of the time, a filter will clone the OID request and pass down
+ // the clone. When the clone completes, the filter completes the original
+ // OID request.
+ //
+ // If your filter needs to modify a specific request, it can modify the
+ // request before or after sending down the cloned request. Or, it can
+ // complete the original request on its own without sending down any
+ // clone at all.
+ //
+ // If your filter driver does not need to modify any OID requests, then
+ // you may simply omit this routine entirely; NDIS will pass OID requests
+ // down on your behalf. This is more efficient than implementing a
+ // routine that does nothing but clone all requests, as in the sample here.
+ //
+
+ do
+ {
+ Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle,
+ Request,
+ FILTER_TAG,
+ &ClonedRequest);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, "FilerOidRequest: Cannot Clone Request\n");
+ break;
+ }
+
+ Context = (PFILTER_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]);
+ *Context = Request;
+
+ bSubmitted = TRUE;
+
+ //
+ // Use same request ID
+ //
+ ClonedRequest->RequestId = Request->RequestId;
+
+ pFilter->PendingOidRequest = ClonedRequest;
+
+
+ Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+
+
+ FilterOidRequestComplete(pFilter, ClonedRequest, Status);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+
+ }while (bFalse);
+
+ if (bSubmitted == FALSE)
+ {
+ switch(Request->RequestType)
+ {
+ case NdisRequestMethod:
+ Request->DATA.METHOD_INFORMATION.BytesRead = 0;
+ Request->DATA.METHOD_INFORMATION.BytesNeeded = 0;
+ Request->DATA.METHOD_INFORMATION.BytesWritten = 0;
+ break;
+
+ case NdisRequestSetInformation:
+ Request->DATA.SET_INFORMATION.BytesRead = 0;
+ Request->DATA.SET_INFORMATION.BytesNeeded = 0;
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
+ Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
+ break;
+ }
+
+ }
+ DEBUGP(DL_TRACE, "<===FilterOidRequest: Status %8x.\n", Status);
+
+ return Status;
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterCancelOidRequest(
+ NDIS_HANDLE FilterModuleContext,
+ PVOID RequestId
+ )
+/*++
+
+Routine Description:
+
+ Cancels an OID request
+
+ If your filter driver does not intercept and hold onto any OID requests,
+ then you do not need to implement this routine. You may simply omit it.
+ Furthermore, if the filter only holds onto OID requests so it can pass
+ down a clone (the most common case) the filter does not need to implement
+ this routine; NDIS will then automatically request that the lower-level
+ filter/miniport cancel your cloned OID.
+
+ Most filters do not need to implement this routine.
+
+Arguments:
+
+ FilterModuleContext - our filter
+ RequestId - identifies the request(s) to cancel
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNDIS_OID_REQUEST Request = NULL;
+ PFILTER_REQUEST_CONTEXT Context;
+ PNDIS_OID_REQUEST OriginalRequest = NULL;
+ BOOLEAN bFalse = FALSE;
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+
+ Request = pFilter->PendingOidRequest;
+
+ if (Request != NULL)
+ {
+ Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
+
+ OriginalRequest = (*Context);
+ }
+
+ if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId))
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+ NdisFCancelOidRequest(pFilter->FilterHandle, RequestId);
+ }
+ else
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+ }
+
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterOidRequestComplete(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_OID_REQUEST Request,
+ NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Notification that an OID request has been completed
+
+ If this filter sends a request down to a lower layer, and the request is
+ pended, the FilterOidRequestComplete routine is invoked when the request
+ is complete. Most requests we've sent are simply clones of requests
+ received from a higher layer; all we need to do is complete the original
+ higher request.
+
+ However, if this filter driver sends original requests down, it must not
+ attempt to complete a pending request to the higher layer.
+
+Arguments:
+
+ FilterModuleContext - our filter context area
+ NdisRequest - the completed request
+ Status - completion status
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNDIS_OID_REQUEST OriginalRequest;
+ PFILTER_REQUEST_CONTEXT Context;
+ BOOLEAN bFalse = FALSE;
+
+ DEBUGP(DL_TRACE, "===>FilterOidRequestComplete, Request %p.\n", Request);
+
+ Context = (PFILTER_REQUEST_CONTEXT)(&Request->SourceReserved[0]);
+ OriginalRequest = (*Context);
+
+ //
+ // This is an internal request
+ //
+ if (OriginalRequest == NULL)
+ {
+ filterInternalRequestComplete(pFilter, Request, Status);
+ return;
+ }
+
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+
+ ASSERT(pFilter->PendingOidRequest == Request);
+ pFilter->PendingOidRequest = NULL;
+
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+
+
+ //
+ // Copy the information from the returned request to the original request
+ //
+ switch(Request->RequestType)
+ {
+ case NdisRequestMethod:
+ OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded;
+ OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten;
+ break;
+
+ case NdisRequestSetInformation:
+ OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead;
+ OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded;
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten;
+ OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded;
+ break;
+ }
+
+
+ (*Context) = NULL;
+
+ NdisFreeCloneOidRequest(pFilter->FilterHandle, Request);
+
+ NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status);
+
+ DEBUGP(DL_TRACE, "<===FilterOidRequestComplete.\n");
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterStatus(
+ NDIS_HANDLE FilterModuleContext,
+ PNDIS_STATUS_INDICATION StatusIndication
+ )
+/*++
+
+Routine Description:
+
+ Status indication handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ StatusIndication - the status being indicated
+
+NOTE: called at <= DISPATCH_LEVEL
+
+ FILTER driver may call NdisFIndicateStatus to generate a status indication to
+ all higher layer modules.
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ DEBUGP(DL_TRACE, "===>FilterStatus, IndicateStatus = %8x.\n", StatusIndication->StatusCode);
+
+
+ //
+ // The filter may do processing on the status indication here, including
+ // intercepting and dropping it entirely. However, the sample does nothing
+ // with status indications except pass them up to the higher layer. It is
+ // more efficient to omit the FilterStatus handler entirely if it does
+ // nothing, but it is included in this sample for illustrative purposes.
+ //
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ ASSERT(pFilter->bIndicating == FALSE);
+ pFilter->bIndicating = TRUE;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+#endif // DBG
+
+ NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication);
+
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, bFalse);
+ ASSERT(pFilter->bIndicating == TRUE);
+ pFilter->bIndicating = FALSE;
+ FILTER_RELEASE_LOCK(&pFilter->Lock, bFalse);
+#endif // DBG
+
+ DEBUGP(DL_TRACE, "<===FilterStatus.\n");
+
+}
+
+_Use_decl_annotations_
+VOID
+FilterDevicePnPEventNotify(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
+ )
+/*++
+
+Routine Description:
+
+ Device PNP event handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetDevicePnPEvent - a Device PnP event
+
+NOTE: called at PASSIVE_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent;
+#if DBG
+ BOOLEAN bFalse = FALSE;
+#endif
+
+ DEBUGP(DL_TRACE, "===>FilterDevicePnPEventNotify: NetPnPEvent = %p.\n", NetDevicePnPEvent);
+
+ //
+ // The filter may do processing on the event here, including intercepting
+ // and dropping it entirely. However, the sample does nothing with Device
+ // PNP events, except pass them down to the next lower* layer. It is more
+ // efficient to omit the FilterDevicePnPEventNotify handler entirely if it
+ // does nothing, but it is included in this sample for illustrative purposes.
+ //
+ // * Trivia: Device PNP events percolate DOWN the stack, instead of upwards
+ // like status indications and Net PNP events. So the next layer is the
+ // LOWER layer.
+ //
+
+ switch (DevicePnPEvent)
+ {
+
+ case NdisDevicePnPEventQueryRemoved:
+ case NdisDevicePnPEventRemoved:
+ case NdisDevicePnPEventSurpriseRemoved:
+ case NdisDevicePnPEventQueryStopped:
+ case NdisDevicePnPEventStopped:
+ case NdisDevicePnPEventPowerProfileChanged:
+ case NdisDevicePnPEventFilterListChanged:
+
+ break;
+
+ default:
+ DEBUGP(DL_ERROR, "FilterDevicePnPEventNotify: Invalid event.\n");
+ FILTER_ASSERT(bFalse);
+
+ break;
+ }
+
+ NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent);
+
+ DEBUGP(DL_TRACE, "<===FilterDevicePnPEventNotify\n");
+
+}
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterNetPnPEvent(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification
+ )
+/*++
+
+Routine Description:
+
+ Net PNP event handler
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetPnPEventNotification - a Net PnP event
+
+NOTE: called at PASSIVE_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // The filter may do processing on the event here, including intercepting
+ // and dropping it entirely. However, the sample does nothing with Net PNP
+ // events, except pass them up to the next higher layer. It is more
+ // efficient to omit the FilterNetPnPEvent handler entirely if it does
+ // nothing, but it is included in this sample for illustrative purposes.
+ //
+
+ Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification);
+
+ return Status;
+}
+
+_Use_decl_annotations_
+VOID
+FilterSendNetBufferListsComplete(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG SendCompleteFlags
+ )
+/*++
+
+Routine Description:
+
+ Send complete handler
+
+ This routine is invoked whenever the lower layer is finished processing
+ sent NET_BUFFER_LISTs. If the filter does not need to be involved in the
+ send path, you should remove this routine and the FilterSendNetBufferLists
+ routine. NDIS will pass along send packets on behalf of your filter more
+ efficiently than the filter can.
+
+Arguments:
+
+ FilterModuleContext - our filter context
+ NetBufferLists - a chain of NBLs that are being returned to you
+ SendCompleteFlags - flags (see documentation)
+
+Return Value:
+
+ NONE
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ ULONG NumOfSendCompletes = 0;
+ BOOLEAN DispatchLevel;
+ PNET_BUFFER_LIST CurrNbl;
+
+ DEBUGP(DL_TRACE, "===>SendNBLComplete, NetBufferList: %p.\n", NetBufferLists);
+
+
+ //
+ // If your filter injected any send packets into the datapath to be sent,
+ // you must identify their NBLs here and remove them from the chain. Do not
+ // attempt to send-complete your NBLs up to the higher layer.
+ //
+
+ //
+ // If your filter has modified any NBLs (or NBs, MDLs, etc) in your
+ // FilterSendNetBufferLists handler, you must undo the modifications here.
+ // In general, NBLs must be returned in the same condition in which you had
+ // you received them. (Exceptions: the NBLs can be re-ordered on the linked
+ // list, and the scratch fields are don't-care).
+ //
+
+ if (pFilter->TrackSends)
+ {
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ NumOfSendCompletes++;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+
+ }
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingSends -= NumOfSendCompletes;
+ FILTER_LOG_SEND_REF(2, pFilter, PrevNbl, pFilter->OutstandingSends);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ // Send complete the NBLs. If you removed any NBLs from the chain, make
+ // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
+
+ NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, SendCompleteFlags);
+
+ DEBUGP(DL_TRACE, "<===SendNBLComplete.\n");
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterSendNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ NDIS_PORT_NUMBER PortNumber,
+ ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ Send Net Buffer List handler
+ This function is an optional function for filter drivers. If provided, NDIS
+ will call this function to transmit a linked list of NetBuffers, described by a
+ NetBufferList, over the network. If this handler is NULL, NDIS will skip calling
+ this filter when sending a NetBufferList and will call the next lower
+ driver in the stack. A filter that doesn't provide a FilerSendNetBufferList
+ handler can not originate a send on its own.
+
+Arguments:
+
+ FilterModuleContext - our filter context area
+ NetBufferLists - a List of NetBufferLists to send
+ PortNumber - Port Number to which this send is targeted
+ SendFlags - specifies if the call is at DISPATCH_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNET_BUFFER_LIST CurrNbl;
+ BOOLEAN DispatchLevel;
+ BOOLEAN bFalse = FALSE;
+
+ DEBUGP(DL_TRACE, "===>SendNetBufferList: NBL = %p.\n", NetBufferLists);
+
+ do
+ {
+
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
+#if DBG
+ //
+ // we should never get packets to send if we are not in running state
+ //
+
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ //
+ // If the filter is not in running state, fail the send
+ //
+ if (pFilter->State != FilterRunning)
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ NdisFSendNetBufferListsComplete(pFilter->FilterHandle,
+ NetBufferLists,
+ DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ break;
+
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+#endif
+ if (pFilter->TrackSends)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ pFilter->OutstandingSends++;
+ FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);
+
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ //
+ // If necessary, queue the NetBufferLists in a local structure for later
+ // processing. However, do not queue them for "too long", or else the
+ // system's performance may be degraded. If you need to hold onto an
+ // NBL for an unbounded amount of time, then allocate memory, perform a
+ // deep copy, and complete the original NBL.
+ //
+
+ NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);
+
+
+ }
+ while (bFalse);
+
+ DEBUGP(DL_TRACE, "<===SendNetBufferList. \n");
+}
+
+_Use_decl_annotations_
+VOID
+FilterReturnNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ ULONG ReturnFlags
+ )
+/*++
+
+Routine Description:
+
+ FilterReturnNetBufferLists handler.
+ FilterReturnNetBufferLists is an optional function. If provided, NDIS calls
+ FilterReturnNetBufferLists to return the ownership of one or more NetBufferLists
+ and their embedded NetBuffers to the filter driver. If this handler is NULL, NDIS
+ will skip calling this filter when returning NetBufferLists to the underlying
+ miniport and will call the next lower driver in the stack. A filter that doesn't
+ provide a FilterReturnNetBufferLists handler cannot originate a receive indication
+ on its own.
+
+Arguments:
+
+ FilterInstanceContext - our filter context area
+ NetBufferLists - a linked list of NetBufferLists that this
+ filter driver indicated in a previous call to
+ NdisFIndicateReceiveNetBufferLists
+ ReturnFlags - flags specifying if the caller is at DISPATCH_LEVEL
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ PNET_BUFFER_LIST CurrNbl = NetBufferLists;
+ UINT NumOfNetBufferLists = 0;
+ BOOLEAN DispatchLevel;
+ ULONG Ref;
+
+ DEBUGP(DL_TRACE, "===>ReturnNetBufferLists, NetBufferLists is %p.\n", NetBufferLists);
+
+
+ //
+ // If your filter injected any receive packets into the datapath to be
+ // received, you must identify their NBLs here and remove them from the
+ // chain. Do not attempt to receive-return your NBLs down to the lower
+ // layer.
+ //
+
+ //
+ // If your filter has modified any NBLs (or NBs, MDLs, etc) in your
+ // FilterReceiveNetBufferLists handler, you must undo the modifications here.
+ // In general, NBLs must be returned in the same condition in which you had
+ // you received them. (Exceptions: the NBLs can be re-ordered on the linked
+ // list, and the scratch fields are don't-care).
+ //
+
+ if (pFilter->TrackReceives)
+ {
+ while (CurrNbl)
+ {
+ NumOfNetBufferLists ++;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+ }
+
+
+ // Return the received NBLs. If you removed any NBLs from the chain, make
+ // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
+
+ NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
+
+ if (pFilter->TrackReceives)
+ {
+ DispatchLevel = NDIS_TEST_RETURN_AT_DISPATCH_LEVEL(ReturnFlags);
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ pFilter->OutstandingRcvs -= NumOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+ FILTER_LOG_RCV_REF(3, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+
+ DEBUGP(DL_TRACE, "<===ReturnNetBufferLists.\n");
+
+
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterReceiveNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PNET_BUFFER_LIST NetBufferLists,
+ NDIS_PORT_NUMBER PortNumber,
+ ULONG NumberOfNetBufferLists,
+ ULONG ReceiveFlags
+ )
+/*++
+
+Routine Description:
+
+ FilerReceiveNetBufferLists is an optional function for filter drivers.
+ If provided, this function processes receive indications made by underlying
+ NIC or lower level filter drivers. This function can also be called as a
+ result of loopback. If this handler is NULL, NDIS will skip calling this
+ filter when processing a receive indication and will call the next higher
+ driver in the stack. A filter that doesn't provide a
+ FilterReceiveNetBufferLists handler cannot provide a
+ FilterReturnNetBufferLists handler and cannot a initiate an original receive
+ indication on its own.
+
+Arguments:
+
+ FilterModuleContext - our filter context area.
+ NetBufferLists - a linked list of NetBufferLists
+ PortNumber - Port on which the receive is indicated
+ ReceiveFlags -
+
+N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND.
+ This controls whether the receive indication is an synchronous or
+ asynchronous function call.
+
+--*/
+{
+
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ BOOLEAN DispatchLevel;
+ ULONG Ref;
+ BOOLEAN bFalse = FALSE;
+#if DBG
+ ULONG ReturnFlags;
+#endif
+
+ DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
+ do
+ {
+
+ DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
+#if DBG
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ if (pFilter->State != FilterRunning)
+ {
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+
+ if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
+ {
+ ReturnFlags = 0;
+ if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
+ {
+ NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
+ }
+ break;
+ }
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+#endif
+
+ ASSERT(NumberOfNetBufferLists >= 1);
+
+ //
+ // If you would like to drop a received packet, then you must carefully
+ // modify the NBL chain as follows:
+ //
+ // if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
+ // For each NBL that is NOT dropped, temporarily unlink it from
+ // the linked list, and indicate it up alone with
+ // NdisFIndicateReceiveNetBufferLists and the
+ // NDIS_RECEIVE_FLAGS_RESOURCES flag set. Then immediately
+ // relink the NBL back into the chain. When all NBLs have been
+ // indicated up, you may return from this function.
+ // otherwise (NDIS_TEST_RECEIVE_CANNOT_PEND is FALSE):
+ // Divide the linked list of NBLs into two chains: one chain
+ // of packets to drop, and everything else in another chain.
+ // Return the first chain with NdisFReturnNetBufferLists, and
+ // indicate up the rest with NdisFIndicateReceiveNetBufferLists.
+ //
+ // Note: on the receive path for Ethernet packets, one NBL will have
+ // exactly one NB. So (assuming you are receiving on Ethernet, or are
+ // attached above Native WiFi) you do not need to worry about dropping
+ // one NB, but trying to indicate up the remaining NBs on the same NBL.
+ // In other words, if the first NB should be dropped, drop the whole NBL.
+ //
+
+ //
+ // If you would like to modify a packet, and can do so quickly, you may
+ // do it here. However, make sure you save enough information to undo
+ // your modification in the FilterReturnNetBufferLists handler.
+ //
+
+ //
+ // If necessary, queue the NetBufferLists in a local structure for later
+ // processing. However, do not queue them for "too long", or else the
+ // system's performance may be degraded. If you need to hold onto an
+ // NBL for an unbounded amount of time, then allocate memory, perform a
+ // deep copy, and return the original NBL.
+ //
+
+ if (pFilter->TrackReceives)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingRcvs += NumberOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+
+ FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ NdisFIndicateReceiveNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferLists,
+ PortNumber,
+ NumberOfNetBufferLists,
+ ReceiveFlags);
+
+
+ if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
+ pFilter->TrackReceives)
+ {
+ FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
+ pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
+ Ref = pFilter->OutstandingRcvs;
+ FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
+ FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
+ }
+
+ } while (bFalse);
+
+ DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);
+
+}
+
+
+_Use_decl_annotations_
+VOID
+FilterCancelSendNetBufferLists(
+ NDIS_HANDLE FilterModuleContext,
+ PVOID CancelId
+ )
+/*++
+
+Routine Description:
+
+ This function cancels any NET_BUFFER_LISTs pended in the filter and then
+ calls the NdisFCancelSendNetBufferLists to propagate the cancel operation.
+
+ If your driver does not queue any send NBLs, you may omit this routine.
+ NDIS will propagate the cancelation on your behalf more efficiently.
+
+Arguments:
+
+ FilterModuleContext - our filter context area.
+ CancelId - an identifier for all NBLs that should be dequeued
+
+Return Value:
+
+ None
+
+*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+
+ NdisFCancelSendNetBufferLists(pFilter->FilterHandle, CancelId);
+}
+
+
+_Use_decl_annotations_
+NDIS_STATUS
+FilterSetModuleOptions(
+ NDIS_HANDLE FilterModuleContext
+ )
+/*++
+
+Routine Description:
+
+ This function set the optional handlers for the filter
+
+Arguments:
+
+ FilterModuleContext: The FilterModuleContext given to NdisFSetAttributes
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_RESOURCES
+ NDIS_STATUS_FAILURE
+
+--*/
+{
+ PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
+ NDIS_FILTER_PARTIAL_CHARACTERISTICS OptionalHandlers;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ BOOLEAN bFalse = FALSE;
+
+ //
+ // Demonstrate how to change send/receive handlers at runtime.
+ //
+ if (bFalse)
+ {
+ UINT i;
+
+
+ pFilter->CallsRestart++;
+
+ i = pFilter->CallsRestart % 8;
+
+ pFilter->TrackReceives = TRUE;
+ pFilter->TrackSends = TRUE;
+
+ NdisMoveMemory(&OptionalHandlers, &DefaultChars, sizeof(OptionalHandlers));
+ OptionalHandlers.Header.Type = NDIS_OBJECT_TYPE_FILTER_PARTIAL_CHARACTERISTICS;
+ OptionalHandlers.Header.Size = sizeof(OptionalHandlers);
+ switch (i)
+ {
+
+ case 0:
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ pFilter->TrackReceives = FALSE;
+ break;
+
+ case 1:
+
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ pFilter->TrackReceives = FALSE;
+ break;
+
+ case 2:
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ pFilter->TrackSends = FALSE;
+ break;
+
+ case 3:
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ pFilter->TrackSends = FALSE;
+ break;
+
+ case 4:
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ break;
+
+ case 5:
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ break;
+
+ case 6:
+
+ OptionalHandlers.ReceiveNetBufferListsHandler = NULL;
+ OptionalHandlers.ReturnNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsHandler = NULL;
+ OptionalHandlers.SendNetBufferListsCompleteHandler = NULL;
+ break;
+
+ case 7:
+ break;
+ }
+ Status = NdisSetOptionalHandlers(pFilter->FilterHandle, (PNDIS_DRIVER_OPTIONAL_HANDLERS)&OptionalHandlers );
+ }
+ return Status;
+}
+
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NDIS_STATUS
+filterDoInternalRequest(
+ _In_ PMS_FILTER FilterModuleContext,
+ _In_ NDIS_REQUEST_TYPE RequestType,
+ _In_ NDIS_OID Oid,
+ _Inout_updates_bytes_to_(InformationBufferLength, *pBytesProcessed)
+ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _In_opt_ ULONG OutputBufferLength,
+ _In_ ULONG MethodId,
+ _Out_ PULONG pBytesProcessed
+ )
+/*++
+
+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.
+
+Arguments:
+
+ FilterModuleContext - pointer to our filter module context
+ 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
+ pBytesProcessed - place to return bytes read/written
+
+Return Value:
+
+ Status of the set/query request
+
+--*/
+{
+ FILTER_REQUEST FilterRequest;
+ PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request;
+ NDIS_STATUS Status;
+ BOOLEAN bFalse;
+
+
+ bFalse = FALSE;
+ *pBytesProcessed = 0;
+ NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));
+
+ NdisInitializeEvent(&FilterRequest.ReqEvent);
+
+ NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
+ NdisRequest->RequestType = RequestType;
+
+ switch (RequestType)
+ {
+ case NdisRequestQueryInformation:
+ NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ case NdisRequestSetInformation:
+ NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ case NdisRequestMethod:
+ NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
+ NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
+ NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength =
+ InformationBufferLength;
+ NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
+ break;
+
+
+
+ default:
+ FILTER_ASSERT(bFalse);
+ break;
+ }
+
+ NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;
+
+ Status = NdisFOidRequest(FilterModuleContext->FilterHandle,
+ NdisRequest);
+
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+
+ NdisWaitEvent(&FilterRequest.ReqEvent, 0);
+ Status = FilterRequest.Status;
+ }
+
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (RequestType == NdisRequestSetInformation)
+ {
+ *pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
+ }
+
+ if (RequestType == NdisRequestQueryInformation)
+ {
+ *pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ }
+
+ if (RequestType == NdisRequestMethod)
+ {
+ *pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
+ }
+
+ //
+ // The driver below should set the correct value to BytesWritten
+ // or BytesRead. But now, we just truncate the value to InformationBufferLength
+ //
+ if (RequestType == NdisRequestMethod)
+ {
+ if (*pBytesProcessed > OutputBufferLength)
+ {
+ *pBytesProcessed = OutputBufferLength;
+ }
+ }
+ else
+ {
+
+ if (*pBytesProcessed > InformationBufferLength)
+ {
+ *pBytesProcessed = InformationBufferLength;
+ }
+ }
+ }
+
+
+ return Status;
+}
+
+VOID
+filterInternalRequestComplete(
+ _In_ NDIS_HANDLE FilterModuleContext,
+ _In_ PNDIS_OID_REQUEST NdisRequest,
+ _In_ NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ NDIS entry point indicating completion of a pended NDIS_OID_REQUEST.
+
+Arguments:
+
+ FilterModuleContext - pointer to filter module context
+ NdisRequest - pointer to NDIS request
+ Status - status of request completion
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFILTER_REQUEST FilterRequest;
+
+
+ UNREFERENCED_PARAMETER(FilterModuleContext);
+
+ //
+ // Get at the request context.
+ //
+ FilterRequest = CONTAINING_RECORD(NdisRequest, FILTER_REQUEST, Request);
+
+ //
+ // Save away the completion status.
+ //
+ FilterRequest->Status = Status;
+
+ //
+ // Wake up the thread blocked for this request to complete.
+ //
+ NdisSetEvent(&FilterRequest->ReqEvent);
+}
+
diff --git a/network/ndis/filter/filter.h b/network/ndis/filter/filter.h
new file mode 100644
index 00000000..42c5d913
--- /dev/null
+++ b/network/ndis/filter/filter.h
@@ -0,0 +1,456 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ Filter.h
+
+Abstract:
+
+ This module contains all prototypes and macros for filter code.
+
+Notes:
+
+--*/
+#ifndef _FILT_H
+#define _FILT_H
+
+#pragma warning(disable:28930) // Unused assignment of pointer, by design in samples
+#pragma warning(disable:28931) // Unused assignment of variable, by design in samples
+
+// TODO: Customize these to hint at your component for memory leak tracking.
+// These should be treated like a pooltag.
+#define FILTER_REQUEST_ID 'RTLF'
+#define FILTER_ALLOC_TAG 'tliF'
+#define FILTER_TAG 'dnTF'
+
+// TODO: Specify which version of the NDIS contract you will use here.
+// In many cases, 6.0 is the best choice. You only need to select a later
+// version if you need a feature that is not available in 6.0.
+//
+// Legal values include:
+// 6.0 Available starting with Windows Vista RTM
+// 6.1 Available starting with Windows Vista SP1 / Windows Server 2008
+// 6.20 Available starting with Windows 7 / Windows Server 2008 R2
+// 6.30 Available starting with Windows 8 / Windows Server "8"
+// Or, just use NDIS_FILTER_MAJOR_VERSION / NDIS_FILTER_MINOR_VERSION
+// to pick up whatever version is defined by your build system
+// (for example, "-DNDIS630").
+#define FILTER_MAJOR_NDIS_VERSION NDIS_FILTER_MAJOR_VERSION
+#define FILTER_MINOR_NDIS_VERSION NDIS_FILTER_MINOR_VERSION
+
+
+//
+// Global variables
+//
+extern NDIS_HANDLE FilterDriverHandle; // NDIS handle for filter driver
+extern NDIS_HANDLE FilterDriverObject;
+extern NDIS_HANDLE NdisFilterDeviceHandle;
+extern PDEVICE_OBJECT DeviceObject;
+
+extern FILTER_LOCK FilterListLock;
+extern LIST_ENTRY FilterModuleList;
+
+
+
+
+#if NDISLWF
+#define FILTER_FRIENDLY_NAME L"NDIS Sample LightWeight Filter"
+// TODO: Customize this to match the GUID in the INF
+#define FILTER_UNIQUE_NAME L"{5cbf81bd-5055-47cd-9055-a76b2b4e3697}" //unique name, quid name
+// TODO: Customize this to match the service name in the INF
+#define FILTER_SERVICE_NAME L"NDISLWF"
+//
+// The filter needs to handle IOCTLs
+//
+#define LINKNAME_STRING L"\\DosDevices\\NDISLWF"
+#define NTDEVICE_STRING L"\\Device\\NDISLWF"
+#endif
+
+
+#if NDISLWF1
+#define FILTER_FRIENDLY_NAME L"NDIS Sample LightWeight Filter 1"
+#define FILTER_UNIQUE_NAME L"{5cbf81be-5055-47cd-9055-a76b2b4e3697}" //unique name, quid name
+#define FILTER_SERVICE_NAME L"NDISLWF1"
+//
+// The filter needs to handle IOCTRLs
+//
+#define LINKNAME_STRING L"\\DosDevices\\NDISLWF1"
+#define NTDEVICE_STRING L"\\Device\\NDISLWF1"
+#endif
+
+#if NDISMON
+#define FILTER_FRIENDLY_NAME L"NDIS Sample Monitor LightWeight Filter"
+#define FILTER_UNIQUE_NAME L"{5cbf81bf-5055-47cd-9055-a76b2b4e3697}" //unique name, quid name
+#define FILTER_SERVICE_NAME L"NDISMON"
+//
+// The filter needs to handle IOCTRLs
+//
+#define LINKNAME_STRING L"\\DosDevices\\NDISMON"
+#define NTDEVICE_STRING L"\\Device\\NDISMON"
+#endif
+
+#if NDISMON1
+#define FILTER_FRIENDLY_NAME L"NDIS Sample Monitor 1 LightWeight Filter"
+#define FILTER_UNIQUE_NAME L"{5cbf81c0-5055-47cd-9055-a76b2b4e3697}" //unique name, quid name
+#define FILTER_SERVICE_NAME L"NDISMON1"
+//
+// The filter needs to handle IOCTRLs
+//
+#define LINKNAME_STRING L"\\DosDevices\\NDISMON1"
+#define NTDEVICE_STRING L"\\Device\\NDISMON1"
+#endif
+
+
+//
+// Types and macros to manipulate packet queue
+//
+typedef struct _QUEUE_ENTRY
+{
+ struct _QUEUE_ENTRY * Next;
+}QUEUE_ENTRY, *PQUEUE_ENTRY;
+
+typedef struct _QUEUE_HEADER
+{
+ PQUEUE_ENTRY Head;
+ PQUEUE_ENTRY Tail;
+} QUEUE_HEADER, PQUEUE_HEADER;
+
+
+#if TRACK_RECEIVES
+UINT filterLogReceiveRefIndex = 0;
+ULONG_PTR filterLogReceiveRef[0x10000];
+#endif
+
+#if TRACK_SENDS
+UINT filterLogSendRefIndex = 0;
+ULONG_PTR filterLogSendRef[0x10000];
+#endif
+
+#if TRACK_RECEIVES
+#define FILTER_LOG_RCV_REF(_O, _Instance, _NetBufferList, _Ref) \
+ {\
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_O); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_Instance); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_NetBufferList); \
+ filterLogReceiveRef[filterLogReceiveRefIndex++] = (ULONG_PTR)(_Ref); \
+ if (filterLogReceiveRefIndex >= (0x10000 - 5)) \
+ { \
+ filterLogReceiveRefIndex = 0; \
+ } \
+ }
+#else
+#define FILTER_LOG_RCV_REF(_O, _Instance, _NetBufferList, _Ref)
+#endif
+
+#if TRACK_SENDS
+#define FILTER_LOG_SEND_REF(_O, _Instance, _NetBufferList, _Ref) \
+ {\
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_O); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_Instance); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_NetBufferList); \
+ filterLogSendRef[filterLogSendRefIndex++] = (ULONG_PTR)(_Ref); \
+ if (filterLogSendRefIndex >= (0x10000 - 5)) \
+ { \
+ filterLogSendRefIndex = 0; \
+ } \
+ }
+
+#else
+#define FILTER_LOG_SEND_REF(_O, _Instance, _NetBufferList, _Ref)
+#endif
+
+
+//
+// DEBUG related macros.
+//
+#if DBG
+#define FILTER_ALLOC_MEM(_NdisHandle, _Size) \
+ filterAuditAllocMem( \
+ _NdisHandle, \
+ _Size, \
+ __FILENUMBER, \
+ __LINE__);
+
+#define FILTER_FREE_MEM(_pMem) \
+ filterAuditFreeMem(_pMem);
+
+#else
+#define FILTER_ALLOC_MEM(_NdisHandle, _Size) \
+ NdisAllocateMemoryWithTagPriority(_NdisHandle, _Size, FILTER_ALLOC_TAG, LowPoolPriority)
+
+#define FILTER_FREE_MEM(_pMem) NdisFreeMemory(_pMem, 0, 0)
+
+#endif //DBG
+
+#if DBG_SPIN_LOCK
+#define FILTER_INIT_LOCK(_pLock) \
+ filterAllocateSpinLock(_pLock, __FILENUMBER, __LINE__)
+
+#define FILTER_FREE_LOCK(_pLock) filterFreeSpinLock(_pLock)
+
+
+#define FILTER_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ filterAcquireSpinLock(_pLock, __FILENUMBER, __LINE__, DisaptchLevel)
+
+#define FILTER_RELEASE_LOCK(_pLock, DispatchLevel) \
+ filterReleaseSpinLock(_pLock, __FILENUMBER, __LINE__, DispatchLevel)
+
+#else
+#define FILTER_INIT_LOCK(_pLock) NdisAllocateSpinLock(_pLock)
+
+#define FILTER_FREE_LOCK(_pLock) NdisFreeSpinLock(_pLock)
+
+#define FILTER_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprAcquireSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisAcquireSpinLock(_pLock); \
+ } \
+ }
+
+#define FILTER_RELEASE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprReleaseSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisReleaseSpinLock(_pLock); \
+ } \
+ }
+#endif //DBG_SPIN_LOCK
+
+
+#define NET_BUFFER_LIST_LINK_TO_ENTRY(_pNBL) ((PQUEUE_ENTRY)(NET_BUFFER_LIST_NEXT_NBL(_pNBL)))
+#define ENTRY_TO_NET_BUFFER_LIST(_pEnt) (CONTAINING_RECORD((_pEnt), NET_BUFFER_LIST, Next))
+
+#define InitializeQueueHeader(_QueueHeader) \
+{ \
+ (_QueueHeader)->Head = (_QueueHeader)->Tail = NULL; \
+}
+
+//
+// Macros for queue operations
+//
+#define IsQueueEmpty(_QueueHeader) ((_QueueHeader)->Head == NULL)
+
+#define RemoveHeadQueue(_QueueHeader) \
+ (_QueueHeader)->Head; \
+ { \
+ PQUEUE_ENTRY pNext; \
+ ASSERT((_QueueHeader)->Head); \
+ pNext = (_QueueHeader)->Head->Next; \
+ (_QueueHeader)->Head = pNext; \
+ if (pNext == NULL) \
+ (_QueueHeader)->Tail = NULL; \
+ }
+
+#define InsertHeadQueue(_QueueHeader, _QueueEntry) \
+ { \
+ ((PQUEUE_ENTRY)(_QueueEntry))->Next = (_QueueHeader)->Head; \
+ (_QueueHeader)->Head = (PQUEUE_ENTRY)(_QueueEntry); \
+ if ((_QueueHeader)->Tail == NULL) \
+ (_QueueHeader)->Tail = (PQUEUE_ENTRY)(_QueueEntry); \
+ }
+
+#define InsertTailQueue(_QueueHeader, _QueueEntry) \
+ { \
+ ((PQUEUE_ENTRY)(_QueueEntry))->Next = NULL; \
+ if ((_QueueHeader)->Tail) \
+ (_QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(_QueueEntry); \
+ else \
+ (_QueueHeader)->Head = (PQUEUE_ENTRY)(_QueueEntry); \
+ (_QueueHeader)->Tail = (PQUEUE_ENTRY)(_QueueEntry); \
+ }
+
+
+//
+// Enum of filter's states
+// Filter can only be in one state at one time
+//
+typedef enum _FILTER_STATE
+{
+ FilterStateUnspecified,
+ FilterInitialized,
+ FilterPausing,
+ FilterPaused,
+ FilterRunning,
+ FilterRestarting,
+ FilterDetaching
+} FILTER_STATE;
+
+
+typedef struct _FILTER_REQUEST
+{
+ NDIS_OID_REQUEST Request;
+ NDIS_EVENT ReqEvent;
+ NDIS_STATUS Status;
+} FILTER_REQUEST, *PFILTER_REQUEST;
+
+//
+// Define the filter struct
+//
+typedef struct _MS_FILTER
+{
+ LIST_ENTRY FilterModuleLink;
+ //Reference to this filter
+ ULONG RefCount;
+
+ NDIS_HANDLE FilterHandle;
+ NDIS_STRING FilterModuleName;
+ NDIS_STRING MiniportFriendlyName;
+ NDIS_STRING MiniportName;
+ NET_IFINDEX MiniportIfIndex;
+
+ NDIS_STATUS Status;
+ NDIS_EVENT Event;
+ ULONG BackFillSize;
+ FILTER_LOCK Lock; // Lock for protection of state and outstanding sends and recvs
+
+ FILTER_STATE State; // Which state the filter is in
+ ULONG OutstandingSends;
+ ULONG OutstandingRequest;
+ ULONG OutstandingRcvs;
+ FILTER_LOCK SendLock;
+ FILTER_LOCK RcvLock;
+ QUEUE_HEADER SendNBLQueue;
+ QUEUE_HEADER RcvNBLQueue;
+
+
+ NDIS_STRING FilterName;
+ ULONG CallsRestart;
+ BOOLEAN TrackReceives;
+ BOOLEAN TrackSends;
+#if DBG
+ BOOLEAN bIndicating;
+#endif
+
+ PNDIS_OID_REQUEST PendingOidRequest;
+
+}MS_FILTER, * PMS_FILTER;
+
+
+typedef struct _FILTER_DEVICE_EXTENSION
+{
+ ULONG Signature;
+ NDIS_HANDLE Handle;
+} FILTER_DEVICE_EXTENSION, *PFILTER_DEVICE_EXTENSION;
+
+
+#define FILTER_READY_TO_PAUSE(_Filter) \
+ ((_Filter)->State == FilterPausing)
+
+//
+// The driver should maintain a list of NDIS filter handles
+//
+typedef struct _FL_NDIS_FILTER_LIST
+{
+ LIST_ENTRY Link;
+ NDIS_HANDLE ContextHandle;
+ NDIS_STRING FilterInstanceName;
+} FL_NDIS_FILTER_LIST, *PFL_NDIS_FILTER_LIST;
+
+//
+// The context inside a cloned request
+//
+typedef struct _NDIS_OID_REQUEST *FILTER_REQUEST_CONTEXT,**PFILTER_REQUEST_CONTEXT;
+
+
+//
+// function prototypes
+//
+DRIVER_INITIALIZE DriverEntry;
+
+FILTER_SET_OPTIONS FilterRegisterOptions;
+
+FILTER_ATTACH FilterAttach;
+
+FILTER_DETACH FilterDetach;
+
+DRIVER_UNLOAD FilterUnload;
+
+FILTER_RESTART FilterRestart;
+
+FILTER_PAUSE FilterPause;
+
+FILTER_OID_REQUEST FilterOidRequest;
+
+FILTER_CANCEL_OID_REQUEST FilterCancelOidRequest;
+
+FILTER_STATUS FilterStatus;
+
+FILTER_DEVICE_PNP_EVENT_NOTIFY FilterDevicePnPEventNotify;
+
+FILTER_NET_PNP_EVENT FilterNetPnPEvent;
+
+FILTER_OID_REQUEST_COMPLETE FilterOidRequestComplete;
+
+FILTER_SEND_NET_BUFFER_LISTS FilterSendNetBufferLists;
+
+FILTER_RETURN_NET_BUFFER_LISTS FilterReturnNetBufferLists;
+
+FILTER_SEND_NET_BUFFER_LISTS_COMPLETE FilterSendNetBufferListsComplete;
+
+FILTER_RECEIVE_NET_BUFFER_LISTS FilterReceiveNetBufferLists;
+
+FILTER_CANCEL_SEND_NET_BUFFER_LISTS FilterCancelSendNetBufferLists;
+
+FILTER_SET_MODULE_OPTIONS FilterSetModuleOptions;
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+FilterRegisterDevice(
+ VOID
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+FilterDeregisterDevice(
+ VOID
+ );
+
+DRIVER_DISPATCH FilterDispatch;
+
+DRIVER_DISPATCH FilterDeviceIoControl;
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PMS_FILTER
+filterFindFilterModule(
+ _In_reads_bytes_(BufferLength)
+ PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NDIS_STATUS
+filterDoInternalRequest(
+ _In_ PMS_FILTER FilterModuleContext,
+ _In_ NDIS_REQUEST_TYPE RequestType,
+ _In_ NDIS_OID Oid,
+ _Inout_updates_bytes_to_(InformationBufferLength, *pBytesProcessed)
+ PVOID InformationBuffer,
+ _In_ ULONG InformationBufferLength,
+ _In_opt_ ULONG OutputBufferLength,
+ _In_ ULONG MethodId,
+ _Out_ PULONG pBytesProcessed
+ );
+
+VOID
+filterInternalRequestComplete(
+ _In_ NDIS_HANDLE FilterModuleContext,
+ _In_ PNDIS_OID_REQUEST NdisRequest,
+ _In_ NDIS_STATUS Status
+ );
+
+
+#endif //_FILT_H
+
+
diff --git a/network/ndis/filter/filter.rc b/network/ndis/filter/filter.rc
new file mode 100644
index 00000000..a2fd2df6
--- /dev/null
+++ b/network/ndis/filter/filter.rc
@@ -0,0 +1,40 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "Sample NDIS 6.0 Filter Driver"
+#define VER_INTERNALNAME_STR "NDISLWF.SYS"
+#define VER_ORIGINALFILENAME_STR "NDISLWF.SYS"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/filter/filter.sln b/network/ndis/filter/filter.sln
new file mode 100644
index 00000000..90e2be1f
--- /dev/null
+++ b/network/ndis/filter/filter.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndislwf", "ndislwf.vcxproj", "{D6A797EC-4BD1-4448-8C69-AAD0F18252E3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|Win32.Build.0 = Debug|Win32
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|Win32.ActiveCfg = Release|Win32
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|Win32.Build.0 = Release|Win32
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|x64.ActiveCfg = Debug|x64
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Debug|x64.Build.0 = Debug|x64
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|x64.ActiveCfg = Release|x64
+ {D6A797EC-4BD1-4448-8C69-AAD0F18252E3}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/ndis/filter/filteruser.h b/network/ndis/filter/filteruser.h
new file mode 100644
index 00000000..2a028752
--- /dev/null
+++ b/network/ndis/filter/filteruser.h
@@ -0,0 +1,89 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#ifndef __FILTERUSER_H__
+#define __FILTERUSER_H__
+
+//
+// Temp file to test filter
+//
+
+#define _NDIS_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_FILTER_RESTART_ALL _NDIS_CONTROL_CODE(0, METHOD_BUFFERED)
+#define IOCTL_FILTER_RESTART_ONE_INSTANCE _NDIS_CONTROL_CODE(1, METHOD_BUFFERED)
+#define IOCTL_FILTER_ENUERATE_ALL_INSTANCES _NDIS_CONTROL_CODE(2, METHOD_BUFFERED)
+#define IOCTL_FILTER_QUERY_ALL_STAT _NDIS_CONTROL_CODE(3, METHOD_BUFFERED)
+#define IOCTL_FILTER_CLEAR_ALL_STAT _NDIS_CONTROL_CODE(4, METHOD_BUFFERED)
+#define IOCTL_FILTER_SET_OID_VALUE _NDIS_CONTROL_CODE(5, METHOD_BUFFERED)
+#define IOCTL_FILTER_QUERY_OID_VALUE _NDIS_CONTROL_CODE(6, METHOD_BUFFERED)
+#define IOCTL_FILTER_CANCEL_REQUEST _NDIS_CONTROL_CODE(7, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_DRIVER_CONFIG _NDIS_CONTROL_CODE(8, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_DRIVER_CONFIG _NDIS_CONTROL_CODE(9, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_ADAPTER_CONFIG _NDIS_CONTROL_CODE(10, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_ADAPTER_CONFIG _NDIS_CONTROL_CODE(11, METHOD_BUFFERED)
+#define IOCTL_FILTER_READ_INSTANCE_CONFIG _NDIS_CONTROL_CODE(12, METHOD_BUFFERED)
+#define IOCTL_FILTER_WRITE_INSTANCE_CONFIG _NDIS_CONTROL_CODE(13, METHOD_BUFFERED)
+
+
+#define MAX_FILTER_INSTANCE_NAME_LENGTH 256
+#define MAX_FILTER_CONFIG_KEYWORD_LENGTH 256
+typedef struct _FILTER_DRIVER_ALL_STAT
+{
+ ULONG AttachCount;
+ ULONG DetachCount;
+ ULONG ExternalRequestFailedCount;
+ ULONG ExternalRequestSuccessCount;
+ ULONG InternalRequestFailedCount;
+} FILTER_DRIVER_ALL_STAT, * PFILTER_DRIVER_ALL_STAT;
+
+
+typedef struct _FILTER_SET_OID
+{
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ NDIS_OID Oid;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+
+}FILTER_SET_OID, *PFILTER_SET_OID;
+
+typedef struct _FILTER_QUERY_OID
+{
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ NDIS_OID Oid;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+
+}FILTER_QUERY_OID, *PFILTER_QUERY_OID;
+
+typedef struct _FILTER_READ_CONFIG
+{
+ _Field_size_bytes_part_(MAX_FILTER_INSTANCE_NAME_LENGTH,InstanceNameLength)
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ _Field_size_bytes_part_(MAX_FILTER_CONFIG_KEYWORD_LENGTH,KeywordLength)
+ WCHAR Keyword[MAX_FILTER_CONFIG_KEYWORD_LENGTH];
+ ULONG KeywordLength;
+ NDIS_PARAMETER_TYPE ParameterType;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+}FILTER_READ_CONFIG, *PFILTER_READ_CONFIG;
+
+typedef struct _FILTER_WRITE_CONFIG
+{
+ _Field_size_bytes_part_(MAX_FILTER_INSTANCE_NAME_LENGTH,InstanceNameLength)
+ WCHAR InstanceName[MAX_FILTER_INSTANCE_NAME_LENGTH];
+ ULONG InstanceNameLength;
+ _Field_size_bytes_part_(MAX_FILTER_CONFIG_KEYWORD_LENGTH,KeywordLength)
+ WCHAR Keyword[MAX_FILTER_CONFIG_KEYWORD_LENGTH];
+ ULONG KeywordLength;
+ NDIS_PARAMETER_TYPE ParameterType;
+ NDIS_STATUS Status;
+ UCHAR Data[sizeof(ULONG)];
+}FILTER_WRITE_CONFIG, *PFILTER_WRITE_CONFIG;
+
+#endif //__FILTERUSER_H__
+
diff --git a/network/ndis/filter/flt_dbg.c b/network/ndis/filter/flt_dbg.c
new file mode 100644
index 00000000..1d52071d
--- /dev/null
+++ b/network/ndis/filter/flt_dbg.c
@@ -0,0 +1,409 @@
+/*++
+
+Copyright (c) 2001 Microsoft Corporation
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ This module contains all debug-related code.
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'GBED'
+
+#if DBG
+
+INT filterDebugLevel = DL_WARN;
+
+NDIS_SPIN_LOCK filterDbgLogLock;
+
+PFILTERD_ALLOCATION filterdMemoryHead = (PFILTERD_ALLOCATION)NULL;
+PFILTERD_ALLOCATION filterdMemoryTail = (PFILTERD_ALLOCATION)NULL;
+ULONG filterdAllocCount = 0; // how many allocated so far (unfreed)
+
+NDIS_SPIN_LOCK filterdMemoryLock;
+BOOLEAN filterdInitDone = FALSE;
+
+
+PVOID
+filterAuditAllocMem(
+ NDIS_HANDLE NdisHandle,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+)
+{
+ PVOID pBuffer;
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ if (!filterdInitDone)
+ {
+ NdisAllocateSpinLock(&(filterdMemoryLock));
+ filterdInitDone = TRUE;
+ }
+
+ //
+ // Integer overflow check
+ //
+ if ((Size + (ULONG) sizeof(FILTERD_ALLOCATION)) < Size)
+ {
+ DEBUGP(DL_VERY_LOUD+50,
+ "filterAuditAllocMem: Integer overflow error file %d, line %d, Size %d \n",
+ FileNumber, LineNumber, Size);
+
+ pBuffer = NULL;
+ }
+ else
+ {
+
+ pAllocInfo = NdisAllocateMemoryWithTagPriority(
+ NdisHandle,
+ Size+sizeof(FILTERD_ALLOCATION),
+ (ULONG)'gdTF',
+ LowPoolPriority
+ );
+
+ if (pAllocInfo == (PFILTERD_ALLOCATION)NULL)
+ {
+ DEBUGP(DL_VERY_LOUD+50,
+ "filterAuditAllocMem: file %d, line %d, Size %d failed!\n",
+ FileNumber, LineNumber, Size);
+ pBuffer = NULL;
+ }
+ else
+ {
+ pBuffer = (PVOID)&(pAllocInfo->UserData);
+ NdisFillMemory(pBuffer, Size, 0xaf);
+ pAllocInfo->Signature = FILTERD_MEMORY_SIGNATURE;
+ pAllocInfo->FileNumber = FileNumber;
+ pAllocInfo->LineNumber = LineNumber;
+ pAllocInfo->Size = Size;
+ pAllocInfo->OwnerHandle = NdisHandle;
+ pAllocInfo->Next = (PFILTERD_ALLOCATION)NULL;
+
+ NdisAcquireSpinLock(&(filterdMemoryLock));
+
+ pAllocInfo->Prev = filterdMemoryTail;
+ if (filterdMemoryTail == (PFILTERD_ALLOCATION)NULL)
+ {
+ //
+ // empty list
+ //
+ filterdMemoryHead = filterdMemoryTail = pAllocInfo;
+ }
+ else
+ {
+ filterdMemoryTail->Next = pAllocInfo;
+ }
+ filterdMemoryTail = pAllocInfo;
+
+ filterdAllocCount++;
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+ }
+ }
+
+ DEBUGP(DL_VERY_LOUD+100,
+ "filterAuditAllocMem: file %c%c%c%c, line %d, %d bytes, OwnerHandle %p, Memory 0x%p\n",
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber, Size, NdisHandle, pBuffer);
+
+ return (pBuffer);
+
+}
+
+
+VOID
+filterAuditFreeMem(
+ PVOID Pointer
+)
+{
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ NdisAcquireSpinLock(&(filterdMemoryLock));
+
+ pAllocInfo = CONTAINING_RECORD(Pointer, FILTERD_ALLOCATION, UserData);
+
+ if (pAllocInfo->Signature != FILTERD_MEMORY_SIGNATURE)
+ {
+ DEBUGP(DL_ERROR,
+ "filterAuditFreeMem: unknown buffer 0x%p!\n", Pointer);
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+#if DBG
+ DbgBreakPoint();
+#endif
+ return;
+ }
+
+ pAllocInfo->Signature = (ULONG)'DEAD';
+ if (pAllocInfo->Prev != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Prev->Next = pAllocInfo->Next;
+ }
+ else
+ {
+ filterdMemoryHead = pAllocInfo->Next;
+ }
+ if (pAllocInfo->Next != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Next->Prev = pAllocInfo->Prev;
+ }
+ else
+ {
+ filterdMemoryTail = pAllocInfo->Prev;
+ }
+ filterdAllocCount--;
+ NdisReleaseSpinLock(&(filterdMemoryLock));
+
+ NdisFreeMemory(pAllocInfo, 0, 0);
+}
+
+
+VOID
+filterAuditShutdown(
+ VOID
+)
+{
+ if (filterdInitDone)
+ {
+ if (filterdAllocCount != 0)
+ {
+ DEBUGP(DL_ERROR, "AuditShutdown: unfreed memory, %d blocks!\n",
+ filterdAllocCount);
+ DEBUGP(DL_ERROR, "MemoryHead: 0x%p, MemoryTail: 0x%p\n",
+ filterdMemoryHead, filterdMemoryTail);
+ DbgBreakPoint();
+ {
+ PFILTERD_ALLOCATION pAllocInfo;
+
+ while (filterdMemoryHead != (PFILTERD_ALLOCATION)NULL)
+ {
+ pAllocInfo = filterdMemoryHead;
+ DEBUGP(DL_INFO, "AuditShutdown: will free 0x%p\n", pAllocInfo);
+ filterAuditFreeMem(&(pAllocInfo->UserData));
+ }
+ }
+ }
+ filterdInitDone = FALSE;
+ }
+}
+
+#define MAX_HD_LENGTH 128
+
+VOID
+DbgPrintHexDump(
+ IN PUCHAR pBuffer,
+ IN ULONG Length
+)
+/*++
+
+Routine Description:
+
+ Print a hex dump of the given contiguous buffer. If the length
+ is too long, we truncate it.
+
+Arguments:
+
+ pBuffer - Points to start of data to be dumped
+ Length - Length of above.
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG i;
+
+ if (Length > MAX_HD_LENGTH)
+ {
+ Length = MAX_HD_LENGTH;
+ }
+
+ for (i = 0; i < Length; i++)
+ {
+ //
+ // Check if we are at the end of a line
+ //
+ if ((i > 0) && ((i & 0xf) == 0))
+ {
+ DbgPrint("\n");
+ }
+
+ //
+ // Print addr if we are at start of a new line
+ //
+ if ((i & 0xf) == 0)
+ {
+ DbgPrint("%08p ", pBuffer);
+ }
+
+ DbgPrint(" %02x", *pBuffer++);
+ }
+
+ //
+ // Terminate the last line.
+ //
+ if (Length > 0)
+ {
+ DbgPrint("\n");
+ }
+}
+#endif // DBG
+
+
+#if DBG_SPIN_LOCK
+ULONG filterdSpinLockInitDone = 0;
+NDIS_SPIN_LOCK filterdLockLock;
+
+VOID
+filterAllocateSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber
+)
+{
+ if (filterdSpinLockInitDone == 0)
+ {
+ filterdSpinLockInitDone = 1;
+ NdisAllocateSpinLock(&(filterdLockLock));
+ }
+
+ NdisAcquireSpinLock(&(filterdLockLock));
+ pLock->Signature = FILT_LOCK_SIG;
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired = 0;
+ pLock->OwnerThread = 0;
+ NdisAllocateSpinLock(&(pLock->NdisLock));
+ NdisReleaseSpinLock(&(filterdLockLock));
+}
+
+VOID
+filterFreeSpinLock(
+ _In_ PFILTER_LOCK pLock
+ )
+{
+ ASSERT(filterdSpinLockInitDone == 1);
+
+
+ NdisFreeSpinLock(&(filterdLockLock));
+ filterdSpinLockInitDone = 0;
+ NdisFreeSpinLock(&(pLock->NdisLock));
+
+}
+
+
+
+VOID
+filterAcquireSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber,
+ _In_ BOOLEAN DispatchLevel
+)
+{
+ if (DispatchLevel)
+ {
+ NdisDprAcquireSpinLock(&(filterdLockLock));
+ }
+ else
+ {
+ NdisAcquireSpinLock(&(filterdLockLock));
+ }
+ if (pLock->Signature != FILT_LOCK_SIG)
+ {
+ DbgPrint("Trying to acquire uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+
+ pLock->IsAcquired++;
+
+ if (DispatchLevel)
+ {
+ NdisDprReleaseSpinLock(&(filterdLockLock));
+ NdisDprAcquireSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(filterdLockLock));
+ NdisAcquireSpinLock(&(pLock->NdisLock));
+ }
+
+ //
+ // Mark this lock.
+ //
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+}
+
+
+VOID
+filterReleaseSpinLock(
+ _In_ PFILTER_LOCK pLock,
+ _In_ ULONG FileNumber,
+ _In_ ULONG LineNumber,
+ _In_ BOOLEAN DispatchLevel
+)
+{
+ NdisDprAcquireSpinLock(&(filterdLockLock));
+ if (pLock->Signature != FILT_LOCK_SIG)
+ {
+ DbgPrint("Trying to release uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+ if (pLock->IsAcquired == 0)
+ {
+ DbgPrint("Detected release of unacquired lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired--;
+ NdisDprReleaseSpinLock(&(filterdLockLock));
+
+ if (DispatchLevel)
+ {
+ NdisDprReleaseSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(pLock->NdisLock));
+ }
+}
+#endif // DBG_SPIN_LOCK
+
diff --git a/network/ndis/filter/flt_dbg.h b/network/ndis/filter/flt_dbg.h
new file mode 100644
index 00000000..f3513588
--- /dev/null
+++ b/network/ndis/filter/flt_dbg.h
@@ -0,0 +1,195 @@
+/*++
+
+Copyright (c) 2001 Microsoft Corporation
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ This module contains all debug related prototypes for MS FILTER
+
+Revision History:
+
+
+Notes:
+
+--*/
+
+// disable warnings
+
+
+#ifndef _FILTDEBUG__H
+#define _FILTDEBUG__H
+
+//
+// Message verbosity: lower values indicate higher urgency
+//
+#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_SPIN_LOCK
+
+typedef struct _FILTER_LOCK
+{
+ ULONG Signature;
+ ULONG IsAcquired;
+ ULONG TouchedByFileNumber;
+ ULONG TouchedInLineNumber;
+ NDIS_SPIN_LOCK NdisLock;
+} FILTER_LOCK, *PFILTER_LOCK;
+
+#define FILT_LOCK_SIG 'kcoL'
+
+extern NDIS_SPIN_LOCK filterDbgLogLock;
+
+extern
+VOID
+filterAllocateSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+filterFreeSpinLock(
+ IN PFILTER_LOCK pLock
+
+);
+
+
+extern
+VOID
+filterAcquireSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber,
+ IN BOOLEAN DispatchLevel
+);
+
+extern
+VOID
+filterReleaseSpinLock(
+ IN PFILTER_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber,
+ IN BOOLEAN DispatchLevel
+);
+
+
+#else
+
+typedef NDIS_SPIN_LOCK FILTER_LOCK;
+typedef PNDIS_SPIN_LOCK PFILTER_LOCK;
+
+#endif // DBG_SPIN_LOCK
+
+#if DBG
+
+extern INT filterDebugLevel;
+
+
+#define DEBUGP(lev, ...) \
+ { \
+ if ((lev) <= filterDebugLevel) \
+ { \
+ DbgPrint("NDISLWF: "); DbgPrint(__VA_ARGS__); \
+ } \
+ }
+
+#define DEBUGPDUMP(lev, pBuf, Len) \
+ { \
+ if ((lev) <= filterDebugLevel) \
+ { \
+ DbgPrintHexDump((PUCHAR)(pBuf), (ULONG)(Len)); \
+ } \
+ }
+
+#define FILTER_ASSERT(exp) \
+ { \
+ if (!(exp)) \
+ { \
+ DbgPrint("Filter: assert " #exp " failed in" \
+ " file %s, line %d\n", __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+ }
+
+
+
+//
+// Memory Allocation/Freeing Audit:
+//
+
+//
+// The FILTER_ALLOCATION structure stores all info about one allocation
+//
+typedef struct _FILTERD_ALLOCATION {
+
+ ULONG Signature;
+ struct _FILTERD_ALLOCATION *Next;
+ struct _FILTERD_ALLOCATION *Prev;
+ ULONG FileNumber;
+ ULONG LineNumber;
+ ULONG Size;
+ NDIS_HANDLE OwnerHandle;
+ union
+ {
+ ULONGLONG Alignment;
+ UCHAR UserData;
+ };
+
+} FILTERD_ALLOCATION, *PFILTERD_ALLOCATION;
+
+#define FILTERD_MEMORY_SIGNATURE (ULONG)'TFSM'
+
+extern
+PVOID
+filterAuditAllocMem (
+ NDIS_HANDLE NdisHandle,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+);
+
+extern
+VOID
+filterAuditFreeMem(
+ PVOID Pointer
+);
+
+extern
+VOID
+filterAuditShutdown(
+ VOID
+);
+
+extern
+VOID
+DbgPrintHexDump(
+ PUCHAR pBuffer,
+ ULONG Length
+);
+
+#else
+
+//
+// No debug
+//
+#define DEBUGP(lev, ...)
+#define DEBUGPDUMP(lev, pBuf, Len)
+
+#define FILTER_ASSERT(exp)
+
+#endif // DBG
+
+
+#endif // _FILTDEBUG__H
diff --git a/network/ndis/filter/ndislwf.vcxproj b/network/ndis/filter/ndislwf.vcxproj
new file mode 100644
index 00000000..6998e55b
--- /dev/null
+++ b/network/ndis/filter/ndislwf.vcxproj
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{D6A797EC-4BD1-4448-8C69-AAD0F18252E3}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{D42F08CB-C626-4709-A3FB-F3A6AC78F6BE}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ndislwf</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ndislwf</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ndislwf</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ndislwf</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="$(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)">%(PreprocessorDefinitions);NDIS60=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7)))">%(PreprocessorDefinitions);NDIS620=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="!(($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN8)) And (!($(_NT_TARGET_VERSION)&lt;$(_NT_TARGET_VERSION_WIN7))))">%(PreprocessorDefinitions);NDIS630=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDISLWF=1</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="filter.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="flt_dbg.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="filter.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/filter/ndislwf.vcxproj.Filters b/network/ndis/filter/ndislwf.vcxproj.Filters
new file mode 100644
index 00000000..1258cc3b
--- /dev/null
+++ b/network/ndis/filter/ndislwf.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{CCCEB33C-30D7-4D55-9C51-2503E8422C74}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{F2D27727-5C77-4D5A-8C78-D4977DA98B1E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{D2E50D90-0B4D-449A-8527-9EA78D1C23F7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3EF75BEF-85CD-4689-B551-9CFC67497380}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="flt_dbg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="filter.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/filter/netlwf.inf b/network/ndis/filter/netlwf.inf
new file mode 100644
index 00000000..1f55291e
--- /dev/null
+++ b/network/ndis/filter/netlwf.inf
@@ -0,0 +1,202 @@
+;-------------------------------------------------------------------------
+; NdisLwf.INF -- Sample NDIS LightWeight Filter Driver
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; TODO: Search for comments marked "TODO:", and follow their instructions to
+; customize this INF for your driver. Then delete the "TODO:" comments.
+;-------------------------------------------------------------------------
+
+[version]
+; Do not change these values
+Signature = "$Windows NT$"
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+CatalogFile = netlwf.cat
+
+; TODO: Customize this string for your company name
+Provider = %Msft%
+
+; TODO: Customize this string for the driver version
+DriverVer = 10/01/2002,6.0.5019.0
+
+
+; TODO: Include each architecture for which your driver package contains a
+; compiled binary. If you do not supply a driver compiled for ia64, delete the
+; NTia64 section.
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64
+
+; TODO: Change the "MS_NdisLwf" name below to identify your component.
+; This name can be used with netcfg.exe to install/uninstall the driver.
+[MSFT.NTx86]
+%NdisLwf_Desc%=Install, MS_NdisLwf
+
+[MSFT.NTia64]
+%NdisLwf_Desc%=Install, MS_NdisLwf
+
+[MSFT.NTamd64]
+%NdisLwf_Desc%=Install, MS_NdisLwf
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+; All LWFs must include the 0x40000 bit (NCF_LW_FILTER). Unlike miniports, you
+; don't usually need to customize this value.
+Characteristics=0x40000
+
+; TODO: You must generate your own random GUID and insert it here. Then, update
+; FILTER_UNIQUE_NAME in filter.h to match this GUID identically. Both should
+; have {curly braces}.
+NetCfgInstanceId="{5cbf81bd-5055-47cd-9055-a76b2b4e3697}"
+
+Copyfiles = ndislwf.copyfiles.sys
+
+[SourceDisksNames]
+1=%NdisLwf_Desc%,"",,
+
+[SourceDisksFiles]
+; TODO: Customize the name of your binary here.
+; Also include any related files that should be installed with your driver.
+ndislwf.sys=1
+
+[DestinationDirs]
+DefaultDestDir=12
+ndislwf.copyfiles.sys=12
+
+[ndislwf.copyfiles.sys]
+; TODO: Customize the name of your binary here.
+ndislwf.sys,,,2
+
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+; TODO: Customize the name of the NT service that will start your driver.
+; Then, update FILTER_SERVICE_NAME in filter.h.
+HKR, Ndi,Service,,"NdisLwf"
+; TODO: Repeat the NT service name above here. Optionally, you may control
+; other services alongside the primary service.
+HKR, Ndi,CoServices,0x00010000,"NdisLwf"
+HKR, Ndi,HelpText,,%NdisLwf_HelpText%
+; TODO: Set the FilterClass here. The FilterClass controls the order in which
+; filters are bound to the underlying miniport. Possible options include:
+; Custom, Diagnostic, Failover, Loadbalance, Vpn, Compression, Encryption, Scheduler
+; See MSDN for a description of each.
+HKR, Ndi,FilterClass,, compression
+; TODO: Specify whether you have a Modifying or Monitoring filter.
+; For a Monitoring filter, use this:
+; HKR, Ndi,FilterType,0x00010001, 1 ; Monitoring filter
+; For a Modifying filter, use this:
+; HKR, Ndi,FilterType,0x00010001, 2 ; Modifying filter
+HKR, Ndi,FilterType,0x00010001,2
+; Do not change these values
+HKR, Ndi\Interfaces,UpperRange,,"noupper"
+HKR, Ndi\Interfaces,LowerRange,,"nolower"
+; TODO: Ensure that the list of media types below is correct. Typically,
+; filters include "ethernet". Filters may also include "ppip" to include
+; native WWAN stacks, but you must be prepared to handle the packet framing.
+; Possible values are listed on MSDN, but common values include:
+; ethernet, wan, ppip, wlan
+HKR, Ndi\Interfaces, FilterMediaTypes,,"ethernet, wan, ppip"
+; TODO: Specify whether you have a Mandatory or Optional filter.
+; For a Mandatory filter, use this:
+; HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter
+; For an Optional filter, use this:
+; HKR, Ndi,FilterRunType,0x00010001, 2 ; Optional filter
+HKR, Ndi,FilterRunType,0x00010001, 1 ; Mandatory filter
+
+; By default, Mandatory filters unbind all protocols when they are
+; installed/uninstalled, while Optional filters merely pause the stack. If you
+; would like to override this behavior, you can include these options. These
+; options only take effect with 6.30 filters on Windows "8" or later.
+; To prevent a full unbind, and merely pause/restart protocols:
+; HKR, Ndi,UnbindOnAttach,0x00010001, 0 ; Do not unbind during FilterAttach
+; HKR, Ndi,UnbindOnDetach,0x00010001, 0 ; Do not unbind during FilterDetach
+; To force a full unbind/bind (which includes pause/restart, of course):
+; HKR, Ndi,UnbindOnAttach,0x00010001, 1 ; Unbind during FilterAttach
+; HKR, Ndi,UnbindOnDetach,0x00010001, 1 ; Unbind during FilterDetach
+;
+
+; NDIS can start a miniport stack even if some Optional filters are
+; missing. However, NDIS reserves the right to wait for the Optional
+; filters to be registered, since it's faster to attach a filter if
+; the protocols haven't been bound yet.
+; If your Optional filter is unlikely to be started at boot, you can
+; use this hint to inform NDIS to spend less time waiting for your
+; filter. Note this setting is ignored for Mandatory filters; NDIS
+; always waits forever for all Mandatory filters.
+; HKR, Ndi,NdisBootStart,0x00010001, 0 ; Don't wait for this driver to start at boot
+; Enable this setting only if your filter will be bound, but the driver
+; is not usually started at boot. If your driver will typically start
+; at boot, then enabling this setting would defeat the NDIS heuristic
+; and slightly slow down boot.
+
+;-------------------------------------------------------------------------
+; Service installation support
+;-------------------------------------------------------------------------
+[Install.Services]
+; TODO: Customize the name of your NT service here.
+; You may also want to add the SPSVCINST_STARTSERVICE flag, like this:
+; AddService=NdisLwf,0x800,NdisLwf_Service_Inst ; SPSVCINST_STARTSERVICE
+AddService=NdisLwf,,NdisLwf_Service_Inst
+
+[NdisLwf_Service_Inst]
+DisplayName = %NdisLwf_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+; Typically you will want your filter driver to start with SERVICE_SYSTEM_START.
+; If it is an Optional filter, you may also use 3;SERVICE_DEMAND_START.
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+; TODO: Customize this to your binary's filename.
+ServiceBinary = %12%\ndislwf.sys
+LoadOrderGroup = NDIS
+Description = %NdisLwf_Desc%
+AddReg = Common.Params.reg, NdisImPlatformBindingOptions.reg
+
+[Install.Remove.Services]
+; TODO: Customize the name of your NT service here.
+; The SPSVCINST_STOPSERVICE flag instructs SCM to stop the NT service
+; before uninstalling the driver.
+DelService=NdisLwf,0x200 ; SPSVCINST_STOPSERVICE
+
+[Common.Params.reg]
+; TODO: You can add any sort of NDIS parameters here. Filter drivers
+; don't always need NDIS parameters, so it's okay to have nothing here.
+
+; TODO: Remove the sample parameters below.
+
+; Sample 1: "DriverParam" is a per-driver parameter.
+HKR, FilterDriverParams\DriverParam, ParamDesc, , "Driverparam for lwf"
+HKR, FilterDriverParams\DriverParam, default, , "5"
+HKR, FilterDriverParams\DriverParam, type, , "int"
+
+; Sample 2: "AdapterParam" is a per-module parameter.
+HKR, FilterAdapterParams\AdapterParam, ParamDesc, , "Adapterparam for lwf"
+HKR, FilterAdapterParams\AdapterParam, default, , "10"
+HKR, FilterAdapterParams\AdapterParam, type, , "int"
+
+[NdisImPlatformBindingOptions.reg]
+; By default, when an LBFO team or Bridge is created, all filters will be
+; unbound from the underlying members and bound to the TNic(s). This keyword
+; allows a component to opt out of the default behavior
+; To prevent binding this filter to the TNic(s):
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,1 ; Do not bind to TNic
+; To prevent unbinding this filter from underlying members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,2 ; Do not unbind from Members
+; To prevent both binding to TNic and unbinding from members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,3 ; Do not bind to TNic or unbind from Members
+HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,0 ; Subscribe to default behavior
+
+[Strings]
+; TODO: Customize these strings.
+Msft = "Your Company"
+NdisLwf_Desc = "NDIS Sample LightWeight Filter"
+NdisLwf_HelpText = "Sample to demonstrate NDIS LightWeight Filters"
+
+
+
+
diff --git a/network/ndis/filter/precomp.h b/network/ndis/filter/precomp.h
new file mode 100644
index 00000000..96cdb488
--- /dev/null
+++ b/network/ndis/filter/precomp.h
@@ -0,0 +1,6 @@
+#pragma warning(disable:4201) //nonstandard extension used : nameless struct/union
+#include <ndis.h>
+#include <filteruser.h>
+#include "flt_dbg.h"
+#include "filter.h"
+
diff --git a/network/ndis/filter/precompsrc.c b/network/ndis/filter/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/filter/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/mux/ReadMe.md b/network/ndis/mux/ReadMe.md
new file mode 100644
index 00000000..e22050fe
--- /dev/null
+++ b/network/ndis/mux/ReadMe.md
@@ -0,0 +1,174 @@
+NDIS MUX Intermediate Driver and Notify Object
+==============================================
+
+The MUX Intermediate Miniport (IM) driver is an NDIS 6.0 driver that demonstrates the operation of an “N:1” MUX driver.The sample demonstrates creating multiple virtual network devices on top of a single lower adapter. Protocols bind to these virtual adapters as if they are real adapters. Examples of Intermediate Miniport drivers that can use this framework are Virtual LAN (VLAN) drivers. Included in the project is a sample Notify Object that demonstrates how to write a notify object for installing and configuring an NDIS MUX intermediate miniport (IM) driver that implements an N:1 relationship between upper and lower bindings, i.e. it creates multiple virtual network devices on top of a single lower adapter. Protocols bind to these virtual adapters as if they are real adapters. Examples of Intermediate Miniport drivers that can use this type of notify object are Virtual LAN (VLAN) drivers.
+
+For more information, see [NDIS Intermediate Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff565773) in the network devices design guide.
+
+INSTALLING THE SAMPLE
+---------------------
+
+MUX is installed as a protocol (called *Sample Mux-IM Protocol Driver* in the supplied INFs/notification object).
+
+To install, follow the steps below:
+
+1. Prepare an installation directory that contains these files: muxp.inf, mux\_mp.inf, mux.sys and mux.dll (notification object DLL, built in this DDK at network\\ndis\\mux\\notifyob).
+2. On the desktop, right-click the **My Network Places** icon and choose **Properties**.
+3. Right-click on the relevant **Local Area Connection** icon and choose **Properties**.
+4. Click **Install**, then **Protocol**, then **Add**, then **Have Disk**.
+5. Browse to the drive/directory containing the files listed above. Click **OK**. This should show **Sample Mux-IM Protocol Driver** in a list of Network Protocols. Highlight this and click **OK**. This should install the MUX driver.
+6. Click **OK** or **Yes** each time the system prompts with a warning regarding installation of unsigned files. This is necessary because binaries generated via the DDK build environment are not signed.
+
+Two .INF files are needed rather than one because MUX is installed both as a protocol and a miniport.
+
+NDIS MUX Intermediate Driver
+----------------------------
+
+The driver binds to Ethernet (NdisMedium802\_3) adapters as a protocol, and exposes one or more virtual Ethernet devices over each lower adapter, based on its configuration. The term “VELAN” is used to denote a Virtual Ethernet LAN adapter implemented by this driver.
+
+When it binds to a lower adapter, MUX reads the standard “UpperBind” key to obtain a list of VELANs configured over this adapter. For each such VELAN, it calls NdisIMInitializeDeviceInstanceEx() to instantiate the NDIS miniport for the VELAN. NDIS then calls the driver’s MiniportInitialize (MPInitialize) routine to start the VELAN miniport.
+
+The MUX driver supports configuring the MAC address for each VELAN miniport using the standard “NetworkAddress” key that it reads from its MiniportInitialize routine. If this is not configured, it computes a “locally significant” MAC address for the VELAN using the MAC address of the lower adapter. The MUX driver sets its lower adapter to promiscuous mode in order to be able to receive frames directed to any of the VELAN MAC addresses. However it does implement packet-filtering (and multicast address filtering) logic for all its VELAN miniports so that it only passes up relevant frames on each VELAN. This aspect of the driver may be modified if, for example, your driver design uses the same MAC address as that of the lower adapter on all VELANs. With such a modification, it is not required to set the lower adapter to promiscuous mode and incur the costs of receiving all packets on the network.
+
+It supports dynamic addition and deletion of VELANs in conjunction with its notify object (related sample). If a VELAN is deleted, the virtual device corresponding to the VELAN is stopped and removed, which in turn results in NDIS halting the miniport instance for the VELAN (see MPHalt). If a VELAN is added, NDIS sends a global reconfiguration event to the protocol edge of this driver. The handler function for this event, PtPNPHandler, goes through all lower adapters to see if any new VELANs have been added, i.e. if any of the “UpperBind” keys have been modified.
+
+Since the driver implements a virtual device, it does not simply pass through most NDIS queries/sets. It keeps its own device view that is reflected in its responses to queries/sets. However it does pass through queries/sets for certain OIDs that are best handled by the lower adapter driver.
+
+The driver supports Power Management in the sense that it allows Wake-On-LAN and related functionality, if supported by the lower adapter, to continue to function. It does so by appropriately forwarding OID\_PNP\_XXX queries/sets to the lower adapter.
+
+### IEEE 802.1Q VLAN Operation
+
+The driver supports configuring a VLAN ID on each VELAN. It then inserts a tag header containing this VLAN ID on all outgoing frames. For incoming frames that contain a tag header, it verifies that a matching VLAN ID is present before indicating it up to protocols. It removes the tag header, if present, from all indicated frames. In all cases, received frames that do not contain tag headers are always handed up to protocols.
+
+With the default configured VLAN ID of zero, the driver does not insert tag header information on sent packets, except for sent packets that contain non-zero Ieee8021QInfo per-packet information, for which the driver does insert corresponding tag headers. Receive-side filtering on VLAN ID is enabled only with a non-zero configured VLAN ID, in which case only received frames containing a matching VLAN ID are passed up. With the default configured VLAN ID of zero, the driver does not check the VLAN ID on received frames.
+
+### Configuring VLANs
+
+The VLAN ID for each VELAN (virtual miniport) can be configured as follows. Right-click on the virtual miniport Local Area Connection icon and choose Properties. Click on the Configure button to bring up the Device Manager UI for the virtual device. Select the Advanced property sheet – this should contain a “VLAN ID” parameter that is configurable to the desired VLAN ID. Choosing a value of 0 (zero) disables receive-side filtering based on VLAN ID.
+
+### Programming Tour
+
+When it loads, i.e. from its DriverEntry function, the MUX driver registers as an Intermediate miniport driver and as a protocol, in that order.
+
+### Binding and VELAN Creation
+
+NDIS calls MUX’s BindAdapter function, `PtBindAdapter`, for each underlying NDIS adapter to which it is configured to bind. This function allocates an `ADAPT` structure to represent the lower adapter, and calls `NdisOpenAdapter` to set up a binding to it. In the context of `BindAdapterHandler`, after successfully opening a binding to the underlying adapter, the driver queries the reserved keyword "UpperBindings" to get a list of device names for the virtual adapters that this particular binding is to expose – see `PtBootStrapVElans` for more details. Note that the MUX driver does not create bindings (i.e. call `NdisOpenAdapter`) from any context other than its BindAdapter function – this is recommended behavior for all drivers of this type.
+
+For each device name specified in the “UpperBindings” key, the MUX driver allocates a VELAN data structure to represent the virtual miniport, calls `NdisIMInitializeDeviceInstanceEx`. In response, NDIS eventually calls the MUX miniport’s MiniportInitialize entry point, MPInitialize, for each VELAN. After MPInitialize successfully returns, NDIS takes care of getting upper-layer protocols to bind to the newly created virtual adapter(s).
+
+### Unbinding and Halting
+
+NDIS calls MUX’s `UnbindAdapter` handler, `PtUnbindAdapter`, to request it to unbind from a lower adapter. In processing this, MUX calls `NdisIMDeInitializeDeviceInstance` for each VELAN instantiated on the indicated adapter – see `PtStopVElan` for details. This call results in NDIS first unbinding any protocols bound to the indicated VELAN, and then calling the MiniportHalt routine, `MPHalt`, for that VELAN. `MPHalt` waits for any outstanding receives/sends on the VELAN to finish before unlinking the VELAN from the ADAPT.
+
+`PtUnbindAdapter` itself blocks until all VELANs associated with the ADAPT structure have been unlinked from it. This is to make sure that no thread running in the context of a miniport-edge entry point for a VELAN will ever access an invalid lower binding handle. Once all VELANs have been unlinked, `PtUnbindAdapter` closes the lower binding by calling `NdisCloseAdapter`. Note that the MUX driver does not close its lower binding from any context other than its `UnbindAdapter` function – this is recommended behavior for all drivers of this type.
+
+`MPHalt` may also be called if the VELAN device is disabled, e.g. from the Network Connections Folder. There is no special code within `MPHalt` to handle this condition. However, `PtUnbindAdapter` takes care to not attempt to deinitialize a VELAN miniport (via `NdisIMDeInitializeDeviceInstance`) that has already been halted.
+
+### Handling Queries
+
+`MPRequest` is the MUX driver’s function that handles queries for OID values on VELAN miniports. Most of the “Ethernet” type information for the virtual miniport is stored in the VELAN structure itself, and the driver returns information from this structure. The queries that are forwarded are **OID\_GEN\_MEDIA\_CONNECT\_STATUS**, **OID\_PNP\_CAPABILITIES** and **OID\_PNP\_WAKE\_UP\_PATTERN\_LIST**. See “Handling Power Management” below for more information about the latter two OIDs.
+
+### Handling Sets
+
+`MPRequest` handles setting OID values on VELAN miniports. Data management OIDs handled by the MUX driver are **OID\_802\_3\_MULTICAST\_LIST** and **OID\_GEN\_CURRENT\_PACKET\_FILTER**. The multicast list is handled entirely within the MUX driver – it just stores the set of multicast addresses in the VELAN structure, for reference during receive-side data processing. The packet filter is handled in a different way – the MUX driver combines the packet filter settings (bitwise OR) of all VELANs associated with the same lower adapter. If the combined packet filter is non-zero, MUX sends a Set request with a value of **NDIS\_PACKET\_TYPE\_PROMISCUOUS** for **OID\_GEN\_CURRENT\_PACKET\_FILTER** to start receives on the lower adapter. If the combined packet filter is zero, MUX sets the lower adapter’s packet filter to 0 (turns off all receives if there aren’t any interested protocols).
+
+Note that setting the lower adapter to promiscuous mode is only done here in order to be able to receive unicast frames directed to multiple MAC addresses. If, for example, all VELANs are assigned the same MAC address (which is identical to the address of the lower adapter), then the MUX driver should only pass down the combined (bitwise OR) setting of packet filter settings of all VELANs.
+
+Some power management OIDs are forwarded to the lower miniport. See “Handling Power Management” below for details.
+
+### Sending Data
+
+Data sent down on a VELAN miniport is forwarded to the lower adapter. The MUX driver itself does not generate any data of its own. The MUX driver clones a `NET_BUFFER_LIST` for each `NetBufferList` passed to its `MPSendNetBufferLists` function, and saves a pointer to the original `NET_BUFFER_LIST` in the reserved area of the `NET_BUFFER_LIST` structure. When the lower adapter completes the send (`PtSendNBLComplete`), MUX picks up the original packet and calls `NdisMSendNetBufferListsComplete` to complete the original send request.
+
+If a non-zero VLAN ID is configured for the VELAN, and/or the packet has non-zero Ieee8021QInfo per-packet information, then the MUX driver inserts an NDIS buffer containing a tag header to the front of the packet before sending it down – see function `MPHandleSendTagging` for details.
+
+### Receiving Data
+
+Data received from a lower adapter is indicated up on zero or more VELANs. The `PtReceiveNBL` function is called for each `NetBufferList` received from the lower adapter. The received data is checked for matches with the packet filter and multicast list for each VELAN associated with the adapter (see `PtMatchPacketToVElan`). Whenever a match is found, a new `NET_BUFFER_LIST` is allocated and set to point to the received data. A pointer to the original received `NET_BUFFER_LIST` (if any) is also stored in the new `NET_BUFFER_LIST`’s reserved area. This packet is indicated up via `NdisMIndicateReceiveNetBufferLists` to all interested protocols on that VELAN.
+
+The driver’s `MPReturnNetBufferLists` function is called either by NDIS or by MUX itself when protocols are done with a received `NET_BUFFER_LIST`. This function returns the original `NET_BUFFER_LIST` indicated by the lower driver, if any, by calling `NdisReturnNetBufferLists.`
+
+The driver indicates up received frames that do not have an IEEE 802.1Q tag header in them – see function `PtHandleRcvTagging`. It always strips off tag headers, if present, on received frames. If a non-zero VLAN ID is configured, then it checks received frames that contain tag headers for matching VLAN Ids – only matching frames are indicated up to protocols. Any VLAN/priority information present in incoming frames is copied to per-packet information fields of indicated `NET_BUFFER_LIST` structures.
+
+### Status Indications
+
+The only status indications that are forwarded up by MUX are media connect status indications. See `PtStatus` for more details.
+
+### Handling Power Management
+
+During initialization (`MPInitialize`), the MUX miniport sets the attribute **NDIS\_ATTRIBUTE\_NO\_HALT\_ON\_SUSPEND** in its call to `NdisMSetMiniportAttributes`. When the MUX miniport is requested to report its Plug and Play capabilities (**OID\_PNP\_CAPABILITIES**), the MUX miniport forwards the request to the underlying miniport. If this request succeeds, then the MUX miniport overwrites the following fields before successfully completing the original request:
+
+<table>
+<colgroup>
+<col width="100%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td align="left"><pre><code>NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+NDIS_DEVICE_POWER_STATE MinPatternWakeUp= NdisDeviceStateUnspecified;
+NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp=NdisDeviceStateUnspecified</code></pre></td>
+</tr>
+</tbody>
+</table>
+
+See `PtPostProcessPnPCapabilities` for details.
+
+**OID\_PNP\_SET\_POWER** and **OID\_PNP\_QUERY\_POWER** are not passed to the lower adapter, since the lower layer miniport will receive independent requests from NDIS.
+
+NDIS calls the MUX driver’s `ProtocolPnPEvent` function (`PtPNPHandler`) whenever the underlying adapter is transitioned to a different power state. If the underlying adapter is transitioning to a low power state, the driver waits for all outstanding sends and requests to complete.
+
+Queries/sets received on a VELAN miniport that are to be forwarded to the underlying adapter are queued on the VELAN if the underlying adapter is at a low power state. These are picked up for processing on receiving a notification that the underlying adapter is back to a powered-up state.
+
+### Handling Global Reconfiguration
+
+All modifications to VELAN configuration are accompanied by PnP reconfigure notifications, i.e. `NetEventReconfigure` events passed to the MUX’s `PnPEventHandler`, `PtPNPHandler`. This driver takes a broad approach to handling reconfiguration, which is to simply re-examine all the “UpperBindings” keys for all currently bound adapters, and start off VELANs for any that do not exist – see `PtBootStrapVElans` for details.
+
+### Canceling Sends
+
+MUX propagates send cancellations from protocols above it to lower miniports.
+
+Sample Notify Object
+--------------------
+
+### Preprocessor Flags:
+
+### DISABLE\_PROTOCOLS\_TO\_PHYSICAL
+
+When this flag is defined in the Sources file, the notify object disables the bindings of other protocols such as TCP/IP to the physical adapters during the installation. When all the virtual adapters are removed either through the custom property page or as a result of uninstalling the MUX driver, the notify object re-enables those bindings.
+
+### PASSTHRU\_NOTIFY
+
+This flag is defined to allow the MUX driver to be used in a passthru mode. When this flag is defined, the notify object:
+
+1. Creates only one virtual miniport for every physical adapter the MUX protocol edge binds to.
+2. Disables the property page to prevent adding of additional virtual miniports.
+3. Stores the device name of the virtual adapter in REG\_SZ registry value under HKLM\\System\\CurrentControlSet\\Services\\muxp\\Parameters\\Adapters\\{PhysicalAdaptersInstanceGuid}\\UpperBindings, because there is one to one binding. In the MUX mode (when this flag is not defined), the notify object stores the device name in a REG\_MULTI\_SZ registry value as there could be more than one virtual miniports.
+
+You can also use this notify object with the Passthru driver by doing the following:
+
+1. Change the protocol name in file src\\network\\ndis\\passthru\\passthru.c from **PASSTHRU** to **MUXP.**
+2. Change the driver name from Passthru to MUX in the sources file.
+3. Rebuild the driver to obtain a mux.sys driver binary.
+4. Build the MUX notify object with **PASSTHRU\_NOTIFY** defined.
+5. Use the MUX inf files, muxp.inf and mux\_mp.inf, to install the driver and dll.
+
+The benefit of using techniques in the MUX notify object for a 1:1 intermediate driver (e.g. Passthru) is to be able to exercise higher level of control over the bindings of MUX with other components in the system, which is not possible with the IM filter driver.
+
+### CUSTOM\_EVENTS
+
+When this macro is defined, the notify object shows how to send custom events to the MUX IM driver when a virtual miniport is added or removed.
+
+### Notify Object Operation
+
+During installation, the notify object performs the following operations:
+
+- It creates one virtual adapter for each physical adapter the MUX protocol edge binds to.
+- It disables the bindings of other protocols such as TCP/IP to physical adapters if it has been compiled with DISABLE\_PROTOCOLS\_TO\_PHYSICAL defined in the Sources file. This is the most commonly desired behavior for N:1 MUX drivers.
+- It disables the bindings of the protocol edge of the MUX IM driver with all its virtual adapters.
+
+The notify object provides a custom property page for the MUX IM driver. The custom property page allows the user to add one or more virtual adapters on top of a physical adapter or delete an existing virtual adapter.
+
+When the MUX IM driver is uninstalled, or binding is disabled, or the user deletes all the virtual adapters on top of a physical adapter, the notify object restores the bindings of other protocols to the physical adapter if it has been compiled with the preprocessor flag **DISABLE\_PROTOCOLS\_TO\_PHYSICAL** defined in the Sources file.
+
+
+
diff --git a/network/ndis/mux/driver/60/miniport.c b/network/ndis/mux/driver/60/miniport.c
new file mode 100644
index 00000000..45cdef53
--- /dev/null
+++ b/network/ndis/mux/driver/60/miniport.c
@@ -0,0 +1,2953 @@
+/*++
+Copyright (c) 1992-2000 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS Miniport Entry points and utility functions for the NDIS
+ MUX Intermediate Miniport sample. The driver exposes zero or more
+ Virtual Ethernet LANs (VELANs) as NDIS miniport instances over
+ each lower (protocol-edge) binding to an underlying adapter.
+
+Environment:
+
+ Kernel mode.
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define MODULE_NUMBER MODULE_MINI
+
+NDIS_OID VElanSupportedOids[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_GEN_STATISTICS,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS,
+ OID_PNP_CAPABILITIES,
+ OID_PNP_SET_POWER,
+ OID_PNP_QUERY_POWER,
+ OID_PNP_ADD_WAKE_UP_PATTERN,
+ OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#if IEEE_VLAN_SUPPORT
+ OID_GEN_VLAN_ID,
+#endif
+ OID_PNP_ENABLE_WAKE_UP
+};
+
+
+NDIS_STATUS
+MPInitialize(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportDriverContext,
+ IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters
+ )
+/*++
+
+Routine Description:
+
+ This is the Miniport Initialize routine which gets called as a
+ result of our call to NdisIMInitializeDeviceInstanceEx.
+ The context parameter which we pass there is the VELan structure
+ which we retrieve here.
+
+Arguments:
+
+ MiniportAdapterHandle NDIS handle for this miniport
+ MiniportDriverContext Handle passed to NDIS when we registered the driver
+ MiniportInitParameters Miniport initialization parameters such
+ as our device context, resources, etc.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS unless something goes wrong
+
+--*/
+{
+ PVELAN pVElan;
+ UINT i;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ NDIS_HANDLE ConfigurationHandle;
+ PVOID NetworkAddress;
+ LOCK_STATE LockState;
+ NET_IFINDEX HigherLayerIfIndex, LowerLayerIfIndex;
+ NDIS_MINIPORT_ADAPTER_ATTRIBUTES MiniportAttributesContent;
+ const PNDIS_MINIPORT_ADAPTER_ATTRIBUTES MiniportAttributes = &MiniportAttributesContent;
+
+
+
+#if IEEE_VLAN_SUPPORT
+ NDIS_STRING strVlanId = NDIS_STRING_CONST("VlanID");
+ PNDIS_CONFIGURATION_PARAMETER Params;
+#endif
+
+
+ //NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RegistrationAttributes;
+ //NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GeneralAttributes;
+ NDIS_CONFIGURATION_OBJECT ConfigObject;
+
+
+ UNREFERENCED_PARAMETER(MiniportDriverContext);
+
+ //
+ // Start off by retrieving our virtual miniport context (VELAN) and
+ // storing the Miniport handle in it.
+ //
+
+ pVElan = MiniportInitParameters->IMDeviceInstanceContext;
+
+ DBGPRINT(MUX_LOUD, ("==> MPInitialize: VELAN %p\n", pVElan));
+
+ ASSERT(pVElan != NULL);
+ ASSERT(pVElan->pAdapt != NULL);
+ NdisZeroMemory(MiniportAttributes,sizeof(NDIS_MINIPORT_ADAPTER_ATTRIBUTES));
+
+ do
+ {
+ pVElan->MiniportAdapterHandle = MiniportAdapterHandle;
+ //
+ // Create an ioctl interface
+ //
+ (VOID)PtRegisterDevice();
+
+ //
+ // register this miniport with NDIS
+ //
+
+ //NdisZeroMemory(&RegistrationAttributes, sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES));
+ //NdisZeroMemory(&GeneralAttributes, sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES));
+
+ //
+ // setting registration attributes
+ //
+ MiniportAttributesContent.RegistrationAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ MiniportAttributesContent.RegistrationAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ MiniportAttributesContent.RegistrationAttributes.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES);
+
+ MiniportAttributesContent.RegistrationAttributes.MiniportAdapterContext = (NDIS_HANDLE)pVElan;
+
+
+ MiniportAttributesContent.RegistrationAttributes.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND;
+
+ MiniportAttributesContent.RegistrationAttributes.CheckForHangTimeInSeconds = 0;
+ MiniportAttributesContent.RegistrationAttributes.InterfaceType = 0;
+
+
+
+ NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(VELAN);
+ Status = NdisMSetMiniportAttributes(MiniportAdapterHandle,
+ MiniportAttributes);
+
+
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ //
+ // Access configuration parameters for this miniport.
+ //
+ ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ ConfigObject.NdisHandle = pVElan->MiniportAdapterHandle;
+ ConfigObject.Flags = 0;
+
+ Status = NdisOpenConfigurationEx(
+ &ConfigObject,
+ &ConfigurationHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ NdisReadNetworkAddress(
+ &Status,
+ &NetworkAddress,
+ &i,
+ ConfigurationHandle);
+
+ //
+ // If there is a NetworkAddress override, use it
+ //
+ if (((Status == NDIS_STATUS_SUCCESS)
+ && (i == ETH_LENGTH_OF_ADDRESS))
+ && ((!ETH_IS_MULTICAST(NetworkAddress))
+ && (ETH_IS_LOCALLY_ADMINISTERED (NetworkAddress))))
+ {
+
+ ETH_COPY_NETWORK_ADDRESS(
+ pVElan->CurrentAddress,
+ NetworkAddress);
+ }
+ else
+ {
+ MPGenerateMacAddr(pVElan);
+ }
+
+ //
+ // ignore error reading the network address
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+#if IEEE_VLAN_SUPPORT
+ //
+ // Read VLAN ID
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Params,
+ ConfigurationHandle,
+ &strVlanId,
+ NdisParameterInteger);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Check for out of bound
+ //
+ if (Params->ParameterData.IntegerData > VLAN_ID_MAX)
+ {
+ pVElan->VlanId = VLANID_DEFAULT;
+ }
+ else
+ {
+ pVElan->VlanId = Params->ParameterData.IntegerData;
+ }
+ }
+
+ else
+ {
+
+ pVElan->VlanId = VLANID_DEFAULT;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+#endif
+
+
+ NdisCloseConfiguration(ConfigurationHandle);
+
+
+
+ //
+ // set up generic attributes
+ //
+
+ MiniportAttributesContent.GeneralAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ MiniportAttributesContent.GeneralAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+ MiniportAttributesContent.GeneralAttributes.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES);
+
+ MiniportAttributesContent.GeneralAttributes.MediaType = VELAN_MEDIA_TYPE;
+ MiniportAttributesContent.GeneralAttributes.MtuSize = pVElan->pAdapt->BindParameters.MtuSize;
+ MiniportAttributesContent.GeneralAttributes.MaxXmitLinkSpeed = pVElan->pAdapt->BindParameters.MaxXmitLinkSpeed;
+ MiniportAttributesContent.GeneralAttributes.MaxRcvLinkSpeed = pVElan->pAdapt->BindParameters.MaxRcvLinkSpeed;
+ MiniportAttributesContent.GeneralAttributes.XmitLinkSpeed = pVElan->pAdapt->BindParameters.XmitLinkSpeed;
+ MiniportAttributesContent.GeneralAttributes.RcvLinkSpeed = pVElan->pAdapt->BindParameters.RcvLinkSpeed;
+
+
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pVElan->pAdapt, &LockState);
+
+ //
+ // Miniport below has indicated some status indication
+ //
+ MiniportAttributesContent.GeneralAttributes.MediaConnectState = pVElan->pAdapt->LastIndicatedLinkState.MediaConnectState;
+ MiniportAttributesContent.GeneralAttributes.MediaDuplexState = pVElan->pAdapt->LastIndicatedLinkState.MediaDuplexState;
+ MiniportAttributesContent.GeneralAttributes.XmitLinkSpeed = pVElan->pAdapt->LastIndicatedLinkState.XmitLinkSpeed;
+ MiniportAttributesContent.GeneralAttributes.RcvLinkSpeed = pVElan->pAdapt->LastIndicatedLinkState.RcvLinkSpeed;
+
+ pVElan->LastIndicatedStatus = NDIS_STATUS_LINK_STATE;
+
+ pVElan->LastIndicatedLinkState = pVElan->pAdapt->LastIndicatedLinkState;
+
+
+ MiniportAttributesContent.GeneralAttributes.LookaheadSize = pVElan->pAdapt->BindParameters.LookaheadSize;
+ MiniportAttributesContent.GeneralAttributes.MaxMulticastListSize = pVElan->pAdapt->BindParameters.MaxMulticastListSize;
+ MiniportAttributesContent.GeneralAttributes.MacAddressLength = pVElan->pAdapt->BindParameters.MacAddressLength;
+
+ MiniportAttributesContent.GeneralAttributes.PhysicalMediumType = pVElan->pAdapt->BindParameters.PhysicalMediumType ;
+ MiniportAttributesContent.GeneralAttributes.AccessType = pVElan->pAdapt->BindParameters.AccessType ;
+ MiniportAttributesContent.GeneralAttributes.DirectionType = pVElan->pAdapt->BindParameters.DirectionType;
+ MiniportAttributesContent.GeneralAttributes.ConnectionType = pVElan->pAdapt->BindParameters.ConnectionType ;
+ MiniportAttributesContent.GeneralAttributes.IfType = pVElan->pAdapt->BindParameters.IfType ;
+ MiniportAttributesContent.GeneralAttributes.IfConnectorPresent = FALSE; // RFC 2665 TRUE if physical adapter
+
+ if (pVElan->pAdapt->BindParameters.RcvScaleCapabilities)
+ {
+ MiniportAttributesContent.GeneralAttributes.RecvScaleCapabilities = pVElan->pAdapt->BindParameters.RcvScaleCapabilities;
+ }
+ else
+ {
+ MiniportAttributesContent.GeneralAttributes.RecvScaleCapabilities = NULL;
+ }
+
+ MiniportAttributesContent.GeneralAttributes.MacOptions = NDIS_MAC_OPTION_NO_LOOPBACK;
+
+
+#if IEEE_VLAN_SUPPORT
+ MiniportAttributesContent.GeneralAttributes.MacOptions |= (NDIS_MAC_OPTION_8021P_PRIORITY |
+ NDIS_MAC_OPTION_8021Q_VLAN);
+
+#endif
+
+ MiniportAttributesContent.GeneralAttributes.SupportedPacketFilters = pVElan->pAdapt->BindParameters.SupportedPacketFilters;
+
+ MiniportAttributesContent.GeneralAttributes.SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED |
+ NDIS_STATISTICS_RCV_OK_SUPPORTED |
+ NDIS_STATISTICS_XMIT_ERROR_SUPPORTED |
+ NDIS_STATISTICS_RCV_ERROR_SUPPORTED |
+ NDIS_STATISTICS_RCV_CRC_ERROR_SUPPORTED |
+ NDIS_STATISTICS_RCV_NO_BUFFER_SUPPORTED |
+ NDIS_STATISTICS_TRANSMIT_QUEUE_LENGTH_SUPPORTED |
+ NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED;
+
+
+ NdisMoveMemory(&MiniportAttributesContent.GeneralAttributes.CurrentMacAddress,
+ &pVElan->CurrentAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ NdisMoveMemory(&MiniportAttributesContent.GeneralAttributes.PermanentMacAddress,
+ &pVElan->PermanentAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ MiniportAttributesContent.GeneralAttributes.PowerManagementCapabilities = &pVElan->pAdapt->PowerManagementCapabilities;
+ MiniportAttributesContent.GeneralAttributes.SupportedOidList = VElanSupportedOids;
+ MiniportAttributesContent.GeneralAttributes.SupportedOidListLength = sizeof(VElanSupportedOids);
+ MUX_RELEASE_ADAPT_READ_LOCK(pVElan->pAdapt, &LockState);
+ Status = NdisMSetMiniportAttributes(MiniportAdapterHandle,MiniportAttributes);
+
+ pVElan->MiniportInitPending = FALSE;
+ } while (FALSE);
+
+
+ //
+ // If we had received an UnbindAdapter notification on the underlying
+ // adapter, we would have blocked that thread waiting for the IM Init
+ // process to complete. Wake up any such thread.
+ //
+ // See PtUnbindAdapter for more details.
+ //
+ //
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // we should set this to FALSE only if we successfully initialized the adapter
+ // otherwise the unbind routine will wait forever for this VElan to go away
+ //
+ pVElan->MiniportInitPending = FALSE;
+ //
+ // Save the IfIndex for this VELAN
+ //
+ HigherLayerIfIndex = MiniportInitParameters->IfIndex;
+ LowerLayerIfIndex = pVElan->pAdapt->BindParameters.BoundIfIndex;
+
+ Status = NdisIfAddIfStackEntry(HigherLayerIfIndex,
+ LowerLayerIfIndex);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pVElan->IfIndex = HigherLayerIfIndex;
+ }
+
+ //
+ // Ignore if the add fails
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+ else
+ {
+ pVElan->MiniportAdapterHandle = NULL;
+ }
+
+ if (pVElan->MiniportInitPending == TRUE)
+ {
+ pVElan->MiniportInitPending = FALSE;
+ }
+
+ // TODO: check to see if we can set the init event in a failure case?
+
+ NdisSetEvent(&pVElan->MiniportInitEvent);
+
+ DBGPRINT(MUX_LOUD, ("<== MPInitialize: VELAN %p, Status %x\n", pVElan, Status));
+
+ return Status;
+}
+
+NDIS_STATUS
+MPQueryInformation(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This function is called to handle the query request specified by NdisRequest
+ All query requests are first handled right here, since this is a virtual
+ device (not pass-through).
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ NdisRequest Specify the query request.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+ Return code from the MPForwardOidRequest below.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ NDIS_MEDIUM Medium = VELAN_MEDIA_TYPE;
+ UCHAR VendorDesc[] = VELAN_VENDOR_DESC;
+ ULONG ulInfo;
+ ULONG64 ulInfo64;
+ USHORT usInfo;
+ PVOID pInfo = (PVOID)&ulInfo;
+ ULONG ulInfoLen = sizeof(ulInfo), NeededLength = 0;
+ // Should we forward the request to the miniport below?
+ BOOLEAN bForwardRequest = FALSE;
+
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ ULONG InformationBufferLength;
+ PULONG BytesWritten;
+ PULONG BytesNeeded;
+ NDIS_STATISTICS_INFO StatisticsInfo;
+
+
+ DBGPRINT(MUX_LOUD, ("==> MPQueryInformation: VElan %p, Request %p\n",pVElan, NdisRequest));
+
+ Oid = NdisRequest->DATA.QUERY_INFORMATION.Oid;
+ InformationBuffer = NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ InformationBufferLength = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
+ BytesWritten = (ULONG*) &(NdisRequest->DATA.QUERY_INFORMATION.BytesWritten);
+ BytesNeeded = (ULONG*) &(NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
+
+
+ // Initialize the result
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ pInfo = (PVOID) VElanSupportedOids;
+ ulInfoLen = sizeof(VElanSupportedOids);
+ break;
+
+ case OID_GEN_SUPPORTED_GUIDS:
+ //
+ // Do NOT forward this down, otherwise we will
+ // end up with spurious instances of private WMI
+ // classes supported by the lower driver(s).
+ //
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ pInfo = (PVOID) &HardwareStatus;
+ ulInfoLen = sizeof(NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ pInfo = (PVOID) &Medium;
+ ulInfoLen = sizeof(NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ ulInfo = pVElan->LookAhead;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ ulInfo = ETH_MAX_PACKET_SIZE - ETH_HEADER_SIZE;
+#if IEEE_VLAN_SUPPORT
+ ulInfo -= VLAN_TAG_HEADER_SIZE;
+
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ ulInfo = (ULONG) ETH_MAX_PACKET_SIZE;
+#if IEEE_VLAN_SUPPORT
+ ulInfo -= VLAN_TAG_HEADER_SIZE;
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ ulInfo = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_NO_LOOPBACK;
+#if IEEE_VLAN_SUPPORT
+ ulInfo |= (NDIS_MAC_OPTION_8021P_PRIORITY |
+ NDIS_MAC_OPTION_8021Q_VLAN);
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ bForwardRequest = TRUE;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ ulInfo = ETH_MAX_PACKET_SIZE * pVElan->MaxBusySends;
+#if IEEE_VLAN_SUPPORT
+ ulInfo -= VLAN_TAG_HEADER_SIZE * pVElan->MaxBusySends;
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ ulInfo = ETH_MAX_PACKET_SIZE * pVElan->MaxBusyRecvs;
+#if IEEE_VLAN_SUPPORT
+ ulInfo -= VLAN_TAG_HEADER_SIZE * pVElan->MaxBusyRecvs;
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ ulInfo = VELAN_VENDOR_ID;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ pInfo = VendorDesc;
+ ulInfoLen = sizeof(VendorDesc);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ ulInfo = VELAN_VENDOR_ID;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ usInfo = (USHORT) VELAN_DRIVER_VERSION;
+ pInfo = (PVOID) &usInfo;
+ ulInfoLen = sizeof(USHORT);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ pInfo = pVElan->PermanentAddress;
+ ulInfoLen = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ pInfo = pVElan->CurrentAddress;
+ ulInfoLen = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ ulInfo = VELAN_MAX_MCAST_LIST;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ ulInfo = VELAN_MAX_SEND_PKTS;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ //
+ // Get this from the adapter below.
+ //
+ bForwardRequest = TRUE;
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ // simply succeed this.
+ ulInfoLen = sizeof(ULONG);
+ ulInfo = 0;
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ case OID_PNP_WAKE_UP_PATTERN_LIST:
+ //
+ // Pass down these power management/PNP OIDs.
+ //
+ bForwardRequest = TRUE;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ ulInfo64 = pVElan->GoodTransmits;
+ pInfo = &ulInfo64;
+ if (InformationBufferLength >= sizeof(ULONG64) ||
+ InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+ NeededLength = sizeof(ulInfo64);
+
+ break;
+
+ case OID_GEN_RCV_OK:
+ ulInfo64 = pVElan->GoodReceives;
+ pInfo = &ulInfo64;
+ if (InformationBufferLength >= sizeof(ULONG64) ||
+ InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+
+ NeededLength = sizeof(ulInfo64);
+
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ ulInfo = pVElan->TxAbortExcessCollisions +
+ pVElan->TxDmaUnderrun +
+ pVElan->TxLostCRS +
+ pVElan->TxLateCollisions+
+ pVElan->TransmitFailuresOther;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ ulInfo = pVElan->RcvCrcErrors +
+ pVElan->RcvAlignmentErrors +
+ pVElan->RcvDmaOverrunErrors +
+ pVElan->RcvRuntErrors;
+#if IEEE_VLAN_SUPPORT
+ ulInfo +=
+ (pVElan->RcvVlanIdErrors +
+ pVElan->RcvFormatErrors);
+#endif
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ ulInfo = pVElan->RcvResourceErrors;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ ulInfo = pVElan->RcvCrcErrors;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ ulInfo = pVElan->RegNumTcb;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_GEN_STATISTICS:
+ ulInfoLen = sizeof (NDIS_STATISTICS_INFO);
+ NdisZeroMemory(&StatisticsInfo, sizeof(NDIS_STATISTICS_INFO));
+
+ StatisticsInfo.Header.Revision = NDIS_OBJECT_REVISION_1;
+ StatisticsInfo.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ StatisticsInfo.Header.Size = sizeof(NDIS_STATISTICS_INFO);
+ StatisticsInfo.SupportedStatistics = NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS |
+ NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR |
+ NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR;
+
+ StatisticsInfo.ifInDiscards = pVElan->RcvCrcErrors +
+ pVElan->RcvAlignmentErrors +
+ pVElan->RcvResourceErrors +
+ pVElan->RcvDmaOverrunErrors +
+ pVElan->RcvRuntErrors;
+
+#if IEEE_VLAN_SUPPORT
+ StatisticsInfo.ifInDiscards += (pVElan->RcvVlanIdErrors +
+ pVElan->RcvFormatErrors);
+#endif
+
+ StatisticsInfo.ifInErrors = StatisticsInfo.ifInDiscards -
+ pVElan->RcvResourceErrors;
+
+
+ StatisticsInfo.ifOutErrors = pVElan->TxAbortExcessCollisions +
+ pVElan->TxDmaUnderrun +
+ pVElan->TxLostCRS +
+ pVElan->TxLateCollisions;
+
+ pInfo = &StatisticsInfo;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ ulInfo = pVElan->RcvAlignmentErrors;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ ulInfo = pVElan->OneRetry;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ ulInfo = pVElan->MoreThanOneRetry;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+ ulInfo = pVElan->TxOKButDeferred;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ ulInfo = pVElan->TxAbortExcessCollisions;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+ ulInfo = pVElan->RcvDmaOverrunErrors;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+ ulInfo = pVElan->TxDmaUnderrun;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ ulInfo = pVElan->TxLostCRS;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ ulInfo = pVElan->TxLostCRS;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ ulInfo = pVElan->TxLateCollisions;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+#if IEEE_VLAN_SUPPORT
+ case OID_GEN_VLAN_ID:
+ ulInfo = pVElan->VlanId;
+ pInfo = (PVOID) &ulInfo;
+ break;
+
+#endif
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (bForwardRequest == FALSE)
+ {
+ //
+ // No need to forward this request down.
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (ulInfoLen <= InformationBufferLength)
+ {
+ // Copy result into InformationBuffer
+ *BytesWritten = ulInfoLen;
+ if(ulInfoLen)
+ {
+ NdisMoveMemory(InformationBuffer, pInfo, ulInfoLen);
+
+ if (NeededLength > ulInfoLen)
+ {
+ *BytesNeeded = NeededLength;
+ }
+ }
+
+
+ }
+ else
+ {
+ // too short
+ *BytesNeeded = (NeededLength > ulInfoLen ? NeededLength : ulInfoLen);
+
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ }
+ }
+ else
+ {
+
+
+ //
+ // Send this request to the binding below.
+ //
+ Status = MPForwardOidRequest(pVElan,NdisRequest);
+ }
+
+ if ((Status != NDIS_STATUS_SUCCESS) &&
+ (Status != NDIS_STATUS_PENDING))
+ {
+ DBGPRINT(MUX_WARN, ("MPQueryInformation VELAN %p, OID 0x%08x, Status = 0x%08x\n",
+ pVElan, Oid, Status));
+ }
+
+
+
+ DBGPRINT(MUX_LOUD, ("<== MPQueryInformation: VElan %p, Request %p returning %08lx\n",pVElan, NdisRequest, Status));
+
+ return(Status);
+
+}
+
+
+NDIS_STATUS
+MPSetInformation(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ )
+/*++
+
+Routine Description:
+
+ This is the handler for an set request operation. Relevant
+ requests are forwarded down to the lower miniport for handling.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ NdisRequest Specify the set request
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_INVALID_LENGTH
+ Return code from the MPForwardOidRequest below.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG PacketFilter;
+ NDIS_DEVICE_POWER_STATE NewDeviceState;
+
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ ULONG InformationBufferLength;
+ PULONG BytesRead;
+ PULONG BytesNeeded;
+
+ // Should we forward the request to the miniport below?
+ BOOLEAN bForwardRequest = FALSE;
+ NDIS_STATUS_INDICATION StatusIndication;
+
+ DBGPRINT(MUX_LOUD, ("==> MPSetInformation: VElan %p, Request %p\n", pVElan, NdisRequest));
+
+ NdisZeroMemory(&StatusIndication, sizeof(NDIS_STATUS_INDICATION));
+ Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
+ InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
+ InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
+ BytesRead = (ULONG*) &(NdisRequest->DATA.SET_INFORMATION.BytesRead);
+ BytesNeeded = (ULONG*) &(NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ //
+ // Let the miniport below handle these OIDs:
+ //
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ case OID_PNP_ENABLE_WAKE_UP:
+ bForwardRequest = TRUE;
+ break;
+
+ case OID_PNP_SET_POWER:
+ //
+ // Store new power state and succeed the request.
+ //
+ *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
+ if (InformationBufferLength < *BytesNeeded)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE)InformationBuffer);
+
+ //
+ // Check if the VELAN adapter goes from lower power state to D0
+ //
+ if ((MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
+ && (!MUX_IS_LOW_POWER_STATE(NewDeviceState)))
+ {
+ //
+ // Indicate the media status is necessary
+ //
+ if (pVElan->LastIndicatedStatus != pVElan->LatestUnIndicateStatus)
+ {
+
+ StatusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ StatusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ StatusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
+
+ StatusIndication.SourceHandle = pVElan->MiniportAdapterHandle;
+ StatusIndication.StatusCode = pVElan->LatestUnIndicateStatus;
+ if (pVElan->LatestUnIndicateStatus == NDIS_STATUS_LINK_STATE)
+ {
+ StatusIndication.StatusBuffer = &pVElan->LatestUnIndicateLinkState;
+ StatusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
+
+ }
+ else
+ {
+ StatusIndication.StatusBuffer = NULL;
+ StatusIndication.StatusBufferSize = 0;
+ }
+
+ NdisMIndicateStatusEx(pVElan->MiniportAdapterHandle, &StatusIndication);
+
+ pVElan->LastIndicatedStatus = pVElan->LatestUnIndicateStatus;
+
+ if (pVElan->LatestUnIndicateStatus == NDIS_STATUS_LINK_STATE)
+ {
+ pVElan->LastIndicatedLinkState = pVElan->LatestUnIndicateLinkState;
+ }
+
+ }
+ else
+ {
+ if (pVElan->LastIndicatedStatus == NDIS_STATUS_LINK_STATE)
+ {
+ if (!NdisEqualMemory(&pVElan->LatestUnIndicateLinkState,
+ &pVElan->LastIndicatedLinkState,
+ sizeof(NDIS_LINK_STATE)))
+ {
+
+ StatusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ StatusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ StatusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
+
+ StatusIndication.SourceHandle = pVElan->MiniportAdapterHandle;
+ StatusIndication.StatusCode = pVElan->LatestUnIndicateStatus;
+ StatusIndication.StatusBuffer = &pVElan->LatestUnIndicateLinkState;
+ StatusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
+
+ NdisMIndicateStatusEx(pVElan->MiniportAdapterHandle, &StatusIndication);
+
+ pVElan->LastIndicatedStatus = pVElan->LatestUnIndicateStatus;
+ pVElan->LastIndicatedLinkState = pVElan->LatestUnIndicateLinkState;
+ }
+ }
+ }
+ }
+ //
+ // Check if the VELAN adapter goes from D0 to lower power state
+ //
+ if ((!MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
+ && (MUX_IS_LOW_POWER_STATE(NewDeviceState)))
+ {
+ //
+ // Initialize LastUnIndicateStatus
+ //
+ pVElan->LatestUnIndicateStatus = pVElan->LastIndicatedStatus;
+
+ if (pVElan->LastIndicatedStatus == NDIS_STATUS_LINK_STATE)
+ {
+ pVElan->LatestUnIndicateLinkState = pVElan->LastIndicatedLinkState;
+ }
+ }
+
+ NdisMoveMemory(&pVElan->MPDevicePowerState,
+ InformationBuffer,
+ *BytesNeeded);
+
+ DBGPRINT(MUX_INFO, ("SetInfo: VElan %p, new miniport power state --- %d\n",
+ pVElan, pVElan->MPDevicePowerState));
+
+ break;
+
+ case OID_802_3_MULTICAST_LIST:
+ Status = MPSetMulticastList(pVElan,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesRead,
+ BytesNeeded);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (InformationBufferLength != sizeof(ULONG))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ *BytesNeeded = sizeof(ULONG);
+ break;
+ }
+
+ NdisMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));
+ *BytesRead = sizeof(ULONG);
+
+ Status = MPSetPacketFilter(pVElan,
+ PacketFilter);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (InformationBufferLength < sizeof(ULONG))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ *BytesNeeded = sizeof(ULONG);
+ break;
+ }
+#if IEEE_VLAN_SUPPORT
+ //
+ // In order to simplify parsing and to avoid excessive
+ // copying, we need the tag header also to be present in the
+ // lookahead buffer. Make sure that the driver below
+ // includes that.
+ //
+ if (*(UNALIGNED PULONG)InformationBuffer < VLAN_TAG_HEADER_SIZE)
+ {
+ pVElan->RestoreLookaheadSize = TRUE;
+ *(UNALIGNED PULONG)InformationBuffer += VLAN_TAG_HEADER_SIZE;
+ }
+#endif
+ bForwardRequest = TRUE;
+ break;
+
+#if IEEE_VLAN_SUPPORT
+ case OID_GEN_VLAN_ID:
+ if (InformationBufferLength == sizeof(ULONG))
+ {
+ NdisMoveMemory((&pVElan->VlanId), InformationBuffer, sizeof(ULONG));
+
+ }
+ else
+ {
+ *BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ break;
+#endif
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ if (bForwardRequest == FALSE)
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = InformationBufferLength;
+ }
+ }
+ else
+ {
+ //
+ // Send this request to the binding below.
+ //
+ Status = MPForwardOidRequest(pVElan,NdisRequest);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== MPSetInformation: VElan %p, Request %p returning %08lx\n",pVElan, NdisRequest, Status));
+
+ return(Status);
+}
+
+NDIS_STATUS
+MPMethodRequest(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ )
+/*++
+Routine Description:
+
+ WMI method request handler
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ NdisRequest Pointer to the request sent down by NDIS
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+
+
+--*/
+{
+ NDIS_OID Oid;
+ ULONG MethodId;
+ PVOID InformationBuffer;
+ ULONG InputBufferLength;
+ ULONG OutputBufferLength;
+ ULONG BytesNeeded;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(pVElan);
+
+ DBGPRINT(MUX_LOUD, ("==> MPMethodRequest: VElan %p, Request %p\n", pVElan, NdisRequest));
+
+
+ Oid = NdisRequest->DATA.METHOD_INFORMATION.Oid;
+ InformationBuffer = (PVOID)(NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer);
+ InputBufferLength = NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength;
+ OutputBufferLength = NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength;
+ MethodId = NdisRequest->DATA.METHOD_INFORMATION.MethodId;
+ UNREFERENCED_PARAMETER(Oid);
+ UNREFERENCED_PARAMETER(InformationBuffer);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(MethodId);
+
+
+ BytesNeeded = 0;
+
+ switch(Oid)
+ {
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+
+ DBGPRINT(MUX_LOUD, ("<== MPMethodRequest: VElan %p, Request %p returning %08lx\n",pVElan, NdisRequest, Status));
+
+ return Status;
+
+}
+
+
+
+NDIS_STATUS
+MPOidRequest(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_OID_REQUEST NdisRequest
+ )
+/*++
+Routine Description:
+
+ MiniportRequest dispatch handler
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ NdisRequest Pointer to NDIS_OID_REQUEST sent down by NDIS.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+ NDIS_STATUS_XXX
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ NDIS_REQUEST_TYPE RequestType;
+ NDIS_STATUS Status;
+
+ DBGPRINT(MUX_LOUD,("==> MPOidRequest: Request %p\n", NdisRequest));
+
+ RequestType = NdisRequest->RequestType;
+
+ switch(RequestType)
+ {
+ case NdisRequestMethod:
+ Status = MPMethodRequest(pVElan, NdisRequest);
+ break;
+
+ case NdisRequestSetInformation:
+ Status = MPSetInformation(pVElan, NdisRequest);
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ Status = MPQueryInformation(pVElan, NdisRequest);
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ DBGPRINT(MUX_LOUD,("<== MPOidRequest: Request %p, Status %08lx\n", NdisRequest, Status));
+
+ return Status;
+}
+
+
+
+VOID
+MPHalt(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HALT_ACTION HaltAction
+ )
+/*++
+
+Routine Description:
+
+ Halt handler. Add any further clean-up for the VELAN to this
+ function.
+
+ We wait for all pending I/O on the VELAN to complete and then
+ unlink the VELAN from the adapter.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the pVElan
+ HaltAction The reason adapter is being halted
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ NET_IFINDEX LowerLayerIfIndex;
+
+ UNREFERENCED_PARAMETER(HaltAction);
+
+
+ DBGPRINT(MUX_LOUD, ("==> MPHalt: VELAN %p\n", pVElan));
+
+ //
+ // Mark the VELAN so that we don't send down any new requests or
+ // sends to the adapter below, or new receives/indications to
+ // protocols above.
+ //
+ pVElan->MiniportHalting = TRUE;
+
+ //
+ // Update the packet filter on the underlying adapter if needed.
+ //
+ if (pVElan->PacketFilter != 0)
+ {
+ MPSetPacketFilter(pVElan, 0);
+ }
+
+ //
+ // Wait for any outstanding sends or requests to complete.
+ //
+ while (pVElan->OutstandingSends)
+ {
+ DBGPRINT(MUX_INFO, ("MPHalt: VELAN %p has %d outstanding sends\n",
+ pVElan, pVElan->OutstandingSends));
+ NdisMSleep(20000);
+ }
+
+ //
+ // Wait for all outstanding indications to be completed and
+ // any pended receive packets to be returned to us.
+ //
+ while (pVElan->OutstandingReceives)
+ {
+ DBGPRINT(MUX_INFO, ("MPHalt: VELAN %p has %d outstanding receives\n",
+ pVElan, pVElan->OutstandingReceives));
+ NdisMSleep(20000);
+ }
+
+
+ //
+ // Delete the ioctl interface that was created when the miniport
+ // was created.
+ //
+ (VOID)PtDeregisterDevice();
+
+
+ //
+ // Delete stack entry for this Velan
+ //
+ if (pVElan->IfIndex != 0)
+ {
+ LowerLayerIfIndex = pVElan->pAdapt->BindParameters.BoundIfIndex;
+
+ NdisIfDeleteIfStackEntry(pVElan->IfIndex,
+ LowerLayerIfIndex);
+ pVElan->IfIndex = 0;
+ }
+
+
+ //
+ // Unlink the VELAN from its parent ADAPT structure. This will
+ // dereference the VELAN.
+ //
+ pVElan->MiniportAdapterHandle = NULL;
+ PtUnlinkVElanFromAdapter(pVElan);
+
+ DBGPRINT(MUX_LOUD, ("<== MPHalt: pVElan %p\n", pVElan));
+}
+
+
+NDIS_STATUS
+MPForwardOidRequest(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST Request
+ )
+/*++
+
+Routine Description:
+
+ Utility routine that forwards an NDIS request made on a VELAN to the
+ lower binding. Since at most a single request can be pended on a VELAN,
+ we use the pre-allocated request structure embedded in the VELAN struct.
+
+Arguments:
+
+ pVElan Pointer to a VElan Adapter
+ Request Pointer to an NDIS request to be forwarded to the below adapter.
+
+Return Value:
+
+ NDIS_STATUS_PENDING if a request was sent down.
+ NDIS_STATUS_XXX Otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PMUX_NDIS_REQUEST pMuxNdisRequest = &pVElan->Request;
+
+ PADAPT pAdapt = pVElan->pAdapt;
+
+
+ DBGPRINT(MUX_LOUD, ("==> MPForwardOidRequest: VELAN %p, Request %p\n", pVElan, Request));
+
+ do
+ {
+ MUX_INCR_PENDING_SENDS(pVElan);
+
+ //
+ // If the miniport below is going away, fail the request
+ //
+ NdisAcquireSpinLock(&pVElan->Lock);
+ if (pVElan->DeInitializing == TRUE)
+ {
+ NdisReleaseSpinLock(&pVElan->Lock);
+ MUX_DECR_PENDING_SENDS(pVElan);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ //
+ // If the virtual miniport edge is at a low power
+ // state, fail this request.
+ //
+ if (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
+ {
+ MUX_DECR_PENDING_SENDS(pVElan);
+ Status = NDIS_STATUS_ADAPTER_NOT_READY;
+ break;
+ }
+
+ NdisAcquireSpinLock(&pVElan->Lock);
+ pMuxNdisRequest->Cancelled = FALSE;
+ pMuxNdisRequest->OrigRequest = Request;
+ pMuxNdisRequest->pCallback = PtCompleteForwardedRequest;
+ pMuxNdisRequest->Request.RequestType = Request->RequestType;
+ pMuxNdisRequest->Refcount = 1;
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ pMuxNdisRequest->Request.Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pMuxNdisRequest->Request.Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pMuxNdisRequest->Request.Header.Size = sizeof(NDIS_OID_REQUEST);
+
+ switch (Request->RequestType)
+ {
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid = Request->DATA.QUERY_INFORMATION.Oid;
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ Request->DATA.QUERY_INFORMATION.InformationBuffer;
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ Request->DATA.QUERY_INFORMATION.InformationBufferLength;
+ break;
+
+ case NdisRequestSetInformation:
+ pMuxNdisRequest->Request.DATA.SET_INFORMATION.Oid = Request->DATA.SET_INFORMATION.Oid;
+ pMuxNdisRequest->Request.DATA.SET_INFORMATION.InformationBuffer =
+ Request->DATA.SET_INFORMATION.InformationBuffer;
+ pMuxNdisRequest->Request.DATA.SET_INFORMATION.InformationBufferLength =
+ Request->DATA.SET_INFORMATION.InformationBufferLength;
+ break;
+
+ case NdisRequestMethod:
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ //
+ // If the miniport below is going away
+ //
+ NdisAcquireSpinLock(&pVElan->Lock);
+ if (pVElan->DeInitializing == TRUE)
+ {
+ pMuxNdisRequest->OrigRequest = NULL;
+ NdisReleaseSpinLock(&pVElan->Lock);
+ MUX_DECR_PENDING_SENDS(pVElan);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ // If the lower binding has been notified of a low
+ // power state, queue this request; it will be picked
+ // up again when the lower binding returns to D0.
+ //
+ if (MUX_IS_LOW_POWER_STATE(pVElan->pAdapt->PtDevicePowerState))
+ {
+ DBGPRINT(MUX_INFO, ("ForwardRequest: VELAN %p, Adapt %p power"
+ " state is %d, queueing OID %x\n",
+ pVElan, pVElan->pAdapt,
+ pVElan->pAdapt->PtDevicePowerState,
+ Request->DATA.QUERY_INFORMATION.Oid));
+
+ pVElan->QueuedRequest = TRUE;
+ NdisReleaseSpinLock(&pVElan->Lock);
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+
+ if (pMuxNdisRequest->Cancelled == TRUE)
+ {
+ NdisReleaseSpinLock(&pVElan->Lock);
+ Status = NDIS_STATUS_REQUEST_ABORTED;
+ PtRequestComplete(pVElan->pAdapt, &pMuxNdisRequest->Request, Status);
+ break;
+ }
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ pAdapt->OutstandingRequests ++;
+
+ if ((pAdapt->Flags & MUX_BINDING_CLOSING)== MUX_BINDING_CLOSING)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NdisOidRequest(pVElan->BindingHandle,
+ &pMuxNdisRequest->Request);
+ }
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ PtRequestComplete(pVElan->pAdapt, &pMuxNdisRequest->Request, Status);
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== MPForwardOidRequest: VELAN %p, Request %p, Status %8x\n", pVElan, Request, Status));
+
+#if IEEE_VELAN_SUPPORT
+ if ((Status != NDIS_STATUS_PENDING)
+ && (((Request->RequestType == NdisRequestSetInformation)
+ && (Request->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_LOOKAHEAD))
+ && (pVElan->RestoreLookaheadSize == TRUE)))
+ {
+ pVElan->RestoreLookaheadSize = FALSE;
+ *(UNALIGNED PULONG)(Request->DATA.SET_INFORMATION.InformationBuffer) -= VLAN_TAG_HEADER_SIZE;
+ }
+#endif
+
+ return (Status);
+}
+
+NDIS_STATUS
+MPSetPacketFilter(
+ IN PVELAN pVElan,
+ IN ULONG PacketFilter
+ )
+/*++
+Routine Description:
+
+ This routine will set up the VELAN so that it accepts packets
+ that match the specified packet filter. The only filter bits
+ that can truly be toggled are for broadcast and promiscuous.
+
+ The MUX driver always sets the lower binding to promiscuous
+ mode, but we do some optimization here to avoid turning on
+ receives too soon. That is, we set the packet filter on the lower
+ binding to a non-zero value iff at least one of the VELANs
+ has a non-zero filter value.
+
+ NOTE: setting the lower binding to promiscuous mode can
+ impact CPU utilization. The only reason we set the lower binding
+ to promiscuous mode in this sample is that we need to be able
+ to receive unicast frames directed to MAC address(es) that do not
+ match the local adapter's MAC address. If VELAN MAC addresses
+ are set to be equal to that of the adapter below, it is sufficient
+ to set the lower packet filter to the bitwise OR'ed value of
+ packet filter settings on all VELANs.
+
+
+Arguments:
+
+ pVElan - pointer to VELAN
+ PacketFilter - the new packet filter
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PADAPT pAdapt;
+ PVELAN pTmpVElan;
+ PLIST_ENTRY p;
+ ULONG AdapterFilter;
+ BOOLEAN bSendUpdate = FALSE;
+ LOCK_STATE LockState;
+
+ DBGPRINT(MUX_LOUD, ("==> MPSetPacketFilter VELAN %p, Filter %x\n", pVElan, PacketFilter));
+
+ do
+ {
+ //
+ // Any bits not supported?
+ //
+ if (PacketFilter & ~VELAN_SUPPORTED_FILTERS)
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ AdapterFilter = 0;
+ pAdapt = pVElan->pAdapt;
+
+ //
+ // Grab a Write lock on the adapter so that this operation
+ // does not interfere with any receives that might be accessing
+ // filter information.
+ //
+ MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ //
+ // Save the new packet filter value
+ //
+ pVElan->PacketFilter = PacketFilter;
+
+ //
+ // Compute the new combined filter for all VELANs on this
+ // adapter.
+ //
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+ pTmpVElan = CONTAINING_RECORD(p, VELAN, Link);
+ AdapterFilter |= pTmpVElan->PacketFilter;
+ }
+
+ //
+ // If all VELANs have packet filters set to 0, turn off
+ // receives on the lower adapter, if not already done.
+ //
+ if ((AdapterFilter == 0) && (pAdapt->PacketFilter != 0))
+ {
+ bSendUpdate = TRUE;
+ pAdapt->PacketFilter = 0;
+ }
+ else
+ //
+ // If receives had been turned off on the lower adapter, and
+ // the new filter is non-zero, turn on the lower adapter.
+ // We set the adapter to promiscuous mode in this sample
+ // so that we are able to receive packets directed to
+ // any of the VELAN MAC addresses.
+ //
+ if ((AdapterFilter != 0) && (pAdapt->PacketFilter == 0))
+ {
+ bSendUpdate = TRUE;
+ pAdapt->PacketFilter = MUX_ADAPTER_PACKET_FILTER;
+ }
+
+ MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ if (bSendUpdate)
+ {
+ PtRequestAdapterAsync(
+ pAdapt,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &pAdapt->PacketFilter,
+ sizeof(pAdapt->PacketFilter),
+ PtDiscardCompletedRequest);
+ }
+
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== MPSetPacketFilter VELAN %p, Status %x\n", pVElan, Status));
+
+ return(Status);
+}
+
+
+NDIS_STATUS
+MPSetMulticastList(
+ IN PVELAN pVElan,
+ _In_reads_bytes_(InformationBufferLength) IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesRead,
+ OUT PULONG pBytesNeeded
+ )
+/*++
+
+Routine Description:
+
+ Set the multicast list on the specified VELAN miniport.
+ We simply validate all information and copy in the multicast
+ list.
+
+ We don't forward the multicast list information down since
+ we set the lower binding to promisc. mode.
+
+Arguments:
+
+ pVElan - VELAN on which to set the multicast list
+ InformationBuffer - pointer to new multicast list
+ InformationBufferLength - length in bytes of above list
+ pBytesRead - place to return # of bytes read from the above
+ pBytesNeeded - place to return expected min # of bytes
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_MULTICAST_FULL
+
+--*/
+{
+ NDIS_STATUS Status;
+ PADAPT pAdapt;
+ LOCK_STATE LockState;
+
+ DBGPRINT(MUX_LOUD, ("==> MPSetMulticastList VELAN %p\n", pVElan));
+ //
+ // Initialize.
+ //
+ *pBytesNeeded = sizeof(MUX_MAC_ADDRESS);
+ *pBytesRead = 0;
+ Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ if (InformationBufferLength % sizeof(MUX_MAC_ADDRESS))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (InformationBufferLength > (VELAN_MAX_MCAST_LIST * sizeof(MUX_MAC_ADDRESS)))
+ {
+ Status = NDIS_STATUS_MULTICAST_FULL;
+ *pBytesNeeded = VELAN_MAX_MCAST_LIST * sizeof(MUX_MAC_ADDRESS);
+ break;
+ }
+
+ pAdapt = pVElan->pAdapt;
+
+ //
+ // Grab a Write lock on the adapter so that this operation
+ // does not interfere with any receives that might be accessing
+ // multicast list information.
+ //
+ MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ NdisZeroMemory(pVElan->McastAddrs,
+ VELAN_MAX_MCAST_LIST * sizeof(MUX_MAC_ADDRESS));
+
+ NdisMoveMemory(&pVElan->McastAddrs[0],
+ InformationBuffer,
+ InformationBufferLength);
+
+ pVElan->McastAddrCount = InformationBufferLength / sizeof(MUX_MAC_ADDRESS);
+
+ MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== MPSetMulticastList VELAN %p, Status %8x\n", pVElan, Status));
+
+ return (Status);
+}
+
+
+
+PUCHAR
+MacAddrToString(
+ PVOID In
+ )
+/*++
+
+Routine Description:
+
+ Careful! Uses static storage for string. Used to simplify DbgPrints
+ of MAC addresses.
+
+Arguments:
+
+ IN Pointer to MAC address array
+
+Return Value:
+
+ A string format of the given mac address
+
+--*/
+{
+ static UCHAR String[20];
+ static PCHAR HexChars = "0123456789abcdef";
+ PUCHAR EthAddr = (PUCHAR) In;
+ UINT i;
+ PUCHAR s;
+
+ for (i = 0, s = String; i < 6; i++, EthAddr++)
+ {
+#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "s is bounded by check above");
+ *s++ = HexChars[(*EthAddr) >> 4];
+ *s++ = HexChars[(*EthAddr) & 0xf];
+ }
+ *s = '\0';
+
+ return String;
+}
+
+
+VOID
+MPGenerateMacAddr(
+ PVELAN pVElan
+)
+/*++
+
+Routine Description:
+
+ Generates a "virtual" MAC address for a VELAN.
+ NOTE: this is only a sample implementation of selecting
+ a MAC address for the VELAN. Other implementations are possible,
+ including using the MAC address of the underlying adapter as
+ the MAC address of the VELAN.
+
+Arguments:
+
+ pVElan - Pointer to velan structure
+
+Return Value:
+
+ None
+
+--*/
+{
+ ETH_COPY_NETWORK_ADDRESS(
+ pVElan->CurrentAddress,
+ pVElan->PermanentAddress);
+
+ DBGPRINT(MUX_LOUD, ("%d CurrentAddress %s\n",
+ pVElan->VElanNumber, MacAddrToString(&pVElan->CurrentAddress)));
+ DBGPRINT(MUX_LOUD, ("%d PermanentAddress %s\n",
+ pVElan->VElanNumber, MacAddrToString(&pVElan->PermanentAddress)));
+
+}
+
+
+
+VOID
+MPDevicePnPEvent(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
+ )
+/*++
+
+Routine Description:
+
+ This handler is called to notify us of PnP events directed to
+ our miniport device object.
+
+Arguments:
+
+ MiniportAdapterContext - pointer to VELAN structure
+ DevicePnPEvent - the event
+ InformationBuffer - Points to additional event-specific information
+ InformationBufferLength - length of above
+
+Return Value:
+
+ None
+--*/
+{
+ // TBD - add code/comments about processing this.
+ //
+
+ DBGPRINT(MUX_LOUD, ("==> MPDevicePnPEvent: AdapterContext %08lp, DevicePnPEvent %x\n",MiniportAdapterContext, NetDevicePnPEvent->DevicePnPEvent));
+
+ UNREFERENCED_PARAMETER(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(NetDevicePnPEvent);
+
+
+ DBGPRINT(MUX_LOUD, ("<== MPDevicePnPEvent: AdapterContext %08lp, DevicePnPEvent %x\n",MiniportAdapterContext, NetDevicePnPEvent->DevicePnPEvent));
+
+ return;
+}
+
+
+VOID
+MPAdapterShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_SHUTDOWN_ACTION ShutdownAction
+ )
+/*++
+
+Routine Description:
+
+ This handler is called to notify us of an impending system shutdown.
+ Since this is not a hardware driver, there isn't anything specific
+ we need to do about this.
+
+Arguments:
+
+ MiniportAdapterContext pointer to VELAN structure
+ ShutdownAction Specify the reason to shut down the adapter
+
+Return Value:
+
+ None
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+
+ DBGPRINT(MUX_LOUD,("==> MPAdapterShutdown: VElan %p, ShutdwonAction %x\n", pVElan, ShutdownAction));
+
+ UNREFERENCED_PARAMETER(pVElan);
+ UNREFERENCED_PARAMETER(ShutdownAction);
+
+ DBGPRINT(MUX_LOUD,("<== MPAdapterShutdown: VElan %p, ShutdwonAction %x\n", pVElan, ShutdownAction));
+
+ return;
+}
+
+
+VOID
+MPUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+ This handler is used to unload the miniport
+
+Arguments:
+ DriverObject Pointer to the system's driver object structure
+ for this driver.
+
+Return Value:
+ None
+
+
+--*/
+{
+
+#if !DBG
+ UNREFERENCED_PARAMETER(DriverObject);
+#endif
+
+ DBGPRINT(MUX_LOUD, ("==> MPUnload: DriverObj %p\n", DriverObject));
+ if (ProtHandle != NULL)
+ {
+ NdisDeregisterProtocolDriver(ProtHandle);
+ }
+ NdisMDeregisterMiniportDriver(DriverHandle);
+
+ NdisFreeSpinLock(&GlobalLock);
+
+ DBGPRINT(MUX_LOUD, ("<== MPUnload: DriverObj %p\n", DriverObject));
+}
+
+NDIS_STATUS
+MPPause(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters
+ )
+/*++
+
+Routine Description:
+ This handler is used to pause the miniport. During which, no NET_BUFFER_LIST
+ will be indicated to the upper binding as well as status indications.
+
+Arguments:
+ MiniportAdapterContext Pointer to our VELAN
+ MiniportPauseParameters Specify the pause parameters
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(MUX_LOUD, ("==> MPPause: VElan %p\n", pVElan));
+
+ UNREFERENCED_PARAMETER(MiniportPauseParameters);
+
+ DBGPRINT(MUX_LOUD,("==>MPPause Adapter %08lp\n",MiniportAdapterContext));
+
+ // Whilst the miniport is being paused, it cannot be restart
+
+ NdisAcquireSpinLock(&pVElan->PauseLock);
+
+ pVElan->Paused = TRUE;
+
+ NdisReleaseSpinLock(&pVElan->PauseLock);
+
+
+
+ DBGPRINT(MUX_LOUD,("<== MPPause,VElan %p, Status %8x\n", pVElan, Status));
+
+ return Status;
+}
+
+
+NDIS_STATUS
+MPRestart(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters
+ )
+/*++
+
+Routine Description:
+ This handler is used to restart the miniport. When the miniport is
+ back in the restart state, it can indicate NET_BUFFER_LISTs to the
+ upper binding
+
+Arguments:
+ MiniportAdapterContext Pointer to our VELAN
+ MiniportRestartParameters
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
+ PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
+
+ UNREFERENCED_PARAMETER(MiniportRestartParameters);
+
+ DBGPRINT(MUX_LOUD,("==> MPRestart Adapter %p\n",MiniportAdapterContext));
+
+
+ //
+ // Here the driver can change its restart attributes
+ //
+ NdisRestartAttributes = MiniportRestartParameters->RestartAttributes;
+
+ //
+ // If NdisRestartAttributes is not NULL, then miniport can modify generic attributes and add
+ // new media specific info attributes at the end. Otherwise, NDIS restarts the miniport because
+ // of other reason, miniport should not try to modify/add attributes
+ //
+ if (NdisRestartAttributes != NULL)
+ {
+
+ ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES);
+
+ NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;
+ UNREFERENCED_PARAMETER(NdisGeneralAttributes);
+
+ //
+ // Check to see if we need to change any attributes, for example, the driver can change the current
+ // MAC address here. Or the driver can add media specific info attributes.
+ //
+ }
+
+ NdisAcquireSpinLock(&pVElan->PauseLock);
+ pVElan->Paused = FALSE;
+
+ NdisReleaseSpinLock(&pVElan->PauseLock);
+
+
+ DBGPRINT(MUX_LOUD,("<== MPRestart: Adapter %p, Status %8x\n", MiniportAdapterContext, Status));
+
+ return Status;
+}
+
+
+VOID
+MPSendNetBufferLists(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ Send NET_BUFFER_LISTs to the lower binding
+
+Arguments:
+ MiniportAdapterContext Pointer to our VELAN
+ NetBufferLists Set of NET_BUFFER_LISTs to send
+ SendFlags Specify the send flags
+ DispatchLevel TRUE if IRQL == DISPATCH_LEVEL
+
+Return Value:
+ None
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ PADAPT pAdapt = pVElan->pAdapt;
+ PNET_BUFFER_LIST CurrentNetBufferList = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PIM_NBL_ENTRY SendContext;
+ ULONG SendCompleteFlags = 0;
+ BOOLEAN DispatchLevel = FALSE;
+
+ DBGPRINT(MUX_VERY_LOUD,("==> MPSendNetBufferLists: MiniportAdapterContext %p, NetBufferLists %p\n",MiniportAdapterContext,NetBufferLists));
+
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
+
+ while(NetBufferLists != NULL)
+ {
+ CurrentNetBufferList = NetBufferLists;
+ NetBufferLists = NET_BUFFER_LIST_NEXT_NBL(NetBufferLists);
+ NET_BUFFER_LIST_NEXT_NBL(CurrentNetBufferList) = NULL;
+
+ MUX_ACQUIRE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+
+ if (pAdapt->BindingState != MuxAdapterBindingRunning)
+ {
+ Status = NDIS_STATUS_REQUEST_ABORTED;
+ MUX_RELEASE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+
+ break;
+ }
+
+ pAdapt->OutstandingSends ++;
+
+ MUX_RELEASE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+
+ do
+ {
+ Status = NdisAllocateNetBufferListContext(CurrentNetBufferList,
+ sizeof(IM_NBL_ENTRY),
+ 0,
+ MUX_TAG);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ SendContext = (PIM_NBL_ENTRY)NET_BUFFER_LIST_CONTEXT_DATA_START(CurrentNetBufferList);
+ NdisZeroMemory(SendContext, sizeof(IM_NBL_ENTRY));
+ SendContext->PreviousSourceHandle = CurrentNetBufferList->SourceHandle;
+ SendContext->pVElan = pVElan;
+
+
+#ifdef IEEE_VLAN_SUPPORT
+ SendContext->Flags = 0;
+
+ Status = MPHandleSendTaggingNB(pVElan, CurrentNetBufferList);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisFreeNetBufferListContext(CurrentNetBufferList,
+ sizeof(IM_NBL_ENTRY));
+ break;
+ }
+
+#endif
+
+ CurrentNetBufferList->SourceHandle = pAdapt->BindingHandle;
+
+ MUX_INCR_PENDING_SENDS(pVElan);
+
+ //
+ // Remove this flag, so NDIS will not try to loopback the packets to mux
+ //
+ SendFlags &= ~NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;
+
+ NdisSendNetBufferLists(pAdapt->BindingHandle,
+ CurrentNetBufferList,
+ PortNumber,
+ SendFlags);
+
+ } while(FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ MUX_ACQUIRE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+ pAdapt->OutstandingSends --;
+
+ if ((pAdapt->OutstandingSends == 0) && (pAdapt->PauseEvent != NULL))
+ {
+ NdisSetEvent(pAdapt->PauseEvent);
+ pAdapt->PauseEvent = NULL;
+ }
+
+ MUX_RELEASE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+ //
+ // Handle failure case
+ //
+ NET_BUFFER_LIST_STATUS(CurrentNetBufferList) = Status;
+
+ if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags))
+ {
+ NDIS_SET_SEND_COMPLETE_FLAG(SendCompleteFlags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NdisMSendNetBufferListsComplete(pVElan->MiniportAdapterHandle,
+ CurrentNetBufferList,
+ SendCompleteFlags);
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ PNET_BUFFER_LIST TempNetBufferList;
+
+ for (TempNetBufferList = CurrentNetBufferList;
+ TempNetBufferList != NULL;
+ TempNetBufferList = NET_BUFFER_LIST_NEXT_NBL(TempNetBufferList))
+ {
+ NET_BUFFER_LIST_STATUS(TempNetBufferList) = Status;
+ }
+ if (NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags))
+ {
+ NDIS_SET_SEND_COMPLETE_FLAG(SendCompleteFlags, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NdisMSendNetBufferListsComplete(pVElan->MiniportAdapterHandle,
+ CurrentNetBufferList,
+ SendCompleteFlags);
+ }
+
+ DBGPRINT(MUX_VERY_LOUD,("<== MPSendNetBufferLists, MiniportAdapterContext %p, NetBufferLists %p\n",MiniportAdapterContext,NetBufferLists));
+}
+
+VOID
+MPReturnNetBufferLists(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN ULONG ReturnFlags
+ )
+/*++
+
+Routine Description:
+ NDIS Miniport entry point called whenever protocols are done with
+ a packet that we had indicated up and they had queued up for returning
+ later.
+
+Arguments:
+ MiniportAdapterContext Pointer to VELAN structure
+ NetBufferLists NetBufferLists being returned
+ Dispatch TRUE if IRQL == DISPATCH_LEVEL
+
+Return Value:
+ None
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ PNET_BUFFER_LIST CurrentNetBufferList = NULL;
+ ULONG NumberOfNetBufferLists = 0;
+#ifdef IEEE_VLAN_SUPPORT
+ NDIS_STATUS Status;
+#endif
+
+ DBGPRINT(MUX_VERY_LOUD,("==> MPReturnNetBufferLists: MiniportAdapterContext %p, NetBufferList %p\n",MiniportAdapterContext,NetBufferLists));
+
+ CurrentNetBufferList = NetBufferLists;
+
+ while (CurrentNetBufferList)
+ {
+ NumberOfNetBufferLists++;
+
+#ifdef IEEE_VLAN_SUPPORT
+ //
+ // Retreat the NBL before returning it to the miniport
+ //
+ Status = PtRestoreReceiveNBL(CurrentNetBufferList);
+
+ ASSERT(Status == NDIS_STATUS_SUCCESS);
+
+ //
+ // Free the context that was allocated in PtReceiveNBL
+ //
+ NdisFreeNetBufferListContext(CurrentNetBufferList,
+ sizeof(RECV_NBL_ENTRY));
+#endif
+
+ CurrentNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrentNetBufferList);
+ }
+
+ NdisReturnNetBufferLists(pVElan->BindingHandle,
+ NetBufferLists,
+ ReturnFlags);
+
+ MUX_DECR_MULTIPLE_PENDING_RECEIVES(pVElan, NumberOfNetBufferLists);
+
+ DBGPRINT(MUX_VERY_LOUD,("<== MPReturnNetBufferLists: MiniportAdapterContext %p, NetBufferList %p\n",MiniportAdapterContext,NetBufferLists));
+}
+
+
+VOID
+MPCancelSendNetBufferLists(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID CancelId
+ )
+/*++
+
+Routine Description:
+
+ The miniport entry point to hanadle cancellation of all send packets that
+ match the given CancelId. If we have queued any packets that match this,
+ then we should dequeue them and call NdisMSendCompleteNetBufferLists for
+ all such packets, with a status of NDIS_STATUS_REQUEST_ABORTED.
+
+ We should also call NdisCancelSendPackets in turn, on each lower binding
+ that this adapter corresponds to. This is to let miniports below cancel
+ any matching packets.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to VELAN structure
+ CancelID ID of NetBufferLists to be cancelled
+
+Return Value:
+ None
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+
+ DBGPRINT(MUX_LOUD,("==> MPCancelSendNetBufferLists: VElan %p, CancelId %p\n", pVElan, CancelId));
+
+ NdisCancelSendNetBufferLists(pVElan->pAdapt->BindingHandle,CancelId);
+
+ DBGPRINT(MUX_LOUD,("<== MPCancelSendNetBufferLists: VElan %p, CancelId %p\n", pVElan, CancelId));
+}
+
+VOID
+MPCancelOidRequest(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID RequestId
+ )
+/*++
+
+Routine Description:
+
+ The miniport entry point to hanadle cancellation of a request. This function
+ checks to see if the CancelRequest should be terminated at this level
+ or passed down to the next driver.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to VELAN structure
+ RequestId RequestId to be cancelled
+
+Return Value:
+ None
+
+--*/
+{
+ PVELAN pVElan = (PVELAN)MiniportAdapterContext;
+ PMUX_NDIS_REQUEST pMuxNdisRequest = &pVElan->Request;
+ BOOLEAN fCancelRequest = FALSE;
+
+ DBGPRINT(MUX_LOUD, ("==> MPCancelOidRequest: VELAN %p, RequestId %p\n", pVElan, RequestId));
+
+ NdisAcquireSpinLock(&pVElan->Lock);
+ if (pMuxNdisRequest->OrigRequest != NULL)
+ {
+ if (pMuxNdisRequest->OrigRequest->RequestId == RequestId)
+ {
+ pMuxNdisRequest->Cancelled = TRUE;
+ fCancelRequest = TRUE;
+ pMuxNdisRequest->Refcount++;
+ }
+
+ }
+
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ //
+ // If we find the request, just send down the cancel, otherwise return because there is only
+ // one request pending from upper layer on the miniport
+ //
+ if (fCancelRequest)
+ {
+ NdisCancelOidRequest(pVElan->pAdapt->BindingHandle, &pMuxNdisRequest->Request);
+
+ PtCompleteForwardedRequest(pVElan->pAdapt,
+ pMuxNdisRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== MPCancelOidRequest: VELAN %p, RequestId %p\n", pVElan, RequestId));
+}
+
+
+
+#ifdef IEEE_VLAN_SUPPORT
+
+PMDL
+MuxAllocateMdl(
+ IN OUT PULONG BufferSize
+ )
+/*++
+
+Routine Description:
+ This function is called by NDIS in order to allocate an MDL and memory when
+ there isn't unused data space in the net buffer when NdisRetreatNetBufferDataStart
+ is called
+
+Arguments:
+ BufferSize Pointer to allocation size being requested
+
+Return Value:
+
+NOTE: This function always returns NULL. This is so that MUX can allocate memory and MDL
+ and save the required context about the NetBuffer in the allocated memory
+
+--*/
+{
+ UNREFERENCED_PARAMETER(BufferSize);
+
+ return NULL;
+}
+
+NDIS_STATUS
+MPHandleSendTaggingNB(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList
+ )
+/*++
+
+Routine Description:
+ This function is called when the driver supports IEEE 802.1Q taggng. It checks
+ the netbuffer to be sent on a VELAN and inserts a tag header if necessary.
+
+Arguments:
+ pVElan Pointer to VELAN structure
+ NetBufferList A pointer to a NET_BUFFER_LIST
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_XXX
+
+NOTE: This functio doesn't handle vlan tagging in an efficient way, please wait for the next release
+ to get a better implementation.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo;
+ PUCHAR pEthFrame = NULL;
+ PUCHAR pEthFrameNew = NULL;
+ PUSHORT pTpid;
+ PVLAN_TAG_HEADER pTagHeader;
+ PIM_NBL_ENTRY SendContext;
+ PNET_BUFFER CurrentNetBuffer;
+ PIM_SEND_NB_ENTRY pNetBufferContext, LastNetBufferContext;
+ PVOID pVa;
+ PMDL Mdl, FirstMdl, SecondMdl, PrevMdl;
+ ULONG BytesToSkip;
+ ULONG BufferLength;
+ PVOID Storage;
+ PNET_BUFFER MdlAllocatedNetBuffers = NULL;
+
+ DBGPRINT(MUX_LOUD, ("==> MPHandleSendTaggingNB: VELAN %p, NetBufferList %p\n", pVElan, NetBufferList));
+
+ NdisPacket8021qInfo.Value = NET_BUFFER_LIST_INFO(NetBufferList, Ieee8021QNetBufferListInfo);
+ SendContext = (PIM_NBL_ENTRY)NET_BUFFER_LIST_CONTEXT_DATA_START(NetBufferList);
+
+ do
+ {
+ Status = NDIS_STATUS_SUCCESS;
+
+ // If the vlan ID of the virtual miniport is 0, the miniport should act like it doesn't
+ // support VELAN tag processing
+
+ if (MuxRecognizedVlanId(pVElan,0))
+ {
+ break;
+ }
+
+ //
+ // Insert a tag only if we have a configured VLAN ID. Note that we do not
+ // support E-RIF
+ //
+
+ if (NdisPacket8021qInfo.TagHeader.CanonicalFormatId)
+ {
+ //
+ // Skip the packet, return NDIS_STATUS_FAILURE
+ //
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+
+ //
+ // If the there is a tag header and it doesn't match the VLAN ID
+ // then the packet is invalid .. ignore!
+ //
+ if ((NdisPacket8021qInfo.TagHeader.VlanId)
+ && (! MuxRecognizedVlanId(pVElan,NdisPacket8021qInfo.TagHeader.VlanId)))
+ {
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+ CurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ LastNetBufferContext = NULL;
+
+ while(CurrentNetBuffer)
+ {
+ //
+ // Find the start address of the frame
+ //
+ Storage = NULL;
+ pEthFrame = NdisGetDataBuffer(CurrentNetBuffer,
+ ETH_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pEthFrame == NULL)
+ {
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+ Mdl = NET_BUFFER_CURRENT_MDL(CurrentNetBuffer);
+ PrevMdl = NULL;
+
+ //
+ // Retreat the net buffer list
+ //
+ Status = NdisRetreatNetBufferDataStart(CurrentNetBuffer,
+ VLAN_TAG_HEADER_SIZE,
+ 0,
+ MuxAllocateMdl);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // If there was a MDL ahead of the current MDL, this could result
+ // in the retreat being successful, but the retreated bytes being in
+ // a different MDL. But we need to make sure that the ethernet header
+ // with the VLAN tag is in contiguous memory
+ //
+ if (Mdl != NET_BUFFER_CURRENT_MDL(CurrentNetBuffer))
+ {
+ //
+ // Advance the NetBuffer so that we can allocate MDLs instead
+ //
+ NdisAdvanceNetBufferDataStart(CurrentNetBuffer,
+ VLAN_TAG_HEADER_SIZE,
+ FALSE,
+ NULL);
+
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ if (Status == NDIS_STATUS_RESOURCES)
+ {
+ do
+ {
+ //
+ // There is no more unused data space in the NetBuffer, need to allocate
+ // a new MDL and memory
+ //
+ BytesToSkip = ETH_HEADER_SIZE;
+ Mdl = NET_BUFFER_CURRENT_MDL(CurrentNetBuffer);
+
+ //
+ // Assume the Ethernet Header is in the first buffer of the packet.
+ // The following loop is to find the start address of the data after
+ // the ethernet header. This may be either in the first MDL
+ // or in the second.
+ //
+ while (TRUE)
+ {
+ pVa = NULL;
+ NdisQueryMdl(Mdl, &pVa, &BufferLength, NormalPagePriority);
+
+ if (pVa == NULL)
+ {
+ break;
+ }
+
+ //
+ // Have we gone far enough into the packet?
+ //
+ if (BytesToSkip == 0)
+ {
+ break;
+ }
+
+ //
+ // Does the current buffer contain bytes past the Ethernet
+ // header? If so, stop.
+ //
+ if (BufferLength > BytesToSkip)
+ {
+ pVa = (PVOID)((PUCHAR)pVa + BytesToSkip);
+ BufferLength -= BytesToSkip;
+ break;
+ }
+
+ //
+ // We haven't gone past the Ethernet header yet, so go
+ // to the next buffer.
+ //
+ BytesToSkip -= BufferLength;
+ Mdl = NDIS_MDL_LINKAGE(Mdl);
+ }
+
+ if (pVa == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // AllocateSpace for Ethernet + VLAN tag header + Netbuffer context
+ //
+ pNetBufferContext = (PIM_SEND_NB_ENTRY) NdisAllocateFromNPagedLookasideList(&pVElan->TagLookaside);
+
+ //
+ // Memory allocation failed
+ //
+ if (pNetBufferContext == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NdisZeroMemory((PVOID)pNetBufferContext, sizeof(IM_SEND_NB_ENTRY));
+
+ pEthFrameNew = ((PUCHAR) pNetBufferContext) + sizeof(IM_SEND_NB_ENTRY);
+
+ //
+ // Allocate MDLs for the Ethernet + VLAN tag header and
+ // the data that follow these.
+ //
+ SecondMdl = NdisAllocateMdl(pVElan->MiniportAdapterHandle,
+ pVa, // byte following the Eth+tag headers
+ BufferLength);
+
+ FirstMdl = NdisAllocateMdl(pVElan->MiniportAdapterHandle,
+ pEthFrameNew,
+ ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE);
+
+ if (!FirstMdl || !SecondMdl)
+ {
+ //
+ // One of the buffer allocations failed
+ //
+ if (FirstMdl)
+ {
+ NdisFreeMdl(FirstMdl);
+ }
+
+ if (SecondMdl)
+ {
+ NdisFreeMdl(SecondMdl);
+ }
+
+ NdisFreeToNPagedLookasideList(&pVElan->TagLookaside, (PVOID) pNetBufferContext);
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // All allocations are successful.
+ // Copy the Ethernet header to the newly allocated memory
+ // Leave space for the VLAN tag
+ //
+ NdisMoveMemory(pEthFrameNew, pEthFrame, 2 * ETH_LENGTH_OF_ADDRESS);
+
+ NdisMoveMemory(pEthFrameNew + (2 * ETH_LENGTH_OF_ADDRESS) + VLAN_TAG_HEADER_SIZE,
+ pEthFrame + (2 * ETH_LENGTH_OF_ADDRESS),
+ 2);
+
+ //
+ // Save the context for the NetBuffer
+ //
+ pNetBufferContext->CurrentMdl = NET_BUFFER_CURRENT_MDL(CurrentNetBuffer);
+
+ //
+ // If the current MDL is not the first on in the chain, we need to adjust the MDL chain
+ //
+ if (NET_BUFFER_FIRST_MDL(CurrentNetBuffer) != NET_BUFFER_CURRENT_MDL(CurrentNetBuffer))
+ {
+ PrevMdl = NET_BUFFER_FIRST_MDL(CurrentNetBuffer);
+ while (NDIS_MDL_LINKAGE(PrevMdl) != NET_BUFFER_CURRENT_MDL(CurrentNetBuffer))
+ {
+ PrevMdl = NDIS_MDL_LINKAGE(PrevMdl);
+ }
+
+ pNetBufferContext->PrevMdl = PrevMdl;
+ }
+
+ pNetBufferContext->CurrentMdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(CurrentNetBuffer);
+
+ //
+ // Link this NB to the NBL context to be restored
+ // This is so that MPRestoreSendNBL can free the MDLs that were allocated
+ // for this NB
+ //
+ if (MdlAllocatedNetBuffers == NULL)
+ {
+ MdlAllocatedNetBuffers = CurrentNetBuffer;
+ }
+ else
+ {
+ ASSERT(LastNetBufferContext);
+ LastNetBufferContext->NextNetBuffer = CurrentNetBuffer;
+ }
+
+ LastNetBufferContext = pNetBufferContext;
+
+ //
+ // Adjust the NetBuffer to use the new Mdls
+ //
+ NDIS_MDL_LINKAGE(FirstMdl) = SecondMdl;
+
+ NDIS_MDL_LINKAGE(SecondMdl) = NDIS_MDL_LINKAGE(Mdl);
+
+ NET_BUFFER_DATA_OFFSET(CurrentNetBuffer) = NET_BUFFER_DATA_OFFSET(CurrentNetBuffer) -
+ NET_BUFFER_CURRENT_MDL_OFFSET(CurrentNetBuffer);
+
+ NET_BUFFER_DATA_LENGTH(CurrentNetBuffer) += VLAN_TAG_HEADER_SIZE;
+
+ NET_BUFFER_CURRENT_MDL_OFFSET(CurrentNetBuffer) = 0;
+
+ NET_BUFFER_CURRENT_MDL(CurrentNetBuffer) = FirstMdl;
+
+ //
+ // If there are any MDLs in the MDL chain ahead of the current MDL,
+ // adjust the linkage
+ //
+ if (PrevMdl)
+ {
+ NDIS_MDL_LINKAGE(PrevMdl) = FirstMdl;
+ }
+ else
+ {
+ NET_BUFFER_FIRST_MDL(CurrentNetBuffer) = FirstMdl;
+ }
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ while (FALSE);
+ }
+ else if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // There was enough unused space in the NetBuffer to
+ // accomodate the VLAN tag.
+ // Get new start address of frame
+ //
+ Storage = NULL;
+ pEthFrameNew = NdisGetDataBuffer(CurrentNetBuffer,
+ VLAN_TAG_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pEthFrameNew == NULL)
+ {
+ NdisAdvanceNetBufferDataStart(CurrentNetBuffer,
+ VLAN_TAG_HEADER_SIZE,
+ FALSE,
+ NULL);
+
+ Status = NDIS_STATUS_INVALID_PACKET;
+ }
+ else
+ {
+ //
+ // Adjust the header to insert the VLAN tag in the packet frame
+ //
+ NdisMoveMemory(pEthFrameNew, pEthFrame, 2 * ETH_LENGTH_OF_ADDRESS);
+ }
+
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pTpid = (PUSHORT)((PUCHAR)pEthFrameNew + 2 * ETH_LENGTH_OF_ADDRESS);
+ *pTpid = TPID;
+ pTagHeader = (PVLAN_TAG_HEADER)(pTpid + 1);
+
+ //
+ // Write IEEE 802.1Q info to packet frame
+ //
+
+ INITIALIZE_TAG_HEADER_TO_ZERO(pTagHeader);
+
+ if (NdisPacket8021qInfo.Value)
+ {
+ SET_USER_PRIORITY_TO_TAG(pTagHeader, NdisPacket8021qInfo.TagHeader.UserPriority);
+ }
+ else
+ {
+ SET_USER_PRIORITY_TO_TAG(pTagHeader, 0);
+ }
+
+ SET_CANONICAL_FORMAT_ID_TO_TAG(pTagHeader, 0);
+
+ if (NdisPacket8021qInfo.TagHeader.VlanId)
+ {
+ SET_VLAN_ID_TO_TAG(pTagHeader, NdisPacket8021qInfo.TagHeader.VlanId);
+ }
+ else
+ {
+ SET_VLAN_ID_TO_TAG(pTagHeader, pVElan->VlanId);
+ }
+
+ CurrentNetBuffer = NET_BUFFER_NEXT_NB(CurrentNetBuffer);
+ }
+
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ SendContext->Flags |= MUX_RETREAT_DATA;
+ SendContext->MdlAllocatedNetBuffers = MdlAllocatedNetBuffers;
+ NET_BUFFER_LIST_INFO(NetBufferList, Ieee8021QNetBufferListInfo) = 0;
+ }
+ else
+ {
+ //
+ // In case of failure, restore the NetBuffers to their original state
+ // Only the NetBuffers in the NBL upto CurrentNetBuffer needs to be restored
+ //
+ MPRestoreSendNBL(pVElan, NetBufferList, CurrentNetBuffer, MdlAllocatedNetBuffers);
+ }
+
+ } while(FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== MPHandleSendTaggingNB: VELAN %p, NetBufferList %p, Status %8x\n", pVElan, NetBufferList, Status));
+ return Status;
+}
+
+VOID
+MPRestoreSendNBL(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList,
+ IN PNET_BUFFER LastNetBuffer,
+ IN PNET_BUFFER MdlAllocatedNetBuffers
+ )
+/*++
+
+Routine Description:
+ Restore the NBL that was modified during Send
+
+Arguments:
+ pVElan Pointer to VELAN structure
+ NetBufferList A pointer to a NET_BUFFER_LIST
+
+Return Value:
+
+--*/
+
+{
+ PNET_BUFFER CurrentNetBuffer;
+ PNET_BUFFER CurrentMdlAllocatedNetBuffer, SavedMdlAllocatedNetBuffer;
+ PIM_SEND_NB_ENTRY NetBufferContext;
+ PVOID pVa = NULL;
+ ULONG BufferLength;
+ PUCHAR pFrame = NULL, pDst = NULL;
+ PMDL FirstMdl, SecondMdl;
+ PVOID Storage;
+
+ CurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ CurrentMdlAllocatedNetBuffer = MdlAllocatedNetBuffers;
+
+ while (CurrentNetBuffer != LastNetBuffer)
+ {
+ SavedMdlAllocatedNetBuffer = CurrentMdlAllocatedNetBuffer;
+
+ //
+ // Free the MDLs and the memory allocated for the NET_BUFFER
+ //
+ if (CurrentMdlAllocatedNetBuffer)
+ {
+ NdisQueryMdl(NET_BUFFER_CURRENT_MDL(CurrentMdlAllocatedNetBuffer),
+ &pVa,
+ &BufferLength,
+ NormalPagePriority);
+ if( pVa == NULL ){
+ //you may do something
+ }
+ NetBufferContext = (PIM_SEND_NB_ENTRY) ((PUCHAR) pVa - sizeof(IM_SEND_NB_ENTRY));
+ ASSERT(NetBufferContext != NULL);
+
+ //
+ // Save the MDLs to be freed in temporary variables
+ //
+ FirstMdl = NET_BUFFER_CURRENT_MDL(CurrentMdlAllocatedNetBuffer);
+
+ SecondMdl = NDIS_MDL_LINKAGE(FirstMdl);
+
+ //
+ // Adjust the offsets and length
+ //
+ if( NetBufferContext == NULL ){
+ //check why NetBufferContext is NULL
+ }
+ else{
+ NET_BUFFER_DATA_OFFSET(CurrentMdlAllocatedNetBuffer) = NET_BUFFER_DATA_OFFSET(CurrentMdlAllocatedNetBuffer) +
+ NetBufferContext->CurrentMdlOffset;
+
+ NET_BUFFER_DATA_LENGTH(CurrentMdlAllocatedNetBuffer) -= VLAN_TAG_HEADER_SIZE;
+
+ NET_BUFFER_CURRENT_MDL_OFFSET(CurrentMdlAllocatedNetBuffer) = NetBufferContext->CurrentMdlOffset;
+
+ NET_BUFFER_CURRENT_MDL(CurrentMdlAllocatedNetBuffer) = NetBufferContext->CurrentMdl;
+
+ if (NetBufferContext->PrevMdl)
+ {
+ NDIS_MDL_LINKAGE(NetBufferContext->PrevMdl) = NetBufferContext->CurrentMdl;
+ }
+ else
+ {
+ NET_BUFFER_FIRST_MDL(CurrentMdlAllocatedNetBuffer) = NetBufferContext->CurrentMdl;
+ }
+
+ CurrentMdlAllocatedNetBuffer = NetBufferContext->NextNetBuffer;
+
+ //
+ // Free the MDLs and the memory allocated
+ //
+ NdisFreeMdl(SecondMdl);
+
+ NdisFreeMdl(FirstMdl);
+
+ NdisFreeToNPagedLookasideList(&pVElan->TagLookaside, (PVOID) NetBufferContext);
+ }
+ }
+
+ //
+ // Advance the NET_BUFFERs until the NET_BUFFER for which
+ // the MDLs were allocated
+ //
+ while ((CurrentNetBuffer != SavedMdlAllocatedNetBuffer) &&
+ (CurrentNetBuffer != LastNetBuffer))
+ {
+ Storage = NULL;
+ pFrame = NdisGetDataBuffer(CurrentNetBuffer,
+ (2 * ETH_LENGTH_OF_ADDRESS) + VLAN_TAG_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pFrame == NULL)
+ {
+ ASSERT(FALSE);
+ }
+ else
+ {
+ //
+ // Restore the original header
+ //
+ pDst = pFrame + VLAN_TAG_HEADER_SIZE;
+
+ RtlMoveMemory(pDst, pFrame, (2 * ETH_LENGTH_OF_ADDRESS));
+ }
+
+ NdisAdvanceNetBufferDataStart(CurrentNetBuffer,
+ VLAN_TAG_HEADER_SIZE,
+ FALSE,
+ NULL);
+
+ CurrentNetBuffer = NET_BUFFER_NEXT_NB(CurrentNetBuffer);
+ }
+
+ if (SavedMdlAllocatedNetBuffer)
+ {
+ CurrentNetBuffer = NET_BUFFER_NEXT_NB(SavedMdlAllocatedNetBuffer);
+ }
+ }
+}
+
+#endif
+
+
diff --git a/network/ndis/mux/driver/60/mux.c b/network/ndis/mux/driver/60/mux.c
new file mode 100644
index 00000000..1ff8698b
--- /dev/null
+++ b/network/ndis/mux/driver/60/mux.c
@@ -0,0 +1,516 @@
+/*++
+Copyright (c) 1992-2000 Microsoft Corporation
+
+Module Name:
+
+ mux.c
+
+Abstract:
+
+ DriverEntry and NT dispatch functions for the NDIS MUX Intermediate
+ Miniport driver sample.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define MODULE_NUMBER MODULE_MUX
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+
+#if DBG
+//
+// Debug level for mux driver
+//
+INT muxDebugLevel = MUX_WARN;
+
+#endif //DBG
+//
+// G L O B A L V A R I A B L E S
+// ----------- -----------------
+//
+
+NDIS_MEDIUM MediumArray[1] =
+ {
+ NdisMedium802_3, // Ethernet
+ };
+
+NDIS_SPIN_LOCK GlobalLock;
+
+//
+// Global Mutex protects the AdapterList;
+// see macros MUX_ACQUIRE/RELEASE_MUTEX
+//
+MUX_MUTEX GlobalMutex = {0};
+
+//
+// List of all bound adapters.
+//
+LIST_ENTRY AdapterList;
+
+
+//
+// list all virtual adapters
+//
+LIST_ENTRY VElanList;
+
+
+//
+// Total number of VELAN miniports in existance:
+//
+LONG MiniportCount = 0;
+
+//
+// Used to assign VELAN numbers (which are used to generate MAC
+// addresses).
+//
+ULONG NextVElanNumber = 0; // monotonically increasing count
+
+//
+// Some global NDIS handles:
+//
+NDIS_HANDLE ProtHandle = NULL; // From NdisRegisterProtocolDriver
+NDIS_HANDLE DriverHandle = NULL; // From NdisMRegisterMiniportDriver
+NDIS_HANDLE NdisDeviceHandle = NULL; // From NdisMRegisterDeviceEx
+
+PDEVICE_OBJECT ControlDeviceObject = NULL; // Device for IOCTLs
+MUX_MUTEX ControlDeviceMutex;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ First entry point to be called, when this driver is loaded.
+ Register with NDIS as an intermediate driver.
+
+Arguments:
+
+ DriverObject - pointer to the system's driver object structure
+ for this driver
+
+ RegistryPath - system's registry path for this driver
+
+Return Value:
+
+ STATUS_SUCCESS if all initialization is successful, STATUS_XXX
+ error code if not.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_PROTOCOL_DRIVER_CHARACTERISTICS PChars;
+ NDIS_MINIPORT_DRIVER_CHARACTERISTICS MChars;
+ NDIS_HANDLE MiniportDriverContext;
+ NDIS_HANDLE ProtocolDriverContext;
+ NDIS_STRING Name;
+
+
+ NdisInitializeListHead(&AdapterList);
+ NdisInitializeListHead(&VElanList);
+ MiniportDriverContext=NULL;
+ ProtocolDriverContext=NULL;
+
+ MUX_INIT_MUTEX(&GlobalMutex);
+ MUX_INIT_MUTEX(&ControlDeviceMutex);
+ NdisAllocateSpinLock(&GlobalLock);
+
+
+ do
+ {
+
+ //
+ // Register the miniport with NDIS. Note that it is the
+ // miniport which was started as a driver and not the protocol.
+ // Also the miniport must be registered prior to the protocol
+ // since the protocol's BindAdapter handler can be initiated
+ // anytime and when it is, it must be ready to
+ // start driver instances.
+ //
+ NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS));
+
+ MChars.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ MChars.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS);
+ MChars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
+
+ MChars.MajorNdisVersion = MUX_MAJOR_NDIS_VERSION;
+ MChars.MinorNdisVersion = MUX_MINOR_NDIS_VERSION;
+
+ MChars.MajorDriverVersion = MUX_MAJOR_DRIVER_VERSION;
+ MChars.MinorDriverVersion = MUX_MINOR_DRIVER_VERSION;
+
+ MChars.SetOptionsHandler = MpSetOptions;
+ MChars.InitializeHandlerEx = MPInitialize;
+ MChars.UnloadHandler = MPUnload;
+ MChars.HaltHandlerEx = MPHalt;
+
+ MChars.OidRequestHandler = MPOidRequest;
+
+ MChars.CancelSendHandler = MPCancelSendNetBufferLists;
+ MChars.DevicePnPEventNotifyHandler = MPDevicePnPEvent;
+ MChars.ShutdownHandlerEx = MPAdapterShutdown;
+ MChars.CancelOidRequestHandler = MPCancelOidRequest;
+
+ //
+ // We will disable the check for hang timeout so we do not
+ // need a check for hang handler!
+ //
+ MChars.CheckForHangHandlerEx = NULL;
+
+ MChars.ReturnNetBufferListsHandler = MPReturnNetBufferLists;
+ MChars.SendNetBufferListsHandler = MPSendNetBufferLists;
+
+ MChars.PauseHandler = MPPause;
+ MChars.RestartHandler = MPRestart;
+
+ MChars.Flags = NDIS_INTERMEDIATE_DRIVER;
+ Status = NdisMRegisterMiniportDriver(DriverObject,
+ RegistryPath,
+ MiniportDriverContext,
+ &MChars,
+ &DriverHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Now register the protocol.
+ //
+ NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_DRIVER_CHARACTERISTICS));
+
+ PChars.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PChars.Header.Size = sizeof(NDIS_PROTOCOL_DRIVER_CHARACTERISTICS);
+ PChars.Header.Revision = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;
+
+ PChars.MajorNdisVersion = MUX_PROT_MAJOR_NDIS_VERSION;
+ PChars.MinorNdisVersion = MUX_PROT_MINOR_NDIS_VERSION;
+
+ PChars.MajorDriverVersion = MUX_MAJOR_DRIVER_VERSION;
+ PChars.MinorDriverVersion = MUX_MINOR_DRIVER_VERSION;
+
+ PChars.SetOptionsHandler = PtSetOptions;
+
+ //
+ // Make sure the protocol-name matches the service-name
+ // (from the INF) under which this protocol is installed.
+ // This is needed to ensure that NDIS can correctly determine
+ // the binding and call us to bind to miniports below.
+ //
+ NdisInitUnicodeString(&Name, L"MUXP"); // Protocol name
+ PChars.Name = Name;
+ PChars.OpenAdapterCompleteHandlerEx = PtOpenAdapterComplete;
+ PChars.CloseAdapterCompleteHandlerEx = PtCloseAdapterComplete;
+
+ PChars.ReceiveNetBufferListsHandler = PtReceiveNBL;
+ PChars.SendNetBufferListsCompleteHandler = PtSendNBLComplete;
+ PChars.OidRequestCompleteHandler = PtRequestComplete;
+ PChars.StatusHandlerEx = PtStatus;
+ PChars.BindAdapterHandlerEx = PtBindAdapter;
+ PChars.UnbindAdapterHandlerEx = PtUnbindAdapter;
+ PChars.NetPnPEventHandler= PtPNPHandler;
+ Status = NdisRegisterProtocolDriver(ProtocolDriverContext,
+ &PChars,
+ &ProtHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NdisMDeregisterMiniportDriver(DriverHandle);
+ break;
+ }
+ //
+ // Let NDIS know of the association between our protocol
+ // and miniport entities.
+ //
+ NdisIMAssociateMiniport(DriverHandle, ProtHandle);
+ }while (FALSE);
+
+ return(Status);
+}
+
+NDIS_STATUS
+MpSetOptions(
+ IN NDIS_HANDLE NdisDriverHandle,
+ IN NDIS_HANDLE DriverContext
+ )
+/*++
+
+Routine Description:
+ This routine registers the optional handlers for the MUX MINIPORT driver
+ with NDIS.
+
+Arguments:
+
+ NdisDriverHandle Mux miniport driver handle
+ DriverContext Specifies a handle to a driver-allocated context area where the driver
+ maintains state and configuration information
+
+Return Value:
+
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UNREFERENCED_PARAMETER(DriverContext);
+ UNREFERENCED_PARAMETER(NdisDriverHandle);
+ return Status;
+}
+
+
+NDIS_STATUS
+PtSetOptions(
+ IN NDIS_HANDLE NdisDriverHandle,
+ IN NDIS_HANDLE DriverContext
+ )
+/*++
+
+Routine Description:
+ This routine registers the optional handlers for the MUX PROTOCOL driver
+ with NDIS.
+
+Arguments:
+
+ NdisDriverHandle Mux protocol driver handle
+ DriverContext Specifies a handle to a driver-allocated context area where the driver
+ maintains state and configuration information
+
+Return Value:
+
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UNREFERENCED_PARAMETER(DriverContext);
+ UNREFERENCED_PARAMETER(NdisDriverHandle);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+PtRegisterDevice(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Register an ioctl interface - a device object to be used for this
+ purpose is created by NDIS when we call NdisMRegisterDevice.
+
+ This routine is called whenever a new miniport instance is
+ initialized. However, we only create one global device object,
+ when the first miniport instance is initialized. This routine
+ handles potential race conditions with PtDeregisterDevice via
+ the ControlDeviceMutex.
+
+ NOTE: do not call this from DriverEntry; it will prevent the driver
+ from being unloaded (e.g. on uninstall).
+
+Arguments:
+
+ None
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we successfully register a device object.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ UNICODE_STRING DeviceName;
+ UNICODE_STRING DeviceLinkUnicodeString;
+ NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceObjectAttributes;
+ PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+
+
+
+ DBGPRINT(MUX_LOUD, ("==>PtRegisterDevice\n"));
+
+ MUX_ACQUIRE_MUTEX(&ControlDeviceMutex);
+
+ ++MiniportCount;
+
+ if (1 == MiniportCount)
+ {
+ NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+ DispatchTable[IRP_MJ_CREATE] = PtDispatch;
+ DispatchTable[IRP_MJ_CLEANUP] = PtDispatch;
+ DispatchTable[IRP_MJ_CLOSE] = PtDispatch;
+ DispatchTable[IRP_MJ_DEVICE_CONTROL] = PtDispatch;
+
+
+ NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
+ NdisInitUnicodeString(&DeviceLinkUnicodeString, GLOBAL_LINKNAME_STRING);
+
+ NdisZeroMemory(&DeviceObjectAttributes, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
+
+ DeviceObjectAttributes.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; // type implicit from the context
+ DeviceObjectAttributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ DeviceObjectAttributes.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
+ DeviceObjectAttributes.DeviceName = &DeviceName;
+ DeviceObjectAttributes.SymbolicName = &DeviceLinkUnicodeString;
+ DeviceObjectAttributes.MajorFunctions = &DispatchTable[0];
+ DeviceObjectAttributes.ExtensionSize = 0;
+ DeviceObjectAttributes.DefaultSDDLString = NULL;
+ DeviceObjectAttributes.DeviceClassGuid = 0;
+
+ Status = NdisRegisterDeviceEx(
+ DriverHandle,
+ &DeviceObjectAttributes,
+ &ControlDeviceObject,
+ &NdisDeviceHandle);
+
+ }
+
+ MUX_RELEASE_MUTEX(&ControlDeviceMutex);
+
+ DBGPRINT(MUX_INFO, ("<==PtRegisterDevice: %x\n", Status));
+
+ return (Status);
+}
+
+
+NTSTATUS
+PtDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+Routine Description:
+
+ Process IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject pointer to a device object
+ Irp pointer to an I/O Request Packet
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS always - change this when adding
+ real code to handle ioctls.
+
+--*/
+{
+ PIO_STACK_LOCATION irpStack;
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG inlen;
+ PVOID buffer;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ DBGPRINT(MUX_LOUD, ("==>PtDispatch %d\n", irpStack->MajorFunction));
+
+ switch (irpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+ break;
+
+ case IRP_MJ_CLEANUP:
+ break;
+
+ case IRP_MJ_CLOSE:
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+ {
+
+ buffer = Irp->AssociatedIrp.SystemBuffer;
+ inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
+ UNREFERENCED_PARAMETER(buffer);
+ UNREFERENCED_PARAMETER(inlen);
+
+ switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ //
+ // Add code here to handle ioctl commands.
+ //
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ DBGPRINT(MUX_LOUD, ("<== Pt Dispatch\n"));
+
+ return status;
+
+}
+
+
+NDIS_STATUS
+PtDeregisterDevice(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Deregister the ioctl interface. This is called whenever a miniport
+ instance is halted. When the last miniport instance is halted, we
+ request NDIS to delete the device object
+
+Arguments:
+
+ NdisDeviceHandle Handle returned by NdisMRegisterDevice
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if everything worked ok
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(MUX_LOUD, ("==>PtDeregisterDevice\n"));
+
+ MUX_ACQUIRE_MUTEX(&ControlDeviceMutex);
+
+ ASSERT(MiniportCount > 0);
+
+ --MiniportCount;
+
+ if (0 == MiniportCount)
+ {
+ //
+ // All VELAN miniport instances have been halted.
+ // Deregister the control device.
+ //
+
+ if (NdisDeviceHandle != NULL)
+ {
+ NdisDeregisterDeviceEx(NdisDeviceHandle);
+ NdisDeviceHandle = NULL;
+ }
+ }
+
+ MUX_RELEASE_MUTEX(&ControlDeviceMutex);
+
+ DBGPRINT(MUX_INFO, ("<== PtDeregisterDevice: %x\n", Status));
+ return Status;
+
+}
+
diff --git a/network/ndis/mux/driver/60/mux.h b/network/ndis/mux/driver/60/mux.h
new file mode 100644
index 00000000..dcdef937
--- /dev/null
+++ b/network/ndis/mux/driver/60/mux.h
@@ -0,0 +1,963 @@
+/*++
+Copyright (c) 1992-2001 Microsoft Corporation
+
+Module Name:
+
+ mux.h
+
+Abstract:
+
+ Data structures, defines and function prototypes for the MUX driver.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+
+--*/
+
+// disable warnings
+
+#if _MSC_VER >= 1200
+
+#pragma warning(push)
+
+#endif
+
+#pragma warning(disable:4200) // zero-sized array in struct/union
+
+#define MUX_MAJOR_NDIS_VERSION 6
+#define MUX_MINOR_NDIS_VERSION 0
+
+#define MUX_MAJOR_DRIVER_VERSION 3
+#define MUX_MINOR_DRIVER_VERSION 0
+
+#define MUX_PROT_MAJOR_NDIS_VERSION 6
+#define MUX_PROT_MINOR_NDIS_VERSION 0
+
+#define MUX_TAG 'SxuM'
+#define WAIT_INFINITE 0
+
+extern LONG MiniportCount;
+
+#if DBG
+//
+// Debug levels: lower values indicate higher urgency
+//
+#define MUX_EXTRA_LOUD 20
+#define MUX_VERY_LOUD 10
+#define MUX_LOUD 8
+#define MUX_INFO 6
+#define MUX_WARN 4
+#define MUX_ERROR 2
+#define MUX_FATAL 0
+
+extern INT muxDebugLevel;
+
+
+#define DBGPRINT(lev, Fmt) \
+ { \
+ if ((lev) <= muxDebugLevel) \
+ { \
+ DbgPrint("MUX-IM: "); \
+ DbgPrint Fmt; \
+ } \
+ }
+#else
+
+#define DBGPRINT(lev, Fmt)
+
+#endif //DBG
+
+
+
+#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
+ (BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x02))
+
+// forward declarations
+typedef struct _ADAPT ADAPT, *PADAPT;
+typedef struct _VELAN VELAN, *PVELAN;
+typedef struct _MUX_NDIS_REQUEST MUX_NDIS_REQUEST, *PMUX_NDIS_REQUEST;
+
+
+typedef
+VOID
+(*PMUX_REQ_COMPLETE_HANDLER) (
+ IN PADAPT pAdapt,
+ IN struct _MUX_NDIS_REQUEST * pMuxRequest,
+ IN NDIS_STATUS Status
+ );
+
+// This OID specifies the current driver version.
+// The high byte is the major version.
+// The low byte is the minor version.
+#define VELAN_DRIVER_VERSION ((MUX_MAJOR_DRIVER_VERSION << 8) + \
+ (MUX_MINOR_DRIVER_VERSION))
+
+// media type, we use ethernet, change if necessary
+#define VELAN_MEDIA_TYPE NdisMedium802_3
+
+// change to your company name instead of using Microsoft
+#define VELAN_VENDOR_DESC "Microsoft"
+
+// Highest byte is the NIC byte plus three vendor bytes, they are normally
+// obtained from the NIC
+#define VELAN_VENDOR_ID 0x00FFFFFF
+
+#define VELAN_MAX_MCAST_LIST 32
+#define VELAN_MAX_SEND_PKTS 5
+
+#define ETH_MAX_PACKET_SIZE 1514
+#define ETH_MIN_PACKET_SIZE 60
+#define ETH_HEADER_SIZE 14
+
+
+#define VELAN_SUPPORTED_FILTERS ( \
+ NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+
+#define MUX_ADAPTER_PACKET_FILTER \
+ NDIS_PACKET_TYPE_PROMISCUOUS
+
+
+
+#define MIN_PACKET_POOL_SIZE 255
+#define MAX_PACKET_POOL_SIZE 4096
+
+typedef UCHAR MUX_MAC_ADDRESS[6];
+
+
+
+//
+// Default values:
+//
+#define MUX_DEFAULT_LINK_SPEED 100000 // in 100s of bits/sec
+#define MUX_DEFAULT_LOOKAHEAD_SIZE 512
+
+DRIVER_INITIALIZE DriverEntry;
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+DRIVER_DISPATCH PtDispatch;
+NTSTATUS
+PtDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NDIS_STATUS
+PtRegisterDevice(
+ VOID
+ );
+
+NDIS_STATUS
+PtDeregisterDevice(
+ VOID
+ );
+//
+// Protocol proto-types
+//
+
+PROTOCOL_SET_OPTIONS PtSetOptions;
+
+PROTOCOL_OPEN_ADAPTER_COMPLETE_EX PtOpenAdapterComplete;
+
+PROTOCOL_CLOSE_ADAPTER_COMPLETE_EX PtCloseAdapterComplete;
+
+PROTOCOL_OID_REQUEST_COMPLETE PtRequestComplete;
+
+PROTOCOL_STATUS_EX PtStatus;
+
+PROTOCOL_BIND_ADAPTER_EX PtBindAdapter;
+
+PROTOCOL_UNBIND_ADAPTER_EX PtUnbindAdapter;
+
+PROTOCOL_NET_PNP_EVENT PtPNPHandler;
+
+PROTOCOL_RECEIVE_NET_BUFFER_LISTS PtReceiveNBL;
+
+PROTOCOL_SEND_NET_BUFFER_LISTS_COMPLETE PtSendNBLComplete;
+
+VOID
+PtQueryAdapterInfo(
+ IN PADAPT pAdapt
+ );
+
+
+VOID
+PtRequestAdapterSync(
+ IN PADAPT pAdapt,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength
+ );
+
+
+VOID
+PtRequestAdapterAsync(
+ IN PADAPT pAdapt,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ IN PMUX_REQ_COMPLETE_HANDLER pCallback
+ );
+
+VOID
+PtCompleteForwardedRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+PtPostProcessPnPCapabilities(
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength
+ );
+
+VOID
+PtCompleteBlockingRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+PtDiscardCompletedRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+NDIS_STATUS
+PtCreateAndStartVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pVElanKey
+ );
+
+PVELAN
+PtAllocateAndInitializeVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pVElanKey
+ );
+
+VOID
+PtDeallocateVElan(
+ IN PVELAN pVElan
+ );
+
+VOID
+PtStopVElan(
+ IN PVELAN pVElan
+ );
+
+VOID
+PtUnlinkVElanFromAdapter(
+ IN PVELAN pVElan
+ );
+
+PVELAN
+PtFindVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pElanKey
+ );
+
+
+NDIS_STATUS
+PtBootStrapVElans(
+ IN PADAPT pAdapt,
+ IN PUNICODE_STRING InstanceName OPTIONAL
+ );
+
+VOID
+PtReferenceVElan(
+ IN PVELAN pVElan,
+ IN PUCHAR String
+ );
+
+ULONG
+PtDereferenceVElan(
+ IN PVELAN pVElan,
+ IN PUCHAR String
+ );
+
+BOOLEAN
+PtReferenceAdapter(
+ IN PADAPT pAdapt,
+ IN PUCHAR String
+ );
+
+ULONG
+PtDereferenceAdapter(
+ IN PADAPT pAdapt,
+ IN PUCHAR String
+ );
+
+
+VOID
+PtCloseAdapter(
+ IN PADAPT Adapt
+ );
+
+//
+// Miniport proto-types
+//
+
+
+MINIPORT_SET_OPTIONS MpSetOptions;
+
+MINIPORT_INITIALIZE MPInitialize;
+
+MINIPORT_HALT MPHalt;
+
+MINIPORT_UNLOAD MPUnload;
+
+MINIPORT_PAUSE MPPause;
+
+MINIPORT_RESTART MPRestart;
+
+MINIPORT_OID_REQUEST MPOidRequest;
+
+MINIPORT_SEND_NET_BUFFER_LISTS MPSendNetBufferLists;
+
+MINIPORT_RETURN_NET_BUFFER_LISTS MPReturnNetBufferLists;
+
+MINIPORT_CANCEL_SEND MPCancelSendNetBufferLists;
+
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY MPDevicePnPEvent;
+
+MINIPORT_SHUTDOWN MPAdapterShutdown;
+
+MINIPORT_CANCEL_OID_REQUEST MPCancelOidRequest;
+
+NDIS_STATUS
+MPQueryInformation(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MPSetInformation(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MPMethodRequest(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ );
+
+NDIS_STATUS
+MPSetPacketFilter(
+ IN PVELAN pVElan,
+ IN ULONG PacketFilter
+ );
+
+NDIS_STATUS
+MPSetMulticastList(
+ IN PVELAN pVElan,
+ _In_reads_bytes_(InformationBufferLength) IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesRead,
+ OUT PULONG pBytesNeeded
+ );
+
+PUCHAR
+MacAddrToString(PVOID In
+ );
+
+VOID
+MPGenerateMacAddr(
+ PVELAN pVElan
+);
+
+
+NDIS_STATUS
+MPForwardOidRequest(
+ IN PVELAN pVElan,
+ IN PNDIS_OID_REQUEST NdisRequest
+ );
+
+//
+// Super-structure for NDIS_REQUEST, to allow us to keep context
+// about requests sent down to a lower binding.
+//
+typedef struct _MUX_NDIS_REQUEST
+{
+ PVELAN pVElan; // Set iff this is a forwarded
+ // request from a VELAN.
+ NDIS_STATUS Status; // Completion status
+ NDIS_EVENT Event; // Used to block for completion.
+ PMUX_REQ_COMPLETE_HANDLER pCallback; // Called on completion of request
+ PNDIS_OID_REQUEST OrigRequest; //Request that originated this request
+ NDIS_OID_REQUEST Request;
+ ULONG Refcount; // Refcount
+ BOOLEAN Cancelled;
+
+} MUX_NDIS_REQUEST, *PMUX_NDIS_REQUEST;
+
+
+typedef enum _MUX_ADAPTER_BINDING_STATE
+{
+ MuxAdapterBindingPaused,
+ MuxAdapterBindingPausing,
+ MuxAdapterBindingRunning
+}MUX_ADAPTER_BINDING_STATE, *PMUX_ADAPTER_BINDING_STATE;
+
+#define MUX_BINDING_ACTIVE 0x00000001
+#define MUX_BINDING_CLOSING 0x00000002
+
+//
+// The ADAPT object represents a binding to a lower adapter by
+// the protocol edge of this driver. Based on the configured
+// Upper bindings, zero or more virtual miniport devices (VELANs)
+// are created above this binding.
+//
+typedef struct _ADAPT
+{
+ // Chain adapters. Access to this is protected by the global lock.
+ LIST_ENTRY Link;
+
+ // References to this adapter.
+ ULONG RefCount;
+
+ // Handle to the lower adapter, used in NDIS calls referring
+ // to this adapter.
+ NDIS_HANDLE BindingHandle;
+
+ // List of all the virtual ELANs created on this lower binding
+ LIST_ENTRY VElanList;
+
+ // Length of above list.
+ ULONG VElanCount;
+
+ // String used to access configuration for this binding.
+ NDIS_STRING ConfigString;
+
+ // Open Status. Used by bind/halt for Open/Close Adapter status.
+ NDIS_STATUS Status;
+
+ NDIS_EVENT Event;
+
+ //
+ // Packet filter set to the underlying adapter. This is
+ // a combination (union) of filter bits set on all
+ // attached VELAN miniports.
+ //
+ ULONG PacketFilter;
+
+ // Power state of the underlying adapter
+ NDIS_DEVICE_POWER_STATE PtDevicePowerState;
+
+ //
+ // NDIS Medium ofr VELAN taken from the miniport below
+ //
+ NDIS_MEDIUM Medium ;
+
+ //
+ // BindParameters passed to protocol giving it information on
+ // the miniport below
+ //
+ NDIS_BIND_PARAMETERS BindParameters;
+ NDIS_PNP_CAPABILITIES PowerManagementCapabilities;
+ NDIS_RECEIVE_SCALE_CAPABILITIES RcvScaleCapabilities;
+ NDIS_LINK_STATE LastIndicatedLinkState;
+ MUX_ADAPTER_BINDING_STATE BindingState;
+
+ ULONG OutstandingSends;
+ PNDIS_EVENT PauseEvent;
+ NDIS_SPIN_LOCK Lock;
+#ifndef WIN9X
+ //
+ // Read/Write lock: allows multiple readers but only a single
+ // writer. Used to protect the VELAN list and fields (e.g. packet
+ // filter) shared on an ADAPT by multiple VELANs. Code that
+ // needs to traverse the VELAN list safely acquires a READ lock.
+ // Code that needs to safely modify the VELAN list or shared
+ // fields acquires a WRITE lock (which also excludes READers).
+ //
+ // See macros MUX_ACQUIRE_ADAPT_xxx/MUX_RELEASE_ADAPT_xxx below.
+ //
+ // TBD - if we want to support this on Win9X, reimplement this!
+ //
+ NDIS_RW_LOCK ReadWriteLock;
+#endif // WIN9X
+
+ ULONG OutstandingRequests;
+ PNDIS_EVENT CloseEvent;
+ ULONG Flags;
+} ADAPT, *PADAPT;
+
+
+//
+// VELAN object represents a virtual ELAN instance and its
+// corresponding virtual miniport adapter.
+//
+typedef struct _VELAN
+{
+ // Link into parent adapter's VELAN list.
+ LIST_ENTRY Link;
+
+ // link inot global VELAN list
+ LIST_ENTRY GlobalLink;
+
+ // References to this VELAN.
+ ULONG RefCount;
+
+ // Parent ADAPT.
+ PADAPT pAdapt;
+
+ // Copy of BindingHandle from ADAPT.
+ NDIS_HANDLE BindingHandle;
+
+ // Adapter handle for NDIS up-calls related to this virtual miniport.
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ // Virtual miniport's power state.
+ NDIS_DEVICE_POWER_STATE MPDevicePowerState;
+
+ // Has our Halt entry point been called?
+ BOOLEAN MiniportHalting;
+
+ // Do we need to indicate receive complete?
+ BOOLEAN IndicateRcvComplete;
+
+ // Do we need to indicate status complete?
+ BOOLEAN IndicateStatusComplete;
+
+ // Synchronization fields
+ BOOLEAN MiniportInitPending;
+ NDIS_EVENT MiniportInitEvent;
+
+ // Uncompleted Sends/Requests to the adapter below.
+ ULONG OutstandingSends;
+
+ // Count outstanding indications, including received
+ // packets, passed up to protocols on this VELAN.
+ ULONG OutstandingReceives;
+
+ // A request block that is used to forward a request presented
+ // to the virtual miniport, to the lower binding. Since NDIS
+ // serializes requests to a miniport, we only need one of these
+ // per VELAN.
+ //
+ MUX_NDIS_REQUEST Request;
+ // Have we queued a request because the lower binding is
+ // at a low power state?
+ BOOLEAN QueuedRequest;
+
+ // Have we started to deinitialize this VELAN?
+ BOOLEAN DeInitializing;
+
+ // configuration
+ UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS];
+ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS];
+
+ NDIS_STRING CfgDeviceName; // used as the unique
+ // ID for the VELAN
+ ULONG VElanNumber; // logical Elan number
+
+
+ //
+ // ----- Buffer Management: Header buffers and Protocol buffers ----
+ //
+
+ // Some standard miniport parameters (OID values).
+ ULONG PacketFilter;
+ ULONG LookAhead;
+ ULONG64 LinkSpeed;
+
+ ULONG MaxBusySends;
+ ULONG MaxBusyRecvs;
+
+ // Packet counts
+ ULONG64 GoodTransmits;
+ ULONG64 GoodReceives;
+ ULONG NumTxSinceLastAdjust;
+
+ // Count of transmit errors
+ ULONG TxAbortExcessCollisions;
+ ULONG TxLateCollisions;
+ ULONG TxDmaUnderrun;
+ ULONG TxLostCRS;
+ ULONG TxOKButDeferred;
+ ULONG OneRetry;
+ ULONG MoreThanOneRetry;
+ ULONG TotalRetries;
+ ULONG TransmitFailuresOther;
+
+ // Count of receive errors
+ ULONG RcvCrcErrors;
+ ULONG RcvAlignmentErrors;
+ ULONG RcvResourceErrors;
+ ULONG RcvDmaOverrunErrors;
+ ULONG RcvCdtFrames;
+ ULONG RcvRuntErrors;
+ ULONG RegNumTcb;
+
+ // Multicast list
+ MUX_MAC_ADDRESS McastAddrs[VELAN_MAX_MCAST_LIST];
+ ULONG McastAddrCount;
+
+
+ NDIS_STATUS LastIndicatedStatus;
+ NDIS_STATUS LatestUnIndicateStatus;
+ NDIS_SPIN_LOCK Lock;
+
+ // Miniport Pause/Restart functionality
+ BOOLEAN Paused;
+ NDIS_SPIN_LOCK PauseLock;
+ NDIS_LINK_STATE LatestUnIndicateLinkState;
+ NDIS_LINK_STATE LastIndicatedLinkState;
+
+#if IEEE_VLAN_SUPPORT
+ ULONG VlanId;
+ ULONG RcvFormatErrors;
+ ULONG RcvVlanIdErrors;
+ BOOLEAN RestoreLookaheadSize;
+ NPAGED_LOOKASIDE_LIST TagLookaside;
+#endif
+
+ NET_IFINDEX IfIndex;
+} VELAN, *PVELAN;
+
+
+#define MUX_ACQUIRE_SPIN_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprAcquireSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisAcquireSpinLock(_pLock); \
+ } \
+ }
+
+#define MUX_RELEASE_SPIN_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel) \
+ { \
+ NdisDprReleaseSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisReleaseSpinLock(_pLock); \
+ } \
+ }
+
+
+
+#if IEEE_VLAN_SUPPORT
+
+#define TPID 0x0081
+//
+// Define tag_header structure
+//
+typedef struct _VLAN_TAG_HEADER
+{
+ UCHAR TagInfo[2];
+} VLAN_TAG_HEADER, *PVLAN_TAG_HEADER;
+
+
+//
+// Macro definitions for VLAN support
+//
+#define VLAN_TAG_HEADER_SIZE 4
+
+#define VLANID_DEFAULT 0
+#define VLAN_ID_MAX 0xfff
+#define VLAN_ID_MIN 0x0
+
+#define USER_PRIORITY_MASK 0xe0
+#define CANONICAL_FORMAT_ID_MASK 0x10
+#define HIGH_VLAN_ID_MASK 0x0F
+
+//
+// Get information for tag headre
+//
+#define GET_CANONICAL_FORMAT_ID_FROM_TAG(_pTagHeader) \
+ ((_pTagHeader)->TagInfo[0] & CANONICAL_FORMAT_ID_MASK)
+
+#define GET_USER_PRIORITY_FROM_TAG(_pTagHeader) \
+ ((_pTagHeader)->TagInfo[0] & USER_PRIORITY_MASK)
+
+#define GET_VLAN_ID_FROM_TAG(_pTagHeader) \
+ (ULONG)(((USHORT)((_pTagHeader)->TagInfo[0] & HIGH_VLAN_ID_MASK) << 8) |(USHORT)((_pTagHeader)->TagInfo[1]))
+
+//
+// Clear the tag header struct
+//
+#define INITIALIZE_TAG_HEADER_TO_ZERO(_pTagHeader) \
+{ \
+ (_pTagHeader)->TagInfo[0] = 0; \
+ (_pTagHeader)->TagInfo[1] = 0; \
+}
+
+//
+// Set VLAN information to tag header
+// Before we called all the set macro, first we need to initialize pTagHeader to be 0
+//
+#define SET_CANONICAL_FORMAT_ID_TO_TAG(_pTagHeader, _CanonicalFormatId) \
+ (_pTagHeader)->TagInfo[0] |= ((UCHAR)(_CanonicalFormatId) << 4)
+
+#define SET_USER_PRIORITY_TO_TAG(_pTagHeader, _UserPriority) \
+ (_pTagHeader)->TagInfo[0] |= ((UCHAR)(_UserPriority) << 5)
+
+#define SET_VLAN_ID_TO_TAG(_pTagHeader, _VlanId) \
+ { \
+ (_pTagHeader)->TagInfo[0] |= (((UCHAR)((_VlanId) >> 8)) & 0x0f); \
+ (_pTagHeader)->TagInfo[1] |= (UCHAR)(_VlanId); \
+ }
+
+
+//
+// Copy tagging information in the indicated frame to per packet info
+//
+#define COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(_Ieee8021qInfo, _pTagHeader) \
+{ \
+ (_Ieee8021qInfo).TagHeader.UserPriority = ((_pTagHeader->TagInfo[0] & USER_PRIORITY_MASK) >> 5); \
+ (_Ieee8021qInfo).TagHeader.CanonicalFormatId = ((_pTagHeader->TagInfo[0] & CANONICAL_FORMAT_ID_MASK) >> 4); \
+ (_Ieee8021qInfo).TagHeader.VlanId = (((USHORT)(_pTagHeader->TagInfo[0] & HIGH_VLAN_ID_MASK) << 8)| (USHORT)(_pTagHeader->TagInfo[1])); \
+}
+
+//
+// Flags used by VELAN supports
+//
+#define MUX_RETREAT_DATA 0x00000001
+
+//
+// Flags used by VELAN on Receive code path
+//
+#define MUX_ADVANCE_DATA 0x00000001
+
+//
+// Every NBL that is indicated up to a protocol needs to advance the buffer
+// in case the VLAN tag is present. It should be restored before returning the
+// packet to the miniport. This structure is used for that purpose
+//
+typedef struct _RECV_NBL_ENTRY
+{
+ ULONG Flags;
+ VLAN_TAG_HEADER TagHeader;
+
+ DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)
+ UCHAR Pad[];
+} RECV_NBL_ENTRY, *PRECV_NBL_ENTRY;
+
+//
+// This structure is used to save context in the NET_BUFFER on the send path,
+// if the ethernet header and VLAN tag is allocated by MUX
+//
+typedef struct _IM_SEND_NB_ENTRY
+{
+ PMDL CurrentMdl;
+ PMDL PrevMdl;
+ ULONG CurrentMdlOffset;
+ PNET_BUFFER NextNetBuffer;
+} IM_SEND_NB_ENTRY, *PIM_SEND_NB_ENTRY;
+
+#endif //IEEE_VLAN_SUPPORT
+
+typedef struct _IM_NBL_ENTRY
+{
+ NDIS_HANDLE PreviousSourceHandle;
+ PVELAN pVElan;
+#if IEEE_VLAN_SUPPORT
+ ULONG Flags;
+ PNET_BUFFER MdlAllocatedNetBuffers;
+#endif
+ DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)
+ UCHAR Pad[];
+} IM_NBL_ENTRY, *PIM_NBL_ENTRY;
+
+//
+// Macro definitions for others.
+//
+
+//
+// Is a given power state a low-power state?
+//
+#define MUX_IS_LOW_POWER_STATE(_PwrState) \
+ ((_PwrState) > NdisDeviceStateD0)
+
+#define MUX_INIT_ADAPT_RW_LOCK(_pAdapt) \
+ NdisInitializeReadWriteLock(&(_pAdapt)->ReadWriteLock)
+
+
+#define MUX_ACQUIRE_ADAPT_READ_LOCK(_pAdapt, _pLockState) \
+ NdisAcquireReadWriteLock(&(_pAdapt)->ReadWriteLock, \
+ FALSE, \
+ _pLockState)
+
+#define MUX_RELEASE_ADAPT_READ_LOCK(_pAdapt, _pLockState) \
+ NdisReleaseReadWriteLock(&(_pAdapt)->ReadWriteLock, \
+ _pLockState)
+
+#define MUX_ACQUIRE_ADAPT_WRITE_LOCK(_pAdapt, _pLockState) \
+ NdisAcquireReadWriteLock(&(_pAdapt)->ReadWriteLock, \
+ TRUE, \
+ _pLockState)
+
+#define MUX_RELEASE_ADAPT_WRITE_LOCK(_pAdapt, _pLockState) \
+ NdisReleaseReadWriteLock(&(_pAdapt)->ReadWriteLock, \
+ _pLockState)
+
+#define MUX_INCR_PENDING_RECEIVES(_pVElan) \
+ NdisInterlockedIncrement((PLONG)&pVElan->OutstandingReceives)
+
+#define MUX_DECR_PENDING_RECEIVES(_pVElan) \
+ NdisInterlockedDecrement((PLONG)&pVElan->OutstandingReceives)
+
+#define MUX_INCR_PENDING_SENDS(_pVElan) \
+ NdisInterlockedIncrement((PLONG)&pVElan->OutstandingSends)
+
+#define MUX_DECR_PENDING_SENDS(_pVElan) \
+ NdisInterlockedDecrement((PLONG)&pVElan->OutstandingSends)
+
+#define MUX_DECR_MULTIPLE_PENDING_RECEIVES(_pVElan, _NumReceives) \
+ InterlockedExchangeAdd((PLONG)&_pVElan->OutstandingReceives, \
+ 0 - (LONG) _NumReceives)
+
+
+
+
+#define MUX_INCR_STATISTICS(_pUlongVal) \
+ NdisInterlockedIncrement((PLONG)_pUlongVal)
+
+#define MUX_INCR_STATISTICS64(_pUlong64Val) \
+{ \
+ PLARGE_INTEGER _pLargeInt = (PLARGE_INTEGER)_pUlong64Val;\
+ if (NdisInterlockedIncrement((PLONG)&_pLargeInt->LowPart) == 0) \
+ { \
+ NdisInterlockedIncrement(&_pLargeInt->HighPart); \
+ } \
+}
+
+#define ASSERT_AT_PASSIVE() \
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL)
+
+#define ASSERT_AT_DISPATCH() \
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL)
+
+
+
+//
+// Simple Mutual Exclusion constructs used in preference to
+// using KeXXX calls since we don't have Mutex calls in NDIS.
+// These can only be called at passive IRQL.
+//
+
+typedef struct _MUX_MUTEX
+{
+ NDIS_MUTEX Mutex;
+ ULONG ModuleAndLine; // useful for debugging
+
+} MUX_MUTEX, *PMUX_MUTEX;
+
+#define MUX_INIT_MUTEX(_pMutex) \
+{ \
+ NDIS_INIT_MUTEX(&(_pMutex)->Mutex); \
+ (_pMutex)->ModuleAndLine = 0; \
+}
+
+#define MUX_ACQUIRE_MUTEX(_pMutex) \
+{ \
+ NDIS_WAIT_FOR_MUTEX(&(_pMutex)->Mutex); \
+ (_pMutex)->ModuleAndLine = (MODULE_NUMBER << 16) | __LINE__;\
+}
+
+#define MUX_RELEASE_MUTEX(_pMutex) \
+{ \
+ (_pMutex)->ModuleAndLine = 0; \
+ NDIS_RELEASE_MUTEX(&(_pMutex)->Mutex); \
+}
+
+
+//
+// Global variables
+//
+extern NDIS_HANDLE ProtHandle, DriverHandle;
+extern NDIS_MEDIUM MediumArray[1];
+extern NDIS_SPIN_LOCK GlobalLock;
+extern MUX_MUTEX GlobalMutex;
+extern LIST_ENTRY AdapterList;
+extern LIST_ENTRY VElanList;
+extern ULONG NextVElanNumber;
+
+//
+// Module numbers for debugging
+//
+#define MODULE_MUX 'X'
+#define MODULE_PROT 'P'
+#define MODULE_MINI 'M'
+#define MODULE_MUX_TEST 'T'
+
+
+#ifdef IEEE_VLAN_SUPPORT
+
+PMDL
+MuxAllocateMdl(
+ IN OUT PULONG BufferSize
+ );
+
+NDIS_STATUS
+MPHandleSendTaggingNB(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList
+ );
+
+VOID
+MPRestoreSendNBL(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList,
+ IN PNET_BUFFER LastNetBuffer,
+ IN PNET_BUFFER MdlAllocatedNetBuffers
+ );
+
+NDIS_STATUS
+PtHandleReceiveTaggingNB(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList,
+ IN PNDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo
+ );
+
+NDIS_STATUS
+PtStripVlanTagNB(
+ IN PNET_BUFFER_LIST NetBufferList,
+ OUT PNDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo,
+ OUT PRECV_NBL_ENTRY RecvContext
+ );
+
+NDIS_STATUS
+PtRestoreReceiveNBL(
+ IN PNET_BUFFER_LIST NetBufferList
+ );
+
+#define MuxRecognizedVlanId(_pVElan, _VlanId) ((_pVElan)->VlanId == (_VlanId))
+
+#endif
+
+
+
+#if _MSC_VER >= 1200
+
+#pragma warning(pop)
+
+#else
+
+#endif
+
+
+
diff --git a/network/ndis/mux/driver/60/mux.htm b/network/ndis/mux/driver/60/mux.htm
new file mode 100644
index 00000000..8a590061
--- /dev/null
+++ b/network/ndis/mux/driver/60/mux.htm
@@ -0,0 +1,617 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml"
+xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns:st1="urn:schemas-microsoft-com:office:smarttags"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 11">
+<meta name=Originator content="Microsoft Word 11">
+<link rel=File-List href="mux2_files/filelist.xml">
+<title>MUX Intermediate Miniport Driver Help</title>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="PlaceName"/>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="PlaceType"/>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="place"/>
+<!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:SpellingState>Clean</w:SpellingState>
+ <w:GrammarState>Clean</w:GrammarState>
+ <w:ValidateAgainstSchemas/>
+ <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
+ <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
+ <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
+ <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
+ </w:WordDocument>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:LatentStyles DefLockedState="false" LatentStyleCount="156">
+ </w:LatentStyles>
+</xml><![endif]--><!--[if !mso]><object
+ classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui></object>
+<style>
+st1\:*{behavior:url(#ieooui) }
+</style>
+<![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+ @font-face
+ {font-family:Verdana;
+ panose-1:2 11 6 4 3 5 4 4 2 4;
+ mso-font-alt:Tahoma;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:536871559 0 0 0 415 0;}
+@font-face
+ {font-family:"MS Sans Serif";
+ panose-1:0 0 0 0 0 0 0 0 0 0;
+ mso-font-alt:Arial;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-format:other;
+ mso-font-pitch:variable;
+ mso-font-signature:3 0 0 0 1 0;}
+ /* Style Definitions */
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";
+ color:black;}
+h2
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:2;
+ font-size:18.0pt;
+ font-family:"Times New Roman";
+ color:black;
+ font-weight:bold;}
+h3
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:3;
+ font-size:13.5pt;
+ font-family:"Times New Roman";
+ color:black;
+ font-weight:bold;}
+h4
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:4;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ color:black;
+ font-weight:bold;}
+a:link, span.MsoHyperlink
+ {color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+a:visited, span.MsoHyperlinkFollowed
+ {color:purple;
+ text-decoration:underline;
+ text-underline:single;}
+p
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";
+ color:black;}
+pre
+ {margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt;
+ font-size:10.0pt;
+ font-family:"Courier New";
+ mso-fareast-font-family:"Courier New";
+ color:black;}
+span.SpellE
+ {mso-style-name:"";
+ mso-spl-e:yes;}
+span.GramE
+ {mso-style-name:"";
+ mso-gram-e:yes;}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.25in 1.0in 1.25in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+-->
+</style>
+<!--[if gte mso 10]>
+<style>
+ /* Style Definitions */
+ table.MsoNormalTable
+ {mso-style-name:"Table Normal";
+ mso-tstyle-rowband-size:0;
+ mso-tstyle-colband-size:0;
+ mso-style-noshow:yes;
+ mso-style-parent:"";
+ mso-padding-alt:0in 5.4pt 0in 5.4pt;
+ mso-para-margin:0in;
+ mso-para-margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:10.0pt;
+ font-family:"Times New Roman";
+ mso-ansi-language:#0400;
+ mso-fareast-language:#0400;
+ mso-bidi-language:#0400;}
+</style>
+<![endif]-->
+<meta name=Template content="C:\Program Files\Microsoft Office\Office\html.dot">
+<!--[if gte mso 9]><xml>
+ <o:shapedefaults v:ext="edit" spidmax="8194"/>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <o:shapelayout v:ext="edit">
+ <o:idmap v:ext="edit" data="1"/>
+ </o:shapelayout></xml><![endif]-->
+</head>
+
+<body bgcolor=white lang=EN-US link=blue vlink=purple style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<h2><a name=MYSAMPLE><span style='font-family:Verdana'>MUX.SYS - Sample NDIS
+MUX Intermediate Driver</span></a><span style='font-family:Verdana'><o:p></o:p></span></h2>
+
+<h3><span style='font-family:Verdana'>SUMMARY<o:p></o:p></span></h3>
+
+<p><st1:place w:st="on"><st1:PlaceName w:st="on"><b><span style='font-family:
+ Verdana'>MUX</span></b></st1:PlaceName><b><span style='font-family:Verdana'> <st1:PlaceName
+ w:st="on">Intermediate</st1:PlaceName> <st1:PlaceType w:st="on">Miniport</st1:PlaceType></span></b></st1:place><b><span
+style='font-family:Verdana'> Driver<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The MUX Intermediate
+Miniport (IM) driver is an NDIS 6.0 driver that demonstrates the operation of
+an �N<span class=GramE>:1</span>� MUX driver, i.e. one which creates multiple
+virtual network devices on top of a single lower adapter. Protocols bind to
+these virtual adapters as if they are real adapters. Examples of <st1:place
+w:st="on"><st1:PlaceName w:st="on">Intermediate</st1:PlaceName> <st1:PlaceType
+ w:st="on">Miniport</st1:PlaceType></st1:place> drivers that can use this
+framework are Virtual LAN (VLAN) drivers.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>This sample implements
+IEEE 802.1Q VLAN tagging, which is enabled by changing the default VLAN ID to a
+non-zero valid value (see �Configuring VLANs� below).<o:p></o:p></span></p>
+
+<p><b><span style='mso-bidi-font-size:10.0pt;font-family:Verdana'>Operation<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The driver binds to
+Ethernet (NdisMedium802_3) adapters as a protocol, and exposes one or more
+virtual Ethernet devices over each lower adapter, based on its configuration.
+The term �VELAN� is used to denote a Virtual Ethernet LAN adapter implemented
+by this driver.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>When it binds to a lower
+adapter, MUX reads the standard �UpperBind� key to obtain a list of VELANs
+configured over this adapter. For each such VELAN, it calls <span class=GramE>NdisIMInitializeDeviceInstanceEx(</span>)
+to instantiate the NDIS miniport for the VELAN. NDIS then calls the driver�s
+MiniportInitialize (<i>MPInitialize</i>) routine to start the VELAN miniport.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The MUX driver supports
+configuring the MAC address for each VELAN miniport using the standard
+�NetworkAddress� key that it reads from its MiniportInitialize routine. If this
+is not configured, it computes a �locally significant� MAC address for the
+VELAN using the MAC address of the lower adapter. The MUX driver sets its lower
+adapter to promiscuous mode in order to be able to receive frames directed to
+any of the VELAN MAC addresses. <span class=GramE>However it does implement
+packet-filtering (and multicast address filtering) logic for all its VELAN
+miniports so that it only passes up relevant frames on each VELAN.</span> This
+aspect of the driver may be modified if, for example, your driver design uses
+the same MAC address as that of the lower adapter on all VELANs. With such a
+modification, it is not required to set the lower adapter to promiscuous mode
+and incur the costs of receiving all packets on the network.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>It supports dynamic
+addition and deletion of VELANs in conjunction with <span class=GramE>its</span>
+notify object (related sample). If a VELAN is deleted, the virtual device
+corresponding to the VELAN is stopped and removed, which in turn results in
+NDIS halting the miniport instance for the VELAN (see <i>MPHalt</i>). If a
+VELAN is added, NDIS sends a global reconfiguration event to the protocol edge
+of this driver. The handler function for this event, PtPNPHandler, goes through
+all lower adapters to see if any new VELANs have been added, i.e. if any of the
+�UpperBind� keys have been modified.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Since the driver
+implements a virtual device, it does not simply pass through most NDIS
+queries/sets. It keeps its own device view that is reflected in its responses
+to queries/sets. However it does pass through queries/sets for certain OIDs
+that are best handled by the lower adapter driver. <o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The driver supports Power
+Management in the sense that it allows Wake-On-LAN and related functionality,
+if supported by the lower adapter, to continue to function. It does so by
+appropriately forwarding OID_PNP_XXX queries/sets to the lower adapter. <o:p></o:p></span></p>
+
+<p><b style='mso-bidi-font-weight:normal'><span style='font-family:Verdana'>IEEE
+802.1Q VLAN Operation<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The driver supports
+configuring a VLAN ID on each VELAN. It then inserts a tag header containing
+this VLAN ID on all outgoing frames. For incoming frames that contain a tag
+header, it verifies that a matching VLAN ID is present before indicating it up
+to protocols. It removes the tag header, if present, from all indicated frames.
+In all cases, received frames that do not contain tag headers are always handed
+up to protocols.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>With the default
+configured VLAN ID of zero, the driver does not insert tag header information
+on sent packets, except for sent packets that contain non-zero Ieee8021QInfo
+per-packet information, for which the driver does insert corresponding tag
+headers. Receive-side filtering on VLAN ID is enabled only with a non-zero
+configured VLAN ID, in which case only received frames containing a matching
+VLAN ID are passed up. With the default configured VLAN ID of zero, the driver
+does not check the VLAN ID on received frames.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>BUILDING THE SAMPLE<o:p></o:p></span></h3>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Run the <b>build</b>
+command from this directory to build the sample�it creates the binary mux.sys.
+To disable IEEE VLAN support, comment out the following line in the sources
+file before building:<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>C_DEFINES=$(C_DEFINES)
+�DIEEE_VLAN_SUPPORT=1<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>To install this driver on
+Windows� codename Whistler, use the MUX sample notification object and INFs,
+also found in this DDK.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>INSTALLING THE SAMPLE<o:p></o:p></span></h3>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>MUX is installed as a
+protocol (called �Sample <span class=SpellE>Mux</span>-IM Protocol Driver� in
+the supplied INFs/notification object). To install, follow the steps below.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Prepare a floppy disk (or
+installation directory) that contains these files: <span class=SpellE>muxp.inf</span>,
+<span class=SpellE>mux_mp.inf</span>, mux.sys and mux.dll (notification object
+DLL, built in this DDK at network\<span class=SpellE>ndis\mux\notifyob</span>).<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>On the desktop,
+right-click the <b>My Network Places</b> icon and choose <b>Properties</b>. <o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Right-click on the
+relevant Local Area Connection icon and choose <b>Properties</b>. <o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Click <b>Install</b>,
+then <b>Protocol</b>, then <b>Add</b>, <span class=GramE>then</span> <b>Have
+Disk</b>. <o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Browse to the
+drive/directory containing the files listed above. Click <b>OK</b>. This should
+show �Sample <span class=SpellE>Mux</span>-IM Protocol Driver� in a list of
+Network Protocols. Highlight this and click <b>OK</b>. This should install the
+MUX driver. <o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Click <b>OK</b> or <span
+class=GramE><b>Yes</b></span> each time the system prompts with a warning
+regarding installation of unsigned files. This is necessary because binaries
+generated via the DDK build environment are not signed.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>Two .INF files are needed
+rather than one because MUX is installed both as a protocol and a miniport.<o:p></o:p></span></p>
+
+<p><b style='mso-bidi-font-weight:normal'><span style='font-family:Verdana'>Configuring
+VLANs<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The VLAN ID for each
+VELAN (virtual miniport) can be configured as follows. Right-click on the
+virtual miniport Local Area Connection icon and choose <b style='mso-bidi-font-weight:
+normal'>Properties</b>. Click on the <b style='mso-bidi-font-weight:normal'>Configure</b>
+button to bring up the Device Manager UI for the virtual device. Select the <b
+style='mso-bidi-font-weight:normal'>Advanced</b> property sheet � this should
+contain a �VLAN ID� parameter that is configurable to the desired VLAN ID.
+Choosing a value of 0 (zero) disables receive-side filtering based on VLAN ID.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>CODE TOUR<o:p></o:p></span></h3>
+
+<h4><span style='font-family:Verdana'>File Manifest<o:p></o:p></span></h4>
+
+<pre><u>File<span style='mso-tab-count:2'>���������� </span>Description<o:p></o:p></u></pre><pre><o:p>&nbsp;</o:p></pre><pre><span
+class=SpellE>Makefile</span><span style='mso-tab-count:1'>������ </span>Used during compilation to create the object and sys files</pre><pre>Miniport.c<span
+style='mso-tab-count:1'>���� </span>Miniport related routines for the MUX driver</pre><pre><span
+class=SpellE>Mux.c</span><span style='mso-tab-count:2'>��������� </span><span
+class=SpellE>DriverEntry</span> routine and any routines common to the MUX miniport and protocol </pre><pre><span
+class=SpellE>Mux.h</span><span style='mso-tab-count:2'>��������� </span>Prototypes of all functions and data structures used by the MUX driver</pre><pre>Mux.htm<span
+style='mso-tab-count:2'>������� </span>Documentation for the MUX driver (this file)</pre><pre><span
+class=SpellE>Mux.rc</span><span style='mso-tab-count:2'>�������� </span>Resource <span
+class=GramE>file</span> for the MUX driver</pre><pre><span class=SpellE>Muxp.inf</span><span
+style='mso-tab-count:1'>������ </span>Installation INF for the service (protocol side installation)</pre><pre><span
+class=SpellE>Mux_mp.inf</span><span style='mso-tab-count:1'>���� </span>Installation INF for the miniport (virtual device installation)</pre><pre><span
+class=SpellE>Precomp.h</span><span style='mso-tab-count:1'>����� </span><span
+class=SpellE>Precompile</span> header file</pre><pre><span class=SpellE>Protocol.c</span><span
+style='mso-tab-count:1'>���� </span>Protocol related routines for the MUX driver</pre><pre>Sources<span
+style='mso-tab-count:2'>������� </span>List of source files that are compiled and linked to create the MUX driver. This can be modified to create binaries that operate on previous Windows versions (e.g. Windows 2000).</pre>
+
+<h4 style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-family:Verdana'>Programming Tour<o:p></o:p></span></h4>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>When it loads, i.e. from its <i>DriverEntry</i>
+function, the MUX driver registers as an Intermediate miniport driver and as a
+protocol, in that order.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Binding and VELAN Creation<o:p></o:p></span></b></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS calls MUX�s BindAdapter
+function, <i>PtBindAdapter</i>, for each underlying NDIS adapter to which it is
+configured to bind. This function allocates an ADAPT structure to represent the
+lower adapter, and calls NdisOpenAdapter to set up a binding to it. In the
+context of BindAdapterHandler, after successfully opening a binding to the
+underlying adapter, the driver queries the reserved keyword
+&quot;UpperBindings&quot; to get a list of device names for the virtual
+adapters that this particular binding is to expose � see <i>PtBootStrapVElans</i>
+for more details. Note that the MUX driver does not create bindings (i.e. call
+NdisOpenAdapter) from any context other than its BindAdapter function � this is
+recommended behavior for all drivers of this type.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>For each device name specified in
+the �UpperBindings� key, the MUX driver allocates a VELAN data structure to
+represent the virtual miniport, calls NdisIMInitializeDeviceInstanceEx. In
+response, NDIS eventually calls the MUX miniport�s MiniportInitialize entry
+point, <i>MPInitialize</i>, for each VELAN. After <i>MPInitialize</i>
+successfully returns, NDIS takes care of getting upper-layer protocols to bind
+to the newly created virtual adapter(s).<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Unbinding and Halting</span></b><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS calls MUX�s UnbindAdapter
+handler, <i>PtUnbindAdapter</i>, to request it to unbind from a lower adapter.
+In processing this, MUX calls NdisIMDeInitializeDeviceInstance for each VELAN
+instantiated on the indicated adapter � see <i>PtStopVElan</i> for details.
+This call results in NDIS first unbinding any protocols bound to the indicated
+VELAN, and then calling the MiniportHalt routine, <i>MPHalt</i>, for that
+VELAN. <i>MPHalt</i> waits for any outstanding receives/sends on the VELAN to
+finish before unlinking the VELAN from the ADAPT.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><i><span
+style='font-size:10.0pt;font-family:Verdana'>PtUnbindAdapter</span></i><span
+style='font-size:10.0pt;font-family:Verdana'> itself blocks until all VELANs
+associated with the ADAPT structure have been unlinked from it. This is to make
+sure that no thread running in the context of a miniport-edge entry point for a
+VELAN will ever access an invalid lower binding handle. Once all VELANs have
+been unlinked, <i>PtUnbindAdapter</i> closes the lower binding by calling
+NdisCloseAdapter. Note that the MUX driver does not close its lower binding
+from any context other than its UnbindAdapter function � this is recommended
+behavior for all drivers of this type.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><i><span
+style='font-size:10.0pt;font-family:Verdana'>MPHalt</span></i><span
+style='font-size:10.0pt;font-family:Verdana'> may also be called if the VELAN
+device is disabled, e.g. from the Network Connections Folder. There is no
+special code within <i>MPHalt</i> to handle this condition. However, <i>PtUnbindAdapter</i>
+takes care to not attempt to deinitialize a VELAN miniport (via
+NdisIMDeInitializeDeviceInstance) that has already been halted.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Handling Queries<o:p></o:p></span></b></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+class=SpellE><i><span style='font-size:10.0pt;font-family:Verdana'>MPRequest</span></i></span><span
+style='font-size:10.0pt;font-family:Verdana'> is the MUX driver�s function that
+handles queries for OID values on VELAN miniports. Most of the �Ethernet� type
+information for the virtual miniport is stored in the VELAN structure itself,
+and the driver returns information from this structure. The queries that are
+forwarded are OID_GEN_MEDIA_CONNECT_STATUS, OID_PNP_CAPABILITIES and
+OID_PNP_WAKE_UP_PATTERN_LIST. See �Handling Power Management� below for more
+information about the latter two OIDs.<i><o:p></o:p></i></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Handling Sets</span></b><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+class=SpellE><i><span style='font-size:10.0pt;font-family:Verdana'>MPRequest</span></i></span><span
+style='font-size:10.0pt;font-family:Verdana'> handles setting OID values on
+VELAN miniports. Data management OIDs handled by the MUX driver are
+OID_802_3_MULTICAST_LIST and OID_GEN_CURRENT_PACKET_FILTER. The multicast list
+is handled entirely within the MUX driver � it just stores the set of multicast
+addresses in the VELAN structure, for reference during receive-side data
+processing. The packet filter is handled in a different way � the MUX driver
+combines the packet filter settings (bitwise OR) of all VELANs associated with
+the same lower adapter. If the combined packet filter is non-zero, MUX sends a
+Set request with a value of NDIS_PACKET_TYPE_PROMISCUOUS for
+OID_GEN_CURRENT_PACKET_FILTER to start receives on the lower adapter. If the
+combined packet filter is zero, MUX sets the lower adapter�s packet filter to 0
+(turns off all receives if there aren�t any interested protocols).<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>Note that setting the lower
+adapter to promiscuous mode is only done here in order to be able to receive <span
+class=SpellE>unicast</span> frames directed to multiple MAC addresses. If, for
+example, all VELANs are assigned the same MAC address (which is identical to
+the address of the lower adapter), then the MUX driver should only pass down
+the combined (bitwise OR) setting of packet filter settings of all VELANs.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>Some power management OIDs are
+forwarded to the lower miniport. See �Handling Power Management� below for
+details. <o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Sending Data<o:p></o:p></span></b></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>Data sent down on a VELAN miniport
+is forwarded to the lower adapter. The MUX driver itself does not generate any
+data of its own. The MUX driver clones a NET_BUFFER_LIST for each <span
+class=SpellE>NetBufferList</span> passed to its <span class=SpellE><i>MPSendNetBufferLists</i></span>
+function, and saves a pointer to the original NET_BUFFER_LIST in the reserved
+area of the NET_BUFFER_LIST structure. When the lower adapter completes the
+send (<span class=SpellE><i>PtSendNBLComplete</i></span>), MUX picks up the
+original packet and calls <span class=SpellE>NdisMSendNetBufferListsComplete</span>
+to complete the original send request.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>If a non-zero VLAN ID is
+configured for the VELAN, and/or the packet has non-zero Ieee8021QInfo
+per-packet information, then the MUX driver inserts an NDIS buffer containing a
+tag header to the front of the packet before sending it down � see function <i
+style='mso-bidi-font-style:normal'>MPHandleSendTagging</i> for details.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Receiving Data<o:p></o:p></span></b></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>Data received from a lower adapter
+is indicated up on zero or more VELANs. The <span class=SpellE><i>PtReceiveNBL</i></span>
+function is called for each <span class=SpellE>NetBufferList</span> received
+from the lower adapter. The received data is checked for matches with the
+packet filter and multicast list for each VELAN associated with the adapter
+(see <i>PtMatchPacketToVElan</i>). Whenever a match is found, a new NET_BUFFER_LIST
+is allocated and set to point to the received data. A pointer to the original
+received NET_BUFFER_LIST (if any) is also stored in the new <span class=SpellE>NET_BUFFER_LIST�s</span>
+reserved area. This packet is indicated up via <span class=SpellE>NdisMIndicateReceiveNetBufferLists</span>
+to all interested protocols on that VELAN. <o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>The driver�s <span class=SpellE><i>MPReturnNetBufferLists</i></span>
+function is called either by NDIS or by MUX itself when protocols are done with
+a received NET_BUFFER_LIST. This function returns the original NET_BUFFER_LIST
+indicated by the lower driver, if any, by calling <span class=SpellE>NdisReturnNetBufferLists</span>.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>The driver indicates up received
+frames that do not have an IEEE 802.1Q tag header in them � see function <i
+style='mso-bidi-font-style:normal'>PtHandleRcvTagging</i>. It always strips off
+tag headers, if present, on received frames. If a non-zero VLAN ID is
+configured, then it checks received frames that contain tag headers for
+matching VLAN Ids � only matching frames are indicated up to protocols. Any
+VLAN/priority information present in incoming frames is copied to per-packet
+information fields of indicated NET_BUFFER_LIST structures.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Status Indications</span></b><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>The only status indications that
+are forwarded up by MUX are media connect status indications. See <i>PtStatus</i>
+for more details.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Handling Power Management</span></b><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>During initialization (<i>MPInitialize</i>),
+the MUX miniport sets the attribute <i>NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND</i> in
+its call to <span class=SpellE>NdisMSetMiniportAttributes</span>. When the MUX
+miniport is requested to report its Plug and Play capabilities
+(OID_PNP_CAPABILITIES), the MUX miniport forwards the request to the underlying
+miniport. If this request succeeds, then the MUX miniport overwrites the
+following fields before successfully completing the original request: <o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS_DEVICE_POWER_STATE<span
+style='mso-tab-count:1'>��������� </span>MinMagicPacketWakeUp =
+NdisDeviceStateUnspecified;<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS_DEVICE_POWER_STATE<span
+style='mso-tab-count:1'>��������� </span><span class=SpellE>MinPatternWakeUp</span>=
+NdisDeviceStateUnspecified;<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS_DEVICE_POWER_STATE<span
+style='mso-tab-count:1'>��������� </span>MinLinkChangeWakeUp=NdisDeviceStateUnspecified<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>See <i>PtPostProcessPnPCapabilities</i>
+for details. <o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>OID_PNP_SET_POWER and
+OID_PNP_QUERY_POWER are not passed to the lower adapter, since the lower layer
+miniport will receive independent requests from NDIS.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>NDIS calls the MUX driver�s
+ProtocolPnPEvent function (<i>PtPNPHandler</i>) whenever the underlying adapter
+is transitioned to a different power state. If the underlying adapter is
+transitioning to a low power state, the driver waits for all outstanding sends
+and requests to complete.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>Queries/sets received on a VELAN
+miniport that are to be forwarded to the underlying adapter are queued on the
+VELAN if the underlying adapter is at a low power state. These are picked up
+for processing on receiving a notification that the underlying adapter is back
+to a powered-up state.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Handling Global Reconfiguration</span></b><span
+style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'>All modifications to VELAN
+configuration are accompanied by PnP reconfigure notifications, i.e.
+NetEventReconfigure events passed to the MUX�s PnPEventHandler, <i>PtPNPHandler</i>.
+This driver takes a broad approach to handling reconfiguration, which is to
+simply re-examine all the �UpperBindings� keys for all currently bound
+adapters, and start off VELANs for any that do not exist � see <i>PtBootStrapVElans</i>
+for details.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span
+style='font-size:10.0pt;font-family:Verdana'>Canceling Sends</span></b><span
+style='font-size:10.0pt;font-family:Verdana'>: MUX propagates send
+cancellations from protocols above it to lower miniports.<o:p></o:p></span></p>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:10.0pt;font-family:Verdana'><span
+style='mso-spacerun:yes'>�</span><o:p></o:p></span></p>
+
+<p align=center style='text-align:center;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><a
+href="#top"><span style='font-size:10.0pt;font-family:Verdana'>Top of page</span></a><span
+style='font-size:10.0pt;font-family:Verdana'> <o:p></o:p></span></p>
+
+<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=624
+ style='width:6.5in;mso-cellspacing:0in;mso-padding-alt:0in 0in 0in 0in'>
+ <tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes;
+ height:1.5pt'>
+ <td style='background:aqua;padding:.75pt .75pt .75pt .75pt;height:1.5pt'>
+ <p class=MsoNormal><o:p>&nbsp;</o:p></p>
+ </td>
+ </tr>
+</table>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:7.5pt;font-family:"MS Sans Serif"'>� 1999 Microsoft
+Corporation</span><span style='font-size:10.0pt;font-family:Verdana'> <o:p></o:p></span></p>
+
+</div>
+
+</body>
+
+</html>
diff --git a/network/ndis/mux/driver/60/mux.rc b/network/ndis/mux/driver/60/mux.rc
new file mode 100644
index 00000000..4d2da7e5
--- /dev/null
+++ b/network/ndis/mux/driver/60/mux.rc
@@ -0,0 +1,50 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+
+#define VER_FILEVERSION 0xFF,0xFFFF,00,0000
+#define VER_FILEVERSION_STR "0xFF.0xFFFF.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_FILEDESCRIPTION_STR "Sample NDIS 6.0 Intermediate Miniport Driver"
+#define VER_INTERNALNAME_STR "MUX.SYS"
+#define VER_ORIGINALFILENAME_STR "MUX.SYS"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/mux/driver/60/mux_mp.inf b/network/ndis/mux/driver/60/mux_mp.inf
new file mode 100644
index 00000000..5d4d8c2d
--- /dev/null
+++ b/network/ndis/mux/driver/60/mux_mp.inf
@@ -0,0 +1,69 @@
+; -- MUXMP.INF --
+;
+; Sample MUX INF file
+;
+; Copyright (c) 1993-2004, Microsoft Corporation
+
+[Version]
+Signature = "$Windows NT$"
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Msft%
+DriverVer =10/01/2002,6.0.5019.0
+
+[ControlFlags]
+ExcludeFromSelect = MS_MUXMP
+
+[Manufacturer]
+%Msft% = MSFT,NTx86,NTia64,NTamd64
+
+[MSFT.NTx86]
+%MUXMP_Desc% = MUXMP.ndi, MS_MUXMP
+
+[MSFT.NTia64]
+%MUXMP_Desc% = MUXMP.ndi, MS_MUXMP
+
+[MSFT.NTamd64]
+%MUXMP_Desc% = MUXMP.ndi, MS_MUXMP
+
+[MUXMP.ndi]
+AddReg = MUXMP.ndi.AddReg
+Characteristics = 0xA1 ;NCF_NOT_USER_REMOVABLE | NCF_VIRTUAL | NCF_HAS_UI
+*IfType = 6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0 ; NdisMedium802_3
+*PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified
+
+
+[MUXMP.ndi.AddReg]
+HKR, Ndi, Service, 0, MUXMP
+HKR, Ndi, HelpText, 0, "%MUXMP_HELP%"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+
+HKR, Ndi\params\VlanID, ParamDesc, 0, %VlanID%
+HKR, Ndi\params\VlanID, default, 0, "0"
+HKR, Ndi\params\VlanID, type, 0, "long"
+HKR, Ndi\params\VlanID, min, 0, "0"
+HKR, Ndi\params\VlanID, max, 0, "4095"
+HKR, Ndi\params\VlanID, step, 0, "1"
+HKR, Ndi\params\VlanID, ParamDesc, 0, %VlanID%
+
+[MUXMP.ndi.Services]
+AddService = MUXMP, 2, MUXMP.AddService
+
+[MUXMP.AddService]
+DisplayName = %MUXMP_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\mux.sys
+Description = %MUXMP_Desc%
+
+
+[Strings]
+Msft = "Your Company"
+MUXMP_Desc = "Sample MUX-IM Virtual Miniport Driver"
+MUXMP_HELP = "Sample MUX-IM Virtual Miniport Instance"
+VlanID = "VLAN ID"
+
+
diff --git a/network/ndis/mux/driver/60/muxp.inf b/network/ndis/mux/driver/60/muxp.inf
new file mode 100644
index 00000000..eeeb6f8a
--- /dev/null
+++ b/network/ndis/mux/driver/60/muxp.inf
@@ -0,0 +1,100 @@
+; -- MUXP.INF --
+;
+; Sample MUX INF file
+;
+; Copyright (c) 1993-2004, Microsoft Corporation
+
+[Version]
+Signature = "$Windows NT$"
+Class = NetTrans
+ClassGUID = {4D36E975-E325-11CE-BFC1-08002BE10318}
+Provider = %Msft%
+DriverVer =10/01/2002,6.0.5019.0
+
+[Manufacturer]
+%Msft% = MSFT,NTx86,NTia64,NTamd64
+
+[MSFT.NTx86]
+%MUXP_Desc% = MUXP.ndi, MS_MUXP
+
+[MSFT.NTia64]
+%MUXP_Desc% = MUXP.ndi, MS_MUXP
+
+[MSFT.NTamd64]
+%MUXP_Desc% = MUXP.ndi, MS_MUXP
+
+; Note:
+; 1. The NCF_* flags are defined in netcfgx.h
+; 2. NCF_HAS_UI (0x80) is required for custom property pages.
+;
+
+[MUXP.ndi]
+AddReg = MUXP.ndi.AddReg
+Characteristics = 0x80 ; NCF_HAS_UI
+copyfiles = MUXP.CopyFiles.DLL, MUXP.CopyFiles.sys
+CopyInf = mux_mp.inf
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+mux.sys = 1
+mux.dll = 1
+
+
+[DestinationDirs]
+DefaultDestDir = 12
+MUXP.CopyFiles.DLL = 11 ; %windir%\System32
+MUXP.CopyFiles.Sys = 12 ; %windir%\System32\drivers
+
+[MUXP.CopyFiles.Sys]
+mux.sys,,,2
+
+[MUXP.CopyFiles.DLL]
+mux.dll,,,2
+
+
+;-----------------------------------------------------------------------
+; Install parameters
+;
+
+[MUXP.ndi.AddReg]
+HKR, Ndi, ClsID, 0, {ee6cd6fc-a32b-4a26-8a1c-dbc97988ad7a}
+HKR, Ndi, ComponentDll, , mux.dll
+HKR, Ndi, HelpText, 0, "%MUXP_HELP%"
+HKR, Ndi, Service, 0, "MUXP"
+HKR, Ndi\Interfaces, UpperRange, 0, "noupper"
+HKR, Ndi\Interfaces, LowerRange, 0, "ndis5"
+
+
+[MUXP.ndi.Services]
+AddService = MUXP, , MUXP.AddService, MUXP.AddEventLog
+
+[MUXP.AddService]
+DisplayName = %MUXP_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\mux.sys
+Description = %MUXP_Desc%
+
+[MUXP.AddEventLog]
+AddReg = MUXP.AddEventLog.AddReg
+
+[MUXP.AddEventLog.AddReg]
+HKR, , EventMessageFile, 0x20000, "%%SystemRoot%%\System32\netevent.dll"
+HKR, , TypesSupported, 0x10001, 7
+
+[MUXP.ndi.Remove.Services]
+DelService = MUXP
+
+[MUXP.ndi.Remove]
+DelFiles = MUXP.CopyFiles.DLL, MUXP.CopyFiles.sys
+
+[Strings]
+Msft = "Your Company"
+MUXP_Desc = "Sample Mux-IM Protocol Driver"
+MUXP_HELP = "Sample Mux-IM Protocol"
+DiskDescription = "Microsoft MUX Sample Driver Disk"
+
+
diff --git a/network/ndis/mux/driver/60/novlan/mux.vcxproj b/network/ndis/mux/driver/60/novlan/mux.vcxproj
new file mode 100644
index 00000000..fdc926c1
--- /dev/null
+++ b/network/ndis/mux/driver/60/novlan/mux.vcxproj
@@ -0,0 +1,287 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{D85A6A77-174C-4C80-8646-06E04ECCBAE8}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\miniport.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\mux.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\protocol.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="..\mux.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters b/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters
new file mode 100644
index 00000000..3a8f8458
--- /dev/null
+++ b/network/ndis/mux/driver/60/novlan/mux.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{DFD5078D-1185-4EEB-97B6-950B984EBE1A}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{4B2DF463-FC38-42F8-A082-E219782CD292}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{80BDAADE-F802-425A-A59E-5A93D4FA068E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{D133C63A-21C1-48F5-AFC1-F852277E2B49}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\miniport.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mux.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\protocol.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\mux.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/driver/60/novlan/precompsrc.c b/network/ndis/mux/driver/60/novlan/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/mux/driver/60/novlan/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/mux/driver/60/precomp.h b/network/ndis/mux/driver/60/precomp.h
new file mode 100644
index 00000000..e7bea3a3
--- /dev/null
+++ b/network/ndis/mux/driver/60/precomp.h
@@ -0,0 +1,14 @@
+#pragma warning(disable:4214) // bit field types other than int
+
+#pragma warning(disable:4201) // nameless struct/union
+#pragma warning(disable:4115) // named type definition in parentheses
+#pragma warning(disable:4127) // conditional expression is constant
+#pragma warning(disable:4054) // cast of function pointer to PVOID
+#pragma warning(disable:4244) // conversion from 'int' to 'BOOLEAN', possible loss of data
+
+
+#include <ndis.h>
+#include "mux.h"
+#include "public.h"
+
+
diff --git a/network/ndis/mux/driver/60/protocol.c b/network/ndis/mux/driver/60/protocol.c
new file mode 100644
index 00000000..908e4de2
--- /dev/null
+++ b/network/ndis/mux/driver/60/protocol.c
@@ -0,0 +1,3353 @@
+/*++
+Copyright(c) 1992-2000 Microsoft Corporation
+
+Module Name:
+
+ protocol.c
+
+Abstract:
+
+ NDIS Protocol Entry points and utility functions for the NDIS
+ MUX Intermediate Miniport sample.
+
+ The protocol edge binds to Ethernet (NdisMedium802_3) adapters,
+ and initiates creation of zero or more Virtual Ethernet LAN (VELAN)
+ miniport instances by calling NdisIMInitializeDeviceInstanceEx once
+ for each VELAN configured over a lower binding.
+
+Environment:
+
+ Kernel mode.
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#define MODULE_NUMBER MODULE_PROT
+
+
+NDIS_STATUS
+PtBindAdapter(
+ IN NDIS_HANDLE ProtocolDriverContext,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_BIND_PARAMETERS BindParameters
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS to bind to a miniport below. This routine
+ creates a binding by calling NdisOpenAdapterEx, and then
+ initiates creation of all configured VELANs on this binding.
+
+Arguments:
+ ProtocolDriverContext A pointer to the driver context
+ BindContext A pointer to the bind context
+ BindParameters Pointing to related information about this new binding.
+
+Return Value:
+
+ Return Status is set to NDIS_STATUS_SUCCESS if no failure occurred
+ while handling this call, otherwise an error code.
+
+--*/
+{
+ PADAPT pAdapt = NULL;
+ UINT MediumIndex = 0;
+ PNDIS_STRING pConfigString;
+ ULONG Length;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_OPEN_PARAMETERS OpenParameters;
+
+ UNREFERENCED_PARAMETER(ProtocolDriverContext);
+ UNREFERENCED_PARAMETER(BindContext);
+
+ pConfigString = (PNDIS_STRING)BindParameters->ProtocolSection;
+
+ DBGPRINT(MUX_LOUD, ("==> Protocol BindAdapter: %ws\n", pConfigString->Buffer));
+
+ do
+ {
+ if (BindParameters->Header.Type != NDIS_OBJECT_TYPE_BIND_PARAMETERS ||
+ BindParameters->Header.Revision != NDIS_BIND_PARAMETERS_REVISION_1)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Allocate memory for Adapter struct plus the config
+ // string with two extra WCHARs for NULL termination.
+ //
+ Length = sizeof(ADAPT) +
+ pConfigString->MaximumLength + sizeof(WCHAR);
+ pAdapt = NdisAllocateMemoryWithTagPriority(ProtHandle, Length , MUX_TAG, LowPoolPriority);
+
+ if (pAdapt == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize the adapter structure
+ //
+ NdisZeroMemory(pAdapt, sizeof(ADAPT));
+
+ (VOID)PtReferenceAdapter(pAdapt, (PUCHAR)"openadapter");
+
+
+ //
+ // Copy in the Config string - we will use this to open the
+ // registry section for this adapter at a later point.
+ //
+ pAdapt->ConfigString.MaximumLength = pConfigString->MaximumLength;
+ pAdapt->ConfigString.Length = pConfigString->Length;
+ pAdapt->ConfigString.Buffer = (PWCHAR)((PUCHAR)pAdapt +
+ sizeof(ADAPT));
+
+ NdisMoveMemory(pAdapt->ConfigString.Buffer,
+ pConfigString->Buffer,
+ pConfigString->Length);
+ pAdapt->ConfigString.Buffer[pConfigString->Length/sizeof(WCHAR)] =
+ ((WCHAR)0);
+
+ NdisInitializeEvent(&pAdapt->Event);
+ NdisInitializeListHead(&pAdapt->VElanList);
+
+ pAdapt->PtDevicePowerState = NdisDeviceStateD0;
+
+ //
+ // Copy the Link state, this could be updated by PtStatus soon after
+ // open operation is complete
+ //
+ pAdapt->LastIndicatedLinkState.Header.Revision = NDIS_LINK_STATE_REVISION_1;
+ pAdapt->LastIndicatedLinkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pAdapt->LastIndicatedLinkState.Header.Size = sizeof(NDIS_LINK_STATE);
+ pAdapt->LastIndicatedLinkState.MediaConnectState = BindParameters->MediaConnectState;
+ pAdapt->LastIndicatedLinkState.MediaDuplexState = BindParameters->MediaDuplexState;
+ pAdapt->LastIndicatedLinkState.XmitLinkSpeed = BindParameters->XmitLinkSpeed;
+ pAdapt->LastIndicatedLinkState.RcvLinkSpeed = BindParameters->RcvLinkSpeed;
+ pAdapt->Flags = 0;
+
+ MUX_INIT_ADAPT_RW_LOCK(pAdapt);
+ NdisAllocateSpinLock(&pAdapt->Lock);
+ //
+ // Now open the adapter below and complete the initialization
+ //
+ NdisZeroMemory(&OpenParameters, sizeof(NDIS_OPEN_PARAMETERS));
+
+ OpenParameters.Header.Type = NDIS_OBJECT_TYPE_OPEN_PARAMETERS;
+ OpenParameters.Header.Revision = NDIS_OPEN_PARAMETERS_REVISION_1;
+ OpenParameters.Header.Size = sizeof(NDIS_OPEN_PARAMETERS);
+ OpenParameters.AdapterName = BindParameters->AdapterName;
+ OpenParameters.MediumArray = MediumArray;
+ OpenParameters.MediumArraySize = sizeof(MediumArray) / sizeof(NDIS_MEDIUM);
+ OpenParameters.SelectedMediumIndex = &MediumIndex;
+
+ OpenParameters.FrameTypeArray = NULL;
+ OpenParameters.FrameTypeArraySize = 0;
+
+ NDIS_DECLARE_PROTOCOL_OPEN_CONTEXT(ADAPT);
+ Status = NdisOpenAdapterEx(ProtHandle,
+ pAdapt,
+ &OpenParameters,
+ BindContext,
+ &pAdapt->BindingHandle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pAdapt->Event, 0);
+ Status = pAdapt->Status;
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ pAdapt->BindingHandle = NULL;
+ break;
+ }
+ pAdapt->Flags |= MUX_BINDING_ACTIVE;
+
+ pAdapt->BindingState = MuxAdapterBindingPaused;
+
+ pAdapt->Medium = MediumArray[MediumIndex];
+
+ //
+ // Add this adapter to the global AdapterList
+ //
+ MUX_ACQUIRE_MUTEX(&GlobalMutex);
+
+ InsertTailList(&AdapterList, &pAdapt->Link);
+
+ MUX_RELEASE_MUTEX(&GlobalMutex);
+
+ //
+ // Copy all the relevant information about the Adapter into
+ // the local structure
+ //
+ pAdapt->BindParameters = *BindParameters;
+
+ if (BindParameters->RcvScaleCapabilities)
+ {
+ pAdapt->RcvScaleCapabilities = (*BindParameters->RcvScaleCapabilities);
+ pAdapt->BindParameters.RcvScaleCapabilities = &pAdapt->RcvScaleCapabilities;
+ }
+
+ pAdapt->PowerManagementCapabilities = (*BindParameters->PowerManagementCapabilities);
+
+
+ PtPostProcessPnPCapabilities(&pAdapt->PowerManagementCapabilities,
+ sizeof(pAdapt->PowerManagementCapabilities));
+
+ //
+ // Zeroing out fields that are not needed by the MUX driver
+ //
+ pAdapt->BindParameters.ProtocolSection= NULL;
+ pAdapt->BindParameters.AdapterName = NULL;
+ pAdapt->BindParameters.PhysicalDeviceObject = NULL;
+
+ //
+ // Start all VELANS configured on this adapter.
+ //
+ Status = PtBootStrapVElans(pAdapt, NULL);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ } while(FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+
+ if (pAdapt != NULL)
+ {
+ //
+ // For some reason, the driver cannot create velan for the binding
+ //
+ if (pAdapt->BindingHandle != NULL)
+ {
+ //
+ // Close the binding the driver opened above
+ //
+ PtCloseAdapter(pAdapt);
+
+ MUX_ACQUIRE_MUTEX(&GlobalMutex);
+
+ RemoveEntryList(&pAdapt->Link);
+
+ MUX_RELEASE_MUTEX(&GlobalMutex);
+ }
+ PtDereferenceAdapter(pAdapt, (PUCHAR)"openadapter");
+ pAdapt = NULL;
+ }
+ }
+
+
+
+ DBGPRINT(MUX_INFO, ("<== PtBindAdapter: pAdapt %p, Status %x\n", pAdapt, Status));
+
+ return Status;
+}
+
+
+VOID
+PtOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for NdisOpenAdapter issued from within the
+ PtBindAdapter. Simply unblock the caller.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter
+ Status Status of the NdisOpenAdapter call
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+
+ DBGPRINT(MUX_LOUD, ("==> PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+
+ pAdapt->Status = Status;
+ NdisSetEvent(&pAdapt->Event);
+
+ DBGPRINT(MUX_LOUD, ("<== PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+}
+
+
+VOID
+PtQueryAdapterInfo(
+ IN PADAPT pAdapt
+ )
+/*++
+
+Routine Description:
+
+ Query the adapter we are bound to for some standard OID values
+ which we cache.
+
+Arguments:
+
+ pAdapt Pointer to the adapter
+
+
+Return Value:
+
+ None
+--*/
+{
+ //
+ // Insert code here to query Adapter info if needed
+ //
+ UNREFERENCED_PARAMETER(pAdapt);
+
+}
+
+
+VOID
+PtRequestAdapterSync(
+ IN PADAPT pAdapt,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength
+ )
+/*++
+
+Routine Description:
+
+ Utility routine to query the adapter for a single OID value. This
+ blocks for the query to complete.
+
+Arguments:
+
+ pAdapt Pointer to the adapter
+ RequestType The type of the NDIS request
+ Oid OID to query for
+ InformationBuffer Place for the result
+ InformationBufferLength Length of the above
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMUX_NDIS_REQUEST pMuxNdisRequest = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ DBGPRINT(MUX_LOUD, ("==> PtRequestAdapterSync: Adapt %p, OID %8x\n", pAdapt, Oid));
+ do
+ {
+ pMuxNdisRequest = NdisAllocateMemoryWithTagPriority(pAdapt->BindingHandle, sizeof(MUX_NDIS_REQUEST), MUX_TAG, LowPoolPriority);
+ if (pMuxNdisRequest == NULL)
+ {
+ break;
+ }
+
+ pMuxNdisRequest->pVElan = NULL; // internal request
+
+ //
+ // Set up completion routine.
+ //
+ pMuxNdisRequest->pCallback = PtCompleteBlockingRequest;
+ NdisInitializeEvent(&pMuxNdisRequest->Event);
+
+ pMuxNdisRequest->Request.Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pMuxNdisRequest->Request.Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pMuxNdisRequest->Request.Header.Size = sizeof(NDIS_OID_REQUEST);
+
+ pMuxNdisRequest->Request.RequestType = RequestType;
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid = Oid;
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ pAdapt->OutstandingRequests ++;
+
+ if ((pAdapt->Flags & MUX_BINDING_CLOSING)== MUX_BINDING_CLOSING)
+ {
+ Status = NDIS_STATUS_CLOSING;
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NdisOidRequest(pAdapt->BindingHandle,
+ &pMuxNdisRequest->Request);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ pAdapt->OutstandingRequests --;
+
+ if ((pAdapt->OutstandingRequests == 0) && (pAdapt->CloseEvent != NULL))
+ {
+ NdisSetEvent(pAdapt->CloseEvent);
+ pAdapt->CloseEvent = NULL;
+ }
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ }
+ else
+ {
+ NdisWaitEvent(&pMuxNdisRequest->Event, 0);
+ Status = pMuxNdisRequest->Status;
+ }
+ }
+ while (FALSE);
+
+ if (NULL != pMuxNdisRequest)
+ {
+ NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PtRequestAdapterSync: Adapt %p, OID %8x, Status %8x\n", pAdapt, Oid, Status));
+}
+
+
+
+VOID
+PtRequestAdapterAsync(
+ IN PADAPT pAdapt,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ IN PMUX_REQ_COMPLETE_HANDLER pCallback
+ )
+/*++
+
+Routine Description:
+
+ Utility routine to query the adapter for a single OID value.
+ This completes asynchronously, i.e. the calling thread is
+ not blocked until the request completes.
+
+Arguments:
+
+ pAdapt Pointer to the adapter
+ RequestType NDIS request type
+ Oid OID to set/query
+ InformationBuffer Input/output buffer
+ InformationBufferLength Length of the above
+ pCallback Function to call on request completion
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMUX_NDIS_REQUEST pMuxNdisRequest = NULL;
+ PNDIS_OID_REQUEST pNdisRequest;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ DBGPRINT(MUX_LOUD, ("==> PtRequestAdapterAsync: Adapt %p, OID %8x\n", pAdapt, Oid));
+ do
+ {
+ pMuxNdisRequest = NdisAllocateMemoryWithTagPriority(pAdapt->BindingHandle, sizeof(MUX_NDIS_REQUEST), MUX_TAG, LowPoolPriority);
+ if (pMuxNdisRequest == NULL)
+ {
+ break;
+ }
+
+ pMuxNdisRequest->pVElan = NULL; // internal request
+
+ //
+ // Set up completion routine.
+ //
+ pMuxNdisRequest->pCallback = pCallback;
+
+ pNdisRequest = &pMuxNdisRequest->Request;
+
+ pNdisRequest->RequestType = RequestType;
+ pNdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pNdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pNdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
+
+ switch (RequestType)
+ {
+ case NdisRequestQueryInformation:
+ pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+
+ break;
+
+ case NdisRequestSetInformation:
+ pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
+ pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ pAdapt->OutstandingRequests ++;
+
+ if ((pAdapt->Flags & MUX_BINDING_CLOSING)== MUX_BINDING_CLOSING)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NdisOidRequest(
+ pAdapt->BindingHandle,
+ pNdisRequest);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ PtRequestComplete(
+ (NDIS_HANDLE)pAdapt,
+ pNdisRequest,
+ Status);
+ }
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== PtRequestAdapterAsync: Adapt %p, OID %8x, Status %8x\n", pAdapt, Oid, Status));
+}
+
+
+
+VOID
+PtCloseAdapter(
+ IN PADAPT pAdapt
+ )
+/*++
+
+Routine Description:
+
+ Call either when the protocol is unbinding or the miniport is halting to set
+ the packet filters back to zero and multicast filter back to zero
+
+Arguments:
+
+ pAdapter Pointer to a virtual adapter
+
+Return Value:
+ None
+
+--*/
+
+{
+ ULONG PacketFilter = 0;
+ PVOID MCastBuf = NULL;
+ ULONG MCastBufSize = 0;
+ NDIS_STATUS Status;
+ NDIS_EVENT CloseEvent;
+
+ DBGPRINT(MUX_LOUD, ("==> PtCloseAdapter: Adapt %p\n", pAdapt));
+
+ ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ //
+ // Clear out the packet filter and multicast list before unbinding
+ // from the adapter below is required for NDIS 6.0 protocols
+ //
+ PtRequestAdapterSync(pAdapt,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter));
+
+ PtRequestAdapterSync(pAdapt,
+ NdisRequestSetInformation,
+ OID_802_3_MULTICAST_LIST,
+ MCastBuf,
+ MCastBufSize);
+ //
+ // Stop sending requests and wait for outstanding requests to complete
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ pAdapt->Flags |= MUX_BINDING_CLOSING;
+
+ ASSERT(pAdapt->CloseEvent == NULL);
+
+ if (pAdapt->OutstandingRequests != 0)
+ {
+ NdisInitializeEvent(&CloseEvent);
+ pAdapt->CloseEvent = &CloseEvent;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ NdisWaitEvent(&CloseEvent, 0);
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ }
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ //
+ // Now Close the binding with the adapter below
+ //
+
+ NdisResetEvent(&pAdapt->Event);
+
+ Status = NdisCloseAdapterEx(pAdapt->BindingHandle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ //
+ // Wait for it to complete.
+ //
+ NdisWaitEvent(&pAdapt->Event, 0);
+ }
+
+ pAdapt->BindingHandle = NULL;
+
+ DBGPRINT(MUX_LOUD, ("<== PtCloseAdapter: Adapt %p\n", pAdapt));
+}
+
+NDIS_STATUS
+PtUnbindAdapter(
+ IN NDIS_HANDLE UnbindContext,
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS when we are required to unbind to the adapter below.
+ Go through all VELANs on the adapter and shut them down.
+
+Arguments:
+
+ Status Placeholder for return status
+ ProtocolBindingContext Pointer to the adapter structure
+ UnbindContext Context for NdisUnbindComplete() if this pends
+
+Return Value:
+
+ Status from closing the binding.
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ PLIST_ENTRY p;
+ PVELAN pVElan = NULL;
+ LOCK_STATE LockState;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(UnbindContext);
+
+ DBGPRINT(MUX_LOUD, ("==> PtUnbindAdapter: Adapt %p\n", pAdapt));
+
+ //
+ // Stop all VELANs associated with the adapter.
+ // Repeatedly find the first unprocessed VELAN on
+ // the adapter, mark it, and stop it.
+ //
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ do
+ {
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+ if (!pVElan->DeInitializing)
+ {
+ pVElan->DeInitializing = TRUE;
+ break;
+ }
+ }
+
+ if (p != &pAdapt->VElanList)
+ {
+ ASSERT(pVElan == CONTAINING_RECORD(p, VELAN, Link));
+
+ //
+ // Got a VELAN to stop. Add a temp ref
+ // so that the VELAN won't go away when
+ // we release the ADAPT lock below.
+ //
+ PtReferenceVElan(pVElan, (PUCHAR)"UnbindTemp");
+
+ //
+ // Release the read lock because we want to
+ // run StopVElan at passive IRQL.
+ //
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ PtStopVElan(pVElan);
+
+ PtDereferenceVElan(pVElan, (PUCHAR)"UnbindTemp");
+
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+ }
+ else
+ {
+ //
+ // No unmarked VELAN, so exit.
+ //
+ break;
+ }
+ }
+ while (TRUE);
+
+ //
+ // Wait until all VELANs are unlinked from the adapter.
+ // This is so that we don't attempt to forward down packets
+ // and/or requests from VELANs after calling NdisCloseAdapter.
+ //
+ while (!IsListEmpty(&pAdapt->VElanList))
+ {
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ DBGPRINT(MUX_INFO, ("PtUnbindAdapter: pAdapt %p, VELANlist not yet empty\n",
+ pAdapt));
+
+ NdisMSleep(2000);
+
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ //
+ // Close the binding to the lower adapter.
+ //
+ if (pAdapt->BindingHandle != NULL)
+ {
+ PtCloseAdapter(pAdapt);
+ }
+ else
+ {
+ //
+ // Binding Handle should not be NULL.
+ //
+ Status = NDIS_STATUS_FAILURE;
+ ASSERT(0);
+ }
+
+ //
+ // Remove the adapter from the global AdapterList
+ //
+
+ MUX_ACQUIRE_MUTEX(&GlobalMutex);
+
+ RemoveEntryList(&pAdapt->Link);
+
+ MUX_RELEASE_MUTEX(&GlobalMutex);
+
+ NdisFreeSpinLock(&pAdapt->Lock);
+
+ //
+ // Free all the resources associated with this Adapter except the
+ // ADAPT struct itself, because that will be freed by
+ // PtDereferenceAdapter call when the reference drops to zero.
+ // Note: Every VELAN associated with this Adapter takes a ref count
+ // on it. So the adapter memory wouldn't be freed until all the VELANs
+ // are shutdown.
+ //
+
+ PtDereferenceAdapter(pAdapt, (PUCHAR)"Unbind");
+
+ DBGPRINT(MUX_LOUD, ("<== PtUnbindAdapter: Adapt %p, Status=%08lx\n", pAdapt, Status));
+
+ return Status;
+}
+
+
+
+VOID
+PtCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+ Completion for the CloseAdapter call.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+
+ DBGPRINT(MUX_LOUD, ("==> PtCloseAdapterComplete: Adapt %p\n",
+ pAdapt));
+
+ NdisSetEvent(&pAdapt->Event);
+
+ DBGPRINT(MUX_LOUD, ("<== PtCloseAdapterComplete: Adapt %p\n",
+ pAdapt));
+}
+
+
+VOID
+PtRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_OID_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion handler for an NDIS request sent to a lower
+ miniport.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ NdisRequest The completed request, must be an element of an instance of MUX_NDIS_REQUEST
+ Status Completion status
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ PMUX_NDIS_REQUEST pMuxNdisRequest;
+
+
+ DBGPRINT(MUX_LOUD, ("==> PtRequestComplete: Adapt %p, Request %p, Status %8x\n",
+ pAdapt, NdisRequest, Status));
+
+ //get the Super-structure for NDIS_REQUEST before getting the callback functions
+ //so make sure NdisRequest is a filled into a MUX_NDIS_REQUEST before using this function
+ pMuxNdisRequest = CONTAINING_RECORD(NdisRequest, MUX_NDIS_REQUEST, Request);
+
+ ASSERT(pMuxNdisRequest->pCallback != NULL);
+
+
+ //
+ // Completion is handled by the callback routine:
+ //
+ (*pMuxNdisRequest->pCallback)(pAdapt,
+ pMuxNdisRequest,
+ Status);
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ pAdapt->OutstandingRequests --;
+
+ if ((pAdapt->OutstandingRequests == 0) && (pAdapt->CloseEvent != NULL))
+ {
+ NdisSetEvent(pAdapt->CloseEvent);
+ pAdapt->CloseEvent = NULL;
+ }
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ DBGPRINT(MUX_LOUD, ("<== PtRequestComplete: Adapt %p, Request %p, Status %8x\n",
+ pAdapt, NdisRequest, Status));
+
+}
+
+
+VOID
+PtCompleteForwardedRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Handle completion of an NDIS request that was originally
+ submitted to our VELAN miniport and was forwarded down
+ to the lower binding.
+
+ We do some postprocessing, to cache the results of
+ certain queries.
+
+Arguments:
+
+ pAdapt - Adapter on which the request was forwarded
+ pMuxNdisRequest - super-struct for request
+ Status - request completion status
+
+Return Value:
+
+ None
+
+--*/
+{
+ PVELAN pVElan = NULL;
+ PNDIS_OID_REQUEST pNdisRequest = &pMuxNdisRequest->Request;
+ NDIS_OID Oid;
+ PNDIS_OID_REQUEST OrigRequest = NULL;
+ BOOLEAN fCompleteRequest = FALSE;
+
+ UNREFERENCED_PARAMETER(pAdapt);
+
+
+ DBGPRINT(MUX_LOUD, ("==> PtCompleteForwardedRequest: Adapt %p, MuxRequest %p, Status %8x\n",
+ pAdapt, pMuxNdisRequest, Status));
+ //
+ // Get the originating VELAN. The VELAN will not be dereferenced
+ // away until the pended request is completed.
+ //
+ pVElan = pMuxNdisRequest->pVElan;
+
+ ASSERT(pVElan != NULL);
+ ASSERT(pMuxNdisRequest == &pVElan->Request);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(MUX_WARN, ("PtCompleteForwardedRequest: pVElan %p, OID %x, Status %x\n",
+ pVElan,
+ pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid,
+ Status));
+ }
+
+ NdisAcquireSpinLock(&pVElan->Lock);
+
+ pMuxNdisRequest->Refcount --;
+ if (pMuxNdisRequest->Refcount == 0)
+ {
+ fCompleteRequest = TRUE;
+ OrigRequest = pMuxNdisRequest->OrigRequest;
+ pMuxNdisRequest->OrigRequest = NULL;
+ }
+
+
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ if (fCompleteRequest == FALSE)
+ {
+ return;
+ }
+
+ //
+ // Complete the original request.
+ //
+ switch (pNdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+
+ OrigRequest->DATA.QUERY_INFORMATION.BytesWritten =
+ pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ OrigRequest->DATA.QUERY_INFORMATION.BytesNeeded =
+ pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+
+ //
+ // Before completing the request, do any necessary
+ // post-processing.
+ //
+ Oid = pNdisRequest->DATA.QUERY_INFORMATION.Oid;
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (Oid == OID_GEN_LINK_SPEED)
+ {
+ NdisMoveMemory (&pVElan->LinkSpeed,
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+ }
+ else if (Oid == OID_PNP_CAPABILITIES)
+ {
+ PtPostProcessPnPCapabilities(pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength);
+ }
+ }
+
+ break;
+
+ case NdisRequestSetInformation:
+
+ OrigRequest->DATA.SET_INFORMATION.BytesRead=
+ pNdisRequest->DATA.SET_INFORMATION.BytesRead;
+ OrigRequest->DATA.QUERY_INFORMATION.BytesNeeded=
+ pNdisRequest->DATA.SET_INFORMATION.BytesNeeded;
+
+#if IEEE_VELAN_SUPPORT
+ if ((pNdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_LOOKAHEAD)
+ && (pVElan->RestoreLookaheadSize == TRUE))
+ {
+ pVElan->RestoreLookaheadSize = FALSE;
+ *(UNALIGNED PULONG)(Request->DATA.SET_INFORMATION.InformationBuffer) -= VLAN_TAG_HEADER_SIZE;
+ }
+#endif
+ //
+ // Before completing the request, cache relevant information
+ // in our structure.
+ //
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Oid = pNdisRequest->DATA.SET_INFORMATION.Oid;
+ switch (Oid)
+ {
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+
+ NdisMoveMemory(&pVElan->LookAhead,
+ pNdisRequest->DATA.SET_INFORMATION.InformationBuffer,
+ sizeof(ULONG));
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ NdisMOidRequestComplete(pVElan->MiniportAdapterHandle,OrigRequest,Status);
+
+ MUX_DECR_PENDING_SENDS(pVElan);
+
+ DBGPRINT(MUX_LOUD, ("<== PtCompleteForwardedRequest: Adapt %p, MuxRequest %p, Status %8x\n",
+ pAdapt, pMuxNdisRequest, Status));
+}
+
+
+
+VOID
+PtPostProcessPnPCapabilities(
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength
+ )
+/*++
+
+Routine Description:
+
+ Postprocess a successfully completed query for OID_PNP_CAPABILITIES.
+ We modify the returned information slightly before completing
+ it to the VELAN above.
+
+Arguments:
+
+ InformationBuffer - points to buffer for the OID
+ InformationBufferLength - byte length of the above.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDIS_PNP_CAPABILITIES pPNPCapabilities;
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
+
+ DBGPRINT(MUX_LOUD, ("==> PtPostProcessPnPCapabilities\n"));
+
+ if (InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
+ {
+ pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)InformationBuffer;
+
+ //
+ // The following fields must be overwritten by an IM driver.
+ //
+ pPMstruct= &pPNPCapabilities->WakeUpCapabilities;
+ pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ }
+ DBGPRINT(MUX_LOUD, ("<== PtPostProcessPnPCapabilities\n"));
+}
+
+VOID
+PtCompleteBlockingRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Handle completion of an NDIS request that was originated
+ by this driver and the calling thread is blocked waiting
+ for completion.
+
+Arguments:
+
+ pAdapt - Adapter on which the request was forwarded
+ pMuxNdisRequest - super-struct for request
+ Status - request completion status
+
+Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pAdapt);
+
+ DBGPRINT(MUX_LOUD, ("==> PtCompleteBlockingRequest: Adapt %p, MuxRequest %p, Status %8x\n",
+ pAdapt, pMuxNdisRequest, Status));
+
+ //
+ // The request was originated from this driver. Wake up the
+ // thread blocked for its completion.
+ //
+ pMuxNdisRequest->Status = Status;
+ NdisSetEvent(&pMuxNdisRequest->Event);
+
+ DBGPRINT(MUX_LOUD, ("<== PtCompleteBlockingRequest: Adapt %p, MuxRequest %p, Status %8x\n",
+ pAdapt, pMuxNdisRequest, Status));
+}
+
+
+VOID
+PtDiscardCompletedRequest(
+ IN PADAPT pAdapt,
+ IN PMUX_NDIS_REQUEST pMuxNdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Handle completion of an NDIS request that was originated
+ by this driver - the request is to be discarded.
+
+Arguments:
+
+ pAdapt - Adapter on which the request was forwarded
+ pMuxNdisRequest - super-struct for request
+ Status - request completion status
+
+Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pAdapt);
+ UNREFERENCED_PARAMETER(Status);
+
+ NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
+}
+
+
+VOID
+PtStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STATUS_INDICATION StatusIndication
+ )
+/*++
+
+Routine Description:
+
+ Handle a status indication on the lower binding (ADAPT).
+ If this is a media status indication, we also pass this
+ on to all associated VELANs.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ GeneralStatus Status code
+ StatusBuffer Status buffer
+ StatusBufferSize Size of the status buffer
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ PLIST_ENTRY p;
+ PVELAN pVElan;
+ LOCK_STATE LockState;
+ NDIS_STATUS GeneralStatus = StatusIndication->StatusCode;
+ NDIS_STATUS_INDICATION NewStatusIndication;
+
+ DBGPRINT(MUX_LOUD, ("==> PtStatus: Adapt %p, Status %x\n", pAdapt, GeneralStatus));
+
+ do
+ {
+
+ //
+ // Ignore status indications that we aren't going
+ // to pass up.
+ //
+ if ((GeneralStatus != NDIS_STATUS_LINK_STATE)
+ )
+ {
+ break;
+ }
+
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ if (GeneralStatus == NDIS_STATUS_LINK_STATE)
+ {
+ pAdapt->LastIndicatedLinkState = *((PNDIS_LINK_STATE)(StatusIndication->StatusBuffer));
+ }
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+
+ MUX_INCR_PENDING_RECEIVES(pVElan);
+
+ //
+ // Should the indication be sent on this VELAN?
+ //
+ if ((pVElan->MiniportInitPending) ||
+ (pVElan->MiniportHalting) ||
+ (pVElan->MiniportAdapterHandle == NULL) ||
+ MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
+ {
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+ if (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
+ {
+ //
+ // Keep track of the lastest status to indicated when VELAN power is on
+ //
+ ASSERT(GeneralStatus == NDIS_STATUS_LINK_STATE);
+
+ pVElan->LatestUnIndicateStatus = GeneralStatus;
+
+ if (GeneralStatus == NDIS_STATUS_LINK_STATE)
+ {
+ pVElan->LatestUnIndicateLinkState = *(PNDIS_LINK_STATE)StatusIndication->StatusBuffer;
+ }
+ }
+
+ continue;
+ }
+
+ //
+ // Save the last indicated status when
+ pVElan->LastIndicatedStatus = GeneralStatus;
+ if (GeneralStatus == NDIS_STATUS_LINK_STATE)
+ {
+ pVElan->LastIndicatedLinkState = *(PNDIS_LINK_STATE)StatusIndication->StatusBuffer;
+ }
+ //
+ // Allocate a new status indication and set the destination handle to null to ensure that the status
+ // is indicated to protocols bound to mux velans. Copy only the fields that makes sense to pass up. For
+ // instance, do not copy PortNumber, RequestId, Flags, Guid, NdisReserved. Port Number is really not
+ // necessary to copy and pass up for the scenario because the port number is an entity that makes sense
+ // between the protocol and the underlying miniport pair.
+ //
+
+ NdisZeroMemory(&NewStatusIndication, sizeof(NDIS_STATUS_INDICATION));
+
+ NewStatusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ NewStatusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ NewStatusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
+
+ NewStatusIndication.StatusCode = StatusIndication->StatusCode;
+ NewStatusIndication.SourceHandle = pVElan->MiniportAdapterHandle;
+ NewStatusIndication.DestinationHandle = NULL;
+
+ NewStatusIndication.StatusBuffer = StatusIndication->StatusBuffer;
+ NewStatusIndication.StatusBufferSize = StatusIndication->StatusBufferSize;
+
+ NdisMIndicateStatusEx(pVElan->MiniportAdapterHandle, &NewStatusIndication);
+
+ //
+ // Mark this so that we forward a status complete
+ // indication as well.
+ //
+ pVElan->IndicateStatusComplete = TRUE;
+
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== PtStatus: Adapt %p, Status %x\n", pAdapt, GeneralStatus));
+}
+
+
+BOOLEAN
+PtMulticastMatch(
+ IN PVELAN pVElan,
+ IN PUCHAR pDstMac
+ )
+/*++
+
+Routine Description:
+
+ Check if the given multicast destination MAC address matches
+ any of the multicast address entries set on the VELAN.
+
+ NOTE: the caller is assumed to hold a READ/WRITE lock
+ to the parent ADAPT structure. This is so that the multicast
+ list on the VELAN is invariant for the duration of this call.
+
+Arguments:
+
+ pVElan - VELAN to look in
+ pDstMac - Destination MAC address to compare
+
+Return Value:
+
+ TRUE iff the address matches an entry in the VELAN
+
+--*/
+{
+ ULONG i;
+ UINT AddrCompareResult;
+
+ for (i = 0; i < pVElan->McastAddrCount; i++)
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->McastAddrs[i],
+ pDstMac,
+ &AddrCompareResult);
+
+ if (AddrCompareResult == 0)
+ {
+ break;
+ }
+ }
+
+ return (i != pVElan->McastAddrCount);
+}
+
+
+BOOLEAN
+PtMatchPacketToVElan(
+ IN PVELAN pVElan,
+ IN PUCHAR pDstMac,
+ IN BOOLEAN bIsMulticast,
+ IN BOOLEAN bIsBroadcast
+ )
+/*++
+
+Routine Description:
+
+ Check if the destination address of a received packet
+ matches the receive criteria on the specified VELAN.
+
+ NOTE: the caller is assumed to hold a READ/WRITE lock
+ to the parent ADAPT structure.
+
+Arguments:
+
+ pVElan - VELAN to check on
+ pDstMac - Destination MAC address in received packet
+ bIsMulticast - is this a multicast address
+ bIsBroadcast - is this a broadcast address
+
+Return Value:
+
+ TRUE iff this packet should be received on the VELAN
+
+--*/
+{
+ UINT AddrCompareResult;
+ ULONG PacketFilter;
+ BOOLEAN bPacketMatch;
+
+ DBGPRINT(MUX_VERY_LOUD, ("==> PtMatchPacketToVElan: VElan %p\n", pVElan));
+ //
+ PacketFilter = pVElan->PacketFilter;
+
+ //
+ // Handle the directed packet case first.
+ //
+ if (!bIsMulticast)
+ {
+ //
+ // If the VELAN is not in promisc. mode, check if
+ // the destination MAC address matches the local
+ // address.
+ //
+ if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == 0)
+ {
+ ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->CurrentAddress,
+ pDstMac,
+ &AddrCompareResult);
+
+ bPacketMatch = ((AddrCompareResult == 0) &&
+ ((PacketFilter & NDIS_PACKET_TYPE_DIRECTED) != 0));
+ }
+ else
+ {
+ bPacketMatch = TRUE;
+ }
+ }
+ else
+ {
+ //
+ // Multicast or broadcast packet.
+ //
+
+ //
+ // Indicate if the filter is set to promisc mode ...
+ //
+ if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ ||
+
+ //
+ // or if this is a broadcast packet and the filter
+ // is set to receive all broadcast packets...
+ //
+ (bIsBroadcast &&
+ (PacketFilter & NDIS_PACKET_TYPE_BROADCAST))
+ ||
+
+ //
+ // or if this is a multicast packet, and the filter is
+ // either set to receive all multicast packets, or
+ // set to receive specific multicast packets. In the
+ // latter case, indicate receive only if the destn
+ // MAC address is present in the list of multicast
+ // addresses set on the VELAN.
+ //
+ (!bIsBroadcast &&
+ ((PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
+ ((PacketFilter & NDIS_PACKET_TYPE_MULTICAST) &&
+ PtMulticastMatch(pVElan, pDstMac))))
+ )
+ {
+ bPacketMatch = TRUE;
+ }
+ else
+ {
+ //
+ // No protocols above are interested in this
+ // multicast/broadcast packet.
+ //
+ bPacketMatch = FALSE;
+ }
+ }
+
+ DBGPRINT(MUX_VERY_LOUD, ("<== PtMatchPacketToVElan: VElan %p, PacketMatch %x\n", pVElan, bPacketMatch));
+
+ return (bPacketMatch);
+}
+
+
+NDIS_STATUS
+PtPnPNetEventSetPower(
+ IN PADAPT pAdapt,
+ IN PNET_PNP_EVENT_NOTIFICATION pNetPnPEventNotification
+ )
+/*++
+Routine Description:
+
+ This is a notification to our protocol edge of the power state
+ of the lower miniport. If it is going to a low-power state, we must
+ wait here for all outstanding sends and requests to complete.
+
+Arguments:
+
+ pAdapt - Pointer to the adpater structure
+ pNetPnPEvent - The Net Pnp Event. this contains the new device state
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ PLIST_ENTRY p;
+ PVELAN pVElan;
+ LOCK_STATE LockState;
+ NDIS_STATUS Status;
+
+ //
+ // Store the new power state.
+ //
+
+ pAdapt->PtDevicePowerState = *(PNDIS_DEVICE_POWER_STATE)pNetPnPEventNotification->NetPnPEvent.Buffer;
+
+ DBGPRINT(MUX_LOUD, ("==> PnPNetEventSetPower: Adapt %p, SetPower to %d\n",
+ pAdapt, pAdapt->PtDevicePowerState));
+
+ //
+ // Check if the miniport below is going to a low power state.
+ //
+ if (MUX_IS_LOW_POWER_STATE(pAdapt->PtDevicePowerState))
+ {
+ ULONG i;
+
+ //
+ // It is going to a low power state. Wait for outstanding
+ // I/O to complete on the adapter.
+ //
+ for (i = 0; i < 10000; i++)
+ {
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+ if ((pVElan->OutstandingSends != 0) ||
+ (pVElan->OutstandingReceives != 0))
+ {
+ break;
+ }
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ if (p == &pAdapt->VElanList)
+ {
+ //
+ // There are no VELANs with pending I/O.
+ //
+ break;
+ }
+
+ DBGPRINT(MUX_INFO, ("SetPower: Adapt %p, waiting for pending IO to complete\n",
+ pAdapt));
+
+ NdisMSleep(1000);
+ }
+
+ }
+ else
+ {
+ //
+ // The device below is powered on. If we had requests
+ // pending on any VELANs, send them down now.
+ //
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+
+ //
+ // Need to make sure other threads do not try to acquire the write lock while holding
+ // the same spin lock
+ //
+ NdisAcquireSpinLock(&pVElan->Lock);
+ if (pVElan->QueuedRequest)
+ {
+ pVElan->QueuedRequest = FALSE;
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ pAdapt->OutstandingRequests ++;
+
+ if ((pAdapt->Flags & MUX_BINDING_CLOSING)== MUX_BINDING_CLOSING)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_CLOSING;
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NdisOidRequest(
+ pAdapt->BindingHandle,
+ &pVElan->Request.Request);
+ }
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ PtRequestComplete(pAdapt,
+ &pVElan->Request.Request,
+ Status);
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pVElan->Lock);
+ }
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PnPNetEventSetPower: Adapt %p, SetPower to %d\n",
+ pAdapt, pAdapt->PtDevicePowerState));
+
+ return (NDIS_STATUS_SUCCESS);
+}
+
+
+NDIS_STATUS
+PtPNPHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_PNP_EVENT_NOTIFICATION pNetPnPEventNotification
+ )
+
+/*++
+Routine Description:
+
+ This is called by NDIS to notify us of a PNP event related to a lower
+ binding. Based on the event, this dispatches to other helper routines.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
+ for "global" notifications
+
+ pNetPnPEvent - Pointer to the PNP event to be processed.
+
+Return Value:
+
+ NDIS_STATUS code indicating status of event processing.
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PLIST_ENTRY p;
+ NDIS_EVENT PauseEvent;
+
+ DBGPRINT(MUX_LOUD, ("==> PtPnPHandler: Adapt %p, NetPnPEvent %d\n", pAdapt,
+ pNetPnPEventNotification->NetPnPEvent.NetEvent));
+
+ switch (pNetPnPEventNotification->NetPnPEvent.NetEvent)
+ {
+ case NetEventSetPower:
+
+ Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEventNotification);
+ break;
+
+ case NetEventReconfigure:
+ //
+ // Rescan configuration and bring up any VELANs that
+ // have been newly added. Make sure that the global
+ // adapter list is undisturbed while we traverse it.
+ //
+ MUX_ACQUIRE_MUTEX(&GlobalMutex);
+
+ for (p = AdapterList.Flink;
+ p != &AdapterList;
+ p = p->Flink)
+ {
+ pAdapt = CONTAINING_RECORD(p, ADAPT, Link);
+
+ PtBootStrapVElans(pAdapt, NULL);
+ }
+
+ MUX_RELEASE_MUTEX(&GlobalMutex);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ case NetEventIMReEnableDevice:
+ MUX_ACQUIRE_MUTEX(&GlobalMutex);
+
+ for (p = AdapterList.Flink;
+ p != &AdapterList;
+ p = p->Flink)
+ {
+ pAdapt = CONTAINING_RECORD(p, ADAPT, Link);
+
+ PtBootStrapVElans(pAdapt, pNetPnPEventNotification->NetPnPEvent.Buffer);
+ }
+
+
+ MUX_RELEASE_MUTEX(&GlobalMutex);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+
+ case NetEventPause:
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ pAdapt->BindingState = MuxAdapterBindingPausing;
+
+ ASSERT(pAdapt->PauseEvent == NULL);
+
+ if (pAdapt->OutstandingSends != 0)
+ {
+ NdisInitializeEvent(&PauseEvent);
+
+ pAdapt->PauseEvent = &PauseEvent;
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ NdisWaitEvent(&PauseEvent, 0);
+
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ }
+
+ pAdapt->BindingState = MuxAdapterBindingPaused;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case NetEventRestart:
+ pAdapt->BindingState = MuxAdapterBindingRunning;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+
+ default:
+ Status = NDIS_STATUS_SUCCESS;
+
+ break;
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PtPnPHandler: Adapt %p, NetPnPEvent %d, Status %8x\n", pAdapt,
+ pNetPnPEventNotification->NetPnPEvent.NetEvent, Status));
+ return Status;
+}
+
+NDIS_STATUS
+PtCreateAndStartVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pVElanKey
+)
+/*++
+
+Routine Description:
+
+ Create and start a VELAN with the given key name. Check if a VELAN
+ with this key name already exists; if so do nothing.
+
+ ASSUMPTION: this is called from either the BindAdapter handler for
+ the underlying adapter, or from the PNP reconfig handler. Both these
+ routines are protected by NDIS against pre-emption by UnbindAdapter.
+ If this routine will be called from any other context, it should
+ be protected against a simultaneous call to our UnbindAdapter handler.
+
+Arguments:
+
+ pAdapt - Pointer to Adapter structure
+ pVElanKey - Points to a Unicode string naming the VELAN to create.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we either found a duplicate VELAN or
+ successfully initiated a new ELAN with the given key.
+
+ NDIS_STATUS_XXX error code otherwise (failure initiating a new VELAN).
+
+--*/
+{
+ NDIS_STATUS Status;
+ PVELAN pVElan;
+
+ Status = NDIS_STATUS_SUCCESS;
+ pVElan = NULL;
+
+ DBGPRINT(MUX_LOUD, ("=> PtCreateAndStartVElan: Adapter %p, ElanKey %ws\n",
+ pAdapt, pVElanKey->Buffer));
+
+ do
+ {
+ //
+ // Weed out duplicates.
+ //
+ if (pVElanKey != NULL)
+ {
+
+ pVElan = PtFindVElan(pAdapt, pVElanKey);
+
+ if (NULL != pVElan)
+ {
+ //
+ // Duplicate - bail out silently.
+ //
+ DBGPRINT(MUX_WARN, ("CreateElan: found duplicate pVElan %p\n", pVElan));
+
+ Status = NDIS_STATUS_SUCCESS;
+ pVElan = NULL;
+ break;
+ }
+ }
+
+ pVElan = NULL;
+
+ if (pVElanKey != NULL)
+ {
+ pVElan = PtAllocateAndInitializeVElan(pAdapt, pVElanKey);
+ }
+
+ if (pVElan == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ //
+ // Request NDIS to initialize the virtual miniport. Set
+ // the flag below just in case an unbind occurs before
+ // MiniportInitialize is called.
+ //
+ PtReferenceVElan(pVElan,(UCHAR*) "CreatVelan");
+ pVElan->MiniportInitPending = TRUE;
+ NdisInitializeEvent(&pVElan->MiniportInitEvent);
+
+ Status = NdisIMInitializeDeviceInstanceEx(DriverHandle,
+ &pVElan->CfgDeviceName,
+ pVElan);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pVElan->MiniportHalting == FALSE)
+ {
+ PtUnlinkVElanFromAdapter(pVElan); // IMInit failed
+ }
+ PtDereferenceVElan(pVElan, (UCHAR*) "CreatVelan");
+ pVElan = NULL;
+ break;
+ }
+
+ PtDereferenceVElan(pVElan,(UCHAR*) "CreatVelan");
+
+ }
+ while (FALSE);
+
+ DBGPRINT(MUX_LOUD, ("<== PtCreateAndStartVElan: Adapter %p, VELAN %p, Status %8x\n", pAdapt, pVElan, Status));
+
+ return Status;
+}
+
+
+PVELAN
+PtAllocateAndInitializeVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pVElanKey
+ )
+/*++
+
+Routine Description:
+
+ Allocates and initializes a VELAN structure. Also links it to
+ the specified ADAPT.
+
+Arguments:
+
+ pAdapt - Adapter to link VELAN to
+ pVElanKey - Key to the VELAN
+
+Return Value:
+
+ Pointer to VELAN structure if successful, NULL otherwise.
+
+--*/
+{
+ PVELAN pVElan;
+ ULONG Length;
+ NDIS_STATUS Status;
+ LOCK_STATE LockState;
+
+ DBGPRINT(MUX_LOUD, ("==> PtCreateAndStartVElan: Adapter %p, VELAN Key %ws\n", pAdapt, pVElanKey->Buffer));
+ pVElan = NULL;
+ Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ Length = sizeof(VELAN) + pVElanKey->Length + sizeof(WCHAR);
+
+ //
+ // Allocate a VELAN data structure.
+ //
+ pVElan = NdisAllocateMemoryWithTagPriority(pAdapt->BindingHandle, Length, MUX_TAG, LowPoolPriority);
+ if (pVElan == NULL)
+ {
+ DBGPRINT(MUX_FATAL, ("AllocateVElan: Failed to allocate %d bytes for VELAN\n",
+ Length));
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize it.
+ //
+ NdisZeroMemory(pVElan, Length);
+ NdisInitializeListHead(&pVElan->Link);
+ NdisInitializeListHead(&pVElan->GlobalLink);
+
+ //
+ // Initialize the built-in request structure to signify
+ // that it is used to forward NDIS requests.
+ //
+ pVElan->Request.pVElan = pVElan;
+ NdisInitializeEvent(&pVElan->Request.Event);
+
+ //
+ // Store in the key name.
+ //
+ pVElan->CfgDeviceName.Length = 0;
+ pVElan->CfgDeviceName.Buffer = (PWCHAR)((PUCHAR)pVElan +
+ sizeof(VELAN));
+ pVElan->CfgDeviceName.MaximumLength =
+ pVElanKey->Length + sizeof(WCHAR);
+ (VOID)NdisUpcaseUnicodeString(&pVElan->CfgDeviceName, pVElanKey);
+ pVElan->CfgDeviceName.Buffer[pVElanKey->Length/sizeof(WCHAR)] =
+ ((WCHAR)0);
+
+ //
+ // Initialize LastIndicatedStatus to media connect
+ //
+ pVElan->LastIndicatedStatus = NDIS_STATUS_LINK_STATE;
+
+ //
+ // Set power state of virtual miniport to D0.
+ //
+ pVElan->MPDevicePowerState = NdisDeviceStateD0;
+
+ //
+ // Cache the binding handle for quick reference.
+ //
+ pVElan->BindingHandle = pAdapt->BindingHandle;
+ pVElan->pAdapt = pAdapt;
+
+ //
+ // Copy in some adapter parameters.
+ //
+ pVElan->LookAhead = pAdapt->BindParameters.LookaheadSize;
+ pVElan->LinkSpeed = pAdapt->BindParameters.RcvLinkSpeed;
+ ASSERT(pAdapt->BindParameters.MacAddressLength == 6);
+
+ if (pAdapt->BindParameters.MacAddressLength == 6)
+ {
+
+ NdisMoveMemory(pVElan->PermanentAddress,
+ &pAdapt->BindParameters.CurrentMacAddress,
+ pAdapt->BindParameters.MacAddressLength);
+
+ NdisMoveMemory(pVElan->CurrentAddress,
+ &pAdapt->BindParameters.CurrentMacAddress,
+ pAdapt->BindParameters.MacAddressLength);
+ }
+ else
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ DBGPRINT(MUX_LOUD, ("Alloced VELAN %p, MAC addr %s\n",
+ pVElan, MacAddrToString(pVElan->CurrentAddress)));
+
+ NdisAllocateSpinLock(&pVElan->Lock);
+
+ NdisAllocateSpinLock(&pVElan->PauseLock);
+
+
+
+#ifdef IEEE_VLAN_SUPPORT
+ //
+ // Allocate lookaside list for tag headers.
+ //
+ NdisInitializeNPagedLookasideList (
+ &pVElan->TagLookaside,
+ NULL,
+ NULL,
+ 0,
+ ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE + sizeof(IM_SEND_NB_ENTRY),
+ MUX_TAG,
+ 0);
+
+#endif
+ //
+ // Finally link this VELAN to the Adapter's VELAN list.
+ //
+ PtReferenceVElan(pVElan, (PUCHAR)"adapter");
+
+ MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ PtReferenceAdapter(pAdapt, (PUCHAR)"VElan");
+ InsertTailList(&pAdapt->VElanList, &pVElan->Link);
+
+ pAdapt->VElanCount++;
+ pVElan->VElanNumber = NdisInterlockedIncrement((PLONG)&NextVElanNumber);
+
+ MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ NdisAcquireSpinLock(&GlobalLock);
+ InsertTailList(&VElanList, &pVElan->GlobalLink);
+ NdisReleaseSpinLock(&GlobalLock);;
+ }
+ while (FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pVElan)
+ {
+ PtDeallocateVElan(pVElan);
+ pVElan = NULL;
+ }
+ }
+ DBGPRINT(MUX_LOUD, ("<== PtCreateAndStartVElan: Adapter %p, VELAN Key %ws, VElan %p\n", pAdapt, pVElanKey->Buffer, pVElan));
+ return (pVElan);
+}
+
+
+VOID
+PtDeallocateVElan(
+ IN PVELAN pVElan
+ )
+/*++
+
+Routine Description:
+
+ Free up all resources allocated to a VELAN, and then the VELAN
+ structure itself.
+
+Arguments:
+
+ pVElan - Pointer to VELAN to be deallocated.
+
+Return Value:
+
+ None
+
+--*/
+{
+
+
+ NdisFreeSpinLock(&pVElan->Lock);
+ NdisFreeSpinLock(&pVElan->PauseLock);
+
+#ifdef IEEE_VLAN_SUPPORT
+ NdisDeleteNPagedLookasideList(&pVElan->TagLookaside);
+#endif
+
+ NdisFreeMemory(pVElan, 0, 0);
+}
+
+
+VOID
+PtStopVElan(
+ IN PVELAN pVElan
+)
+/*++
+
+Routine Description:
+
+ Stop a VELAN by requesting NDIS to halt the virtual miniport.
+ The caller has a reference on the VELAN, so it won't go away
+ while we are executing in this routine.
+
+ ASSUMPTION: this is only called in the context of unbinding
+ from the underlying miniport. If it may be called from elsewhere,
+ this should protect itself from re-entrancy.
+
+Arguments:
+
+ pVElan - Pointer to VELAN to be stopped.
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_HANDLE MiniportAdapterHandle;
+ BOOLEAN bMiniportInitCancelled = FALSE;
+
+ DBGPRINT(MUX_LOUD, ("==> PtStopVElan: VELAN %p, Adapt %p\n", pVElan, pVElan->pAdapt));
+
+ //
+ // We make blocking calls below.
+ //
+ ASSERT_AT_PASSIVE();
+
+ //
+ // If there was a queued request on this VELAN, fail it now.
+ //
+ NdisAcquireSpinLock(&pVElan->Lock);
+ ASSERT(pVElan->DeInitializing == TRUE);
+ if (pVElan->QueuedRequest)
+ {
+ pVElan->QueuedRequest = FALSE;
+ NdisReleaseSpinLock(&pVElan->Lock);
+
+ PtRequestComplete(pVElan->pAdapt,
+ &pVElan->Request.Request,
+ NDIS_STATUS_FAILURE);
+ }
+
+ else
+ {
+ NdisReleaseSpinLock(&pVElan->Lock);
+ }
+ //
+ // Check if we had called NdisIMInitializeDeviceInstanceEx and
+ // we are awaiting a call to MiniportInitialize.
+ //
+ if (pVElan->MiniportInitPending)
+ {
+ //
+ // Attempt to cancel miniport init.
+ //
+ Status = NdisIMCancelInitializeDeviceInstance(
+ DriverHandle,
+ &pVElan->CfgDeviceName);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Successfully cancelled IM initialization; our
+ // Miniport Init routine will not be called for this
+ // VELAN miniport.
+ //
+ pVElan->MiniportInitPending = FALSE;
+ ASSERT(pVElan->MiniportAdapterHandle == NULL);
+ bMiniportInitCancelled = TRUE;
+ }
+ else
+ {
+ //
+ // Our Miniport Initialize routine will be called
+ // (may be running on another thread at this time).
+ // Wait for it to finish.
+ //
+ NdisWaitEvent(&pVElan->MiniportInitEvent, 0);
+ ASSERT(pVElan->MiniportInitPending == FALSE);
+ }
+ }
+
+ //
+ // Check if Miniport Init has run. If so, deinitialize the virtual
+ // miniport. This will result in a call to our Miniport Halt routine,
+ // where the VELAN will be cleaned up.
+ //
+ MiniportAdapterHandle = pVElan->MiniportAdapterHandle;
+
+ if ((NULL != MiniportAdapterHandle) &&
+ (!pVElan->MiniportHalting))
+ {
+ //
+ // The miniport was initialized, and has not yet halted.
+ //
+ ASSERT(bMiniportInitCancelled == FALSE);
+ (VOID)NdisIMDeInitializeDeviceInstance(MiniportAdapterHandle);
+ }
+ else
+ {
+ if (bMiniportInitCancelled ||
+ ((MiniportAdapterHandle == NULL) && !pVElan->MiniportHalting))
+ {
+
+ //
+ // No NDIS events can come to this VELAN since it
+ // was never initialized as a miniport. We need to unlink
+ // it explicitly here.
+ //
+ PtUnlinkVElanFromAdapter(pVElan);
+ }
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PtStopVElan: VELAN %p, Adapt %p\n", pVElan, pVElan->pAdapt));
+}
+
+
+VOID
+PtUnlinkVElanFromAdapter(
+ IN PVELAN pVElan
+)
+/*++
+
+Routine Description:
+
+ Utility routine to unlink a VELAN from its parent ADAPT structure.
+
+Arguments:
+
+ pVElan - Pointer to VELAN to be unlinked.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = pVElan->pAdapt;
+ LOCK_STATE LockState;
+
+ DBGPRINT(MUX_LOUD, ("==> PtUnlinkVElanFromAdapter: VELAN %p, Adapt %p\n", pVElan, pAdapt));
+ ASSERT(pAdapt != NULL);
+
+
+ //
+ // Remove this VELAN from the global list
+ //
+
+ NdisAcquireSpinLock(&GlobalLock);
+ RemoveEntryList(&pVElan->GlobalLink);
+ NdisReleaseSpinLock(&GlobalLock);
+
+ //
+ // Remove this VELAN from the Adapter list
+ //
+ MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+
+ RemoveEntryList(&pVElan->Link);
+ pAdapt->VElanCount--;
+
+ MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+ pVElan->pAdapt = NULL;
+ PtDereferenceVElan(pVElan, (PUCHAR)"adapter");
+
+ PtDereferenceAdapter(pAdapt, (PUCHAR)"VElan");
+ DBGPRINT(MUX_LOUD, ("<== PtUnlinkVElanFromAdapter: VELAN %p, Adapt %p\n", pVElan, pAdapt));
+}
+
+
+PVELAN
+PtFindVElan(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING pVElanKey
+)
+/*++
+
+Routine Description:
+
+ Find an ELAN by bind name/key
+
+Arguments:
+
+ pAdapt - Pointer to an adapter struct.
+ pVElanKey - The VELAN's device name
+
+Return Value:
+
+ Pointer to matching VELAN or NULL if not found.
+
+--*/
+{
+ PLIST_ENTRY p;
+ PVELAN pVElan;
+ BOOLEAN Found;
+ NDIS_STRING VElanKeyName = {0, 0, NULL};
+ LOCK_STATE LockState;
+
+ ASSERT_AT_PASSIVE();
+
+ DBGPRINT(MUX_LOUD, ("==> PtFindElan: Adapter %p, ElanKey %ws\n", pAdapt,
+ pVElanKey->Buffer));
+
+ pVElan = NULL;
+ Found = FALSE;
+ VElanKeyName.Buffer = NULL;
+
+ do
+ {
+ //
+ // Make an up-cased copy of the given string.
+ //
+ VElanKeyName.Buffer = NdisAllocateMemoryWithTagPriority(pAdapt->BindingHandle,
+ pVElanKey->MaximumLength,
+ MUX_TAG,
+ LowPoolPriority);
+ if (VElanKeyName.Buffer == NULL)
+ {
+ break;
+ }
+
+ VElanKeyName.Length = pVElanKey->Length;
+ VElanKeyName.MaximumLength = pVElanKey->MaximumLength;
+
+ (VOID)NdisUpcaseUnicodeString(&VElanKeyName, pVElanKey);
+
+ //
+ // Go through all VELANs on the ADAPT structure, looking
+ // for a VELAN that has a matching device name.
+ //
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ p = pAdapt->VElanList.Flink;
+ while (p != &pAdapt->VElanList)
+ {
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+
+ if ((VElanKeyName.Length == pVElan->CfgDeviceName.Length) &&
+ (memcmp(VElanKeyName.Buffer, pVElan->CfgDeviceName.Buffer,
+ VElanKeyName.Length) == 0))
+ {
+ Found = TRUE;
+ break;
+ }
+
+ p = p->Flink;
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ }
+ while (FALSE);
+
+ if (!Found)
+ {
+ DBGPRINT(MUX_INFO, ( "FindElan: No match found!\n"));
+ pVElan = NULL;
+ }
+
+ if (VElanKeyName.Buffer)
+ {
+ NdisFreeMemory(VElanKeyName.Buffer, VElanKeyName.Length, 0);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PtFindElan: Adapter %p, ElanKey %ws, VElan %p\n", pAdapt,
+ pVElanKey->Buffer, pVElan));
+ return pVElan;
+}
+
+
+NDIS_STATUS
+PtBootStrapVElans(
+ IN PADAPT pAdapt,
+ IN PNDIS_STRING InstanceName OPTIONAL
+
+)
+/*++
+
+Routine Description:
+
+ Start up the VELANs configured for an adapter.
+
+Arguments:
+
+ pAdapt - Pointer to ATMLANE Adapter structure
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_HANDLE AdapterConfigHandle;
+ PNDIS_CONFIGURATION_PARAMETER Param;
+ NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
+ PWSTR buffer;
+ LOCK_STATE LockState;
+ NDIS_CONFIGURATION_OBJECT ConfigObject;
+
+ DBGPRINT(MUX_LOUD, ("==> PtBootStrapElans: adapter %p\n", pAdapt));
+ //
+ // Initialize.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ AdapterConfigHandle = NULL;
+
+ do
+ {
+ DBGPRINT(MUX_LOUD, ("PtBootStrapElans: Starting ELANs on adapter %p\n", pAdapt));
+
+ //
+ // Open the protocol configuration section for this adapter.
+ //
+ ConfigObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ ConfigObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ ConfigObject.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ ConfigObject.NdisHandle = pAdapt->BindingHandle;
+ ConfigObject.Flags = 0;
+
+ Status = NdisOpenConfigurationEx(
+ &ConfigObject,
+ &AdapterConfigHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AdapterConfigHandle = NULL;
+ DBGPRINT(MUX_ERROR, ("PtBootStrapElans: OpenProtocolConfiguration failed\n"));
+ Status = NDIS_STATUS_OPEN_FAILED;
+ break;
+ }
+
+ //
+ // Read the "UpperBindings" reserved key that contains a list
+ // of device names representing our miniport instances corresponding
+ // to this lower binding. The UpperBindings is a
+ // MULTI_SZ containing a list of device names. We will loop through
+ // this list and initialize the virtual miniports.
+ //
+ NdisReadConfiguration(&Status,
+ &Param,
+ AdapterConfigHandle,
+ &DeviceStr,
+ NdisParameterMultiString);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(MUX_ERROR, ("PtBootStrapElans: NdisReadConfiguration failed\n"));
+ break;
+ }
+
+ //
+ // Parse the Multi_sz string to extract the device name of each VELAN.
+ // This is used as the key name for the VELAN.
+ //
+ buffer = (PWSTR)Param->ParameterData.StringData.Buffer;
+ while(*buffer != L'\0')
+ {
+ NDIS_STRING DeviceName;
+
+ NdisInitUnicodeString(&DeviceName, buffer);
+
+ if (InstanceName != NULL)
+ {
+ if (NdisEqualString(&DeviceName, InstanceName, TRUE))
+ {
+ Status = PtCreateAndStartVElan(pAdapt, &DeviceName);
+ break;
+ }
+ }
+ else
+ {
+
+ Status = PtCreateAndStartVElan(pAdapt, &DeviceName);
+ }
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DBGPRINT(MUX_ERROR, ("PtBootStrapElans: CreateVElan failed\n"));
+ break;
+ }
+ buffer = (PWSTR)((PUCHAR)buffer + DeviceName.Length + sizeof(WCHAR));
+ };
+
+ } while (FALSE);
+
+ //
+ // Close config handles
+ //
+ if (NULL != AdapterConfigHandle)
+ {
+ NdisCloseConfiguration(AdapterConfigHandle);
+ }
+ //
+ // If the driver cannot create any velan for the adapter
+ //
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+ //
+ // No VElan is created for this adapter
+ //
+ if (pAdapt->VElanCount != 0)
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
+ }
+
+ DBGPRINT(MUX_LOUD, ("<== PtBootStrapElans: adapter %p, Status %8x\n", pAdapt, Status));
+
+ return Status;
+}
+
+VOID
+PtReferenceVElan(
+ IN PVELAN pVElan,
+ IN PUCHAR String
+ )
+/*++
+
+Routine Description:
+
+ Add a references to an Elan structure.
+
+Arguments:
+
+ pElan - Pointer to the Elan structure.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ NdisInterlockedIncrement((PLONG)&pVElan->RefCount);
+
+#if !DBG
+ UNREFERENCED_PARAMETER(String);
+#endif
+
+ DBGPRINT(MUX_LOUD, ("ReferenceElan: Elan %p (%s) new count %d\n",
+ pVElan, String, pVElan->RefCount));
+
+ return;
+}
+
+ULONG
+PtDereferenceVElan(
+ IN PVELAN pVElan,
+ IN PUCHAR String
+ )
+/*++
+
+Routine Description:
+
+ Subtract a reference from an VElan structure.
+ If the reference count becomes zero, deallocate it.
+
+Arguments:
+
+ pElan - Pointer to an VElan structure.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG rc;
+
+#if !DBG
+ UNREFERENCED_PARAMETER(String);
+#endif
+
+ ASSERT(pVElan->RefCount > 0);
+
+ rc = NdisInterlockedDecrement((PLONG)&pVElan->RefCount);
+
+ if (rc == 0)
+ {
+ //
+ // Free memory if there is no outstanding reference.
+ // Note: Length field is not required if the memory
+ // is allocated with NdisAllocateMemoryWithTagPriority.
+ //
+ PtDeallocateVElan(pVElan);
+ }
+
+ DBGPRINT(MUX_LOUD, ("DereferenceElan: VElan %p (%s) new count %d\n",
+ pVElan, String, rc));
+ return (rc);
+}
+
+
+BOOLEAN
+PtReferenceAdapter(
+ IN PADAPT pAdapt,
+ IN PUCHAR String
+ )
+/*++
+
+Routine Description:
+
+ Add a references to an Adapter structure.
+
+Arguments:
+
+ pAdapt - Pointer to the Adapter structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+#if !DBG
+ UNREFERENCED_PARAMETER(String);
+#endif
+
+ NdisInterlockedIncrement((PLONG)&pAdapt->RefCount);
+
+ DBGPRINT(MUX_LOUD, ("ReferenceAdapter: Adapter %p (%s) new count %d\n",
+ pAdapt, String, pAdapt->RefCount));
+
+ return TRUE;
+}
+
+ULONG
+PtDereferenceAdapter(
+ IN PADAPT pAdapt,
+ IN PUCHAR String
+ )
+/*++
+
+Routine Description:
+
+ Subtract a reference from an Adapter structure.
+ If the reference count becomes zero, deallocate it.
+
+Arguments:
+
+ pAdapt - Pointer to an adapter structure.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG rc;
+
+#if !DBG
+ UNREFERENCED_PARAMETER(String);
+#endif
+
+ ASSERT(pAdapt->RefCount > 0);
+
+
+ rc = NdisInterlockedDecrement ((PLONG)&pAdapt->RefCount);
+
+ if (rc == 0)
+ {
+ //
+ // Free memory if there is no outstanding reference.
+ // Note: Length field is not required if the memory
+ // is allocated with NdisAllocateMemoryWithTagPriority.
+ //
+ NdisFreeMemory(pAdapt, 0, 0);
+ }
+
+ DBGPRINT(MUX_LOUD, ("DereferenceAdapter: Adapter %p (%s) new count %d\n",
+ pAdapt, String, rc));
+
+ return (rc);
+}
+
+
+VOID
+PtReceiveNBL(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN ULONG NumberOfNetBufferLists,
+ IN ULONG ReceiveFlags
+ )
+/*++
+
+Routine Description:
+ ReceiveNetBufferList handler.
+
+Arguments:
+ ProtocolBindingContext Pointer to our PADAPT structure
+ NetBufferLists Net Buffer Lists received
+ PortNumber Port on which NBLS were received
+ NumberOfNetBufferLists Number of Net Buffer Lists
+ ReceiveFlags Flags associated with the receive
+
+Return Value:
+ None
+
+NOTE: This receive code path is not efficient, we will optimize it later.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ PVELAN pVElan = NULL;
+ PUCHAR pDstMac;
+ BOOLEAN bIsMulticast;
+ BOOLEAN bIsBroadcast;
+ PNET_BUFFER_LIST CurrentNetBufferList = NULL;
+ PNET_BUFFER_LIST ReturnNetBufferList = NULL;
+ PNET_BUFFER_LIST LastReturnNetBufferList = NULL;
+ LOCK_STATE LockState;
+ PLIST_ENTRY p;
+ ULONG ReturnFlags;
+ ULONG NewReceiveFlags;
+ UCHAR Data[6]={0,0,0,0,0,0};
+ //BOOLEAN DispatchLevel;
+ BOOLEAN bReturnNbl;
+
+#ifdef IEEE_VLAN_SUPPORT
+ NDIS_STATUS NdisStatus;
+ NDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo;
+ BOOLEAN bAllocatedContext;
+ PRECV_NBL_ENTRY RecvContext;
+#endif
+
+ UNREFERENCED_PARAMETER(NumberOfNetBufferLists);
+
+ DBGPRINT(MUX_VERY_LOUD,("==>PtReceiveNBL: ProtocolBindingContext %p, NetBufferLists %p\n",ProtocolBindingContext,NetBufferLists));
+
+ //DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
+
+ ReturnFlags = 0;
+
+ if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
+ {
+ NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
+ }
+
+ ASSERT(NetBufferLists != NULL);
+
+ // We could get receives in the interval between
+ // initiating a request to set the packet filter on
+ // the binding to 0 and completion of that request.
+ // Return immediately
+
+ if (pAdapt->PacketFilter == 0)
+ {
+ if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE)
+ {
+ NdisReturnNetBufferLists(pAdapt->BindingHandle,
+ NetBufferLists,
+ ReturnFlags);
+ }
+ return;
+ }
+
+ while (NetBufferLists != NULL)
+ {
+ CurrentNetBufferList = NetBufferLists;
+
+ NetBufferLists = NET_BUFFER_LIST_NEXT_NBL(NetBufferLists);
+
+ NET_BUFFER_LIST_NEXT_NBL(CurrentNetBufferList) = NULL;
+
+ bReturnNbl = TRUE;
+
+#ifdef IEEE_VLAN_SUPPORT
+ bAllocatedContext = FALSE;
+#endif
+
+ do
+ {
+ // Collect some information about the packet
+ pDstMac = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(CurrentNetBufferList),
+ 6,
+ (PVOID)Data,
+ 1,
+ 0);
+
+ if (pDstMac == NULL)
+ {
+ ASSERT(0);
+ break;
+ }
+
+ // Determine if the packet is broadcast or multicast
+
+ bIsMulticast = ETH_IS_MULTICAST(pDstMac);
+ bIsBroadcast = ETH_IS_BROADCAST(pDstMac);
+
+#ifdef IEEE_VLAN_SUPPORT
+ //
+ // Create Receive context to save information about tag
+ //
+ NdisStatus = NdisAllocateNetBufferListContext(CurrentNetBufferList,
+ sizeof(RECV_NBL_ENTRY),
+ 0,
+ MUX_TAG);
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ bAllocatedContext = TRUE;
+
+ RecvContext = (PRECV_NBL_ENTRY) NET_BUFFER_LIST_CONTEXT_DATA_START(CurrentNetBufferList);
+ NdisZeroMemory(RecvContext, sizeof(RECV_NBL_ENTRY));
+
+ //
+ // Strip off the VLAN Tag if present
+ //
+ if ((NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(CurrentNetBufferList))) < (ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE))
+ {
+ //
+ // If the VLAN tag is not present in the buffer, ignore this NBL
+ //
+ DBGPRINT(MUX_LOUD,("PtReceiveNBL: NBL %p size < VLAN_TAG_HEADER_SIZE\n",CurrentNetBufferList));
+ break;
+ }
+
+ if (NET_BUFFER_LIST_INFO(CurrentNetBufferList, Ieee8021QNetBufferListInfo) != 0)
+ {
+ //
+ // If the VLAN info is already in the NBL, take this information it
+ //
+ DBGPRINT(MUX_LOUD,("PtReceiveNBL: NBL %p already has Ieee8021QNetBufferListInfo\n",CurrentNetBufferList));
+
+ RtlCopyMemory((PVOID UNALIGNED) &NdisPacket8021qInfo, &NET_BUFFER_LIST_INFO(CurrentNetBufferList, Ieee8021QNetBufferListInfo),sizeof(NdisPacket8021qInfo));
+ }
+ else
+ {
+ NdisStatus = PtStripVlanTagNB(CurrentNetBufferList, &NdisPacket8021qInfo, RecvContext);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+#endif
+
+ // Lock down the VLAN list on the adapter so that no insertions
+ // deletions to this list happen while we loop through it. The packet
+ // filter will also not change during this time we hold the read lock.
+
+ MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
+
+ // Set up the ref count before we start indicating the packet
+
+ for (p = pAdapt->VElanList.Flink;
+ p != &pAdapt->VElanList;
+ p = p->Flink)
+ {
+ BOOLEAN bIndicateReceive;
+
+ pVElan = CONTAINING_RECORD(p, VELAN, Link);
+
+ // Should the packet be indicated up on this VELAN ?
+
+ bIndicateReceive = PtMatchPacketToVElan(pVElan,
+ pDstMac,
+ bIsMulticast,
+ bIsBroadcast);
+
+ if (!bIndicateReceive)
+ {
+ continue;
+ }
+
+ MUX_INCR_PENDING_RECEIVES(pVElan);
+
+ if ((pVElan->MiniportInitPending)
+ || (pVElan->MiniportHalting)
+ || (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
+ {
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+ continue;
+ }
+
+ NdisAcquireSpinLock(&pVElan->PauseLock);
+
+ if (!pVElan->Paused)
+ {
+ NdisReleaseSpinLock(&pVElan->PauseLock);
+
+#ifdef IEEE_VLAN_SUPPORT
+ NdisStatus = PtHandleReceiveTaggingNB(pVElan, CurrentNetBufferList, &NdisPacket8021qInfo);
+
+ if (NdisStatus != STATUS_SUCCESS)
+ {
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+ continue;
+ }
+#endif
+
+ MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
+
+ // Indicate to the protocol(s) bound to the Miniport
+ NewReceiveFlags = ReceiveFlags;
+
+ //
+ // Indicate with RESOURCES flag if it is not the last VELAN
+ // and NBLs were not indicated with RESOURCES flag to us.
+ //
+ if ((p->Flink != &pAdapt->VElanList) ||
+ (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) == TRUE))
+ {
+ NDIS_SET_RECEIVE_FLAG(NewReceiveFlags, NDIS_RECEIVE_FLAGS_RESOURCES);
+ }
+ else
+ {
+ bReturnNbl = FALSE;
+ }
+
+ NdisMIndicateReceiveNetBufferLists(pVElan->MiniportAdapterHandle,
+ CurrentNetBufferList,
+ PortNumber,
+ 1,
+ NewReceiveFlags);
+ //
+ // Decrement OutstandingReceives for the case where the NBL
+ // was indicated with RESOURCES flag. Otherwise it will be
+ // decremented in MPReturnNetBufferLists
+ //
+ if (bReturnNbl)
+ {
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+
+#ifdef IEEE_VLAN_SUPPORT
+ //
+ // If the buffer was advanced, retreat it
+ //
+ NdisStatus = PtRestoreReceiveNBL(CurrentNetBufferList);
+ ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
+#endif
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pVElan->PauseLock);
+ MUX_DECR_PENDING_RECEIVES(pVElan);
+ }
+
+ }
+
+ MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
+ }
+ while (FALSE);
+
+ if (bReturnNbl == TRUE)
+ {
+#ifdef IEEE_VLAN_SUPPORT
+ //
+ // Free the context only if we are returning the NBL here.
+ // Otherwise MPReturnNetBufferLists will free it.
+ //
+ if (bAllocatedContext)
+ {
+ NdisFreeNetBufferListContext(CurrentNetBufferList,
+ sizeof(RECV_NBL_ENTRY));
+ }
+#endif
+
+ //
+ // The NetBufferList is not pending with any upper protocol.
+ // Return the NetBufferList back to the miniport if the miniport
+ // gave us ownership of it
+ //
+ if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE)
+ {
+ if (ReturnNetBufferList == NULL)
+ {
+ ReturnNetBufferList = CurrentNetBufferList;
+ }
+ else
+ {
+ NET_BUFFER_LIST_NEXT_NBL(LastReturnNetBufferList) = CurrentNetBufferList;
+ }
+
+ LastReturnNetBufferList = CurrentNetBufferList;
+ NET_BUFFER_LIST_NEXT_NBL(LastReturnNetBufferList) = NULL;
+ }
+ else
+ {
+ //
+ // Restore the NetBufferList chain
+ //
+ NET_BUFFER_LIST_NEXT_NBL(CurrentNetBufferList) = NetBufferLists;
+ }
+ }
+ }
+
+ if (ReturnNetBufferList != NULL)
+ {
+ NdisReturnNetBufferLists(pAdapt->BindingHandle,
+ ReturnNetBufferList,
+ ReturnFlags);
+ }
+
+ DBGPRINT(MUX_VERY_LOUD,("<==PtReceiveNBL: ProtocolBindingContext %p, NetBufferLists %p\n",ProtocolBindingContext,NetBufferLists));
+}
+
+
+VOID
+PtSendNBLComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN ULONG SendCompleteFlags
+ )
+/*++
+
+Routine Description:
+ Called by NDIS when the miniport below has completed a send.
+ We complete the corresponding upper-edge send this represents.
+
+Arguments:
+ ProtocolBindingHandle Points to our PADAPT structure
+ NetBufferLists Packet being completed by the lower miniport
+ SendCompleteFlags Is the call at DispatchLevel
+
+Return Value:
+ None
+
+--*/
+{
+
+ PVELAN pVElan;
+ NDIS_STATUS Status;
+ PIM_NBL_ENTRY SendContext;
+ PNET_BUFFER_LIST CurrentNetBufferList;
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ BOOLEAN DispatchLevel = FALSE;
+#ifdef IEEE_VLAN_SUPPORT
+ PNET_BUFFER MdlAllocatedNetBuffers;
+ ULONG Flags = 0;
+#endif
+
+ DBGPRINT(MUX_VERY_LOUD,("==> PtSendNBLComplete: ProtocolBindingContext %p, NetBufferLists %p\n",
+ ProtocolBindingContext,NetBufferLists));
+
+ DispatchLevel = NDIS_TEST_SEND_COMPLETE_AT_DISPATCH_LEVEL(SendCompleteFlags);
+
+ while(NetBufferLists)
+ {
+ CurrentNetBufferList = NetBufferLists;
+ NetBufferLists = NET_BUFFER_LIST_NEXT_NBL(NetBufferLists);
+ NET_BUFFER_LIST_NEXT_NBL(CurrentNetBufferList) = NULL;
+
+ SendContext = (PIM_NBL_ENTRY)NET_BUFFER_LIST_CONTEXT_DATA_START(CurrentNetBufferList);
+
+ pVElan = SendContext->pVElan;
+
+ CurrentNetBufferList->SourceHandle = SendContext->PreviousSourceHandle;
+#ifdef IEEE_VLAN_SUPPORT
+ Flags = SendContext->Flags;
+ MdlAllocatedNetBuffers = SendContext->MdlAllocatedNetBuffers;
+#endif
+
+ Status = NET_BUFFER_LIST_STATUS(CurrentNetBufferList);
+
+ NdisFreeNetBufferListContext(CurrentNetBufferList,
+ sizeof(IM_NBL_ENTRY));
+
+#ifdef IEEE_VLAN_SUPPORT
+
+ if ((Flags & MUX_RETREAT_DATA) != 0)
+ {
+ MPRestoreSendNBL(pVElan,
+ CurrentNetBufferList,
+ NULL,
+ MdlAllocatedNetBuffers);
+ }
+
+#endif
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ MUX_INCR_STATISTICS64(&pVElan->GoodTransmits);
+ }
+ else
+ {
+ MUX_INCR_STATISTICS(&pVElan->TransmitFailuresOther);
+ }
+
+ NdisMSendNetBufferListsComplete(pVElan->MiniportAdapterHandle,
+ CurrentNetBufferList,
+ SendCompleteFlags);
+
+
+ MUX_DECR_PENDING_SENDS(pVElan);
+
+ MUX_ACQUIRE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+ pAdapt->OutstandingSends --;
+
+ if ((pAdapt->OutstandingSends == 0) && (pAdapt->PauseEvent != NULL))
+ {
+ NdisSetEvent(pAdapt->PauseEvent);
+ pAdapt->PauseEvent = NULL;
+ }
+ MUX_RELEASE_SPIN_LOCK(&pAdapt->Lock, DispatchLevel);
+
+
+ }
+
+ DBGPRINT(MUX_VERY_LOUD,("<== PtSendNBLComplete: ProtocolBindingContext %p, NetBufferLists %p\n",ProtocolBindingContext,NetBufferLists));
+}
+
+#ifdef IEEE_VLAN_SUPPORT
+NDIS_STATUS
+PtHandleReceiveTaggingNB(
+ IN PVELAN pVElan,
+ IN PNET_BUFFER_LIST NetBufferList,
+ IN PNDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo
+ )
+/*++
+
+Routine Description:
+
+ Parse a received Ethernet frame for 802.1Q tag information.
+ If a tag header is present, copy in relevant field values to
+ per-packet inforation to the new NET_BUFFER_LIST used
+ to indicate up this frame.
+
+Arguments:
+ pVElan Pointer to the VELAN structure
+ NetBufferList Pointer to the indicated packet from the lower miniport
+ NdisPacket8021qInfo 802.1Q tag information
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_ACCEPTED
+
+
+--*/
+{
+ PVOID pFrame = NULL;
+ PVOID pDst;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PRECV_NBL_ENTRY RecvContext;
+ PVOID Storage;
+ USHORT UNALIGNED * pTpid;
+
+
+ DBGPRINT(MUX_VERY_LOUD,("==> PtHandleReceiveTaggingNB: VElan %p, NetBufferList %p, NdisPacket8021qInfo %p\n",pVElan,NetBufferList, NdisPacket8021qInfo));
+ do
+ {
+ RecvContext = (PRECV_NBL_ENTRY) NET_BUFFER_LIST_CONTEXT_DATA_START(NetBufferList);
+ RecvContext->Flags = 0;
+
+ //
+ // If the vlan ID of the virtual miniport is 0, the miniport should
+ // act like it doesn't support VELAN tag processing
+ //
+ if (MuxRecognizedVlanId(pVElan,0))
+ break;
+
+ // Check if Tag header is present
+
+ if (NdisPacket8021qInfo->Value == 0)
+ {
+ break;
+ }
+
+ //
+ // If E-RIF present then discard header as we do not support
+ // this variation
+ //
+
+ if (NdisPacket8021qInfo->TagHeader.CanonicalFormatId != 0)
+ {
+ //
+ // Drop packet
+ //
+
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ MUX_INCR_STATISTICS(&pVElan->RcvFormatErrors);
+ break;
+ }
+
+ if ((NdisPacket8021qInfo->TagHeader.VlanId != 0)
+ && (!MuxRecognizedVlanId(pVElan, NdisPacket8021qInfo->TagHeader.VlanId)))
+ {
+ //
+ // Drop the packet
+ //
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+
+ MUX_INCR_STATISTICS(&pVElan->RcvVlanIdErrors);
+ break;
+ }
+ Storage=NULL;
+ pFrame = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(NetBufferList),
+ 2 * ETH_LENGTH_OF_ADDRESS + VLAN_TAG_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pFrame == NULL)
+ {
+ ASSERT(0);
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+ pTpid = (USHORT UNALIGNED *)((PUCHAR)pFrame + 2 * ETH_LENGTH_OF_ADDRESS);
+
+ //
+ //Strip header only if it's present in the packet
+ //
+ if (*pTpid == TPID)
+ {
+ RecvContext->Flags |= MUX_ADVANCE_DATA;
+
+ //
+ // Strip off header
+ //
+ pDst = (PVOID)((PUCHAR)pFrame + VLAN_TAG_HEADER_SIZE);
+
+ RtlMoveMemory(pDst, pFrame, 2 * ETH_LENGTH_OF_ADDRESS);
+
+ NET_BUFFER_LIST_INFO(NetBufferList, Ieee8021QNetBufferListInfo) = NdisPacket8021qInfo->Value;
+
+ NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(NetBufferList),
+ VLAN_TAG_HEADER_SIZE,
+ FALSE,
+ NULL);
+ }
+
+ } while(FALSE);
+
+ DBGPRINT(MUX_VERY_LOUD,("<== PtHandleReceiveTaggingNB: VElan %p, NetBufferList %p, NdisPacket8021qInfo %p, Status %8x\n",pVElan,NetBufferList, NdisPacket8021qInfo, Status));
+ return Status;
+}
+
+NDIS_STATUS
+PtStripVlanTagNB(
+ IN PNET_BUFFER_LIST NetBufferList,
+ OUT PNDIS_NET_BUFFER_LIST_8021Q_INFO NdisPacket8021qInfo,
+ OUT PRECV_NBL_ENTRY RecvContext
+ )
+/*++
+
+Routine Description:
+
+ Parse a received Ethernet frame for 802.1Q tag information.
+ If a tag header is present, copy in the output parameter
+
+Arguments:
+ NetBufferList Pointer to the indicated packet from the lower miniport
+ NdisPacket8021qInfo Pointer to the VLAN tag information
+ RecvContext Context for the received NBL
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+
+
+--*/
+{
+ VLAN_TAG_HEADER UNALIGNED * pTagHeader;
+ USHORT UNALIGNED * pTpid;
+ PVOID pFrame = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVOID Storage;
+
+
+ DBGPRINT(MUX_VERY_LOUD,("==> PtStripVlanTagNB: NetBufferList %p, NdisPacket8021qInfo %p\n",NetBufferList, NdisPacket8021qInfo));
+ do
+ {
+ NdisPacket8021qInfo->Value = NULL;
+ Storage=NULL;
+ pFrame = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(NetBufferList),
+ 2 * ETH_LENGTH_OF_ADDRESS + VLAN_TAG_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pFrame == NULL)
+ {
+ ASSERT(0);
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+ // Get at the Ethertype field
+
+ pTpid = (USHORT UNALIGNED *)((PUCHAR)pFrame + 2 * ETH_LENGTH_OF_ADDRESS);
+
+ // Check if Tag header is present
+
+ if (*pTpid != TPID)
+ {
+ break;
+ }
+
+ pTagHeader = (VLAN_TAG_HEADER UNALIGNED *)(pTpid + 1);
+
+ COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(*NdisPacket8021qInfo, pTagHeader);
+
+ RtlCopyMemory((PVOID UNALIGNED) &RecvContext->TagHeader, pTagHeader, 2);
+
+ } while(FALSE);
+
+ DBGPRINT(MUX_VERY_LOUD,("<== PtStripVlanTagNB: NetBufferList %p, NdisPacket8021qInfo %p, Status %8x\n",NetBufferList, NdisPacket8021qInfo, Status));
+ return Status;
+}
+
+NDIS_STATUS
+PtRestoreReceiveNBL(
+ IN PNET_BUFFER_LIST NetBufferList
+ )
+/*++
+
+Routine Description:
+
+ Restore the received NBL if the tag header was parsed
+
+Arguments:
+ NetBufferList Pointer to the indicated packet from the lower miniport
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+
+
+--*/
+{
+ PUCHAR pFrame = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PRECV_NBL_ENTRY ReceiveNblEntry;
+ USHORT Tpid;
+ PVOID Storage;
+
+ do
+ {
+ ReceiveNblEntry = (PRECV_NBL_ENTRY) NET_BUFFER_LIST_CONTEXT_DATA_START(NetBufferList);
+
+ //
+ // Check ifthe NBL was modified
+ //
+ if ((ReceiveNblEntry->Flags & MUX_ADVANCE_DATA) != MUX_ADVANCE_DATA)
+ {
+ break;
+ }
+
+ //
+ // Retreat the net buffer list
+ //
+ Status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(NetBufferList),
+ VLAN_TAG_HEADER_SIZE,
+ 0,
+ NULL);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Find the start address of the frame
+ //
+ Storage=NULL;
+ pFrame = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(NetBufferList),
+ 2 * ETH_LENGTH_OF_ADDRESS + VLAN_TAG_HEADER_SIZE,
+ Storage,
+ 1,
+ 0);
+
+ if (pFrame == NULL)
+ {
+ ASSERT(0);
+ Status = NDIS_STATUS_INVALID_PACKET;
+ break;
+ }
+
+ //
+ // Insert the VLAN tag to restore the received frame to the
+ // original state
+ //
+ Tpid = TPID;
+
+ NdisMoveMemory(pFrame, pFrame + VLAN_TAG_HEADER_SIZE, (2 * ETH_LENGTH_OF_ADDRESS));
+
+ NdisMoveMemory(pFrame + (2 * ETH_LENGTH_OF_ADDRESS), &Tpid, 2);
+
+ NdisMoveMemory(pFrame + (2 * ETH_LENGTH_OF_ADDRESS) + sizeof(Tpid), &ReceiveNblEntry->TagHeader, 2);
+
+ NET_BUFFER_LIST_INFO(NetBufferList, Ieee8021QNetBufferListInfo) = 0;
+ }
+ while (FALSE);
+
+ return Status;
+}
+
+#endif
+
+
+
diff --git a/network/ndis/mux/driver/60/public.h b/network/ndis/mux/driver/60/public.h
new file mode 100644
index 00000000..972939c7
--- /dev/null
+++ b/network/ndis/mux/driver/60/public.h
@@ -0,0 +1,46 @@
+/*++
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Author:
+
+
+Environment:
+
+ user and kernel
+Notes:
+
+
+Revision History:
+
+
+--*/
+#ifndef __PUBLIC_H
+#define __PUBLIC_H
+
+//
+// To support ioctls from user-mode:
+//
+
+#define GLOBAL_LINKNAME_STRING L"\\DosDevices\\Global\\Mux"
+#define NTDEVICE_STRING L"\\Device\\Mux"
+
+#define MUX_CUSTOM_EVENT 1
+
+#define NOTIFY_SIGNATURE 0xAFCDABAB
+
+typedef struct _NOTIFY_CUSTOM_EVENT {
+ ULONG uSignature;
+ ULONG uEvent;
+ WCHAR szMiniport[1];
+} NOTIFY_CUSTOM_EVENT, *PNOTIFY_CUSTOM_EVENT;
+#endif
+
diff --git a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj
new file mode 100644
index 00000000..83e3f351
--- /dev/null
+++ b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F277EC93-B131-4A8E-8899-C62F31AE70EC}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{22F44364-DB40-46E1-8E05-EBCB1DDEC8E5}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>muxvlan</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>muxvlan</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>muxvlan</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>muxvlan</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /GS</AdditionalOptions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);IEEE_VLAN_SUPPORT=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\miniport.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\mux.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\protocol.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="..\mux.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters
new file mode 100644
index 00000000..fad75bc6
--- /dev/null
+++ b/network/ndis/mux/driver/60/vlan/muxvlan.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{1AADD0B1-7A47-42D2-95E3-7F106683CF72}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{181362AF-397B-4B8F-A43F-8E9D2962680E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{1E01B05D-68A4-4A5F-B969-3B6FD90223DF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{966F89E0-3A82-4396-9FD3-3F8EB1BB58D9}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\miniport.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mux.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\protocol.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\mux.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/driver/60/vlan/precompsrc.c b/network/ndis/mux/driver/60/vlan/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/mux/driver/60/vlan/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/mux/mux.sln b/network/ndis/mux/mux.sln
new file mode 100644
index 00000000..47d46e28
--- /dev/null
+++ b/network/ndis/mux/mux.sln
@@ -0,0 +1,66 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vlan", "Vlan", "{54A94908-2C5F-4A7A-811A-853AE27B7850}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{0FCA78EE-A888-441E-A320-83951CF296AC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B3A64960-7B29-4262-9833-F1A493D5CCFC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Novlan", "Novlan", "{3D789463-134E-4028-BC7C-20B1BFA46278}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifyob", "Notifyob", "{DAE5645C-5ADF-4048-8010-39A47184E5C9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "muxvlan", "driver\60\vlan\muxvlan.vcxproj", "{F277EC93-B131-4A8E-8899-C62F31AE70EC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "driver\60\novlan\mux.vcxproj", "{3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mux", "notifyob\mux.vcxproj", "{CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|Win32.Build.0 = Debug|Win32
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|Win32.ActiveCfg = Release|Win32
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|Win32.Build.0 = Release|Win32
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|x64.ActiveCfg = Debug|x64
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Debug|x64.Build.0 = Debug|x64
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|x64.ActiveCfg = Release|x64
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC}.Release|x64.Build.0 = Release|x64
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|Win32.Build.0 = Debug|Win32
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|Win32.ActiveCfg = Release|Win32
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|Win32.Build.0 = Release|Win32
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|x64.ActiveCfg = Debug|x64
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Debug|x64.Build.0 = Debug|x64
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|x64.ActiveCfg = Release|x64
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789}.Release|x64.Build.0 = Release|x64
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|Win32.Build.0 = Debug|Win32
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|Win32.ActiveCfg = Release|Win32
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|Win32.Build.0 = Release|Win32
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|x64.ActiveCfg = Debug|x64
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Debug|x64.Build.0 = Debug|x64
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|x64.ActiveCfg = Release|x64
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F277EC93-B131-4A8E-8899-C62F31AE70EC} = {54A94908-2C5F-4A7A-811A-853AE27B7850}
+ {3316ED07-27E3-4AE6-BE12-E8A5F9ADE789} = {3D789463-134E-4028-BC7C-20B1BFA46278}
+ {CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6} = {DAE5645C-5ADF-4048-8010-39A47184E5C9}
+ {54A94908-2C5F-4A7A-811A-853AE27B7850} = {0FCA78EE-A888-441E-A320-83951CF296AC}
+ {0FCA78EE-A888-441E-A320-83951CF296AC} = {B3A64960-7B29-4262-9833-F1A493D5CCFC}
+ {3D789463-134E-4028-BC7C-20B1BFA46278} = {0FCA78EE-A888-441E-A320-83951CF296AC}
+ EndGlobalSection
+EndGlobal
diff --git a/network/ndis/mux/notifyob/adapter.cpp b/network/ndis/mux/notifyob/adapter.cpp
new file mode 100644
index 00000000..ea964c7a
--- /dev/null
+++ b/network/ndis/mux/notifyob/adapter.cpp
@@ -0,0 +1,965 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: A D A P T E R . C P P
+//
+// Contents: Physical adapter class definition.
+//
+// Notes:
+//
+// Author: Alok Sinha
+//
+//----------------------------------------------------------------------------
+
+#include "adapter.h"
+#include "common.h"
+
+#ifdef CUSTOM_EVENTS
+#include "public.h"
+#endif
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::CMuxPhysicalAdapter
+//
+// Purpose: Constructor for class CMuxPhysicalAdapter
+//
+// Arguments: None
+//
+// Returns:
+//
+// Notes:
+//
+
+CMuxPhysicalAdapter::CMuxPhysicalAdapter (INetCfg *pnc,
+ GUID *pguidAdapter)
+{
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::CMuxPhysicalAdapter(Constructor).\n" );
+
+ m_pnc = pnc;
+ m_pnc->AddRef();
+
+ CopyMemory( &m_guidAdapter,
+ pguidAdapter,
+ sizeof(GUID) );
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::CMuxPhysicalAdapter(Constructor).\n" );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::~CMuxPhysicalAdapter
+//
+// Purpose: Destructor for class CMuxPhysicalAdapter
+//
+// Arguments: None
+//
+// Returns:
+//
+// Notes:
+//
+
+CMuxPhysicalAdapter::~CMuxPhysicalAdapter (VOID)
+{
+ CMuxVirtualMiniport *pMiniport;
+ DWORD dwMiniportCount;
+ DWORD i;
+
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::~CMuxPhysicalAdapter(Destructor).\n" );
+
+ //
+ // Delete all the instances representing the virtual miniports.
+ // We are only deleting the class instances, not uninstalling the
+ // the virtual miniports.
+ //
+
+ dwMiniportCount = m_MiniportList.ListCount();
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportList.Remove( &pMiniport );
+ delete pMiniport;
+ }
+
+ dwMiniportCount = m_MiniportsToAdd.ListCount();
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportsToAdd.Remove( &pMiniport );
+ delete pMiniport;
+ }
+
+ dwMiniportCount = m_MiniportsToRemove.ListCount();
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportsToRemove.Remove( &pMiniport );
+ delete pMiniport;
+ }
+
+ ReleaseObj( m_pnc );
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::~CMuxPhysicalAdapter(Destructor).\n" );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::LoadConfiguration
+//
+// Purpose: Read the registry to get the device IDs of the
+// virtual miniports installed on the adapter and
+// crate an instance to represent each virtual miniport.
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxPhysicalAdapter::LoadConfiguration (VOID)
+{
+ HKEY hkeyAdapterGuid;
+ WCHAR szAdapterGuidKey[MAX_PATH+1];
+ WCHAR szAdapterGuid[MAX_PATH+1];
+ LPWSTR lpMiniportList;
+ LPWSTR lpMiniport;
+ LPWSTR lpMiniportGuid;
+ DWORD dwDisp;
+ CMuxVirtualMiniport *pMiniport;
+ GUID guidMiniport;
+ DWORD dwBytes;
+ LONG lResult;
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::LoadConfiguration.\n" );
+
+ //
+ // Build the registry key using the adapter guid under which
+ // device IDs of the virtual miniports are stored.
+ //
+
+ StringFromGUID2( m_guidAdapter,
+ szAdapterGuid,
+ MAX_PATH+1 );
+
+ StringCchPrintfW ( szAdapterGuidKey,
+ celems(szAdapterGuidKey),
+ L"%s\\%s",
+ c_szAdapterList,
+ szAdapterGuid );
+
+ szAdapterGuidKey[MAX_PATH]='\0';
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ szAdapterGuidKey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterGuid,
+ &dwDisp);
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ //
+ // If dwDisp indicates that a new key is created then, we know there
+ // is no virtual miniport currently listed underneath and we simply
+ // return.
+ //
+
+ if ( dwDisp != REG_CREATED_NEW_KEY ) {
+
+ dwBytes = 0;
+ lResult = RegQueryValueExW(
+ hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ NULL,
+ &dwBytes );
+ if(lResult != ERROR_SUCCESS){
+ // you may do something
+ }
+
+
+
+ //alloc lpMiniportList with dwBytes elements and initialzes each to be 0
+ lpMiniportList = (LPWSTR)calloc( dwBytes, 1 );
+
+ if ( lpMiniportList != NULL ) {
+
+ lResult = RegQueryValueExW(
+ hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ (LPBYTE)lpMiniportList,
+ &dwBytes );
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ lpMiniport = lpMiniportList;
+
+
+#ifndef PASSTHRU_NOTIFY
+
+ //
+ // In case of mux, c_szUpperBindings is a REG_MULTI_SZ string.
+ //
+
+ lpMiniport[dwBytes-1] = '\0';
+ while ( wcslen(lpMiniport) ) {
+
+ lpMiniportGuid = RemoveDevicePrefix( lpMiniport );
+
+ TraceMsg( L" Loading configuration for miniport %s...\n",
+ lpMiniportGuid );
+
+ if ( lpMiniportGuid != NULL ) {
+
+ CLSIDFromString( lpMiniportGuid,
+ &guidMiniport );
+
+ //
+ // Create an instance representing the virtual miniport.
+ //
+
+ #pragma prefast(suppress:8197, "The instance is freed in the destructor")
+ pMiniport = new CMuxVirtualMiniport( m_pnc,
+ &guidMiniport,
+ &m_guidAdapter );
+
+ if ( pMiniport ) {
+
+ //
+ // Load any miniport specific configuration.
+ //
+
+ pMiniport->LoadConfiguration();
+
+ //
+ // Save the miniport instance in a list.
+ //
+
+ m_MiniportList.Insert( pMiniport,
+ guidMiniport );
+
+ }
+
+ free( lpMiniportGuid );
+ }
+
+ //
+ // Get next miniport guid.
+ //
+
+ lpMiniport += wcslen(lpMiniport) + 1;
+ }
+
+#else
+
+ //
+ // In case of the passthru driver, c_szUpperBindings is
+ // a reg_sz string.
+ //
+
+ lpMiniportGuid = RemoveDevicePrefix( lpMiniport );
+
+ TraceMsg( L" Loading configuration for miniport %s...\n",
+ lpMiniportGuid );
+
+ if ( lpMiniportGuid ) {
+
+ CLSIDFromString( lpMiniportGuid,
+ &guidMiniport );
+
+ //
+ // Create an instance representing the virtual miniport.
+ //
+
+ pMiniport = new CMuxVirtualMiniport( m_pnc,
+ &guidMiniport,
+ &m_guidAdapter );
+
+ if ( pMiniport ) {
+
+ //
+ // Load any miniport specific configuration.
+ //
+
+ pMiniport->LoadConfiguration();
+
+ //
+ // Save the miniport instance in a list.
+ //
+
+ m_MiniportList.Insert( pMiniport,
+ guidMiniport );
+ }
+
+ free( lpMiniportGuid );
+ }
+#endif
+ }
+ else {
+ TraceMsg( L" Failed to read the registry value: %s.\n",
+ c_szUpperBindings );
+ }
+
+ free( lpMiniportList );
+ }
+ else {
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ RegCloseKey( hkeyAdapterGuid );
+ }
+ else {
+
+ TraceMsg( L" Failed to open the registry key: %s.\n",
+ szAdapterGuidKey );
+ }
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::LoadConfiguration(HRESULT = %x).\n",
+ HRESULT_FROM_WIN32(lResult) );
+
+ return HRESULT_FROM_WIN32(lResult);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::GetAdapterGUID
+//
+// Purpose: Returns the adapter GUID.
+//
+// Arguments:
+// OUT pguidAdapter: GUID of the adapter returned.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID CMuxPhysicalAdapter::GetAdapterGUID (GUID *pguidAdapter)
+{
+ TraceMsg( L"-->CMuxPhysicalAdapter::GetAdapterGUID.\n" );
+
+ CopyMemory( pguidAdapter,
+ &m_guidAdapter,
+ sizeof(GUID) );
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::GetAdapterGUID.\n" );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::AddMiniport
+//
+// Purpose: Puts the miniport instance into the list of newly added miniports.
+//
+// Arguments:
+// IN pMiniport: A newly create miniport instance.
+//
+// Returns: S_OK on success, otherwize and error code.
+//
+// Notes:
+//
+
+HRESULT CMuxPhysicalAdapter::AddMiniport (CMuxVirtualMiniport *pMiniport)
+{
+ GUID guidMiniport;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::AddMiniport.\n" );
+
+ pMiniport->GetMiniportGUID( &guidMiniport );
+
+ hr = m_MiniportsToAdd.Insert( pMiniport,
+ guidMiniport );
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::AddMiniport(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::RemoveMiniport
+//
+// Purpose: Remove a specified miniport instance from the list and
+// uninstalls the corresponding virtual miniport.
+//
+// Arguments:
+// IN pguidMiniportToRemove: GUID of the miniport to be removed
+// and uninstalled. If it is NULL then,
+// the first miniport instance is removed.
+//
+// Returns: S_OK on success, otherwize and error code.
+//
+// Notes:
+//
+
+HRESULT CMuxPhysicalAdapter::RemoveMiniport (GUID *pguidMiniportToRemove)
+{
+ CMuxVirtualMiniport *pMiniport;
+ GUID guidMiniport;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::RemoveMiniport.\n" );
+
+ //
+ // If miniport GUID specified then, delete that one.
+ //
+
+ if ( pguidMiniportToRemove ) {
+
+ hr = m_MiniportList.RemoveByKey( *pguidMiniportToRemove,
+ &pMiniport );
+ }
+ else {
+
+ //
+ // No GUID specified, so we just delete the first one.
+ //
+
+ hr = m_MiniportList.Remove( &pMiniport );
+ }
+
+ if ( hr == S_OK ) {
+
+ pMiniport->GetMiniportGUID( &guidMiniport );
+
+ m_MiniportsToRemove.Insert( pMiniport,
+ guidMiniport );
+ pMiniport->DeInstall();
+ }
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::RemoveMiniport(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::Remove
+//
+// Purpose: Uninstall all the instances of virtual miniports.
+//
+// Arguments: None
+//
+// Returns: S_OK.
+//
+// Notes:
+//
+
+HRESULT CMuxPhysicalAdapter::Remove (VOID)
+{
+ CMuxVirtualMiniport *pMiniport = NULL;
+ GUID guidMiniport;
+ DWORD dwMiniportCount;
+ DWORD i;
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::Remove.\n" );
+
+ dwMiniportCount = m_MiniportList.ListCount();
+
+ TraceMsg ( L" Removing %d miniports.\n",
+ dwMiniportCount );
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportList.Remove( &pMiniport );
+ pMiniport->GetMiniportGUID( &guidMiniport );
+ m_MiniportsToRemove.Insert( pMiniport,
+ guidMiniport );
+ pMiniport->DeInstall();
+ }
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::Remove(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::ApplyRegistryChanges
+//
+// Purpose: Update the registry depending on the actions performed.
+//
+// Arguments:
+// IN eApplyAction: Action that was last performed.
+//
+//
+// Returns: S_OK.
+//
+// Notes:
+// More than one action could have been performed by the user
+// but this function is called only once at the end. So, the argument
+// only denotes the very last action performed. For example, if the
+// user deletes one miniport and adds two miniports then, the argument
+// will denote an add action.
+//
+
+HRESULT CMuxPhysicalAdapter::ApplyRegistryChanges (ConfigAction eApplyAction)
+{
+ HKEY hkeyAdapterList;
+ HKEY hkeyAdapterGuid;
+ WCHAR szAdapterGuid[MAX_PATH+1];
+ CMuxVirtualMiniport *pMiniport = NULL;
+ DWORD dwMiniportCount;
+ DWORD dwDisp;
+ DWORD i;
+ LONG lResult;
+ HRESULT hr;
+
+
+ TraceMsg( L"-->CMuxPhysicalAdapter::ApplyRegistryChanges.\n" );
+
+ //
+ // Open/create and then close the registry key to ensure that it does exist.
+ //
+
+ StringFromGUID2( m_guidAdapter,
+ szAdapterGuid,
+ MAX_PATH+1 );
+
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ c_szAdapterList,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterList,
+ &dwDisp);
+
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ lResult = RegCreateKeyExW( hkeyAdapterList,
+ szAdapterGuid,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterGuid,
+ &dwDisp);
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ RegCloseKey( hkeyAdapterGuid );
+ }
+ else {
+ TraceMsg( L" Failed to create/open the registry key: %s\\%s.\n",
+ c_szAdapterList, szAdapterGuid );
+ }
+
+ RegCloseKey( hkeyAdapterList );
+ }
+ else {
+
+ TraceMsg( L" Failed to open the registry key: %s.\n",
+ c_szAdapterList );
+ }
+
+ //
+ // Update the registry in case there were new miniports installed.
+ //
+
+ hr = HRESULT_FROM_WIN32( lResult );
+ if( hr != S_OK){
+ // you may do something
+ }
+
+ dwMiniportCount = m_MiniportsToAdd.ListCount();
+
+ TraceMsg( L" Applying registry changes when %d miniports added.\n",
+ dwMiniportCount );
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ m_MiniportsToAdd.Find( i,
+ &pMiniport );
+
+ //
+ // Do virtual miniport specific registry changes.
+ //
+ // We need to tell the miniport instance explicitly what the action
+ // is.
+ //
+
+ hr = pMiniport->ApplyRegistryChanges( eActAdd );
+
+ if ( hr != S_OK ) {
+
+ TraceMsg( L" Failed to apply registry changes to miniport(%d).\n",
+ i );
+
+ }
+ }
+
+
+
+ //
+ // Update the registry in case one or more miniports were uninstalled.
+ //
+
+ dwMiniportCount = m_MiniportsToRemove.ListCount();
+
+ TraceMsg( L" Applying registry changes when %d miniports removed.\n",
+ dwMiniportCount );
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ m_MiniportsToRemove.Find( i,
+ &pMiniport );
+
+ //
+ // Do virtual miniport specific registry changes.
+ //
+ // We need to tell the miniport instance explicitly what the action
+ // is.
+ //
+
+ hr = pMiniport->ApplyRegistryChanges( eActRemove );
+
+ if ( hr != S_OK ) {
+
+ TraceMsg( L" Failed to apply registry changes to miniport(%d).\n",
+ i );
+
+ }
+ }
+
+ //
+ // If the adapter is being removed or the protocol is being uninstalled,
+ // delete the adatper registry key.
+ //
+
+ if ( eApplyAction == eActRemove ) {
+
+ //
+ // Delete the adapter key.
+ //
+
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ c_szAdapterList,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterList,
+ &dwDisp);
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ TraceMsg( L" Deleting the registry key: %s.\n", szAdapterGuid );
+
+ RegDeleteKeyW( hkeyAdapterList, szAdapterGuid );
+ RegCloseKey ( hkeyAdapterList );
+ }
+ }
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::ApplyRegistryChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::ApplyPnpChanges
+//
+// Purpose: Apply the PnP changes depending on the actions performed.
+//
+// Arguments:
+// IN pfCallback : SendPnpConfig Callback interface.
+// IN eApplyAction: Action that was last performed.
+//
+//
+// Returns: S_OK.
+//
+// Notes:
+// More than one action could have been performed by the user
+// but this function is called only once at the end. So, the argument
+// only denotes the very last action performed. For example, if the
+// user deletes one miniport and adds two miniports then, the argument
+// will denote an add action.
+//
+
+HRESULT CMuxPhysicalAdapter::ApplyPnpChanges(
+ INetCfgPnpReconfigCallback *pfCallback,
+ ConfigAction eApplyAction)
+{
+ CMuxVirtualMiniport *pMiniport = NULL;
+ GUID guidMiniport;
+ DWORD dwMiniportCount;
+ DWORD i;
+ HRESULT hr;
+
+#ifdef CUSTOM_EVENTS
+ LPWSTR lpDevice;
+ WCHAR szMiniportGuid[MAX_PATH+1];
+ DWORD dwBytes;
+ INetCfgComponent *pncc;
+ LPWSTR lpszBindName;
+ PNOTIFY_CUSTOM_EVENT lppnpEvent;
+#endif
+
+ UNREFERENCED_PARAMETER(eApplyAction);
+ TraceMsg( L"-->CMuxPhysicalAdapter::ApplyPnpChanges.\n" );
+
+#ifdef CUSTOM_EVENTS
+
+ //
+ // Find the instance of the adapter to get its bindname.
+ //
+
+ hr = HrFindInstance( m_pnc,
+ m_guidAdapter,
+ &pncc );
+
+ if ( hr == S_OK ) {
+
+ hr = pncc->GetBindName( &lpszBindName );
+
+ if ( hr != S_OK ) {
+ TraceMsg( L" GetBindName failed.(HRESULT = %x). PnP changes will not "
+ L"be applied and the driver will not be notified.\n",
+ hr );
+ }
+
+ ReleaseObj( pncc );
+ }
+ else {
+ TraceMsg( L" PnP changes will not "
+ L"be applied and the driver will not be notified.\n",
+ hr );
+ }
+
+#endif
+
+ dwMiniportCount = m_MiniportsToAdd.ListCount();
+
+ TraceMsg( L" Applying PnP changes to %d new miniports.\n",
+ dwMiniportCount );
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportsToAdd.Remove( &pMiniport );
+
+ pMiniport->GetMiniportGUID( &guidMiniport );
+
+ m_MiniportList.Insert( pMiniport,
+ guidMiniport );
+
+ //
+ // Do miniport specific Pnp Changes when they are added.
+ //
+
+ hr = pMiniport->ApplyPnpChanges( pfCallback,
+ eActAdd );
+ if( hr != S_OK){
+ // you may do something
+ }
+
+#ifdef CUSTOM_EVENTS
+
+
+ //
+ // Notify the driver that one or more virtual miniports have been added.
+ //
+
+ StringFromGUID2( guidMiniport,
+ szMiniportGuid,
+ MAX_PATH+1 );
+ lpDevice = AddDevicePrefix( szMiniportGuid );
+
+ if ( lpDevice ) {
+
+ dwBytes = sizeof(NOTIFY_CUSTOM_EVENT) +
+ ((wcslen(lpDevice) + 1) * sizeof(WCHAR));
+
+ lppnpEvent = (PNOTIFY_CUSTOM_EVENT)malloc( dwBytes );
+
+ if ( lppnpEvent ) {
+
+ lppnpEvent->uSignature = NOTIFY_SIGNATURE;
+ lppnpEvent->uEvent = MUX_CUSTOM_EVENT;
+ wcscpy( lppnpEvent->szMiniport,
+ lpDevice );
+
+ hr = pfCallback->SendPnpReconfig( NCRL_NDIS,
+ c_szMuxService,
+ lpszBindName,
+ (PVOID)lppnpEvent,
+ dwBytes );
+
+ TraceMsg( L" INetCfgPnpReconfigCallback->SendPnpReconfig returned "
+ L"%#x.\n",
+ hr );
+
+ if ( hr != S_OK ) {
+
+ TraceMsg( L" Failed to apply Pnp changes, miniport(%d).\n",
+ i );
+
+ }
+
+ free( lppnpEvent );
+ }
+ free( lpDevice );
+ }
+#endif
+ }
+
+ dwMiniportCount = m_MiniportsToRemove.ListCount();
+
+ TraceMsg( L" Applying PnP changes to %d removed miniports.\n",
+ dwMiniportCount );
+
+ for (i=0; i < dwMiniportCount; ++i) {
+
+ pMiniport = NULL;
+ m_MiniportsToRemove.Remove( &pMiniport );
+
+ pMiniport->GetMiniportGUID( &guidMiniport );
+
+ //
+ // Do miniport specific Pnp Changes when they are uninstalled.
+ //
+
+ hr = pMiniport->ApplyPnpChanges( pfCallback,
+ eActRemove );
+ if( hr != S_OK){
+ // you may do something
+ }
+
+ delete pMiniport;
+
+#ifdef CUSTOM_EVENTS
+
+ //
+ // Notify the driver that one or more virtual miniports have been
+ // uninstalled.
+ //
+ // We can't notify the driver in case the adapter or the protocol is
+ // being uninstalled because the binding handle doesn't exist.
+ //
+
+ if ( eApplyAction != eActRemove ) {
+
+ StringFromGUID2( guidMiniport,
+ szMiniportGuid,
+ MAX_PATH+1 );
+ lpDevice = AddDevicePrefix( szMiniportGuid );
+
+ if ( lpDevice ) {
+
+ dwBytes = sizeof(NOTIFY_CUSTOM_EVENT) +
+ ((wcslen(lpDevice) + 1) * sizeof(WCHAR));
+
+ lppnpEvent = (PNOTIFY_CUSTOM_EVENT)malloc( dwBytes );
+
+ if ( lppnpEvent ) {
+
+ lppnpEvent->uSignature = NOTIFY_SIGNATURE;
+ lppnpEvent->uEvent = MUX_CUSTOM_EVENT;
+ wcscpy( lppnpEvent->szMiniport,
+ lpDevice );
+
+ hr = pfCallback->SendPnpReconfig( NCRL_NDIS,
+ c_szMuxService,
+ lpszBindName,
+ (PVOID)lppnpEvent,
+ dwBytes );
+ TraceMsg( L" INetCfgPnpReconfigCallback->SendPnpReconfig returned "
+ L"%#x.\n",
+ hr );
+
+ if ( hr != S_OK ) {
+
+ TraceMsg( L" Failed to apply Pnp changes, miniport(%d).\n",
+ i );
+
+ }
+
+ free( lppnpEvent );
+ }
+
+ free( lpDevice );
+ }
+ }
+#endif
+
+ }
+
+#ifdef CUSTOM_EVENTS
+ CoTaskMemFree( lpszBindName );
+#endif
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::ApplyPnpChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::CancelChanges
+//
+// Purpose: Cancel any changes made.
+//
+// Arguments: None
+//
+//
+// Returns: S_OK.
+//
+// Notes:
+//
+
+HRESULT CMuxPhysicalAdapter::CancelChanges (VOID)
+{
+ TraceMsg( L"-->CMuxPhysicalAdapter::CancelChanges.\n" );
+
+ TraceMsg( L"<--CMuxPhysicalAdapter::CancelChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxPhysicalAdapter::AllMiniportsRemoved
+//
+// Purpose: Find out if there is no miniport installed on the adapter.
+//
+// Arguments: None
+//
+//
+// Returns: TRUE if all the miniports associated with this adapter have been
+// uninstalled and there is none pending to be added, otherwise FALSE.
+//
+// Notes:
+//
+
+BOOL CMuxPhysicalAdapter::AllMiniportsRemoved (VOID)
+{
+ return (m_MiniportList.ListCount() + m_MiniportsToAdd.ListCount()) == 0;
+}
diff --git a/network/ndis/mux/notifyob/adapter.h b/network/ndis/mux/notifyob/adapter.h
new file mode 100644
index 00000000..9bf5614f
--- /dev/null
+++ b/network/ndis/mux/notifyob/adapter.h
@@ -0,0 +1,99 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: A D A P T E R . H
+//
+// Contents: Header file for physical adapter class.
+//
+// Notes:
+//
+// Author: Alok Sinha 31-Oct-2000
+//
+//----------------------------------------------------------------------------
+
+#ifndef ADAPTER_H_INCLUDED
+
+#define ADAPTER_H_INCLUDED
+
+#include <windows.h>
+#include <netcfgn.h>
+
+#include "common.h"
+#include "virtual.h"
+#include "list.h"
+
+//
+// Class to represent a physical adapter.
+//
+
+class CMuxPhysicalAdapter
+{
+ //
+ // Private member variables.
+ //
+
+ GUID m_guidAdapter;
+
+ INetCfg *m_pnc;
+
+ //
+ // List of virtual miniports associated with the adapter.
+ //
+
+ List<CMuxVirtualMiniport *, GUID> m_MiniportList;
+
+ //
+ // List of virtual miniports to be added.
+ //
+
+ List<CMuxVirtualMiniport *, GUID> m_MiniportsToAdd;
+
+ //
+ // List of virtual miniports to be removed.
+ //
+
+ List<CMuxVirtualMiniport *, GUID> m_MiniportsToRemove;
+
+ //
+ // Private member functions.
+ //
+
+ public:
+
+ //
+ // Public member functions
+ //
+
+ CMuxPhysicalAdapter (INetCfg *pnc,
+ GUID *guidAdapter);
+
+ virtual ~CMuxPhysicalAdapter (VOID);
+
+ HRESULT LoadConfiguration (VOID);
+
+ VOID GetAdapterGUID (GUID *guidAdapter);
+
+ HRESULT AddMiniport (CMuxVirtualMiniport *pNewMiniport);
+
+ HRESULT RemoveMiniport (GUID *pguidMiniport);
+
+ HRESULT Remove (VOID);
+
+ HRESULT ApplyRegistryChanges (ConfigAction eApplyAction);
+
+ HRESULT ApplyPnpChanges (INetCfgPnpReconfigCallback *pfCallback,
+ ConfigAction eApplyAction);
+
+ HRESULT CancelChanges (VOID);
+
+ DWORD MiniportCount (VOID) { return m_MiniportList.ListCount(); }
+
+ DWORD MiniportAddCount (VOID) { return m_MiniportsToAdd.ListCount(); }
+
+ BOOL AllMiniportsRemoved (VOID);
+};
+
+
+#endif // ADAPTER_H_INCLUDED
diff --git a/network/ndis/mux/notifyob/common.cpp b/network/ndis/mux/notifyob/common.cpp
new file mode 100644
index 00000000..24c7b486
--- /dev/null
+++ b/network/ndis/mux/notifyob/common.cpp
@@ -0,0 +1,624 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: COMMON.CPP
+//
+// Contents: Debug & Utility functions
+//
+// Notes:
+//
+// Author: Alok Sinha
+//
+//----------------------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <netcfgn.h>
+#include "common.h"
+
+#ifdef DBG
+
+void
+TraceMsg (
+ _In_ LPWSTR szFormat,
+ ...)
+{
+ static WCHAR szTempBuf[4096];
+
+ va_list arglist;
+
+ va_start(arglist, szFormat);
+
+ StringCchVPrintfW ( szTempBuf,
+ celems(szTempBuf),
+ szFormat,
+ arglist );
+
+ OutputDebugStringW( szTempBuf );
+
+ va_end(arglist);
+}
+
+void DumpChangeFlag (DWORD dwChangeFlag)
+{
+ TraceMsg( L" ChangeFlag:" );
+
+ if ( dwChangeFlag & NCN_ADD ) {
+ TraceMsg( L" NCN_ADD" );
+ }
+
+ if ( dwChangeFlag & NCN_REMOVE ) {
+ TraceMsg( L" NCN_REMOVE" );
+ }
+
+ if ( dwChangeFlag & NCN_UPDATE ) {
+ TraceMsg( L" NCN_UPDATE" );
+ }
+
+ if ( dwChangeFlag & NCN_ENABLE ) {
+ TraceMsg( L" NCN_ENABLE" );
+ }
+
+ if ( dwChangeFlag & NCN_DISABLE ) {
+ TraceMsg( L" NCN_DISABLE" );
+ }
+
+ if ( dwChangeFlag & NCN_BINDING_PATH ) {
+ TraceMsg( L" NCN_BINDING_PATH" );
+ }
+
+ if ( dwChangeFlag & NCN_PROPERTYCHANGE ) {
+ TraceMsg( L" NCN_PROPERTYCHANGE" );
+ }
+
+ if ( dwChangeFlag & NCN_NET ) {
+ TraceMsg( L" NCN_NET" );
+ }
+
+ if ( dwChangeFlag & NCN_NETTRANS ) {
+ TraceMsg( L" NCN_NETTRANS" );
+ }
+
+ if ( dwChangeFlag & NCN_NETCLIENT ) {
+ TraceMsg( L" NCN_NETCLIENT" );
+ }
+
+ if ( dwChangeFlag & NCN_NETSERVICE ) {
+ TraceMsg( L" NCN_NETSERVICE" );
+ }
+
+ TraceMsg( L"\n" );
+ return;
+}
+
+void DumpBindingPath (INetCfgBindingPath *pncbp)
+{
+ LPWSTR lpsz;
+ HRESULT hr;
+
+#ifdef VERBOSE_TRACE
+ INetCfgComponent *pncc;
+ IEnumNetCfgBindingInterface *pencbi;
+ INetCfgBindingInterface *pncbi;
+ DWORD dwIndex;
+ ULONG ulCount;
+#endif
+
+ hr = pncbp->GetPathToken( &lpsz );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" BindingPath: %s\n",
+ lpsz );
+
+ CoTaskMemFree( lpsz );
+ }
+ else {
+
+ TraceMsg( L" BindingPath: GetPathToken failed(HRESULT %x).\n",
+ hr );
+ }
+
+#ifdef VERBOSE_TRACE
+
+ hr = pncbp->EnumBindingInterfaces( &pencbi );
+
+ if ( hr == S_OK ) {
+
+ hr = pencbi ->Next( 1, &pncbi, &ulCount );
+
+ for (dwIndex=0; hr == S_OK; dwIndex++ ) {
+
+ hr = pncbi->GetName( &lpsz );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" BindingInterface(%d): %s\n",
+ dwIndex, lpsz );
+
+ CoTaskMemFree( lpsz );
+ }
+ else {
+
+ TraceMsg( L" BindingInterface(%d): GetName failed(HRESULT %x).\n",
+ dwIndex, hr );
+ }
+
+ hr = pncbi->GetUpperComponent( &pncc );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \tUpperComponent of the interface(%d)...\n",
+ dwIndex );
+
+ DumpComponent( pncc );
+
+ ReleaseObj( pncc );
+ }
+ else {
+
+ TraceMsg( L" UpperComponent: GetUpperComponent failed(HRESULT = %x).\n",
+ hr );
+ }
+ hr = pncbi->GetLowerComponent( &pncc );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \tLowerComponent of the interface(%d)...\n",
+ dwIndex );
+ DumpComponent( pncc );
+
+ ReleaseObj( pncc );
+ }
+ else {
+
+ TraceMsg( L" LowerComponent: GetLowerComponent failed(HRESULT = %x).\n",
+ hr );
+ }
+
+ ReleaseObj( pncbi );
+
+ hr = pencbi ->Next( 1,
+ &pncbi,
+ &ulCount );
+ }
+
+ ReleaseObj( pencbi );
+ }
+ else {
+
+ TraceMsg( L" EnumBindingInterfaces failed, (HRESULT = %x)\n",
+ hr );
+ }
+#endif
+ return;
+}
+
+void DumpComponent (INetCfgComponent *pncc)
+{
+ LPWSTR lpsz;
+ DWORD dwChars;
+ ULONG ulStatus;
+ HRESULT hr;
+ hr = pncc->GetDisplayName( &lpsz );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \t\tComponent: %s\n",
+ lpsz );
+
+ CoTaskMemFree( lpsz );
+ }
+ else {
+
+ TraceMsg( L" GetDisplay failed(HRESULT %x).\n",
+ hr );
+ }
+
+ hr = pncc->GetCharacteristics( &dwChars );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \t\tCharacteristics:" );
+
+ if ( dwChars & NCF_HIDDEN ) {
+ TraceMsg( L" NCF_HIDDEN" );
+ }
+
+ if ( dwChars & NCF_NO_SERVICE ) {
+ TraceMsg( L" NCF_NO_SERVICE" );
+ }
+
+ if ( dwChars & NCF_VIRTUAL ) {
+ TraceMsg( L" NCF_VIRTUAL" );
+ }
+
+ if ( dwChars & NCF_PHYSICAL ) {
+ TraceMsg( L" NCF_PHYSICAL" );
+ }
+
+ if ( dwChars & NCF_FILTER ) {
+ TraceMsg( L" NCF_FILTER" );
+ }
+
+ if ( dwChars & NCF_NOT_USER_REMOVABLE ) {
+ TraceMsg( L" NCF_NOT_USER_REMOVABLE" );
+ }
+
+ if ( dwChars & NCF_HAS_UI ) {
+ TraceMsg( L" NCF_HAS_UI" );
+ }
+
+ if ( dwChars & NCF_SOFTWARE_ENUMERATED ) {
+ TraceMsg( L" NCF_SOFTWARE_ENUMERATED" );
+ }
+
+ if ( dwChars & NCF_MULTIPORT_INSTANCED_ADAPTER ) {
+ TraceMsg( L" NCF_MULTIPORT_INSTANCED_ADAPTER" );
+ }
+
+ TraceMsg( L"\n" );
+ }
+ else {
+
+ TraceMsg( L" GetCharacteristics failed(HRESULT %x).\n",
+ hr );
+ }
+
+ hr = pncc->GetId( &lpsz );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \t\tHardware Id: %s\n",
+ lpsz );
+
+ CoTaskMemFree( lpsz );
+ }
+ else {
+
+ TraceMsg( L" GetId failed(HRESULT %x).\n",
+ hr );
+ }
+
+ hr = pncc->GetBindName( &lpsz );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \t\tBindName: %s\n",
+ lpsz );
+
+ CoTaskMemFree( lpsz );
+ }
+ else {
+
+ TraceMsg( L" GetBindName failed(HRESULT %x).\n",
+ hr );
+ }
+
+ if ( dwChars & NCF_PHYSICAL ) {
+ hr = pncc->GetDeviceStatus( &ulStatus );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" \t\tDeviceStatus: %#x\n",
+ ulStatus );
+ }
+ else {
+
+ TraceMsg( L" GetDeviceStatus failed(HRESULT %x).\n",
+ hr );
+ }
+ }
+
+ return;
+}
+
+#endif
+
+HRESULT HrFindInstance (INetCfg *pnc,
+ GUID &guidInstance,
+ INetCfgComponent **ppnccMiniport)
+{
+ IEnumNetCfgComponent *pencc;
+ INetCfgComponent *pncc;
+ GUID guid;
+ WCHAR szGuid[MAX_PATH+1];
+ ULONG ulCount;
+ BOOL found;
+ HRESULT hr;
+
+ TraceMsg( L"-->HrFindInstance.\n" );
+
+ hr = pnc->EnumComponents( &GUID_DEVCLASS_NET,
+ &pencc );
+
+ if ( hr == S_OK ) {
+
+ StringFromGUID2( guidInstance,
+ szGuid,
+ MAX_PATH+1 );
+
+ TraceMsg( L" Looking for component with InstanceGuid %s\n",
+ szGuid );
+
+ hr = pencc->Next( 1,
+ &pncc,
+ &ulCount );
+
+ for ( found=FALSE; (hr == S_OK) && (found == FALSE); ) {
+
+ hr = pncc->GetInstanceGuid( &guid );
+
+ if ( hr == S_OK ) {
+
+ StringFromGUID2( guid,
+ szGuid,
+ MAX_PATH+1 );
+
+ TraceMsg( L" Found component with InstanceGuid %s\n",
+ szGuid );
+
+ found = IsEqualGUID( guid,
+ guidInstance );
+
+ if ( found == FALSE ) {
+
+ ReleaseObj( pncc );
+
+ hr = pencc->Next( 1,
+ &pncc,
+ &ulCount );
+ }
+ else {
+ *ppnccMiniport = pncc;
+ }
+ }
+ }
+
+ ReleaseObj( pencc );
+ }
+ else {
+
+ TraceMsg( L" EnumComponents failed(HRESULT = %x).\n",
+ hr );
+ }
+
+ TraceMsg( L"<--HrFindInstance(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+LONG
+AddToMultiSzValue (
+ HKEY hkeyAdapterGuid,
+ _In_ LPWSTR szMiniportGuid)
+{
+ LPWSTR lpCurrentValue=NULL;
+ LPWSTR lpNewValue=NULL;
+ DWORD dwLen;
+ DWORD dwNewLen;
+ LONG lResult;
+
+ dwLen = 0;
+ lResult = RegQueryValueExW(
+ hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ NULL,
+ &dwLen );
+ if( lResult != ERROR_SUCCESS ){
+ //you may do something
+ }
+
+ if ( dwLen != 0 ) {
+ lpCurrentValue = (LPWSTR)calloc( dwLen, 1 );
+
+ if ( lpCurrentValue ) {
+
+ lResult = RegQueryValueExW( hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ (LPBYTE)lpCurrentValue,
+ &dwLen );
+
+ }
+ else {
+
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ else {
+ dwLen = sizeof(WCHAR);
+ lpCurrentValue = (LPWSTR)calloc( dwLen, 1 );
+
+ if ( !lpCurrentValue ) {
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ lResult = ERROR_SUCCESS;
+ }
+ }
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ dwNewLen =(DWORD) (dwLen + ((wcslen(szMiniportGuid) + 1) * sizeof(WCHAR)));
+
+ lpNewValue = (LPWSTR)malloc( dwNewLen );
+
+ if ( lpNewValue ) {
+
+ StringCbCopyW ( lpNewValue,
+ dwNewLen,
+ szMiniportGuid );
+
+ CopyMemory( lpNewValue+wcslen(szMiniportGuid)+1,
+ lpCurrentValue,
+ dwLen );
+
+ lResult = RegSetValueExW( hkeyAdapterGuid,
+ c_szUpperBindings,
+ 0,
+ REG_MULTI_SZ,
+ (LPBYTE)lpNewValue,
+ dwNewLen );
+ }
+ else {
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ if ( lpCurrentValue ) {
+
+#ifndef DISABLE_PREFAST_PRAGMA
+#pragma prefast(suppress:__WARNING_MISSING_ZERO_TERMINATION, "lpCurrentValue is used as a counted string.")
+#endif
+
+ free( lpCurrentValue );
+ }
+
+ if ( lpNewValue ) {
+ free( lpNewValue );
+ }
+
+ return lResult;
+}
+
+LONG
+DeleteFromMultiSzValue (
+ HKEY hkeyAdapterGuid,
+ _In_ LPWSTR szMiniportGuid)
+{
+ LPWSTR lpCurrentValue=NULL;
+ LPWSTR lpNewValue=NULL;
+ LPWSTR lpCurrentValueTemp;
+ LPWSTR lpNewValueTemp;
+ DWORD dwLen;
+ DWORD dwNewLen;
+ LONG lResult;
+
+ dwLen = 0;
+ lResult = RegQueryValueExW(
+ hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ NULL,
+ &dwLen );
+
+ if ( lResult == ERROR_SUCCESS ) {
+ lpCurrentValue = (LPWSTR)calloc( dwLen, 1 );
+ lpNewValue = (LPWSTR)calloc( dwLen, 1 );
+
+ if ( (lpCurrentValue != NULL) && (lpNewValue != NULL) ) {
+
+ lResult = RegQueryValueExW(
+ hkeyAdapterGuid,
+ c_szUpperBindings,
+ NULL,
+ NULL,
+ (LPBYTE)lpCurrentValue,
+ &dwLen );
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ lpCurrentValueTemp = lpCurrentValue;
+ lpNewValueTemp = lpNewValue;
+
+ dwNewLen = 0;
+
+ lpCurrentValueTemp[dwLen-1]='\0';
+ while( wcslen(lpCurrentValueTemp) > 0) {
+
+ //if a register in the existing register sequence do not match szMiniportGuid, copy to new register sequence
+ if ( _wcsicmp(lpCurrentValueTemp, szMiniportGuid) != 0 ) {
+ StringCchCopyW ( lpNewValueTemp,
+ wcslen(lpCurrentValueTemp), //size of the register
+ lpCurrentValueTemp );
+
+ *(lpNewValueTemp+=wcslen(lpCurrentValueTemp)+1)='\0';
+
+ lpNewValueTemp += wcslen(lpNewValueTemp) + 1;
+ dwNewLen += (DWORD)wcslen(lpNewValueTemp) + 1;
+ }
+
+ lpCurrentValueTemp += wcslen(lpCurrentValueTemp) + 1;
+ } //end of while
+
+ //the minimum length of a register sequence is 3 (start with '\\' and end with '\0') eg: '\\','a','\0'
+ if ( dwNewLen > 2 ) {
+ lResult = RegSetValueExW( hkeyAdapterGuid,
+ c_szUpperBindings,
+ 0,
+ REG_MULTI_SZ,
+ (LPBYTE)lpNewValue,
+ dwNewLen );
+ }
+ else {
+ lResult = RegDeleteValueW( hkeyAdapterGuid,
+ c_szUpperBindings );
+ }
+ }
+ }
+ else {
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ if ( lpCurrentValue ) {
+ free( lpCurrentValue );
+ }
+
+ if ( lpNewValue ) {
+ free( lpNewValue );
+ }
+
+ return lResult;
+}
+
+LPWSTR
+AddDevicePrefix (
+ _In_ LPWSTR lpStr)
+{
+ LPWSTR lpNewStr;
+
+ size_t cchNewStr = wcslen(lpStr) + wcslen(c_szDevicePrefix) + 1;
+ lpNewStr = (LPWSTR)malloc( cchNewStr * sizeof(WCHAR) );
+ if ( lpNewStr )
+ {
+ StringCchCopyW (lpNewStr,
+ cchNewStr,
+ c_szDevicePrefix );
+ lpNewStr[cchNewStr-1]='\0';
+ StringCchCatW ( lpNewStr,
+ cchNewStr,
+ lpStr );
+ }
+
+ return lpNewStr;
+}
+
+LPWSTR
+RemoveDevicePrefix (
+ _In_ LPWSTR lpStr)
+{
+ LPWSTR lpNewStr;
+ LPWSTR lpTemp;
+
+ lpTemp = wcsrchr( lpStr, '\\' );
+
+ if ( lpTemp != NULL ) {
+
+ lpNewStr = _wcsdup( lpTemp+1 );
+ }
+ else {
+ lpNewStr = NULL;
+ }
+
+ return lpNewStr;
+}
+
diff --git a/network/ndis/mux/notifyob/common.h b/network/ndis/mux/notifyob/common.h
new file mode 100644
index 00000000..517641f7
--- /dev/null
+++ b/network/ndis/mux/notifyob/common.h
@@ -0,0 +1,103 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: C O M M O N. H
+//
+// Contents: Common macros and declarations for the sample notify object.
+//
+// Notes:
+//
+// Author: Alok Sinha
+//
+//----------------------------------------------------------------------------
+
+
+#ifndef COMMON_H_INCLUDED
+
+#define COMMON_H_INCLUDED
+
+#include <devguid.h>
+#include <strsafe.h>
+
+#define celems(_x) (sizeof(_x) / sizeof(_x[0]))
+
+#define MAX_VIRTUAL_MP_PER_ADAPTER 64
+
+enum ConfigAction {
+
+ eActUnknown,
+ eActInstall,
+ eActAdd,
+ eActRemove,
+ eActUpdate,
+ eActPropertyUIAdd,
+ eActPropertyUIRemove
+};
+
+//
+// PnP ID, also referred to as Hardware ID, of the protocol interface.
+//
+
+const WCHAR c_szMuxProtocol[] = L"ms_muxp";
+
+//
+// PnP ID, also referred to as Hardware ID, of the Miniport interface.
+//
+
+const WCHAR c_szMuxMiniport[] = L"ms_muxmp";
+
+//
+// Name of the service as specified in the inf file in AddService directive.
+//
+
+const WCHAR c_szMuxService[] = L"muxp";
+
+//
+// Path to the config string where the virtual miniport instance names
+// are stored.
+//
+
+const WCHAR c_szAdapterList[] =
+ L"System\\CurrentControlSet\\Services\\muxp\\Parameters\\Adapters";
+
+//
+// Value name in the registry where miniport device id is stored.
+//
+
+const WCHAR c_szUpperBindings[] = L"UpperBindings";
+
+
+const WCHAR c_szDevicePrefix[] = L"\\Device\\";
+
+#define ReleaseObj( x ) if ( x ) \
+ ((IUnknown*)(x))->Release();
+
+
+#if DBG
+void TraceMsg ( _In_ LPWSTR szFormat, ...);
+void DumpChangeFlag (DWORD dwChangeFlag);
+void DumpBindingPath (INetCfgBindingPath* pncbp);
+void DumpComponent (INetCfgComponent *pncc);
+#else
+#define TraceMsg
+#define DumpChangeFlag( x )
+#define DumpBindingPath( x )
+#define DumpComponent( x )
+#endif
+
+HRESULT HrFindInstance (INetCfg *pnc,
+ GUID &guidInstance,
+ INetCfgComponent **ppnccMiniport);
+
+LONG AddToMultiSzValue( HKEY hkeyAdapterGuid,
+ _In_ LPWSTR szMiniportGuid);
+
+LONG DeleteFromMultiSzValue( HKEY hkeyAdapterGuid,
+ _In_ LPWSTR szMiniportGuid);
+
+LPWSTR AddDevicePrefix ( _In_ LPWSTR lpStr);
+LPWSTR RemoveDevicePrefix ( _In_ LPWSTR lpStr);
+
+#endif // COMMON_H_INCLUDED
diff --git a/network/ndis/mux/notifyob/dllmain.cpp b/network/ndis/mux/notifyob/dllmain.cpp
new file mode 100644
index 00000000..d9785cd6
--- /dev/null
+++ b/network/ndis/mux/notifyob/dllmain.cpp
@@ -0,0 +1,117 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: DLLMAIN . C P P
+//
+// Contents: Main entry points into the DLL
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+
+#include <atlbase.h>
+extern CComModule _Module; // required by atlcom.h
+#include <atlcom.h>
+#include <devguid.h>
+
+#include "notify.h"
+#include "notifyn_i.c"
+
+
+CComModule _Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+ OBJECT_ENTRY(CLSID_CMuxNotify, CMuxNotify)
+END_OBJECT_MAP()
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// DLL Entry Point
+
+extern "C"
+BOOL WINAPI DllMain (HINSTANCE hInstance,
+ DWORD dwReason,
+ LPVOID /*lpReserved*/)
+{
+ TraceMsg( L"-->DllMain.\n");
+
+ if (dwReason == DLL_PROCESS_ATTACH) {
+
+ TraceMsg( L" Reason: Attach.\n");
+
+ _Module.Init(ObjectMap, hInstance);
+
+ DisableThreadLibraryCalls(hInstance);
+ }
+ else if (dwReason == DLL_PROCESS_DETACH) {
+
+ TraceMsg( L" Reason: Detach.\n");
+
+ _Module.Term();
+ }
+
+ TraceMsg( L"<--DllMain.\n");
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Used to determine whether the DLL can be unloaded by OLE
+
+STDAPI DllCanUnloadNow(void)
+{
+ HRESULT hr;
+
+ TraceMsg( L"-->DllCanUnloadNow.\n");
+
+ hr = (_Module.GetLockCount() == 0) ? S_OK : S_FALSE;
+
+ TraceMsg( L"-->DllCanUnloadNow(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Returns a class factory to create an object of the requested type
+
+STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv)
+{
+ TraceMsg( L"-->DllGetClassObject.\n");
+
+ return _Module.GetClassObject(rclsid, riid, ppv);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// DllRegisterServer - Adds entries to the system registry
+
+STDAPI DllRegisterServer(void)
+{
+ // Registers object, typelib and all interfaces in typelib
+
+ TraceMsg( L"-->DllRegisterServer.\n");
+
+ return _Module.RegisterServer(TRUE);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// DllUnregisterServer - Removes entries from the system registry
+
+STDAPI DllUnregisterServer(void)
+{
+ TraceMsg( L"-->DllUnregisterServer.\n");
+
+ _Module.UnregisterServer();
+
+ return S_OK;
+}
diff --git a/network/ndis/mux/notifyob/implinc.cpp b/network/ndis/mux/notifyob/implinc.cpp
new file mode 100644
index 00000000..31e34f27
--- /dev/null
+++ b/network/ndis/mux/notifyob/implinc.cpp
@@ -0,0 +1,31 @@
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+
+#include <atlbase.h>
+extern CComModule _Module; // required by atlcom.h
+#include <atlcom.h>
+#include <initguid.h>
+#include <devguid.h>
+
+#ifdef SubclassWindow
+
+#undef SubclassWindow
+
+#endif
+#pragma prefast(push)
+#pragma prefast(disable:28196 28197, "supress warnings caused by atl headers")
+#include <atlwin.h>
+
+#ifdef _ATL_STATIC_REGISTRY
+
+#include <statreg.h>
+
+#endif
+
+
+#pragma prefast(pop)
+
+
+//EXTERN_C const IID IID_INetLanConnectionUiInfo = {0xC08956A6,0x1CD3,0x11D1,{0xB1,0xC5,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
+
diff --git a/network/ndis/mux/notifyob/list.h b/network/ndis/mux/notifyob/list.h
new file mode 100644
index 00000000..b52b75e7
--- /dev/null
+++ b/network/ndis/mux/notifyob/list.h
@@ -0,0 +1,241 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: LIST . H
+//
+// Contents:
+//
+// Notes: List manipulation functions.
+//
+//----------------------------------------------------------------------------
+
+#ifndef LIST_H_INCLUDED
+
+#define LIST_H_INCLUDED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+
+
+template<class X, class Y> class List {
+ struct Node {
+ X item;
+ Y key;
+ Node *next;
+ };
+
+ Node *m_head;
+ DWORD m_dwNodeCount;
+
+ public:
+
+ List ();
+
+ virtual ~List();
+
+ HRESULT Insert (X item,
+ Y key);
+
+ HRESULT Remove (X *item);
+
+ HRESULT RemoveThis (X item);
+
+ HRESULT RemoveByKey (Y key,
+ X *item);
+
+ VOID RemoveAll(VOID);
+
+ HRESULT Find (DWORD dwIndex,
+ X *item);
+
+ HRESULT FindByKey (Y key,
+ X *item);
+
+ DWORD ListCount (VOID);
+};
+
+template<class X, class Y> List<X, Y>::List ()
+{
+ m_head = NULL;
+ m_dwNodeCount = 0;
+}
+
+template<class X, class Y> List<X, Y>::~List ()
+{
+ RemoveAll();
+}
+
+template<class X, class Y> HRESULT List<X, Y>::Insert (X item,
+ Y key)
+{
+ Node *pNewNode;
+
+ pNewNode = new Node;
+
+ if ( pNewNode ) {
+ pNewNode->item = item;
+ pNewNode->key = key;
+ pNewNode->next = NULL;
+
+ if ( m_dwNodeCount ) {
+ pNewNode->next = m_head;
+ }
+
+ m_head = pNewNode;
+ m_dwNodeCount++;
+ }
+
+ return ( pNewNode ) ? S_OK : HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+}
+
+template<class X, class Y> HRESULT List<X, Y>::Remove (X *item)
+{
+ Node *temp;
+
+ if ( m_dwNodeCount == 0 ) {
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ }
+
+ *item = m_head->item;
+ temp = m_head;
+ m_head = m_head->next;
+ delete temp;
+ m_dwNodeCount--;
+
+ return S_OK;
+}
+
+template<class X, class Y> HRESULT List<X, Y>::RemoveThis (X item)
+{
+ Node *temp;
+ Node *nodeToFind;
+
+ if ( m_dwNodeCount == 0 ) {
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ }
+
+ if ( m_head->item == item ) {
+
+ nodeToFind = m_head;
+ m_head = m_head->next;
+ }
+ else {
+ for (temp = m_head; temp->next && (temp->next->item != item); ) {
+ temp = temp->next;
+ }
+
+ if ( temp->next ) {
+ nodeToFind = temp->next;
+ temp->next = temp->next->next;
+ }
+ else
+ nodeToFind = NULL;
+ }
+
+ if ( nodeToFind ) {
+ delete nodeToFind;
+ m_dwNodeCount--;
+ return S_OK;
+ }
+ else
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+}
+
+template<class X, class Y> HRESULT List<X, Y>::RemoveByKey (Y key,
+ X *item)
+{
+ Node *temp;
+ Node *nodeToFind;
+
+ if ( m_dwNodeCount == 0 ) {
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ }
+
+ if ( m_head->key == key ) {
+
+ nodeToFind = m_head;
+ m_head = m_head->next;
+ }
+ else {
+ for (temp = m_head; temp->next && (temp->next->key != key); ) {
+ temp = temp->next;
+ }
+
+ if ( temp->next ) {
+ nodeToFind = temp->next;
+ temp->next = temp->next->next;
+ }
+ else
+ nodeToFind = NULL;
+ }
+
+ if ( nodeToFind ) {
+ *item = nodeToFind->item;
+
+ delete nodeToFind;
+ m_dwNodeCount--;
+
+ return S_OK;
+ }
+ else
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+}
+
+template<class X, class Y> VOID List<X, Y>::RemoveAll (VOID)
+{
+ Node *temp;
+
+ for (; m_dwNodeCount; --m_dwNodeCount) {
+ temp = m_head;
+ m_head = m_head->next;
+ delete temp;
+ }
+
+ return;
+}
+
+template<class X, class Y> HRESULT List<X, Y>::Find (DWORD dwIndex,
+ X *item)
+{
+ Node *temp;
+ DWORD i;
+
+ if ( (m_dwNodeCount == 0) || (dwIndex > m_dwNodeCount) ) {
+
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ }
+
+ for (i=0, temp = m_head; i < dwIndex; ++i) {
+ temp = temp->next;
+ }
+
+ *item = temp->item;
+ return S_OK;
+}
+
+template<class X, class Y> HRESULT List<X, Y>::FindByKey (Y key,
+ X *item)
+{
+ Node *temp;
+
+ for (temp = m_head; temp && (temp->key != key); )
+ temp = temp->next;
+
+ if ( temp ) {
+ *item = temp->item;
+ return S_OK;
+ }
+ else {
+ return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ }
+}
+
+template<class X, class Y> DWORD List<X, Y>::ListCount (VOID)
+{
+ return m_dwNodeCount;
+}
+
+#endif
diff --git a/network/ndis/mux/notifyob/mux.def b/network/ndis/mux/notifyob/mux.def
new file mode 100644
index 00000000..7dc2d972
--- /dev/null
+++ b/network/ndis/mux/notifyob/mux.def
@@ -0,0 +1,6 @@
+LIBRARY MUX
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/network/ndis/mux/notifyob/mux.vcxproj b/network/ndis/mux/notifyob/mux.vcxproj
new file mode 100644
index 00000000..eb3db887
--- /dev/null
+++ b/network/ndis/mux/notifyob/mux.vcxproj
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CE2FDBC5-FB0E-4B75-9D1F-60BE72C639A6}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{B6C3DAD5-A1FA-45F1-98F8-66CD4FEDD014}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>mux</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;DISABLE_PROTOCOLS_TO_PHYSICAL</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <AdditionalOptions>%(AdditionalOptions) -no_format_opt</AdditionalOptions>
+ </Midl>
+ <ResourceCompile>
+ <AdditionalOptions>%(AdditionalOptions) -i $(IntDir) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <AdditionalOptions>%(AdditionalOptions) -no_format_opt</AdditionalOptions>
+ </Midl>
+ <ResourceCompile>
+ <AdditionalOptions>%(AdditionalOptions) -i $(IntDir) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <AdditionalOptions>%(AdditionalOptions) -no_format_opt</AdditionalOptions>
+ </Midl>
+ <ResourceCompile>
+ <AdditionalOptions>%(AdditionalOptions) -i $(IntDir) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <AdditionalOptions>%(AdditionalOptions) -no_format_opt</AdditionalOptions>
+ </Midl>
+ <ResourceCompile>
+ <AdditionalOptions>%(AdditionalOptions) -i $(IntDir) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;setupapi.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>mux.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;setupapi.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>mux.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;setupapi.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>mux.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;setupapi.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>mux.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="adapter.cpp" />
+ <ClCompile Include="common.cpp" />
+ <ClCompile Include="dllmain.cpp" />
+ <ClCompile Include="implinc.cpp" />
+ <ClCompile Include="notify.cpp" />
+ <ClCompile Include="virtual.cpp" />
+ <Midl Include="notifyn.idl" />
+ <ResourceCompile Include="notify.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/notifyob/mux.vcxproj.Filters b/network/ndis/mux/notifyob/mux.vcxproj.Filters
new file mode 100644
index 00000000..ae8436c6
--- /dev/null
+++ b/network/ndis/mux/notifyob/mux.vcxproj.Filters
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{7CBE03EB-893C-48D0-9792-100241030FDE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{819C3038-4DC6-4786-98BA-ADC2B360C2BB}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{416958BA-8A0D-44E3-8B1E-F089723BC01A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="adapter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="common.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="implinc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="notify.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="virtual.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <Midl Include="notifyn.idl">
+ <Filter>Source Files</Filter>
+ </Midl>
+ <None Include="mux.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="notify.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/mux/notifyob/notify.RC b/network/ndis/mux/notifyob/notify.RC
new file mode 100644
index 00000000..4888e305
--- /dev/null
+++ b/network/ndis/mux/notifyob/notify.RC
@@ -0,0 +1,47 @@
+//Microsoft Developer Studio generated resource script.
+//
+
+#include "resource.h"
+
+#include "windows.h"
+
+1 TYPELIB "notifyn.tlb"
+IDR_REG_SAMPLE_NOTIFY REGISTRY "notify.rgs"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+IDD_NOTIFY_GENERAL DIALOG DISCARDABLE 0, 0, 232, 151
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Remove a Miniport",IDC_REMOVE,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,39,73,75,10
+ CONTROL "Add a Miniport",IDC_ADD,"Button",BS_AUTORADIOBUTTON |
+ WS_TABSTOP,39,36,61,10
+ LTEXT "Removal of miniport happens in FIFO order",IDC_STATIC,
+ 39,93,135,8
+ CTEXT "What do you want to do today?",IDC_STATIC,0,12,231,14
+END
+
+
+#include <ntverp.h>
+#include <winver.h>
+
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Sample MUX Notify Object"
+#define VER_INTERNALNAME_STR "notify.dll"
+
+#include <common.ver>
+
+
+
+
+
+
+
+
diff --git a/network/ndis/mux/notifyob/notify.RGS b/network/ndis/mux/notifyob/notify.RGS
new file mode 100644
index 00000000..51e234e2
--- /dev/null
+++ b/network/ndis/mux/notifyob/notify.RGS
@@ -0,0 +1,14 @@
+HKCR
+{
+ NoRemove CLSID
+ {
+ ForceRemove {ee6cd6fc-a32b-4a26-8a1c-dbc97988ad7a} = s 'Sample Notify Object'
+ {
+ InProcServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Both'
+ }
+ }
+ }
+}
+
diff --git a/network/ndis/mux/notifyob/notify.cpp b/network/ndis/mux/notifyob/notify.cpp
new file mode 100644
index 00000000..be239fcd
--- /dev/null
+++ b/network/ndis/mux/notifyob/notify.cpp
@@ -0,0 +1,2139 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: N O T I F Y . C P P
+//
+// Contents: Sample notify object code
+//
+// Notes:
+//
+// Author: Alok Sinha
+
+//----------------------------------------------------------------------------
+
+#include "notify.h"
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::CMuxNotify
+//
+// Purpose: Constructor for CMuxNotify
+//
+// Arguments: None
+//
+// Returns: None
+//
+// Notes:
+//
+
+CMuxNotify::CMuxNotify (VOID) : m_pncc (NULL),
+ m_pnc(NULL),
+ m_eApplyAction(eActUnknown),
+ m_pUnkContext(NULL)
+{
+ TraceMsg( L"-->CMuxNotify::CMuxNotify(Constructor).\n" );
+
+ TraceMsg( L"<--CMuxNotify::CMuxNotify(Constructor).\n" );
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::~CMuxNotify
+//
+// Purpose: Destructor for class CMuxNotify
+//
+// Arguments: None
+//
+// Returns: None
+//
+// Notes:
+//
+CMuxNotify::~CMuxNotify (VOID)
+{
+ CMuxPhysicalAdapter *pAdapter;
+ DWORD dwAdapterCount;
+ DWORD i;
+
+ TraceMsg( L"-->CMuxNotify::~CMuxNotify(Destructor).\n" );
+
+ // release interfaces if acquired
+
+ ReleaseObj( m_pncc );
+ ReleaseObj( m_pnc );
+ ReleaseObj( m_pUnkContext );
+
+ dwAdapterCount = m_AdaptersList.ListCount();
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ pAdapter = NULL;
+ m_AdaptersList.Remove( &pAdapter );
+
+ delete pAdapter;
+ }
+
+ dwAdapterCount = m_AdaptersToRemove.ListCount();
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ pAdapter = NULL;
+ m_AdaptersToRemove.Remove( &pAdapter );
+
+ delete pAdapter;
+ }
+
+ dwAdapterCount = m_AdaptersToAdd.ListCount();
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ pAdapter = NULL;
+ m_AdaptersToAdd.Remove( &pAdapter );
+
+ delete pAdapter;
+ }
+
+ TraceMsg( L"<--CMuxNotify::~CMuxNotify(Destructor).\n" );
+}
+
+//
+//---------------------- NOTIFY OBJECT FUNCTIONS -----------------------------
+//
+
+//----------------------------------------------------------------------------
+// INetCfgComponentControl
+//
+// The following functions provide the INetCfgComponentControl interface.
+//
+//----------------------------------------------------------------------------
+
+//
+// Function: CMuxNotify::Initialize
+//
+// Purpose: Initialize the notify object
+//
+// Arguments:
+// IN pnccItem : Pointer to INetCfgComponent object
+// IN pnc : Pointer to INetCfg object
+// IN fInstalling: TRUE if we are being installed
+//
+// Returns:
+//
+// Notes:
+//
+
+STDMETHODIMP CMuxNotify::Initialize (INetCfgComponent* pncc,
+ INetCfg* pnc,
+ BOOL fInstalling)
+{
+ HRESULT hr = S_OK;
+
+ TraceMsg( L"-->CMuxNotify INetCfgControl::Initialize.\n" );
+
+
+ // Save INetCfg & INetCfgComponent and add a refcount
+
+ m_pncc = pncc;
+ m_pnc = pnc;
+
+ if (m_pncc) {
+
+ m_pncc->AddRef();
+ }
+
+ if (m_pnc) {
+
+ m_pnc->AddRef();
+ }
+
+
+ //
+ // If this not an installation, then we need to
+ // initialize all of our data and classes
+ //
+
+ if ( !fInstalling ) {
+
+ hr = HrLoadAdapterConfiguration();
+ }
+
+ TraceMsg( L"<--CMuxNotify INetCfgControl::Initialize(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::CancelChanges
+//
+// Purpose: Cancel any changes made to internal data
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+
+STDMETHODIMP CMuxNotify::CancelChanges (VOID)
+{
+ TraceMsg( L"-->CMuxNotify INetCfgControl::CancelChanges.\n" );
+
+
+ TraceMsg( L"<--CMuxNotify INetCfgControl::CancelChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::ApplyRegistryChanges
+//
+// Purpose: Apply changes.
+//
+// Arguments: None
+//
+// Returns: S_OK.
+//
+// Notes: We can make changes to registry etc. here.
+
+STDMETHODIMP CMuxNotify::ApplyRegistryChanges(VOID)
+{
+ CMuxPhysicalAdapter *pAdapter = NULL;
+ DWORD dwAdapterCount;
+ DWORD i;
+
+ TraceMsg( L"-->CMuxNotify INetCfgControl::ApplyRegistryChanges.\n" );
+
+ //
+ // Make registry changes for the adapters added.
+ //
+
+ dwAdapterCount = m_AdaptersToAdd.ListCount();
+
+ TraceMsg( L" Adding %d new adapters.\n",
+ dwAdapterCount );
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersToAdd.Find( i,
+ &pAdapter );
+
+ pAdapter->ApplyRegistryChanges( eActAdd );
+
+ }
+
+ //
+ // Make registry changes for the adapters uninstalled.
+ //
+
+ dwAdapterCount = m_AdaptersToRemove.ListCount();
+
+ TraceMsg( L" Removing %d adapters.\n",
+ dwAdapterCount );
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersToRemove.Find( i,
+ &pAdapter );
+
+ pAdapter->ApplyRegistryChanges( eActRemove );
+ }
+
+ //
+ // Make registry changes for the miniports added/removed
+ // through the property pages.
+ //
+
+ dwAdapterCount = m_AdaptersList.ListCount();
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersList.Find( i,
+ &pAdapter );
+
+ pAdapter->ApplyRegistryChanges( eActUpdate );
+ }
+
+ TraceMsg( L"<--CMuxNotify INetCfgControl::ApplyRegistryChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::ApplyPnpChanges
+//
+// Purpose: Apply changes.
+//
+// Arguments:
+// IN pfCallback: PnPConfigCallback interface.
+//
+// Returns: S_OK.
+//
+// Notes:
+
+STDMETHODIMP CMuxNotify::ApplyPnpChanges (
+ INetCfgPnpReconfigCallback* pfCallback)
+{
+ CMuxPhysicalAdapter *pAdapter = NULL;
+ GUID guidAdapter;
+ DWORD dwAdapterCount;
+ DWORD i;
+
+ TraceMsg( L"-->CMuxNotify INetCfgControl::ApplyPnpChanges.\n" );
+
+ //
+ // Apply PnP changes for the adapters added.
+ //
+
+ dwAdapterCount = m_AdaptersToAdd.ListCount();
+
+ TraceMsg( L" Applying PnP changes when %d adapters added.\n",
+ dwAdapterCount );
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersToAdd.Remove( &pAdapter );
+
+ pAdapter->ApplyPnpChanges( pfCallback,
+ eActAdd );
+
+ pAdapter->GetAdapterGUID( &guidAdapter );
+
+ m_AdaptersList.Insert( pAdapter,
+ guidAdapter );
+ }
+
+ //
+ // Apply PnP changes for the adapters uninstalled.
+ //
+
+ dwAdapterCount = m_AdaptersToRemove.ListCount();
+
+ TraceMsg( L" Applying PnP changes when %d adapters removed.\n",
+ dwAdapterCount );
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersToRemove.Remove( &pAdapter );
+
+ pAdapter->ApplyPnpChanges( pfCallback,
+ eActRemove );
+
+ delete pAdapter;
+ }
+
+ //
+ // Apply PnP changes for the miniports added/removed through
+ // the property pages.
+ //
+
+ dwAdapterCount = m_AdaptersList.ListCount();
+
+ for (i=0; i < dwAdapterCount; ++i) {
+
+ m_AdaptersList.Find( i,
+ &pAdapter );
+
+ pAdapter->ApplyPnpChanges( pfCallback,
+ eActUpdate );
+ }
+
+ TraceMsg( L"<--CMuxNotify INetCfgControl::ApplyPnpChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+//----------------------------------------------------------------------------
+// INetCfgComponentSetup
+//
+// The following functions provide the INetCfgComponentSetup interface.
+//
+//----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::Install
+//
+// Purpose: Do operations necessary during the installation.
+//
+// Arguments:
+// IN dwSetupFlags: Setup flags
+//
+// Returns: S_OK
+//
+// Notes: Don't do anything irreversible (like modifying registry) yet
+// since the config. actually completes only when Apply is called!
+//
+
+STDMETHODIMP CMuxNotify::Install (DWORD dwSetupFlags)
+{
+
+ UNREFERENCED_PARAMETER(dwSetupFlags);
+ TraceMsg( L"-->CMuxNotify INetCfgSetup::Install.\n" );
+
+ // Start up the install process
+
+ m_eApplyAction = eActInstall;
+
+ TraceMsg( L"<--CMuxNotify INetCfgSetup::Install(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::Upgrade
+//
+// Purpose: Do operations necessary during the upgrade.
+//
+// Arguments:
+// IN dwSetupFlags: Setup flags
+//
+// Returns: S_OK
+//
+// Notes: Don't do anything irreversible (like modifying registry) yet
+// since the config. actually completes only when Apply is called!
+//
+
+STDMETHODIMP CMuxNotify::Upgrade (IN DWORD dwSetupFlags,
+ IN DWORD dwUpgradeFromBuildNo)
+{
+
+ TraceMsg( L"-->CMuxNotify INetCfgSetup::Upgrade.\n" );
+
+ TraceMsg( L" DwSetupFlags = %x, dwUpgradeFromBuildNo = %x\n",
+ dwSetupFlags,
+ dwUpgradeFromBuildNo );
+
+ TraceMsg( L"<--CMuxNotify INetCfgSetup::Upgrade(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::ReadAnswerFile
+//
+// Purpose: Read settings from answerfile and configure CMuxNotify
+//
+// Arguments:
+// IN pszAnswerFile : Name of AnswerFile
+// IN pszAnswerSection: Name of parameters section
+//
+// Returns:
+//
+// Notes: Don't do anything irreversible (like modifying registry) yet
+// since the config. actually completes only when Apply is called!
+//
+
+STDMETHODIMP CMuxNotify::ReadAnswerFile (PCWSTR pszAnswerFile,
+ PCWSTR pszAnswerSection)
+{
+// PCWSTR pszParamReadFromAnswerFile = L"ParamFromAnswerFile";
+
+ UNREFERENCED_PARAMETER(pszAnswerFile);
+ UNREFERENCED_PARAMETER(pszAnswerSection);
+
+ TraceMsg( L"-->CMuxNotify INetCfgSetup::ReadAnswerFile.\n" );
+
+ // We will pretend here that szParamReadFromAnswerFile was actually
+ // read from the AnswerFile using the following steps
+ //
+ // - Open file pszAnswerFile using SetupAPI
+ // - locate section pszAnswerSection
+ // - locate the required key and get its value
+ // - store its value in pszParamReadFromAnswerFile
+ // - close HINF for pszAnswerFile
+
+ // Now that we have read pszParamReadFromAnswerFile from the
+ // AnswerFile, store it in our memory structure.
+ // Remember we should not be writing it to the registry till
+ // our Apply is called!!
+ //
+
+ TraceMsg( L"<--CMuxNotify INetCfgSetup::ReadAnswerFile(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::Removing
+//
+// Purpose: Do necessary cleanup when being removed
+//
+// Arguments: None
+//
+// Returns: S_OK
+//
+// Notes: Don't do anything irreversible (like modifying registry) yet
+// since the removal is actually complete only when Apply is called!
+//
+
+STDMETHODIMP CMuxNotify::Removing (VOID)
+{
+
+ TraceMsg( L"-->CMuxNotify INetCfgSetup::Removing.\n" );
+
+ TraceMsg( L"<--CMuxNotify INetCfgSetup::Removing(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+
+//----------------------------------------------------------------------------
+// INetCfgComponentNotifyBinding
+//
+// The following functions provide the INetCfgComponentNotifyBinding interface.
+//
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::QueryBindingPath
+//
+// Purpose: This is specific to the component being installed. This will
+// ask us if we want to bind to the Item being passed into
+// this routine. We can disable the binding by returning
+// NETCFG_S_DISABLE_QUERY
+//
+//
+// Arguments:
+// IN dwChangeFlag: Type of binding change
+// IN pncbpItem : Pointer to INetCfgBindingPath object
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::QueryBindingPath (IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath *pncbp)
+{
+ UNREFERENCED_PARAMETER(pncbp);
+ UNREFERENCED_PARAMETER(dwChangeFlag);
+
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyBinding::QueryBindingPath.\n" );
+
+ DumpChangeFlag( dwChangeFlag );
+ DumpBindingPath( pncbp );
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyBinding::QueryBindingPath(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::NotifyBindingPath
+//
+// Purpose: We are now being told to bind to the component passed to us.
+//
+//
+// Arguments:
+// IN dwChangeFlag: Type of system change
+// IN pncc : Pointer to INetCfgComponent object
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+
+
+
+STDMETHODIMP CMuxNotify::NotifyBindingPath (IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath *pncbp)
+{
+ INetCfgComponent *pnccLower;
+ INetCfgComponent *pnccUpper;
+ LPWSTR pszwInfIdLower;
+ LPWSTR pszwInfIdUpper;
+ DWORD dwCharcteristics;
+ HRESULT hr = S_OK;
+
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyBinding::NotifyBindingPath.\n" );
+
+ DumpChangeFlag( dwChangeFlag );
+ DumpBindingPath( pncbp );
+
+ //
+ // We are only interested to know 1) when a component is installed
+ // and we are binding to it i.e. dwChangeFlag = NCN_ADD | NCN_ENABLE
+ // and 2) when a component is removed to which we are bound i.e.
+ // dwChangeFlag = NCN_REMOVE | NCN_ENABLE. dwChangeFlag is never
+ // set to NCN_ADD or NCN_REMOVE only. So, checking for NCN_ENABLE
+ // covers the case of NCN_ADD | NCN_ENABLE and checking for NCN_REMOVE
+ // covers the case of NCN_REMOVE | NCN_ENABLE. We don't care about
+ // NCN_ADD | NCN_DISABLE (case 1) and NCN_REMOVE | NCN_DISABLE (case 2).
+ //
+
+ if ( dwChangeFlag & (NCN_ENABLE | NCN_REMOVE) ) {
+
+ //
+ // Get the upper and lower components.
+ //
+
+ hr = HrGetUpperAndLower( pncbp,
+ &pnccUpper,
+ &pnccLower );
+
+ if ( hr == S_OK ) {
+
+ hr = pnccLower->GetCharacteristics( &dwCharcteristics );
+
+ if ( hr == S_OK ) {
+ hr = pnccLower->GetId( &pszwInfIdLower );
+
+ if ( hr == S_OK ) {
+ hr = pnccUpper->GetId( &pszwInfIdUpper );
+
+ if ( hr == S_OK ) {
+
+ //
+ // We are interested only in binding to a
+ // physical ethernet adapters.
+ //
+
+ if ( dwCharcteristics & NCF_PHYSICAL ) {
+
+ if ( !_wcsicmp( pszwInfIdUpper, c_szMuxProtocol ) ) {
+
+ if ( dwChangeFlag & NCN_ADD ) {
+
+ hr = HrAddAdapter( pnccLower );
+ if( hr != S_OK ){
+ // you may do something
+ }
+ m_eApplyAction = eActAdd;
+
+ } else if ( dwChangeFlag & NCN_REMOVE ) {
+
+ hr = HrRemoveAdapter( pnccLower );
+ if( hr != S_OK ){
+ // you may do something
+ }
+ m_eApplyAction = eActRemove;
+ }
+ }
+ } // Physical Adapters.
+ else if (dwCharcteristics & NCF_VIRTUAL) {
+
+ }
+
+ CoTaskMemFree( pszwInfIdUpper );
+
+ } // Got the upper component id.
+
+ CoTaskMemFree( pszwInfIdLower );
+
+ } // Got the lower component id.
+
+ } // Got NIC's characteristics
+
+ ReleaseObj(pnccLower);
+ ReleaseObj(pnccUpper);
+
+ } // Got the upper and lower components.
+
+ }
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyBinding::NotifyBindingPath(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+
+
+//----------------------------------------------------------------------------
+// INetCfgComponentNotifyGlobal
+//
+// The following functions provide the INetCfgComponentNotifyGlobal interface.
+//
+//----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::GetSupportedNotifications
+//
+// Purpose: Tell the system which notifications we are interested in
+//
+// Arguments:
+// OUT pdwNotificationFlag: Pointer to NotificationFlag
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::GetSupportedNotifications (
+ OUT DWORD* pdwNotificationFlag)
+{
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::GetSupportedNotifications.\n" );
+
+ *pdwNotificationFlag = NCN_NET | NCN_NETTRANS | NCN_ADD | NCN_REMOVE |
+ NCN_BINDING_PATH | NCN_ENABLE | NCN_DISABLE;
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::GetSupportedNotifications(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::SysQueryBindingPath
+//
+// Purpose: Enable or Disable a binding path.
+//
+// Arguments:
+// IN dwChangeFlag: Type of binding change
+// IN pncbp : Pointer to INetCfgBindingPath object
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+
+STDMETHODIMP CMuxNotify::SysQueryBindingPath (DWORD dwChangeFlag,
+ INetCfgBindingPath* pncbp)
+{
+ INetCfgComponent *pnccLower;
+ INetCfgComponent *pnccUpper;
+ LPWSTR pszwInfIdLower;
+ LPWSTR pszwInfIdUpper;
+ DWORD dwCharcteristics;
+ HRESULT hr = S_OK;
+
+
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysQueryBindingPath.\n" );
+
+ DumpChangeFlag( dwChangeFlag );
+ DumpBindingPath( pncbp );
+
+ if ( dwChangeFlag & NCN_ENABLE ) {
+
+ //
+ // Get the upper and lower components.
+ //
+
+ hr = HrGetUpperAndLower( pncbp,
+ &pnccUpper,
+ &pnccLower );
+
+ if ( hr == S_OK ) {
+ hr = pnccLower->GetCharacteristics( &dwCharcteristics );
+
+ if ( hr == S_OK ) {
+ hr = pnccLower->GetId( &pszwInfIdLower );
+
+ if ( hr == S_OK ) {
+ hr = pnccUpper->GetId( &pszwInfIdUpper );
+
+ if ( hr == S_OK ) {
+
+ //
+ // We are interested only in bindings to physical
+ // ethernet adapters.
+ //
+
+ if ( dwCharcteristics & NCF_PHYSICAL ) {
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+ //
+ // If it not our protocol binding to the
+ // physical adapter then, disable the
+ // binding.
+ //
+
+ if (_wcsicmp( pszwInfIdUpper, c_szMuxProtocol ) ) {
+
+ TraceMsg( L" Disabling the binding between %s "
+ L"and %s.\n",
+ pszwInfIdUpper,
+ pszwInfIdLower );
+
+ hr = NETCFG_S_DISABLE_QUERY;
+ }
+#endif
+
+ } // Physical Adapters.
+ else {
+ if (dwCharcteristics & NCF_VIRTUAL) {
+
+ // If the lower component is our miniport
+ // and the upper component is our protocol
+ // then also, disable the binding.
+
+ if ( !_wcsicmp(pszwInfIdLower, c_szMuxMiniport) &&
+ !_wcsicmp(pszwInfIdUpper, c_szMuxProtocol) ) {
+
+ TraceMsg( L" Disabling the binding between %s "
+ L"and %s.\n",
+ pszwInfIdUpper,
+ pszwInfIdLower );
+
+ hr = NETCFG_S_DISABLE_QUERY;
+ }
+
+ } // Virtual Adapters
+
+ }
+
+ CoTaskMemFree( pszwInfIdUpper );
+
+ } // Got the upper component id.
+
+ CoTaskMemFree( pszwInfIdLower );
+
+ } // Got the lower component id.
+
+ } // Got NIC's characteristics
+
+ ReleaseObj(pnccLower);
+ ReleaseObj(pnccUpper);
+
+ }
+
+ }
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysQueryBindingPath(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::SysNotifyBindingPath
+//
+// Purpose: System tells us by calling this function which
+// binding path has just been formed.
+//
+// Arguments:
+// IN dwChangeFlag: Type of binding change
+// IN pncbpItem : Pointer to INetCfgBindingPath object
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::SysNotifyBindingPath (DWORD dwChangeFlag,
+ INetCfgBindingPath* pncbp)
+{
+ UNREFERENCED_PARAMETER(dwChangeFlag);
+ UNREFERENCED_PARAMETER(pncbp);
+
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysNotifyBindingPath.\n" );
+
+ DumpChangeFlag( dwChangeFlag );
+ DumpBindingPath( pncbp );
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysNotifyBindingPath(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::SysNotifyComponent
+//
+// Purpose: System tells us by calling this function which
+// component has undergone a change (installed/removed)
+//
+// Arguments:
+// IN dwChangeFlag: Type of system change
+// IN pncc : Pointer to INetCfgComponent object
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::SysNotifyComponent (DWORD dwChangeFlag,
+ INetCfgComponent* pncc)
+{
+ UNREFERENCED_PARAMETER(dwChangeFlag);
+ UNREFERENCED_PARAMETER(pncc);
+
+ TraceMsg( L"-->CMuxNotify INetCfgNotifyGlobal::SysNotifyComponent.\n" );
+
+ DumpChangeFlag( dwChangeFlag );
+ DumpComponent( pncc );
+
+ TraceMsg( L"<--CMuxNotify INetCfgNotifyGlobal::SysNotifyComponent(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+
+//----------------------------------------------------------------------------
+// INetCfgComponentPropertyUi
+//
+// The following functions provide the INetCfgComponentPropertyUi interface.
+//
+//----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::MergePropPages
+//
+// Purpose: Supply our property page to system.
+//
+// Arguments:
+// OUT pdwDefPages : Pointer to num default pages
+// OUT pahpspPrivate: Pointer to array of pages
+// OUT pcPages : Pointer to num pages
+// IN hwndParent : Handle of parent window
+// IN szStartPage : Pointer to
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::MergePropPages (IN OUT DWORD* pdwDefPages,
+ OUT LPBYTE* pahpspPrivate,
+ OUT UINT* pcPages,
+ IN HWND hwndParent,
+ OUT PCWSTR* szStartPage)
+{
+ HRESULT hr = S_OK;
+ HPROPSHEETPAGE *ahpsp;;
+ INetLanConnectionUiInfo *pLanConnUiInfo;
+
+ UNREFERENCED_PARAMETER(szStartPage);
+ UNREFERENCED_PARAMETER(hwndParent);
+
+ TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::MergePropPages\n");
+
+ //
+ // We don't want any default pages to be shown
+ //
+
+ *pdwDefPages = 0;
+ *pcPages = 0;
+ *pahpspPrivate = NULL;
+
+ if ( !m_pUnkContext ) {
+ return E_UNEXPECTED;
+ }
+
+ hr = m_pUnkContext->QueryInterface(
+ IID_INetLanConnectionUiInfo,
+ reinterpret_cast<PVOID *>(&pLanConnUiInfo));
+
+ if ( hr == S_OK ) {
+
+ ReleaseObj( pLanConnUiInfo );
+
+ ahpsp = (HPROPSHEETPAGE*)CoTaskMemAlloc( sizeof(HPROPSHEETPAGE) );
+
+ if (ahpsp) {
+
+ PROPSHEETPAGE psp = {0};
+
+ psp.dwSize = sizeof(PROPSHEETPAGE);
+ psp.dwFlags = PSP_DEFAULT;
+ psp.hInstance = _Module.GetModuleInstance();
+ psp.pszTemplate = MAKEINTRESOURCE(IDD_NOTIFY_GENERAL);
+ psp.pfnDlgProc = NotifyDialogProc;
+ psp.pfnCallback = NULL; (LPFNPSPCALLBACK)NotifyPropSheetPageProc;
+ psp.lParam = (LPARAM) this;
+ psp.pszHeaderTitle = NULL;
+ psp.pszHeaderSubTitle = NULL;
+
+ ahpsp[0] = ::CreatePropertySheetPage(&psp);
+ *pcPages = 1;
+ *pahpspPrivate = (LPBYTE)ahpsp;
+ }
+ else {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::MergePropPages(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::ValidateProperties
+//
+// Purpose: Validate changes to property page.
+//
+// Arguments:
+// IN hwndSheet: Window handle of property sheet
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+
+STDMETHODIMP CMuxNotify::ValidateProperties (HWND hwndSheet)
+{
+
+ UNREFERENCED_PARAMETER(hwndSheet);
+
+ TraceMsg( L"-->CMuxNotify INetCfgPropertyUi::ValidateProperties\n" );
+
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::ValidateProperties(HRESULT = %x).\n",
+ S_OK );
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::CancelProperties
+//
+// Purpose: Cancel changes to property page
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::CancelProperties (VOID)
+{
+ TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::CancelProperties\n");
+
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::CancelProperties(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::ApplyProperties
+//
+// Purpose: Apply value of controls on property page
+// to internal memory structure
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes:
+//
+STDMETHODIMP CMuxNotify::ApplyProperties (VOID)
+{
+ INetLanConnectionUiInfo *pLanConnUiInfo;
+ CMuxPhysicalAdapter *pAdapter;
+ GUID guidAdapter;
+ INetCfgComponent *pncc;
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(pncc);
+
+ TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::ApplyProperties\n");
+
+ if ( m_pUnkContext ) {
+
+ hr = m_pUnkContext->QueryInterface(
+ IID_INetLanConnectionUiInfo,
+ reinterpret_cast<PVOID *>(&pLanConnUiInfo));
+
+ if ( hr == S_OK ) {
+
+ hr = pLanConnUiInfo->GetDeviceGuid( &guidAdapter );
+
+ if ( hr == S_OK ) {
+
+ hr = m_AdaptersList.FindByKey( guidAdapter,
+ &pAdapter );
+ if ( hr == S_OK ) {
+
+ switch( m_eApplyAction ) {
+
+ case eActPropertyUIAdd:
+
+ hr = HrAddMiniport( pAdapter,
+ &guidAdapter );
+ break;
+
+ case eActPropertyUIRemove:
+
+ hr = HrRemoveMiniport( pAdapter,
+ &guidAdapter );
+ break;
+ }
+ }
+ }
+
+ ReleaseObj( pLanConnUiInfo );
+ }
+ }
+
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::ApplyProperties(HRESULT = %x).\n",
+ hr );
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::QueryPropertyUi
+//
+// Purpose: System is asking if we support property pages.
+//
+// Arguments:
+// IN pUnk: Pointer to IUnknown.
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes: We display property pages only in the context of
+// a LAN connection.
+//
+
+STDMETHODIMP CMuxNotify::QueryPropertyUi (IUnknown * pUnk)
+{
+ INetLanConnectionUiInfo *pLanConnUiInfo;
+ HRESULT hr=S_FALSE;
+
+ TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::QueryPropertyUi\n");
+
+#ifndef PASSTHRU_NOTIFY
+
+ if ( pUnk ) {
+
+ hr = pUnk->QueryInterface(
+ IID_INetLanConnectionUiInfo,
+ reinterpret_cast<PVOID *>(&pLanConnUiInfo));
+
+ ReleaseObj( pLanConnUiInfo );
+ }
+#endif
+
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::QueryPropertyUi(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::SetContext
+//
+// Purpose: Save the LAN connection context.
+//
+// Arguments:
+// IN pUnk: Pointer to IUnknown.
+//
+// Returns: S_OK on success, otherwise an error code
+//
+// Notes: It is also called to release the current LAN connection context.
+//
+
+STDMETHODIMP CMuxNotify::SetContext (IUnknown * pUnk)
+{
+ TraceMsg(L"-->CMuxNotify INetCfgPropertyUi::SetContext\n");
+
+ //
+ // Release previous context, if any
+ //
+
+ ReleaseObj( m_pUnkContext );
+
+ m_pUnkContext = NULL;
+
+ if ( pUnk ) {
+
+ m_pUnkContext = pUnk;
+ m_pUnkContext->AddRef();
+ }
+
+ TraceMsg(L"<--CMuxNotify INetCfgPropertyUi::SetContext(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrLoadAdapterConfiguration
+//
+// Purpose: This loads the Miniport and adapters that have already been
+// installed into our own data structures
+//
+// Arguments: None.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes:
+//
+
+
+HRESULT CMuxNotify::HrLoadAdapterConfiguration (VOID)
+{
+ HKEY hkeyAdapterList;
+ WCHAR szAdapterGuid[MAX_PATH+1];
+ DWORD dwDisp;
+ CMuxPhysicalAdapter *pAdapter;
+ GUID guidAdapter;
+ DWORD dwIndex;
+ LONG lResult;
+
+ TraceMsg( L"-->CMuxNotify::HrLoadAdapterConfiguration.\n" );
+
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ c_szAdapterList,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterList,
+ &dwDisp);
+
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ //
+ // If dwDisp indicates that a new key is created then, we know there
+ // is no adapter currently listed underneath and we simply
+ // return, otherwise, we enumerate the subkeys, each one representing an
+ // adapter.
+ //
+
+ if ( dwDisp != REG_CREATED_NEW_KEY ) {
+
+ lResult = RegEnumKeyW( hkeyAdapterList,
+ 0,
+ szAdapterGuid,
+ MAX_PATH+1 );
+
+ for (dwIndex=1; lResult == ERROR_SUCCESS; ++dwIndex) {
+
+ TraceMsg( L" Loading configuration for adapter %s...\n",
+ szAdapterGuid );
+
+ //
+ // Subkeys are actually a guid/bindname of the adapters.
+ //
+ szAdapterGuid[MAX_PATH]='\0';
+ CLSIDFromString( szAdapterGuid,
+ &guidAdapter );
+
+ //
+ // Create an instance representing the adapter.
+ //
+
+ #pragma prefast(suppress:8197, "The instance is freed in the destructor")
+ pAdapter = new CMuxPhysicalAdapter( m_pnc,
+ &guidAdapter );
+
+ if ( pAdapter ) {
+
+ //
+ // Load any adapter specific configuration.
+ //
+
+ pAdapter->LoadConfiguration();
+
+ //
+ // Save the adapter instance in a list.
+ //
+
+ m_AdaptersList.Insert( pAdapter,
+ guidAdapter );
+
+ //
+ // Get next subkey.
+ //
+
+ lResult = RegEnumKeyW( hkeyAdapterList,
+ dwIndex,
+ szAdapterGuid,
+ MAX_PATH+1 );
+ }
+ else {
+
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ //
+ // RegEnumKeyW may have returned error when there are no more
+ // subkeys to read.
+ //
+
+ lResult = ERROR_SUCCESS;
+ }
+
+ RegCloseKey( hkeyAdapterList );
+ }
+
+ TraceMsg( L"<--CMuxNotify::HrLoadAdapterConfiguration(HRESULT = %x).\n",
+ HRESULT_FROM_WIN32(lResult) );
+
+ return HRESULT_FROM_WIN32(lResult);
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrGetUpperAndLower
+//
+// Purpose: Get the upper and lower component of the first interface
+// of a binding path.
+//
+// Arguments:
+// IN pncbp : Binding path.
+// OUT ppnccUpper: Upper component.
+// OUT ppnccLower: Lower component.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrGetUpperAndLower (INetCfgBindingPath* pncbp,
+ INetCfgComponent **ppnccUpper,
+ INetCfgComponent **ppnccLower)
+{
+ IEnumNetCfgBindingInterface* pencbi;
+ INetCfgBindingInterface* pncbi;
+ ULONG ulCount;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxNotify::HrGetUpperAndLowerComponent.\n" );
+
+ *ppnccUpper = NULL;
+ *ppnccLower = NULL;
+
+ hr = pncbp->EnumBindingInterfaces(&pencbi);
+
+ if (S_OK == hr) {
+
+ //
+ // get the first binding interface
+ //
+
+ hr = pencbi->Next(1, &pncbi, &ulCount);
+
+ if ( hr == S_OK ) {
+
+ hr = pncbi->GetUpperComponent( ppnccUpper );
+
+ if ( hr == S_OK ) {
+
+ hr = pncbi->GetLowerComponent ( ppnccLower );
+ }
+ else {
+ if( ppnccUpper != NULL )
+ {
+ ReleaseObj( *ppnccUpper );
+ }
+ }
+
+ ReleaseObj( pncbi );
+ }
+
+ ReleaseObj( pencbi );
+ }
+
+ TraceMsg( L"<--CMuxNotify::HrGetUpperAndLowerComponent(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrAddAdapter
+//
+// Purpose: Create an instance representing the physical adapter and install
+// a virtual miniport.
+//
+// Arguments:
+// IN pnccAdapter: Pointer to the physical adapter.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrAddAdapter (INetCfgComponent *pnccAdapter)
+{
+ GUID guidAdapter;
+ CMuxPhysicalAdapter *pAdapter;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxNotify::HrAddAdapter.\n" );
+
+ hr = pnccAdapter->GetInstanceGuid( &guidAdapter );
+
+ if ( hr == S_OK ) {
+
+ #pragma prefast(suppress:8197, "The instance is freed in the destructor")
+ pAdapter = new CMuxPhysicalAdapter( m_pnc,
+ &guidAdapter );
+
+ if ( pAdapter ) {
+
+ hr = HrAddMiniport( pAdapter,
+ &guidAdapter );
+
+ if ( hr == S_OK ) {
+
+ m_AdaptersToAdd.Insert( pAdapter,
+ guidAdapter );
+ }
+ else {
+
+ delete pAdapter;
+ }
+ }
+ else {
+ hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+ TraceMsg( L"<--CMuxNotify::HrAddAdapter(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrRemoveAdapter
+//
+// Purpose: Deletes the instance representing the physical adapter
+// and uninstalls all the virtual miniports.
+//
+// Arguments:
+// IN pnccAdapter: Pointer to the physical adapter.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes: This function is called when the adapter or the protocol
+// is being uninstalled.
+//
+
+HRESULT CMuxNotify::HrRemoveAdapter (INetCfgComponent *pnccAdapter)
+{
+ GUID guidAdapter;
+ CMuxPhysicalAdapter *pAdapter;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxNotify::HrRemoveAdapter.\n" );
+
+ hr = pnccAdapter->GetInstanceGuid( &guidAdapter );
+
+ if ( hr == S_OK ) {
+
+ hr = m_AdaptersList.RemoveByKey( guidAdapter,
+ &pAdapter );
+
+ if ( hr == S_OK ) {
+
+ m_AdaptersToRemove.Insert( pAdapter,
+ guidAdapter );
+ hr = pAdapter->Remove();
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+ //
+ // Restore the bindings of other protocols to the physical
+ // adapter.
+ //
+
+ EnableBindings( pnccAdapter,
+ TRUE );
+#endif
+ }
+ }
+
+ TraceMsg( L"<--CMuxNotify::HrRemoveAdapter(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrAddMiniport
+//
+// Purpose: Installs a virtual miniport.
+//
+// Arguments:
+// IN pAdapter : Pointer to the physical adapter class instance.
+// IN pguidAdapter: Pointer to the GUID of the adapter.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrAddMiniport (CMuxPhysicalAdapter *pAdapter,
+ GUID *pguidAdapter)
+{
+ CMuxVirtualMiniport *pMiniport;
+ INetCfgComponent *pnccAdapter;
+ HRESULT hr = S_OK;
+
+ TraceMsg( L"-->CMuxNotify::HrAddMiniport.\n" );
+
+ //
+ // Limit the number of virtual miniports
+ //
+ if ((pAdapter->MiniportCount() + pAdapter->MiniportAddCount()) >= MAX_VIRTUAL_MP_PER_ADAPTER)
+ {
+ hr = HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES );
+ TraceMsg( L" Virtual miniport limit reached\n" );
+ }
+
+ if ( hr == S_OK )
+ {
+ #pragma prefast(suppress:8197, "The instance is freed in the destructor")
+ pMiniport = new CMuxVirtualMiniport( m_pnc,
+ NULL,
+ pguidAdapter );
+ if ( pMiniport ) {
+
+ hr = pMiniport->Install();
+
+ if ( hr == S_OK ) {
+
+ hr = pAdapter->AddMiniport( pMiniport );
+
+ if ( hr != S_OK ) {
+
+ pMiniport->DeInstall();
+
+ delete pMiniport;
+ }
+ }
+ else
+ {
+ delete pMiniport;
+ }
+ }
+ else {
+
+ hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+ if ( hr == S_OK ) {
+
+ //
+ // If this is the first virtual miniport then, disable the bindings
+ // of other protocols to the physical adapter.
+ //
+
+ if ( pAdapter->MiniportCount() == 0 ) {
+
+ hr = HrFindInstance( m_pnc,
+ *pguidAdapter,
+ &pnccAdapter );
+
+ if ( hr == S_OK ) {
+ EnableBindings( pnccAdapter,
+ FALSE );
+
+ ReleaseObj( pnccAdapter );
+ }
+ }
+ }
+#endif
+
+ TraceMsg( L"<--CMuxNotify::HrAddMiniport(HRESULT = %x).\n",
+ hr );
+ return hr;
+}
+
+//----------------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrRemoveMiniport
+//
+// Purpose: Uninstalls a virtual miniport.
+//
+// Arguments:
+// IN pAdapter : Pointer to the physical adapter class instance.
+// IN pguidAdapter: Pointer to the GUID of the adapter.
+//
+// Returns: S_OK, or an error.
+//
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrRemoveMiniport (CMuxPhysicalAdapter *pAdapter,
+ GUID *pguidAdapter)
+{
+ INetCfgComponent *pnccAdapter;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxNotify::HrRemoveMiniport.\n" );
+
+ hr = pAdapter->RemoveMiniport( NULL );
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+ if ( hr == S_OK ) {
+
+ //
+ // If this was the last miniport that was removed then, restore the
+ // bindings of other protocols to the physical adapter.
+ //
+
+ if ( pAdapter->AllMiniportsRemoved() ) {
+
+ hr = HrFindInstance( m_pnc,
+ *pguidAdapter,
+ &pnccAdapter );
+
+ if ( hr == S_OK ) {
+ EnableBindings( pnccAdapter,
+ TRUE );
+
+ ReleaseObj( pnccAdapter );
+ }
+ }
+ }
+#endif
+
+ TraceMsg( L"<--CMuxNotify::HrRemoveMiniport(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::OnInitDialog
+//
+// Purpose: Initialize controls
+//
+// Arguments:
+// IN hWnd: Window handle to the property page.
+//
+// Returns: TRUE.
+//
+// Notes:
+//
+
+LRESULT CMuxNotify::OnInitDialog (IN HWND hWndPage)
+{
+ m_eApplyAction = eActUnknown;
+
+ ::SendMessage(GetDlgItem(hWndPage, IDC_ADD), BM_SETCHECK, BST_CHECKED, 0);
+ ::SendMessage(GetDlgItem(hWndPage, IDC_REMOVE), BM_SETCHECK, BST_UNCHECKED, 0);
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::OnOk
+//
+// Purpose: Do actions when OK is pressed
+//
+// Arguments:
+// IN hWnd: Window handle to the property page.
+//
+// Returns: PSNRET_NOERROR
+//
+// Notes:
+//
+
+LRESULT CMuxNotify::OnOk (IN HWND hWndPage)
+{
+ TraceMsg(L"-->CMuxNotify::OnOk\n");
+
+ if ( ::SendMessage(GetDlgItem(hWndPage, IDC_ADD),
+ BM_GETCHECK, 0, 0) == BST_CHECKED ) {
+
+ m_eApplyAction = eActPropertyUIAdd;
+ }
+ else {
+ m_eApplyAction = eActPropertyUIRemove;
+ }
+
+ //
+ // Set the property sheet changed flag if any of our controls
+ // get changed. This is important so that we get called to
+ // apply our property changes.
+ //
+
+ PropSheet_Changed( GetParent(hWndPage), hWndPage);
+
+ TraceMsg(L"<--CMuxNotify::OnOk(Action = %s).\n",
+ (m_eApplyAction == eActPropertyUIAdd) ? L"Add" : L"Remove" );
+
+ return PSNRET_NOERROR;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::OnCancel
+//
+// Purpose: Do actions when CANCEL is pressed
+//
+// Arguments:
+// IN hWnd: Window handle to the property page.
+//
+// Returns: FALSE
+//
+// Notes:
+//
+LRESULT CMuxNotify::OnCancel (IN HWND hWndPage)
+{
+ UNREFERENCED_PARAMETER(hWndPage);
+
+ TraceMsg(L"-->CMuxNotify::OnCancel\n");
+
+ m_eApplyAction = eActUnknown;
+
+ TraceMsg(L"<--CMuxNotify::OnCancel\n");
+
+ return FALSE;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotifyDialogProc
+//
+// Purpose: Dialog proc
+//
+// Arguments:
+// IN hWnd : See win32 documentation.
+// IN uMsg : See win32 documentation.
+// IN wParam: See win32 documentation.
+// IN lParam: See win32 documentation.
+//
+// Returns: See win32 documentation.
+//
+// Notes:
+//
+INT_PTR CALLBACK NotifyDialogProc (HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ CMuxNotify *psf;
+ LRESULT lRes=FALSE;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ if ( uMsg != WM_INITDIALOG ) {
+
+ psf = (CMuxNotify *)::GetWindowLongPtr( hWnd,
+ DWLP_USER );
+
+ // Until we get WM_INITDIALOG, just return FALSE
+
+ if ( !psf ) {
+
+ return lRes;
+ }
+ }
+
+ switch( uMsg ) {
+
+ case WM_INITDIALOG:
+ {
+ PROPSHEETPAGE* ppsp;
+ ppsp = (PROPSHEETPAGE *)lParam;
+
+ psf = (CMuxNotify *)ppsp->lParam;
+
+ SetWindowLongPtr( hWnd,
+ DWLP_USER,
+ (LONG_PTR)psf);
+
+ lRes = psf->OnInitDialog( hWnd );
+ }
+ break;
+
+ case WM_COMMAND:
+
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pnmh = (LPNMHDR)lParam;
+
+ switch (pnmh->code) {
+
+ case PSN_KILLACTIVE:
+
+ //
+ // ok to loose focus.
+ //
+
+ SetWindowLongPtr( hWnd, DWLP_MSGRESULT, FALSE);
+
+ lRes = TRUE;
+ break;
+
+ case PSN_APPLY:
+
+ psf = (CMuxNotify *)::GetWindowLongPtr( hWnd, DWLP_USER);
+ lRes = psf->OnOk( hWnd );
+
+ SetWindowLongPtr( hWnd, DWLP_MSGRESULT, lRes);
+ lRes = TRUE;
+ break;
+
+ case PSN_RESET:
+
+ psf = (CMuxNotify *)::GetWindowLongPtr( hWnd, DWLP_USER);
+ psf->OnCancel( hWnd );
+ }
+ }
+ }
+
+ return lRes;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotifyPropSheetPageProc
+//
+// Purpose: Prop sheet proc
+//
+// Arguments:
+// IN hWnd: See win32 documentation
+// IN uMsg: See win32 documentation
+// IN ppsp: See win32 documentation
+//
+// Returns: See win32 documentation
+//
+// Notes:
+//
+
+UINT CALLBACK NotifyPropSheetPageProc(HWND hWnd,
+ UINT uMsg,
+ LPPROPSHEETPAGE ppsp)
+{
+ UNREFERENCED_PARAMETER(hWnd);
+ UNREFERENCED_PARAMETER(uMsg);
+ UNREFERENCED_PARAMETER(ppsp);
+
+ return TRUE;
+}
+
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::EnableBindings
+//
+// Purpose: Enable/Disable the bindings of other protocols to
+// the physical adapter.
+//
+// Arguments:
+// IN pnccAdapter: Pointer to the physical adapter.
+// IN bEnable: TRUE/FALSE to enable/disable respectively.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID CMuxNotify::EnableBindings (INetCfgComponent *pnccAdapter,
+ BOOL bEnable)
+{
+ IEnumNetCfgBindingPath *pencbp;
+ INetCfgBindingPath *pncbp;
+ HRESULT hr;
+
+ TraceMsg( L"-->CMuxNotify::EnableBindings.\n" );
+
+
+ //
+ // Get the binding path enumerator.
+ //
+
+ hr = HrGetBindingPathEnum( pnccAdapter,
+ EBP_ABOVE,
+ &pencbp );
+ if ( hr == S_OK ) {
+
+ hr = HrGetBindingPath( pencbp,
+ &pncbp );
+
+ //
+ // Traverse each binding path.
+ //
+
+ while( hr == S_OK ) {
+
+ //
+ // If our protocol does exist in the binding path then,
+ // disable it.
+ //
+
+ if ( !IfExistMux(pncbp) ) {
+
+ pncbp->Enable( bEnable );
+ }
+
+ ReleaseObj( pncbp );
+
+ hr = HrGetBindingPath( pencbp,
+ &pncbp );
+ }
+
+ ReleaseObj( pencbp );
+ }
+ else {
+ TraceMsg( L" Couldn't get the binding path enumerator, "
+ L"bindings will not be %s.\n",
+ bEnable ? L"enabled" : L"disabled" );
+ }
+
+ TraceMsg( L"<--CMuxNotify::EnableBindings.\n" );
+
+ return;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::IfExistMux
+//
+// Purpose: Determine if a given binding path contains our protocol.
+//
+// Arguments:
+// IN pncbp: Pointer to the binding path.
+//
+// Returns: TRUE if our protocol exists, otherwise FALSE.
+//
+// Notes:
+//
+
+BOOL CMuxNotify::IfExistMux (INetCfgBindingPath *pncbp)
+{
+ IEnumNetCfgBindingInterface *pencbi;
+ INetCfgBindingInterface *pncbi;
+ INetCfgComponent *pnccUpper;
+ LPWSTR lpszIdUpper;
+ HRESULT hr;
+ BOOL bExist = FALSE;
+
+ TraceMsg( L"-->CMuxNotify::IfExistMux.\n" );
+
+ //
+ // Get the binding interface enumerator.
+ //
+
+ hr = HrGetBindingInterfaceEnum( pncbp,
+ &pencbi );
+
+ if ( hr == S_OK ) {
+
+ //
+ // Traverse each binding interface.
+ //
+
+ hr = HrGetBindingInterface( pencbi,
+ &pncbi );
+
+ while( !bExist && (hr == S_OK) ) {
+
+ //
+ // Is the upper component our protocol?
+ //
+
+ hr = pncbi->GetUpperComponent( &pnccUpper );
+
+ if ( hr == S_OK ) {
+
+ hr = pnccUpper->GetId( &lpszIdUpper );
+
+ if ( hr == S_OK ) {
+
+ bExist = !_wcsicmp( lpszIdUpper, c_szMuxProtocol );
+
+ CoTaskMemFree( lpszIdUpper );
+ }
+ else {
+ TraceMsg( L" Failed to get the upper component of the interface.\n" );
+ }
+
+ ReleaseObj( pnccUpper );
+ }
+ else {
+ TraceMsg( L" Failed to get the upper component of the interface.\n" );
+ }
+
+ ReleaseObj( pncbi );
+
+ if ( !bExist ) {
+ hr = HrGetBindingInterface( pencbi,
+ &pncbi );
+ }
+ }
+
+ ReleaseObj( pencbi );
+ }
+ else {
+ TraceMsg( L" Couldn't get the binding interface enumerator.\n" );
+ }
+
+ TraceMsg( L"<--CMuxNotify::IfExistMux(BOOL = %x).\n",
+ bExist );
+
+ return bExist;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrGetBindingPathEnum
+//
+// Purpose: Returns the binding path enumerator.
+//
+// Arguments:
+// IN pnccAdapter : Pointer to the physical adapter.
+// IN dwBindingType: Type of binding path enumerator.
+// OUT ppencbp : Pointer to the binding path enumerator.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrGetBindingPathEnum (
+ INetCfgComponent *pnccAdapter,
+ DWORD dwBindingType,
+ IEnumNetCfgBindingPath **ppencbp)
+{
+ INetCfgComponentBindings *pnccb = NULL;
+ HRESULT hr;
+
+ *ppencbp = NULL;
+
+ hr = pnccAdapter->QueryInterface( IID_INetCfgComponentBindings,
+ (PVOID *)&pnccb );
+
+ if ( hr == S_OK ) {
+ hr = pnccb->EnumBindingPaths( dwBindingType,
+ ppencbp );
+
+ ReleaseObj( pnccb );
+ }
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrGetBindingPath
+//
+// Purpose: Returns a binding path.
+//
+// Arguments:
+// IN pencbp : Pointer to the binding path enumerator.
+// OUT ppncbp : Pointer to the binding path.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrGetBindingPath (IEnumNetCfgBindingPath *pencbp,
+ INetCfgBindingPath **ppncbp)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbp = NULL;
+
+ hr = pencbp->Next( 1,
+ ppncbp,
+ &ulCount );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrGetBindingInterfaceEnum
+//
+// Purpose: Returns the binding interface enumerator.
+//
+// Arguments:
+// IN pncbp : Pointer to the binding path.
+// OUT ppencbi: Pointer to the binding path enumerator.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrGetBindingInterfaceEnum (
+ INetCfgBindingPath *pncbp,
+ IEnumNetCfgBindingInterface **ppencbi)
+{
+ HRESULT hr;
+
+ *ppencbi = NULL;
+
+ hr = pncbp->EnumBindingInterfaces( ppencbi );
+
+ return hr;
+}
+
+// ----------------------------------------------------------------------
+//
+// Function: CMuxNotify::HrGetBindingInterface
+//
+// Purpose: Returns a binding interface.
+//
+// Arguments:
+// IN pencbi : Pointer to the binding interface enumerator.
+// OUT ppncbi : Pointer to the binding interface.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxNotify::HrGetBindingInterface (
+ IEnumNetCfgBindingInterface *pencbi,
+ INetCfgBindingInterface **ppncbi)
+{
+ ULONG ulCount;
+ HRESULT hr;
+
+ *ppncbi = NULL;
+
+ hr = pencbi->Next( 1,
+ ppncbi,
+ &ulCount );
+
+ return hr;
+}
+
+#endif
+
diff --git a/network/ndis/mux/notifyob/notify.h b/network/ndis/mux/notifyob/notify.h
new file mode 100644
index 00000000..08f16e00
--- /dev/null
+++ b/network/ndis/mux/notifyob/notify.h
@@ -0,0 +1,282 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: N O T I F Y . H
+//
+// Contents: Header file for sample notify object.
+//
+// Notes:
+//
+// Author: Alok Sinha
+//
+//----------------------------------------------------------------------------
+
+#ifndef NOTIFY_H_INCLUDE
+
+#define NOTIFY_H_INCLUDE
+
+#include <windows.h>
+
+#include <atlbase.h>
+extern CComModule _Module; // required by atlcom.h
+#include <atlcom.h>
+#include <devguid.h>
+#include <setupapi.h>
+
+#include <notifyn.h>
+#include "list.h"
+#include "adapter.h"
+#include "resource.h"
+#include "common.h"
+
+
+//
+// CMuxNotify Object - Base class for the entire notify object
+//
+
+
+class CMuxNotify :
+
+ //
+ // Must inherit from CComObjectRoot(Ex) for reference count
+ // management and default threading model.
+ //
+
+ public CComObjectRoot,
+
+ //
+ // Define the default class factory and aggregation model.
+ //
+
+ public CComCoClass<CMuxNotify, &CLSID_CMuxNotify>,
+
+ //
+ // Notify Object's interfaces.
+ //
+
+ public INetCfgComponentControl,
+ public INetCfgComponentSetup,
+ public INetCfgComponentPropertyUi,
+ public INetCfgComponentNotifyBinding,
+ public INetCfgComponentNotifyGlobal
+{
+
+ //
+ // Public members.
+ //
+
+ public:
+
+ //
+ // Constructor
+ //
+
+ CMuxNotify(VOID);
+
+ //
+ // Destructors.
+ //
+
+ ~CMuxNotify(VOID);
+
+ //
+ // Notify Object's interfaces.
+ //
+
+ BEGIN_COM_MAP(CMuxNotify)
+ COM_INTERFACE_ENTRY(INetCfgComponentControl)
+ COM_INTERFACE_ENTRY(INetCfgComponentSetup)
+ COM_INTERFACE_ENTRY(INetCfgComponentPropertyUi)
+ COM_INTERFACE_ENTRY(INetCfgComponentNotifyBinding)
+ COM_INTERFACE_ENTRY(INetCfgComponentNotifyGlobal)
+ END_COM_MAP()
+
+ //
+ // Uncomment the the line below if you don't want your object to
+ // support aggregation. The default is to support it
+ //
+ // DECLARE_NOT_AGGREGATABLE(CMuxNotify)
+ //
+
+ DECLARE_REGISTRY_RESOURCEID(IDR_REG_SAMPLE_NOTIFY)
+
+ //
+ // INetCfgComponentControl
+ //
+
+ STDMETHOD (Initialize) (
+ IN INetCfgComponent *pIComp,
+ IN INetCfg *pINetCfg,
+ IN BOOL fInstalling);
+
+ STDMETHOD (CancelChanges) ();
+
+ STDMETHOD (ApplyRegistryChanges) ();
+
+ STDMETHOD (ApplyPnpChanges) (
+ IN INetCfgPnpReconfigCallback* pICallback);
+
+ //
+ // INetCfgComponentSetup
+ //
+
+ STDMETHOD (Install) (
+ IN DWORD dwSetupFlags);
+
+ STDMETHOD (Upgrade) (
+ IN DWORD dwSetupFlags,
+ IN DWORD dwUpgradeFromBuildNo);
+
+ STDMETHOD (ReadAnswerFile) (
+ IN PCWSTR szAnswerFile,
+ IN PCWSTR szAnswerSections);
+
+ STDMETHOD (Removing) ();
+
+ //
+ // INetCfgComponentPropertyUi
+ //
+
+ STDMETHOD (QueryPropertyUi) (
+ IN IUnknown* pUnk);
+
+ STDMETHOD (SetContext) (
+ IN IUnknown* pUnk);
+
+ STDMETHOD (MergePropPages) (
+ IN OUT DWORD* pdwDefPages,
+ OUT LPBYTE* pahpspPrivate,
+ OUT UINT* pcPrivate,
+ IN HWND hwndParent,
+ OUT PCWSTR* pszStartPage);
+
+ STDMETHOD (ValidateProperties) (
+ HWND hwndSheet);
+
+ STDMETHOD (CancelProperties) ();
+
+ STDMETHOD (ApplyProperties) ();
+
+ //
+ // INetCfgNotifyBinding
+ //
+
+ STDMETHOD (QueryBindingPath) (
+ IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath* pncbp);
+
+ STDMETHOD (NotifyBindingPath) (
+ IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath* pncbp);
+
+ //
+ // INetCfgNotifyGlobal
+ //
+
+ STDMETHOD (GetSupportedNotifications) (
+ OUT DWORD* pdwNotificationFlag );
+
+ STDMETHOD (SysQueryBindingPath) (
+ IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath* pncbp);
+
+ STDMETHOD (SysNotifyBindingPath) (
+ IN DWORD dwChangeFlag,
+ IN INetCfgBindingPath* pncbp);
+
+ STDMETHOD (SysNotifyComponent) (
+ IN DWORD dwChangeFlag,
+ IN INetCfgComponent* pncc);
+
+ //
+ // Private members.
+ //
+
+ private:
+
+ //
+ // Private member variables.
+ //
+
+ INetCfgComponent *m_pncc; // Protocol's Net Config component
+ INetCfg *m_pnc;
+ ConfigAction m_eApplyAction;
+ IUnknown* m_pUnkContext;
+
+ //
+ // List of physical adapters currently installed.
+ //
+
+ List<CMuxPhysicalAdapter *, GUID> m_AdaptersList;
+
+ //
+ // List of physical adapters to be removed.
+ //
+
+ List<CMuxPhysicalAdapter *, GUID> m_AdaptersToRemove;
+
+ //
+ // List of physical adapters to be added.
+ //
+
+ List<CMuxPhysicalAdapter *, GUID> m_AdaptersToAdd;
+
+ //
+ // Private member functions.
+ //
+
+ HRESULT HrLoadAdapterConfiguration (VOID);
+
+ HRESULT HrGetUpperAndLower (INetCfgBindingPath* pncbp,
+ INetCfgComponent **ppnccUpper,
+ INetCfgComponent **ppnccLower);
+
+ HRESULT HrAddAdapter (INetCfgComponent *pnccAdapter);
+
+ HRESULT HrRemoveAdapter (INetCfgComponent *pnccAdapter);
+
+ HRESULT HrAddMiniport (CMuxPhysicalAdapter *pAdapter,
+ GUID *guidAdapter);
+
+ HRESULT HrRemoveMiniport (CMuxPhysicalAdapter *pAdapter,
+ GUID *guidAdapter);
+
+#ifdef DISABLE_PROTOCOLS_TO_PHYSICAL
+
+ VOID EnableBindings (INetCfgComponent *pnccAdapter,
+ BOOL bEnable);
+
+ BOOL IfExistMux (INetCfgBindingPath *pncbp);
+
+ HRESULT HrGetBindingPathEnum (INetCfgComponent *pnccAdapter,
+ DWORD dwBindingType,
+ IEnumNetCfgBindingPath **ppencbp);
+
+ HRESULT HrGetBindingPath (IEnumNetCfgBindingPath *pencbp,
+ INetCfgBindingPath **ppncbp);
+
+ HRESULT HrGetBindingInterfaceEnum (INetCfgBindingPath *pncbp,
+ IEnumNetCfgBindingInterface **ppencbi);
+
+ HRESULT HrGetBindingInterface (IEnumNetCfgBindingInterface *pencbi,
+ INetCfgBindingInterface **ppncbi);
+#endif
+
+ public:
+
+ LRESULT OnInitDialog (IN HWND hWnd);
+ LRESULT OnOk (IN HWND hWnd);
+ LRESULT OnCancel (IN HWND hWnd);
+};
+
+
+INT_PTR CALLBACK NotifyDialogProc (HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam);
+UINT CALLBACK NotifyPropSheetPageProc (HWND hWnd,
+ UINT uMsg,
+ LPPROPSHEETPAGE ppsp);
+#endif // NOTIFY_H_INCLUDE
diff --git a/network/ndis/mux/notifyob/notify.htm b/network/ndis/mux/notifyob/notify.htm
new file mode 100644
index 00000000..6fe84b68
--- /dev/null
+++ b/network/ndis/mux/notifyob/notify.htm
@@ -0,0 +1,552 @@
+<html xmlns:v="urn:schemas-microsoft-com:vml"
+xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns:p="urn:schemas-microsoft-com:office:powerpoint"
+xmlns:oa="urn:schemas-microsoft-com:office:activation"
+xmlns:st1="urn:schemas-microsoft-com:office:smarttags"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 11">
+<meta name=Originator content="Microsoft Word 11">
+<link rel=File-List href="notify_files/filelist.xml">
+<title>Mux.dll - Sample Notify Object</title>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="place"/>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="PlaceType"/>
+<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
+ name="PlaceName"/>
+<!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:SpellingState>Clean</w:SpellingState>
+ <w:GrammarState>Clean</w:GrammarState>
+ <w:ValidateAgainstSchemas/>
+ <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
+ <w:IgnoreMixedContent>false</w:IgnoreMixedContent>
+ <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
+ <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
+ </w:WordDocument>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:LatentStyles DefLockedState="false" LatentStyleCount="156">
+ </w:LatentStyles>
+</xml><![endif]--><!--[if !mso]><object
+ classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui></object>
+<style>
+st1\:*{behavior:url(#ieooui) }
+</style>
+<![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+ @font-face
+ {font-family:SimSun;
+ panose-1:2 1 6 0 3 1 1 1 1 1;
+ mso-font-alt:\5B8B\4F53;
+ mso-font-charset:134;
+ mso-generic-font-family:auto;
+ mso-font-format:other;
+ mso-font-pitch:variable;
+ mso-font-signature:1 135135232 16 0 262144 0;}
+@font-face
+ {font-family:Verdana;
+ panose-1:2 11 6 4 3 5 4 4 2 4;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:536871559 0 0 0 415 0;}
+@font-face
+ {font-family:"MS Sans Serif";
+ panose-1:0 0 0 0 0 0 0 0 0 0;
+ mso-font-alt:"Times New Roman";
+ mso-font-charset:0;
+ mso-generic-font-family:roman;
+ mso-font-format:other;
+ mso-font-pitch:auto;
+ mso-font-signature:0 0 0 0 0 0;}
+@font-face
+ {font-family:"\@SimSun";
+ mso-font-charset:134;
+ mso-generic-font-family:auto;
+ mso-font-pitch:variable;
+ mso-font-signature:3 135135232 16 0 262145 0;}
+ /* Style Definitions */
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+h1
+ {mso-style-next:Normal;
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ page-break-after:avoid;
+ mso-outline-level:1;
+ font-size:10.0pt;
+ font-family:Verdana;
+ mso-fareast-font-family:SimSun;
+ mso-font-kerning:0pt;
+ font-weight:bold;}
+h2
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:2;
+ font-size:18.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:SimSun;
+ font-weight:bold;}
+h3
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:3;
+ font-size:13.5pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:SimSun;
+ font-weight:bold;}
+h4
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ mso-outline-level:4;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:SimSun;
+ font-weight:bold;}
+a:link, span.MsoHyperlink
+ {color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+a:visited, span.MsoHyperlinkFollowed
+ {color:blue;
+ text-decoration:underline;
+ text-underline:single;}
+p
+ {mso-margin-top-alt:auto;
+ margin-right:0in;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+pre
+ {margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt;
+ font-size:10.0pt;
+ font-family:"Courier New";
+ mso-fareast-font-family:"Courier New";}
+span.SpellE
+ {mso-style-name:"";
+ mso-spl-e:yes;}
+span.GramE
+ {mso-style-name:"";
+ mso-gram-e:yes;}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.25in 1.0in 1.25in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+ /* List Definitions */
+ @list l0
+ {mso-list-id:354117224;
+ mso-list-type:hybrid;
+ mso-list-template-ids:-730287492 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
+@list l0:level1
+ {mso-level-number-format:bullet;
+ mso-level-text:\F0B7;
+ mso-level-tab-stop:.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;
+ font-family:Symbol;}
+@list l0:level2
+ {mso-level-tab-stop:1.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level3
+ {mso-level-tab-stop:1.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level4
+ {mso-level-tab-stop:2.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level5
+ {mso-level-tab-stop:2.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level6
+ {mso-level-tab-stop:3.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level7
+ {mso-level-tab-stop:3.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level8
+ {mso-level-tab-stop:4.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l0:level9
+ {mso-level-tab-stop:4.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1
+ {mso-list-id:379671731;
+ mso-list-type:hybrid;
+ mso-list-template-ids:-1929328134 67698705 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
+@list l1:level1
+ {mso-level-text:"%1\)";
+ mso-level-tab-stop:.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level2
+ {mso-level-tab-stop:1.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level3
+ {mso-level-tab-stop:1.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level4
+ {mso-level-tab-stop:2.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level5
+ {mso-level-tab-stop:2.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level6
+ {mso-level-tab-stop:3.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level7
+ {mso-level-tab-stop:3.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level8
+ {mso-level-tab-stop:4.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l1:level9
+ {mso-level-tab-stop:4.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2
+ {mso-list-id:1626816921;
+ mso-list-type:hybrid;
+ mso-list-template-ids:-553597382 67698705 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
+@list l2:level1
+ {mso-level-text:"%1\)";
+ mso-level-tab-stop:.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level2
+ {mso-level-tab-stop:1.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level3
+ {mso-level-tab-stop:1.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level4
+ {mso-level-tab-stop:2.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level5
+ {mso-level-tab-stop:2.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level6
+ {mso-level-tab-stop:3.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level7
+ {mso-level-tab-stop:3.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level8
+ {mso-level-tab-stop:4.0in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+@list l2:level9
+ {mso-level-tab-stop:4.5in;
+ mso-level-number-position:left;
+ text-indent:-.25in;}
+ol
+ {margin-bottom:0in;}
+ul
+ {margin-bottom:0in;}
+-->
+</style>
+<!--[if gte mso 10]>
+<style>
+ /* Style Definitions */
+ table.MsoNormalTable
+ {mso-style-name:"Table Normal";
+ mso-tstyle-rowband-size:0;
+ mso-tstyle-colband-size:0;
+ mso-style-noshow:yes;
+ mso-style-parent:"";
+ mso-padding-alt:0in 5.4pt 0in 5.4pt;
+ mso-para-margin:0in;
+ mso-para-margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:10.0pt;
+ font-family:"Times New Roman";
+ mso-ansi-language:#0400;
+ mso-fareast-language:#0400;
+ mso-bidi-language:#0400;}
+</style>
+<![endif]-->
+</head>
+
+<body lang=EN-US link=blue vlink=blue style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<h2><span style='font-family:Verdana'>MUX.DLL � Sample Notify Object <o:p></o:p></span></h2>
+
+<h3><span style='font-family:Verdana'>SUMMARY<o:p></o:p></span></h3>
+
+<h3><span style='font-size:12.0pt;font-family:Verdana'>MUX Notify Object<o:p></o:p></span></h3>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>This sample demonstrates
+how to write a notify object for installing and configuring an NDIS MUX intermediate
+miniport (IM) driver that implements an N:1 relationship between upper and
+lower bindings, i.e. it creates multiple virtual network devices on top of a
+single lower adapter. Protocols bind to these virtual adapters as if they are
+real adapters. Examples of <st1:place w:st="on"><st1:PlaceName w:st="on">Intermediate</st1:PlaceName>
+ <st1:PlaceType w:st="on">Miniport</st1:PlaceType></st1:place> drivers that can
+use this type of notify <span class=GramE>object are</span> Virtual LAN (VLAN)
+drivers.<o:p></o:p></span></p>
+
+<p><b style='mso-bidi-font-weight:normal'><span style='font-family:Verdana'>Operation</span></b><span
+style='font-family:Verdana'><o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>During installation, the
+notify object performs the following operations.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo2;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol'><span
+style='mso-list:Ignore'>�<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>It
+creates one virtual adapter for each physical adapter the MUX protocol edge
+binds to.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo2;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol'><span
+style='mso-list:Ignore'>�<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>It
+disables the bindings of other protocols such as TCP/IP to physical adapters if
+it has been compiled with DISABLE_PROTOCOLS_TO_PHYSICAL defined in the Sources
+file. This is the most commonly desired behavior for N:1 MUX drivers.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo2;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Symbol;mso-fareast-font-family:Symbol;mso-bidi-font-family:Symbol'><span
+style='mso-list:Ignore'>�<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>It
+disables the bindings of the protocol edge of the MUX IM driver with all its
+virtual adapters.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The notify object
+provides a custom property page for the MUX IM driver. The custom property page
+allows the user to add one or more virtual adapters on top of a physical
+adapter or delete an existing virtual adapter.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>When the MUX IM driver is
+uninstalled, or binding is disabled, or the user deletes all the virtual
+adapters on top of a physical adapter, the notify object restores the bindings
+of other protocols to the physical adapter if it has been compiled with the
+preprocessor flag DISABLE_PROTOCOLS_TO_PHYSICAL defined in the Sources file.<o:p></o:p></span></p>
+
+<p><b style='mso-bidi-font-weight:normal'><span style='font-size:10.0pt;
+font-family:Verdana'>Windows 2000 Specific<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>During the installation,
+the notify object copies the INF file for the virtual adapter from the
+installation media to the system INF directory by using the <span class=SpellE>SetupCopyOEMInf</span>
+function. This is done because Windows 2000 does not support the <span
+class=SpellE>CopyINF</span> directive to copy INF files from another INF file.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>BUILDING THE SAMPLE<o:p></o:p></span></h3>
+
+<p style='tab-stops:657.0pt'><span style='font-size:10.0pt;font-family:Verdana'>To
+build the sample, type <b>build -ceZ</b>. This command produces the binary
+mux.dll, which is the sample notify object.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The sample compiles
+properly for 32-bit and 64-bit systems, and builds properly with Microsoft�
+Visual C� 6.0.<o:p></o:p></span></p>
+
+<p><b style='mso-bidi-font-weight:normal'><span style='font-size:10.0pt;
+font-family:Verdana'>Preprocessor Flags:<o:p></o:p></span></b></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>DISABLE_PROTOCOLS_TO_PHYSICAL<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>When this flag is defined
+in the Sources file, the notify object disables the bindings of other protocols
+such as TCP/IP to the physical adapters during the installation. When all the
+virtual adapters are removed either through the custom property page or as a
+result of uninstalling the MUX driver, the notify object re-enables those
+bindings.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>PASSTHRU_NOTIFY<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>This flag is defined to
+allow the MUX driver to be used in a passthru mode. When this flag is defined,
+the notify object:<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l1 level1 lfo4;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>1)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Creates
+only one virtual miniport for every physical adapter the MUX protocol edge
+binds to.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l1 level1 lfo4;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>2)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Disables
+the property page to prevent adding of additional virtual miniports. <o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l1 level1 lfo4;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>3)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Stores
+the device name of the virtual adapter in REG_SZ registry value under
+HKLM\System\<span class=SpellE>CurrentControlSet\Services\muxp\Parameters\Adapters</span><span
+class=GramE>\{</span><span class=SpellE><i style='mso-bidi-font-style:normal'>PhysicalAdaptersInstanceGuid</i></span><i
+style='mso-bidi-font-style:normal'>}\</i><span class=SpellE>UpperBindings</span>,
+because there is one to one binding. In the MUX mode (when this flag is not
+defined), the notify object stores the device name in a REG_MULTI_SZ registry
+value as there could be more than one virtual miniports.<o:p></o:p></span></p>
+
+<p style='margin-left:.25in'><span style='font-size:10.0pt;font-family:Verdana'>You
+can also use this notify object with the Passthru driver by doing the
+following:<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo6;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>1)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Change
+the protocol name in file <span class=SpellE>src\network\ndis\passthru\passthru.c</span>
+from PASSTHRU to MUXP.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo6;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>2)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Change
+the driver name from Passthru to MUX in the sources file.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo6;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>3)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Rebuild
+the driver to obtain a mux.sys driver binary.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo6;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>4)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Build
+the MUX notify object with PASSTHRU_NOTIFY defined.<o:p></o:p></span></p>
+
+<p style='margin-left:.5in;text-indent:-.25in;mso-list:l2 level1 lfo6;
+tab-stops:list .5in'><![if !supportLists]><span style='font-size:10.0pt;
+font-family:Verdana;mso-fareast-font-family:Verdana;mso-bidi-font-family:Verdana'><span
+style='mso-list:Ignore'>5)<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;
+</span></span></span><![endif]><span style='font-size:10.0pt;font-family:Verdana'>Use
+the MUX <span class=SpellE><span class=GramE>inf</span></span> files, <span
+class=SpellE>muxp.inf</span> and <span class=SpellE>mux_mp.inf</span>, to
+install the driver and <span class=SpellE>dll</span>.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>The benefit of using
+techniques in the MUX notify object for a 1:1 intermediate driver (e.g.
+Passthru) is to be able to exercise higher level of control over the bindings
+of MUX with other components in the system, which is not possible with the IM
+filter driver.<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>CUSTOM_EVENTS<o:p></o:p></span></p>
+
+<p><span style='font-size:10.0pt;font-family:Verdana'>When this macro is
+defined, the notify object shows how to send custom events to the MUX IM driver
+when a virtual miniport is added or removed.<o:p></o:p></span></p>
+
+<h3><span style='font-family:Verdana'>CODE TOUR<o:p></o:p></span></h3>
+
+<h4><span style='font-family:Verdana'>File Manifest<o:p></o:p></span></h4>
+
+<pre><u>File<span style='mso-tab-count:2'>���������� </span>Description<o:p></o:p></u></pre><pre><span
+class=SpellE>Dllmain.cpp</span><span style='mso-tab-count:1'>��� </span>File containing implementations of DLL entry point and exports. </pre><pre><span
+class=SpellE>Implinc.cpp</span><span style='mso-tab-count:1'>��� </span>File including source code for ATL utilities.</pre><pre>mux.htm<span
+style='mso-tab-count:2'>������� </span>The documentation for this sample.</pre><pre><span
+class=SpellE>Pch.h</span><span style='mso-tab-count:2'>��������� </span>Pre-compiled header file.</pre><pre><span
+class=SpellE>Resource.h</span><span style='mso-tab-count:1'>���� </span>The resource header.</pre><pre><span
+class=SpellE>notify.cpp</span><span style='mso-tab-count:1'>���� </span>Notify object implementation.</pre><pre><span
+class=SpellE>virtual.cpp</span><span style='mso-tab-count:1'>��� </span>Virtual adapter class implementation.</pre><pre><span
+class=SpellE>adapter.cpp</span><span style='mso-tab-count:1'>��� </span>Physical adapter class implementation.</pre><pre><span
+class=SpellE>common.cpp</span><span style='mso-tab-count:1'>���� </span>Global functions, variables and macro definitions.</pre><pre><span
+class=SpellE>mux.def</span><span style='mso-tab-count:2'>������� </span>The sample's linker definition file.</pre><pre><span
+class=SpellE>mux.h</span><span style='mso-tab-count:2'>��������� </span>The header file for <span
+class=SpellE>mux.cpp</span>.</pre><pre><span class=SpellE>virtual.h</span><span
+style='mso-tab-count:1'>����� </span>Virtual adapter class declaration.</pre><pre><span
+class=SpellE>Adapter.h</span><span style='mso-tab-count:1'>����� </span>Physical adapter class declaration.</pre><pre><span
+class=SpellE>notify.rc</span><span style='mso-tab-count:1'>����� </span>The resource file.</pre><pre><span
+class=SpellE>notify.rgs</span><span style='mso-tab-count:1'>���� </span>Script-based registry.</pre><pre><span
+class=SpellE>notifyn.idl</span><span style='mso-tab-count:1'>��� </span>The notify object's .<span
+class=SpellE>idl</span> file.</pre><pre><span class=SpellE>setupdi.cpp</span><span
+style='mso-tab-count:1'>��� </span>Functions to copy the miniport INF file to the system.</pre><pre><o:p>&nbsp;</o:p></pre>
+
+<p align=center style='text-align:center;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b
+style='mso-bidi-font-weight:normal'><a href="#_top"><span style='font-size:
+10.0pt;font-family:Verdana;font-weight:normal'>Top of page</span></a></b><span
+style='font-size:10.0pt;font-family:Verdana'> <o:p></o:p></span></p>
+
+<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=624
+ style='width:6.5in;mso-cellspacing:0in;mso-padding-alt:0in 0in 0in 0in'>
+ <tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes;
+ height:1.5pt'>
+ <td style='background:aqua;padding:.75pt .75pt .75pt .75pt;height:1.5pt'>
+ <p class=MsoNormal><o:p>&nbsp;</o:p></p>
+ </td>
+ </tr>
+</table>
+
+<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span
+style='font-size:7.5pt;font-family:"MS Sans Serif"'>� 2004 Microsoft
+Corporation</span><span style='font-size:10.0pt;font-family:Verdana'><o:p></o:p></span></p>
+
+</div>
+
+</body>
+
+</html>
+ \ No newline at end of file
diff --git a/network/ndis/mux/notifyob/notifyn.idl b/network/ndis/mux/notifyob/notifyn.idl
new file mode 100644
index 00000000..319ddbfd
--- /dev/null
+++ b/network/ndis/mux/notifyob/notifyn.idl
@@ -0,0 +1,34 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: NOTIFYN.IDL
+//
+// Contents:
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+#include <netcfgn.idl>
+
+[
+ uuid(58dbe723-da1a-484c-9f5b-113ba31869f2),
+ version(1.0),
+ helpstring("Sample Notify Object 1.0 Type Library")
+]
+library SampleNotifyLib
+{
+ [
+ uuid(ee6cd6fc-a32b-4a26-8a1c-dbc97988ad7a),
+ helpstring("Sample MUX Notify Class")
+ ]
+ coclass CMuxNotify
+ {
+ [restricted] interface INetCfgComponentControl;
+ [restricted] interface INetCfgComponentSetup;
+ [restricted] interface INetCfgComponentNotifyBinding;
+ [restricted] interface INetCfgComponentNotifyGlobal;
+ [restricted] interface INetCfgComponentPropertyUi;
+ };
+};
diff --git a/network/ndis/mux/notifyob/public.h b/network/ndis/mux/notifyob/public.h
new file mode 100644
index 00000000..3d6147fc
--- /dev/null
+++ b/network/ndis/mux/notifyob/public.h
@@ -0,0 +1,47 @@
+/*++
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Author:
+
+
+Environment:
+
+ user and kernel
+Notes:
+
+
+Revision History:
+
+
+--*/
+#ifndef __PUBLIC_H
+#define __PUBLIC_H
+
+//
+// To support ioctls from user-mode:
+//
+
+#define LINKNAME_STRING L"\\DosDevices\\Mux"
+#define NTDEVICE_STRING L"\\Device\\Mux"
+
+#define MUX_CUSTOM_EVENT 1
+
+#define NOTIFY_SIGNATURE 0xAFCDABAB
+
+typedef struct _NOTIFY_CUSTOM_EVENT {
+ ULONG uSignature;
+ ULONG uEvent;
+ WCHAR szMiniport[1];
+} NOTIFY_CUSTOM_EVENT, *PNOTIFY_CUSTOM_EVENT;
+#endif
+
+
diff --git a/network/ndis/mux/notifyob/resource.h b/network/ndis/mux/notifyob/resource.h
new file mode 100644
index 00000000..498c95d8
--- /dev/null
+++ b/network/ndis/mux/notifyob/resource.h
@@ -0,0 +1,12 @@
+#ifndef RESOURCE_H_INCLUDE
+
+#define RESOURCE_H_INCLUDE
+
+#define IDR_REG_SAMPLE_NOTIFY 40001
+
+#define IDD_NOTIFY_GENERAL 1850
+#define IDC_STATIC -1
+#define IDC_ADD 100
+#define IDC_REMOVE 200
+
+#endif
diff --git a/network/ndis/mux/notifyob/virtual.cpp b/network/ndis/mux/notifyob/virtual.cpp
new file mode 100644
index 00000000..5b6cde80
--- /dev/null
+++ b/network/ndis/mux/notifyob/virtual.cpp
@@ -0,0 +1,512 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: V I R T U A L . C P P
+//
+// Contents: Virtual miniport class definition.
+//
+// Notes:
+//
+// Author: Alok Sinha
+//----------------------------------------------------------------------------
+
+#include "virtual.h"
+#include "common.h"
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::CMuxVirtualMiniport
+//
+// Purpose: Constructor for class CMuxVirtualMiniport
+//
+// Arguments: None
+//
+// Returns:
+//
+// Notes:
+//
+
+CMuxVirtualMiniport::CMuxVirtualMiniport(INetCfg *pnc,
+ GUID *pguidMiniport,
+ GUID *pguidAdapter)
+{
+ TraceMsg( L"-->CMuxVirtualMiniport::CMuxVirtualMiniport(Constructor).\n" );
+
+ m_pnc = pnc;
+ m_pnc->AddRef();
+
+ CopyMemory( &m_guidAdapter,
+ pguidAdapter,
+ sizeof(GUID) );
+
+ if ( pguidMiniport ) {
+
+ CopyMemory( &m_guidMiniport,
+ pguidMiniport,
+ sizeof(GUID) );
+
+ }
+ else {
+
+ ZeroMemory( &m_guidMiniport,
+ sizeof(GUID) );
+ }
+
+ TraceMsg( L"<--CMuxVirtualMiniport::CMuxVirtualMiniport(Constructor).\n" );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::~CMuxVirtualMiniport
+//
+// Purpose: Destructor for class CMuxVirtualMiniport
+//
+// Arguments: None
+//
+// Returns:
+//
+// Notes:
+//
+
+CMuxVirtualMiniport::~CMuxVirtualMiniport(VOID)
+{
+ TraceMsg( L"-->CMuxVirtualMiniport::~CMuxVirtualMiniport(Destructor).\n" );
+
+ ReleaseObj( m_pnc );
+
+ TraceMsg( L"<--CMuxVirtualMiniport::~CMuxVirtualMiniport(Destructor).\n" );
+
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::LoadConfiguration
+//
+// Purpose: Load miniport configuration from the registry.
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxVirtualMiniport::LoadConfiguration(VOID)
+{
+ TraceMsg( L"-->CMuxVirtualMiniport::LoadConfiguration.\n" );
+
+ TraceMsg( L"<--CMuxVirtualMiniport::LoadConfiguration(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::GetAdapterGUID
+//
+// Purpose: Returns the adapter GUID.
+//
+// Arguments:
+// OUT pguidAdapter: GUID of the adapter returned.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID CMuxVirtualMiniport::GetAdapterGUID (GUID *pguidAdapter)
+{
+ TraceMsg( L"-->CMuxVirtualMiniport::GetAdapterGUID.\n" );
+
+ CopyMemory( pguidAdapter,
+ &m_guidAdapter,
+ sizeof(GUID) );
+
+ TraceMsg( L"<--CMuxVirtualMiniport::GetAdapterGUID.\n" );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::GetMiniportGUID
+//
+// Purpose: Returns the miniport GUID.
+//
+// Arguments:
+// OUT pguidMiniport: GUID of the miniport returned.
+//
+// Returns: None.
+//
+// Notes:
+//
+
+VOID CMuxVirtualMiniport::GetMiniportGUID (GUID *pguidMiniport)
+{
+ TraceMsg( L"-->CMuxVirtualMiniport::GetMiniportGUID.\n" );
+
+ CopyMemory( pguidMiniport,
+ &m_guidMiniport,
+ sizeof(GUID) );
+
+ TraceMsg( L"<--CMuxVirtualMiniport::GetMiniportGUID.\n" );
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::Install
+//
+// Purpose: Installs a virtual miniport.
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxVirtualMiniport::Install (VOID)
+{
+ INetCfgClass *pncClass;
+ INetCfgClassSetup *pncClassSetup;
+ INetCfgComponent *pnccMiniport;
+ HRESULT hr;
+ LPWSTR *pmszwRefs=NULL;
+ OBO_TOKEN *pOboToken=NULL;
+ DWORD dwSetupFlags=0;
+ LPCWSTR pszwAnswerFile=NULL;
+ LPCWSTR pszwAnswerSections=NULL;
+
+
+ TraceMsg( L"-->CMuxVirtualMiniport::Install.\n" );
+
+ hr = m_pnc->QueryNetCfgClass( &GUID_DEVCLASS_NET,
+ IID_INetCfgClass,
+ (void **)&pncClass );
+ if ( hr == S_OK ) {
+
+ hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+ (void **)&pncClassSetup );
+ if ( hr == S_OK ) {
+
+ hr = pncClassSetup->Install( c_szMuxMiniport,
+ pOboToken,
+ dwSetupFlags,
+ 0,
+ pszwAnswerFile,
+ pszwAnswerSections,
+ &pnccMiniport );
+ if ( hr == S_OK ) {
+
+ hr = pnccMiniport->GetInstanceGuid( &m_guidMiniport );
+
+ if ( hr != S_OK ) {
+
+ TraceMsg( L" Failed to get the instance guid, uninstalling "
+ L" the miniport.\n" );
+
+ pncClassSetup->DeInstall( pnccMiniport,
+ pOboToken,
+ pmszwRefs );
+ }
+
+ ReleaseObj( pnccMiniport );
+ }
+ else {
+
+ TraceMsg( L" Failed to install the miniport.\n" );
+ }
+
+ ReleaseObj( pncClassSetup );
+ }
+ else {
+
+ TraceMsg( L" QueryInterface failed.\n" );
+ }
+
+ ReleaseObj( pncClass );
+ }
+ else {
+
+ TraceMsg( L" QueryNetCfgClass failed.\n" );
+ }
+
+ TraceMsg( L"<--CMuxVirtualMiniport::Install(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::DeInstall
+//
+// Purpose: Uninstalls the virtual miniport.
+//
+// Arguments: None
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxVirtualMiniport::DeInstall (VOID)
+{
+ INetCfgClass *pncClass;
+ INetCfgClassSetup *pncClassSetup;
+ INetCfgComponent *pnccMiniport;
+ HRESULT hr;
+ LPWSTR *pmszwRefs=NULL;
+ OBO_TOKEN *pOboToken=NULL;
+
+ TraceMsg( L"-->CMuxVirtualMiniport::DeInstall.\n" );
+
+ hr = m_pnc->QueryNetCfgClass( &GUID_DEVCLASS_NET,
+ IID_INetCfgClass,
+ (void **)&pncClass );
+ if ( hr == S_OK ) {
+
+ hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+ (void **)&pncClassSetup );
+ if ( hr == S_OK ) {
+
+ hr = HrFindInstance( m_pnc,
+ m_guidMiniport,
+ &pnccMiniport );
+
+ if ( hr == S_OK ) {
+
+ TraceMsg( L" Found the miniport instance to uninstall.\n" );
+
+ hr = pncClassSetup->DeInstall( pnccMiniport,
+ pOboToken,
+ pmszwRefs );
+ ReleaseObj( pnccMiniport );
+ }
+ else {
+ TraceMsg( L" Didn't find the miniport instance to uninstall.\n" );
+ }
+
+ ReleaseObj( pncClassSetup );
+ }
+ else {
+
+ TraceMsg( L" QueryInterface failed.\n" );
+ }
+
+ ReleaseObj( pncClass );
+ }
+ else {
+
+ TraceMsg( L" QueryNetCfgClass failed.\n" );
+ }
+
+ TraceMsg( L"<--CMuxVirtualMiniport::DeInstall(HRESULT = %x).\n",
+ hr );
+
+ return hr;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::ApplyRegistryChanges
+//
+// Purpose: Store the changes in the registry.
+//
+// Arguments:
+// IN eApplyAction: Action performed.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxVirtualMiniport::ApplyRegistryChanges(ConfigAction eApplyAction)
+{
+ HKEY hkeyAdapterGuid;
+ WCHAR szAdapterGuid[MAX_PATH+1];
+ WCHAR szAdapterGuidKey[MAX_PATH+1];
+ WCHAR szMiniportGuid[MAX_PATH+1];
+ LPWSTR lpDevice;
+ LONG lResult = 0;
+
+ TraceMsg( L"-->CMuxVirtualMiniport::ApplyRegistryChanges.\n" );
+
+ switch( eApplyAction ) {
+
+ case eActAdd: // Virtual miniport added.
+
+ StringFromGUID2( m_guidAdapter,
+ szAdapterGuid,
+ MAX_PATH+1 );
+
+ StringCchPrintfW ( szAdapterGuidKey,
+ celems(szAdapterGuidKey),
+ L"%s\\%s",
+ c_szAdapterList,
+ szAdapterGuid );
+
+ szAdapterGuidKey[MAX_PATH]='\0';
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ szAdapterGuidKey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterGuid,
+ NULL);
+
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ StringFromGUID2( m_guidMiniport,
+ szMiniportGuid,
+ MAX_PATH+1 );
+
+ lpDevice = AddDevicePrefix( szMiniportGuid );
+
+ if ( lpDevice ) {
+
+#ifndef PASSTHRU_NOTIFY
+
+ lResult = AddToMultiSzValue( hkeyAdapterGuid,
+ lpDevice );
+#else
+
+ lResult = RegSetValueExW( hkeyAdapterGuid,
+ c_szUpperBindings,
+ 0,
+ REG_SZ,
+ (LPBYTE)lpDevice,
+ (wcslen(lpDevice) + 1) *
+ sizeof(WCHAR) );
+
+
+#endif
+
+ if ( lResult != ERROR_SUCCESS ) {
+
+ TraceMsg( L" Failed to save %s at %s\\%s.\n",
+ lpDevice,
+ szAdapterGuidKey,
+ c_szUpperBindings );
+
+ }
+
+ free( lpDevice );
+ }
+ else {
+ lResult = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RegCloseKey( hkeyAdapterGuid );
+ }
+ else {
+ TraceMsg( L" Failed to open the registry key: %s.\n",
+ szAdapterGuidKey );
+ }
+ break;
+
+ case eActRemove: // Virtual miniport removed.
+
+ StringFromGUID2( m_guidAdapter,
+ szAdapterGuid,
+ MAX_PATH+1 );
+
+ StringCchPrintfW( szAdapterGuidKey,
+ celems(szAdapterGuidKey),
+ L"%s\\%s",
+ c_szAdapterList,
+ szAdapterGuid );
+ szAdapterGuidKey[MAX_PATH]='\0';
+ lResult = RegCreateKeyExW( HKEY_LOCAL_MACHINE,
+ szAdapterGuidKey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkeyAdapterGuid,
+ NULL);
+
+
+ if ( lResult == ERROR_SUCCESS ) {
+
+ StringFromGUID2( m_guidMiniport,
+ szMiniportGuid,
+ MAX_PATH+1 );
+
+ lpDevice = AddDevicePrefix( szMiniportGuid );
+ TraceMsg( L" Deleting %s at %s.\n",
+ lpDevice,
+ szAdapterGuidKey );
+
+ if ( lpDevice ) {
+
+#ifndef PASSTHRU_NOTIFY
+
+ lResult = DeleteFromMultiSzValue( hkeyAdapterGuid,
+ lpDevice );
+#else
+
+ lResult = RegDeleteValueW( hkeyAdapterGuid,
+ c_szUpperBindings );
+#endif
+
+ if ( lResult != ERROR_SUCCESS ) {
+
+ TraceMsg( L" Failed to delete %s at %s\\%s.\n",
+ lpDevice,
+ szAdapterGuidKey,
+ c_szUpperBindings );
+
+ }
+
+ free( lpDevice );
+ }
+
+ RegCloseKey( hkeyAdapterGuid );
+ }
+ else {
+ TraceMsg( L" Failed to open the registry key: %s.\n",
+ szAdapterGuidKey );
+ }
+ }
+
+ TraceMsg( L"<--CMuxVirtualMiniport::ApplyRegistryChanges(HRESULT = %x).\n",
+ HRESULT_FROM_WIN32(lResult) );
+
+ return HRESULT_FROM_WIN32(lResult);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: CMuxVirtualMiniport::ApplyPnpChanges
+//
+// Purpose:
+//
+// Arguments:
+// IN eApplyAction: Action performed.
+//
+// Returns: S_OK on success, otherwise an error code.
+//
+// Notes:
+//
+
+HRESULT CMuxVirtualMiniport::ApplyPnpChanges
+ (INetCfgPnpReconfigCallback *pfCallback,
+ ConfigAction eApplyAction)
+{
+ UNREFERENCED_PARAMETER(pfCallback);
+ UNREFERENCED_PARAMETER(eApplyAction);
+
+ TraceMsg( L"-->CMuxVirtualMiniport::ApplyPnpChanges.\n" );
+
+ TraceMsg( L"<--CMuxVirtualMiniport::ApplyPnpChanges(HRESULT = %x).\n",
+ S_OK );
+
+ return S_OK;
+}
+
diff --git a/network/ndis/mux/notifyob/virtual.h b/network/ndis/mux/notifyob/virtual.h
new file mode 100644
index 00000000..5cb8f050
--- /dev/null
+++ b/network/ndis/mux/notifyob/virtual.h
@@ -0,0 +1,68 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992-2001.
+//
+// File: V I R T U A L . H
+//
+// Contents: Header file for virtual miniport class.
+//
+// Notes:
+//
+// Author: Alok Sinha
+//
+//----------------------------------------------------------------------------
+
+#ifndef VIRTUAL_H_INCLUDED
+
+#define VIRTUAL_H_INCLUDE
+
+#include <windows.h>
+#include <stdio.h>
+#include "netcfgn.h"
+
+#include "common.h"
+
+//
+// Class to represent a virtual miniport created by IM driver.
+//
+
+class CMuxVirtualMiniport
+{
+ //
+ // Private member variables.
+ //
+
+ INetCfg *m_pnc;
+ GUID m_guidAdapter;
+ GUID m_guidMiniport;
+
+ //
+ // Public members.
+ //
+
+ public:
+
+ CMuxVirtualMiniport(INetCfg *m_pnc,
+ GUID *pguidMiniport,
+ GUID *guidAdapter);
+
+ virtual ~CMuxVirtualMiniport(VOID);
+
+ HRESULT LoadConfiguration(VOID);
+
+ VOID GetAdapterGUID (GUID *);
+
+ VOID GetMiniportGUID (GUID *);
+
+ HRESULT Install (VOID);
+
+ HRESULT DeInstall (VOID);
+
+ HRESULT ApplyRegistryChanges (ConfigAction eApplyAction);
+
+ HRESULT ApplyPnpChanges (INetCfgPnpReconfigCallback *pfCallback,
+ ConfigAction eApplyAction);
+};
+
+#endif // VIRTUAL_H_INCLUDED \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/ReadMe.md b/network/ndis/ndisprot/6x/ReadMe.md
new file mode 100644
index 00000000..63e3a5ec
--- /dev/null
+++ b/network/ndis/ndisprot/6x/ReadMe.md
@@ -0,0 +1,84 @@
+NDIS Connection-less Protocol Driver Sample
+===========================================
+
+This sample demonstrates a connection-less NDIS 6.0 protocol.The driver supports sending and receiving raw Ethernet frames using `ReadFile`/`WriteFile` calls from user-mode. It only receives frames with a specific EtherType field. As an NDIS protocol, it illustrates how to establish and tear down bindings to Ethernet adapters, i.e. those that export medium type **NdisMedium802\_3**. It shows how to set a packet filter, send and receive data, and handle plug-and-play events.
+
+
+INSTALLATION
+------------
+
+The driver is installed using the INF file ndisprot.inf, which is provided in the driver directory. In Network Connections UI, select an adapter and open **Properties.**
+
+Click **Install**, then **Protocol**, then **Add**, and then **Have disk**. Then point to the location of the .inf and driver.
+
+Select **Sample NDIS Protocol Driver** and click **OK**. After installing the protocol, copy over the test application prottest.exe to a convenient location. Please note that the driver service has been set to manual start in the INF file. As a result, it doesn't get loaded automatically when you install.
+
+Usage
+-----
+
+To start the driver, type **Net start ndisprot**.
+
+To stop the driver, type **Net stop ndisprot**.
+
+To test the driver, run **prottest**. For help on usage, run **prottest -?**
+
+**usage: PROTTEST [options] \<devicename\>**
+
+**options:**
+
+<table>
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td align="left">-e
+Enumerate devices</td>
+<td align="left">-r
+Read</td>
+</tr>
+</tbody>
+</table>
+
+Prottest exercises the IOCTLs supported by NDISPROT, and sends and/or receives data on the selected device. In order to use prottest, the user must have administrative privilege. Users should pass down a big enough buffer in order to receive the entire received data. If the length of the buffer passed down is smaller than the length of the received data, NDISPROT will only copy part of the data and discard the rest when the given buffer is full.
+
+Use the **–e** option to enumerate all devices to which NDISPROT is bound:
+
+**C:\\prot\>prottest -n 2 \\DEVICE\\{9273DA7D-5275-4B9A-AC56-68A49D121F1F}**
+
+**DoWriteProc: finished sending 2 packets of 100 bytes each**
+
+**DoReadProc finished: read 2 packets**
+
+**Note**  
+
+With a checked version of ndisprot.sys, you can control the volume of debug information generated by changing the variable `ndisprotDebugLevel`. Refer to debug.h for more information.
+
+For more information, see [NDIS Protocol Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff566821) in the network devices design guide.
+
+File Manifest
+-------------
+
+<table>
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="left">File
+Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left">prottest.c
+User-mode test application</td>
+<td align="left">debug.c
+Routines to aid debugging</td>
+</tr>
+</tbody>
+</table>
+
+
diff --git a/network/ndis/ndisprot/6x/ndisprot60.sln b/network/ndis/ndisprot/6x/ndisprot60.sln
new file mode 100644
index 00000000..cc13f976
--- /dev/null
+++ b/network/ndis/ndisprot/6x/ndisprot60.sln
@@ -0,0 +1,63 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{39A2B1A3-5281-47DF-A0A5-B08E1F979C9E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{C09D8AF9-55C0-4192-A787-B6CA08D83AD0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{7BA6C25F-BBE2-4331-B598-C5F03E11B45D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{A41A7FEE-D4C4-4D9E-B7B3-679200586B93}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot60", "sys\60\ndisprot60.vcxproj", "{74918B99-A7A2-4462-9330-D61ED648B991}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ndisprot630", "sys\630\ndisprot630.vcxproj", "{DB252AE8-E32C-4E60-B0EB-33A2CB80861C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prottest", "test\prottest.vcxproj", "{0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|Win32.ActiveCfg = Debug|Win32
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|Win32.Build.0 = Debug|Win32
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Release|Win32.ActiveCfg = Release|Win32
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Release|Win32.Build.0 = Release|Win32
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|x64.ActiveCfg = Debug|x64
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Debug|x64.Build.0 = Debug|x64
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Release|x64.ActiveCfg = Release|x64
+ {74918B99-A7A2-4462-9330-D61ED648B991}.Release|x64.Build.0 = Release|x64
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|Win32.Build.0 = Debug|Win32
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|Win32.ActiveCfg = Release|Win32
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|Win32.Build.0 = Release|Win32
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|x64.ActiveCfg = Debug|x64
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Debug|x64.Build.0 = Debug|x64
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|x64.ActiveCfg = Release|x64
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C}.Release|x64.Build.0 = Release|x64
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|Win32.Build.0 = Debug|Win32
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|Win32.ActiveCfg = Release|Win32
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|Win32.Build.0 = Release|Win32
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|x64.ActiveCfg = Debug|x64
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Debug|x64.Build.0 = Debug|x64
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|x64.ActiveCfg = Release|x64
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {74918B99-A7A2-4462-9330-D61ED648B991} = {39A2B1A3-5281-47DF-A0A5-B08E1F979C9E}
+ {DB252AE8-E32C-4E60-B0EB-33A2CB80861C} = {7BA6C25F-BBE2-4331-B598-C5F03E11B45D}
+ {0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0} = {A41A7FEE-D4C4-4D9E-B7B3-679200586B93}
+ {39A2B1A3-5281-47DF-A0A5-B08E1F979C9E} = {C09D8AF9-55C0-4192-A787-B6CA08D83AD0}
+ {7BA6C25F-BBE2-4331-B598-C5F03E11B45D} = {C09D8AF9-55C0-4192-A787-B6CA08D83AD0}
+ EndGlobalSection
+EndGlobal
diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.inf b/network/ndis/ndisprot/6x/sys/60/ndisprot60.inf
new file mode 100644
index 00000000..5618bfcf
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.inf
@@ -0,0 +1,90 @@
+;-------------------------------------------------------------------------
+; NDISPROT60.INF -- Sample NDIS Protocol Driver
+;
+; Copyright (c) 2003, Microsoft Corporation
+;-------------------------------------------------------------------------
+[version]
+Signature = "$Windows NT$"
+Class = NetTrans
+ClassGUID = {4d36e975-e325-11ce-bfc1-08002be10318}
+Provider = %Msft%
+DriverVer = 10/01/2002,4.2
+CatalogFile = ndisprot60.cat
+
+
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64
+
+[MSFT.NTx86]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTia64]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTamd64]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+Characteristics=0x0 ;
+CopyFiles=CpyFiles_Sys
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+HKR,Ndi,Service,,"Ndisprot"
+HKR,Ndi,HelpText,,%NDISPROT_HelpText%
+HKR,Ndi\Interfaces, UpperRange,, noupper
+HKR,"Ndi\Interfaces","LowerRange",,"ndis5,ndis4,ndis5_prot"
+
+;-------------------------------------------------------------------------
+; Service installation support
+;-------------------------------------------------------------------------
+[Install.Services]
+AddService=Ndisprot,,NDISPROT_Service_Inst
+
+[NDISPROT_Service_Inst]
+DisplayName = %NDISPROT_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\ndisprot60.sys
+Description = %NDISPROT_Desc%
+
+[Install.Remove.Services]
+DelService=Ndisprot,0x200
+
+;-------------------------------------------------------------------------
+; Declare Destination Directories for file copy/deletion
+;-------------------------------------------------------------------------
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+ndisprot60.sys=1
+
+
+[DestinationDirs]
+CpyFiles_Sys = 12 ; DIRID_DRIVERS
+
+
+;-------------------------------------------------------------------------
+; Files to Copy/Delete - Referenced by Install and Remove sections above
+;-------------------------------------------------------------------------
+[CpyFiles_Sys]
+Ndisprot60.sys,,,2
+
+[Strings]
+Msft = "Your Company"
+DiskDescription = "Microsoft Ndisprot Sample Protocol Driver Disk"
+NDISPROT_Desc = "Sample NDIS Protocol Driver"
+NDISPROT_HelpText = "A driver to support user-mode I/O on NDIS devices"
+
+
+
+
+
diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.rc b/network/ndis/ndisprot/6x/sys/60/ndisprot60.rc
new file mode 100644
index 00000000..59a37c53
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.rc
@@ -0,0 +1,49 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ndisprot.rc
+
+Abstract:
+
+ Internal resource file for driver.
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+
+#define VER_FILEDESCRIPTION_STR "NDIS User mode I/O Driver"
+#define VER_INTERNALNAME_STR "NDISPROT60.SYS"
+#define VER_ORIGINALFILENAME_STR "NDISPROT60.SYS"
+#define VER_LANGNEUTRAL
+
+#define VER_FILEVERSION 4,20,00,0000
+#define VER_FILEVERSION_STR "4.20.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2010 Microsoft Corporation"
+
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "NDIS 6.0 Sample Protocol Driver"
+
+#include "common.ver"
+
diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj
new file mode 100644
index 00000000..068f19e0
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{74918B99-A7A2-4462-9330-D61ED648B991}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{F57A9742-AE91-4E5C-AAF8-582BEC93A8CA}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ndisprot60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ndisprot60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ndisprot60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ndisprot60</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS60=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\debug.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ExCallbk.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ndisbind.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ntdisp.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\recv.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\send.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="ndisprot60.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters
new file mode 100644
index 00000000..e971259b
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/60/ndisprot60.vcxproj.Filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{FC988553-FCE1-455C-A2B8-4253B2E40339}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{CA13EBCF-7249-4085-AEED-A9AB9756BBDF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{B5901951-2387-48ED-83C6-A5D259BF7E0D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{FCDA9B5C-B135-477F-BC65-BE9761005881}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\debug.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ExCallbk.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ndisbind.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ntdisp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\recv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\send.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ndisprot60.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/60/precompsrc.c b/network/ndis/ndisprot/6x/sys/60/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/60/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.inf b/network/ndis/ndisprot/6x/sys/630/ndisprot630.inf
new file mode 100644
index 00000000..0fc1eb67
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.inf
@@ -0,0 +1,109 @@
+;-------------------------------------------------------------------------
+; NDISPROT630.INF -- Sample NDIS Protocol Driver
+;
+; Copyright (c) 2003, Microsoft Corporation
+;-------------------------------------------------------------------------
+[version]
+Signature = "$Windows NT$"
+Class = NetTrans
+ClassGUID = {4d36e975-e325-11ce-bfc1-08002be10318}
+Provider = %Msft%
+DriverVer = 07/16/2010,4.2
+CatalogFile = ndisprot630.cat
+
+
+[Manufacturer]
+%Msft%=MSFT,NTx86,NTia64,NTamd64,NTarm,NTarm64
+
+[MSFT.NTx86]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTia64]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTamd64]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTarm]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+[MSFT.NTarm64]
+%NDISPROT_Desc%=Install, MS_NDISPROT
+
+;-------------------------------------------------------------------------
+; Installation Section
+;-------------------------------------------------------------------------
+[Install]
+AddReg=Inst_Ndi
+Characteristics=0x0 ;
+CopyFiles=CpyFiles_Sys
+
+;-------------------------------------------------------------------------
+; Ndi installation support
+;-------------------------------------------------------------------------
+[Inst_Ndi]
+HKR,Ndi,Service,,"Ndisprot"
+HKR,Ndi,HelpText,,%NDISPROT_HelpText%
+HKR,Ndi\Interfaces, UpperRange,, noupper
+HKR,"Ndi\Interfaces","LowerRange",,"ndis5,ndis4,ndis5_prot"
+
+;-------------------------------------------------------------------------
+; Service installation support
+;-------------------------------------------------------------------------
+[Install.Services]
+AddService=Ndisprot,,NDISPROT_Service_Inst
+
+[NDISPROT_Service_Inst]
+DisplayName = %NDISPROT_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\ndisprot630.sys
+Description = %NDISPROT_Desc%
+AddReg = NdisImPlatformBinding_Reg
+
+[NdisImPlatformBinding_Reg]
+; By default, when an LBFO team or Bridge is created, all protocols will be
+; unbound from the underlying members and bound to the TNic(s). This keyword
+; allows a component to opt out of the default behavior
+; To prevent binding this protocol to the TNic(s):
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,1 ; Do not bind to TNic
+; To prevent unbinding this protocol from underlying members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,2 ; Do not unbind from Members
+; To prevent both binding to TNic and unbinding from members:
+; HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,3 ; Do not bind to TNic or unbind from Members
+HKR, Parameters, NdisImPlatformBindingOptions,0x00010001,0 ; Subscribe to default behavior
+
+[Install.Remove.Services]
+DelService=Ndisprot,0x200
+
+;-------------------------------------------------------------------------
+; Declare Destination Directories for file copy/deletion
+;-------------------------------------------------------------------------
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+ndisprot630.sys=1
+
+
+[DestinationDirs]
+CpyFiles_Sys = 12 ; DIRID_DRIVERS
+
+
+;-------------------------------------------------------------------------
+; Files to Copy/Delete - Referenced by Install and Remove sections above
+;-------------------------------------------------------------------------
+[CpyFiles_Sys]
+Ndisprot630.sys,,,2
+
+[Strings]
+Msft = "Your Company"
+DiskDescription = "Microsoft Ndisprot Sample Protocol Driver Disk"
+NDISPROT_Desc = "Sample NDIS Protocol Driver"
+NDISPROT_HelpText = "A driver to support user-mode I/O on NDIS devices"
+
+
+
+
+
diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.rc b/network/ndis/ndisprot/6x/sys/630/ndisprot630.rc
new file mode 100644
index 00000000..f50de3f9
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.rc
@@ -0,0 +1,49 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ndisprot.rc
+
+Abstract:
+
+ Internal resource file for driver.
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+
+#define VER_FILEDESCRIPTION_STR "NDIS User mode I/O Driver"
+#define VER_INTERNALNAME_STR "NDISPROT630.SYS"
+#define VER_ORIGINALFILENAME_STR "NDISPROT630.SYS"
+#define VER_LANGNEUTRAL
+
+#define VER_FILEVERSION 4,20,00,0000
+#define VER_FILEVERSION_STR "4.20.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2010 Microsoft Corporation"
+
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "NDIS 6.30 Sample Protocol Driver"
+
+#include "common.ver"
+
diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj
new file mode 100644
index 00000000..5a913947
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DB252AE8-E32C-4E60-B0EB-33A2CB80861C}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{FA9D6F91-6B1C-4EFF-BAEA-E67F4CFE9D3E}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ndisprot630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ndisprot630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ndisprot630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ndisprot630</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1;NDIS630=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\debug.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ExCallbk.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ndisbind.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\ntdisp.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\recv.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\send.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="ndisprot630.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters
new file mode 100644
index 00000000..bbdb53e8
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/630/ndisprot630.vcxproj.Filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{088C6D92-3084-464D-B6CD-B47E67D278B5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{EDCAD0DA-E747-487E-8458-BAC6BA5E5744}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{9F1E323E-8118-4CAC-8124-DA41F78075BE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{5EA1AAE7-3C58-475C-84F0-40DCDF8823E9}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\debug.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ExCallbk.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ndisbind.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ntdisp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\recv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\send.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ndisprot630.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/630/precompsrc.c b/network/ndis/ndisprot/6x/sys/630/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/630/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/sys/debug.c b/network/ndis/ndisprot/6x/sys/debug.c
new file mode 100644
index 00000000..40e90984
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/debug.c
@@ -0,0 +1,425 @@
+/*++
+
+Copyright (c) 1997 Microsoft Corporation
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ This module contains all debug-related code.
+
+Revision History:
+
+Notes:
+
+--*/
+
+#include <precomp.h>
+
+#define __FILENUMBER 'GBED'
+
+#if DBG
+
+INT ndisprotDebugLevel=DL_WARN;
+
+NDIS_SPIN_LOCK ndisprotDbgLogLock;
+
+PNPROTD_ALLOCATION ndisprotdMemoryHead = (PNPROTD_ALLOCATION)NULL;
+PNPROTD_ALLOCATION ndisprotdMemoryTail = (PNPROTD_ALLOCATION)NULL;
+ULONG ndisprotdAllocCount = 0; // how many allocated so far (unfreed)
+
+NDIS_SPIN_LOCK ndisprotdMemoryLock;
+BOOLEAN ndisprotdInitDone = FALSE;
+
+
+PVOID
+ndisprotAuditAllocMem(
+ PVOID pPointer,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+)
+{
+ PVOID pBuffer;
+ PNPROTD_ALLOCATION pAllocInfo;
+
+ if (!ndisprotdInitDone)
+ {
+ NdisAllocateSpinLock(&(ndisprotdMemoryLock));
+ ndisprotdInitDone = TRUE;
+ }
+
+ NdisAllocateMemoryWithTag(
+ (PVOID *)&pAllocInfo,
+ Size+sizeof(NPROTD_ALLOCATION),
+ (ULONG)'oiuN'
+ );
+
+ if (pAllocInfo == (PNPROTD_ALLOCATION)NULL)
+ {
+ DEBUGP(DL_VERY_LOUD+50,
+ ("ndisprotAuditAllocMem: file %d, line %d, Size %d failed!\n",
+ FileNumber, LineNumber, Size));
+ pBuffer = NULL;
+ }
+ else
+ {
+ pBuffer = (PVOID)&(pAllocInfo->UserData);
+ NPROT_SET_MEM(pBuffer, 0xaf, Size);
+ pAllocInfo->Signature = NPROTD_MEMORY_SIGNATURE;
+ pAllocInfo->FileNumber = FileNumber;
+ pAllocInfo->LineNumber = LineNumber;
+ pAllocInfo->Size = Size;
+ pAllocInfo->Location = (ULONG_PTR)pPointer;
+ pAllocInfo->Next = (PNPROTD_ALLOCATION)NULL;
+
+ NdisAcquireSpinLock(&(ndisprotdMemoryLock));
+
+ pAllocInfo->Prev = ndisprotdMemoryTail;
+ if (ndisprotdMemoryTail == (PNPROTD_ALLOCATION)NULL)
+ {
+ // empty list
+ ndisprotdMemoryHead = ndisprotdMemoryTail = pAllocInfo;
+ }
+ else
+ {
+ ndisprotdMemoryTail->Next = pAllocInfo;
+ }
+ ndisprotdMemoryTail = pAllocInfo;
+
+ ndisprotdAllocCount++;
+ NdisReleaseSpinLock(&(ndisprotdMemoryLock));
+ }
+
+ DEBUGP(DL_VERY_LOUD+100,
+ ("ndisprotAuditAllocMem: file %c%c%c%c, line %d, %d bytes, [0x%p] <- 0x%p\n",
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber, Size, pPointer, pBuffer));
+
+ return (pBuffer);
+
+}
+
+
+VOID
+ndisprotAuditFreeMem(
+ PVOID Pointer
+)
+{
+ PNPROTD_ALLOCATION pAllocInfo;
+
+ NdisAcquireSpinLock(&(ndisprotdMemoryLock));
+
+ pAllocInfo = CONTAINING_RECORD(Pointer, NPROTD_ALLOCATION, UserData);
+
+ if (pAllocInfo->Signature != NPROTD_MEMORY_SIGNATURE)
+ {
+ DEBUGP(DL_ERROR,
+ ("ndisprotAuditFreeMem: unknown buffer 0x%p!\n", Pointer));
+ NdisReleaseSpinLock(&(ndisprotdMemoryLock));
+#if DBG
+ DbgBreakPoint();
+#endif
+ return;
+ }
+
+ pAllocInfo->Signature = (ULONG)'DEAD';
+ if (pAllocInfo->Prev != (PNPROTD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Prev->Next = pAllocInfo->Next;
+ }
+ else
+ {
+ ndisprotdMemoryHead = pAllocInfo->Next;
+ }
+ if (pAllocInfo->Next != (PNPROTD_ALLOCATION)NULL)
+ {
+ pAllocInfo->Next->Prev = pAllocInfo->Prev;
+ }
+ else
+ {
+ ndisprotdMemoryTail = pAllocInfo->Prev;
+ }
+ ndisprotdAllocCount--;
+ NdisReleaseSpinLock(&(ndisprotdMemoryLock));
+
+ NdisFreeMemory(pAllocInfo, 0, 0);
+}
+
+
+VOID
+ndisprotAuditShutdown(
+ VOID
+)
+{
+ if (ndisprotdInitDone)
+ {
+ if (ndisprotdAllocCount != 0)
+ {
+ DEBUGP(DL_ERROR, ("AuditShutdown: unfreed memory, %d blocks!\n",
+ ndisprotdAllocCount));
+ DEBUGP(DL_ERROR, ("MemoryHead: 0x%p, MemoryTail: 0x%p\n",
+ ndisprotdMemoryHead, ndisprotdMemoryTail));
+ DbgBreakPoint();
+ {
+ PNPROTD_ALLOCATION pAllocInfo;
+
+ while (ndisprotdMemoryHead != (PNPROTD_ALLOCATION)NULL)
+ {
+ pAllocInfo = ndisprotdMemoryHead;
+ DEBUGP(DL_INFO, ("AuditShutdown: will free 0x%p\n", pAllocInfo));
+ ndisprotAuditFreeMem(&(pAllocInfo->UserData));
+ }
+ }
+ }
+ ndisprotdInitDone = FALSE;
+ }
+}
+
+#define MAX_HD_LENGTH 128
+
+VOID
+DbgPrintHexDump(
+ IN PUCHAR pBuffer,
+ IN ULONG Length
+)
+/*++
+
+Routine Description:
+
+ Print a hex dump of the given contiguous buffer. If the length
+ is too long, we truncate it.
+
+Arguments:
+
+ pBuffer - Points to start of data to be dumped
+ Length - Length of above.
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG i;
+
+ if (Length > MAX_HD_LENGTH)
+ {
+ Length = MAX_HD_LENGTH;
+ }
+
+ for (i = 0; i < Length; i++)
+ {
+ //
+ // Check if we are at the end of a line
+ //
+ if ((i > 0) && ((i & 0xf) == 0))
+ {
+ DbgPrint("\n");
+ }
+
+ //
+ // Print addr if we are at start of a new line
+ //
+ if ((i & 0xf) == 0)
+ {
+ DbgPrint("%08p ", pBuffer);
+ }
+
+ DbgPrint(" %02x", *pBuffer++);
+ }
+
+ //
+ // Terminate the last line.
+ //
+ if (Length > 0)
+ {
+ DbgPrint("\n");
+ }
+}
+#endif // DBG
+
+
+#if DBG_SPIN_LOCK
+ULONG ndisprotdSpinLockInitDone = 0;
+NDIS_SPIN_LOCK ndisprotdLockLock;
+
+VOID
+ndisprotAllocateSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+)
+{
+ if (ndisprotdSpinLockInitDone == 0)
+ {
+ ndisprotdSpinLockInitDone = 1;
+ NdisAllocateSpinLock(&(ndisprotdLockLock));
+ }
+
+ NdisAcquireSpinLock(&(ndisprotdLockLock));
+ pLock->Signature = NPROTL_SIG;
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired = 0;
+ pLock->OwnerThread = 0;
+ NdisAllocateSpinLock(&(pLock->NdisLock));
+ NdisReleaseSpinLock(&(ndisprotdLockLock));
+}
+
+VOID
+ndisprotFreeSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+)
+{
+
+ NdisAcquireSpinLock(&(ndisprotdLockLock));
+ pLock->Signature = NUIOL_SIG;
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired = 0;
+ pLock->OwnerThread = 0;
+ NdisFreeSpinLock(&(pLock->NdisLock));
+ NdisReleaseSpinLock(&(ndisprotdLockLock));
+}
+
+VOID
+ndisprotFreeDbgLock(
+ VOID
+ )
+{
+
+ ASSERT(ndisprotdSpinLockInitDone == 1);
+
+ ndisprotdSpinLockInitDone = 0;
+ NdisFreeSpinLock(&(ndisprotdLockLock));
+}
+
+VOID
+ndisprotAcquireSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN BOOLEAN DispatchLevel,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+)
+{
+ PKTHREAD pThread;
+
+ pThread = KeGetCurrentThread();
+ if (DispatchLevel == TRUE)
+ {
+ NdisDprAcquireSpinLock(&(ndisprotdLockLock));
+ }
+ else
+ {
+ NdisAcquireSpinLock(&(ndisprotdLockLock));
+ }
+ if (pLock->Signature != NPROTL_SIG)
+ {
+ DbgPrint("Trying to acquire uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+ if (pLock->IsAcquired != 0)
+ {
+ if (pLock->OwnerThread == pThread)
+ {
+ DbgPrint("Detected multiple locking!: pLock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgPrint("pLock 0x%x already acquired in File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(pLock->TouchedByFileNumber & 0xff),
+ (CHAR)((pLock->TouchedByFileNumber >> 8) & 0xff),
+ (CHAR)((pLock->TouchedByFileNumber >> 16) & 0xff),
+ (CHAR)((pLock->TouchedByFileNumber >> 24) & 0xff),
+ pLock->TouchedInLineNumber);
+ DbgBreakPoint();
+ }
+ }
+
+ pLock->IsAcquired++;
+ if (DispatchLevel == TRUE)
+ {
+ NdisDprReleaseSpinLock(&(ndisprotdLockLock));
+ NdisDprAcquireSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(ndisprotdLockLock));
+ NdisAcquireSpinLock(&(pLock->NdisLock));
+ }
+
+ //
+ // Mark this lock.
+ //
+ pLock->OwnerThread = pThread;
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+}
+
+
+VOID
+ndisprotReleaseSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN BOOLEAN DispatchLevel,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+)
+{
+ NdisDprAcquireSpinLock(&(ndisprotdLockLock));
+ if (pLock->Signature != NPROTL_SIG)
+ {
+ DbgPrint("Trying to release uninited lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+
+ if (pLock->IsAcquired == 0)
+ {
+ DbgPrint("Detected release of unacquired lock 0x%x, File %c%c%c%c, Line %d\n",
+ pLock,
+ (CHAR)(FileNumber & 0xff),
+ (CHAR)((FileNumber >> 8) & 0xff),
+ (CHAR)((FileNumber >> 16) & 0xff),
+ (CHAR)((FileNumber >> 24) & 0xff),
+ LineNumber);
+ DbgBreakPoint();
+ }
+ pLock->TouchedByFileNumber = FileNumber;
+ pLock->TouchedInLineNumber = LineNumber;
+ pLock->IsAcquired--;
+ pLock->OwnerThread = 0;
+ NdisDprReleaseSpinLock(&(ndisprotdLockLock));
+ if (DispatchLevel == TRUE)
+ {
+ NdisDprReleaseSpinLock(&(pLock->NdisLock));
+ }
+ else
+ {
+ NdisReleaseSpinLock(&(pLock->NdisLock));
+ }
+}
+#endif // DBG_SPIN_LOCK
diff --git a/network/ndis/ndisprot/6x/sys/debug.h b/network/ndis/ndisprot/6x/sys/debug.h
new file mode 100644
index 00000000..64de3453
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/debug.h
@@ -0,0 +1,220 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ debug.h
+
+Abstract:
+
+ Debug macros for NDISPROT
+
+Revision History:
+
+Notes:
+
+--*/
+
+#ifndef _NPROTDEBUG__H
+#define _NPROTDEBUG__H
+
+//
+// Message verbosity: lower values indicate higher urgency
+//
+#define DL_EXTRA_LOUD 20
+#define DL_VERY_LOUD 10
+#define DL_LOUD 8
+#define DL_INFO 6
+#define DL_WARN 4
+#define DL_ERROR 2
+#define DL_FATAL 0
+
+#if DBG_SPIN_LOCK
+
+typedef struct _NPROT_LOCK
+{
+ ULONG Signature;
+ ULONG IsAcquired;
+ PKTHREAD OwnerThread;
+ ULONG TouchedByFileNumber;
+ ULONG TouchedInLineNumber;
+ NDIS_SPIN_LOCK NdisLock;
+} NPROT_LOCK, *PNPROT_LOCK;
+
+#define NPROTL_SIG 'KCOL'
+
+extern NDIS_SPIN_LOCK ndisprotDbgLogLock;
+
+extern
+VOID
+ndisprotAllocateSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+ndisprotFreeSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+ndisprotAcquireSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN BOOLEAN DispatchLevel,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+ndisprotReleaseSpinLock(
+ IN PNPROT_LOCK pLock,
+ IN BOOLEAN DispatchLevel,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+);
+
+extern
+VOID
+ndisprotFreeDbgLock(
+ VOID
+);
+
+#define CHECK_LOCK_COUNT(Count) \
+ { \
+ if ((INT)(Count) < 0) \
+ { \
+ DbgPrint("Lock Count %d is < 0! File %s, Line %d\n",\
+ Count, __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+ }
+#else
+
+#define CHECK_LOCK_COUNT(Count)
+
+typedef NDIS_SPIN_LOCK NPROT_LOCK;
+typedef PNDIS_SPIN_LOCK PNPROT_LOCK;
+
+#endif // DBG_SPIN_LOCK
+
+#if DBG
+
+extern INT ndisprotDebugLevel;
+
+
+#define DEBUGP(lev, stmt) \
+ { \
+ if ((lev) <= ndisprotDebugLevel) \
+ { \
+ DbgPrint("Ndisprot: "); DbgPrint stmt; \
+ } \
+ }
+
+#define DEBUGPDUMP(lev, pBuf, Len) \
+ { \
+ if ((lev) <= ndisprotDebugLevel) \
+ { \
+ DbgPrintHexDump((PUCHAR)(pBuf), (ULONG)(Len)); \
+ } \
+ }
+
+#define NPROT_ASSERT(exp) \
+ { \
+ if (!(exp)) \
+ { \
+ DbgPrint("Ndisprot: assert " #exp " failed in" \
+ " file %s, line %d\n", __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ } \
+ }
+
+#define NPROT_SET_SIGNATURE(s, t)\
+ (s)->t##_sig = t##_signature;
+
+#define NPROT_STRUCT_ASSERT(s, t) \
+ if ((s)->t##_sig != t##_signature) \
+ { \
+ DbgPrint("ndisprot: assertion failure" \
+ " for type " #t " at 0x%p in file %s, line %d\n", \
+ s, __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ }
+
+
+//
+// Memory Allocation/Freeing Audit:
+//
+
+//
+// The NPROTD_ALLOCATION structure stores all info about one allocation
+//
+typedef struct _NPROTD_ALLOCATION {
+
+ ULONG Signature;
+ struct _NPROTD_ALLOCATION *Next;
+ struct _NPROTD_ALLOCATION *Prev;
+ ULONG FileNumber;
+ ULONG LineNumber;
+ ULONG Size;
+ ULONG_PTR Location; // where the returned ptr was stored
+ union
+ {
+ ULONGLONG Alignment;
+ UCHAR UserData;
+ };
+
+} NPROTD_ALLOCATION, *PNPROTD_ALLOCATION;
+
+#define NPROTD_MEMORY_SIGNATURE (ULONG)'CSII'
+
+extern
+PVOID
+ndisprotAuditAllocMem (
+ PVOID pPointer,
+ ULONG Size,
+ ULONG FileNumber,
+ ULONG LineNumber
+);
+
+extern
+VOID
+ndisprotAuditFreeMem(
+ PVOID Pointer
+);
+
+extern
+VOID
+ndisprotAuditShutdown(
+ VOID
+);
+
+extern
+VOID
+DbgPrintHexDump(
+ PUCHAR pBuffer,
+ ULONG Length
+);
+
+#else
+
+//
+// No debug
+//
+#define DEBUGP(lev, stmt)
+#define DEBUGPDUMP(lev, pBuf, Len)
+
+#define NPROT_ASSERT(exp)
+#define NPROT_SET_SIGNATURE(s, t) UNREFERENCED_PARAMETER(s)
+#define NPROT_STRUCT_ASSERT(s, t) UNREFERENCED_PARAMETER(s)
+
+#endif // DBG
+
+
+#endif // _NPROTDEBUG__H
diff --git a/network/ndis/ndisprot/6x/sys/excallbk.c b/network/ndis/ndisprot/6x/sys/excallbk.c
new file mode 100644
index 00000000..baa2298c
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/excallbk.c
@@ -0,0 +1,195 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ExCallbk.c
+
+Abstract: The routines in this module helps to solve driver load order
+ dependency between this sample and NDISWDM sample. These
+ routines are not required in a typical protocol driver. By default
+ this module is not included in the sample. You include these routines
+ by adding EX_CALLBACK defines to the 'sources' file. Read the
+ NDISWDM samples readme file for more information on how ExCallback
+ kernel interfaces are used to solve driver load order issue.
+
+
+Environment:
+
+ Kernel mode
+
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+#ifdef EX_CALLBACK
+
+#define __FILENUMBER 'LCxE'
+
+#define NDISPROT_CALLBACK_NAME L"\\Callback\\NdisProtCallbackObject"
+
+#define CALLBACK_SOURCE_NDISPROT 0
+#define CALLBACK_SOURCE_NDISWDM 1
+
+PCALLBACK_OBJECT CallbackObject = NULL;
+PVOID CallbackRegisterationHandle = NULL;
+
+typedef VOID (* NOTIFY_PRESENCE_CALLBACK)(OUT PVOID Source);
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(PAGE, ndisprotRegisterExCallBack)
+#pragma alloc_text(PAGE, ndisprotUnregisterExCallBack)
+
+#endif // ALLOC_PRAGMA
+
+BOOLEAN
+ndisprotRegisterExCallBack()
+{
+ OBJECT_ATTRIBUTES ObjectAttr;
+ UNICODE_STRING CallBackObjectName;
+ NTSTATUS Status;
+ BOOLEAN bResult = TRUE;
+
+ DEBUGP(DL_LOUD, ("--> ndisprotRegisterExCallBack\n"));
+
+ PAGED_CODE();
+
+ do {
+
+ RtlInitUnicodeString(&CallBackObjectName, NDISPROT_CALLBACK_NAME);
+
+ InitializeObjectAttributes(&ObjectAttr,
+ &CallBackObjectName,
+ OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+ NULL,
+ NULL);
+
+ Status = ExCreateCallback(&CallbackObject,
+ &ObjectAttr,
+ TRUE,
+ TRUE);
+
+
+ if (!NT_SUCCESS(Status))
+ {
+
+ DEBUGP(DL_ERROR, ("RegisterExCallBack: failed to create callback %lx\n", Status));
+ bResult = FALSE;
+ break;
+ }
+
+ CallbackRegisterationHandle = ExRegisterCallback(CallbackObject,
+ ndisprotCallback,
+ (PVOID)NULL);
+ if (CallbackRegisterationHandle == NULL)
+ {
+ DEBUGP(DL_ERROR,("RegisterExCallBack: failed to register a Callback routine%lx\n", Status));
+ bResult = FALSE;
+ break;
+ }
+
+ ExNotifyCallback(CallbackObject,
+ (PVOID)CALLBACK_SOURCE_NDISPROT,
+ (PVOID)NULL);
+
+
+ }while(FALSE);
+
+ if(!bResult) {
+ if (CallbackRegisterationHandle)
+ {
+ ExUnregisterCallback(CallbackRegisterationHandle);
+ CallbackRegisterationHandle = NULL;
+ }
+
+ if (CallbackObject)
+ {
+ ObDereferenceObject(CallbackObject);
+ CallbackObject = NULL;
+ }
+ }
+
+ DEBUGP(DL_LOUD, ("<-- ndisprotRegisterExCallBack\n"));
+
+ return bResult;
+
+}
+
+VOID
+ndisprotUnregisterExCallBack()
+{
+ DEBUGP(DL_LOUD, ("--> ndisprotUnregisterExCallBack\n"));
+
+ PAGED_CODE();
+
+ if (CallbackRegisterationHandle)
+ {
+ ExUnregisterCallback(CallbackRegisterationHandle);
+ CallbackRegisterationHandle = NULL;
+ }
+
+ if (CallbackObject)
+ {
+ ObDereferenceObject(CallbackObject);
+ CallbackObject = NULL;
+ }
+
+ DEBUGP(DL_LOUD, ("<-- ndisprotUnregisterExCallBack\n"));
+
+}
+
+VOID
+ndisprotCallback(
+ PVOID CallBackContext,
+ PVOID Source,
+ PVOID CallbackAddr
+ )
+{
+ NOTIFY_PRESENCE_CALLBACK func;
+
+ DEBUGP(DL_LOUD, ("==>ndisprotoCallback: Source %lx, CallbackAddr %p\n",
+ Source, CallbackAddr));
+
+ //
+ // if we are the one issuing this notification, just return
+ //
+ if (Source == CALLBACK_SOURCE_NDISPROT) {
+ return;
+ }
+
+ //
+ // Notification is coming from NDISWDM
+ // let it know that you are here
+ //
+ ASSERT(Source == (PVOID)CALLBACK_SOURCE_NDISWDM);
+
+ if(Source == (PVOID)CALLBACK_SOURCE_NDISWDM) {
+
+ ASSERT(CallbackAddr);
+
+ if (CallbackAddr == NULL)
+ {
+ DEBUGP(DL_ERROR, ("Callback called with invalid address %p\n", CallbackAddr));
+ return;
+ }
+
+ func = CallbackAddr;
+
+ func(CALLBACK_SOURCE_NDISPROT);
+ }
+
+ DEBUGP(DL_LOUD, ("<==ndisprotoCallback: Source, %lx\n", Source));
+
+}
+
+#endif
diff --git a/network/ndis/ndisprot/6x/sys/macros.h b/network/ndis/ndisprot/6x/sys/macros.h
new file mode 100644
index 00000000..d750129c
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/macros.h
@@ -0,0 +1,234 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ macros.h
+
+Abstract:
+
+ Some macros for NDISPROT.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+
+#ifndef MIN
+#define MIN(_a, _b) ((_a) < (_b)? (_a): (_b))
+#endif
+
+#if DBG
+#define NPROT_REF_OPEN(_pOpen) ndisprotDbgRefOpen(_pOpen, __FILENUMBER, __LINE__)
+#define NPROT_DEREF_OPEN(_pOpen) ndisprotDbgDerefOpen(_pOpen, __FILENUMBER, __LINE__)
+#else
+#define NPROT_REF_OPEN(_pOpen) ndisprotRefOpen(_pOpen)
+#define NPROT_DEREF_OPEN(_pOpen) ndisprotDerefOpen(_pOpen)
+#endif
+
+
+//
+// Spinlock macros
+//
+#if DBG_SPIN_LOCK
+
+#define NPROT_INIT_LOCK(_pLock) \
+ ndisprotAllocateSpinLock(_pLock, __FILENUMBER, __LINE__)
+
+#define NPROT_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ ndisprotAcquireSpinLock(_pLock, DispatchLevel,__FILENUMBER, __LINE__)
+
+#define NPROT_RELEASE_LOCK(_pLock,DispatchLevel) \
+ ndisprotReleaseSpinLock(_pLock, DispatchLevel,__FILENUMBER, __LINE__)
+
+#define NPROT_FREE_LOCK(_pLock) \
+ ndisprotFreeSpinLock(_pLock, __FILENUMBER, __LINE__)
+
+#define NPROT_FREE_DBG_LOCK() \
+ ndisprotFreeDbgLock()
+#else
+
+#define NPROT_INIT_LOCK(_pLock) NdisAllocateSpinLock(_pLock)
+#define NPROT_ACQUIRE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel == TRUE) \
+ { \
+ NdisDprAcquireSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisAcquireSpinLock(_pLock); \
+ } \
+ }
+#define NPROT_RELEASE_LOCK(_pLock, DispatchLevel) \
+ { \
+ if (DispatchLevel == TRUE) \
+ { \
+ NdisDprReleaseSpinLock(_pLock); \
+ } \
+ else \
+ { \
+ NdisReleaseSpinLock(_pLock); \
+ } \
+ }
+
+#define NPROT_FREE_LOCK(_pLock) NdisFreeSpinLock(_pLock)
+
+#define NPROT_FREE_DBG_LOCK()
+
+#endif // DBG
+
+//
+// List manipulation.
+//
+#define NPROT_INIT_LIST_HEAD(_pList) InitializeListHead(_pList)
+#define NPROT_IS_LIST_EMPTY(_pList) IsListEmpty(_pList)
+#define NPROT_INSERT_HEAD_LIST(_pList, _pEnt) InsertHeadList(_pList, _pEnt)
+#define NPROT_INSERT_TAIL_LIST(_pList, _pEnt) InsertTailList(_pList, _pEnt)
+#define NPROT_REMOVE_ENTRY_LIST(_pEnt) RemoveEntryList(_pEnt)
+#define NPROT_REMOVE_HEAD_LIST(_pList) RemoveHeadList(_pList)
+
+
+
+#define NPROT_RCV_NBL_TO_LIST_ENTRY(_pNbl) \
+ (&((PNPROT_RECV_NBL_RSVD)(NET_BUFFER_LIST_PROTOCOL_RESERVED(_pNbl)))->Link)
+
+#define NPROT_RCV_NBL_FROM_LIST_ENTRY(_pEnt) \
+ (((PNPROT_RECV_NBL_RSVD)(CONTAINING_RECORD(_pEnt, NPROT_RECV_NBL_RSVD, Link)))->pNetBufferList)
+
+
+//
+// Send net buffer list context
+//
+#define NPROT_IRP_FROM_SEND_NBL(_pNbl) \
+ (((PNPROT_SEND_NETBUFLIST_RSVD)((_pNbl)->Context->ContextData + (_pNbl)->Context->Offset))->pIrp)
+
+#define NPROT_SEND_NBL_RSVD(_pNbl) \
+ ((PNPROT_SEND_NETBUFLIST_RSVD)((_pNbl)->Context->ContextData + (_pNbl)->Context->Offset))
+
+
+#define NPROT_REF_SEND_NBL(_pNbl) \
+ (VOID)NdisInterlockedIncrement((PLONG)&NPROT_SEND_NBL_RSVD(_pNbl)->RefCount)
+
+
+#define NPROT_DEREF_SEND_NBL(_pNbl, DispatchLevel) \
+ { \
+ if (NdisInterlockedDecrement((PLONG)&NPROT_SEND_NBL_RSVD(_pNbl)->RefCount) == 0) \
+ { \
+ NdisFreeNetBufferList(_pNbl); \
+ } \
+ }
+
+//
+// Cancel IDs are generated by using the partial cancel ID we got from
+// NDIS ORed with a monotonically increasing locally generated ID.
+//
+#define NPROT_CANCEL_ID_LOW_MASK (((ULONG_PTR)-1) >> 8)
+
+#define NPROT_GET_NEXT_CANCEL_ID() \
+ (PVOID)(Globals.PartialCancelId | \
+ ((NdisInterlockedIncrement((PLONG)&Globals.LocalCancelId)) & NPROT_CANCEL_ID_LOW_MASK))
+
+
+//
+// Memory allocation
+//
+#if DBG
+#define NPROT_ALLOC_MEM(_pVar, _Size) \
+ (_pVar) = ndisprotAuditAllocMem( \
+ (PVOID)&(_pVar), \
+ _Size, \
+ __FILENUMBER, \
+ __LINE__);
+
+#define NPROT_FREE_MEM(_pMem) \
+ ndisprotAuditFreeMem(_pMem);
+
+#else
+
+#define NPROT_ALLOC_MEM(_pVar, _Size) \
+ NdisAllocateMemoryWithTag((PVOID *)(&_pVar), (_Size), NPROT_ALLOC_TAG)
+
+#define NPROT_FREE_MEM(_pMem) \
+ NdisFreeMemory(_pMem, 0, 0)
+
+#endif // DBG
+
+
+#define NPROT_ZERO_MEM(_pMem, _ByteCount) \
+ NdisZeroMemory(_pMem, _ByteCount)
+
+#define NPROT_COPY_MEM(_pDst, _pSrc, _ByteCount) \
+ NdisMoveMemory(_pDst, _pSrc, _ByteCount)
+
+#define NPROT_MEM_CMP(_p1, _p2, _ByteCount) \
+ NdisEqualMemory(_p1, _p2, _ByteCount)
+
+#define NPROT_SET_MEM(_pMem, _ByteVal, _ByteCount) \
+ NdisFillMemory(_pMem, _ByteCount, _ByteVal)
+
+//
+// Events.
+//
+#define NPROT_INIT_EVENT(_pEvent) NdisInitializeEvent(_pEvent)
+#define NPROT_SIGNAL_EVENT(_pEvent) NdisSetEvent(_pEvent)
+#define NPROT_WAIT_EVENT(_pEvent, _MsToWait) NdisWaitEvent(_pEvent, _MsToWait)
+
+
+//
+// Flags
+//
+#define NPROT_SET_FLAGS(_FlagsVar, _Mask, _BitsToSet) \
+ (_FlagsVar) = ((_FlagsVar) & ~(_Mask)) | (_BitsToSet)
+
+#define NPROT_TEST_FLAGS(_FlagsVar, _Mask, _BitsToCheck) \
+ (((_FlagsVar) & (_Mask)) == (_BitsToCheck))
+
+
+#define NDIS_STATUS_TO_NT_STATUS(_NdisStatus, _pNtStatus) \
+{ \
+ /* \
+ * The following NDIS status codes map directly to NT status codes. \
+ */ \
+ if (((NDIS_STATUS_SUCCESS == (_NdisStatus)) || \
+ (NDIS_STATUS_PENDING == (_NdisStatus)) || \
+ (NDIS_STATUS_BUFFER_OVERFLOW == (_NdisStatus)) || \
+ (NDIS_STATUS_FAILURE == (_NdisStatus)) || \
+ (NDIS_STATUS_RESOURCES == (_NdisStatus)) || \
+ (NDIS_STATUS_NOT_SUPPORTED == (_NdisStatus)))) \
+ { \
+ *(_pNtStatus) = (NTSTATUS)(_NdisStatus); \
+ } \
+ else if (NDIS_STATUS_BUFFER_TOO_SHORT == (_NdisStatus)) \
+ { \
+ /* \
+ * The above NDIS status codes require a little special casing. \
+ */ \
+ *(_pNtStatus) = STATUS_BUFFER_TOO_SMALL; \
+ } \
+ else if (NDIS_STATUS_INVALID_LENGTH == (_NdisStatus)) \
+ { \
+ *(_pNtStatus) = STATUS_INVALID_BUFFER_SIZE; \
+ } \
+ else if (NDIS_STATUS_INVALID_DATA == (_NdisStatus)) \
+ { \
+ *(_pNtStatus) = STATUS_INVALID_PARAMETER; \
+ } \
+ else if (NDIS_STATUS_ADAPTER_NOT_FOUND == (_NdisStatus)) \
+ { \
+ *(_pNtStatus) = STATUS_NO_MORE_ENTRIES; \
+ } \
+ else if (NDIS_STATUS_ADAPTER_NOT_READY == (_NdisStatus)) \
+ { \
+ *(_pNtStatus) = STATUS_DEVICE_NOT_READY; \
+ } \
+ else \
+ { \
+ *(_pNtStatus) = STATUS_UNSUCCESSFUL; \
+ } \
+}
diff --git a/network/ndis/ndisprot/6x/sys/ndisbind.c b/network/ndis/ndisprot/6x/sys/ndisbind.c
new file mode 100644
index 00000000..5257d3a2
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/ndisbind.c
@@ -0,0 +1,2061 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ ndisbind.c
+
+Abstract:
+
+ NDIS protocol entry points and utility routines to handle binding
+ and unbinding from adapters.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+
+#include "precomp.h"
+
+#define __FILENUMBER 'DNIB'
+
+NDIS_OID ndisprotSupportedSetOids[] =
+{
+ OID_802_11_INFRASTRUCTURE_MODE,
+ OID_802_11_AUTHENTICATION_MODE,
+ OID_802_11_RELOAD_DEFAULTS,
+ OID_802_11_REMOVE_WEP,
+ OID_802_11_WEP_STATUS,
+ OID_802_11_BSSID_LIST_SCAN,
+ OID_802_11_ADD_WEP,
+ OID_802_11_SSID,
+ OID_802_11_BSSID,
+ OID_802_11_BSSID_LIST,
+ OID_802_11_DISASSOCIATE,
+ OID_802_11_STATISTICS, // Later used by power management
+ OID_802_11_POWER_MODE, // Later used by power management
+ OID_802_11_NETWORK_TYPE_IN_USE,
+ OID_802_11_RSSI,
+ OID_802_11_SUPPORTED_RATES,
+ OID_802_11_CONFIGURATION,
+ OID_802_3_MULTICAST_LIST,
+};
+
+NDIS_STATUS
+NdisprotBindAdapter(
+ IN NDIS_HANDLE ProtocolDriverContext,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_BIND_PARAMETERS BindParameters
+ )
+/*++
+
+Routine Description:
+
+ Protocol Bind Handler entry point called when NDIS wants us
+ to bind to an adapter. We go ahead and set up a binding.
+ An OPEN_CONTEXT structure is allocated to keep state about
+ this binding.
+
+Arguments:
+
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ NDIS_STATUS Status;
+
+ UNREFERENCED_PARAMETER(ProtocolDriverContext);
+
+ do
+ {
+ //
+ // Allocate our context for this open.
+ //
+ NPROT_ALLOC_MEM(pOpenContext, sizeof(NDISPROT_OPEN_CONTEXT));
+ if (pOpenContext == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize it.
+ //
+ NPROT_ZERO_MEM(pOpenContext, sizeof(NDISPROT_OPEN_CONTEXT));
+ NPROT_SET_SIGNATURE(pOpenContext, oc);
+
+ NPROT_INIT_LOCK(&pOpenContext->Lock);
+ NPROT_INIT_LIST_HEAD(&pOpenContext->PendedReads);
+ NPROT_INIT_LIST_HEAD(&pOpenContext->PendedWrites);
+ NPROT_INIT_LIST_HEAD(&pOpenContext->RecvNetBufListQueue);
+ NPROT_INIT_EVENT(&pOpenContext->PoweredUpEvent);
+
+
+ //
+ // Start off by assuming that the device below is powered up.
+ //
+ NPROT_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
+
+ NPROT_REF_OPEN(pOpenContext); // Bind
+
+ //
+ // Add it to the global list.
+ //
+ NPROT_ACQUIRE_LOCK(&Globals.GlobalLock, FALSE);
+
+ NPROT_INSERT_TAIL_LIST(&Globals.OpenList,
+ &pOpenContext->Link);
+
+ NPROT_RELEASE_LOCK(&Globals.GlobalLock, FALSE);
+
+ pOpenContext->State = NdisprotInitializing;
+
+ //
+ // Here we reference the open context to make sure that even if
+ // ndisprotCreateBinding failed, open context is still valid
+ //
+ NPROT_REF_OPEN(pOpenContext);
+ //
+ // Set up the NDIS binding, ndisprotCreateBinding does the cleanup for the
+ // binding if somehow it fails to create the binding, the
+ //
+ Status = ndisprotCreateBinding(
+ pOpenContext,
+ BindParameters,
+ BindContext,
+ (PUCHAR)BindParameters->AdapterName->Buffer,
+ BindParameters->AdapterName->Length);
+
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Dereference the open context because we referenced it before we call
+ // ndisprotCreateBinding
+ //
+ NPROT_DEREF_OPEN(pOpenContext);
+ break;
+ }
+ //
+ // Dereference the open context because we referenced it before we call
+ // ndisprotCreateBinding
+ //
+ NPROT_DEREF_OPEN(pOpenContext);
+ }
+ while (FALSE);
+
+ return Status;
+
+}
+
+VOID
+NdisprotOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion routine called by NDIS if our call to NdisOpenAdapterEx
+ pends. Wake up the thread that called NdisOpenAdapterEx.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context structure
+ Status - status of the open
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ pOpenContext->BindStatus = Status;
+
+ NPROT_SIGNAL_EVENT(&pOpenContext->BindEvent);
+}
+
+
+NDIS_STATUS
+NdisprotUnbindAdapter(
+ IN NDIS_HANDLE UnbindContext,
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+ NDIS calls this when it wants us to close the binding to an adapter.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context structure
+ UnbindContext - to use in NdisCompleteUnbindAdapter if we return pending
+
+Return Value:
+
+ pending or success
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+
+ UNREFERENCED_PARAMETER(UnbindContext);
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Mark this open as having seen an Unbind.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_UNBIND_FLAGS, NPROTO_UNBIND_RECEIVED);
+
+ //
+ // In case we had threads blocked for the device below to be powered
+ // up, wake them up.
+ //
+ NPROT_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ pOpenContext->State = NdisprotClosing;
+
+ ndisprotShutdownBinding(pOpenContext);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+
+VOID
+NdisprotCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS to complete a pended call to NdisCloseAdapter.
+ We wake up the thread waiting for this completion.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context structure
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ NPROT_SIGNAL_EVENT(&pOpenContext->BindEvent);
+}
+
+NDIS_STATUS
+NdisprotPnPEventHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_PNP_EVENT_NOTIFICATION pNetPnPEventNotification
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS to notify us of a PNP event. The most significant
+ one for us is power state change.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context structure
+ this is NULL for global reconfig events.
+
+ pNetPnPEventNotification - pointer to the PNP event notification
+
+Return Value:
+
+ Our processing status for the PNP event.
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PUCHAR Buffer = NULL;
+ ULONG BufferLength = 0;
+ PNDIS_PROTOCOL_RESTART_PARAMETERS RestartParameters = NULL;
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+
+ switch (pNetPnPEventNotification->NetPnPEvent.NetEvent)
+ {
+ case NetEventSetPower:
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+ pOpenContext->PowerState = *(PNET_DEVICE_POWER_STATE)pNetPnPEventNotification->NetPnPEvent.Buffer;
+
+ if (pOpenContext->PowerState > NetDeviceStateD0)
+ {
+ //
+ // The device below is transitioning to a low power state.
+ // Block any threads attempting to query the device while
+ // in this state.
+ //
+ NPROT_INIT_EVENT(&pOpenContext->PoweredUpEvent);
+
+ //
+ // There is no need to wait for pending I/O here.
+ // We wait for it in the NetEventPause handler.
+ //
+
+ //
+ // Return any receives that we had queued up.
+ //
+ ndisprotFlushReceiveQueue(pOpenContext);
+ DEBUGP(DL_INFO, ("PnPEvent: Open %p, SetPower to %d\n",
+ pOpenContext, pOpenContext->PowerState));
+ }
+ else
+ {
+ //
+ // The device below is powered up.
+ //
+ DEBUGP(DL_INFO, ("PnPEvent: Open %p, SetPower ON: %d\n",
+ pOpenContext, pOpenContext->PowerState));
+ NPROT_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
+ }
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case NetEventQueryPower:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case NetEventBindsComplete:
+ NPROT_SIGNAL_EVENT(&Globals.BindsComplete);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case NetEventPause:
+ //
+ // Wait all sends to be complete.
+ //
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ pOpenContext->State = NdisprotPausing;
+
+ //
+ // we could also complete the PnP Event asynchrously.
+ //
+ while (TRUE)
+ {
+ if (pOpenContext->PendedSendCount == 0)
+ break;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ DEBUGP(DL_INFO, ("PnPEvent: Open %p, outstanding count is %d\n", pOpenContext,
+ pOpenContext->PendedSendCount));
+
+ NdisMSleep(100000); // 100 ms.
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ //
+ // Return all queued receives.
+ //
+ ndisprotFlushReceiveQueue(pOpenContext);
+ pOpenContext->State = NdisprotPaused;
+
+ break;
+
+ case NetEventRestart:
+
+
+ ASSERT(pOpenContext->State == NdisprotPaused);
+ //
+ // Get the updated attributes
+ //
+ Buffer = pNetPnPEventNotification->NetPnPEvent.Buffer;
+ if (Buffer == NULL)
+ {
+ pOpenContext->State = NdisprotRunning;
+ break;
+ }
+ BufferLength = pNetPnPEventNotification->NetPnPEvent.BufferLength;
+
+ ASSERT(BufferLength == sizeof(NDIS_PROTOCOL_RESTART_PARAMETERS));
+
+ RestartParameters = (PNDIS_PROTOCOL_RESTART_PARAMETERS)Buffer;
+ ndisprotRestart(pOpenContext,RestartParameters);
+
+
+ pOpenContext->State = NdisprotRunning;
+ break;
+
+ case NetEventQueryRemoveDevice:
+ case NetEventCancelRemoveDevice:
+ case NetEventReconfigure:
+ case NetEventBindList:
+ case NetEventPnPCapabilities:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ DEBUGP(DL_INFO, ("PnPEvent: Open %p, Event %d, Status %x\n",
+ pOpenContext, pNetPnPEventNotification->NetPnPEvent.NetEvent, Status));
+
+ return (Status);
+}
+
+VOID
+NdisprotProtocolUnloadHandler(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ NDIS calls this on a usermode request to uninstall us.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+ ndisprotDoProtocolUnload();
+}
+
+NDIS_STATUS
+ndisprotCreateBinding(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNDIS_BIND_PARAMETERS BindParameters,
+ IN NDIS_HANDLE BindContext,
+ _In_reads_bytes_(BindingInfoLength) IN PUCHAR pBindingInfo,
+ IN ULONG BindingInfoLength
+ )
+/*++
+
+Routine Description:
+
+ Utility function to create an NDIS binding to the indicated device,
+ if no such binding exists.
+
+ Here is where we also allocate additional resources (e.g. packet pool)
+ for the binding.
+
+ NOTE: this function blocks and finishes synchronously.
+
+Arguments:
+
+ pOpenContext - pointer to open context block
+ BindParameters - pointer to NDIS_BIND_PARAMETERS
+ BindConext - pointer to NDIS bind context
+ pBindingInfo - pointer to unicode device name string
+ BindingInfoLength - length in bytes of the above.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if a binding was successfully set up.
+ NDIS_STATUS_XXX error code on any failure.
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_MEDIUM MediumArray[1] = {NdisMedium802_3};
+ NDIS_OPEN_PARAMETERS OpenParameters;
+ NET_BUFFER_LIST_POOL_PARAMETERS PoolParameters;
+ UINT SelectedMediumIndex;
+ BOOLEAN fOpenComplete = FALSE;
+ ULONG GenericUlong = 0;
+ NET_FRAME_TYPE FrameTypeArray[2] = {NDIS_ETH_TYPE_802_1X, NDIS_ETH_TYPE_802_1Q};
+#if DBG
+ PNDISPROT_OPEN_CONTEXT pTmpOpenContext;
+#endif
+
+ DEBUGP(DL_LOUD, ("CreateBinding: open %p/%x, device [%s]\n",
+ pOpenContext, pOpenContext->Flags, pBindingInfo));
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ //
+ // Check if we already have a binding to this device.
+ //
+#if DBG
+ pTmpOpenContext = ndisprotLookupDevice(pBindingInfo, BindingInfoLength);
+
+ ASSERT(pTmpOpenContext == NULL);
+
+ if (pTmpOpenContext != NULL)
+ {
+ DEBUGP(DL_WARN,
+ ("CreateBinding: Binding to device %ws already exists on open %p\n",
+ pTmpOpenContext->DeviceName.Buffer, pTmpOpenContext));
+
+ NPROT_DEREF_OPEN(pTmpOpenContext); // temp ref added by Lookup
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+#endif
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_OPENING);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Copy in the device name. Add room for a NULL terminator.
+ //
+ NPROT_ALLOC_MEM(pOpenContext->DeviceName.Buffer, BindingInfoLength + sizeof(WCHAR));
+ if (pOpenContext->DeviceName.Buffer == NULL)
+ {
+ DEBUGP(DL_WARN, ("CreateBinding: failed to alloc device name buf (%d bytes)\n",
+ BindingInfoLength + sizeof(WCHAR)));
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ NPROT_COPY_MEM(pOpenContext->DeviceName.Buffer, pBindingInfo, BindingInfoLength);
+#pragma prefast(suppress: 12009, "DeviceName length will not cause overflow")
+ *(PWCHAR)((PUCHAR)pOpenContext->DeviceName.Buffer + BindingInfoLength) = L'\0';
+ NdisInitUnicodeString(&pOpenContext->DeviceName, pOpenContext->DeviceName.Buffer);
+
+ NdisZeroMemory(&PoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
+
+ PoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ PoolParameters.Header.Size = sizeof(PoolParameters);
+ PoolParameters.ProtocolId = NDIS_PROTOCOL_ID_IPX ;
+ PoolParameters.ContextSize = sizeof(NPROT_SEND_NETBUFLIST_RSVD);
+ PoolParameters.fAllocateNetBuffer = TRUE;
+ PoolParameters.PoolTag = NPROT_ALLOC_TAG;
+
+ pOpenContext->SendNetBufferListPool = NdisAllocateNetBufferListPool(
+ Globals.NdisProtocolHandle,
+ &PoolParameters);
+ if (pOpenContext->SendNetBufferListPool == NULL)
+ {
+ DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
+ " send net buffer list pool\n"));
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ PoolParameters.ContextSize = 0;
+
+ pOpenContext->RecvNetBufferListPool = NdisAllocateNetBufferListPool(
+ Globals.NdisProtocolHandle,
+ &PoolParameters);
+
+ if (pOpenContext->RecvNetBufferListPool == NULL)
+ {
+ DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
+ " recv net buffer list pool.\n"));
+
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Assume that the device is powered up.
+ //
+ pOpenContext->PowerState = NetDeviceStateD0;
+
+ //
+ // Open the adapter.
+ //
+ NPROT_INIT_EVENT(&pOpenContext->BindEvent);
+
+ NPROT_ZERO_MEM(&OpenParameters, sizeof(NDIS_OPEN_PARAMETERS));
+ OpenParameters.Header.Revision = NDIS_OPEN_PARAMETERS_REVISION_1;
+ OpenParameters.Header.Size = sizeof(NDIS_OPEN_PARAMETERS);
+ OpenParameters.Header.Type = NDIS_OBJECT_TYPE_OPEN_PARAMETERS;
+ OpenParameters.AdapterName = BindParameters->AdapterName;
+ OpenParameters.MediumArray = &MediumArray[0];
+ OpenParameters.MediumArraySize = sizeof(MediumArray) / sizeof(NDIS_MEDIUM);
+ OpenParameters.SelectedMediumIndex = &SelectedMediumIndex;
+ OpenParameters.FrameTypeArray = &FrameTypeArray[0];
+ OpenParameters.FrameTypeArraySize = sizeof(FrameTypeArray) / sizeof(NET_FRAME_TYPE);
+
+
+ NDIS_DECLARE_PROTOCOL_OPEN_CONTEXT(NDISPROT_OPEN_CONTEXT);
+ Status = NdisOpenAdapterEx(Globals.NdisProtocolHandle,
+ (NDIS_HANDLE)pOpenContext,
+ &OpenParameters,
+ BindContext,
+ &pOpenContext->BindingHandle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NPROT_WAIT_EVENT(&pOpenContext->BindEvent, 0);
+ Status = pOpenContext->BindStatus;
+ }
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, ("CreateBinding: NdisOpenAdapter (%ws) failed: %x\n",
+ pOpenContext->DeviceName.Buffer, Status));
+ break;
+ }
+
+ pOpenContext->State = NdisprotPaused;
+
+ fOpenComplete = TRUE;
+
+ //
+ // Get the friendly name for the adapter. It is not fatal for this
+ // to fail.
+ //
+ (VOID)NdisQueryAdapterInstanceName(
+ &pOpenContext->DeviceDescr,
+ pOpenContext->BindingHandle
+ );
+
+ NdisMoveMemory(&pOpenContext->CurrentAddress[0],
+ BindParameters->CurrentMacAddress,
+ NPROT_MAC_ADDR_LEN);
+ //
+ // Get MAC options.
+ //
+ pOpenContext->MacOptions = BindParameters->MacOptions;
+
+
+ //
+ // Get the max frame size.
+ //
+ pOpenContext->MaxFrameSize = BindParameters->MtuSize;
+
+ //
+ // Get the media connect status.
+ //
+ GenericUlong = BindParameters->MediaConnectState;
+
+ if (GenericUlong == NdisMediaStateConnected)
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_MEDIA_FLAGS, NPROTO_MEDIA_CONNECTED);
+ }
+ else
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_MEDIA_FLAGS, NPROTO_MEDIA_DISCONNECTED);
+ }
+ //
+ // Get the back fill size
+ //
+ pOpenContext->DataBackFillSize = BindParameters->DataBackFillSize;
+ pOpenContext->ContextBackFillSize = BindParameters->ContextBackFillSize;
+
+ //
+ // Mark this open. Also check if we received an Unbind while
+ // we were setting this up.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE);
+
+ ASSERT(!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_UNBIND_FLAGS, NPROTO_UNBIND_RECEIVED));
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ }
+ while (FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Check if we had actually finished opening the adapter.
+ //
+ if (fOpenComplete)
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE);
+ }
+ else if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_OPENING))
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_FAILED);
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ ndisprotShutdownBinding(pOpenContext);
+ }
+
+ DEBUGP(DL_INFO, ("CreateBinding: OpenContext %p, Status %x\n",
+ pOpenContext, Status));
+
+ return (Status);
+}
+
+
+
+VOID
+ndisprotShutdownBinding(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Utility function to shut down the NDIS binding, if one exists, on
+ the specified open. This is written to be called from:
+
+ ndisprotCreateBinding - on failure
+ NdisprotUnbindAdapter
+
+ We handle the case where a binding is in the process of being set up.
+ This precaution is not needed if this routine is only called from
+ the context of our UnbindAdapter handler, but they are here in case
+ we initiate unbinding from elsewhere (e.g. on processing a user command).
+
+ NOTE: this blocks and finishes synchronously.
+
+Arguments:
+
+ pOpenContext - pointer to open context block
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_STATUS Status;
+ BOOLEAN DoCloseBinding = FALSE;
+ NPROT_EVENT ClosingEvent;
+
+ do
+ {
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_OPENING))
+ {
+ //
+ // We are still in the process of setting up this binding.
+ //
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ break;
+ }
+
+ if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ ASSERT(pOpenContext->ClosingEvent == NULL);
+ pOpenContext->ClosingEvent = NULL;
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING);
+
+ if (pOpenContext->PendedSendCount != 0)
+ {
+ pOpenContext->ClosingEvent = &ClosingEvent;
+ NPROT_INIT_EVENT(&ClosingEvent);
+ }
+
+ DoCloseBinding = TRUE;
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (DoCloseBinding)
+ {
+ ULONG PacketFilter = 0;
+ ULONG BytesRead = 0;
+
+ //
+ // Set Packet filter to 0 before closing the binding
+ //
+ Status = ndisprotDoRequest(
+ pOpenContext,
+ NDIS_DEFAULT_PORT_NUMBER,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesRead);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, ("ShutDownBinding: set packet filter failed: %x\n", Status));
+ }
+
+ //
+ // Set multicast list to null before closing the binding
+ //
+ Status = ndisprotDoRequest(
+ pOpenContext,
+ NDIS_DEFAULT_PORT_NUMBER,
+ NdisRequestSetInformation,
+ OID_802_3_MULTICAST_LIST,
+ NULL,
+ 0,
+ &BytesRead);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, ("ShutDownBinding: set multicast list failed: %x\n", Status));
+ }
+
+ //
+ // Wait for any pending sends or requests on
+ // the binding to complete.
+ //
+ ndisprotWaitForPendingIO(pOpenContext, TRUE);
+
+ //
+ // Discard any queued receives.
+ //
+ ndisprotFlushReceiveQueue(pOpenContext);
+
+ //
+ // Close the binding now.
+ //
+ NPROT_INIT_EVENT(&pOpenContext->BindEvent);
+
+ DEBUGP(DL_INFO, ("ShutdownBinding: Closing OpenContext %p,"
+ " BindingHandle %p\n",
+ pOpenContext, pOpenContext->BindingHandle));
+
+ Status = NdisCloseAdapterEx(pOpenContext->BindingHandle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NPROT_WAIT_EVENT(&pOpenContext->BindEvent, 0);
+ Status = pOpenContext->BindStatus;
+ }
+
+ NPROT_ASSERT(Status == NDIS_STATUS_SUCCESS);
+
+ pOpenContext->BindingHandle = NULL;
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_IDLE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_UNBIND_FLAGS, 0);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ }
+ } while (FALSE);
+
+
+ //
+ // Remove it from the global list.
+ //
+ NPROT_ACQUIRE_LOCK(&Globals.GlobalLock, FALSE);
+
+ NPROT_REMOVE_ENTRY_LIST(&pOpenContext->Link);
+
+ NPROT_RELEASE_LOCK(&Globals.GlobalLock, FALSE);
+
+ //
+ // Free any other resources allocated for this bind.
+ //
+ ndisprotFreeBindResources(pOpenContext);
+
+ NPROT_DEREF_OPEN(pOpenContext); // Shutdown binding
+
+}
+
+
+VOID
+ndisprotFreeBindResources(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Free any resources set up for an NDIS binding.
+
+Arguments:
+
+ pOpenContext - pointer to open context block
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (pOpenContext->SendNetBufferListPool != NULL)
+ {
+ NdisFreeNetBufferListPool(pOpenContext->SendNetBufferListPool);
+ pOpenContext->SendNetBufferListPool = NULL;
+ }
+
+ if (pOpenContext->RecvNetBufferListPool != NULL)
+ {
+ NdisFreeNetBufferListPool(pOpenContext->RecvNetBufferListPool);
+ pOpenContext->RecvNetBufferListPool = NULL;
+ }
+
+ if (pOpenContext->DeviceName.Buffer != NULL)
+ {
+ NPROT_FREE_MEM(pOpenContext->DeviceName.Buffer);
+ pOpenContext->DeviceName.Buffer = NULL;
+ pOpenContext->DeviceName.Length =
+ pOpenContext->DeviceName.MaximumLength = 0;
+ }
+
+ if (pOpenContext->DeviceDescr.Buffer != NULL)
+ {
+ //
+ // this would have been allocated by NdisQueryAdpaterInstanceName.
+ //
+ NdisFreeMemory(pOpenContext->DeviceDescr.Buffer, 0, 0);
+ pOpenContext->DeviceDescr.Buffer = NULL;
+ }
+}
+
+
+VOID
+ndisprotWaitForPendingIO(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN BOOLEAN DoCancelReads
+ )
+/*++
+
+Routine Description:
+
+ Utility function to wait for all outstanding I/O to complete
+ on an open context. It is assumed that the open context
+ won't go away while we are in this routine.
+
+Arguments:
+
+ pOpenContext - pointer to open context structure
+ DoCancelReads - do we wait for pending reads to go away (and cancel them)?
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Wait for any pending sends or requests on the binding to complete.
+ //
+ if (pOpenContext->PendedSendCount == 0)
+ {
+ ASSERT(pOpenContext->ClosingEvent == NULL);
+ }
+ else
+ {
+ ASSERT(pOpenContext->ClosingEvent != NULL);
+ DEBUGP(DL_WARN, ("WaitForPendingIO: Open %p, %d pended sends\n",
+ pOpenContext, pOpenContext->PendedSendCount));
+
+ NPROT_WAIT_EVENT(pOpenContext->ClosingEvent, 0);
+
+ }
+
+ if (DoCancelReads)
+ {
+ //
+ // Wait for any pended reads to complete/cancel.
+ //
+ while (pOpenContext->PendedReadCount != 0)
+ {
+ DEBUGP(DL_INFO, ("WaitForPendingIO: Open %p, %d pended reads\n",
+ pOpenContext, pOpenContext->PendedReadCount));
+
+ //
+ // Cancel any pending reads.
+ //
+ ndisprotCancelPendingReads(pOpenContext);
+
+ NdisMSleep(100000); // 100 ms.
+ }
+ }
+
+}
+
+
+VOID
+ndisprotDoProtocolUnload(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Utility routine to handle unload from the NDIS protocol side.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_HANDLE ProtocolHandle;
+
+ DEBUGP(DL_INFO, ("ProtocolUnload: ProtocolHandle %lp\n",
+ Globals.NdisProtocolHandle));
+
+ if (Globals.NdisProtocolHandle != NULL)
+ {
+ ProtocolHandle = Globals.NdisProtocolHandle;
+ Globals.NdisProtocolHandle = NULL;
+
+ NdisDeregisterProtocolDriver(ProtocolHandle);
+
+ }
+}
+
+
+NDIS_STATUS
+ndisprotDoRequest(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesProcessed
+ )
+/*++
+
+Routine Description:
+
+ Utility routine that forms and sends an NDIS_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 binding handle until this returns.
+
+Arguments:
+
+ pOpenContext - pointer to our open context
+ PortNumber - the port to issue the request
+ RequestType - NdisRequest[Set|Query|Method]Information
+ Oid - the object being set/queried
+ InformationBuffer - data for the request
+ InformationBufferLength - length of the above
+ pBytesProcessed - place to return bytes read/written
+
+Return Value:
+
+ Status of the set/query/method request
+
+--*/
+{
+ NDISPROT_REQUEST ReqContext;
+ PNDIS_OID_REQUEST pNdisRequest = &ReqContext.Request;
+ NDIS_STATUS Status;
+
+
+ NdisZeroMemory(&ReqContext, sizeof(ReqContext));
+
+ NPROT_INIT_EVENT(&ReqContext.ReqEvent);
+ pNdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pNdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pNdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
+ pNdisRequest->RequestType = RequestType;
+ pNdisRequest->PortNumber = PortNumber;
+
+ switch (RequestType)
+ {
+ case NdisRequestQueryInformation:
+ pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ case NdisRequestSetInformation:
+ pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
+ pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
+ InformationBuffer;
+ pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
+ InformationBufferLength;
+ break;
+
+ default:
+ NPROT_ASSERT(FALSE);
+ break;
+ }
+
+ pNdisRequest->RequestId = NPROT_GET_NEXT_CANCEL_ID();
+ Status = NdisOidRequest(pOpenContext->BindingHandle,
+ pNdisRequest);
+
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+
+ NPROT_WAIT_EVENT(&ReqContext.ReqEvent, 0);
+ Status = ReqContext.Status;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *pBytesProcessed = (RequestType == NdisRequestQueryInformation)?
+ pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten:
+ pNdisRequest->DATA.SET_INFORMATION.BytesRead;
+
+ //
+ // The driver below should set the correct value to BytesWritten
+ // or BytesRead. But now, we just truncate the value to InformationBufferLength
+ //
+ if (*pBytesProcessed > InformationBufferLength)
+ {
+ *pBytesProcessed = InformationBufferLength;
+ }
+ }
+
+ return (Status);
+}
+
+
+NDIS_STATUS
+ndisprotValidateOpenAndDoRequest(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesProcessed,
+ IN BOOLEAN bWaitForPowerOn
+ )
+/*++
+
+Routine Description:
+
+ Utility routine to prevalidate and reference an open context
+ before calling ndisprotDoRequest. This routine makes sure
+ we have a valid binding.
+
+Arguments:
+
+ pOpenContext - pointer to our open context
+ RequestType - NdisRequest[Set|Query]Information
+ Oid - the object being set/queried
+ InformationBuffer - data for the request
+ InformationBufferLength - length of the above
+ pBytesProcessed - place to return bytes read/written
+ bWaitForPowerOn - Wait for the device to be powered on if it isn't already.
+
+Return Value:
+
+ Status of the set/query request
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ do
+ {
+ if (pOpenContext == NULL)
+ {
+ DEBUGP(DL_WARN, ("ValidateOpenAndDoRequest: request on unassociated file object!\n"));
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Proceed only if we have a binding.
+ //
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ NPROT_ASSERT(pOpenContext->BindingHandle != NULL);
+
+ //
+ // Make sure that the binding does not go away until we
+ // are finished with the request.
+ //
+ pOpenContext->PendedSendCount++;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (bWaitForPowerOn)
+ {
+ //
+ // Wait for the device below to be powered up.
+ // We don't wait indefinitely here - this is to avoid
+ // a PROCESS_HAS_LOCKED_PAGES bugcheck that could happen
+ // if the calling process terminates, and this IRP doesn't
+ // complete within a reasonable time. An alternative would
+ // be to explicitly handle cancellation of this IRP.
+ //
+ //NPROT_WAIT_EVENT(&pOpenContext->PoweredUpEvent, 4500);
+ //the following replace NPROT_WAIT_EVENT(&pOpenContext->PoweredUpEvent, 4500); to supress prefast warning 28193
+ NdisWaitEvent(&pOpenContext->PoweredUpEvent, 4500);
+ }
+
+ if (pOpenContext->PowerState == NetDeviceStateD0)
+ {
+
+ Status = ndisprotDoRequest(
+ pOpenContext,
+ NDIS_DEFAULT_PORT_NUMBER,
+ RequestType,
+ Oid,
+ InformationBuffer,
+ InformationBufferLength,
+ pBytesProcessed);
+ }
+ else
+ {
+ Status = NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ //
+ // Let go of the binding.
+ //
+ pOpenContext->PendedSendCount --;
+ if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
+ && (pOpenContext->PendedSendCount == 0))
+ {
+ ASSERT(pOpenContext->ClosingEvent != NULL);
+ NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
+ pOpenContext->ClosingEvent = NULL;
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ }
+ while (FALSE);
+
+ DEBUGP(DL_LOUD, ("ValidateOpenAndDoReq: Open %p/%x, OID %x, Status %x\n",
+ pOpenContext, pOpenContext->Flags, Oid, Status));
+
+ return (Status);
+}
+
+
+VOID
+NdisprotRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_OID_REQUEST pNdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ NDIS entry point indicating completion of a pended NDIS_REQUEST.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context
+ pNdisRequest - pointer to NDIS request
+ Status - status of reset completion
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PNDISPROT_REQUEST pReqContext;
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Get at the request context.
+ //
+ pReqContext = CONTAINING_RECORD(pNdisRequest, NDISPROT_REQUEST, Request);
+
+ //
+ // Save away the completion status.
+ //
+ pReqContext->Status = Status;
+
+ //
+ // Wake up the thread blocked for this request to complete.
+ //
+ NPROT_SIGNAL_EVENT(&pReqContext->ReqEvent);
+}
+
+
+VOID
+NdisprotStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STATUS_INDICATION StatusIndication
+ )
+/*++
+
+Routine Description:
+
+ Protocol entry point called by NDIS to indicate a change
+ in status at the miniport.
+
+ We make note of reset and media connect status indications.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context
+ StatusIndication - pointer to NDIS_STATUS_INDICATION
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ NDIS_STATUS GeneralStatus;
+ PNDIS_LINK_STATE LinkState;
+
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+
+ if ((StatusIndication->Header.Type != NDIS_OBJECT_TYPE_STATUS_INDICATION)
+ || (StatusIndication->Header.Size != sizeof(NDIS_STATUS_INDICATION)))
+ {
+ DEBUGP(DL_INFO, ("Status: Received an invalid status indication: Open %p, StatusIndication %p\n",
+ pOpenContext, StatusIndication));
+ return;
+ }
+
+ GeneralStatus = StatusIndication->StatusCode;
+
+ DEBUGP(DL_INFO, ("Status: Open %p, Status %x\n",
+ pOpenContext, GeneralStatus));
+
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ do
+ {
+ if (pOpenContext->PowerState != NetDeviceStateD0)
+ {
+ //
+ //
+ // The device is in a low power state.
+
+ //
+ // We continue and make note of status indications
+ //
+
+ //
+ // NOTE that any actions we take based on these
+ // status indications should take into account
+ // the current device power state.
+ //
+ }
+
+ switch(GeneralStatus)
+ {
+ case NDIS_STATUS_RESET_START:
+
+ NPROT_ASSERT(!NPROT_TEST_FLAGS(pOpenContext->Flags,
+ NPROTO_RESET_FLAGS,
+ NPROTO_RESET_IN_PROGRESS));
+
+ NPROT_SET_FLAGS(pOpenContext->Flags,
+ NPROTO_RESET_FLAGS,
+ NPROTO_RESET_IN_PROGRESS);
+
+ break;
+
+ case NDIS_STATUS_RESET_END:
+
+ NPROT_ASSERT(NPROT_TEST_FLAGS(pOpenContext->Flags,
+ NPROTO_RESET_FLAGS,
+ NPROTO_RESET_IN_PROGRESS));
+
+ NPROT_SET_FLAGS(pOpenContext->Flags,
+ NPROTO_RESET_FLAGS,
+ NPROTO_NOT_RESETTING);
+
+ break;
+
+ case NDIS_STATUS_LINK_STATE:
+
+ ASSERT(StatusIndication->StatusBufferSize >= sizeof(NDIS_LINK_STATE));
+
+ LinkState = (PNDIS_LINK_STATE)StatusIndication->StatusBuffer;
+
+ if (LinkState->MediaConnectState == MediaConnectStateConnected)
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags,
+ NPROTO_MEDIA_FLAGS,
+ NPROTO_MEDIA_CONNECTED);
+ }
+ else
+ {
+ NPROT_SET_FLAGS(pOpenContext->Flags,
+ NPROTO_MEDIA_FLAGS,
+ NPROTO_MEDIA_DISCONNECTED);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (FALSE);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+}
+
+NDIS_STATUS
+ndisprotWriteString(
+ _Out_writes_bytes_to_(OutputLength, *pBytesWritten)
+ PUCHAR pBuffer,
+ _In_ ULONG OutputLength,
+ _Out_ PULONG pBytesWritten,
+ _In_ PNDIS_STRING String
+ )
+/*++
+
+Routine Description:
+
+ Writes an NDIS_STRING to an output buffer as a NULL-terminated string
+
+Arguments:
+
+ pBuffer - output buffer
+ OutputLength - size of pBuffer
+ pBytesWritten - receives the number of bytes written to pBuffer
+ String - NDIS_STRING to write
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful
+ NDIS_STATUS_BUFFER_OVERFLOW if OutputLength is insufficient
+
+--*/
+{
+ ULONG BytesNeeded = String->Length + sizeof(UNICODE_NULL);
+
+ if (OutputLength < BytesNeeded)
+ {
+ return NDIS_STATUS_BUFFER_OVERFLOW;
+ }
+
+ NPROT_COPY_MEM(pBuffer, String->Buffer, String->Length);
+ *(PWCHAR)(pBuffer + String->Length) = UNICODE_NULL;
+
+ *pBytesWritten = BytesNeeded;
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS
+ndisprotQueryBinding(
+ _Inout_updates_bytes_to_(OutputLength, *pBytesReturned)
+ PUCHAR pBuffer,
+ _In_ ULONG InputLength,
+ _In_ ULONG OutputLength,
+ _Out_ PULONG pBytesReturned
+ )
+/*++
+
+Routine Description:
+
+ Return information about the specified binding.
+
+Arguments:
+
+ pBuffer - pointer to NDISPROT_QUERY_BINDING
+ InputLength - input buffer size
+ OutputLength - output buffer size
+ pBytesReturned - place to return copied byte count.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful, failure code otherwise.
+
+--*/
+{
+ PNDISPROT_QUERY_BINDING pQueryBinding;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PLIST_ENTRY pEnt;
+ ULONG BindingIndex;
+ NDIS_STATUS Status;
+ ULONG DeviceNameOffset;
+ ULONG DeviceDescrOffset;
+ ULONG StringBytesWritten;
+
+ do
+ {
+ *pBytesReturned = 0;
+
+ if (InputLength < sizeof(NDISPROT_QUERY_BINDING))
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ if (OutputLength < sizeof(NDISPROT_QUERY_BINDING))
+ {
+ Status = NDIS_STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ pQueryBinding = (PNDISPROT_QUERY_BINDING)pBuffer;
+ BindingIndex = pQueryBinding->BindingIndex;
+
+ Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+ pOpenContext = NULL;
+
+ NPROT_ACQUIRE_LOCK(&Globals.GlobalLock, FALSE);
+
+ for (pEnt = Globals.OpenList.Flink;
+ pEnt != &Globals.OpenList;
+ pEnt = pEnt->Flink)
+ {
+ pOpenContext = CONTAINING_RECORD(pEnt, NDISPROT_OPEN_CONTEXT, Link);
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Skip if not bound.
+ //
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ continue;
+ }
+
+ if (BindingIndex == 0)
+ {
+ //
+ // Got the binding we are looking for. Copy the device
+ // name and description strings to the output buffer.
+ //
+ DEBUGP(DL_INFO,
+ ("QueryBinding: found open %p\n", pOpenContext));
+
+ pQueryBinding->DeviceNameOffset = 0;
+ pQueryBinding->DeviceNameLength = pOpenContext->DeviceName.Length;
+ pQueryBinding->DeviceDescrOffset = 0;
+ pQueryBinding->DeviceDescrLength = pOpenContext->DeviceDescr.Length;
+
+ *pBytesReturned = sizeof(NDISPROT_QUERY_BINDING);
+
+ //
+ // Copy the DeviceName string
+ //
+
+ DeviceNameOffset = sizeof(NDISPROT_QUERY_BINDING);
+
+ Status = ndisprotWriteString(pBuffer + DeviceNameOffset,
+ OutputLength - DeviceNameOffset,
+ &StringBytesWritten,
+ &pOpenContext->DeviceName);
+
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ break;
+ }
+
+ pQueryBinding->DeviceNameOffset = DeviceNameOffset;
+ *pBytesReturned += StringBytesWritten;
+
+ //
+ // Copy the DeviceDescr string
+ //
+
+ DeviceDescrOffset = DeviceNameOffset + StringBytesWritten;
+
+ Status = ndisprotWriteString(pBuffer + DeviceDescrOffset,
+ OutputLength - DeviceDescrOffset,
+ &StringBytesWritten,
+ &pOpenContext->DeviceDescr);
+
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ break;
+ }
+
+ pQueryBinding->DeviceDescrOffset = DeviceDescrOffset;
+ *pBytesReturned += StringBytesWritten;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ BindingIndex--;
+ }
+
+ NPROT_RELEASE_LOCK(&Globals.GlobalLock, FALSE);
+
+ }
+ while (FALSE);
+
+ return (Status);
+}
+
+PNDISPROT_OPEN_CONTEXT
+ndisprotLookupDevice(
+ _In_reads_bytes_(BindingInfoLength) IN PUCHAR pBindingInfo,
+ IN ULONG BindingInfoLength
+ )
+/*++
+
+Routine Description:
+
+ Search our global list for an open context structure that
+ has a binding to the specified device, and return a pointer
+ to it.
+
+ NOTE: we reference the open that we return.
+
+Arguments:
+
+ pBindingInfo - pointer to unicode device name string
+ BindingInfoLength - length in bytes of the above.
+
+Return Value:
+
+ Pointer to the matching open context if found, else NULL
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PLIST_ENTRY pEnt;
+
+ pOpenContext = NULL;
+
+ NPROT_ACQUIRE_LOCK(&Globals.GlobalLock, FALSE);
+
+ for (pEnt = Globals.OpenList.Flink;
+ pEnt != &Globals.OpenList;
+ pEnt = pEnt->Flink)
+ {
+ pOpenContext = CONTAINING_RECORD(pEnt, NDISPROT_OPEN_CONTEXT, Link);
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Check if this has the name we are looking for.
+ //
+ if ((pOpenContext->DeviceName.Length == BindingInfoLength) &&
+ NPROT_MEM_CMP(pOpenContext->DeviceName.Buffer, pBindingInfo, BindingInfoLength))
+ {
+ NPROT_REF_OPEN(pOpenContext); // ref added by LookupDevice
+ break;
+ }
+
+ pOpenContext = NULL;
+ }
+
+ NPROT_RELEASE_LOCK(&Globals.GlobalLock, FALSE);
+
+ return (pOpenContext);
+}
+
+
+NDIS_STATUS
+ndisprotQueryOidValue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ OUT PVOID pDataBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG pBytesWritten
+ )
+/*++
+
+Routine Description:
+
+ Query an arbitrary OID value from the miniport.
+
+Arguments:
+
+ pOpenContext - pointer to open context representing our binding to the miniport
+ pDataBuffer - place to store the returned value
+ BufferLength - length of the above
+ pBytesWritten - place to return length returned
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we successfully queried the OID.
+ NDIS_STATUS_XXX error code otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDISPROT_QUERY_OID pQuery;
+ NDIS_OID Oid;
+
+ Oid = 0;
+
+ do
+ {
+ if (BufferLength < sizeof(NDISPROT_QUERY_OID))
+ {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ break;
+ }
+
+ pQuery = (PNDISPROT_QUERY_OID)pDataBuffer;
+ Oid = pQuery->Oid;
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ DEBUGP(DL_WARN,
+ ("QueryOid: Open %p/%x is in invalid state\n",
+ pOpenContext, pOpenContext->Flags));
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure the binding doesn't go away.
+ //
+ pOpenContext->PendedSendCount++;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ Status = ndisprotDoRequest(
+ pOpenContext,
+ pQuery->PortNumber,
+ NdisRequestQueryInformation,
+ Oid,
+ &pQuery->Data[0],
+ BufferLength - FIELD_OFFSET(NDISPROT_QUERY_OID, Data),
+ pBytesWritten);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Let go of the binding.
+ //
+ pOpenContext->PendedSendCount --;
+ if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
+ && (pOpenContext->PendedSendCount == 0))
+ {
+ ASSERT(pOpenContext->ClosingEvent != NULL);
+ NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
+ pOpenContext->ClosingEvent = NULL;
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *pBytesWritten += FIELD_OFFSET(NDISPROT_QUERY_OID, Data);
+ }
+
+ }
+ while (FALSE);
+
+ DEBUGP(DL_LOUD, ("QueryOid: Open %p/%x, OID %x, Status %x\n",
+ pOpenContext, pOpenContext->Flags, Oid, Status));
+
+ return (Status);
+
+}
+
+NDIS_STATUS
+ndisprotSetOidValue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ OUT PVOID pDataBuffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ Set an arbitrary OID value to the miniport.
+
+Arguments:
+
+ pOpenContext - pointer to open context representing our binding to the miniport
+ pDataBuffer - buffer that contains the value to be set
+ BufferLength - length of the above
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we successfully set the OID
+ NDIS_STATUS_XXX error code otherwise.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDISPROT_SET_OID pSet;
+ NDIS_OID Oid;
+ ULONG BytesWritten;
+
+ Oid = 0;
+
+ do
+ {
+ if (BufferLength < sizeof(NDISPROT_SET_OID))
+ {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ break;
+ }
+
+ pSet = (PNDISPROT_SET_OID)pDataBuffer;
+ Oid = pSet->Oid;
+
+ //
+ // We should check the OID is settable by the user mode apps
+ //
+ if (!ndisprotValidOid(Oid))
+ {
+ DEBUGP(DL_WARN, ("SetOid: Oid %x cannot be set\n", Oid));
+
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ DEBUGP(DL_WARN,
+ ("SetOid: Open %p/%x is in invalid state\n",
+ pOpenContext, pOpenContext->Flags));
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Make sure the binding doesn't go away.
+ //
+ pOpenContext->PendedSendCount++;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ Status = ndisprotDoRequest(
+ pOpenContext,
+ pSet->PortNumber,
+ NdisRequestSetInformation,
+ Oid,
+ &pSet->Data[0],
+ BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data),
+ &BytesWritten);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Let go of the binding.
+ //
+ pOpenContext->PendedSendCount --;
+ if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
+ && (pOpenContext->PendedSendCount == 0))
+ {
+ ASSERT(pOpenContext->ClosingEvent != NULL);
+ NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
+ pOpenContext->ClosingEvent = NULL;
+ }
+
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ }
+ while (FALSE);
+
+ DEBUGP(DL_LOUD, ("SetOid: Open %p/%x, OID %x, Status %x\n",
+ pOpenContext, pOpenContext->Flags, Oid, Status));
+
+ return (Status);
+}
+
+BOOLEAN
+ndisprotValidOid(
+ IN NDIS_OID Oid
+ )
+/*++
+
+Routine Description:
+
+ Validate whether the given set OID is settable or not.
+
+Arguments:
+
+ Oid - The OID which the user tries to set.
+
+Return Value:
+
+ TRUE if the OID is allowed to set
+ FALSE otherwise.
+
+--*/
+{
+ UINT i;
+ UINT NumOids;
+
+ NumOids = sizeof(ndisprotSupportedSetOids) / sizeof(NDIS_OID);
+
+ for (i = 0; i < NumOids; i++)
+ {
+ if (ndisprotSupportedSetOids[i] == Oid)
+ {
+ break;
+ }
+ }
+
+ return (i < NumOids);
+}
+
+
+
+VOID
+#pragma warning(suppress:6262) // Function is only 22 bytes over the 1k guideline, reasonable enough.
+ndisprotRestart(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNDIS_PROTOCOL_RESTART_PARAMETERS RestartParameters
+ )
+/*++
+
+Routine Description:
+
+ Handle restart attributes changes.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+ RestartParameters - pointer to ndis restart parameters
+
+Return Value:
+
+ None
+
+NOTE: Protocols should query any attribute:
+ 1. the attribute is not included in the RestartAttributes
+ and 2. The protocol cares about whether the attributes is changed by underlying driver.
+
+--*/
+
+{
+ ULONG Length;
+ ULONG TotalLength = 0;
+ PUCHAR Buffer;
+ ULONG BufferLength;
+#define NPROT_MAX_FILTER_NAME_LENGTH 512
+
+ WCHAR FilterNameBuffer[NPROT_MAX_FILTER_NAME_LENGTH];
+ PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes;
+ PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes;
+
+ DEBUGP(DL_LOUD, ("ndisprotRestart: Open %p", pOpenContext));
+ //
+ // Check the filter stack changes
+ //
+ if (RestartParameters->FilterModuleNameBuffer != NULL)
+ {
+
+ Buffer = RestartParameters->FilterModuleNameBuffer;
+
+ while (RestartParameters->FilterModuleNameBufferLength > TotalLength)
+ {
+
+ BufferLength = *(PUSHORT)Buffer;
+
+ TotalLength += BufferLength + sizeof(USHORT);
+ Length = BufferLength + sizeof(USHORT);
+
+ if (BufferLength >= (NPROT_MAX_FILTER_NAME_LENGTH * sizeof(WCHAR)))
+ {
+ BufferLength = (NPROT_MAX_FILTER_NAME_LENGTH - 1) * sizeof(WCHAR);
+ }
+ NdisMoveMemory(FilterNameBuffer, Buffer + sizeof(USHORT), BufferLength);
+
+ BufferLength /= sizeof(WCHAR);
+
+ //
+ // BufferLength is bounded by the check above. Check again to suppress
+ // prefast warning
+ //
+ if (BufferLength < NPROT_MAX_FILTER_NAME_LENGTH)
+ {
+ FilterNameBuffer[BufferLength] = 0;
+ }
+
+ DEBUGP(DL_INFO, ("Filter: %ws\n", FilterNameBuffer));
+
+ Buffer += Length;
+ }
+ }
+ //
+ // Checked for updated attributes
+ //
+ NdisRestartAttributes = RestartParameters->RestartAttributes;
+
+ //
+ // NdisProt is only interested in the generic attributes.
+ //
+ while (NdisRestartAttributes != NULL)
+ {
+ if (NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
+ {
+ break;
+ }
+ NdisRestartAttributes = NdisRestartAttributes->Next;
+ }
+
+ //
+ // Pick up the new attributes of interest
+ //
+ if (NdisRestartAttributes != NULL)
+ {
+ NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data;
+
+ pOpenContext->MacOptions = NdisGeneralAttributes->MacOptions;
+ pOpenContext->MaxFrameSize = NdisGeneralAttributes->MtuSize;
+ }
+
+ DEBUGP(DL_LOUD, ("ndisprotRestart: Open %p", pOpenContext));
+
+}
+
+
diff --git a/network/ndis/ndisprot/6x/sys/ndisprot.h b/network/ndis/ndisprot/6x/sys/ndisprot.h
new file mode 100644
index 00000000..60ebb2af
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/ndisprot.h
@@ -0,0 +1,567 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ ndisprot.h
+
+Abstract:
+
+ Data structures, defines and function prototypes for NDISPROT.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#ifndef __NDISPROT__H
+#define __NDISPROT__H
+
+#pragma warning(disable:28930) // Unused assignment of pointer, by design in samples
+#pragma warning(disable:28931) // Unused assignment of variable, by design in samples
+
+//
+// Update the driver version number every time you release a new driver
+// The high word is the major version. The low word is the minor version.
+// Also make sure that VER_FILEVERSION specified in the .RC file also
+// matches with the driver version.
+//
+// Let's say we're version 4.2.
+//
+#define MAJOR_DRIVER_VERSION 0x04
+#define MINOR_DRIVER_VERISON 0x02
+
+
+//
+// Define the NDIS protocol interface version that this driver targets.
+//
+#if defined(NDIS60)
+# define NDIS_PROT_MAJOR_VERSION 6
+# define NDIS_PROT_MINOR_VERSION 0
+#elif defined(NDIS630)
+# define NDIS_PROT_MAJOR_VERSION 6
+# define NDIS_PROT_MINOR_VERSION 30
+#else
+# error Unsupported NDIS version
+#endif
+
+
+#define NT_DEVICE_NAME L"\\Device\\Ndisprot"
+#define DOS_DEVICE_NAME L"\\Global??\\Ndisprot"
+
+
+//
+// Abstract types
+//
+typedef NDIS_EVENT NPROT_EVENT, *PNPROT_EVENT;
+
+#define MAX_MULTICAST_ADDRESS 0x20
+
+#define NPROT_MAC_ADDR_LEN 6
+
+
+typedef enum _NDISPROT_OPEN_STATE{
+ NdisprotInitializing,
+ NdisprotRunning,
+ NdisprotPausing,
+ NdisprotPaused,
+ NdisprotRestarting,
+ NdisprotClosing
+} NDISPROT_OPEN_STATE;
+//
+// The Open Context represents an open of our device object.
+// We allocate this on processing a BindAdapter from NDIS,
+// and free it when all references (see below) to it are gone.
+//
+// Binding/unbinding to an NDIS device:
+//
+// On processing a BindAdapter call from NDIS, we set up a binding
+// to the specified NDIS device (miniport). This binding is
+// torn down when NDIS asks us to Unbind by calling
+// our UnbindAdapter handler.
+//
+// Receiving data:
+//
+// While an NDIS binding exists, read IRPs are queued on this
+// structure, to be processed when packets are received.
+// If data arrives in the absense of a pended read IRP, we
+// queue it, to the extent of one packet, i.e. we save the
+// contents of the latest packet received. We fail read IRPs
+// received when no NDIS binding exists (or is in the process
+// of being torn down).
+//
+// Sending data:
+//
+// Write IRPs are used to send data. Each write IRP maps to
+// a single NDIS packet. Packet send-completion is mapped to
+// write IRP completion. We use NDIS 5.1 CancelSend to support
+// write IRP cancellation. Write IRPs that arrive when we don't
+// have an active NDIS binding are failed.
+//
+// Reference count:
+//
+// The following are long-lived references:
+// OPEN_DEVICE ioctl (goes away on processing a Close IRP)
+// Pended read IRPs
+// Queued received packets
+// Uncompleted write IRPs (outstanding sends)
+// Existence of NDIS binding
+//
+typedef struct _NDISPROT_OPEN_CONTEXT
+{
+ LIST_ENTRY Link; // Link into global list
+ ULONG Flags; // State information
+ ULONG RefCount;
+ NPROT_LOCK Lock;
+
+ PFILE_OBJECT pFileObject; // Set on OPEN_DEVICE
+
+ NDIS_HANDLE BindingHandle;
+ NDIS_HANDLE SendNetBufferListPool;
+ // let every net buffer list contain one net buffer(don't know how many net buffers can be include in one list.
+ NDIS_HANDLE RecvNetBufferListPool;
+
+ ULONG MacOptions;
+ ULONG MaxFrameSize;
+ ULONG DataBackFillSize;
+ ULONG ContextBackFillSize;
+
+ LIST_ENTRY PendedWrites; // pended Write IRPs
+ ULONG PendedSendCount;
+
+ LIST_ENTRY PendedReads; // pended Read IRPs
+ ULONG PendedReadCount;
+ LIST_ENTRY RecvNetBufListQueue;
+ ULONG RecvNetBufListCount;
+
+ NET_DEVICE_POWER_STATE PowerState;
+ NDIS_EVENT PoweredUpEvent; // signalled iff PowerState is D0
+ NDIS_STRING DeviceName; // used in NdisOpenAdapter
+ NDIS_STRING DeviceDescr; // friendly name
+
+ NDIS_STATUS BindStatus; // for Open/CloseAdapter
+ NPROT_EVENT BindEvent; // for Open/CloseAdapter
+
+ ULONG oc_sig; // Signature for sanity
+ NDISPROT_OPEN_STATE State;
+ PNPROT_EVENT ClosingEvent;
+ UCHAR CurrentAddress[NPROT_MAC_ADDR_LEN];
+ UCHAR MCastAddress[MAX_MULTICAST_ADDRESS][NPROT_MAC_ADDR_LEN];
+} NDISPROT_OPEN_CONTEXT, *PNDISPROT_OPEN_CONTEXT;
+
+
+#define oc_signature 'OiuN'
+
+//
+// Definitions for Flags above.
+//
+#define NPROTO_BIND_IDLE 0x00000000
+#define NPROTO_BIND_OPENING 0x00000001
+#define NPROTO_BIND_FAILED 0x00000002
+#define NPROTO_BIND_ACTIVE 0x00000004
+#define NPROTO_BIND_CLOSING 0x00000008
+#define NPROTO_BIND_FLAGS 0x0000000F // State of the binding
+
+#define NPROTO_OPEN_IDLE 0x00000000
+#define NPROTO_OPEN_ACTIVE 0x00000010
+#define NPROTO_OPEN_FLAGS 0x000000F0 // State of the I/O open
+
+#define NPROTO_RESET_IN_PROGRESS 0x00000100
+#define NPROTO_NOT_RESETTING 0x00000000
+#define NPROTO_RESET_FLAGS 0x00000100
+
+#define NPROTO_MEDIA_CONNECTED 0x00000000
+#define NPROTO_MEDIA_DISCONNECTED 0x00000200
+#define NPROTO_MEDIA_FLAGS 0x00000200
+
+#define NPROTO_READ_SERVICING 0x00100000 // Is the read service
+ // routine running?
+#define NPROTO_READ_FLAGS 0x00100000
+
+#define NPROTO_UNBIND_RECEIVED 0x10000000 // Seen NDIS Unbind?
+#define NPROTO_UNBIND_FLAGS 0x10000000
+
+
+#define NPROT_ALLOCATED_NBL 0x10000000
+#define NPROT_NBL_RETREAT_RECV_RSVD 0x20000000
+
+//
+// Globals:
+//
+typedef struct _NDISPROT_GLOBALS
+{
+ PDRIVER_OBJECT pDriverObject;
+ PDEVICE_OBJECT ControlDeviceObject;
+ NDIS_HANDLE NdisProtocolHandle;
+ USHORT EthType; // frame type we are interested in
+ UCHAR PartialCancelId; // for cancelling sends
+ ULONG LocalCancelId;
+ LIST_ENTRY OpenList; // of OPEN_CONTEXT structures
+ NPROT_LOCK GlobalLock; // to protect the above
+ NPROT_EVENT BindsComplete; // have we seen NetEventBindsComplete?
+} NDISPROT_GLOBALS, *PNDISPROT_GLOBALS;
+
+
+//
+// The following are arranged in the way a little-endian processor
+// would read 2 bytes off the wire.
+//
+#define NPROT_ETH_TYPE 0x8e88
+#define NPROT_8021P_TAG_TYPE 0x0081
+
+//
+// NDIS Request context structure
+//
+typedef struct _NDISPROT_REQUEST
+{
+ NDIS_OID_REQUEST Request;
+ NPROT_EVENT ReqEvent;
+ ULONG Status;
+
+} NDISPROT_REQUEST, *PNDISPROT_REQUEST;
+
+
+#define NPROTO_PACKET_FILTER (NDIS_PACKET_TYPE_DIRECTED| \
+ NDIS_PACKET_TYPE_MULTICAST| \
+ NDIS_PACKET_TYPE_BROADCAST)
+
+//
+// Send packet pool bounds
+//
+/*
+#define MIN_SEND_PACKET_POOL_SIZE 20
+*/
+#define MAX_SEND_PACKET_POOL_SIZE 400
+
+
+//
+// ProtocolReserved in sent packets. We save a pointer to the IRP
+// that generated the send.
+//
+// The RefCount is used to determine when to free the packet back
+// to its pool. It is used to synchronize between a thread completing
+// a send and a thread attempting to cancel a send.
+//
+typedef struct _NPROT_SEND_NETBUFLIST_RSVD
+{
+ PIRP pIrp;
+ ULONG RefCount;
+
+} NPROT_SEND_NETBUFLIST_RSVD, *PNPROT_SEND_NETBUFLIST_RSVD;
+//
+// Receive packet pool bounds
+//
+#define MIN_RECV_PACKET_POOL_SIZE 4
+#define MAX_RECV_PACKET_POOL_SIZE 20
+
+//
+// Max receive packets we allow to be queued up
+//
+#define MAX_RECV_QUEUE_SIZE 4
+
+//
+// ProtocolReserved in received packets: we link these
+// packets up in a queue waiting for Read IRPs.
+//
+typedef struct _NPROT_RECV_NBL_RSVD
+{
+ LIST_ENTRY Link;
+ PNET_BUFFER_LIST pNetBufferList; // used if we had to partial-map
+
+} NPROT_RECV_NBL_RSVD, *PNPROT_RECV_NBL_RSVD;
+
+
+#include <pshpack1.h>
+
+typedef struct _NDISPROT_ETH_HEADER
+{
+ UCHAR DstAddr[NPROT_MAC_ADDR_LEN];
+ UCHAR SrcAddr[NPROT_MAC_ADDR_LEN];
+ USHORT EthType;
+
+} NDISPROT_ETH_HEADER;
+
+typedef struct _NDISPROT_ETH_HEADER UNALIGNED * PNDISPROT_ETH_HEADER;
+
+#include <poppack.h>
+
+
+extern NDISPROT_GLOBALS Globals;
+
+
+#define NPROT_ALLOC_TAG 'oiuN'
+
+
+//
+// Prototypes.
+//
+
+DRIVER_INITIALIZE DriverEntry;
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT pDriverObject,
+ IN PUNICODE_STRING pRegistryPath
+ );
+
+DRIVER_UNLOAD NdisprotUnload;
+VOID
+NdisprotUnload(
+ IN PDRIVER_OBJECT pDriverObject
+ );
+
+_Dispatch_type_(IRP_MJ_CREATE) DRIVER_DISPATCH NdisprotOpen;
+
+NTSTATUS
+NdisprotOpen(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+_Dispatch_type_(IRP_MJ_CLOSE) DRIVER_DISPATCH NdisprotClose;
+NTSTATUS
+NdisprotClose(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+_Dispatch_type_(IRP_MJ_CLEANUP) DRIVER_DISPATCH NdisprotCleanup;
+NTSTATUS
+NdisprotCleanup(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH NdisprotIoControl;
+_Function_class_(DRIVER_DISPATCH)
+_IRQL_requires_(PASSIVE_LEVEL)
+_IRQL_requires_same_
+NTSTATUS
+NdisprotIoControl(
+ _In_ IN PDEVICE_OBJECT pDeviceObject,
+ _Inout_ IN PIRP pIrp
+ );
+
+NTSTATUS
+ndisprotOpenDevice(
+ _In_reads_bytes_(DeviceNameLength) IN PUCHAR pDeviceName,
+ IN ULONG DeviceNameLength,
+ IN PFILE_OBJECT pFileObject,
+ OUT PNDISPROT_OPEN_CONTEXT * ppOpenContext
+ );
+
+VOID
+ndisprotRefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+VOID
+ndisprotDerefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+#if DBG
+VOID
+ndisprotDbgRefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+ );
+
+VOID
+ndisprotDbgDerefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+ );
+#endif // DBG
+
+PROTOCOL_BIND_ADAPTER_EX NdisprotBindAdapter;
+
+PROTOCOL_OPEN_ADAPTER_COMPLETE_EX NdisprotOpenAdapterComplete;
+
+PROTOCOL_UNBIND_ADAPTER_EX NdisprotUnbindAdapter;
+
+PROTOCOL_CLOSE_ADAPTER_COMPLETE_EX NdisprotCloseAdapterComplete;
+
+
+PROTOCOL_NET_PNP_EVENT NdisprotPnPEventHandler;
+
+VOID
+NdisprotProtocolUnloadHandler(
+ VOID
+ );
+
+NDIS_STATUS
+ndisprotCreateBinding(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNDIS_BIND_PARAMETERS BindParameters,
+ IN NDIS_HANDLE BindContext,
+ _In_reads_bytes_(BindingInfoLength) IN PUCHAR pBindingInfo,
+ IN ULONG BindingInfoLength
+ );
+
+VOID
+ndisprotShutdownBinding(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+VOID
+ndisprotFreeBindResources(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+VOID
+ndisprotWaitForPendingIO(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN BOOLEAN DoCancelReads
+ );
+
+VOID
+ndisprotDoProtocolUnload(
+ VOID
+ );
+
+NDIS_STATUS
+ndisprotDoRequest(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesProcessed
+ );
+
+NDIS_STATUS
+ndisprotValidateOpenAndDoRequest(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN NDIS_REQUEST_TYPE RequestType,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG pBytesProcessed,
+ IN BOOLEAN bWaitForPowerOn
+ );
+
+PROTOCOL_OID_REQUEST_COMPLETE NdisprotRequestComplete;
+
+PROTOCOL_STATUS_EX NdisprotStatus;
+
+NDIS_STATUS
+ndisprotQueryBinding(
+ _Inout_updates_bytes_to_(OutputLength, *pBytesReturned)
+ PUCHAR pBuffer,
+ _In_ ULONG InputLength,
+ _In_ ULONG OutputLength,
+ _Out_ PULONG pBytesReturned
+ );
+
+PNDISPROT_OPEN_CONTEXT
+ndisprotLookupDevice(
+ _In_reads_bytes_(BindingInfoLength) IN PUCHAR pBindingInfo,
+ IN ULONG BindingInfoLength
+ );
+
+NDIS_STATUS
+ndisprotQueryOidValue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ OUT PVOID pDataBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG pBytesWritten
+ );
+
+NDIS_STATUS
+ndisprotSetOidValue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ OUT PVOID pDataBuffer,
+ IN ULONG BufferLength
+ );
+
+BOOLEAN
+ndisprotValidOid(
+ IN NDIS_OID Oid
+ );
+
+_Dispatch_type_(IRP_MJ_READ) DRIVER_DISPATCH NdisprotRead;
+NTSTATUS
+NdisprotRead(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+DRIVER_CANCEL NdisprotCancelRead;
+VOID
+NdisprotCancelRead(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+VOID
+ndisprotServiceReads(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+PROTOCOL_RECEIVE_NET_BUFFER_LISTS NdisprotReceiveNetBufferLists;
+
+VOID
+ndisprotQueueReceiveNetBufferList(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNET_BUFFER_LIST pRcvNetBufList,
+ BOOLEAN DispatchLevel
+ );
+
+_Success_(return != 0)
+PNET_BUFFER_LIST
+ndisprotAllocateReceiveNetBufferList(
+ _In_ PNDISPROT_OPEN_CONTEXT pOpenContext,
+ _In_ UINT DataLength,
+ _Outptr_result_bytebuffer_(DataLength)
+ PUCHAR * ppDataBuffer
+ );
+
+VOID
+ndisprotFreeReceiveNetBufferList(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNET_BUFFER_LIST pNetBufferList,
+ IN BOOLEAN DispatchLevel
+ );
+
+VOID
+ndisprotCancelPendingReads(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+VOID
+ndisprotFlushReceiveQueue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ );
+
+_Dispatch_type_(IRP_MJ_WRITE) DRIVER_DISPATCH NdisprotWrite;
+NTSTATUS
+NdisprotWrite(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+DRIVER_CANCEL NdisprotCancelWrite;
+VOID
+NdisprotCancelWrite(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+PROTOCOL_SEND_NET_BUFFER_LISTS_COMPLETE NdisprotSendComplete;
+
+VOID
+ndisprotRestart(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNDIS_PROTOCOL_RESTART_PARAMETERS RestartParameters
+ );
+
+#endif // __NDISPROT__H
+
+
diff --git a/network/ndis/ndisprot/6x/sys/ntdisp.c b/network/ndis/ndisprot/6x/sys/ntdisp.c
new file mode 100644
index 00000000..21ceeaeb
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/ntdisp.c
@@ -0,0 +1,916 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ ntdisp.c
+
+Abstract:
+
+ NT Entry points and dispatch routines for NDISPROT.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'PSID'
+
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, NdisprotUnload)
+#pragma alloc_text(PAGE, NdisprotOpen)
+#pragma alloc_text(PAGE, NdisprotClose)
+#pragma alloc_text(PAGE, NdisprotIoControl)
+
+#endif // ALLOC_PRAGMA
+
+
+//
+// Globals:
+//
+NDISPROT_GLOBALS Globals = {0};
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT pDriverObject,
+ IN PUNICODE_STRING pRegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Called on loading. We create a device object to handle user-mode requests
+ on, and register ourselves as a protocol with NDIS.
+
+Arguments:
+
+ pDriverObject - Pointer to driver object created by system.
+
+ pRegistryPath - Pointer to the Unicode name of the registry path
+ for this driver.
+
+Return Value:
+
+ NT Status code
+
+--*/
+{
+ NDIS_PROTOCOL_DRIVER_CHARACTERISTICS protocolChar = {0};
+ NTSTATUS status = STATUS_SUCCESS;
+ NDIS_STRING protoName = NDIS_STRING_CONST("NDISPROT");
+ UNICODE_STRING ntDeviceName;
+ UNICODE_STRING win32DeviceName;
+ BOOLEAN fSymbolicLink = FALSE;
+ PDEVICE_OBJECT deviceObject = NULL;
+ NDIS_HANDLE ProtocolDriverContext={0};
+
+ UNREFERENCED_PARAMETER(pRegistryPath);
+
+ DEBUGP(DL_LOUD, ("DriverEntry\n"));
+
+ Globals.pDriverObject = pDriverObject;
+ Globals.EthType = NPROT_ETH_TYPE;
+ NPROT_INIT_EVENT(&Globals.BindsComplete);
+
+ do
+ {
+ //
+ // Create our device object using which an application can
+ // access NDIS devices.
+ //
+ RtlInitUnicodeString(&ntDeviceName, NT_DEVICE_NAME);
+
+ status = IoCreateDevice (pDriverObject,
+ 0,
+ &ntDeviceName,
+ FILE_DEVICE_NETWORK,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS (status))
+ {
+ //
+ // Either not enough memory to create a deviceobject or another
+ // deviceobject with the same name exits. This could happen
+ // if you install another instance of this device.
+ //
+ break;
+ }
+
+ RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
+
+ status = IoCreateSymbolicLink(&win32DeviceName, &ntDeviceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+ fSymbolicLink = TRUE;
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+ Globals.ControlDeviceObject = deviceObject;
+
+ NPROT_INIT_LIST_HEAD(&Globals.OpenList);
+ NPROT_INIT_LOCK(&Globals.GlobalLock);
+
+ //
+ // Initialize the protocol characterstic structure
+ //
+#if (NDIS_SUPPORT_NDIS630)
+ {C_ASSERT(sizeof(protocolChar) >= NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2);}
+ protocolChar.Header.Type = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS,
+ protocolChar.Header.Size = NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
+ protocolChar.Header.Revision = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
+#elif (NDIS_SUPPORT_NDIS6)
+ {C_ASSERT(sizeof(protocolChar) >= NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1);}
+ protocolChar.Header.Type = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS,
+ protocolChar.Header.Size = NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;
+ protocolChar.Header.Revision = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_1;
+#endif // NDIS MINIPORT VERSION
+
+ protocolChar.MajorNdisVersion = NDIS_PROT_MAJOR_VERSION;
+ protocolChar.MinorNdisVersion = NDIS_PROT_MINOR_VERSION;
+ protocolChar.MajorDriverVersion = MAJOR_DRIVER_VERSION;
+ protocolChar.MinorDriverVersion = MINOR_DRIVER_VERISON;
+ protocolChar.Name = protoName;
+ protocolChar.SetOptionsHandler = NULL;
+ protocolChar.OpenAdapterCompleteHandlerEx = NdisprotOpenAdapterComplete;
+ protocolChar.CloseAdapterCompleteHandlerEx = NdisprotCloseAdapterComplete;
+ protocolChar.SendNetBufferListsCompleteHandler = NdisprotSendComplete;
+ protocolChar.OidRequestCompleteHandler = NdisprotRequestComplete;
+ protocolChar.StatusHandlerEx = NdisprotStatus;
+ protocolChar.UninstallHandler = NULL;
+ protocolChar.ReceiveNetBufferListsHandler = NdisprotReceiveNetBufferLists;
+ protocolChar.NetPnPEventHandler = NdisprotPnPEventHandler;
+ protocolChar.BindAdapterHandlerEx = NdisprotBindAdapter;
+ protocolChar.UnbindAdapterHandlerEx = NdisprotUnbindAdapter;
+
+ //
+ // Register as a protocol driver
+ //
+
+ status = NdisRegisterProtocolDriver(ProtocolDriverContext, // driver context
+ &protocolChar,
+ &Globals.NdisProtocolHandle);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, ("Failed to register protocol with NDIS\n"));
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ Globals.PartialCancelId = NdisGeneratePartialCancelId();
+ Globals.PartialCancelId <<= ((sizeof(PVOID) - 1) * 8);
+ DEBUGP(DL_LOUD, ("DriverEntry: CancelId %lx\n", Globals.PartialCancelId));
+
+ //
+ // Now set only the dispatch points we would like to handle.
+ //
+
+ pDriverObject->MajorFunction[IRP_MJ_CREATE] = NdisprotOpen;
+
+ pDriverObject->MajorFunction[IRP_MJ_CLOSE] = NdisprotClose;
+
+ pDriverObject->MajorFunction[IRP_MJ_READ] = NdisprotRead;
+
+ pDriverObject->MajorFunction[IRP_MJ_WRITE] = NdisprotWrite;
+
+ pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = NdisprotCleanup;
+
+ pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisprotIoControl;
+
+
+ pDriverObject->DriverUnload = NdisprotUnload;
+
+ status = STATUS_SUCCESS;
+
+
+ }
+ while (FALSE);
+
+
+ if (!NT_SUCCESS(status))
+ {
+ if (deviceObject)
+ {
+ KeEnterCriticalRegion();
+ IoDeleteDevice(deviceObject);
+ KeLeaveCriticalRegion();
+ Globals.ControlDeviceObject = NULL;
+ }
+
+ if (fSymbolicLink)
+ {
+ IoDeleteSymbolicLink(&win32DeviceName);
+ fSymbolicLink = FALSE;
+ }
+
+ if (Globals.NdisProtocolHandle)
+ {
+ NdisDeregisterProtocolDriver(Globals.NdisProtocolHandle);
+ Globals.NdisProtocolHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+
+VOID
+NdisprotUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ Free all the allocated resources, etc.
+
+Arguments:
+
+ DriverObject - pointer to a driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+
+ UNICODE_STRING win32DeviceName;
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ DEBUGP(DL_LOUD, ("Unload Enter\n"));
+
+ //
+ // First delete the Control deviceobject and the corresponding
+ // symbolicLink
+ //
+ RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
+
+ IoDeleteSymbolicLink(&win32DeviceName);
+
+
+ if (Globals.ControlDeviceObject)
+ {
+ IoDeleteDevice(Globals.ControlDeviceObject);
+ Globals.ControlDeviceObject = NULL;
+ }
+
+
+ ndisprotDoProtocolUnload();
+
+#if DBG
+ ndisprotAuditShutdown();
+#endif
+
+ DEBUGP(DL_LOUD, ("Unload Exit\n"));
+}
+
+
+
+NTSTATUS
+NdisprotOpen(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for handling IRP_MJ_CREATE.
+ We simply succeed this.
+
+Arguments:
+
+ pDeviceObject - Pointer to the device object.
+
+ pIrp - Pointer to the request packet.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS NtStatus = STATUS_SUCCESS;
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrpSp->FileObject->FsContext = NULL;
+
+ DEBUGP(DL_INFO, ("Open: FileObject %p\n", pIrpSp->FileObject));
+
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return NtStatus;
+}
+
+NTSTATUS
+NdisprotClose(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for handling IRP_MJ_CLOSE.
+ We simply succeed this.
+
+Arguments:
+
+ pDeviceObject - Pointer to the device object.
+
+ pIrp - Pointer to the request packet.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PIO_STACK_LOCATION pIrpSp;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pOpenContext = pIrpSp->FileObject->FsContext;
+
+ DEBUGP(DL_INFO, ("Close: FileObject %p\n",
+ IoGetCurrentIrpStackLocation(pIrp)->FileObject));
+
+ if (pOpenContext != NULL)
+ {
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Deref the endpoint
+ //
+ NPROT_DEREF_OPEN(pOpenContext); // Close
+ }
+
+ pIrpSp->FileObject->FsContext = NULL;
+ NtStatus = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return NtStatus;
+}
+
+
+
+NTSTATUS
+NdisprotCleanup(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for handling IRP_MJ_CLEANUP.
+
+Arguments:
+
+ pDeviceObject - Pointer to the device object.
+
+ pIrp - Pointer to the request packet.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS NtStatus;
+ NDIS_STATUS NdisStatus;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ ULONG PacketFilter;
+ ULONG BytesProcessed;
+
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pOpenContext = pIrpSp->FileObject->FsContext;
+
+ DEBUGP(DL_VERY_LOUD, ("Cleanup: FileObject %p, Open %p\n",
+ pIrpSp->FileObject, pOpenContext));
+
+ if (pOpenContext != NULL)
+ {
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Set the packet filter to 0, telling NDIS that we aren't
+ // interested in any more receives.
+ //
+ PacketFilter = 0;
+ NdisStatus = ndisprotValidateOpenAndDoRequest(
+ pOpenContext,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesProcessed,
+ FALSE // Don't wait for device to be powered on
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_INFO, ("Cleanup: Open %p, set packet filter (%x) failed: %x\n",
+ pOpenContext, PacketFilter, NdisStatus));
+ //
+ // Ignore the result. If this failed, we may continue
+ // to get indicated receives, which will be handled
+ // appropriately.
+ //
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Mark this endpoint.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_IDLE);
+ pOpenContext->pFileObject = NULL;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Cancel any pending reads.
+ //
+ ndisprotCancelPendingReads(pOpenContext);
+ //
+ // Clean up the receive packet queue
+ //
+ ndisprotFlushReceiveQueue(pOpenContext);
+ }
+
+ NtStatus = STATUS_SUCCESS;
+
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ DEBUGP(DL_INFO, ("Cleanup: OpenContext %p\n", pOpenContext));
+
+ return (NtStatus);
+}
+
+NTSTATUS
+NdisprotIoControl(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This is the dispatch routine for handling device ioctl requests.
+
+Arguments:
+
+ pDeviceObject - Pointer to the device object.
+
+ pIrp - Pointer to the request packet.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ PIO_STACK_LOCATION pIrpSp;
+ ULONG FunctionCode;
+ NTSTATUS NtStatus;
+ NDIS_STATUS Status;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ ULONG BytesReturned;
+#if !DBG
+ UNREFERENCED_PARAMETER(pDeviceObject);
+#endif
+ PAGED_CODE();
+ DEBUGP(DL_LOUD, ("IoControl: DevObj %p, Irp %p\n", pDeviceObject, pIrp));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)pIrpSp->FileObject->FsContext;
+ BytesReturned = 0;
+
+ switch (FunctionCode)
+ {
+ case IOCTL_NDISPROT_BIND_WAIT:
+ //
+ // Block until we have seen a NetEventBindsComplete event,
+ // meaning that we have finished binding to all running
+ // adapters that we are supposed to bind to.
+ //
+ // If we don't get this event in 5 seconds, time out.
+ //
+ NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
+
+ if (NPROT_WAIT_EVENT(&Globals.BindsComplete, 5000))
+ {
+ NtStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ NtStatus = STATUS_TIMEOUT;
+ }
+ DEBUGP(DL_INFO, ("IoControl: BindWait returning %x\n", NtStatus));
+ break;
+
+ case IOCTL_NDISPROT_QUERY_BINDING:
+
+ NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
+
+ Status = ndisprotQueryBinding(
+ pIrp->AssociatedIrp.SystemBuffer,
+ pIrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ &BytesReturned
+ );
+
+ NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
+
+ DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus));
+
+ break;
+
+ case IOCTL_NDISPROT_OPEN_DEVICE:
+
+ NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
+ if (pOpenContext != NULL)
+ {
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+ DEBUGP(DL_WARN, ("IoControl: OPEN_DEVICE: FileObj %p already"
+ " associated with open %p\n", pIrpSp->FileObject, pOpenContext));
+
+ NtStatus = STATUS_DEVICE_BUSY;
+ break;
+ }
+
+ NtStatus = ndisprotOpenDevice(
+ pIrp->AssociatedIrp.SystemBuffer,
+ pIrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ pIrpSp->FileObject,
+ &pOpenContext
+ );
+
+ if (NT_SUCCESS(NtStatus))
+ {
+
+ DEBUGP(DL_VERY_LOUD, ("IoControl OPEN_DEVICE: Open %p <-> FileObject %p\n",
+ pOpenContext, pIrpSp->FileObject));
+
+ }
+ else
+ {
+ DEBUGP(DL_INFO, ("NdisprotIoControl: IOCTL_NDISPROT_OPEN_DEVICE, ndisprotOpenDevice failed %lx\n", NtStatus));
+ }
+
+ break;
+
+ case IOCTL_NDISPROT_QUERY_OID_VALUE:
+
+ NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
+ if (pOpenContext != NULL)
+ {
+ Status = ndisprotQueryOidValue(
+ pOpenContext,
+ pIrp->AssociatedIrp.SystemBuffer,
+ pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ &BytesReturned
+ );
+
+ NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
+ }
+ else
+ {
+ NtStatus = STATUS_DEVICE_NOT_CONNECTED;
+ }
+ break;
+
+ case IOCTL_NDISPROT_SET_OID_VALUE:
+
+ NPROT_ASSERT((FunctionCode & 0x3) == METHOD_BUFFERED);
+ if (pOpenContext != NULL)
+ {
+ Status = ndisprotSetOidValue(
+ pOpenContext,
+ pIrp->AssociatedIrp.SystemBuffer,
+ pIrpSp->Parameters.DeviceIoControl.InputBufferLength
+ );
+
+ BytesReturned = 0;
+
+ NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
+ }
+ else
+ {
+ NtStatus = STATUS_DEVICE_NOT_CONNECTED;
+ }
+ break;
+
+ default:
+
+ NtStatus = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (NtStatus != STATUS_PENDING)
+ {
+ pIrp->IoStatus.Information = BytesReturned;
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return NtStatus;
+}
+
+
+
+NTSTATUS
+ndisprotOpenDevice(
+ _In_reads_bytes_(DeviceNameLength) IN PUCHAR pDeviceName,
+ IN ULONG DeviceNameLength,
+ IN PFILE_OBJECT pFileObject,
+ OUT PNDISPROT_OPEN_CONTEXT * ppOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Helper routine called to process IOCTL_NDISPROT_OPEN_DEVICE. Check if
+ there is a binding to the specified device, and is not associated with
+ a file object already. If so, make an association between the binding
+ and this file object.
+
+Arguments:
+
+ pDeviceName - pointer to device name string
+ DeviceNameLength - length of above
+ pFileObject - pointer to file object being associated with the device binding
+
+Return Value:
+
+ Status is returned.
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ NTSTATUS NtStatus;
+ ULONG PacketFilter;
+ NDIS_STATUS NdisStatus;
+ ULONG BytesProcessed;
+ PNDISPROT_OPEN_CONTEXT pCurrentOpenContext = NULL;
+
+ pOpenContext = NULL;
+
+ do
+ {
+ pOpenContext = ndisprotLookupDevice(
+ pDeviceName,
+ DeviceNameLength
+ );
+
+ if (pOpenContext == NULL)
+ {
+ DEBUGP(DL_WARN, ("ndisprotOpenDevice: couldn't find device\n"));
+ NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
+ break;
+ }
+
+ //
+ // else ndisprotLookupDevice would have addref'ed the open.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_IDLE))
+ {
+ NPROT_ASSERT(pOpenContext->pFileObject != NULL);
+
+ DEBUGP(DL_WARN, ("ndisprotOpenDevice: Open %p/%x already associated"
+ " with another FileObject %p\n",
+ pOpenContext, pOpenContext->Flags, pOpenContext->pFileObject));
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure
+ NtStatus = STATUS_DEVICE_BUSY;
+ break;
+ }
+ //
+ // This InterlockedXXX function performs an atomic operation: First it compare
+ // pFileObject->FsContext with NULL, if they are equal, the function puts pOpenContext
+ // into FsContext, and return NULL. Otherwise, it return pFileObject->FsContext without
+ // changing anything.
+ //
+
+ if ((pCurrentOpenContext = InterlockedCompareExchangePointer (& (pFileObject->FsContext), pOpenContext, NULL)) != NULL)
+ {
+ //
+ // pFileObject->FsContext already is used by other open
+ //
+ DEBUGP(DL_WARN, ("ndisprotOpenDevice: FileObject %p already associated"
+ " with another Open %p/%x\n",
+ pFileObject, pCurrentOpenContext, pCurrentOpenContext->Flags)); //BUG
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure
+ NtStatus = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ pOpenContext->pFileObject = pFileObject;
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_ACTIVE);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Set the packet filter now.
+ //
+ PacketFilter = NPROTO_PACKET_FILTER;
+ NdisStatus = ndisprotValidateOpenAndDoRequest(
+ pOpenContext,
+ NdisRequestSetInformation,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesProcessed,
+ TRUE // Do wait for power on
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(DL_WARN, ("openDevice: Open %p: set packet filter (%x) failed: %x\n",
+ pOpenContext, PacketFilter, NdisStatus));
+
+ //
+ // Undo all that we did above.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ //
+ // Need to set pFileObject->FsContext to NULL again, so others can open a device
+ // for this file object later
+ //
+ pCurrentOpenContext = InterlockedCompareExchangePointer (& (pFileObject->FsContext), NULL, pOpenContext);
+
+
+ NPROT_ASSERT(pCurrentOpenContext == pOpenContext);
+
+ NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_IDLE);
+ pOpenContext->pFileObject = NULL;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure
+
+ NDIS_STATUS_TO_NT_STATUS(NdisStatus, &NtStatus);
+ break;
+ }
+
+ *ppOpenContext = pOpenContext;
+
+ NtStatus = STATUS_SUCCESS;
+ }
+ while (FALSE);
+
+ return (NtStatus);
+}
+
+
+VOID
+ndisprotRefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Reference the given open context.
+
+ NOTE: Can be called with or without holding the opencontext lock.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+
+Return Value:
+
+ None
+
+--*/
+{
+ NdisInterlockedIncrement((PLONG)&pOpenContext->RefCount);
+}
+
+
+VOID
+ndisprotDerefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Dereference the given open context. If the ref count goes to zero,
+ free it.
+
+ NOTE: called without holding the opencontext lock
+
+Arguments:
+
+ pOpenContext - pointer to open context
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (NdisInterlockedDecrement((PLONG)&pOpenContext->RefCount) == 0)
+ {
+ DEBUGP(DL_INFO, ("DerefOpen: Open %p, Flags %x, ref count is zero!\n",
+ pOpenContext, pOpenContext->Flags));
+
+ NPROT_ASSERT(pOpenContext->BindingHandle == NULL);
+ NPROT_ASSERT(pOpenContext->RefCount == 0);
+ NPROT_ASSERT(pOpenContext->pFileObject == NULL);
+
+ pOpenContext->oc_sig++;
+
+ //
+ // Free it.
+ //
+ NPROT_FREE_MEM(pOpenContext);
+ }
+}
+
+#if DBG
+VOID
+ndisprotDbgRefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+ )
+{
+ DEBUGP(DL_VERY_LOUD, (" RefOpen: Open %p, old ref %d, File %c%c%c%c, line %d\n",
+ pOpenContext,
+ pOpenContext->RefCount,
+ (CHAR)(FileNumber),
+ (CHAR)(FileNumber >> 8),
+ (CHAR)(FileNumber >> 16),
+ (CHAR)(FileNumber >> 24),
+ LineNumber));
+
+ ndisprotRefOpen(pOpenContext);
+}
+
+VOID
+ndisprotDbgDerefOpen(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN ULONG FileNumber,
+ IN ULONG LineNumber
+ )
+{
+ DEBUGP(DL_VERY_LOUD, ("DerefOpen: Open %p, old ref %d, File %c%c%c%c, line %d\n",
+ pOpenContext,
+ pOpenContext->RefCount,
+ (CHAR)(FileNumber),
+ (CHAR)(FileNumber >> 8),
+ (CHAR)(FileNumber >> 16),
+ (CHAR)(FileNumber >> 24),
+ LineNumber));
+
+ ndisprotDerefOpen(pOpenContext);
+}
+
+#endif // DBG
+
diff --git a/network/ndis/ndisprot/6x/sys/precomp.h b/network/ndis/ndisprot/6x/sys/precomp.h
new file mode 100644
index 00000000..1e9c0b78
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/precomp.h
@@ -0,0 +1,18 @@
+#pragma warning(disable:4214) // bit field types other than int
+
+#pragma warning(disable:4201) // nameless struct/union
+#pragma warning(disable:4115) // named type definition in parentheses
+#pragma warning(disable:4127) // conditional expression is constant
+#pragma warning(disable:4054) // cast of function pointer to PVOID
+#pragma warning(disable:4244) // conversion from 'int' to 'BOOLEAN', possible loss of data
+#pragma warning(disable:4206) // nonstandard extension used : translation unit is empty
+
+#include "ndis.h"
+#include "ntddk.h"
+#include <wmistr.h>
+#include <wdmsec.h>
+#include <wdmguid.h>
+#include "debug.h"
+#include "ndisprot.h"
+#include "macros.h"
+#include "protuser.h"
diff --git a/network/ndis/ndisprot/6x/sys/protuser.h b/network/ndis/ndisprot/6x/sys/protuser.h
new file mode 100644
index 00000000..823d1ef5
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/protuser.h
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ nuiouser.h
+
+Abstract:
+
+ Constants and types to access the NDISPROT driver.
+ Users must also include ntddndis.h
+
+Environment:
+
+ User/Kernel mode.
+
+Revision History:
+
+--*/
+
+#ifndef __NPROTUSER__H
+#define __NPROTUSER__H
+
+
+#define FSCTL_NDISPROT_BASE FILE_DEVICE_NETWORK
+
+#define _NDISPROT_CTL_CODE(_Function, _Method, _Access) \
+ CTL_CODE(FSCTL_NDISPROT_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISPROT_OPEN_DEVICE \
+ _NDISPROT_CTL_CODE(0x200, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_QUERY_OID_VALUE \
+ _NDISPROT_CTL_CODE(0x201, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_SET_OID_VALUE \
+ _NDISPROT_CTL_CODE(0x205, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_QUERY_BINDING \
+ _NDISPROT_CTL_CODE(0x203, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_BIND_WAIT \
+ _NDISPROT_CTL_CODE(0x204, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+
+
+
+//
+// Structure to go with IOCTL_NDISPROT_QUERY_OID_VALUE.
+// The Data part is of variable length, determined by
+// the input buffer length passed to DeviceIoControl.
+//
+typedef struct _NDISPROT_QUERY_OID
+{
+ NDIS_OID Oid;
+ NDIS_PORT_NUMBER PortNumber;
+ UCHAR Data[sizeof(ULONG)];
+} NDISPROT_QUERY_OID, *PNDISPROT_QUERY_OID;
+
+//
+// Structure to go with IOCTL_NDISPROT_SET_OID_VALUE.
+// The Data part is of variable length, determined
+// by the input buffer length passed to DeviceIoControl.
+//
+typedef struct _NDISPROT_SET_OID
+{
+ NDIS_OID Oid;
+ NDIS_PORT_NUMBER PortNumber;
+ UCHAR Data[sizeof(ULONG)];
+} NDISPROT_SET_OID, *PNDISPROT_SET_OID;
+
+
+//
+// Structure to go with IOCTL_NDISPROT_QUERY_BINDING.
+// The input parameter is BindingIndex, which is the
+// index into the list of bindings active at the driver.
+// On successful completion, we get back a device name
+// and a device descriptor (friendly name).
+//
+typedef struct _NDISPROT_QUERY_BINDING
+{
+ ULONG BindingIndex; // 0-based binding number
+ ULONG DeviceNameOffset; // from start of this struct
+ ULONG DeviceNameLength; // in bytes
+ ULONG DeviceDescrOffset; // from start of this struct
+ ULONG DeviceDescrLength; // in bytes
+
+} NDISPROT_QUERY_BINDING, *PNDISPROT_QUERY_BINDING;
+
+#endif // __NPROTUSER__H
+
diff --git a/network/ndis/ndisprot/6x/sys/recv.c b/network/ndis/ndisprot/6x/sys/recv.c
new file mode 100644
index 00000000..71c867f1
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/recv.c
@@ -0,0 +1,1119 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ recv.c
+
+Abstract:
+
+ NDIS protocol entry points and utility routines to handle receiving
+ data.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'VCER'
+
+
+
+NTSTATUS
+NdisprotRead(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Dispatch routine to handle IRP_MJ_READ.
+
+Arguments:
+
+ pDeviceObject - pointer to our device object
+ pIrp - Pointer to request packet
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS NtStatus;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pOpenContext = pIrpSp->FileObject->FsContext;
+
+ do
+ {
+ //
+ // Validate!
+ //
+ if (pOpenContext == NULL)
+ {
+ DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %p\n",
+ pIrpSp->FileObject));
+ NtStatus = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ if (pIrp->MdlAddress == NULL)
+ {
+ DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %p\n", pIrp));
+ NtStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Try to get a virtual address for the MDL.
+ //
+ if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL)
+ {
+ DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %p\n",
+ pIrp, pIrp->MdlAddress));
+ NtStatus = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ NtStatus = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ IoSetCancelRoutine(pIrp, NdisprotCancelRead);
+
+ if (pIrp->Cancel &&
+ IoSetCancelRoutine(pIrp, NULL))
+ {
+
+ //
+ // IRP has been canceled but the I/O manager did not manage to call our cancel routine. This
+ // code is safe referencing the Irp->Cancel field without locks because of the memory barriers
+ // in the interlocked exchange sequences used by IoSetCancelRoutine.
+ //
+
+ NtStatus = STATUS_CANCELLED;
+
+ // IRP should be completed after releasing the lock
+
+ }
+ else
+ {
+
+ //
+ // Add this IRP to the list of pended Read IRPs
+ //
+ NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry);
+ pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
+
+ NPROT_REF_OPEN(pOpenContext); // pended read IRP
+ pOpenContext->PendedReadCount++;
+ IoMarkIrpPending(pIrp);
+
+
+ NtStatus = STATUS_PENDING;
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+ //
+ // Run the service routine for reads.
+ //
+ ndisprotServiceReads(pOpenContext);
+
+ }
+ while (FALSE);
+
+ if (NtStatus != STATUS_PENDING)
+ {
+ NPROT_ASSERT(NtStatus != STATUS_SUCCESS);
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return (NtStatus);
+}
+
+
+VOID
+NdisprotCancelRead(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Cancel a pending read IRP. We unlink the IRP from the open context
+ queue and complete it.
+
+Arguments:
+
+ pDeviceObject - pointer to our device object
+ pIrp - IRP to be cancelled
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
+ pOpenContext->PendedReadCount--;
+
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp));
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ NPROT_DEREF_OPEN(pOpenContext); // Cancel removed pended Read
+
+}
+
+
+
+VOID
+ndisprotServiceReads(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Utility routine to copy received data into user buffers and
+ complete READ IRPs.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+
+Return Value:
+
+ None
+
+--*/
+{
+ PIRP pIrp = NULL;
+ PLIST_ENTRY pIrpEntry;
+ PNET_BUFFER_LIST pRcvNetBufList;
+ PLIST_ENTRY pRcvNetBufListEntry;
+ PUCHAR pSrc, pDst;
+ ULONG BytesRemaining; // at pDst
+ PMDL pMdl;
+ ULONG BytesAvailable;
+ BOOLEAN FoundPendingIrp = FALSE;
+ ULONG SrcTotalLength = 0; // Source NetBuffer DataLenght
+ ULONG Offset = 0; // CurrentMdlOffset
+ ULONG BytesToCopy = 0;
+
+ DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
+ pOpenContext, pOpenContext->Flags));
+
+ NPROT_REF_OPEN(pOpenContext); // temp ref - service reads
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
+ !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
+ {
+ FoundPendingIrp = FALSE;
+
+ //
+ // Get the first pended Read IRP
+ //
+ pIrpEntry = pOpenContext->PendedReads.Flink;
+ while (pIrpEntry != &pOpenContext->PendedReads)
+ {
+ pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // Check to see if it is being cancelled.
+ //
+ if (IoSetCancelRoutine(pIrp, NULL))
+ {
+ //
+ // It isn't being cancelled, and can't be cancelled henceforth.
+ //
+ NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
+ FoundPendingIrp = TRUE;
+ break;
+
+ //
+ // NOTE: we decrement PendedReadCount way below in the
+ // while loop, to avoid letting through a thread trying
+ // to unbind.
+ //
+ }
+ else
+ {
+ //
+ // The IRP is being cancelled; let the cancel routine handle it.
+ //
+ DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
+ pOpenContext, pIrp));
+
+ pIrpEntry = pIrpEntry->Flink;
+ }
+ }
+
+ if (FoundPendingIrp == FALSE)
+ {
+ break;
+ }
+ //
+ // Get the first queued receive packet
+ //
+ pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
+ NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);
+
+ pOpenContext->RecvNetBufListCount --;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet
+
+ pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
+ NPROT_ASSERT(pRcvNetBufList != NULL);
+ _Analysis_assume_(pRcvNetBufList != NULL);
+ NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;
+
+ //
+ // Copy as much data as possible from the receive packet to
+ // the IRP MDL.
+ //
+
+ pDst = NULL;
+ NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority);
+ NPROT_ASSERT(pDst != NULL); // since it was already mapped
+ _Analysis_assume_(pDst != NULL);
+
+ pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
+
+ //
+ // Copy the data in the received packet into the buffer provided by the client.
+ // If the length of the receive packet is greater than length of the given buffer,
+ // we just copy as many bytes as we can. Once the buffer is full, we just discard
+ // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
+ //
+
+ SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
+ Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
+
+ while (BytesRemaining && (pMdl != NULL) && SrcTotalLength)
+ {
+ pSrc = NULL;
+ NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority);
+
+ if (pSrc == NULL)
+ {
+ DEBUGP(DL_FATAL,
+ ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n",
+ pOpenContext, pMdl));
+ break;
+ }
+
+ NPROT_ASSERT(BytesAvailable > Offset);
+
+ BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining);
+ BytesToCopy = MIN(BytesToCopy, SrcTotalLength);
+
+ NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy);
+ BytesRemaining -= BytesToCopy;
+ pDst += BytesToCopy;
+ SrcTotalLength -= BytesToCopy;
+
+ //
+ // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0.
+ //
+ Offset = 0;
+
+ NdisGetNextMdl(pMdl, &pMdl);
+ }
+
+ //
+ // Complete the IRP.
+ //
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;
+
+ DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
+ pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information));
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE);
+
+
+ NPROT_DEREF_OPEN(pOpenContext); // took out pended Read
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ pOpenContext->PendedReadCount--;
+
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // temp ref - service reads
+}
+
+
+VOID
+NdisprotReceiveNetBufferLists(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_BUFFER_LIST pNetBufferLists,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN ULONG NumberOfNetBufferLists,
+ IN ULONG ReceiveFlags
+ )
+/*++
+
+Routine Description:
+
+ Protocol entry point called by NDIS if the driver below
+ uses NDIS 6 net buffer list indications.
+
+ If the miniport allows us to hold on to this net buffer list, we
+ use it as is, otherwise we make a copy.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context
+ pNetBufferLists - a list of the Net Buffer lists being indicated up.
+ PortNumber - Port on which the Net Bufer list was received
+ NumberOfNetBufferLists - the number of NetBufferLists in this indication
+ ReceiveFlags - indicates whether the NetBufferLists can be pended in
+ the protocol driver.
+
+Return Value:
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PMDL pMdl = NULL;
+ UINT BufferLength;
+ PNDISPROT_ETH_HEADER pEthHeader = NULL;
+ PNET_BUFFER_LIST pCopyNetBufList;
+ PUCHAR pCopyBuf;
+ ULONG TotalLength;
+ ULONG BytesCopied;
+ PNET_BUFFER_LIST pNetBufList;
+ PNET_BUFFER_LIST pNetBufListOrig = NULL;
+ PNET_BUFFER_LIST pNextNetBufList;
+ PNET_BUFFER_LIST pReturnNetBufList = NULL;
+ PNET_BUFFER_LIST pLastReturnNetBufList = NULL;
+ NTSTATUS NtStatus;
+ BOOLEAN bAcceptedReceive;
+ ULONG Offset;
+ ULONG ReturnFlags = 0;
+ BOOLEAN DispatchLevel;
+ BOOLEAN NoReadIRP = FALSE;
+
+ UNREFERENCED_PARAMETER(PortNumber);
+ UNREFERENCED_PARAMETER(NumberOfNetBufferLists);
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+
+ if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
+ {
+ NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+ if ((pOpenContext->State == NdisprotPausing)
+ || (pOpenContext->State == NdisprotPaused))
+ {
+ if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE)
+ {
+
+ NdisReturnNetBufferLists(pOpenContext->BindingHandle,
+ pNetBufferLists,
+ ReturnFlags);
+ }
+ return;
+ }
+
+ pNetBufList = pNetBufferLists;
+
+ while (pNetBufList != NULL)
+ {
+ pNextNetBufList = NET_BUFFER_LIST_NEXT_NBL (pNetBufList);
+
+ NBL_CLEAR_PROT_RSVD_FLAG(pNetBufList, NBL_PROT_RSVD_FLAGS);
+ bAcceptedReceive = FALSE;
+
+ //
+ // Get first MDL and data length in the list
+ //
+ pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
+ TotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
+ Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
+ BufferLength = 0;
+
+ do
+ {
+ ASSERT(pMdl != NULL);
+ if (pMdl)
+ {
+ NdisQueryMdl(
+ pMdl,
+ &pEthHeader,
+ &BufferLength,
+ NormalPagePriority);
+ }
+
+ if (pEthHeader == NULL)
+ {
+ //
+ // The system is low on resources. Set up to handle failure
+ // below.
+ //
+ BufferLength = 0;
+ break;
+ }
+
+ if (BufferLength == 0)
+ {
+ break;
+ }
+
+ ASSERT(BufferLength > Offset);
+
+ BufferLength -= Offset;
+ pEthHeader = (PNDISPROT_ETH_HEADER)((PUCHAR)pEthHeader + Offset);
+
+ if (BufferLength < sizeof(NDISPROT_ETH_HEADER))
+ {
+ DEBUGP(DL_WARN,
+ ("ReceiveNetBufferList: Open %p, runt nbl %p, first buffer length %d\n",
+ pOpenContext, pNetBufList, BufferLength));
+
+ break;
+ }
+
+ //
+ // Check the EtherType. If the Ether type indicates presence of
+ // a tag, then the "real" Ether type is 4 bytes further down.
+ //
+ if (pEthHeader->EthType == NPROT_8021P_TAG_TYPE)
+ {
+ USHORT UNALIGNED *pEthType;
+
+ if (BufferLength < (sizeof(NDISPROT_ETH_HEADER) + 4))
+ {
+ break;
+ }
+
+ pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);
+
+ if (*pEthType != Globals.EthType)
+ {
+ break;
+ }
+ }
+ else if (pEthHeader->EthType != Globals.EthType)
+ {
+ break;
+ }
+
+ bAcceptedReceive = TRUE;
+ DEBUGP(DL_LOUD, ("ReceiveNetBufferList: Open %p, interesting nbl %p\n",
+ pOpenContext, pNetBufList));
+
+ //
+ // If the miniport is out of resources, we can't queue
+ // this list of net buffer list - make a copy if this is so.
+ //
+ DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
+
+ NoReadIRP = NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads);
+
+ if (NoReadIRP || NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags))
+ {
+ bAcceptedReceive = FALSE;
+ pCopyNetBufList = ndisprotAllocateReceiveNetBufferList(
+ pOpenContext,
+ TotalLength,
+ &pCopyBuf);
+
+ if (pCopyNetBufList == NULL)
+ {
+ DEBUGP(DL_FATAL, ("ReceiveNetBufferList: Open %p, failed to"
+ " alloc copy, %d bytes\n", pOpenContext, TotalLength));
+ break;
+ }
+ NBL_SET_PROT_RSVD_FLAG(pCopyNetBufList, NPROT_ALLOCATED_NBL);
+ //
+ // Copy the data to the new allocated NetBufferList
+ //
+ NtStatus = NdisCopyFromNetBufferToNetBuffer(NET_BUFFER_LIST_FIRST_NB(pCopyNetBufList),
+ 0,
+ TotalLength,
+ NET_BUFFER_LIST_FIRST_NB(pNetBufList),
+ 0,
+ &BytesCopied);
+
+
+ if (NtStatus != STATUS_SUCCESS)
+ {
+ DEBUGP(DL_FATAL, ("ReceiveNetBufferList: Open %p, failed to"
+ " copy the data, %d bytes\n", pOpenContext, TotalLength));
+ //
+ // Free the NetBufferList and memory allocate before
+ //
+ ndisprotFreeReceiveNetBufferList(pOpenContext,
+ pCopyNetBufList,
+ DispatchLevel);
+ break;
+ }
+
+ NPROT_ASSERT(BytesCopied == TotalLength);
+
+
+ //
+ // The other members of NET_BUFFER_DATA structure are already initialized properly during allocation.
+ //
+ NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pCopyNetBufList)) = BytesCopied;
+
+ //
+ //save a copy for no Read IRP case
+ //
+ if(NoReadIRP)
+ {
+ pNetBufListOrig = pNetBufList;
+ }
+ pNetBufList = pCopyNetBufList;
+
+ }
+ //
+ // Queue this up and service any pending Read IRPs.
+ //
+ ndisprotQueueReceiveNetBufferList(pOpenContext, pNetBufList, DispatchLevel);
+
+ }
+ while (FALSE);
+
+ //
+ // Ndisprot is not interested this NetBufferList, return the
+ // NetBufferList back to the miniport if the miniport gave us
+ // ownership of it
+ //
+ if ((bAcceptedReceive == FALSE) &&
+ (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE))
+ {
+ // Restore pNetBufList if it was overwritten earlier
+ if (pNetBufListOrig != NULL)
+ {
+ pNetBufList = pNetBufListOrig;
+
+ pNetBufListOrig = NULL;
+ }
+ if (pReturnNetBufList == NULL)
+ {
+ pReturnNetBufList = pNetBufList;
+ }
+ else
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pLastReturnNetBufList) = pNetBufList;
+ }
+ pLastReturnNetBufList = pNetBufList;
+ NET_BUFFER_LIST_NEXT_NBL(pNetBufList) = NULL;
+
+ }
+
+ pNetBufList = pNextNetBufList;
+ } // end of the for loop
+
+ if (pReturnNetBufList != NULL)
+ {
+ NdisReturnNetBufferLists(pOpenContext->BindingHandle,
+ pReturnNetBufList,
+ ReturnFlags);
+ }
+
+}
+
+
+VOID
+ndisprotQueueReceiveNetBufferList(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNET_BUFFER_LIST pRcvNetBufList,
+ IN BOOLEAN DispatchLevel
+ )
+/*++
+
+Routine Description:
+
+ Queue up a received net buffer list on the open context structure.
+ If the queue size goes beyond a water mark, discard a Net Buffer list
+ at the head of the queue.
+
+ Finally, run the queue service routine.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+ pRcvPacket - the received packet
+ DipatchLevel - the irql level
+
+Return Value:
+
+ None
+
+--*/
+{
+ PLIST_ENTRY pEnt;
+ PLIST_ENTRY pDiscardEnt;
+ PNET_BUFFER_LIST pDiscardNetBufList;
+
+ do
+ {
+
+ NPROT_REF_OPEN(pOpenContext); // queued rcv net buffer list
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ if ((pOpenContext->State == NdisprotPaused)
+ || (pOpenContext->State == NdisprotPausing))
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel);
+ break;
+ }
+
+ //
+ // Check if the binding is in the proper state to receive
+ // this net buffer list.
+ //
+ if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE) &&
+ (pOpenContext->PowerState == NetDeviceStateD0))
+ {
+
+ //
+ // Queue the net buffer list
+ //
+ pEnt = NPROT_RCV_NBL_TO_LIST_ENTRY(pRcvNetBufList);
+ NPROT_INSERT_TAIL_LIST(&pOpenContext->RecvNetBufListQueue, pEnt);
+ NPROT_RCV_NBL_FROM_LIST_ENTRY(pEnt) = pRcvNetBufList;
+ pOpenContext->RecvNetBufListCount++;
+
+ DEBUGP(DL_VERY_LOUD, ("QueueReceiveNetBufferList: open %p,"
+ " queued nbl %p, queue size %d\n",
+ pOpenContext, pRcvNetBufList, pOpenContext->RecvNetBufListCount));
+
+ }
+ else
+ {
+ //
+ // Received this net buffer list when the binding is going away.
+ // Drop this.
+ //
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel);
+
+ NPROT_DEREF_OPEN(pOpenContext); // dropped rcv packet - bad state
+ break;
+ }
+
+
+ //
+ // Trim the queue if it has grown too big.
+ //
+ if (pOpenContext->RecvNetBufListCount > MAX_RECV_QUEUE_SIZE)
+ {
+ //
+ // Remove the head of the queue.
+ //
+ pDiscardEnt = pOpenContext->RecvNetBufListQueue.Flink;
+ NPROT_REMOVE_ENTRY_LIST(pDiscardEnt);
+
+ pOpenContext->RecvNetBufListCount --;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ pDiscardNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt);
+
+ NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt) = NULL;
+
+ ndisprotFreeReceiveNetBufferList(pOpenContext, pDiscardNetBufList, DispatchLevel);
+
+ NPROT_DEREF_OPEN(pOpenContext); // dropped rcv packet - queue too long
+
+ DEBUGP(DL_INFO, ("QueueReceiveNetBufferList: open %p queue"
+ " too long, discarded %p\n",
+ pOpenContext, pDiscardNetBufList));
+ }
+ else
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+ }
+
+ //
+ // Run the receive queue service routine now.
+ //
+ ndisprotServiceReads(pOpenContext);
+ }
+ while (FALSE);
+}
+
+_Success_(return != 0)
+PNET_BUFFER_LIST
+ndisprotAllocateReceiveNetBufferList(
+ _In_ PNDISPROT_OPEN_CONTEXT pOpenContext,
+ _In_ UINT DataLength,
+ _Outptr_result_bytebuffer_(DataLength)
+ PUCHAR * ppDataBuffer
+ )
+/*++
+
+Routine Description:
+
+ Allocate resources to copy and queue a received net buffer list
+
+Arguments:
+
+ pOpenContext - pointer to open context for received packet
+ DataLength - total length in bytes of the net buffer list's first net buffer
+ ppDataBuffer - place to return pointer to allocated buffer
+
+Return Value:
+
+ Pointer to NDIS packet if successful, else NULL.
+
+--*/
+{
+ PNET_BUFFER_LIST pNetBufList;
+ PMDL pMdl;
+ PUCHAR pDataBuffer;
+
+ pNetBufList = NULL;
+ pMdl = NULL;
+ pDataBuffer = NULL;
+ *ppDataBuffer = NULL;
+
+ do
+ {
+ NPROT_ALLOC_MEM(pDataBuffer, DataLength);
+
+ if (pDataBuffer == NULL)
+ {
+ DEBUGP(DL_FATAL, ("AllocRcvNbl: open %p, failed to alloc"
+ " data buffer %d bytes\n", pOpenContext, DataLength));
+ break;
+ }
+
+ //
+ // Make this an NDIS buffer.
+ //
+ pMdl = NdisAllocateMdl(pOpenContext->BindingHandle, pDataBuffer, DataLength);
+
+ if (pMdl == NULL)
+ {
+ DEBUGP(DL_FATAL, ("AllocateRcvNbl: open %p, failed to alloc"
+ " MDL, %d bytes\n", pOpenContext, DataLength));
+ break;
+ }
+
+ pNetBufList = NdisAllocateNetBufferAndNetBufferList(
+ pOpenContext->RecvNetBufferListPool,
+ 0, // ContextSize
+ 0, // ContextBackfill
+ pMdl, // MdlChain
+ 0, // DataOffset
+ DataLength); // DataLength
+
+ if (pNetBufList == NULL)
+ {
+ DEBUGP(DL_FATAL, ("AllocateRcvNbl: open %p, failed to alloc"
+ " Net Buffer List, %d bytes\n", pOpenContext, DataLength));
+ break;
+ }
+
+
+ *ppDataBuffer = pDataBuffer;
+
+ }
+ while (FALSE);
+
+ if (pNetBufList == NULL)
+ {
+ //
+ // Clean up
+ //
+ if (pMdl != NULL)
+ {
+ NdisFreeMdl(pMdl);
+ }
+
+ if (pDataBuffer != NULL)
+ {
+ NPROT_FREE_MEM(pDataBuffer);
+ }
+ }
+
+ return (pNetBufList);
+}
+
+
+
+VOID
+ndisprotFreeReceiveNetBufferList(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext,
+ IN PNET_BUFFER_LIST pNetBufferList,
+ IN BOOLEAN DispatchLevel
+ )
+/*++
+
+Routine Description:
+
+ Free up all resources associated with a received net buffer list. If this
+ is a local copy, free the net buffer list to our receive pool, else return
+ this to the miniport.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+ pNetBufferList - pointer to net buffer list to be freed.
+ DipatchLevel - the irql level
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMDL pMdl;
+ UINT TotalLength;
+ UINT BufferLength;
+ PUCHAR pCopyData = NULL;
+ ULONG ReturnFlags = 0;
+
+
+ do
+ {
+ if (NBL_TEST_PROT_RSVD_FLAG(pNetBufferList, NPROT_ALLOCATED_NBL))
+ {
+ //
+ // This is a local copy.
+ //
+
+ pMdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));
+ TotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));
+
+ NPROT_ASSERT(pMdl != NULL);
+
+ NdisQueryMdl(
+ pMdl,
+ (PVOID *)&pCopyData,
+ &BufferLength,
+ NormalPagePriority);
+
+ NPROT_ASSERT(BufferLength == TotalLength);
+
+
+ NPROT_ASSERT(pCopyData != NULL); // we would have allocated non-paged pool
+
+
+ NdisFreeNetBufferList(pNetBufferList);
+
+ NdisFreeMdl(pMdl);
+
+ NPROT_FREE_MEM(pCopyData);
+ break;
+ }
+ //
+ // The NetBufferList should be returned
+
+ NET_BUFFER_LIST_NEXT_NBL(pNetBufferList) = NULL;
+
+ if (DispatchLevel)
+ {
+ NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
+ }
+
+ NdisReturnNetBufferLists(pOpenContext->BindingHandle,
+ pNetBufferList,
+ ReturnFlags);
+ }
+ while (FALSE);
+
+}
+
+
+VOID
+ndisprotCancelPendingReads(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Cancel any pending read IRPs queued on the given open.
+
+Arguments:
+
+ pOpenContext - pointer to open context
+
+Return Value:
+
+ None
+
+--*/
+{
+ PIRP pIrp;
+ PLIST_ENTRY pIrpEntry;
+
+ NPROT_REF_OPEN(pOpenContext); // temp ref - cancel reads
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads))
+ {
+ //
+ // Get the first pended Read IRP
+ //
+ pIrpEntry = pOpenContext->PendedReads.Flink;
+ pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // Check to see if it is being cancelled.
+ //
+ if (IoSetCancelRoutine(pIrp, NULL))
+ {
+ //
+ // It isn't being cancelled, and can't be cancelled henceforth.
+ //
+ NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Complete the IRP.
+ //
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+
+ DEBUGP(DL_INFO, ("CancelPendingReads: Open %p, IRP %p cancelled\n",
+ pOpenContext, pIrp));
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ NPROT_DEREF_OPEN(pOpenContext); // took out pended Read for cancelling
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ pOpenContext->PendedReadCount--;
+ }
+ else
+ {
+ //
+ // It is being cancelled, let the cancel routine handle it.
+ //
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Give the cancel routine some breathing space, otherwise
+ // we might end up examining the same (cancelled) IRP over
+ // and over again.
+ //
+ NdisMSleep(100000); // 100 ms.
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ }
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // temp ref - cancel reads
+}
+
+
+VOID
+ndisprotFlushReceiveQueue(
+ IN PNDISPROT_OPEN_CONTEXT pOpenContext
+ )
+/*++
+
+Routine Description:
+
+ Free any receive packets queued up on the specified open
+
+Arguments:
+
+ pOpenContext - pointer to open context
+
+Return Value:
+
+ None
+
+--*/
+{
+ PLIST_ENTRY pRcvNetBufListEntry;
+ PNET_BUFFER_LIST pRcvNetBufList;
+
+ NPROT_REF_OPEN(pOpenContext); // temp ref - flushRcvQueue
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ while (!NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
+ {
+ //
+ // Get the first queued receive packet
+ //
+ pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
+ NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);
+
+ pOpenContext->RecvNetBufListCount--;
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
+ NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;
+
+ DEBUGP(DL_LOUD, ("FlushReceiveQueue: open %p, nbl %p\n",
+ pOpenContext, pRcvNetBufList));
+
+ ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // took out pended Read
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ NPROT_DEREF_OPEN(pOpenContext); // temp ref - flushRcvQueue
+}
+
+
diff --git a/network/ndis/ndisprot/6x/sys/send.c b/network/ndis/ndisprot/6x/sys/send.c
new file mode 100644
index 00000000..b2be7300
--- /dev/null
+++ b/network/ndis/ndisprot/6x/sys/send.c
@@ -0,0 +1,463 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ NDIS protocol entry points and utility routines to handle sending
+ data.
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+
+#define __FILENUMBER 'DNES'
+
+
+
+
+NTSTATUS
+NdisprotWrite(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Dispatch routine to handle IRP_MJ_WRITE.
+
+Arguments:
+
+ pDeviceObject - pointer to our device object
+ pIrp - Pointer to request packet
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PIO_STACK_LOCATION pIrpSp;
+ ULONG DataLength;
+ NTSTATUS NtStatus;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PNET_BUFFER_LIST pNetBufferList;
+ PMDL pMdl;
+ NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
+ PVOID CancelId;
+ ULONG SendFlags = 0;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pOpenContext = pIrpSp->FileObject->FsContext;
+
+
+ do
+ {
+ if (pOpenContext == NULL)
+ {
+ DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
+ pIrpSp->FileObject));
+ NtStatus = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ if (pIrp->MdlAddress == NULL)
+ {
+ DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
+ NtStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Try to get a virtual address for the MDL.
+ //
+
+ pEthHeader = NULL;
+ NdisQueryMdl(pIrp->MdlAddress, &pEthHeader, &DataLength, NormalPagePriority);
+
+ if (pEthHeader == NULL)
+ {
+ DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
+ " IRP %p, MDL %p\n",
+ pIrp, pIrp->MdlAddress));
+ NtStatus = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ //
+ // Sanity-check the length.
+ //
+ if (DataLength < sizeof(NDISPROT_ETH_HEADER))
+ {
+ DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
+ DataLength));
+ NtStatus = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
+ {
+ DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
+ " larger than max frame size (%d)\n",
+ pOpenContext, DataLength, pOpenContext->MaxFrameSize));
+
+ NtStatus = STATUS_INVALID_BUFFER_SIZE;
+ break;
+ }
+
+ if (pEthHeader->EthType != Globals.EthType)
+ {
+ DEBUGP(DL_WARN, ("Write: Failing send with EthType %x\n",
+ pEthHeader->EthType));
+ NtStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
+ {
+ DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
+ NtStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
+ " or in low power state\n", pOpenContext));
+
+ NtStatus = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ if (pOpenContext->State != NdisprotRunning ||
+ pOpenContext->PowerState != NetDeviceStateD0)
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ DEBUGP(DL_INFO, ("Device is not ready.\n"));
+ NtStatus = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+
+ pMdl = pIrp->MdlAddress;
+ NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL);
+ pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
+ pOpenContext->SendNetBufferListPool,
+ sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta
+ 0, // back fill size
+ pMdl,
+ 0, // Data offset
+ DataLength);
+
+ if (pNetBufferList == NULL)
+ {
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n",
+ pOpenContext));
+ NtStatus = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ pOpenContext->PendedSendCount++;
+
+ NPROT_REF_OPEN(pOpenContext); // pended send
+
+ IoMarkIrpPending(pIrp);
+
+ //
+ // Initialize the NetBufferList ref count. This NetBufferList will be freed
+ // when this count goes to zero.
+ //
+ NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1;
+
+ //
+ // We set up a cancel ID on each send NetBufferList (which maps to a Write IRP),
+ // and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use
+ // NdisCancelSendNetBufferLists() to cancel the NetBufferList.
+ //
+
+ CancelId = NPROT_GET_NEXT_CANCEL_ID();
+ NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId);
+ pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
+ pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNetBufferList;
+ pIrp->Tail.Overlay.DriverContext[2] = CancelId;
+
+ NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);
+
+ IoSetCancelRoutine(pIrp, NdisprotCancelWrite);
+
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ //
+ // Set a back pointer from the packet to the IRP.
+ //
+ NPROT_IRP_FROM_SEND_NBL(pNetBufferList) = pIrp;
+
+ NtStatus = STATUS_PENDING;
+
+
+#if SEND_DBG
+ {
+ PUCHAR pData;
+
+ pData = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
+ NPROT_ASSERT(pEthHeader == pData);
+
+ DEBUGP(DL_VERY_LOUD,
+ ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
+ pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));
+
+ DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
+ }
+#endif // SEND_DBG
+
+ pNetBufferList->SourceHandle = pOpenContext->BindingHandle;
+ ASSERT (NDIS_MDL_LINKAGE(pMdl) == NULL);
+
+ SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;
+
+ NdisSendNetBufferLists(
+ pOpenContext->BindingHandle,
+ pNetBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ SendFlags);
+
+ }
+ while (FALSE);
+
+ if (NtStatus != STATUS_PENDING)
+ {
+ pIrp->IoStatus.Status = NtStatus;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ return (NtStatus);
+}
+
+
+
+VOID
+NdisprotCancelWrite(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ Cancel a pending write IRP. This routine attempt to cancel the NDIS send.
+
+Arguments:
+
+ pDeviceObject - pointer to our device object
+ pIrp - IRP to be cancelled
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PLIST_ENTRY pIrpEntry;
+ BOOLEAN FoundIrp = FALSE;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
+ if (pOpenContext == NULL)
+ {
+ //
+ // The IRP is going to be completed from send complete function
+ //
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ return;
+ }
+
+ NPROT_REF_OPEN(pOpenContext);
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+
+ //
+ // Try to locate the IRP in the pended write queue. The send completion
+ // routine may be running and might have removed it from there.
+ //
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
+
+ for (pIrpEntry = pOpenContext->PendedWrites.Flink;
+ pIrpEntry != &pOpenContext->PendedWrites;
+ pIrpEntry = pIrpEntry->Flink)
+ {
+ if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
+ {
+ FoundIrp = TRUE;
+ break;
+ }
+ }
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
+
+ if (FoundIrp)
+ {
+ PVOID CancelId;
+
+ CancelId = pIrp->Tail.Overlay.DriverContext[2];
+ //
+ // Either the send completion routine hasn't run, or we got a peak
+ // at the IRP/netbufferlist before it had a chance to take it out of the
+ // pending IRP queue.
+ //
+ // We do not complete the IRP here - note that we didn't dequeue it
+ // above. This is because we always want the send complete routine to
+ // complete the IRP. And this in turn is because the NetBufferlist that was
+ // prepared from the IRP has a buffer chain pointing to data associated
+ // with this IRP. Therefore we cannot complete the IRP before the driver
+ // below us is done with the data it pointed to.
+ //
+
+ //
+ // Request NDIS to cancel this send. The result of this call is that
+ // our SendComplete handler will be called (if not already called).
+ //
+ DEBUGP(DL_INFO, ("CancelWrite: cancelling nbl %p on Open %p\n",
+ pIrp->Tail.Overlay.DriverContext[1], pOpenContext));
+
+ NdisCancelSendNetBufferLists(
+ pOpenContext->BindingHandle,
+ CancelId);
+
+ }
+ //
+ // else the send completion routine has already picked up this IRP.
+ //
+ NPROT_DEREF_OPEN(pOpenContext);
+}
+
+
+VOID
+NdisprotSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_BUFFER_LIST pNetBufferList,
+ IN ULONG SendCompleteFlags
+ )
+/*++
+
+Routine Description:
+
+ NDIS entry point called to signify completion of a packet send.
+ We pick up and complete the Write IRP corresponding to this packet.
+
+Arguments:
+
+ ProtocolBindingContext - pointer to open context
+ pNetBufferList - NetBufferList that completed send
+ SendCompleteFlags - Specifies if the caller is at DISPATCH level
+
+Return Value:
+
+ None
+
+--*/
+{
+ PIRP pIrp;
+ PIO_STACK_LOCATION pIrpSp;
+ PNDISPROT_OPEN_CONTEXT pOpenContext;
+ PNET_BUFFER_LIST CurrNetBufferList = NULL;
+ PNET_BUFFER_LIST NextNetBufferList;
+ NDIS_STATUS CompletionStatus;
+ BOOLEAN DispatchLevel;
+
+ pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
+ NPROT_STRUCT_ASSERT(pOpenContext, oc);
+ DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);
+
+ for (CurrNetBufferList = pNetBufferList;
+ CurrNetBufferList != NULL;
+ CurrNetBufferList = NextNetBufferList)
+ {
+ NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList);
+
+ pIrp = NPROT_IRP_FROM_SEND_NBL(CurrNetBufferList);
+
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+ IoSetCancelRoutine(pIrp, NULL);
+ pIrp->Tail.Overlay.DriverContext[0] = NULL;
+ pIrp->Tail.Overlay.DriverContext[1] = NULL;
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
+
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList);
+
+
+ //
+ // We are done with the NDIS_PACKET:
+ //
+ NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel);
+
+ //
+ // Complete the Write IRP with the right status.
+ //
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ if (CompletionStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d "
+ "completed with status %x\n",
+ CurrNetBufferList, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);
+ pOpenContext->PendedSendCount--;
+
+ if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
+ && (pOpenContext->PendedSendCount == 0))
+ {
+ ASSERT(pOpenContext->ClosingEvent != NULL);
+ NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
+ pOpenContext->ClosingEvent = NULL;
+ }
+ NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
+
+ NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
+ }
+
+}
+
+
diff --git a/network/ndis/ndisprot/6x/test/prottest.c b/network/ndis/ndisprot/6x/test/prottest.c
new file mode 100644
index 00000000..54af3ddc
--- /dev/null
+++ b/network/ndis/ndisprot/6x/test/prottest.c
@@ -0,0 +1,665 @@
+//
+// UIOTEST.C
+//
+// Test program for ndisprot.sys
+//
+// usage: UIOTEST [options] <devicename>
+//
+// options:
+// -e: Enumerate devices
+// -r: Read
+// -w: Write (default)
+// -l <length>: length of each packet (default: %d)\n", PacketLength
+// -n <count>: number of packets (defaults to infinity)
+// -m <MAC address> (defaults to local MAC)
+//
+
+#pragma warning(disable:4201) // nameless struct/union
+#pragma warning(disable:4127) // conditional expression is constant
+
+#include <windows.h>
+#include <winioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <malloc.h>
+
+#include <winerror.h>
+#include <winsock.h>
+
+#include <ntddndis.h>
+#include "protuser.h"
+
+// this is needed to prevent comppiler from complaining about
+// pragma prefast statements below
+#ifndef _PREFAST_
+ #pragma warning(disable:4068)
+#endif
+
+#ifndef NDIS_STATUS
+#define NDIS_STATUS ULONG
+#endif
+
+#if DBG
+#define DEBUGP(stmt) printf stmt
+#else
+#define DEBUGP(stmt)
+#endif
+
+#define PRINTF(stmt) printf stmt
+
+#ifndef MAC_ADDR_LEN
+#define MAC_ADDR_LEN 6
+#endif
+
+#define MAX_NDIS_DEVICE_NAME_LEN 256
+
+CHAR NdisProtDevice[] = "\\\\.\\\\NdisProt";
+CHAR * pNdisProtDevice = &NdisProtDevice[0];
+
+BOOLEAN DoEnumerate = FALSE;
+BOOLEAN DoReads = FALSE;
+INT NumberOfPackets = -1;
+ULONG PacketLength = 100;
+UCHAR SrcMacAddr[MAC_ADDR_LEN];
+UCHAR DstMacAddr[MAC_ADDR_LEN];
+BOOLEAN bDstMacSpecified = FALSE;
+CHAR * pNdisDeviceName = "JUNK";
+USHORT EthType = 0x8e88;
+BOOLEAN bUseFakeAddress = FALSE;
+UCHAR FakeSrcMacAddr[MAC_ADDR_LEN] = {0};
+
+
+#include <pshpack1.h>
+
+typedef struct _ETH_HEADER
+{
+ UCHAR DstAddr[MAC_ADDR_LEN];
+ UCHAR SrcAddr[MAC_ADDR_LEN];
+ USHORT EthType;
+} ETH_HEADER, *PETH_HEADER;
+
+#include <poppack.h>
+
+
+VOID
+PrintUsage()
+{
+ PRINTF(("usage: PROTTEST [options] <devicename>\n"));
+ PRINTF(("options:\n"));
+ PRINTF((" -e: Enumerate devices\n"));
+ PRINTF((" -r: Read\n"));
+ PRINTF((" -w: Write (default)\n"));
+ PRINTF((" -l <length>: length of each packet (default: %d)\n", PacketLength));
+ PRINTF((" -n <count>: number of packets (defaults to infinity)\n"));
+ PRINTF((" -m <MAC address> (defaults to local MAC)\n"));
+ PRINTF((" -f Use a fake address to send out the packets.\n"));
+
+
+}
+
+BOOL
+GetOptions(
+ INT argc,
+ _In_reads_(argc+1) CHAR *argv[]
+)
+{
+ INT i, j;
+ CHAR *pOption;
+ ULONG DstMacAddrUlong[MAC_ADDR_LEN];
+ INT RetVal;
+ PCSTR Parameter;
+
+ do
+ {
+ if (argc < 2)
+ {
+ PRINTF(("Missing <devicename> argument\n"));
+ return FALSE;
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ pOption = argv[i];
+
+ if ((*pOption == '-') || (*pOption == '/'))
+ {
+ pOption++;
+ if (*pOption == '\0')
+ {
+ DEBUGP(("Badly formed option\n"));
+ return (FALSE);
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ if (i < argc - 2)
+ {
+ Parameter = argv[i+1];
+ }
+ else
+ {
+ Parameter = NULL;
+ }
+
+ switch (*pOption)
+ {
+ case 'e':
+ DoEnumerate = TRUE;
+ break;
+
+ case 'f':
+ bUseFakeAddress = TRUE;
+ break;
+
+ case 'r':
+ DoReads = TRUE;
+ break;
+
+ case 'w':
+ DoReads = FALSE;
+ break;
+
+ case 'l':
+
+ if (Parameter != NULL)
+ {
+ RetVal = atoi(Parameter);
+ if (RetVal != 0)
+ {
+ PacketLength = RetVal;
+ DEBUGP((" Option: PacketLength = %d\n", PacketLength));
+ i++;
+ break;
+ }
+ }
+ PRINTF(("Option l needs PacketLength parameter\n"));
+ return (FALSE);
+
+ case 'n':
+
+ if (Parameter != NULL)
+ {
+ RetVal = atoi(Parameter);
+ if (RetVal != 0)
+ {
+ NumberOfPackets = RetVal;
+ DEBUGP((" Option: NumberOfPackets = %d\n", NumberOfPackets));
+ i++;
+ break;
+ }
+ }
+ PRINTF(("Option n needs NumberOfPackets parameter\n"));
+ return (FALSE);
+
+ case 'm':
+
+ if (Parameter != NULL)
+ {
+ RetVal = sscanf_s(Parameter, "%2x:%2x:%2x:%2x:%2x:%2x",
+ &DstMacAddrUlong[0],
+ &DstMacAddrUlong[1],
+ &DstMacAddrUlong[2],
+ &DstMacAddrUlong[3],
+ &DstMacAddrUlong[4],
+ &DstMacAddrUlong[5]);
+
+ if (RetVal == 6)
+ {
+ for (j = 0; j < MAC_ADDR_LEN; j++)
+ {
+ DstMacAddr[j] = (UCHAR)DstMacAddrUlong[j];
+ }
+
+ DEBUGP((" Option: Dest MAC Addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ DstMacAddr[0],
+ DstMacAddr[1],
+ DstMacAddr[2],
+ DstMacAddr[3],
+ DstMacAddr[4],
+ DstMacAddr[5]));
+ bDstMacSpecified = TRUE;
+
+ i++;
+ break;
+ }
+ }
+
+ PRINTF(("Option m needs MAC address parameter\n"));
+ return (FALSE);
+
+ case '?':
+ return (FALSE);
+
+ default:
+ PRINTF(("Unknown option %c\n", *pOption));
+ return (FALSE);
+ }
+ }
+
+ pNdisDeviceName = argv[i];
+
+ }
+ while (FALSE);
+
+ return TRUE;
+}
+
+
+HANDLE
+OpenHandle(
+ _In_ PSTR pDeviceName
+)
+{
+ DWORD DesiredAccess;
+ DWORD ShareMode;
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
+
+ DWORD CreationDistribution;
+ DWORD FlagsAndAttributes;
+ HANDLE Handle;
+ DWORD BytesReturned;
+
+ DesiredAccess = GENERIC_READ|GENERIC_WRITE;
+ ShareMode = 0;
+ CreationDistribution = OPEN_EXISTING;
+ FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+
+ Handle = CreateFileA(
+ pDeviceName,
+ DesiredAccess,
+ ShareMode,
+ lpSecurityAttributes,
+ CreationDistribution,
+ FlagsAndAttributes,
+ NULL
+ );
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ DEBUGP(("Creating file failed, error %x\n", GetLastError()));
+ return Handle;
+ }
+ //
+ // Wait for the driver to finish binding.
+ //
+ if (!DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_BIND_WAIT,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &BytesReturned,
+ NULL))
+ {
+ DEBUGP(("IOCTL_NDISIO_BIND_WAIT failed, error %x\n", GetLastError()));
+ CloseHandle(Handle);
+ Handle = INVALID_HANDLE_VALUE;
+ }
+
+ return (Handle);
+}
+
+
+BOOL
+OpenNdisDevice(
+ _In_ HANDLE Handle,
+ _In_ PCSTR pDeviceName
+)
+{
+ WCHAR wNdisDeviceName[MAX_NDIS_DEVICE_NAME_LEN];
+ INT wNameLength;
+ SIZE_T NameLength = strlen(pDeviceName);
+ DWORD BytesReturned;
+ SIZE_T i;
+
+
+ //
+ // Convert to unicode string - non-localized...
+ //
+ wNameLength = 0;
+ for (i = 0; i < NameLength && i < MAX_NDIS_DEVICE_NAME_LEN-1; i++)
+ {
+ wNdisDeviceName[i] = (WCHAR)pDeviceName[i];
+ wNameLength++;
+ }
+ wNdisDeviceName[i] = L'\0';
+
+ DEBUGP(("Trying to access NDIS Device: %ws\n", wNdisDeviceName));
+
+ return (DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_OPEN_DEVICE,
+ (LPVOID)&wNdisDeviceName[0],
+ wNameLength*sizeof(WCHAR),
+ NULL,
+ 0,
+ &BytesReturned,
+ NULL));
+
+}
+
+_Success_(return)
+BOOL
+GetSrcMac(
+ _In_ HANDLE Handle,
+ _Out_writes_bytes_(MAC_ADDR_LEN) PUCHAR pSrcMacAddr
+ )
+{
+ DWORD BytesReturned;
+ BOOLEAN bSuccess;
+ UCHAR QueryBuffer[sizeof(NDISPROT_QUERY_OID) + MAC_ADDR_LEN];
+ PNDISPROT_QUERY_OID pQueryOid;
+
+
+ DEBUGP(("Trying to get src mac address\n"));
+
+ pQueryOid = (PNDISPROT_QUERY_OID)&QueryBuffer[0];
+ pQueryOid->Oid = OID_802_3_CURRENT_ADDRESS;
+ pQueryOid->PortNumber = 0;
+
+ bSuccess = (BOOLEAN)DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_QUERY_OID_VALUE,
+ (LPVOID)&QueryBuffer[0],
+ sizeof(QueryBuffer),
+ (LPVOID)&QueryBuffer[0],
+ sizeof(QueryBuffer),
+ &BytesReturned,
+ NULL);
+
+ if (bSuccess)
+ {
+ DEBUGP(("GetSrcMac: IoControl success, BytesReturned = %d\n",
+ BytesReturned));
+
+#pragma warning(suppress:6202) // buffer overrun warning - enough space allocated in QueryBuffer
+ memcpy(pSrcMacAddr, pQueryOid->Data, MAC_ADDR_LEN);
+ }
+ else
+ {
+ DEBUGP(("GetSrcMac: IoControl failed: %d\n", GetLastError()));
+ }
+
+ return (bSuccess);
+}
+
+
+
+VOID
+DoReadProc(
+ HANDLE Handle
+ )
+{
+ PUCHAR pReadBuf = NULL;
+ INT ReadCount = 0;
+ BOOLEAN bSuccess;
+ ULONG BytesRead;
+
+ DEBUGP(("DoReadProc\n"));
+
+ do
+ {
+ pReadBuf = malloc(PacketLength);
+
+ if (pReadBuf == NULL)
+ {
+ PRINTF(("DoReadProc: failed to alloc %d bytes\n", PacketLength));
+ break;
+ }
+
+ ReadCount = 0;
+ while (TRUE)
+ {
+ bSuccess = (BOOLEAN)ReadFile(
+ Handle,
+ (LPVOID)pReadBuf,
+ PacketLength,
+ &BytesRead,
+ NULL);
+
+ if (!bSuccess)
+ {
+ PRINTF(("DoReadProc: ReadFile failed on Handle %p, error %x\n",
+ Handle, GetLastError()));
+ break;
+ }
+ ReadCount++;
+
+ DEBUGP(("DoReadProc: read pkt # %d, %d bytes\n", ReadCount, BytesRead));
+
+ if ((NumberOfPackets != -1) && (ReadCount == NumberOfPackets))
+ {
+ break;
+ }
+ }
+ }
+ while (FALSE);
+
+ if (pReadBuf)
+ {
+ free(pReadBuf);
+ }
+
+ PRINTF(("DoReadProc finished: read %d packets\n", ReadCount));
+
+}
+
+
+VOID
+DoWriteProc(
+ HANDLE Handle
+ )
+{
+ PUCHAR pWriteBuf = NULL;
+ PUCHAR pData;
+ UINT i;
+ INT SendCount;
+ PETH_HEADER pEthHeader;
+ DWORD BytesWritten;
+ BOOLEAN bSuccess;
+
+ DEBUGP(("DoWriteProc\n"));
+ SendCount = 0;
+
+ do
+ {
+ pWriteBuf = malloc(PacketLength);
+
+ if (pWriteBuf == NULL)
+ {
+ DEBUGP(("DoWriteProc: Failed to malloc %d bytes\n", PacketLength));
+ break;
+ }
+ pEthHeader = (PETH_HEADER)pWriteBuf;
+ pEthHeader->EthType = EthType;
+
+ if (bUseFakeAddress)
+ {
+ memcpy(pEthHeader->SrcAddr, FakeSrcMacAddr, MAC_ADDR_LEN);
+ }
+ else
+ {
+ memcpy(pEthHeader->SrcAddr, SrcMacAddr, MAC_ADDR_LEN);
+ }
+
+ memcpy(pEthHeader->DstAddr, DstMacAddr, MAC_ADDR_LEN);
+
+ pData = (PUCHAR)(pEthHeader + 1);
+ for (i = 0; i < PacketLength - sizeof(ETH_HEADER); i++)
+ {
+ *pData++ = (UCHAR)i;
+ }
+
+ SendCount = 0;
+
+ while (TRUE)
+ {
+
+ bSuccess = (BOOLEAN)WriteFile(
+ Handle,
+ pWriteBuf,
+ PacketLength,
+ &BytesWritten,
+ NULL);
+ if (!bSuccess)
+ {
+ PRINTF(("DoWriteProc: WriteFile failed on Handle %p\n", Handle));
+ break;
+ }
+ SendCount++;
+
+ DEBUGP(("DoWriteProc: sent %d bytes\n", BytesWritten));
+
+ if ((NumberOfPackets != -1) && (SendCount == NumberOfPackets))
+ {
+ break;
+ }
+ }
+
+ }
+ while (FALSE);
+
+ if (pWriteBuf)
+ {
+ free(pWriteBuf);
+ }
+
+ PRINTF(("DoWriteProc: finished sending %d packets of %d bytes each\n",
+ SendCount, PacketLength));
+}
+
+VOID
+EnumerateDevices(
+ HANDLE Handle
+ )
+{
+ typedef __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) QueryBindingCharBuf;
+ QueryBindingCharBuf Buf[1024];
+ DWORD BufLength = sizeof(Buf);
+ DWORD BytesWritten;
+ DWORD i;
+ PNDISPROT_QUERY_BINDING pQueryBinding;
+
+ pQueryBinding = (PNDISPROT_QUERY_BINDING)Buf;
+
+ i = 0;
+ for (pQueryBinding->BindingIndex = i;
+ /* NOTHING */;
+ pQueryBinding->BindingIndex = ++i)
+ {
+ if (DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_QUERY_BINDING,
+ pQueryBinding,
+ sizeof(NDISPROT_QUERY_BINDING),
+ Buf,
+ BufLength,
+ &BytesWritten,
+ NULL))
+ {
+ PRINTF(("%2d. %ws\n - %ws\n",
+ pQueryBinding->BindingIndex,
+ (WCHAR *)((PUCHAR)pQueryBinding + pQueryBinding->DeviceNameOffset),
+ (WCHAR *)((PUCHAR )pQueryBinding + pQueryBinding->DeviceDescrOffset)));
+
+ memset(Buf, 0, BufLength);
+ }
+ else
+ {
+ ULONG rc = GetLastError();
+ if (rc != ERROR_NO_MORE_ITEMS)
+ {
+ PRINTF(("EnumerateDevices: terminated abnormally, error %d\n", rc));
+ }
+ break;
+ }
+ }
+}
+
+
+
+
+VOID __cdecl
+main(
+ INT argc,
+ _In_reads_(argc+1) LPSTR *argv
+)
+{
+ HANDLE DeviceHandle;
+
+ DeviceHandle = INVALID_HANDLE_VALUE;
+
+ do
+ {
+ if (!GetOptions(argc, argv))
+ {
+ PrintUsage();
+ break;
+ }
+
+ DeviceHandle = OpenHandle(pNdisProtDevice);
+
+ if (DeviceHandle == INVALID_HANDLE_VALUE)
+ {
+ PRINTF(("Failed to open %s\n", pNdisProtDevice));
+ break;
+ }
+
+ if (DoEnumerate)
+ {
+ EnumerateDevices(DeviceHandle);
+ break;
+ }
+
+ if (!OpenNdisDevice(DeviceHandle, pNdisDeviceName))
+ {
+ PRINTF(("Failed to access %s\n", pNdisDeviceName));
+ break;
+ }
+
+ DEBUGP(("Opened device %s successfully!\n", pNdisDeviceName));
+
+ if (!GetSrcMac(DeviceHandle, SrcMacAddr))
+ {
+ PRINTF(("Failed to obtain local MAC address\n"));
+ break;
+ }
+
+
+ DEBUGP(("Got local MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ SrcMacAddr[0],
+ SrcMacAddr[1],
+ SrcMacAddr[2],
+ SrcMacAddr[3],
+ SrcMacAddr[4],
+ SrcMacAddr[5]));
+
+ if (!bDstMacSpecified)
+ {
+ memcpy(DstMacAddr, SrcMacAddr, MAC_ADDR_LEN);
+ }
+
+ if (DoReads)
+ {
+ DoReadProc(DeviceHandle);
+ }
+ else
+ {
+ DoWriteProc(DeviceHandle);
+ DoReadProc(DeviceHandle);
+ }
+
+ }
+ while (FALSE);
+
+ if (DeviceHandle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(DeviceHandle);
+ }
+}
diff --git a/network/ndis/ndisprot/6x/test/prottest.vcxproj b/network/ndis/ndisprot/6x/test/prottest.vcxproj
new file mode 100644
index 00000000..7706c8e3
--- /dev/null
+++ b/network/ndis/ndisprot/6x/test/prottest.vcxproj
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{0AD0B8E0-5A3E-43FE-8E27-E5BB3DB184B0}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{B8B7CF7B-163A-4705-B726-3B7251D8BD10}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>prottest</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>prottest</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>prottest</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>prottest</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32WIN_</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);user32.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);user32.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);user32.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);user32.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="prottest.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters b/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters
new file mode 100644
index 00000000..8b87abfa
--- /dev/null
+++ b/network/ndis/ndisprot/6x/test/prottest.vcxproj.Filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{5DB43F2D-E248-4063-B2E6-D0F81FCF5D84}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{3B8958F0-D888-4CE4-9473-3300FDF5A2B3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{35E32097-01E2-4113-877C-7E88FDCD0FAA}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="prottest.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/60/netvmini60.inf b/network/ndis/netvmini/6x/60/netvmini60.inf
new file mode 100644
index 00000000..043aff2e
--- /dev/null
+++ b/network/ndis/netvmini/6x/60/netvmini60.inf
Binary files differ
diff --git a/network/ndis/netvmini/6x/60/netvmini60.rc b/network/ndis/netvmini/6x/60/netvmini60.rc
new file mode 100644
index 00000000..ac470534
--- /dev/null
+++ b/network/ndis/netvmini/6x/60/netvmini60.rc
@@ -0,0 +1,51 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ netvmini.rc
+
+Abstract:
+
+ Internal resource file for driver.
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Miniport Driver"
+#define VER_INTERNALNAME_STR "netvmin6.sys"
+#define VER_ORIGINALFILENAME_STR "netvmin6.sys"
+
+
+
+#define VER_FILEVERSION 4,02,00,0000
+#define VER_FILEVERSION_STR "4.02.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2009 Microsoft Corporation"
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#endif
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft Virtual Network Adapter (NDIS 6.0 Miniport)"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/netvmini/6x/60/netvmini60.vcxproj b/network/ndis/netvmini/6x/60/netvmini60.vcxproj
new file mode 100644
index 00000000..34fbc15f
--- /dev/null
+++ b/network/ndis/netvmini/6x/60/netvmini60.vcxproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{FB69D6D4-CF9F-4C63-9FEA-D7D1B1F73BFF}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="..\miniport.c; ..\adapter.c; ..\ctrlpath.c; ..\datapath.c; ..\tcbrcb.c; ..\mphal.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </ClCompile>
+ <OtherWpp Include="netvmini60.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>netvmini60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>netvmini60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>netvmini60</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>netvmini60</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS60_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini60.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters b/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters
new file mode 100644
index 00000000..36412ff4
--- /dev/null
+++ b/network/ndis/netvmini/6x/60/netvmini60.vcxproj.Filters
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{60D1BC26-8429-4B71-B0A4-A09C81AA9006}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{C5B761C0-3390-4C0D-92B3-296CBE739D12}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{2837E1B4-FB49-43C4-B0DA-0459E959F944}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{78CC6DBE-CEE8-4DB1-BD8D-4C3C3551030A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\adapter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ctrlpath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\datapath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\miniport.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mphal.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tcbrcb.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini60.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/620/netvmini620.inf b/network/ndis/netvmini/6x/620/netvmini620.inf
new file mode 100644
index 00000000..307f43a0
--- /dev/null
+++ b/network/ndis/netvmini/6x/620/netvmini620.inf
Binary files differ
diff --git a/network/ndis/netvmini/6x/620/netvmini620.rc b/network/ndis/netvmini/6x/620/netvmini620.rc
new file mode 100644
index 00000000..72dba137
--- /dev/null
+++ b/network/ndis/netvmini/6x/620/netvmini620.rc
@@ -0,0 +1,51 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ netvmini.rc
+
+Abstract:
+
+ Internal resource file for driver.
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Miniport Driver"
+#define VER_INTERNALNAME_STR "netvmini62.sys"
+#define VER_ORIGINALFILENAME_STR "netvmini62.sys"
+
+
+
+#define VER_FILEVERSION 4,02,00,0000
+#define VER_FILEVERSION_STR "4.02.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2009 Microsoft Corporation"
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#endif
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft Virtual Network Adapter (NDIS 6.20 Miniport)"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/netvmini/6x/620/netvmini620.vcxproj b/network/ndis/netvmini/6x/620/netvmini620.vcxproj
new file mode 100644
index 00000000..dda1e977
--- /dev/null
+++ b/network/ndis/netvmini/6x/620/netvmini620.vcxproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{7039332E-F9EF-43DD-8AEC-4478C735DF1D}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="..\miniport.c; ..\adapter.c; ..\ctrlpath.c; ..\datapath.c; ..\tcbrcb.c; ..\mphal.c; ..\vmq.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </ClCompile>
+ <OtherWpp Include="netvmini620.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>netvmini620</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>netvmini620</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>netvmini620</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>netvmini620</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS620_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini620.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters b/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters
new file mode 100644
index 00000000..3237b662
--- /dev/null
+++ b/network/ndis/netvmini/6x/620/netvmini620.vcxproj.Filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{703913F3-8635-4541-B263-C02BD6486AA1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{A1EB0C9F-4422-445A-8E6C-268C9DF3497F}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{175D5117-B719-462D-AD06-09F8EDFF3688}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{C815125B-DF87-4E45-8C33-58380D5859E2}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\adapter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ctrlpath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\datapath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\miniport.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mphal.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tcbrcb.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\vmq.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini620.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/630/netvmini630.inf b/network/ndis/netvmini/6x/630/netvmini630.inf
new file mode 100644
index 00000000..dc6bb49a
--- /dev/null
+++ b/network/ndis/netvmini/6x/630/netvmini630.inf
Binary files differ
diff --git a/network/ndis/netvmini/6x/630/netvmini630.rc b/network/ndis/netvmini/6x/630/netvmini630.rc
new file mode 100644
index 00000000..4cd2306b
--- /dev/null
+++ b/network/ndis/netvmini/6x/630/netvmini630.rc
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ netvmini630.rc
+
+Abstract:
+
+ Internal resource file for driver.
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Miniport Driver"
+#define VER_INTERNALNAME_STR "netvmini630.sys"
+#define VER_ORIGINALFILENAME_STR "netvmini630.sys"
+
+
+#define VER_FILEVERSION 4,20,00,0000
+#define VER_FILEVERSION_STR "4.20.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2009 Microsoft Corporation"
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#endif
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft Virtual Network Adapter (NDIS 6.30 Miniport)"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/network/ndis/netvmini/6x/630/netvmini630.vcxproj b/network/ndis/netvmini/6x/630/netvmini630.vcxproj
new file mode 100644
index 00000000..b881fbd6
--- /dev/null
+++ b/network/ndis/netvmini/6x/630/netvmini630.vcxproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{20227FE5-F4F3-4980-98C2-B860C8B2F62C}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2C8923A5-C60B-45DE-AF84-B27B1BECA400}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="..\miniport.c; ..\adapter.c; ..\ctrlpath.c; ..\datapath.c; ..\tcbrcb.c; ..\mphal.c; ..\vmq.c; ..\qos.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </ClCompile>
+ <OtherWpp Include="netvmini630.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>DEBUGP(LEVEL,MSG,...)</WppTraceFunction>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>netvmini630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>netvmini630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>netvmini630</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>netvmini630</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ <DisableSpecificWarnings>%(DisableSpecificWarnings);4201;4214;4127</DisableSpecificWarnings>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS630_MINIPORT=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_MINIPORT_DRIVER=1</PreprocessorDefinitions>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);NDIS_WDM=1</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini630.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters b/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters
new file mode 100644
index 00000000..93779b42
--- /dev/null
+++ b/network/ndis/netvmini/6x/630/netvmini630.vcxproj.Filters
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{9D259E56-FF93-4ED4-B79E-BE9390D6F96E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{2D6DC915-1942-425E-87CD-DC9F26064AED}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{2DBFC871-0321-474E-ACAA-EF309426BBED}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{8493E657-4501-41D4-8F6A-B7527F30AA2D}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\adapter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ctrlpath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\datapath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\miniport.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mphal.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\qos.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tcbrcb.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\vmq.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="netvmini630.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/ndis/netvmini/6x/ReadMe.md b/network/ndis/netvmini/6x/ReadMe.md
new file mode 100644
index 00000000..a056a846
--- /dev/null
+++ b/network/ndis/netvmini/6x/ReadMe.md
@@ -0,0 +1,15 @@
+NDIS Virtual Miniport Driver
+============================
+
+The NDIS Virtual Miniport Driver sample illustrates the functionality of an NDIS miniport driver without requiring a physical network adapter.
+
+Because the driver does not interact with any hardware, it makes it easier to understand the miniport interface and the usage of various NDIS functions without the clutter of hardware-specific code that is normally found in a fully functional driver. The driver can be installed either manually using the Add Hardware wizard as a root enumerated virtual miniport driver or on a virtual bus (like toaster bus).
+
+This sample driver demonstrates an NDIS virtual miniport driver. If a single instance of the virtual miniport exists, it simply drops the send packets and completes the send operation successfully. If there are multiple virtual miniport instances, the instances behave as if they were multiple network interface cards (NICs) plugged into a single Ethernet hub. This "hub" indicates the incoming send packets to all of the virtual miniport instances.
+
+To test the miniport driver, install more than one miniport driver instance. You can repeat the installation to install more than one instance of the miniport.
+
+**Note**  This sample provides an example of minimal driver intended for education purposes. The driver and its sample test programs are not intended for use in a production environment.
+
+For more information on creating NDIS Miniport Drivers, see [NDIS Miniport Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff565949).
+
diff --git a/network/ndis/netvmini/6x/adapter.c b/network/ndis/netvmini/6x/adapter.c
new file mode 100644
index 00000000..0cea21d4
--- /dev/null
+++ b/network/ndis/netvmini/6x/adapter.c
@@ -0,0 +1,2318 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Adapter.C
+
+Abstract:
+
+ The purpose of this sample is to illustrate functionality of a deserialized
+ NDIS miniport driver without requiring a physical network adapter. This
+ sample is based on E100BEX sample present in the DDK. It is basically a
+ simplified version of E100bex driver. The driver can be installed either
+ manually using Add Hardware wizard as a root enumerated virtual miniport
+ driver or on a virtual bus (like toaster bus). Since the driver does not
+ interact with any hardware, it makes it very easy to understand the miniport
+ interface and the usage of various NDIS functions without the clutter of
+ hardware specific code normally found in a fully functional driver.
+
+ This sample provides an example of minimal driver intended for education
+ purposes. Neither the driver or its sample test programs are intended
+ for use in a production environment.
+
+Revision History:
+
+Notes:
+
+--*/
+
+#include "netvmin6.h"
+#include "adapter.tmh"
+
+static
+NDIS_STATUS
+NICAllocAdapter(
+ _In_ NDIS_HANDLE MiniportAdapterHandle,
+ _Outptr_ PMP_ADAPTER *Adapter);
+
+void
+NICFreeAdapter(
+ _In_ PMP_ADAPTER Adapter);
+
+VOID
+NICFreeReceiveDpc(
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc);
+
+static
+NDIS_STATUS
+NICReadRegParameters(
+ _In_ PMP_ADAPTER Adapter);
+
+static
+VOID
+NICSetMacAddress(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_HANDLE ConfigurationHandle);
+
+
+static
+VOID
+NICScheduleTheResetOrPauseDpc(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ BOOLEAN fReschedule);
+
+NDIS_TIMER_FUNCTION NICAsyncResetOrPauseDpc;
+
+#pragma NDIS_PAGEABLE_FUNCTION(MPInitializeEx)
+#pragma NDIS_PAGEABLE_FUNCTION(MPPause)
+#pragma NDIS_PAGEABLE_FUNCTION(MPRestart)
+#pragma NDIS_PAGEABLE_FUNCTION(MPHaltEx)
+#pragma NDIS_PAGEABLE_FUNCTION(MPDevicePnpEventNotify)
+#pragma NDIS_PAGEABLE_FUNCTION(NICAllocAdapter)
+#pragma NDIS_PAGEABLE_FUNCTION(NICReadRegParameters)
+#pragma NDIS_PAGEABLE_FUNCTION(NICSetMacAddress)
+
+
+
+NDIS_OID NICSupportedOids[] =
+{
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_STATISTICS,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH, // Optional
+ OID_GEN_LINK_PARAMETERS,
+ OID_GEN_INTERRUPT_MODERATION,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED, // Optional
+ OID_802_3_XMIT_MAX_COLLISIONS, // Optional
+ OID_802_3_RCV_OVERRUN, // Optional
+ OID_802_3_XMIT_UNDERRUN, // Optional
+ OID_802_3_XMIT_HEARTBEAT_FAILURE, // Optional
+ OID_802_3_XMIT_TIMES_CRS_LOST, // Optional
+ OID_802_3_XMIT_LATE_COLLISIONS, // Optional
+ OID_PNP_CAPABILITIES, // Optional
+ #if (NDIS_SUPPORT_NDIS620)
+ OID_RECEIVE_FILTER_ALLOCATE_QUEUE,
+ OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE,
+ OID_RECEIVE_FILTER_FREE_QUEUE,
+ OID_RECEIVE_FILTER_CLEAR_FILTER,
+ OID_RECEIVE_FILTER_SET_FILTER,
+#endif
+};
+
+
+NDIS_STATUS
+MPInitializeEx(
+ _In_ NDIS_HANDLE MiniportAdapterHandle,
+ _In_ NDIS_HANDLE MiniportDriverContext,
+ _In_ PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
+/*++
+Routine Description:
+
+ The MiniportInitialize function is a required function that sets up a
+ NIC (or virtual NIC) for network I/O operations, claims all hardware
+ resources necessary to the NIC in the registry, and allocates resources
+ the driver needs to carry out network I/O operations.
+
+ MiniportInitialize runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER Adapter = NULL;
+
+
+ DEBUGP(MP_TRACE, "---> MPInitializeEx\n");
+ UNREFERENCED_PARAMETER(MiniportDriverContext);
+ PAGED_CODE();
+
+
+ do
+ {
+ NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES AdapterRegistration = {0};
+ NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES AdapterGeneral = {0};
+
+#if (NDIS_SUPPORT_NDIS620)
+ NDIS_PM_CAPABILITIES PmCapabilities;
+#elif (NDIS_SUPPORT_NDIS6)
+ NDIS_PNP_CAPABILITIES PnpCapabilities;
+#endif // NDIS MINIPORT VERSION
+
+ //
+ // Allocate adapter context structure and initialize all the
+ // memory resources for sending and receiving packets.
+ //
+ Status = NICAllocAdapter(MiniportAdapterHandle, &Adapter);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ DEBUGP(MP_TRACE, "[%p] MPInitializeEx Adapter allocated.\n", Adapter);
+
+ //
+ // First, set the registration attributes.
+ //
+#if (NDIS_SUPPORT_NDIS630)
+ {C_ASSERT(sizeof(AdapterRegistration) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_2);}
+ AdapterRegistration.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ AdapterRegistration.Header.Size = sizeof(AdapterRegistration);
+ AdapterRegistration.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_2;
+#else
+ {C_ASSERT(sizeof(AdapterRegistration) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1);}
+ AdapterRegistration.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ AdapterRegistration.Header.Size = sizeof(AdapterRegistration);
+ AdapterRegistration.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+#endif // NDIS MINIPORT VERSION
+
+ AdapterRegistration.MiniportAdapterContext = Adapter;
+ AdapterRegistration.AttributeFlags = NIC_ADAPTER_ATTRIBUTES_FLAGS;
+
+#if (NDIS_SUPPORT_NDIS630)
+ AdapterRegistration.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_NO_PAUSE_ON_SUSPEND;
+#endif
+
+ AdapterRegistration.CheckForHangTimeInSeconds = NIC_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS;
+ AdapterRegistration.InterfaceType = NIC_INTERFACE_TYPE;
+
+ NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(MP_ADAPTER);
+ Status = NdisMSetMiniportAttributes(
+ MiniportAdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterRegistration);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisSetOptionalHandlers Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // Read Advanced configuration information from the registry
+ //
+ Status = NICReadRegParameters(Adapter);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // NdisMGetDeviceProperty function enables us to get the:
+ // PDO - created by the bus driver to represent our device.
+ // FDO - created by NDIS to represent our miniport as a function driver.
+ // NextDeviceObject - deviceobject of another driver (filter)
+ // attached to us at the bottom.
+ // In a pure NDIS miniport driver, there is no use for this
+ // information, but a NDISWDM driver would need to know this so that it
+ // can transfer packets to the lower WDM stack using IRPs.
+ //
+ NdisMGetDeviceProperty(
+ MiniportAdapterHandle,
+ &Adapter->Pdo,
+ &Adapter->Fdo,
+ &Adapter->NextDeviceObject,
+ NULL,
+ NULL);
+
+ //
+ // Allocate default DPC, using current processor information (this will be
+ // added to the DPC list by the allocation function). The default DPC
+ // is used for all receives when VMQ is not enabled, and for the default queue
+ // when VMQ is enabled.
+ //
+ Adapter->DefaultRecvDpc = NICAllocReceiveDpc(Adapter, 0, 0, 0);
+ if(!Adapter->DefaultRecvDpc)
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed while allocating the default DPC\n", Adapter);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // If VMQ is enabled, allocate the default receive queue. Otherwise, initialize the default receive
+ // block for use in non-VMQ receives
+ //
+ if(VMQ_ENABLED(Adapter))
+ {
+ Status = AllocateDefaultRxQueue(Adapter);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] AllocateDefaultRxQueue Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+ }
+ else
+ {
+ //
+ // Initialize the default receive block
+ //
+ Status = NICInitializeReceiveBlock(Adapter, 0);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NICInitializeReceiveBlock Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // Initialize list and lock of the free Rcb list
+ //
+ NdisInitializeListHead(&Adapter->FreeRcbList);
+ NdisAllocateSpinLock(&Adapter->FreeRcbListLock);
+
+ //
+ // Allocate the adapter's non-VMQ RCB & receive NBL data
+ //
+ Status = NICAllocRCBData(
+ Adapter,
+ NIC_MAX_BUSY_RECVS,
+ &Adapter->RcbMemoryBlock,
+ &Adapter->FreeRcbList,
+ &Adapter->FreeRcbListLock,
+ &Adapter->RecvNblPoolHandle
+ );
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ //
+ // Next, set the general attributes.
+ //
+
+#if (NDIS_SUPPORT_NDIS620)
+ {C_ASSERT(sizeof(AdapterGeneral) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2);}
+ AdapterGeneral.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ AdapterGeneral.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
+ AdapterGeneral.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
+#elif (NDIS_SUPPORT_NDIS6)
+ {C_ASSERT(sizeof(AdapterGeneral) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1);}
+ AdapterGeneral.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ AdapterGeneral.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+ AdapterGeneral.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+#endif // NDIS MINIPORT VERSION
+
+ //
+ // Specify the medium type that the NIC can support but not
+ // necessarily the medium type that the NIC currently uses.
+ //
+ AdapterGeneral.MediaType = NIC_MEDIUM_TYPE;
+
+ //
+ // Specifiy medium type that the NIC currently uses.
+ //
+ AdapterGeneral.PhysicalMediumType = NIC_PHYSICAL_MEDIUM;
+
+ //
+ // Specifiy the maximum network frame size, in bytes, that the NIC
+ // supports excluding the header. A NIC driver that emulates another
+ // medium type for binding to a transport must ensure that the maximum
+ // frame size for a protocol-supplied net buffer does not exceed the
+ // size limitations for the true network medium.
+ //
+ AdapterGeneral.MtuSize = HW_FRAME_MAX_DATA_SIZE;
+ AdapterGeneral.MaxXmitLinkSpeed = Adapter->ulLinkSendSpeed;
+ AdapterGeneral.XmitLinkSpeed = Adapter->ulLinkSendSpeed;
+ AdapterGeneral.MaxRcvLinkSpeed = Adapter->ulLinkRecvSpeed;
+ AdapterGeneral.RcvLinkSpeed = Adapter->ulLinkRecvSpeed;
+ AdapterGeneral.MediaConnectState = HWGetMediaConnectStatus(Adapter);
+ AdapterGeneral.MediaDuplexState = MediaDuplexStateFull;
+
+ //
+ // The maximum number of bytes the NIC can provide as lookahead data.
+ // If that value is different from the size of the lookahead buffer
+ // supported by bound protocols, NDIS will call MiniportOidRequest to
+ // set the size of the lookahead buffer provided by the miniport driver
+ // to the minimum of the miniport driver and protocol(s) values. If the
+ // driver always indicates up full packets with
+ // NdisMIndicateReceiveNetBufferLists, it should set this value to the
+ // maximum total frame size, which excludes the header.
+ //
+ // Upper-layer drivers examine lookahead data to determine whether a
+ // packet that is associated with the lookahead data is intended for
+ // one or more of their clients. If the underlying driver supports
+ // multipacket receive indications, bound protocols are given full net
+ // packets on every indication. Consequently, this value is identical
+ // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE.
+ //
+ AdapterGeneral.LookaheadSize = Adapter->ulLookahead;
+ AdapterGeneral.MacOptions = NIC_MAC_OPTIONS;
+ AdapterGeneral.SupportedPacketFilters = NIC_SUPPORTED_FILTERS;
+
+
+ //
+ // The maximum number of multicast addresses the NIC driver can manage.
+ // This list is global for all protocols bound to (or above) the NIC.
+ // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from
+ // the NIC driver when attempting to set the multicast address list,
+ // even if the number of elements in the given list is less than the
+ // number originally returned for this query.
+ //
+ AdapterGeneral.MaxMulticastListSize = NIC_MAX_MCAST_LIST;
+ AdapterGeneral.MacAddressLength = NIC_MACADDR_SIZE;
+
+
+ //
+ // Return the MAC address of the NIC burnt in the hardware.
+ //
+ NIC_COPY_ADDRESS(AdapterGeneral.PermanentMacAddress, Adapter->PermanentAddress);
+
+ //
+ // Return the MAC address the NIC is currently programmed to use. Note
+ // that this address could be different from the permananent address as
+ // the user can override using registry. Read NdisReadNetworkAddress
+ // doc for more info.
+ //
+ NIC_COPY_ADDRESS(AdapterGeneral.CurrentMacAddress, Adapter->CurrentAddress);
+ AdapterGeneral.RecvScaleCapabilities = NULL;
+ AdapterGeneral.AccessType = NIC_ACCESS_TYPE;
+ AdapterGeneral.DirectionType = NIC_DIRECTION_TYPE;
+ AdapterGeneral.ConnectionType = NIC_CONNECTION_TYPE;
+ AdapterGeneral.IfType = NIC_IFTYPE;
+ AdapterGeneral.IfConnectorPresent = NIC_HAS_PHYSICAL_CONNECTOR;
+ AdapterGeneral.SupportedStatistics = NIC_SUPPORTED_STATISTICS;
+ AdapterGeneral.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
+ AdapterGeneral.DataBackFillSize = 0;
+ AdapterGeneral.ContextBackFillSize = 0;
+
+
+ //
+ // The SupportedOidList is an array of OIDs for objects that the
+ // underlying driver or its NIC supports. Objects include general,
+ // media-specific, and implementation-specific objects. NDIS forwards a
+ // subset of the returned list to protocols that make this query. That
+ // is, NDIS filters any supported statistics OIDs out of the list
+ // because protocols never make statistics queries.
+ //
+ AdapterGeneral.SupportedOidList = NICSupportedOids;
+ AdapterGeneral.SupportedOidListLength = sizeof(NICSupportedOids);
+ AdapterGeneral.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
+
+ //
+ // Set the power management capabilities. The format used is NDIS
+ // version-specific.
+ //
+#if (NDIS_SUPPORT_NDIS620)
+
+ NdisZeroMemory(&PmCapabilities, sizeof(PmCapabilities));
+
+ {C_ASSERT(sizeof(PmCapabilities) >= NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_1);}
+ PmCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PmCapabilities.Header.Size = NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_1;
+ PmCapabilities.Header.Revision = NDIS_PM_CAPABILITIES_REVISION_1;
+
+ PmCapabilities.MinMagicPacketWakeUp = NIC_MAGIC_PACKET_WAKEUP;
+ PmCapabilities.MinPatternWakeUp = NIC_PATTERN_WAKEUP;
+ PmCapabilities.MinLinkChangeWakeUp = NIC_LINK_CHANGE_WAKEUP;
+
+ AdapterGeneral.PowerManagementCapabilitiesEx = &PmCapabilities;
+
+#elif (NDIS_SUPPORT_NDIS6)
+
+ NdisZeroMemory(&PnpCapabilities, sizeof(PnpCapabilities));
+ PnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NIC_MAGIC_PACKET_WAKEUP;
+ PnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NIC_PATTERN_WAKEUP;
+ AdapterGeneral.PowerManagementCapabilities = &PnpCapabilities; // Optional
+
+#endif // NDIS MINIPORT VERSION
+
+ Status = NdisMSetMiniportAttributes(
+ MiniportAdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneral);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisSetOptionalHandlers Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // Set Miniport attributes for supported and enabled VMQ features.
+ //
+ Status = InitializeRxQueueMPConfig(Adapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] InitializeRxQueueMPConfig Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // Set miniport attributes for supported and enabled NDIS QOS features.
+ //
+ Status = InitializeQOSConfig(Adapter);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] InitializeQOSConfig Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // For hardware devices, you should register your interrupt handlers
+ // here, using NdisMRegisterInterruptEx.
+ //
+
+ //
+ // Get the Adapter Resources & Initialize the hardware.
+ //
+
+ Status = HWInitialize(Adapter, MiniportInitParameters);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ } while(FALSE);
+
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (Adapter)
+ {
+ NICFreeAdapter(Adapter);
+ }
+ Adapter = NULL;
+ }
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPInitializeEx Status = 0x%08x%\n", Adapter, Status);
+ return Status;
+}
+
+
+NDIS_STATUS
+MPPause(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
+/*++
+
+Routine Description:
+
+ When a miniport receives a pause request, it enters into a Pausing state.
+ The miniport should not indicate up any more network data. Any pending
+ send requests must be completed, and new requests must be rejected with
+ NDIS_STATUS_PAUSED.
+
+ Once all sends have been completed and all recieve NBLs have returned to
+ the miniport, the miniport enters the Paused state.
+
+ While paused, the miniport can still service interrupts from the hardware
+ (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT
+ notifications).
+
+ The miniport must continue to be able to handle status indications and OID
+ requests. MiniportPause is different from MiniportHalt because, in
+ general, the MiniportPause operation won't release any resources.
+ MiniportPause must not attempt to acquire any resources where allocation
+ can fail, since MiniportPause itself must not fail.
+
+
+ MiniportPause runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ MiniportPauseParameters Additional information about the pause operation
+
+Return Value:
+
+ If the miniport is able to immediately enter the Paused state, it should
+ return NDIS_STATUS_SUCCESS.
+
+ If the miniport must wait for send completions or pending receive NBLs, it
+ should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the
+ miniport has entered the Paused state.
+
+ No other return value is permitted. The pause operation must not fail.
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPPause\n", Adapter);
+ UNREFERENCED_PARAMETER(MiniportPauseParameters);
+ PAGED_CODE();
+
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS);
+
+ NICStopTheDatapath(Adapter);
+
+
+ if (NICIsBusy(Adapter))
+ {
+ //
+ // The adapter is busy sending or receiving data, so the pause must
+ // be completed asynchronously later.
+ //
+ NICScheduleTheResetOrPauseDpc(Adapter, FALSE);
+ Status = NDIS_STATUS_PENDING;
+ }
+ else // !NICIsBusy
+ {
+ //
+ // The pause operation has completed synchronously.
+ //
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_PAUSED);
+ MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPPause\n", Adapter);
+ return Status;
+}
+
+
+NDIS_STATUS
+MPRestart(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNDIS_MINIPORT_RESTART_PARAMETERS RestartParameters)
+/*++
+
+Routine Description:
+
+ When a miniport receives a restart request, it enters into a Restarting
+ state. The miniport may begin indicating received data (e.g., using
+ NdisMIndicateReceiveNetBufferLists), handling status indications, and
+ processing OID requests in the Restarting state. However, no sends will be
+ requested while the miniport is in the Restarting state.
+
+ Once the miniport is ready to send data, it has entered the Running state.
+ The miniport informs NDIS that it is in the Running state by returning
+ NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function
+ has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete.
+
+
+ MiniportRestart runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ RestartParameters Additional information about the restart operation
+
+Return Value:
+
+ If the miniport is able to immediately enter the Running state, it should
+ return NDIS_STATUS_SUCCESS.
+
+ If the miniport is still in the Restarting state, it should return
+ NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport
+ has entered the Running state.
+
+ Other NDIS_STATUS codes indicate errors. If an error is encountered, the
+ miniport must return to the Paused state (i.e., stop indicating receives).
+
+--*/
+
+{
+ NDIS_STATUS Status = NDIS_STATUS_PENDING;
+
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPRestart\n", Adapter);
+ UNREFERENCED_PARAMETER(Adapter);
+ UNREFERENCED_PARAMETER(RestartParameters);
+ PAGED_CODE();
+
+
+ MP_CLEAR_FLAG(Adapter, (fMP_ADAPTER_PAUSE_IN_PROGRESS|fMP_ADAPTER_PAUSED));
+
+ NICStartTheDatapath(Adapter);
+
+
+ //
+ // The simulated hardware is immediately ready to send data again, so in
+ // this sample code, MiniportRestart always returns success. If we had to
+ // wait for hardware to reinitialize, we'd return NDIS_STATUS_PENDING now,
+ // and call NdisMRestartComplete later.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPRestart\n", Adapter);
+ return Status;
+}
+
+
+VOID
+MPHaltEx(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HALT_ACTION HaltAction
+ )
+/*++
+
+Routine Description:
+
+ Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE,
+ IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP
+ manager. Here, the driver should free all the resources acquired in
+ MiniportInitialize and stop access to the hardware. NDIS will not submit
+ any further request once this handler is invoked.
+
+ 1) Free and unmap all I/O resources.
+ 2) Disable interrupt and deregister interrupt handler.
+ 3) Deregister shutdown handler regsitered by
+ NdisMRegisterAdapterShutdownHandler .
+ 4) Cancel all queued up timer callbacks.
+ 5) Finally wait indefinitely for all the outstanding receive
+ packets indicated to the protocol to return.
+
+ MiniportHalt runs at IRQL = PASSIVE_LEVEL.
+
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ HaltAction The reason for halting the adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+ LONG nHaltCount = 0;
+
+
+ PAGED_CODE();
+ DEBUGP(MP_TRACE, "[%p] ---> MPHaltEx\n", Adapter);
+ UNREFERENCED_PARAMETER(HaltAction);
+
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS);
+
+ //
+ // Call Shutdown handler to disable interrupt and turn the hardware off by
+ // issuing a full reset
+ //
+ // On XP and later, NDIS notifies our PNP event handler the reason for
+ // calling Halt. So before accessing the device, check to see if the device
+ // is surprise removed, if so don't bother calling the shutdown handler to
+ // stop the hardware because it doesn't exist.
+ //
+ if(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED)) {
+ MPShutdownEx(MiniportAdapterContext, NdisShutdownPowerOff);
+ }
+
+
+ NICStopTheDatapath(Adapter);
+
+
+ while (NICIsBusy(Adapter) ||
+ Adapter->SendCompleteWorkItemQueued ||
+ Adapter->SendCompleteWorkItemRunning)
+ {
+ if (++nHaltCount % 100 == 0)
+ {
+ DEBUGP(MP_ERROR, "[%p] Halt timed out!\n", Adapter);
+ ASSERT(FALSE);
+ }
+
+ DEBUGP(MP_INFO, "[%p] MPHaltEx - waiting ...\n", Adapter);
+ NdisMSleep(1000);
+ }
+
+
+ NICFreeAdapter(Adapter);
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPHaltEx\n", Adapter);
+}
+
+
+NDIS_STATUS
+MPResetEx(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _Out_ PBOOLEAN AddressingReset)
+/*++
+
+Routine Description:
+
+ MiniportResetEx is a required to issue a hardware reset to the NIC
+ and/or to reset the driver's software state.
+
+ 1) The miniport driver can optionally complete any pending
+ OID requests. NDIS will submit no further OID requests
+ to the miniport driver for the NIC being reset until
+ the reset operation has finished. After the reset,
+ NDIS will resubmit to the miniport driver any OID requests
+ that were pending but not completed by the miniport driver
+ before the reset.
+
+ 2) A deserialized miniport driver must complete any pending send
+ operations. NDIS will not requeue pending send packets for
+ a deserialized driver since NDIS does not maintain the send
+ queue for such a driver.
+
+ 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must
+ complete the original request subsequently with a call to
+ NdisMResetComplete.
+
+ MiniportReset runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+AddressingReset - If multicast or functional addressing information
+ or the lookahead size, is changed by a reset,
+ MiniportReset must set the variable at AddressingReset
+ to TRUE before it returns control. This causes NDIS to
+ call the MiniportSetInformation function to restore
+ the information.
+
+MiniportAdapterContext - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status;
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPResetEx\n", Adapter);
+
+ *AddressingReset = FALSE;
+
+ do
+ {
+ ASSERT(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS));
+
+ if (MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
+ {
+ Status = NDIS_STATUS_RESET_IN_PROGRESS;
+ break;
+ }
+
+ MP_SET_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
+
+ //
+ // Complete all the queued up send packets
+ //
+ TXFlushSendQueue(Adapter, NDIS_STATUS_RESET_IN_PROGRESS);
+
+ if (NICIsBusy(Adapter))
+ {
+ NICScheduleTheResetOrPauseDpc(Adapter, FALSE);
+
+ //
+ // By returning NDIS_STATUS_PENDING, we are promising NDIS that
+ // we will complete the reset request by calling NdisMResetComplete.
+ //
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+
+ MP_CLEAR_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ } while(FALSE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPResetEx Status = 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+VOID
+NICScheduleTheResetOrPauseDpc(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ BOOLEAN fReschedule)
+/*++
+
+Routine Description:
+
+ Schedules the timer callback function for asynchronous pause/reset.
+
+Arguments:
+
+ Adapter -
+ fReschedule - TRUE if this is rescheduling an existing async pause/reset
+ operation, or FALSE if this is a new pause/reset operation.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER liRetryTime;
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICScheduleTheResetOrPauseDpc\n", Adapter);
+
+ if (!fReschedule)
+ {
+ Adapter->AsyncBusyCheckCount = 0;
+ }
+
+
+ liRetryTime.QuadPart = -1000000LL; // 100ms in 100ns increments
+ NdisSetTimerObject(Adapter->AsyncBusyCheckTimer, liRetryTime, 0, NULL);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICScheduleTheResetOrPauseDpc\n", Adapter);
+}
+
+
+_Use_decl_annotations_
+VOID
+NICAsyncResetOrPauseDpc(
+ PVOID SystemSpecific1,
+ PVOID FunctionContext,
+ PVOID SystemSpecific2,
+ PVOID SystemSpecific3)
+/*++
+
+Routine Description:
+
+ Timer callback function for Reset operation.
+
+Arguments:
+
+FunctionContext - Pointer to our adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(FunctionContext);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(SystemSpecific1);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+ UNREFERENCED_PARAMETER(SystemSpecific3);
+
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICAsyncResetOrPauseDpc\n", Adapter);
+
+ if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS)
+ || MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
+ {
+ BOOLEAN fBusy = NICIsBusy(Adapter);
+
+ if (fBusy && ++Adapter->AsyncBusyCheckCount <= 20)
+ {
+ //
+ // Still busy -- let's try another time.
+ //
+ NICScheduleTheResetOrPauseDpc(Adapter, TRUE);
+ }
+ else
+ {
+ if (fBusy)
+ {
+
+ //
+ // We have tried enough. Something is wrong. Let us
+ // just complete the reset request with failure.
+ //
+ DEBUGP(MP_ERROR, "[%p] Reset timed out!!!\n", Adapter);
+
+ ASSERT(FALSE);
+
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+
+ if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS))
+ {
+ DEBUGP(MP_INFO, "[%p] Done - NdisMPauseComplete\n", Adapter);
+
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_PAUSED);
+ MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS);
+
+ NdisMPauseComplete(Adapter->AdapterHandle);
+ }
+ else if (MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
+ {
+ DEBUGP(MP_INFO, "[%p] Done - NdisMResetComplete\n", Adapter);
+
+ MP_CLEAR_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
+
+ NdisMResetComplete(Adapter->AdapterHandle, Status, FALSE);
+ }
+ }
+ }
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICAsyncResetOrPauseDpc Status = 0x%08x\n", Adapter, Status);
+}
+
+VOID
+MPShutdownEx(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ NDIS_SHUTDOWN_ACTION ShutdownAction)
+/*++
+
+Routine Description:
+
+ The MiniportShutdownEx handler restores hardware to its initial state when
+ the system is shut down, whether by the user or because an unrecoverable
+ system error occurred. This is to ensure that the NIC is in a known
+ state and ready to be reinitialized when the machine is rebooted after
+ a system shutdown occurs for any reason, including a crash dump.
+
+ Here just disable the interrupt and stop the DMA engine. Do not free
+ memory resources or wait for any packet transfers to complete. Do not call
+ into NDIS at this time.
+
+ This can be called at aribitrary IRQL, including in the context of a
+ bugcheck.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ ShutdownAction The reason why NDIS called the shutdown function
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(ShutdownAction);
+ UNREFERENCED_PARAMETER(Adapter);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPShutdownEx\n", Adapter);
+
+ //
+ // We don't have any hardware to reset.
+ //
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPShutdownEx\n", Adapter);
+}
+
+
+BOOLEAN
+MPCheckForHangEx(
+ _In_ NDIS_HANDLE MiniportAdapterContext)
+/*++
+
+Routine Description:
+
+ The MiniportCheckForHangEx handler is called to report the state of the
+ NIC, or to monitor the responsiveness of an underlying device driver.
+ This is an optional function. If this handler is not specified, NDIS
+ judges the driver unresponsive when the driver holds
+ MiniportQueryInformation or MiniportSetInformation requests for a
+ time-out interval (deafult 4 sec), and then calls the driver's
+ MiniportReset function. A NIC driver's MiniportInitialize function can
+ extend NDIS's time-out interval by calling NdisMSetAttributesEx to
+ avoid unnecessary resets.
+
+ MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+
+Return Value:
+
+ TRUE NDIS calls the driver's MiniportReset function.
+ FALSE Everything is fine
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPCheckForHangEx\n", Adapter);
+ DEBUGP(MP_TRACE, "[%p] <--- MPCheckForHangEx. FALSE\n", Adapter);
+ return FALSE;
+}
+
+
+VOID
+MPDevicePnpEventNotify(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
+/*++
+
+Routine Description:
+
+
+
+ Runs at IRQL = PASSIVE_LEVEL in the context of system thread.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ NetDevicePnPEvent Self-explanatory
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPDevicePnpEventNotify\n", Adapter);
+
+ PAGED_CODE();
+
+
+ switch (NetDevicePnPEvent->DevicePnPEvent)
+ {
+ case NdisDevicePnPEventSurpriseRemoved:
+ //
+ // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL.
+ // NDIS calls MiniportHalt function after this call returns.
+ //
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED);
+ DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", Adapter);
+ break;
+
+ case NdisDevicePnPEventPowerProfileChanged:
+ //
+ // After initializing a miniport driver and after miniport driver
+ // receives an OID_PNP_SET_POWER notification that specifies
+ // a device power state of NdisDeviceStateD0 (the powered-on state),
+ // NDIS calls the miniport's MiniportPnPEventNotify function with
+ // PnPEvent set to NdisDevicePnPEventPowerProfileChanged.
+ //
+ DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventPowerProfileChanged\n", Adapter);
+
+ if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG))
+ {
+ ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer);
+
+ if (NdisPowerProfile == NdisPowerProfileBattery)
+ {
+ DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", Adapter);
+ }
+ if (NdisPowerProfile == NdisPowerProfileAcOnLine)
+ {
+ DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter);
+ }
+ }
+ break;
+
+ default:
+ DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, NetDevicePnPEvent->DevicePnPEvent);
+ }
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPDevicePnpEventNotify\n", Adapter);
+}
+
+NDIS_STATUS
+NICAllocAdapter(
+ _In_ NDIS_HANDLE MiniportAdapterHandle,
+ _Outptr_ PMP_ADAPTER *pAdapter)
+/*++
+Routine Description:
+
+ The NICAllocAdapter function allocates and initializes the memory used to track a miniport instance.
+
+ NICAllocAdapter runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ MiniportAdapterHandle NDIS handle for the adapter.
+ pAdapter Receives the allocated and initialized adapter memory.
+
+ Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ PMP_ADAPTER Adapter = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LONG index;
+
+ DEBUGP(MP_TRACE, "---> NICAllocAdapter\n");
+
+ PAGED_CODE();
+
+ *pAdapter = NULL;
+
+ do
+ {
+ //
+ // Allocate extra space for the MP_ADAPTER memory (one cache line's worth) so that we can
+ // reference the memory from a cache-aligned starting point. This way we guarantee that
+ // members with cache-aligned directives are actually cache aligned.
+ //
+ PVOID UnalignedAdapterBuffer = NULL;
+ ULONG UnalignedAdapterBufferSize = sizeof(MP_ADAPTER)+ NdisGetSharedDataAlignment();
+ NDIS_TIMER_CHARACTERISTICS Timer;
+
+ //
+ // Allocate memory for adapter context (unaligned)
+ //
+ UnalignedAdapterBuffer = NdisAllocateMemoryWithTagPriority(
+ NdisDriverHandle,
+ UnalignedAdapterBufferSize,
+ NIC_TAG,
+ NormalPoolPriority);
+ if (!UnalignedAdapterBuffer)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "Failed to allocate memory for adapter context\n");
+ break;
+ }
+
+ //
+ // Zero the memory block
+ //
+ NdisZeroMemory(UnalignedAdapterBuffer, UnalignedAdapterBufferSize);
+
+ //
+ // Start the Adapter pointer at a cache-aligned boundary
+ //
+ Adapter = ALIGN_UP_POINTER_BY(UnalignedAdapterBuffer, NdisGetSharedDataAlignment());
+
+ //
+ // Store the unaligned information so that we can free it later
+ //
+ Adapter->UnalignedAdapterBuffer = UnalignedAdapterBuffer;
+ Adapter->UnalignedAdapterBufferSize = UnalignedAdapterBufferSize;
+
+ //
+ // Set the adapter handle
+ //
+ Adapter->AdapterHandle = MiniportAdapterHandle;
+
+ NdisInitializeListHead(&Adapter->List);
+
+ //
+ // Initialize Send & Recv listheads and corresponding
+ // spinlocks.
+ //
+ NdisInitializeListHead(&Adapter->FreeTcbList);
+ NdisAllocateSpinLock(&Adapter->FreeTcbListLock);
+
+ NdisInitializeListHead(&Adapter->SendWaitList);
+ NdisAllocateSpinLock(&Adapter->SendWaitListLock);
+
+ NdisInitializeListHead(&Adapter->BusyTcbList);
+ NdisAllocateSpinLock(&Adapter->BusyTcbListLock);
+
+ KeInitializeSpinLock(&Adapter->SendPathSpinLock);
+
+ //
+ // Set the default lookahead buffer size.
+ //
+ Adapter->ulLookahead = NIC_MAX_LOOKAHEAD;
+
+ //
+ // Allocate data for Send and Receive Control blocks.
+ //
+
+ Adapter->TcbMemoryBlock = NdisAllocateMemoryWithTagPriority(
+ MiniportAdapterHandle,
+ sizeof(TCB) * NIC_MAX_BUSY_SENDS,
+ NIC_TAG_TCB,
+ NormalPoolPriority);
+
+ if (!Adapter->TcbMemoryBlock)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateMemoryWithTagPriority failed\n", Adapter);
+ break;
+ }
+
+ for (index = 0; index < NIC_MAX_BUSY_SENDS; index++)
+ {
+ NdisInterlockedInsertTailList(
+ &Adapter->FreeTcbList,
+ &((PTCB)Adapter->TcbMemoryBlock)[index].TcbLink,
+ &Adapter->FreeTcbListLock);
+ }
+
+ //
+ // Set up timers to simulate hardware interrupts (SendComplete and Recv)
+ //
+
+ NdisZeroMemory(&Timer, sizeof(Timer));
+
+ {C_ASSERT(NDIS_SIZEOF_TIMER_CHARACTERISTICS_REVISION_1 <= sizeof(Timer));}
+ Timer.Header.Type = NDIS_OBJECT_TYPE_TIMER_CHARACTERISTICS;
+ Timer.Header.Size = NDIS_SIZEOF_TIMER_CHARACTERISTICS_REVISION_1;
+ Timer.Header.Revision = NDIS_TIMER_CHARACTERISTICS_REVISION_1;
+
+ Timer.TimerFunction = TXSendCompleteDpc;
+ Timer.FunctionContext = Adapter;
+ Timer.AllocationTag = NIC_TAG_TIMER;
+
+ Status = NdisAllocateTimerObject(
+ NdisDriverHandle,
+ &Timer,
+ &Adapter->SendCompleteTimer);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ Adapter->SendCompleteWorkItem = NdisAllocateIoWorkItem(MiniportAdapterHandle);
+ if (Adapter->SendCompleteWorkItem == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize DPC list data
+ //
+ NdisInitializeListHead(&Adapter->RecvDpcList);
+ NdisAllocateSpinLock(&Adapter->RecvDpcListLock);
+
+ //
+ // Set up a timer function for use with our MPReset routine.
+ //
+ Timer.TimerFunction = NICAsyncResetOrPauseDpc;
+
+ Status = NdisAllocateTimerObject(
+ NdisDriverHandle,
+ &Timer,
+ &Adapter->AsyncBusyCheckTimer);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // The miniport adapter is powered up
+ //
+ Adapter->CurrentPowerState = NdisDeviceStateD0;
+
+ //
+ // Initialize and allocate the basic VMQ data for this adapter if supported. Queues, filters, shared memory,
+ // and other data is allocated at a later time, when the relavant OID's are called to eable/configure them.
+ //
+ Status = AllocateVMQData(Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] AllocateVMQData Status 0x%08x\n", Adapter, Status);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ } while(FALSE);
+
+
+ *pAdapter = Adapter;
+
+ //
+ // In the failure case, the caller of this routine will end up
+ // calling NICFreeAdapter to free all the successfully allocated
+ // resources.
+ //
+ DEBUGP(MP_TRACE, "[%p] <--- NICAllocAdapter\n", Adapter);
+ return Status;
+}
+
+
+void NICFreeAdapter(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+Routine Description:
+
+ The NICFreeAdapter function frees memory used to track a miniport instance. Should only be called from MPHaltEx.
+
+ NICFreeAdapter runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter Adapter memory to free.
+
+ Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ PLIST_ENTRY pEntry;
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICFreeAdapter\n", Adapter);
+
+ ASSERT(Adapter);
+
+ //
+ // Free all the resources we allocated in NICAllocAdapter.
+ //
+
+ if (Adapter->AsyncBusyCheckTimer)
+ {
+ NdisFreeTimerObject(Adapter->AsyncBusyCheckTimer);
+ Adapter->AsyncBusyCheckTimer = NULL;
+ }
+
+ if(Adapter->SendCompleteTimer)
+ {
+ NdisFreeTimerObject(Adapter->SendCompleteTimer);
+ Adapter->SendCompleteTimer = NULL;
+ }
+
+ if (Adapter->SendCompleteWorkItem)
+ {
+ ASSERT(!Adapter->SendCompleteWorkItemQueued);
+ NdisFreeIoWorkItem(Adapter->SendCompleteWorkItem);
+ Adapter->SendCompleteWorkItem = NULL;
+ }
+
+ //
+ // If VMQ is enabled, then the global adapter RCB list will not have been allocated
+ //
+ if(!VMQ_ENABLED(Adapter))
+ {
+ if(Adapter->FreeRcbList.Flink)
+ {
+ while (NULL != (pEntry = NdisInterlockedRemoveHeadList(
+ &Adapter->FreeRcbList,
+ &Adapter->FreeRcbListLock)))
+ {
+ PRCB Rcb = CONTAINING_RECORD(pEntry, RCB, RcbLink);
+ NdisFreeNetBufferList(Rcb->Nbl);
+ }
+ }
+
+ if (Adapter->RecvNblPoolHandle)
+ {
+ NdisFreeNetBufferListPool(Adapter->RecvNblPoolHandle);
+ Adapter->RecvNblPoolHandle = NULL;
+ }
+
+ if (Adapter->RcbMemoryBlock)
+ {
+ NdisFreeMemory(
+ Adapter->RcbMemoryBlock,
+ sizeof(RCB)*NIC_MAX_BUSY_RECVS,
+ 0);
+ Adapter->RcbMemoryBlock = NULL;
+ }
+
+ if(Adapter->DefaultRecvDpc)
+ {
+ //
+ // For non VMQ receives, we've referenced the default queue DPC so we should reduce that count
+ //
+ NICReceiveDpcRemoveOwnership(Adapter->DefaultRecvDpc, 0);
+ Adapter->DefaultRecvDpc = NULL;
+ }
+
+ }
+
+ if (Adapter->TcbMemoryBlock)
+ {
+ NdisFreeMemory(
+ Adapter->TcbMemoryBlock,
+ sizeof(TCB)*NIC_MAX_BUSY_SENDS,
+ 0);
+ Adapter->TcbMemoryBlock = NULL;
+ }
+
+ ASSERT(Adapter->SendWaitList.Flink && IsListEmpty(&Adapter->SendWaitList));
+ ASSERT(Adapter->BusyTcbList.Flink && IsListEmpty(&Adapter->BusyTcbList));
+
+ NdisFreeSpinLock(&Adapter->FreeTcbListLock);
+ NdisFreeSpinLock(&Adapter->SendWaitListLock);
+ NdisFreeSpinLock(&Adapter->BusyTcbListLock);
+ NdisFreeSpinLock(&Adapter->FreeRcbListLock);
+
+ //
+ // Free any remaining VMQ related data
+ //
+ FreeVMQData(Adapter);
+
+ //
+ // Free receive DPCs
+ //
+ if(Adapter->RecvDpcList.Flink)
+ {
+ while (!IsListEmpty(&Adapter->RecvDpcList))
+ {
+ pEntry = RemoveHeadList(&Adapter->RecvDpcList);
+ NICFreeReceiveDpc(CONTAINING_RECORD(pEntry, MP_ADAPTER_RECEIVE_DPC, Entry));
+ }
+ }
+ NdisFreeSpinLock(&Adapter->RecvDpcListLock);
+
+ //
+ // Finally free the memory for adapter context.
+ //
+ NdisFreeMemory(Adapter->UnalignedAdapterBuffer, Adapter->UnalignedAdapterBufferSize, 0);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICFreeAdapter\n", Adapter);
+}
+
+VOID
+NICUpdateDPCMaxIndicateCount(
+ _In_ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc)
+/*++
+Routine Description:
+
+ The NICUpdateDPCMaxIndicateCount function updates the maximum amount of NBLs to be indicated per block, based
+ on the number of owned receive blocks.
+
+Arguments:
+
+ ReceiveDpc The receive DPC being modified
+ BlockId ID of the receive block to add ownership
+
+ Return Value:
+
+ None
+--*/
+{
+ if(ReceiveDpc->RecvBlockCount)
+ {
+ //
+ // Update MaxNblCountPerIndicate. Scale back the amount of NBL indications we're allowed to do per
+ // consumed receive block so that we don't sepnd too much time in the DPC as the number of queues grows large.
+ //
+ ReceiveDpc->MaxNblCountPerIndicate = NIC_MAX_RECVS_PER_DPC/ReceiveDpc->RecvBlockCount;
+ }
+
+}
+
+VOID
+NICReceiveDpcSetOwnership(
+ _In_ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ The NICReceiveDpcSetOwnership function updates the Receive DPC passed in so that it consumes the receive queue of the
+ passed in receive block ID. This involves updating the boolean array, block count, and updating the maximum
+ amount of NBLs to be indicated per block.
+
+Arguments:
+
+ ReceiveDpc The receive DPC being modified
+ BlockId ID of the receive block to add ownership
+
+ Return Value:
+
+ None
+--*/
+{
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+
+ //
+ // If the DPC is not already set to consume receives for this QueueId, increase
+ // the reference count and set it to be consumed.
+ //
+ if(!ReceiveDpc->RecvBlock[BlockId])
+ {
+ InterlockedIncrement(&ReceiveDpc->RecvBlockCount);
+ ReceiveDpc->RecvBlock[BlockId]=TRUE;
+ NICUpdateDPCMaxIndicateCount(ReceiveDpc);
+ }
+}
+
+VOID
+NICReceiveDpcRemoveOwnership(
+ _In_ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ The NICReceiveDpcRemoveOwnership function updates the Receive DPC passed in so that it stops consuming the receive
+ queue of the passed in receive block ID. This involves updating the boolean array, block count, and updating the maximum
+ amount of NBLs to be indicated per block.
+
+Arguments:
+
+ ReceiveDpc The receive DPC being modified
+ ReceiveBlockId ID of the receive block to remove ownership
+
+ Return Value:
+
+ None
+--*/
+{
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+
+ //
+ // If the DPC is set to consume receives for this QueueId, decrease
+ // the reference count and set it to not be consumed.
+ //
+ if(ReceiveDpc->RecvBlock[BlockId])
+ {
+ InterlockedDecrement(&ReceiveDpc->RecvBlockCount);
+ ASSERT(ReceiveDpc->RecvBlockCount>=0);
+ ReceiveDpc->RecvBlock[BlockId]=FALSE;
+ NICUpdateDPCMaxIndicateCount(ReceiveDpc);
+ }
+}
+
+PMP_ADAPTER_RECEIVE_DPC
+NICAllocReceiveDpc(
+ _In_ PMP_ADAPTER Adapter,
+ ULONG ProcessorNumber,
+ USHORT ProcessorGroup,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ The NICAllocReceiveDpc function allocates a receive DPC with the specified processor characteristics
+ for the target QueueId. If the adapter has already allocated a DPC that matches the processor requirements,
+ the existing DPC is reused and given ownership of consuming the QueueId's receives.
+
+ NICAllocReceiveDpc runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to the adapter that will own the DPC.
+ ProcessorNumber Target processor for DPC
+ ProcessorGroup Target processor group for the DPC (if not Win7, set to 0)
+ QueueId Queue whose receives the DPC should consume (0 for non-VMQ scenarios)
+
+ Return Value:
+
+ PMP_ADAPTER_RECEIVE_DPC structure on success.
+ NULL on failure.
+
+--*/
+{
+ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc=NULL, ExistingDpc=NULL;
+ PLIST_ENTRY ReceiveListEntry;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+
+ do
+ {
+ ReceiveDpc = NdisAllocateMemoryWithTagPriority(
+ Adapter->AdapterHandle,
+ sizeof(MP_ADAPTER_RECEIVE_DPC),
+ NIC_TAG_DPC,
+ NormalPoolPriority);
+ if(!ReceiveDpc)
+ {
+ DEBUGP(MP_ERROR, "[%p] Could not allocate memory for receive DPC.\n", Adapter);
+ break;
+ }
+ NdisZeroMemory(ReceiveDpc, sizeof(MP_ADAPTER_RECEIVE_DPC));
+
+ ReceiveDpc->Adapter = Adapter;
+
+ //
+ // Initialize DPC data (entry, DPC function, target processor)
+ //
+ NdisInitializeListHead(&ReceiveDpc->Entry);
+ KeInitializeDpc(&ReceiveDpc->Dpc, RXReceiveIndicateDpc, Adapter);
+
+ //
+ // Allocate the work item that's used if we're close to the DPC watchdog timer limit
+ //
+ ReceiveDpc->WorkItem = NdisAllocateIoWorkItem(Adapter->AdapterHandle);
+ if(!ReceiveDpc->WorkItem)
+ {
+ DEBUGP(MP_ERROR, "[%p] Could not allocate work item for receive DPC.\n", Adapter);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Make sure the target DPC list starts getting processed as soon as it's queued even if was queued from
+ // another processor.
+ //
+ KeSetImportanceDpc(&ReceiveDpc->Dpc, MediumHighImportance);
+
+#if (NDIS_SUPPORT_NDIS620)
+ {
+ //
+ // Use Win7 APIs to set the target processor
+ //
+ PROCESSOR_NUMBER DpcProcessor = {0};
+ DpcProcessor.Number = (UCHAR)ProcessorNumber;
+ DpcProcessor.Group = ProcessorGroup;
+ Status = KeSetTargetProcessorDpcEx(&ReceiveDpc->Dpc, &DpcProcessor);
+ }
+#else
+ //
+ // Use Vista APIs to set target processor
+ //
+ KeSetTargetProcessorDpc(&ReceiveDpc->Dpc, (CCHAR)ProcessorNumber);
+#endif
+ if(!NT_SUCCESS(Status))
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed setting KeSetTargetProcessorDpcEx. Status: 0x%08x\n", Adapter, Status);
+ break;
+ }
+ ReceiveDpc->ProcessorGroup = ProcessorGroup;
+ ReceiveDpc->ProcessorNumber = ProcessorNumber;
+
+ //
+ // Check if it's already on the list, if it is, return existing Dpc and free this one
+ // otherwise, add to the adapter's DPC list.
+ //
+ NdisAcquireSpinLock(&Adapter->RecvDpcListLock);
+
+ for(ReceiveListEntry = Adapter->RecvDpcList.Flink;
+ ReceiveListEntry != &Adapter->RecvDpcList;
+ ExistingDpc = NULL, ReceiveListEntry = ReceiveListEntry->Flink)
+ {
+ ExistingDpc = CONTAINING_RECORD(ReceiveListEntry, MP_ADAPTER_RECEIVE_DPC, Entry);
+ if(ExistingDpc->ProcessorNumber == ProcessorNumber && ExistingDpc->ProcessorGroup == ProcessorGroup)
+ {
+ //
+ // A DPC exists with matching affinity information. Break so that we don't NULL ExistingDpc
+ //
+ break;
+ }
+ }
+
+ if(ExistingDpc)
+ {
+ //
+ // Use existing DPC
+ //
+ DEBUGP(MP_TRACE, "[%p] Reusing existing DPC which matches affinity.\n", Adapter);
+ NICFreeReceiveDpc(ReceiveDpc);
+ ReceiveDpc = ExistingDpc;
+
+ }
+ else
+ {
+ //
+ // Add new DPC to adapter's list
+ //
+ InsertTailList(&Adapter->RecvDpcList, &ReceiveDpc->Entry);
+ }
+
+ NdisReleaseSpinLock(&Adapter->RecvDpcListLock);
+
+ NICReceiveDpcSetOwnership(ReceiveDpc,BlockId);
+
+ }while(FALSE);
+
+ if(!NT_SUCCESS(Status) && ReceiveDpc)
+ {
+ NICFreeReceiveDpc(ReceiveDpc);
+ ReceiveDpc = NULL;
+ }
+
+ return ReceiveDpc;
+}
+
+VOID
+NICFreeReceiveDpc(
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc)
+/*++
+Routine Description:
+
+ The NICFreeReceiveDpc function frees the passed in DPC. Should only be called when the DPC is not active (not queued, flushed).
+
+Arguments:
+
+ AdapterDpc DPC to free
+
+ Return Value:
+
+ None
+
+--*/
+{
+ ASSERT(AdapterDpc->RecvBlockCount==0);
+ //
+ // Free DPC dymainc fields and memory
+ //
+ if(AdapterDpc->WorkItem)
+ {
+ NdisFreeIoWorkItem(AdapterDpc->WorkItem);
+ }
+ NdisFreeMemory(AdapterDpc, sizeof(MP_ADAPTER_RECEIVE_DPC), 0);
+}
+
+PMP_ADAPTER_RECEIVE_DPC
+NICGetDefaultReceiveDpc(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ The NICGetDefaultReceiveDpc function returns the default receive DPC for the adapter, and sets it to consume
+ receives from the passed in QueueId.
+
+
+Arguments:
+
+ Adapter Pointer to the adapter that will own the DPC.
+ QueueId Queue whose receives the DPC should consume (0 for non-VMQ scenarios)
+
+ Return Value:
+
+ PMP_ADAPTER_RECEIVE_DPC structure.
+
+--*/
+{
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ NdisAcquireSpinLock(&Adapter->RecvDpcListLock);
+ NICReceiveDpcSetOwnership(Adapter->DefaultRecvDpc,BlockId);
+ NdisReleaseSpinLock(&Adapter->RecvDpcListLock);
+ }
+ else
+ {
+ UNREFERENCED_PARAMETER(BlockId);
+ }
+
+ return Adapter->DefaultRecvDpc;
+}
+
+NDIS_STATUS
+ NICAllocRCBData(
+ _In_ PMP_ADAPTER Adapter,
+ ULONG NumberOfRcbs,
+ _Outptr_result_bytebuffer_(NumberOfRcbs * sizeof(RCB)) PVOID *RcbMemoryBlock,
+ _Inout_ PLIST_ENTRY FreeRcbList,
+ _Inout_ PNDIS_SPIN_LOCK FreeRcbListLock,
+ _Inout_ PNDIS_HANDLE RecvNblPoolHandle
+ )
+/*++
+Routine Description:
+
+ The NICAllocRCBData function allocated NumberOfRcbs worth of RCB and NBL memory for use in receive indication,
+ and populates the passed in FreeRcbList with this data.
+
+ IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ NumberOfRcbs Number of RCB structures to allocate (and NBLs as a result)
+ RcbMemoryBlock Receives the allocated memory block that is split up into each individual RCB
+ FreeRcbList Initialized blank list to be populated with each individual RCB.
+ FreeRcbListLock Initialized lock used when updating the RCB list (and subsequent consumers should use lock).
+ RcbNblPoolHandle Receives the Ndis NBL pool handle for the allocated NBLs (to be used on free).
+
+ Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NET_BUFFER_LIST_POOL_PARAMETERS NblParameters;
+ ULONG index;
+
+ do
+ {
+ //
+ // Allocate an NBL pool for receive indications.
+ //
+
+ {C_ASSERT(sizeof(NblParameters) >= NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1);}
+ NblParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ NblParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ NblParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+
+ NblParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT; // always use DEFAULT for miniport drivers
+ NblParameters.fAllocateNetBuffer = TRUE;
+ NblParameters.ContextSize = 0;
+ NblParameters.PoolTag = NIC_TAG_RECV_NBL;
+ NblParameters.DataSize = 0;
+
+ *RecvNblPoolHandle = NdisAllocateNetBufferListPool(
+ NdisDriverHandle,
+ &NblParameters);
+ if (!*RecvNblPoolHandle)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateNetBufferListPool failed\n", Adapter);
+ break;
+ }
+
+ //
+ // Allocate receive memory block
+ //
+ *RcbMemoryBlock = NdisAllocateMemoryWithTagPriority(
+ Adapter->AdapterHandle,
+ sizeof(RCB) * NumberOfRcbs,
+ NIC_TAG_RCB,
+ NormalPoolPriority);
+
+ if (!*RcbMemoryBlock)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateMemoryWithTagPriority failed\n", Adapter);
+ break;
+ }
+ NdisZeroMemory(*RcbMemoryBlock, sizeof(RCB) * NumberOfRcbs);
+
+ //
+ // Split into individual RCBs, allocate NBL, and add to free list
+ //
+ for (index = 0; index < NumberOfRcbs; index++)
+ {
+ PRCB Rcb = &((PRCB)*RcbMemoryBlock)[index];
+
+ //
+ // Allocate an NBL with its single NET_BUFFER from the preallocated
+ // pool.
+ //
+ Rcb->Nbl = NdisAllocateNetBufferAndNetBufferList(
+ *RecvNblPoolHandle,
+ 0, // ContextSize
+ 0, // ContextBackfill
+ NULL, // MdlChain
+ 0, // DataOffset
+ 0); // DataLength
+ if (Rcb->Nbl == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateNetBufferAndNetBufferList failed\n", Adapter);
+ break;
+ }
+
+ //
+ // Add RCB pointer to miniport reserved portion of NBL
+ //
+ RCB_FROM_NBL(Rcb->Nbl) = Rcb;
+
+ NdisInterlockedInsertTailList(
+ FreeRcbList,
+ &Rcb->RcbLink,
+ FreeRcbListLock);
+ }
+
+ }while(FALSE);
+
+ return Status;
+}
+
+NDIS_STATUS
+NICReadRegParameters(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+Routine Description:
+
+ Read device configuration parameters from the registry
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ WrapperConfigurationContext For use by NdisOpenConfiguration
+
+ Should be called at IRQL = PASSIVE_LEVEL.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+ NDIS_STATUS_RESOURCES
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ NDIS_CONFIGURATION_OBJECT ConfigurationParameters;
+ NDIS_HANDLE ConfigurationHandle;
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICReadRegParameters\n", Adapter);
+
+ PAGED_CODE();
+
+ //
+ // Open the registry for this adapter to read advanced
+ // configuration parameters stored by the INF file.
+ //
+
+ NdisZeroMemory(&ConfigurationParameters, sizeof(ConfigurationParameters));
+
+ {C_ASSERT(sizeof(ConfigurationParameters) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1);}
+ ConfigurationParameters.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ ConfigurationParameters.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1;
+ ConfigurationParameters.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+
+ ConfigurationParameters.NdisHandle = Adapter->AdapterHandle;
+ ConfigurationParameters.Flags = 0;
+
+ Status = NdisOpenConfigurationEx(
+ &ConfigurationParameters,
+ &ConfigurationHandle);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisOpenConfigurationEx Status = 0x%08x\n", Adapter, Status);
+ return NDIS_STATUS_FAILURE;
+ }
+
+
+ //
+ // Read all of our configuration parameters using NdisReadConfiguration
+ // and parse the value.
+ //
+ NICSetMacAddress(Adapter, ConfigurationHandle);
+
+ Adapter->ulLinkSendSpeed = NIC_XMIT_SPEED;
+ Adapter->ulLinkRecvSpeed = NIC_RECV_SPEED;
+
+ //
+ // Read VMQ related configuration parameters
+ //
+ Status = ReadRxQueueConfig(ConfigurationHandle, Adapter);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] ReadRxQueueConfig Status = 0x%08x\n", Adapter, Status);
+ Status = NDIS_STATUS_FAILURE;
+ goto Exit;
+ }
+
+ //
+ // Read NDIS QOS related configuration parameters
+ //
+ Status = ReadQOSConfig(ConfigurationHandle, Adapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] ReadQOSConfig Status = 0x%08x\n", Adapter, Status);
+ Status = NDIS_STATUS_FAILURE;
+ goto Exit;
+ }
+
+Exit:
+ //
+ // Close the configuration registry
+ //
+ NdisCloseConfiguration(ConfigurationHandle);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICReadRegParameters Status = 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+VOID
+NICSetMacAddress(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_HANDLE ConfigurationHandle)
+/*++
+Routine Description:
+
+ Configures the NIC with the correct permanent and current MAC addresses.
+ If no permanent address is saved, generate a new one.
+
+ IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ ConfigurationHandle NIC configuration from NdisOpenConfigurationEx
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PUCHAR NetworkAddress;
+ UINT Length = 0;
+
+
+ PAGED_CODE();
+
+
+ HWReadPermanentMacAddress(
+ Adapter,
+ ConfigurationHandle,
+
+ Adapter->PermanentAddress);
+
+
+ //
+ // Now seed the current MAC address with the permanent address.
+ //
+ NIC_COPY_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress);
+
+
+ //
+ // Read NetworkAddress registry value and use it as the current address
+ // if there is a software configurable NetworkAddress specified in
+ // the registry.
+ //
+ NdisReadNetworkAddress(
+ &Status,
+ &NetworkAddress,
+ &Length,
+ ConfigurationHandle);
+
+ if ((Status == NDIS_STATUS_SUCCESS) && (Length == NIC_MACADDR_SIZE))
+ {
+ if ((NIC_ADDR_IS_MULTICAST(NetworkAddress)
+ || NIC_ADDR_IS_BROADCAST(NetworkAddress))
+ || !NIC_ADDR_IS_LOCALLY_ADMINISTERED(NetworkAddress))
+ {
+ DEBUGP(MP_ERROR, "[%p] Overriding NetworkAddress is invalid: ", Adapter);
+ DbgPrintAddress(NetworkAddress);
+ }
+ else
+ {
+ NIC_COPY_ADDRESS(Adapter->CurrentAddress, NetworkAddress);
+ }
+ }
+
+ DEBUGP(MP_LOUD, "[%p] Permanent Address = ", Adapter);
+ DbgPrintAddress(Adapter->PermanentAddress);
+
+ DEBUGP(MP_LOUD, "[%p] Current Address = ", Adapter);
+ DbgPrintAddress(Adapter->CurrentAddress);
+}
+
+
+BOOLEAN
+NICIsBusy(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+Routine Description:
+
+ The NICIsBusy function returns whether the NIC has pending receives or sends. Before calling this
+ function, the NIC should be in a state where it will not receive new sends/receives (either datapath
+ is stopped, or !MP_IS_READY). Otherwise, the NIC may create new pending receives and sends after the
+ NICIsBusy call.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+ TRUE: Send or Receive path is not idle.
+ FALSE: Send & Receive paths are idle.
+
+--*/
+{
+ BOOLEAN fBusy = FALSE;
+ DEBUGP(MP_TRACE, "[%p] ---> NICIsBusy\n", Adapter);
+
+#if DBG
+ //
+ // Check whether we might get new sends/receives
+ //
+ if(MPIsAdapterAttached(Adapter))
+ {
+ //
+ // Adapter is still attached to the datapath, so it should not be ready (otherwise receives could get queued after we've read the counters)
+ //
+ ASSERT(!MP_IS_READY(Adapter));
+ }
+#endif
+
+ //
+ // Check if all the NBLs that the protocol sent down for transmission have
+ // been completed yet.
+ //
+ if (Adapter->nBusySend)
+ {
+ DEBUGP(MP_INFO, "[%p] Send path is not idle, nBusySend = %d", Adapter, Adapter->nBusySend);
+ fBusy = TRUE;
+ }
+ else
+ {
+ //
+ // Check if all of our NBLs that we indicated up to the protocol have
+ // returned to us yet.
+ //
+ USHORT ReceiveBlockId = 0;
+ for(;ReceiveBlockId<NIC_SUPPORTED_NUM_QUEUES; ++ReceiveBlockId)
+ {
+ if(RECEIVE_BLOCK_IS_BUSY(Adapter, ReceiveBlockId))
+ {
+ DEBUGP(MP_INFO, "[%p] Recv block %i not idle, nBusyRecv = %u\n", Adapter, ReceiveBlockId, Adapter->ReceiveBlock[ReceiveBlockId].PendingReceives);
+ fBusy = TRUE;
+ break;
+ }
+ }
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICIsBusy fBusy = %u\n", Adapter, (UINT)fBusy);
+ return fBusy;
+}
+
+
+NDIS_STATUS
+NICInitializeReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ The NICInitializeReceiveBlock function initializes the fields of an adapter receive block. This block
+ is consumed by the owning receive DPC.
+
+
+Arguments:
+
+ Adapter - Pointer to our Adapter
+ BlockIndex - Receive block to initialize
+
+Return Value:
+
+ NDIS_STATUS_xxx code.
+
+--*/
+{
+ DEBUGP(MP_TRACE, "[%p] ---> NICInitializeReceiveBlock. Index: %i\n", Adapter, BlockId);
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+
+ NdisZeroMemory(&Adapter->ReceiveBlock[BlockId], sizeof(MP_ADAPTER_RECEIVE_BLOCK));
+ NdisInitializeListHead(&Adapter->ReceiveBlock[BlockId].ReceiveList);
+ NdisAllocateSpinLock(&Adapter->ReceiveBlock[BlockId].ReceiveListLock);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICInitializeReceiveBlock\n", Adapter);
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+VOID
+NICFlushReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ This routine flushes all pending receives for a specific adapter receive block.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ BlockIndex - Receive block to flush
+Return Value:
+
+ None
+
+--*/
+{
+ PLIST_ENTRY Entry;
+ PMP_ADAPTER_RECEIVE_BLOCK ReceiveBlock;
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICFlushReceiveBlock. QueueId: %i\n", Adapter, BlockId);
+ ASSERT(BlockId < NIC_SUPPORTED_NUM_QUEUES);
+ ReceiveBlock = &Adapter->ReceiveBlock[BlockId];
+
+ //
+ // Return any pending receives on the block
+ //
+ for(Entry = NdisInterlockedRemoveHeadList(&ReceiveBlock->ReceiveList, &ReceiveBlock->ReceiveListLock);
+ Entry;
+ Entry = NdisInterlockedRemoveHeadList(&ReceiveBlock->ReceiveList, &ReceiveBlock->ReceiveListLock))
+ {
+ ReturnRCB(Adapter, CONTAINING_RECORD(Entry, RCB, RcbLink));
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <-- NICFlushReceiveBlock\n", Adapter);
+
+}
+
+NDIS_STATUS
+NICReferenceReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId)
+/*++
+Routine Description:
+
+ This routine increments the pending receive count on a adapter receive block. This count is used
+ throughout the code to determine whether there are pending operations that will use the adapter's resources such as
+ receive buffers (which would pend operations such as adapter reset, VMQ queue free, etc...).
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ BlockIndex - Receive block to flush
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if reference was acquired succesfully.
+ NDIS_STATUS_ADAPTER_NOT_READY if the adapter state is such that we should not acquire new references to resources
+
+--*/
+{
+ //
+ // Increment the reference count before checking NIC state avoid race conditions with code that checks reference count. The
+ // reference will be undone if the adapter is not ready.
+ //
+ ULONG RefCount = InterlockedIncrement(&Adapter->ReceiveBlock[BlockId].PendingReceives);
+
+ //
+ // Make sure the increment happens before ready state check
+ //
+ KeMemoryBarrier();
+
+ //
+ // If the adapter is not ready, undo the reference and fail the call
+ //
+ if(!MP_IS_READY(Adapter))
+ {
+ InterlockedDecrement(&Adapter->ReceiveBlock[BlockId].PendingReceives);
+ DEBUGP(MP_LOUD, "[%p] Could not acquire reference for ReceiveBlock %i. The adapter is not ready.\n", Adapter, BlockId);
+ return NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+
+ DEBUGP(MP_LOUD, "[%p] Acquired reference for ReceiveBlock %i. RefCount: %i.\n", Adapter, BlockId, RefCount);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+NICDereferenceReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId,
+ _Out_opt_ ULONG *RefCount)
+/*++
+Routine Description:
+
+ This routine decrements the pending receive count on a adapter receive block. This count is used
+ throughout the code to determine whether there are pending operations that will use the adapter's resources such as
+ receive buffers (which would pend operations such as adapter reset, VMQ queue free, etc...).
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ BlockIndex - Receive block to flush
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG Count = InterlockedDecrement(&Adapter->ReceiveBlock[BlockId].PendingReceives);
+ DEBUGP(MP_LOUD, "[%p] Released reference for ReceiveBlock %i. RefCount: %i.\n", Adapter, BlockId, Count);
+ if(RefCount)
+ {
+ *RefCount = Count;
+ }
+}
diff --git a/network/ndis/netvmini/6x/adapter.h b/network/ndis/netvmini/6x/adapter.h
new file mode 100644
index 00000000..7162fc02
--- /dev/null
+++ b/network/ndis/netvmini/6x/adapter.h
@@ -0,0 +1,376 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Adapter.H
+
+Abstract:
+
+ This module contains structure definitons and function prototypes.
+
+Revision History:
+
+Notes:
+
+--*/
+
+
+
+
+//
+// Utility macros
+// -----------------------------------------------------------------------------
+//
+
+#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F))
+#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F))
+#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0)
+#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F))
+
+#define MP_IS_READY(_M) (((_M)->Flags & \
+ (fMP_DISCONNECTED \
+ | fMP_RESET_IN_PROGRESS \
+ | fMP_ADAPTER_HALT_IN_PROGRESS \
+ | fMP_ADAPTER_PAUSE_IN_PROGRESS \
+ | fMP_ADAPTER_PAUSED \
+ | fMP_ADAPTER_LOW_POWER \
+ )) == 0)
+
+//
+// Each receive DPC is tracked by this structure, kept in a list in the MP_ADAPTER structure.
+// It tracks the DPC object, the processor affinity of the DPC, and which MP_ADAPTER_RECEIVE_BLOCK
+// indexes the DPC should consume for receive NBLs.
+//
+typedef struct _MP_ADAPTER_RECEIVE_DPC
+{
+ LIST_ENTRY Entry;
+ //
+ // Kernel DPC used for recieve
+ //
+ KDPC Dpc;
+ USHORT ProcessorGroup;
+ ULONG ProcessorNumber;
+
+ //
+ // Tracks which receive blocks need to be recieved on this DPC.
+ //
+ BOOLEAN RecvBlock[NIC_SUPPORTED_NUM_QUEUES];
+ volatile LONG RecvBlockCount;
+
+ //
+ // Sets up the maximum amount of NBLs that can be indicated by a single
+ // receive block. This is initially NIC_MAX_RECVS_PER_INDICATE.
+ //
+ ULONG MaxNblCountPerIndicate;
+
+ //
+ // Work item used if we need to avoid DPC timeout
+ //
+ NDIS_HANDLE WorkItem;
+ volatile LONG WorkItemQueued;
+
+ //
+ // Pointer back to owner Adapter structure (accesed within work item)
+ //
+ struct _MP_ADAPTER *Adapter;
+
+} MP_ADAPTER_RECEIVE_DPC, * PMP_ADAPTER_RECEIVE_DPC;
+
+//
+// This structure is used to track pending receives on the adpater (consumed by receive DPCs).
+// One receive block maintained for each VMQ queue (if enabled), otherwise
+// a single structure is used to track receives on the adapter.
+//
+typedef struct DECLSPEC_CACHEALIGN _MP_ADAPTER_RECEIVE_BLOCK
+{
+ //
+ // List of pending RCB blocks that need to be indicated up to NDIS
+ //
+ LIST_ENTRY ReceiveList;
+ NDIS_SPIN_LOCK ReceiveListLock;
+ volatile LONG PendingReceives;
+} MP_ADAPTER_RECEIVE_BLOCK, * PMP_ADAPTER_RECEIVE_BLOCK;
+
+//
+// Each adapter managed by this driver has a MP_ADAPTER struct.
+//
+typedef struct _MP_ADAPTER
+{
+ LIST_ENTRY List;
+
+ //
+ // Keep track of various device objects.
+ //
+ PDEVICE_OBJECT Pdo;
+ PDEVICE_OBJECT Fdo;
+ PDEVICE_OBJECT NextDeviceObject;
+
+ NDIS_HANDLE AdapterHandle;
+
+
+ //
+ // Status flags
+ //
+
+#define fMP_RESET_IN_PROGRESS 0x00000001
+#define fMP_DISCONNECTED 0x00000002
+#define fMP_ADAPTER_HALT_IN_PROGRESS 0x00000004
+#define fMP_ADAPTER_PAUSE_IN_PROGRESS 0x00000010
+#define fMP_ADAPTER_PAUSED 0x00000020
+#define fMP_ADAPTER_SURPRISE_REMOVED 0x00000100
+#define fMP_ADAPTER_LOW_POWER 0x00000200
+
+ ULONG Flags;
+
+
+ UCHAR PermanentAddress[NIC_MACADDR_SIZE];
+ UCHAR CurrentAddress[NIC_MACADDR_SIZE];
+
+ //
+ // Send tracking
+ // -------------------------------------------------------------------------
+ //
+
+ // Pool of unused TCBs
+ PVOID TcbMemoryBlock;
+
+ // List of unused TCBs (sliced out of TcbMemoryBlock)
+ LIST_ENTRY FreeTcbList;
+ NDIS_SPIN_LOCK FreeTcbListLock;
+
+ // List of net buffers to send that are waiting for a free TCB
+ LIST_ENTRY SendWaitList;
+ NDIS_SPIN_LOCK SendWaitListLock;
+
+ // List of TCBs that are being read by the NIC hardware
+ LIST_ENTRY BusyTcbList;
+ NDIS_SPIN_LOCK BusyTcbListLock;
+
+ // A DPC that simulates interrupt processing for send completes
+ NDIS_HANDLE SendCompleteTimer;
+
+ //
+ // Work item used if we need to avoid DPC timeout
+ //
+ NDIS_HANDLE SendCompleteWorkItem;
+ volatile LONG SendCompleteWorkItemQueued;
+ volatile BOOLEAN SendCompleteWorkItemRunning;
+
+
+ // Number of transmit NBLs from the protocol that we still have
+ volatile LONG nBusySend;
+
+ // Spin lock to ensure only one CPU is sending at a time
+ KSPIN_LOCK SendPathSpinLock;
+
+
+ //
+ // Receive tracking
+ // -------------------------------------------------------------------------
+ //
+
+ // Pool of unused RCBs
+ PVOID RcbMemoryBlock;
+
+ // List of unused RCBs (sliced out of RcbMemoryBlock)
+ LIST_ENTRY FreeRcbList;
+ NDIS_SPIN_LOCK FreeRcbListLock;
+
+ NDIS_HANDLE RecvNblPoolHandle;
+
+ //
+ // List of receive DPCs allocated for various ProcessorAffinity values (if only
+ // one needed, then only default is present in the list
+ //
+ LIST_ENTRY RecvDpcList;
+ NDIS_SPIN_LOCK RecvDpcListLock;
+ PMP_ADAPTER_RECEIVE_DPC DefaultRecvDpc;
+
+ //
+ // Async pause and reset tracking
+ // -------------------------------------------------------------------------
+ //
+ NDIS_HANDLE AsyncBusyCheckTimer;
+ LONG AsyncBusyCheckCount;
+
+
+ //
+ // NIC configuration
+ // -------------------------------------------------------------------------
+ //
+ ULONG PacketFilter;
+ ULONG ulLookahead;
+ ULONG64 ulLinkSendSpeed;
+ ULONG64 ulLinkRecvSpeed;
+ ULONG ulMaxBusySends;
+ ULONG ulMaxBusyRecvs;
+
+ // multicast list
+ ULONG ulMCListSize;
+ UCHAR MCList[NIC_MAX_MCAST_LIST][NIC_MACADDR_SIZE];
+
+
+ //
+ // Statistics
+ // -------------------------------------------------------------------------
+ //
+
+ // Packet counts
+ ULONG64 FramesRxDirected;
+ ULONG64 FramesRxMulticast;
+ ULONG64 FramesRxBroadcast;
+ ULONG64 FramesTxDirected;
+ ULONG64 FramesTxMulticast;
+ ULONG64 FramesTxBroadcast;
+
+ // Byte counts
+ ULONG64 BytesRxDirected;
+ ULONG64 BytesRxMulticast;
+ ULONG64 BytesRxBroadcast;
+ ULONG64 BytesTxDirected;
+ ULONG64 BytesTxMulticast;
+ ULONG64 BytesTxBroadcast;
+
+ // Count of transmit errors
+ ULONG TxAbortExcessCollisions;
+ ULONG TxLateCollisions;
+ ULONG TxDmaUnderrun;
+ ULONG TxLostCRS;
+ ULONG TxOKButDeferred;
+ ULONG OneRetry;
+ ULONG MoreThanOneRetry;
+ ULONG TotalRetries;
+ ULONG TransmitFailuresOther;
+
+ // Count of receive errors
+ ULONG RxCrcErrors;
+ ULONG RxAlignmentErrors;
+ ULONG RxResourceErrors;
+ ULONG RxDmaOverrunErrors;
+ ULONG RxCdtFrames;
+ ULONG RxRuntErrors;
+
+ //
+ // Reference to the allocated root of MP_ADAPTER memory, which may not be cache aligned.
+ // When allocating, the pointer returned will be UnalignedBuffer + an offset that will make
+ // the base pointer cache aligned.
+ //
+ PVOID UnalignedAdapterBuffer;
+ ULONG UnalignedAdapterBufferSize;
+
+ //
+ // Tracks any pending NBLs for the particular receiver (either
+ // 0 for non-VMQ scenarios, or the corresponding VMQ queue). These
+ // are consumed by the receive DPCs.
+ //
+ MP_ADAPTER_RECEIVE_BLOCK ReceiveBlock[NIC_SUPPORTED_NUM_QUEUES];
+
+ //
+ // An OID request that could not be fulfulled at the time of the call. These OIDs are serialized
+ // so we will not receive new queue management OID's until this one is complete.
+ // Currently this is used only for freeing a Queue (which may still have outstanding references)
+ //
+ PNDIS_OID_REQUEST PendingRequest;
+
+ NDIS_DEVICE_POWER_STATE CurrentPowerState;
+
+#if (NDIS_SUPPORT_NDIS620)
+
+ //
+ // VMQ related data
+ //
+ MP_ADAPTER_VMQ_DATA VMQData;
+
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+
+ //
+ // NDIS QoS related data
+ //
+ MP_ADAPTER_QOS_DATA QOSData;
+
+#endif
+
+} MP_ADAPTER, *PMP_ADAPTER;
+
+#define MP_ADAPTER_FROM_CONTEXT(_ctx_) ((PMP_ADAPTER)(_ctx_))
+
+PMP_ADAPTER_RECEIVE_DPC
+NICAllocReceiveDpc(
+ _In_ PMP_ADAPTER Adapter,
+ ULONG ProcessorNumber,
+ USHORT ProcessorGroup,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+VOID
+NICReceiveDpcRemoveOwnership(
+ _In_ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+PMP_ADAPTER_RECEIVE_DPC
+NICGetDefaultReceiveDpc(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+NDIS_STATUS
+NICAllocRCBData(
+ _In_ PMP_ADAPTER Adapter,
+ ULONG NumberOfRcbs,
+ _Outptr_result_bytebuffer_(NumberOfRcbs * sizeof(RCB)) PVOID *RcbMemoryBlock,
+ _Inout_ PLIST_ENTRY FreeRcbList,
+ _Inout_ PNDIS_SPIN_LOCK FreeRcbListLock,
+ _Inout_ PNDIS_HANDLE RecvNblPoolHandle);
+
+NDIS_STATUS
+NICInitializeReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+VOID
+NICFlushReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+NDIS_STATUS
+NICReferenceReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId);
+
+VOID
+NICDereferenceReceiveBlock(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) ULONG BlockId,
+ _Out_opt_ ULONG *RefCount);
+
+
+BOOLEAN
+NICIsBusy(
+ _In_ PMP_ADAPTER Adapter);
+
+
+#define RECEIVE_BLOCK_REFERENCE_COUNT(Adapter, BlockIndex) Adapter->ReceiveBlock[BlockIndex].PendingReceives
+#define RECEIVE_BLOCK_IS_BUSY(Adapter, BlockIndex) Adapter->ReceiveBlock[BlockIndex].PendingReceives!=0
+
+// Prototypes for standard NDIS miniport entry points
+MINIPORT_INITIALIZE MPInitializeEx;
+MINIPORT_HALT MPHaltEx;
+MINIPORT_UNLOAD DriverUnload;
+MINIPORT_PAUSE MPPause;
+MINIPORT_RESTART MPRestart;
+MINIPORT_SEND_NET_BUFFER_LISTS MPSendNetBufferLists;
+MINIPORT_RETURN_NET_BUFFER_LISTS MPReturnNetBufferLists;
+MINIPORT_CANCEL_SEND MPCancelSend;
+MINIPORT_CHECK_FOR_HANG MPCheckForHangEx;
+MINIPORT_RESET MPResetEx;
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY MPDevicePnpEventNotify;
+MINIPORT_SHUTDOWN MPShutdownEx;
+MINIPORT_CANCEL_OID_REQUEST MPCancelOidRequest;
+
diff --git a/network/ndis/netvmini/6x/ctrlpath.c b/network/ndis/netvmini/6x/ctrlpath.c
new file mode 100644
index 00000000..01969705
--- /dev/null
+++ b/network/ndis/netvmini/6x/ctrlpath.c
@@ -0,0 +1,1755 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ CtrlPath.c
+
+Abstract:
+
+ This module implements the miniport's control path. It contains the main
+ miniport entrypoint for OID handling.
+
+--*/
+
+
+#include "netvmin6.h"
+#include "ctrlpath.tmh"
+
+
+static
+NDIS_STATUS
+MPMethodRequest(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisRequest);
+
+static
+NDIS_STATUS
+MPSetInformation(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+static
+NDIS_STATUS
+MPQueryInformation(
+ _In_ PMP_ADAPTER Adapter,
+ _Inout_ PNDIS_OID_REQUEST NdisQueryRequest);
+
+static
+NDIS_STATUS
+NICSetMulticastList(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+static
+NDIS_STATUS
+NICSetPacketFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ ULONG PacketFilter);
+
+#if (NDIS_SUPPORT_NDIS620)
+
+static
+NDIS_STATUS
+NICAllocateRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest);
+
+static
+NDIS_STATUS
+NICCompleteAllocationRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest);
+
+static
+NDIS_STATUS
+NICFreeRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+static
+NDIS_STATUS
+NICSetRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest);
+
+static
+NDIS_STATUS
+NICClearRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+static
+NDIS_STATUS
+NICUpdateRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+_IRQL_requires_(PASSIVE_LEVEL)
+static
+NDIS_STATUS
+NICSetQOSParameters(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest);
+
+#pragma NDIS_PAGEABLE_FUNCTION(NICFreeRxQueue)
+#pragma NDIS_PAGEABLE_FUNCTION(NICClearRxFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(NICUpdateRxQueue)
+#pragma NDIS_PAGEABLE_FUNCTION(NICAllocateRxQueue)
+#pragma NDIS_PAGEABLE_FUNCTION(NICCompleteAllocationRxQueue)
+#pragma NDIS_PAGEABLE_FUNCTION(NICSetRxFilter)
+#pragma NDIS_PAGEABLE_FUNCTION(NICSetQOSParameters)
+
+#endif
+
+static
+NDIS_STATUS
+MPSetPower(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest);
+
+static
+NDIS_STATUS
+MPSetPowerD0(
+ _In_ PMP_ADAPTER Adapter);
+
+static
+NDIS_STATUS
+MPSetPowerLow(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_DEVICE_POWER_STATE PowerState);
+
+
+#pragma NDIS_PAGEABLE_FUNCTION(MPOidRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(MPQueryInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(MPSetInformation)
+#pragma NDIS_PAGEABLE_FUNCTION(MPMethodRequest)
+#pragma NDIS_PAGEABLE_FUNCTION(MPSetPower)
+#pragma NDIS_PAGEABLE_FUNCTION(MPSetPowerD0)
+#pragma NDIS_PAGEABLE_FUNCTION(MPSetPowerLow)
+#pragma NDIS_PAGEABLE_FUNCTION(NICSetMulticastList)
+#pragma NDIS_PAGEABLE_FUNCTION(NICSetPacketFilter)
+
+
+NDIS_STATUS
+MPOidRequest(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNDIS_OID_REQUEST NdisRequest)
+/*++
+
+Routine Description:
+
+ Entry point called by NDIS to get or set the value of a specified OID.
+
+Arguments:
+
+ MiniportAdapterContext - Our adapter handle
+ NdisRequest - The OID request to handle
+
+Return Value:
+
+ Return code from the NdisRequest below.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ PAGED_CODE();
+
+ DEBUGP(MP_LOUD, "[%p] ---> MPOidRequest\n", Adapter);
+
+
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestMethod:
+ Status = MPMethodRequest(Adapter, NdisRequest);
+ break;
+
+ case NdisRequestSetInformation:
+ Status = MPSetInformation(Adapter, NdisRequest);
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ Status = MPQueryInformation(Adapter, NdisRequest);
+ break;
+
+ default:
+ //
+ // The entry point may by used by other requests
+ //
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+
+ DEBUGP(MP_LOUD, "[%p] <--- MPOidRequest Status = 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+VOID
+MPCancelOidRequest(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PVOID RequestId)
+/*++
+
+Routine Description:
+
+ Entry point called by NDIS to abort an asynchronous OID request.
+
+Arguments:
+
+ MiniportAdapterContext - Our adapter handle
+ RequestId - An identifier that corresponds to the RequestId
+ field of the NDIS_OID_REQUEST
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+
+ DEBUGP(MP_LOUD, "[%p] ---> MPCancelOidRequest", Adapter);
+ UNREFERENCED_PARAMETER(Adapter);
+ UNREFERENCED_PARAMETER(RequestId);
+
+
+ //
+ // This miniport sample does not pend any OID requests, so we don't have
+ // to worry about cancelling them.
+ //
+
+ DEBUGP(MP_LOUD, "[%p] <--- MPCancelOidRequest", Adapter);
+}
+
+
+
+NDIS_STATUS
+MPQueryInformation(
+ _In_ PMP_ADAPTER Adapter,
+ _Inout_ PNDIS_OID_REQUEST NdisQueryRequest)
+/*++
+
+Routine Description:
+
+ Helper function to perform a query OID request
+
+Arguments:
+
+ Adapter -
+ NdisQueryRequest - The OID that is being queried
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _QUERY *Query = &NdisQueryRequest->DATA.QUERY_INFORMATION;
+
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ UCHAR VendorDesc[] = NIC_VENDOR_DESC;
+ NDIS_MEDIUM Medium = NIC_MEDIUM_TYPE;
+ ULONG ulInfo;
+ USHORT usInfo;
+ ULONG64 ulInfo64;
+
+ // Default to returning the ULONG value
+ PVOID pInfo=NULL;
+ ULONG ulInfoLen = sizeof(ulInfo);
+
+ PAGED_CODE();
+
+ DEBUGP(MP_LOUD, "[%p] ---> MPQueryInformation ", Adapter);
+ DbgPrintOidName(Query->Oid);
+
+
+ switch(Query->Oid)
+ {
+ case OID_GEN_HARDWARE_STATUS:
+ //
+ // Specify the current hardware status of the underlying NIC as
+ // one of the following NDIS_HARDWARE_STATUS-type values.
+ //
+ pInfo = (PVOID) &HardwareStatus;
+ ulInfoLen = sizeof(NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ //
+ // Specify the maximum total packet length, in bytes, the NIC
+ // supports including the header. A protocol driver might use
+ // this returned length as a gauge to determine the maximum
+ // size packet that a NIC driver could forward to the
+ // protocol driver. The miniport driver must never indicate
+ // up to the bound protocol driver packets received over the
+ // network that are longer than the packet size specified by
+ // OID_GEN_MAXIMUM_TOTAL_SIZE.
+ //
+
+ __fallthrough;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ //
+ // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum
+ // number of bytes that a single net packet occupies in the
+ // transmit buffer space of the NIC. For example, a NIC that
+ // has a transmit space divided into 256-byte pieces would have
+ // a transmit block size of 256 bytes. To calculate the total
+ // transmit buffer space on such a NIC, its driver multiplies
+ // the number of transmit buffers on the NIC by its transmit
+ // block size. In our case, the transmit block size is
+ // identical to its maximum packet size.
+
+ __fallthrough;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ //
+ // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of
+ // storage, in bytes, that a single packet occupies in the receive
+ // buffer space of the NIC.
+ //
+
+ ulInfo = (ULONG) HW_MAX_FRAME_SIZE;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ //
+ // Specify the amount of memory, in bytes, on the NIC that
+ // is available for buffering transmit data. A protocol can
+ // use this OID as a guide for sizing the amount of transmit
+ // data per send.
+ //
+
+ ulInfo = HW_MAX_FRAME_SIZE * Adapter->ulMaxBusySends;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ //
+ // Specify the amount of memory on the NIC that is available
+ // for buffering receive data. A protocol driver can use this
+ // OID as a guide for advertising its receive window after it
+ // establishes sessions with remote nodes.
+ //
+
+ ulInfo = HW_MAX_FRAME_SIZE * Adapter->ulMaxBusyRecvs;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ //
+ // Return an array of media that are supported by the miniport.
+ // This miniport only supports one medium (Ethernet), so the OID
+ // returns identical results to OID_GEN_MEDIA_IN_USE.
+ //
+
+ __fallthrough;
+
+ case OID_GEN_MEDIA_IN_USE:
+ //
+ // Return an array of media that are currently in use by the
+ // miniport. This array should be a subset of the array returned
+ // by OID_GEN_MEDIA_SUPPORTED.
+ //
+ pInfo = &Medium;
+ ulInfoLen = sizeof(Medium);
+ break;
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ ulInfo = NIC_MAX_BUSY_SENDS;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ ulInfo = (ULONG)
+ (Adapter->TxAbortExcessCollisions +
+ Adapter->TxDmaUnderrun +
+ Adapter->TxLostCRS +
+ Adapter->TxLateCollisions+
+ Adapter->TransmitFailuresOther);
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ ulInfo = (ULONG)
+ (Adapter->RxCrcErrors +
+ Adapter->RxAlignmentErrors +
+ Adapter->RxDmaOverrunErrors +
+ Adapter->RxRuntErrors);
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_DISCARDS:
+ ulInfo = (ULONG)Adapter->RxResourceErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ ulInfo = (ULONG)
+ Adapter->RxResourceErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ //
+ // Specify a three-byte IEEE-registered vendor code, followed
+ // by a single byte that the vendor assigns to identify a
+ // particular NIC. The IEEE code uniquely identifies the vendor
+ // and is the same as the three bytes appearing at the beginning
+ // of the NIC hardware address. Vendors without an IEEE-registered
+ // code should use the value 0xFFFFFF.
+ //
+
+ ulInfo = NIC_VENDOR_ID;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ //
+ // Specify a zero-terminated string describing the NIC vendor.
+ //
+ pInfo = VendorDesc;
+ ulInfoLen = sizeof(VendorDesc);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ //
+ // Specify the vendor-assigned version number of the NIC driver.
+ // The low-order half of the return value specifies the minor
+ // version; the high-order half specifies the major version.
+ //
+
+ ulInfo = NIC_VENDOR_DRIVER_VERSION;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ //
+ // Specify the NDIS version in use by the NIC driver. The high
+ // byte is the major version number; the low byte is the minor
+ // version number.
+ //
+ usInfo = (USHORT) (MP_NDIS_MAJOR_VERSION<<8) + MP_NDIS_MINOR_VERSION;
+ pInfo = (PVOID) &usInfo;
+ ulInfoLen = sizeof(USHORT);
+ break;
+
+#if (NDIS_SUPPORT_NDIS61 && !NDIS_SUPPORT_NDIS620)
+ case OID_PNP_CAPABILITIES:
+ //
+ // This OID is obsolete for NDIS 6.20 drivers
+ //
+ // Return the wake-up capabilities of its NIC. If you return
+ // NDIS_STATUS_NOT_SUPPORTED, NDIS considers the miniport driver
+ // to be not Power management aware and doesn't send any power
+ // or wake-up related queries such as
+ // OID_PNP_SET_POWER, OID_PNP_QUERY_POWER,
+ // OID_PNP_ADD_WAKE_UP_PATTERN, OID_PNP_REMOVE_WAKE_UP_PATTERN,
+ // OID_PNP_ENABLE_WAKE_UP.
+ //
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+#endif
+ //
+ // Following 4 OIDs are for querying Ethernet Operational
+ // Characteristics.
+ //
+ case OID_802_3_PERMANENT_ADDRESS:
+ //
+ // Return the MAC address of the NIC burnt in the hardware.
+ //
+ pInfo = Adapter->PermanentAddress;
+ ulInfoLen = NIC_MACADDR_SIZE;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ //
+ // Return the MAC address the NIC is currently programmed to
+ // use. Note that this address could be different from the
+ // permananent address as the user can override using
+ // registry. Read NdisReadNetworkAddress doc for more info.
+ //
+ pInfo = Adapter->CurrentAddress;
+ ulInfoLen = NIC_MACADDR_SIZE;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ //
+ // The maximum number of multicast addresses the NIC driver
+ // can manage. This list is global for all protocols bound
+ // to (or above) the NIC. Consequently, a protocol can receive
+ // NDIS_STATUS_MULTICAST_FULL from the NIC driver when
+ // attempting to set the multicast address list, even if
+ // the number of elements in the given list is less than
+ // the number originally returned for this query.
+ //
+
+ ulInfo = NIC_MAX_MCAST_LIST;
+ pInfo = &ulInfo;
+ break;
+
+ //
+ // Following list consists of both general and Ethernet
+ // specific statistical OIDs.
+ //
+
+ case OID_GEN_XMIT_OK:
+ ulInfo64 = Adapter->FramesTxBroadcast
+ + Adapter->FramesTxMulticast
+ + Adapter->FramesTxDirected;
+ pInfo = &ulInfo64;
+ if (Query->InformationBufferLength >= sizeof(ULONG64) ||
+ Query->InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+ // We should always report that only 8 bytes are required to keep ndistest happy
+ Query->BytesNeeded = sizeof(ULONG64);
+ break;
+
+ case OID_GEN_RCV_OK:
+ ulInfo64 = Adapter->FramesRxBroadcast
+ + Adapter->FramesRxMulticast
+ + Adapter->FramesRxDirected;
+ pInfo = &ulInfo64;
+ if (Query->InformationBufferLength >= sizeof(ULONG64) ||
+ Query->InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+ // We should always report that only 8 bytes are required to keep ndistest happy
+ Query->BytesNeeded = sizeof(ULONG64);
+ break;
+
+ case OID_GEN_STATISTICS:
+
+ if (Query->InformationBufferLength < sizeof(NDIS_STATISTICS_INFO))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ Query->BytesNeeded = sizeof(NDIS_STATISTICS_INFO);
+ break;
+ }
+ else
+ {
+ PNDIS_STATISTICS_INFO Statistics = (PNDIS_STATISTICS_INFO)Query->InformationBuffer;
+
+ {C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);}
+ Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
+
+ Statistics->SupportedStatistics = NIC_SUPPORTED_STATISTICS;
+
+ /* Bytes in */
+ Statistics->ifHCInOctets =
+ Adapter->BytesRxDirected +
+ Adapter->BytesRxMulticast +
+ Adapter->BytesRxBroadcast;
+
+ Statistics->ifHCInUcastOctets =
+ Adapter->BytesRxDirected;
+
+ Statistics->ifHCInMulticastOctets =
+ Adapter->BytesRxMulticast;
+
+ Statistics->ifHCInBroadcastOctets =
+ Adapter->BytesRxBroadcast;
+
+ /* Packets in */
+ Statistics->ifHCInUcastPkts =
+ Adapter->FramesRxDirected;
+
+ Statistics->ifHCInMulticastPkts =
+ Adapter->FramesRxMulticast;
+
+ Statistics->ifHCInBroadcastPkts =
+ Adapter->FramesRxBroadcast;
+
+ /* Errors in */
+ Statistics->ifInErrors =
+ Adapter->RxCrcErrors +
+ Adapter->RxAlignmentErrors +
+ Adapter->RxDmaOverrunErrors +
+ Adapter->RxRuntErrors;
+
+ Statistics->ifInDiscards =
+ Adapter->RxResourceErrors;
+
+
+ /* Bytes out */
+ Statistics->ifHCOutOctets =
+ Adapter->BytesTxDirected +
+ Adapter->BytesTxMulticast +
+ Adapter->BytesTxBroadcast;
+
+ Statistics->ifHCOutUcastOctets =
+ Adapter->BytesTxDirected;
+
+ Statistics->ifHCOutMulticastOctets =
+ Adapter->BytesTxMulticast;
+
+ Statistics->ifHCOutBroadcastOctets =
+ Adapter->BytesTxBroadcast;
+
+ /* Packets out */
+ Statistics->ifHCOutUcastPkts =
+ Adapter->FramesTxDirected;
+
+ Statistics->ifHCOutMulticastPkts =
+ Adapter->FramesTxMulticast;
+
+ Statistics->ifHCOutBroadcastPkts =
+ Adapter->FramesTxBroadcast;
+
+ /* Errors out */
+ Statistics->ifOutErrors =
+ Adapter->TxAbortExcessCollisions +
+ Adapter->TxDmaUnderrun +
+ Adapter->TxLostCRS +
+ Adapter->TxLateCollisions+
+ Adapter->TransmitFailuresOther;
+
+ Statistics->ifOutDiscards =
+ 0ULL;
+
+ ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ }
+
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+
+ ulInfo = Adapter->nBusySend;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ ulInfo = Adapter->RxAlignmentErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ ulInfo = Adapter->OneRetry;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ ulInfo = Adapter->MoreThanOneRetry;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+
+ ulInfo = Adapter->TxOKButDeferred;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+
+ ulInfo = Adapter->TxAbortExcessCollisions;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+
+ ulInfo = Adapter->RxDmaOverrunErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+
+ ulInfo = Adapter->TxDmaUnderrun;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+
+ ulInfo = Adapter->TxLostCRS;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+
+ ulInfo = Adapter->TxLostCRS;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+
+ ulInfo = Adapter->TxLateCollisions;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_INTERRUPT_MODERATION:
+ {
+ PNDIS_INTERRUPT_MODERATION_PARAMETERS Moderation = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)Query->InformationBuffer;
+ Moderation->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ Moderation->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ Moderation->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ Moderation->Flags = 0;
+ Moderation->InterruptModeration = NdisInterruptModerationNotSupported;
+ ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ }
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ // simply succeed this.
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ASSERT(ulInfoLen > 0);
+
+ if (ulInfoLen <= Query->InformationBufferLength)
+ {
+ if(pInfo)
+ {
+ // Copy result into InformationBuffer
+ NdisMoveMemory(Query->InformationBuffer, pInfo, ulInfoLen);
+ }
+ Query->BytesWritten = ulInfoLen;
+ }
+ else
+ {
+ // too short
+ Query->BytesNeeded = ulInfoLen;
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ }
+
+
+ DEBUGP(MP_LOUD, "[%p] <--- MPQueryInformation Status = 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+NDIS_STATUS
+MPSetInformation(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+
+Routine Description:
+
+ Helper function to perform a set OID request
+
+Arguments:
+
+ Adapter -
+ NdisSetRequest - The OID to set
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_LOUD, "[%p] ---> MPSetInformation ", Adapter);
+ DbgPrintOidName(Set->Oid);
+
+
+ switch(Set->Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ //
+ // Set the multicast address list on the NIC for packet reception.
+ // The NIC driver can set a limit on the number of multicast
+ // addresses bound protocol drivers can enable simultaneously.
+ // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver
+ // exceeds this limit or if it specifies an invalid multicast
+ // address.
+ //
+ Status = NICSetMulticastList(Adapter, NdisSetRequest);
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ //
+ // Program the hardware to indicate the packets
+ // of certain filter types.
+ //
+ if(Set->InformationBufferLength != sizeof(ULONG))
+ {
+ Set->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ Set->BytesRead = Set->InformationBufferLength;
+
+ Status = NICSetPacketFilter(
+ Adapter,
+ *((PULONG)Set->InformationBuffer));
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ //
+ // A protocol driver can set a suggested value for the number
+ // of bytes to be used in its binding; however, the underlying
+ // NIC driver is never required to limit its indications to
+ // the value set.
+ //
+ if (Set->InformationBufferLength != sizeof(ULONG))
+ {
+ Set->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ Adapter->ulLookahead = *(PULONG)Set->InformationBuffer;
+
+ Set->BytesRead = sizeof(ULONG);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+#if (NDIS_SUPPORT_NDIS620)
+
+ case OID_RECEIVE_FILTER_FREE_QUEUE:
+ //
+ // Free the requested receive queue.
+ //
+ Status = NICFreeRxQueue(
+ Adapter,
+ NdisSetRequest);
+ break;
+
+ case OID_RECEIVE_FILTER_CLEAR_FILTER:
+ //
+ // Remove the requested filter on the requested receive queue.
+ //
+ Status = NICClearRxFilter(
+ Adapter,
+ NdisSetRequest);
+ break;
+
+ case OID_RECEIVE_FILTER_QUEUE_PARAMETERS:
+ //
+ // Update the queue information.
+ //
+ Status = NICUpdateRxQueue(
+ Adapter,
+ NdisSetRequest);
+ break;
+#endif
+
+ case OID_PNP_SET_POWER:
+ //
+ // Update power state
+ //
+ Status = MPSetPower(
+ Adapter,
+ NdisSetRequest);
+ break;
+
+#if (NDIS_SUPPORT_NDIS620)
+ case OID_PM_ADD_WOL_PATTERN:
+ case OID_PM_REMOVE_WOL_PATTERN:
+ case OID_PM_ADD_PROTOCOL_OFFLOAD:
+ case OID_PM_REMOVE_PROTOCOL_OFFLOAD:
+ case OID_PM_PARAMETERS:
+
+#else if (NDIS_SUPPORT_NDIS61)
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ case OID_PNP_ENABLE_WAKE_UP:
+#endif
+ ASSERT(!"NIC does not support wake on LAN OIDs");
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ Set->BytesRead = Set->InformationBufferLength;
+ }
+
+
+ DEBUGP(MP_LOUD, "[%p] <--- MPSetInformation Status = 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+MPMethodRequest(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisRequest)
+/*++
+Routine Description:
+
+ Helper function to perform a WMI OID request
+
+Arguments:
+
+ Adapter -
+ NdisRequest - THe WMI OID request
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_OID Oid = NdisRequest->DATA.METHOD_INFORMATION.Oid;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(Adapter);
+ UNREFERENCED_PARAMETER(NdisRequest);
+
+ DEBUGP(MP_LOUD, "[%p] ---> MPMethodRequest ", Adapter);
+ DbgPrintOidName(Oid);
+
+
+ switch (Oid)
+ {
+
+#if (NDIS_SUPPORT_NDIS620)
+ case OID_RECEIVE_FILTER_ALLOCATE_QUEUE:
+ //
+ // Allocate the requested receive queue.
+ //
+ Status = NICAllocateRxQueue(
+ Adapter,
+ NdisRequest);
+
+ break;
+
+ case OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE:
+ //
+ // Complete any remaining allocation for receive queues.
+ //
+ Status = NICCompleteAllocationRxQueue(
+ Adapter,
+ NdisRequest);
+
+ break;
+
+ case OID_RECEIVE_FILTER_SET_FILTER:
+ //
+ // Add a filter to the requested queue.
+ //
+ Status = NICSetRxFilter(
+ Adapter,
+ NdisRequest);
+ break;
+
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+ case OID_QOS_PARAMETERS:
+ //
+ // Set NDIS QoS configuration parameters.
+ //
+ Status = NICSetQOSParameters(
+ Adapter,
+ NdisRequest);
+ break;
+
+#endif
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+
+ DEBUGP(MP_LOUD, "[%p] <--- MPMethodRequest Status = 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+
+
+NDIS_STATUS
+NICSetPacketFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ ULONG PacketFilter)
+/*++
+Routine Description:
+
+ This routine will set up the adapter so that it accepts packets
+ that match the specified packet filter.
+
+Arguments:
+
+ Adapter - pointer to adapter block
+ PacketFilter - the new packet filter
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_NOT_SUPPORTED
+
+--*/
+
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICSetPacketFilter\n", Adapter);
+
+
+ // any bits not supported?
+ if (PacketFilter & ~(NIC_SUPPORTED_FILTERS))
+ {
+ DEBUGP(MP_WARNING, "[%p] Unsupported packet filter: 0x%08x\n", Adapter, PacketFilter);
+ return NDIS_STATUS_NOT_SUPPORTED;
+ }
+
+ // any filtering changes?
+ if (PacketFilter != Adapter->PacketFilter)
+ {
+ //
+ // Change the filtering modes on hardware
+ //
+
+
+ // Save the new packet filter value
+ Adapter->PacketFilter = PacketFilter;
+ }
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICSetPacketFilter Status = 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NICSetMulticastList(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+Routine Description:
+
+ This routine will set up the adapter for a specified multicast
+ address list.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID request with the new multicast list
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+
+#if DBG
+ ULONG index;
+#endif
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICSetMulticastList\n", Adapter);
+
+
+ //
+ // Initialize.
+ //
+ Set->BytesNeeded = NIC_MACADDR_SIZE;
+ Set->BytesRead = Set->InformationBufferLength;
+
+ do
+ {
+ if (Set->InformationBufferLength % NIC_MACADDR_SIZE)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (Set->InformationBufferLength > (NIC_MAX_MCAST_LIST * NIC_MACADDR_SIZE))
+ {
+ Status = NDIS_STATUS_MULTICAST_FULL;
+ Set->BytesNeeded = NIC_MAX_MCAST_LIST * NIC_MACADDR_SIZE;
+ break;
+ }
+
+ //
+ // Protect the list update with a lock if it can be updated by
+ // another thread simultaneously.
+ //
+
+ NdisZeroMemory(Adapter->MCList,
+ NIC_MAX_MCAST_LIST * NIC_MACADDR_SIZE);
+
+ NdisMoveMemory(Adapter->MCList,
+ Set->InformationBuffer,
+ Set->InformationBufferLength);
+
+ Adapter->ulMCListSize = Set->InformationBufferLength / NIC_MACADDR_SIZE;
+
+#if DBG
+ // display the multicast list
+ for(index = 0; index < Adapter->ulMCListSize; index++)
+ {
+ DEBUGP(MP_LOUD, "[%p] MC(%d) = ", Adapter, index);
+ DbgPrintAddress(Adapter->MCList[index]);
+ }
+#endif
+ }
+ while (FALSE);
+
+
+ //
+ // Program the hardware to add suport for these muticast addresses
+ //
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICSetMulticastList Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+#if (NDIS_SUPPORT_NDIS620)
+
+#define VERIFY_OID_SET(_Request, _MinRevision, _MinLength)\
+ _Request->DATA.SET_INFORMATION.BytesNeeded = _MinLength;\
+ if(_Request->Header.Revision < _MinRevision)\
+ { \
+ Status = NDIS_STATUS_NOT_SUPPORTED;\
+ break;\
+ }\
+ if(_Request->DATA.SET_INFORMATION.InformationBufferLength < _MinLength)\
+ {\
+ Status = NDIS_STATUS_INVALID_LENGTH;\
+ break;\
+ }\
+
+#define VERIFY_OID_METHOD(_Request, _MinRevision, _MinLength)\
+ _Request->DATA.METHOD_INFORMATION.BytesNeeded = _MinLength;\
+ if(_Request->Header.Revision < _MinRevision)\
+ { \
+ Status = NDIS_STATUS_NOT_SUPPORTED;\
+ break;\
+ }\
+ if(_Request->DATA.METHOD_INFORMATION.InputBufferLength < _MinLength)\
+ {\
+ Status = NDIS_STATUS_INVALID_LENGTH;\
+ break;\
+ }\
+
+
+NDIS_STATUS
+NICAllocateRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest)
+/*++
+Routine Description:
+
+ This routine will allocate a receive queue according to the passed in allocation request. It verifies that the request
+ is well formed, then passes the request to underlying queue management code.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _METHOD *Method = &NdisMethodRequest->DATA.METHOD_INFORMATION;
+ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams = (PNDIS_RECEIVE_QUEUE_PARAMETERS)Method->InformationBuffer;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICAllocateRxQueue\n", Adapter);
+
+ do
+ {
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_METHOD(NdisMethodRequest,
+ NDIS_RECEIVE_QUEUE_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_QUEUE_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Method->BytesRead = NDIS_SIZEOF_RECEIVE_QUEUE_PARAMETERS_REVISION_1;
+
+ //
+ // Should not ask to allocate default queue, or non VMQ type
+ //
+ if(QueueParams->QueueId==NDIS_DEFAULT_RECEIVE_QUEUE_ID
+ ||
+ QueueParams->QueueType != NdisReceiveQueueTypeVMQueue)
+ {
+ DEBUGP(MP_ERROR, "[%p] Unsupported QueueId (%i) or QueueType (%i) for allocation.\n", Adapter, QueueParams->QueueId, QueueParams->QueueType);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Ready to allocate
+ //
+ Status = AllocateRxQueue(Adapter, QueueParams);
+
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICAllocateRxQueuee Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+NICCompleteAllocationRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest)
+/*++
+Routine Description:
+
+ This routine will complete any remaining queue allocation, including shared memory. It verifies that the request
+ is well formed, then passes the request to underlying queue management code.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _METHOD *Method = &NdisMethodRequest->DATA.METHOD_INFORMATION;
+ PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY CompleteArray = (PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY)Method->InformationBuffer;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICCompleteAllocationRxQueue\n", Adapter);
+
+ do
+ {
+
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_METHOD(NdisMethodRequest,
+ NDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Method->BytesRead = NDIS_SIZEOF_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY_REVISION_1+
+ (CompleteArray->NumElements * CompleteArray->ElementSize);
+
+ //
+ // Ready to complete allocation
+ //
+ Status = CompleteAllocationRxQueue(Adapter, CompleteArray);
+
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICCompleteAllocationRxQueue Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+
+}
+
+NDIS_STATUS
+NICFreeRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+Routine Description:
+
+ This routine will handle the passed in queue free request. It verifies that the request
+ is well formed, then passes the request to underlying queue management code.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+ PNDIS_RECEIVE_QUEUE_FREE_PARAMETERS QueueFreeParams = (PNDIS_RECEIVE_QUEUE_FREE_PARAMETERS)Set->InformationBuffer;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICFreeRxQueue\n", Adapter);
+
+ do
+ {
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_SET(NdisSetRequest,
+ NDIS_RECEIVE_QUEUE_FREE_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_QUEUE_FREE_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Set->BytesRead = NDIS_SIZEOF_RECEIVE_QUEUE_FREE_PARAMETERS_REVISION_1;
+
+ //
+ // Default queue cannot be freed
+ //
+ if(QueueFreeParams->QueueId==NDIS_DEFAULT_RECEIVE_QUEUE_ID)
+ {
+ DEBUGP(MP_ERROR, "[%p] Received request to free default queue.\n", Adapter);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Ready to attempt a free.
+ //
+ Status = FreeRxQueue(Adapter, QueueFreeParams, NdisSetRequest);
+
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICFreeRxQueuee Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+NICSetRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest)
+/*++
+Routine Description:
+
+ This routine will handle the passed filter set request. It verifies that the request
+ is well formed, then passes the request to underlying filter management code.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _METHOD *Method = &NdisMethodRequest->DATA.METHOD_INFORMATION;
+ PNDIS_RECEIVE_FILTER_PARAMETERS FilterParams = (PNDIS_RECEIVE_FILTER_PARAMETERS)Method->InformationBuffer;
+
+ PAGED_CODE();
+
+ do
+ {
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_METHOD(NdisMethodRequest,
+ NDIS_RECEIVE_FILTER_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_FILTER_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Method->BytesRead = NDIS_SIZEOF_RECEIVE_FILTER_PARAMETERS_REVISION_1;
+
+ //
+ // Ready to set Filter
+ //
+ Status = SetRxFilter(Adapter, FilterParams);
+
+ }while(FALSE);
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+NICClearRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+Routine Description:
+
+ This routine will handle the passed filter clear request. It verifies that the request
+ is well formed, then passes the request to underlying filter management code.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+ PNDIS_RECEIVE_FILTER_CLEAR_PARAMETERS FilterParams = (PNDIS_RECEIVE_FILTER_CLEAR_PARAMETERS)Set->InformationBuffer;
+
+ PAGED_CODE();
+
+ do
+ {
+
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_SET(NdisSetRequest,
+ NDIS_RECEIVE_FILTER_CLEAR_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_FILTER_CLEAR_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Set->BytesRead = NDIS_SIZEOF_RECEIVE_FILTER_CLEAR_PARAMETERS_REVISION_1;
+
+ //
+ // Ready to clear the filter
+ //
+ Status = ClearRxFilter(Adapter, FilterParams);
+
+ }while(FALSE);
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+NICUpdateRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+ PNDIS_RECEIVE_QUEUE_PARAMETERS FilterParams = (PNDIS_RECEIVE_QUEUE_PARAMETERS)Set->InformationBuffer;
+
+ PAGED_CODE();
+
+ do
+ {
+
+ //
+ // Verify that the request matches our requirements
+ //
+ VERIFY_OID_SET(NdisSetRequest,
+ NDIS_RECEIVE_QUEUE_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_RECEIVE_QUEUE_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read
+ //
+ Set->BytesRead = NDIS_SIZEOF_RECEIVE_FILTER_CLEAR_PARAMETERS_REVISION_1;
+
+ //
+ // Ready to clear the filter
+ //
+ Status = UpdateRxQueue(Adapter, FilterParams);
+
+ } while(FALSE);
+
+ return Status;
+
+}
+
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+NICSetQOSParameters(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisMethodRequest)
+/*++
+Routine Description:
+
+ This routine will build a classification table according to the request. It verifies that
+ the request is well formed, then passes the request to the underlying classification
+ management code. On the other hand, hardware-oriented parameters such as PFC and ETS are
+ validated but not enforceable in a software implementation.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _METHOD *Method = &NdisMethodRequest->DATA.METHOD_INFORMATION;
+ PNDIS_QOS_PARAMETERS Params = (PNDIS_QOS_PARAMETERS)Method->InformationBuffer;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICSetQOSParameters\n", Adapter);
+
+ do
+ {
+ //
+ // Verify that the request matches our requirements.
+ //
+ VERIFY_OID_METHOD(NdisMethodRequest,
+ NDIS_QOS_PARAMETERS_REVISION_1,
+ NDIS_SIZEOF_QOS_PARAMETERS_REVISION_1);
+
+ //
+ // Request is well formed, set bytes read.
+ //
+ Method->BytesRead = NDIS_SIZEOF_QOS_PARAMETERS_REVISION_1 +
+ Params->NumClassificationElements * Params->ClassificationElementSize;
+
+ Status = SetQOSParameters(Adapter, Params);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Set bytes written for in-place write, basically same as bytes read.
+ //
+ Method->BytesWritten = Method->BytesRead;
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICSetQOSParameters Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+#endif
+
+static
+NDIS_STATUS
+MPSetPower(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+Routine Description:
+
+ This routine handles OID_PNP_SET_POWER request.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ NdisSetRequest - The OID data for the request
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _SET *Set = &NdisSetRequest->DATA.SET_INFORMATION;
+ NDIS_DEVICE_POWER_STATE PowerState;
+
+ PAGED_CODE();
+
+ if (Set->InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ return NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)Set->InformationBuffer;
+ Set->BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+
+ if(PowerState < NdisDeviceStateD0 ||
+ PowerState > NdisDeviceStateD3)
+ {
+ return NDIS_STATUS_INVALID_DATA;
+ }
+
+
+ if (PowerState == NdisDeviceStateD0)
+ {
+ Status = MPSetPowerD0(Adapter);
+ }
+ else
+ {
+ Status = MPSetPowerLow(Adapter, PowerState);
+ }
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+MPSetPowerD0(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+Routine Description:
+
+ NIC power has been restored to the working power state (D0).
+ Prepare the NIC for normal operation:
+ - Restore hardware context (packet filters, multicast addresses, MAC address, etc.)
+ - Enable interrupts and the NIC's DMA engine.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ Adapter->CurrentPowerState = NdisDeviceStateD0;
+ MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_LOW_POWER);
+
+ NICStartTheDatapath(Adapter);
+
+ return Status;
+}
+
+static
+NDIS_STATUS
+MPSetPowerLow(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_DEVICE_POWER_STATE PowerState)
+/*++
+Routine Description:
+
+ The NIC is about to be transitioned to a low power state.
+ Prepare the NIC for the sleeping state:
+ - Disable interrupts and the NIC's DMA engine, cancel timers.
+ - Save any hardware context that the NIC cannot preserve in
+ a sleeping state (packet filters, multicast addresses,
+ the current MAC address, etc.)
+ A miniport driver cannot access the NIC hardware after
+ the NIC has been set to the D3 state by the bus driver.
+
+ Miniport drivers NDIS v6.30 and above
+ Do NOT wait for NDIS to return the ownership of all
+ NBLs from outstanding receive indications
+ Retain ownership of all the receive descriptors and
+ packet buffers previously owned by the hardware.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ PowerState - New power state
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LONG nSendWaitCount = 0;
+
+ PAGED_CODE();
+
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_LOW_POWER);
+ Adapter->CurrentPowerState = PowerState;
+
+
+#if (NDIS_SUPPORT_NDIS630)
+
+ //
+ // Miniport drivers NDIS v6.30 and above are not
+ // necessarily paused prior the low power transition
+ //
+
+ //
+ // Prevent future sends and receives on the data path
+ //
+ NICStopTheDatapath(Adapter);
+
+ //
+ // Wait for outstanding sends
+ // Do NOT wait for outstanding receives
+ //
+ while(Adapter->nBusySend)
+ {
+ if (++nSendWaitCount % 100)
+ {
+ DEBUGP(MP_ERROR, "[%p] MPSetPowerLow timed out!\n", Adapter);
+ ASSERT(FALSE);
+ }
+
+ DEBUGP(MP_INFO, "[%p] MPSetPowerLow - waiting ...\n", Adapter);
+ NdisMSleep(1000);
+ }
+
+#else
+
+ UNREFERENCED_PARAMETER(nSendWaitCount);
+
+ //
+ // Miniport drivers NDIS v6.20 and below are
+ // paused prior the low power transition
+ //
+ ASSERT(MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSED));
+ ASSERT(!NICIsBusy(Adapter));
+
+#endif
+
+ return Status;
+}
diff --git a/network/ndis/netvmini/6x/ctrlpath.h b/network/ndis/netvmini/6x/ctrlpath.h
new file mode 100644
index 00000000..99fd791e
--- /dev/null
+++ b/network/ndis/netvmini/6x/ctrlpath.h
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ CtrlPath.H
+
+Abstract:
+
+ This module declares functions for the miniport's control path.
+
+--*/
+
+#ifndef _CTRLPATH_H
+#define _CTRLPATH_H
+
+
+MINIPORT_OID_REQUEST MPOidRequest;
+
+
+#endif // _CTRLPATH_H
+
diff --git a/network/ndis/netvmini/6x/datapath.c b/network/ndis/netvmini/6x/datapath.c
new file mode 100644
index 00000000..1c18094c
--- /dev/null
+++ b/network/ndis/netvmini/6x/datapath.c
@@ -0,0 +1,1740 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ DataPath.C
+
+Abstract:
+
+ This module implements the data path of the netvmini miniport.
+
+ In order to excercise the data path of this driver,
+ you should install more than one instance of the miniport. If there
+ is only one instance installed, the driver throws the send packet on
+ the floor and completes the send successfully. If there are more
+ instances present, it indicates the incoming send packet to the other
+ instances. For example, if there 3 instances: A, B, & C installed.
+ Frames sent on instance A would be received on B & C; frames
+ sent on B would be received on C, & A; and frames sent on C
+ would be received on A & B.
+
+ This sample miniport goes to some extra lengths so that the data path's
+ design resembles the design of a real hardware miniport's data path. For
+ example, this sample has both send and receive queues, even though all the
+ miniports on the simulated network are on the same computer (and thus could
+ take some shortcuts when passing data buffers back and forth).
+
+
+
+--*/
+
+#include "netvmin6.h"
+#include "datapath.tmh"
+
+static
+VOID
+TXQueueNetBufferForSend(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER NetBuffer);
+
+static
+VOID
+TXTransmitQueuedSends(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ BOOLEAN fAtDispatch);
+
+static
+VOID
+TXScheduleTheSendComplete(
+ _In_ PMP_ADAPTER Adapter);
+
+static
+VOID
+RXQueueFrameOnAdapter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame);
+
+static
+VOID
+RXScheduleTheReceiveIndication(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PRCB Rcb);
+
+_Must_inspect_result_
+static
+PTCB
+TXGetNextTcbToSend(
+ _In_ PMP_ADAPTER Adapter);
+
+
+VOID
+RXRequeueRcbToReceive(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PRCB Rcb);
+
+VOID
+RXReceiveIndicate(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc,
+ BOOLEAN AtDpc);
+
+NDIS_IO_WORKITEM_FUNCTION RXReceiveIndicateWorkItem;
+NDIS_IO_WORKITEM_FUNCTION TXSendCompleteWorkItem;
+
+#pragma NDIS_PAGEABLE_FUNCTION(NICStartTheDatapath)
+#pragma NDIS_PAGEABLE_FUNCTION(NICStopTheDatapath)
+
+VOID
+MPSendNetBufferLists(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNET_BUFFER_LIST NetBufferLists,
+ _In_ NDIS_PORT_NUMBER PortNumber,
+ _In_ ULONG SendFlags)
+/*++
+
+Routine Description:
+
+ Send Packet Array handler. Called by NDIS whenever a protocol
+ bound to our miniport sends one or more packets.
+
+ The input packet descriptor pointers have been ordered according
+ to the order in which the packets should be sent over the network
+ by the protocol driver that set up the packet array. The NDIS
+ library preserves the protocol-determined ordering when it submits
+ each packet array to MiniportSendPackets
+
+ As a deserialized driver, we are responsible for holding incoming send
+ packets in our internal queue until they can be transmitted over the
+ network and for preserving the protocol-determined ordering of packet
+ descriptors incoming to its MiniportSendPackets function.
+ A deserialized miniport driver must complete each incoming send packet
+ with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ NetBufferLists Head of a list of NBLs to send
+ PortNumber A miniport adapter port. Default is 0.
+ SendFlags Additional flags for the send operation
+
+Return Value:
+
+ None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS
+ macro.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+ PNET_BUFFER_LIST Nbl;
+ PNET_BUFFER_LIST NextNbl = NULL;
+ BOOLEAN fAtDispatch = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ? TRUE:FALSE;
+ NDIS_STATUS Status;
+ ULONG NumNbls=0;
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPSendNetBufferLists\n", Adapter);
+
+ UNREFERENCED_PARAMETER(PortNumber);
+ UNREFERENCED_PARAMETER(SendFlags);
+ ASSERT(PortNumber == 0); // Only the default port is supported
+
+
+ //
+ // Each NET_BUFFER_LIST has a list of NET_BUFFERs.
+ // Loop over all the NET_BUFFER_LISTs, sending each NET_BUFFER.
+ //
+ for (
+ Nbl = NetBufferLists;
+ Nbl!= NULL;
+ Nbl = NextNbl, ++NumNbls)
+ {
+ PNET_BUFFER NetBuffer;
+
+ NextNbl = NET_BUFFER_LIST_NEXT_NBL(Nbl);
+
+ //
+ // Unlink the NBL and prepare our bookkeeping.
+ //
+ // We use a reference count to make sure that we don't send complete
+ // the NBL until we're done reading each NB on the NBL.
+ //
+ NET_BUFFER_LIST_NEXT_NBL(Nbl) = NULL;
+ SEND_REF_FROM_NBL(Nbl) = 0;
+
+ Status = TXNblReference(Adapter, Nbl);
+
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_SUCCESS;
+
+ //
+ // Queue each NB for transmission.
+ //
+ for (
+ NetBuffer = NET_BUFFER_LIST_FIRST_NB(Nbl);
+ NetBuffer != NULL;
+ NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer))
+ {
+ NBL_FROM_SEND_NB(NetBuffer) = Nbl;
+ TXQueueNetBufferForSend(Adapter, NetBuffer);
+ }
+
+ TXNblRelease(Adapter, Nbl, fAtDispatch);
+ }
+ else
+ {
+ //
+ // We can't send this NBL now. Indicate failure.
+ //
+ if (MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
+ {
+ NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_PAUSE_IN_PROGRESS|fMP_ADAPTER_PAUSED))
+ {
+ NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_PAUSED;
+ }
+ else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_LOW_POWER))
+ {
+ NET_BUFFER_LIST_STATUS(Nbl) = NDIS_STATUS_LOW_POWER_STATE;
+ }
+ else
+ {
+ NET_BUFFER_LIST_STATUS(Nbl) = Status;
+ }
+
+ NdisMSendNetBufferListsComplete(
+ Adapter->AdapterHandle,
+ Nbl,
+ fAtDispatch ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);
+
+ continue;
+ }
+ }
+
+ DEBUGP(MP_TRACE, "[%p] %i NBLs processed.\n", Adapter, NumNbls);
+
+ //
+ // Now actually go send each of the queued NBs.
+ //
+ TXTransmitQueuedSends(Adapter, fAtDispatch);
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPSendNetBufferLists\n", Adapter);
+}
+
+VOID
+TXQueueNetBufferForSend(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER NetBuffer)
+/*++
+
+Routine Description:
+
+ This routine inserts the NET_BUFFER into the SendWaitList, then calls
+ TXTransmitQueuedSends to start sending data from the list.
+
+ We use this indirect queue to send data because the miniport should try to
+ send frames in the order in which the protocol gave them. If we just sent
+ the NET_BUFFER immediately, then it would be out-of-order with any data on
+ the SendWaitList.
+
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Adapter that is transmitting this NB
+ NetBuffer NB to be transfered
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ UCHAR DestAddress[NIC_MACADDR_SIZE];
+
+ DEBUGP(MP_TRACE, "[%p] ---> TXQueueNetBufferForSend, NB= 0x%p\n", Adapter, NetBuffer);
+
+ do
+ {
+ //
+ // First, do a sanity check on the frame data.
+ //
+ Status = HWGetDestinationAddress(NetBuffer, DestAddress);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(NetBuffer)) = NDIS_STATUS_INVALID_DATA;
+ break;
+ }
+
+ //
+ // Stash away the frame type. We'll use that later, when updating
+ // our send statistics (since we don't have NIC hardware to compute the
+ // send statistics for us).
+ //
+ FRAME_TYPE_FROM_SEND_NB(NetBuffer) = NICGetFrameTypeFromDestination(DestAddress);
+
+ //
+ // Pin the original NBL with a reference, so it isn't completed until
+ // we're done with its NB.
+ //
+ Status = TXNblReference(Adapter, NBL_FROM_SEND_NB(NetBuffer));
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Insert the NB into the queue. The caller will flush the queue when
+ // it's done adding items to the queue.
+ //
+ NdisInterlockedInsertTailList(
+ &Adapter->SendWaitList,
+ SEND_WAIT_LIST_FROM_NB(NetBuffer),
+ &Adapter->SendWaitListLock);
+ }
+
+ } while (FALSE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- TXQueueNetBufferForSend\n", Adapter);
+}
+
+
+VOID
+#pragma prefast(suppress: 28167, "PREfast does not recognize IRQL is conditionally raised and lowered")
+TXTransmitQueuedSends(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ BOOLEAN fAtDispatch)
+/*++
+
+Routine Description:
+
+ This routine sends as many frames from the SendWaitList as it can.
+
+ If there are not enough resources to send immediately, this function stops
+ and leaves the remaining frames on the SendWaitList, to be sent once there
+ are enough resources.
+
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Our adapter
+ fAtDispatch TRUE if the current IRQL is DISPATCH_LEVEL
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN fScheduleTheSendCompleteDpc = FALSE;
+ ULONG NumFramesSent = 0;
+ KIRQL OldIrql = PASSIVE_LEVEL;
+
+ DEBUGP(MP_TRACE,
+ "[%p] ---> TXTransmitQueuedSends\n",
+ Adapter);
+
+ //
+ // This guard ensures that only one CPU is running this function at a time.
+ // We check this so that items from the SendWaitList get sent to the
+ // receiving adapters in the same order that they were queued.
+ //
+ // You could remove this guard and everything will still work ok, but some
+ // frames might be delivered out-of-order.
+ //
+ // Generally, this mechanism wouldn't be applicable to real hardware, since
+ // the hardware would have its own mechanism to ensure sends are transmitted
+ // in the correct order.
+ //
+ if (!fAtDispatch)
+ {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ }
+
+ if (KeTryToAcquireSpinLockAtDpcLevel(&Adapter->SendPathSpinLock))
+ {
+ for (NumFramesSent = 0; NumFramesSent < NIC_MAX_SENDS_PER_DPC; NumFramesSent++)
+ {
+ PLIST_ENTRY pTcbEntry = NULL;
+ PTCB Tcb = NULL;
+ PLIST_ENTRY pQueuedSend = NULL;
+ PNET_BUFFER NetBuffer;
+
+ //
+ // Get the next available TCB.
+ //
+ pTcbEntry = NdisInterlockedRemoveHeadList(
+ &Adapter->FreeTcbList,
+ &Adapter->FreeTcbListLock);
+ if (!pTcbEntry)
+ {
+ //
+ // The adapter can't handle any more simultaneous transmit
+ // operations. Keep any remaining sends in the SendWaitList and
+ // we'll come back later when there are TCBs available.
+ //
+ break;
+ }
+
+ Tcb = CONTAINING_RECORD(pTcbEntry, TCB, TcbLink);
+
+ //
+ // Get the next NB that needs sending.
+ //
+ pQueuedSend = NdisInterlockedRemoveHeadList(
+ &Adapter->SendWaitList,
+ &Adapter->SendWaitListLock);
+ if (!pQueuedSend)
+ {
+ //
+ // There's nothing left that needs sending. We're all done.
+ //
+ NdisInterlockedInsertTailList(
+ &Adapter->FreeTcbList,
+ &Tcb->TcbLink,
+ &Adapter->FreeTcbListLock);
+ break;
+ }
+
+ NetBuffer = NB_FROM_SEND_WAIT_LIST(pQueuedSend);
+
+
+ //
+ // We already packed the frame type into the net buffer before accepting
+ // it for send. Now that we have a TCB to keep track of the data, let's
+ // pull it out and keep it in a proper variable.
+ //
+ Tcb->FrameType = FRAME_TYPE_FROM_SEND_NB(NetBuffer);
+
+ HWProgramDmaForSend(Adapter, Tcb, NetBuffer, fAtDispatch);
+
+ NdisInterlockedInsertTailList(
+ &Adapter->BusyTcbList,
+ &Tcb->TcbLink,
+ &Adapter->BusyTcbListLock);
+
+ fScheduleTheSendCompleteDpc = TRUE;
+ }
+
+ KeReleaseSpinLock(&Adapter->SendPathSpinLock, DISPATCH_LEVEL);
+ }
+
+ if (!fAtDispatch)
+ {
+ KeLowerIrql(OldIrql);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] %i Frames transmitted.\n", Adapter, NumFramesSent);
+
+ if (fScheduleTheSendCompleteDpc)
+ {
+ TXScheduleTheSendComplete(Adapter);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <-- TXTransmitQueuedSends\n", Adapter);
+}
+
+
+VOID
+TXScheduleTheSendComplete(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ This function schedules the transmit DPC on the sending miniport.
+
+Arguments:
+
+ FunctionContext Pointer to the adapter that is sending frames
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER liDelay;
+
+ if (!Adapter->SendCompleteWorkItemQueued)
+ {
+ liDelay.QuadPart = -(NIC_SIMULATED_LATENCY);
+ NdisSetTimerObject(Adapter->SendCompleteTimer, liDelay, 0, NULL);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] Scheduled Send Complete DPC [Delay: %i].\n", Adapter, NIC_SIMULATED_LATENCY);
+
+}
+
+
+_IRQL_requires_(DISPATCH_LEVEL)
+BOOLEAN
+WorkItemQueuedForWatchdogAvoidance(
+ _In_ NDIS_HANDLE WorkItem,
+ _In_ volatile LONG* WorkItemQueued,
+ _In_ NDIS_IO_WORKITEM_ROUTINE WIRoutine,
+ _In_ PVOID WIContext
+ )
+/*++
+
+Routine Description:
+
+ This function should be called from the receive or send-complete DPCs. It queues a work item to do the receives or send-completes
+ if the DPC watchdog timer is within 25% of the limit. This allows the processor to reach PASSIVE_LEVEL and reset the watchdog.
+
+ Runs at IRQL = DISPATCH_LEVEL.
+
+Arguments:
+
+ WorkItem The work item to queue
+ WorkItemQueued Variable that stores whether a work item is currently queued
+ WIRoutine The work routine
+ WIContext The context passed to the work routine
+
+Return Value:
+
+ TRUE - Work item queued due to watchdog timer, caller should exit DPC
+ FALSE - Ok to continue in DPC
+
+--*/
+{
+ KDPC_WATCHDOG_INFORMATION WatchdogInfo;
+ NTSTATUS Status;
+
+ if(*WorkItemQueued)
+ {
+ //
+ // We've already queued up the work item, no need to check watchdog information
+ //
+ return TRUE;
+ }
+
+ Status = KeQueryDpcWatchdogInformation(&WatchdogInfo);
+ if (NT_SUCCESS(Status)
+ //
+ // Verify the watchdog is enabled
+ //
+ && WatchdogInfo.DpcWatchdogLimit != 0
+ //
+ // Once we go below 25% of the watchdog limit we fall back on the work item to allow the watchdog to reset
+ //
+ && WatchdogInfo.DpcWatchdogCount < WatchdogInfo.DpcWatchdogLimit / 4)
+ {
+ //
+ // Make sure we don't queue the work item if it's already been queued for this DPC
+ //
+ LONG AlreadyQueued = InterlockedCompareExchange(
+ WorkItemQueued,
+ TRUE,
+ FALSE);
+ if(!AlreadyQueued)
+ {
+ //
+ // We've crossed our threshold for consecutive DPCs, schedule work item to complete this receive
+ //
+ DEBUGP(MP_TRACE, "Processor has spent too much time in DPC. Queueing work item to handle next receives/send-completes.\n");
+ NdisQueueIoWorkItem(WorkItem, WIRoutine, WIContext);
+ }
+ return TRUE;
+ }
+
+ //
+ // We're still within acceptable time limits
+ //
+ return FALSE;
+}
+
+
+_IRQL_requires_(DISPATCH_LEVEL)
+VOID
+TXSendComplete(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ This routine completes pending sends for the given adapter.
+
+ Each busy TCB is popped from the BusyTcbList and its corresponding NB is
+ released. If there was an error sending the frame, the NB's NBL's status
+ is updated.
+
+--*/
+{
+ BOOLEAN fRescheduleThisDpcAgain = TRUE;
+ ULONG NumFramesSent = 0;
+
+ DEBUGP(MP_TRACE, "[%p] ---> TXSendComplete.\n", Adapter);
+
+ for (NumFramesSent = 0; NumFramesSent < NIC_MAX_SENDS_PER_DPC; NumFramesSent++)
+ {
+ ULONG BytesSent;
+
+ PTCB Tcb = TXGetNextTcbToSend(Adapter);
+ if (!Tcb)
+ {
+ //
+ // There are no more TCBs remaining to send. We're all done.
+ //
+ fRescheduleThisDpcAgain = FALSE;
+ break;
+ }
+
+
+ //
+ // Finish the transmit operation. For our hardware, that means the
+ // frame is pushed onto the RecvWaitLists of each other adapter.
+ //
+
+ BytesSent = HWGetBytesSent(Adapter, Tcb);
+
+ if (BytesSent == 0)
+ {
+ //
+ // Failed to send the frame.
+ //
+
+ Adapter->TransmitFailuresOther++;
+ NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ //
+ // We've finished sending this NB successfully; update the stats.
+ //
+ switch (Tcb->FrameType)
+ {
+ case NDIS_PACKET_TYPE_BROADCAST:
+ Adapter->FramesTxBroadcast++;
+ Adapter->BytesTxBroadcast += BytesSent;
+ break;
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ Adapter->FramesTxMulticast++;
+ Adapter->BytesTxMulticast += BytesSent;
+ break;
+
+ case NDIS_PACKET_TYPE_DIRECTED:
+ default:
+ Adapter->FramesTxDirected++;
+ Adapter->BytesTxDirected += BytesSent;
+ }
+ }
+
+
+ //
+ // Now that we've finished using the TCB and its associated NET_BUFFER,
+ // we can release the NET_BUFFER back to the protocol and the TCB back
+ // to the free list.
+ //
+ ReturnTCB(Adapter, Tcb);
+ }
+
+ TXTransmitQueuedSends(Adapter, TRUE);
+
+ if (fRescheduleThisDpcAgain)
+ {
+ TXScheduleTheSendComplete(Adapter);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- TXSendComplete.\n", Adapter);
+}
+
+_Use_decl_annotations_
+VOID
+TXSendCompleteWorkItem(
+ PVOID FunctionContext,
+ NDIS_HANDLE WorkItem)
+/*++
+
+Routine Description:
+
+ This work item handler is used to do send completions in the case when we are trying
+ to avoid a DPC watchdog timeout
+
+Arguments:
+
+ FunctionContext - The Adapter object for which send-completions are to be done
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(FunctionContext);
+ KIRQL OldIrql;
+
+ UNREFERENCED_PARAMETER(WorkItem);
+
+ ASSERT(Adapter != NULL);
+ _Analysis_assume_(Adapter != NULL);
+ DEBUGP(MP_TRACE, "[%p] ---> TXSendCompleteWorkItem.\n", Adapter);
+
+ Adapter->SendCompleteWorkItemRunning = TRUE;
+ KeMemoryBarrier();
+
+ Adapter->SendCompleteWorkItemQueued = FALSE;
+ KeMemoryBarrier();
+
+ NDIS_RAISE_IRQL_TO_DISPATCH(&OldIrql);
+ TXSendComplete(Adapter);
+ NDIS_LOWER_IRQL(OldIrql,DISPATCH_LEVEL);
+
+ KeMemoryBarrier();
+ Adapter->SendCompleteWorkItemRunning = FALSE;
+
+ DEBUGP(MP_TRACE, "[%p] <--- TXSendCompleteWorkItem.\n", Adapter);
+}
+
+_Use_decl_annotations_
+VOID
+TXSendCompleteDpc(
+ PVOID UnusedParameter1,
+ PVOID FunctionContext,
+ PVOID UnusedParameter2,
+ PVOID UnusedParameter3)
+/*++
+
+Routine Description:
+
+ This routine simulates the DPC handler of a send complete hardware
+ interrupt.
+
+Arguments:
+
+ FunctionContext - The Adapter object for which send-completions are to be done
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(FunctionContext);
+
+ UNREFERENCED_PARAMETER(UnusedParameter1);
+ UNREFERENCED_PARAMETER(UnusedParameter2);
+ UNREFERENCED_PARAMETER(UnusedParameter3);
+
+ DEBUGP(MP_TRACE, "[%p] ---> TXSendCompleteDpc\n", Adapter);
+
+ if (!WorkItemQueuedForWatchdogAvoidance(Adapter->SendCompleteWorkItem,
+ &Adapter->SendCompleteWorkItemQueued,
+ TXSendCompleteWorkItem,
+ Adapter))
+ {
+ TXSendComplete(Adapter);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- TXSendCompleteDpc\n", Adapter);
+}
+
+NDIS_STATUS
+TXNblReference(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER_LIST NetBufferList)
+/*++
+
+Routine Description:
+
+ Adds a reference on a NBL that is being transmitted.
+ The NBL won't be returned to the protocol until the last reference is
+ released.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ NetBufferList The NBL to reference
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if reference was acquired succesfully.
+ NDIS_STATUS_ADAPTER_NOT_READY if the adapter state is such that we should not acquire new references to resources
+
+--*/
+{
+ NdisInterlockedIncrement(&Adapter->nBusySend);
+
+ //
+ // Make sure the increment happens before ready state check
+ //
+ KeMemoryBarrier();
+
+ //
+ // If the adapter is not ready, undo the reference and fail the call
+ //
+ if(!MP_IS_READY(Adapter))
+ {
+ InterlockedDecrement(&Adapter->nBusySend);
+ DEBUGP(MP_LOUD, "[%p] Could not acquire transmit reference, the adapter is not ready.\n", Adapter);
+ return NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+
+ NdisInterlockedIncrement(&SEND_REF_FROM_NBL(NetBufferList));
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+TXNblRelease(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER_LIST NetBufferList,
+ _In_ BOOLEAN fAtDispatch)
+/*++
+
+Routine Description:
+
+ Releases a reference on a NBL that is being transmitted.
+ If the last reference is released, the NBL is returned to the protocol.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ NetBufferList The NBL to release
+ fAtDispatch TRUE if the current IRQL is DISPATCH_LEVEL
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ if (0 == NdisInterlockedDecrement(&SEND_REF_FROM_NBL(NetBufferList)))
+ {
+ DEBUGP(MP_TRACE, "[%p] Send NBL %p complete.\n", Adapter, NetBufferList);
+
+ NET_BUFFER_LIST_NEXT_NBL(NetBufferList) = NULL;
+
+ NdisMSendNetBufferListsComplete(
+ Adapter->AdapterHandle,
+ NetBufferList,
+ fAtDispatch ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL:0);
+ }
+ else
+ {
+ DEBUGP(MP_TRACE, "[%p] Send NBL %p not complete. RefCount: %i.\n", Adapter, NetBufferList, SEND_REF_FROM_NBL(NetBufferList));
+ }
+
+ NdisInterlockedDecrement(&Adapter->nBusySend);
+}
+
+
+_Must_inspect_result_
+PTCB
+TXGetNextTcbToSend(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ Returns the next TCB queued on the send list, or NULL if the list was empty.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+ NULL if there was no TCB queued.
+ Else, a pointer to the TCB that was popped off the top of the BusyTcbList.
+
+--*/
+{
+ PTCB Tcb;
+ PLIST_ENTRY pTcbEntry = NdisInterlockedRemoveHeadList(
+ &Adapter->BusyTcbList,
+ &Adapter->BusyTcbListLock);
+
+ if (! pTcbEntry)
+ {
+ // End of list -- no more items to receive.
+ return NULL;
+ }
+
+ Tcb = CONTAINING_RECORD(pTcbEntry, TCB, TcbLink);
+
+ ASSERT(Tcb);
+ ASSERT(Tcb->NetBuffer);
+
+ return Tcb;
+}
+
+
+VOID
+TXFlushSendQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_STATUS CompleteStatus)
+/*++
+
+Routine Description:
+
+ This routine is called by the Halt or Reset handler to fail all
+ the queued up Send NBLs because the device is either gone, being
+ stopped for resource rebalance, or reset.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ CompleteStatus The status code with which to complete each NBL
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PTCB Tcb;
+
+ DEBUGP(MP_TRACE, "[%p] ---> TXFlushSendQueue Status = 0x%08x\n", Adapter, CompleteStatus);
+
+
+ //
+ // First, free anything queued in the driver.
+ //
+
+ while (TRUE)
+ {
+ PLIST_ENTRY pEntry;
+ PNET_BUFFER NetBuffer;
+ PNET_BUFFER_LIST NetBufferList;
+
+ pEntry = NdisInterlockedRemoveHeadList(
+ &Adapter->SendWaitList,
+ &Adapter->SendWaitListLock);
+
+ if (!pEntry)
+ {
+ // End of list -- nothing left to free.
+ break;
+ }
+
+ NetBuffer = NB_FROM_SEND_WAIT_LIST(pEntry);
+ NetBufferList = NBL_FROM_SEND_NB(NetBuffer);
+
+ DEBUGP(MP_TRACE, "[%p] Dropping Send NB: 0x%p.\n", Adapter, NetBuffer);
+
+ NET_BUFFER_LIST_STATUS(NetBufferList) = CompleteStatus;
+ TXNblRelease(Adapter, NetBufferList, FALSE);
+ }
+
+
+ //
+ // Next, cancel anything queued in the hardware.
+ //
+
+ while (NULL != (Tcb = TXGetNextTcbToSend(Adapter)))
+ {
+ NET_BUFFER_LIST_STATUS(NBL_FROM_SEND_NB(Tcb->NetBuffer)) = CompleteStatus;
+ ReturnTCB(Adapter, Tcb);
+ }
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- TXFlushSendQueue\n", Adapter);
+}
+
+
+VOID
+RXDeliverFrameToEveryAdapter(
+ _In_ PMP_ADAPTER SendAdapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame,
+ _In_ BOOLEAN fAtDispatch)
+/*++
+
+Routine Description:
+
+ This routine sends a TCB to each netvmini 6.x adapter (besides the sending
+ adapter itself)
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ SendAdapter Our adapter that is doing the sending
+ Nbl1QInfo 8021Q Tag information for the FRAME to be sent
+ Frame The FRAME to be sent
+ fAtDispatch TRUE if the current IRQL is DISPATCH_LEVEL
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MP_LOCK_STATE LockState;
+ PLIST_ENTRY AdapterLink;
+
+
+ DEBUGP(MP_TRACE, "[%p] ---> RXDeliverFrameToEveryAdapter. Frame=0x%p\n", SendAdapter, Frame);
+
+ LOCK_ADAPTER_LIST_FOR_READ(&LockState, fAtDispatch ? NDIS_RWL_AT_DISPATCH_LEVEL:0);
+ UNREFERENCED_PARAMETER(fAtDispatch);
+
+ //
+ // Go through the adapter list and queue packet for
+ // indication on them if there are any. Otherwise
+ // just drop the packet on the floor and tell NDIS that
+ // you have completed send.
+ //
+
+ for (
+ AdapterLink = GlobalData.AdapterList.Flink;
+ AdapterLink != &GlobalData.AdapterList;
+ AdapterLink = AdapterLink->Flink
+ )
+ {
+ PMP_ADAPTER DestAdapter = CONTAINING_RECORD(AdapterLink, MP_ADAPTER, List);
+
+ if (DestAdapter == SendAdapter)
+ {
+ // Don't loopback packets to the sending adapter.
+ continue;
+ }
+
+ RXQueueFrameOnAdapter(DestAdapter, Nbl1QInfo, Frame);
+ }
+
+ UNLOCK_ADAPTER_LIST(&LockState);
+
+ DEBUGP(MP_TRACE, "[%p] <-- RXDeliverFrameToEveryAdapter\n", SendAdapter);
+
+}
+
+VOID
+RXQueueFrameOnAdapter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame)
+/*++
+
+Routine Description:
+
+ This routine queues the send packet in to the destination
+ adapters RecvWaitList and fires a timer DPC so that it
+ can be indicated as soon as possible.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Pointer to the destination adapter
+ Nbl1QInfo 8021Q Tag information for the FRAME to be sent
+ Frame Pointer to FRAME that contains the data payload
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DEBUGP(MP_TRACE, "[%p] ---> RXQueueFrameOnAdapter\n", Adapter);
+
+ do
+ {
+ PRCB Rcb;
+ UCHAR DestAddress[NIC_MACADDR_SIZE];
+ ULONG FrameType;
+
+
+ if (!MP_IS_READY(Adapter))
+ {
+ //
+ // The NIC is not receiving any data.
+ //
+ break;
+ }
+
+ if (Frame->ulSize < HW_MIN_FRAME_SIZE)
+ {
+ //
+ // This frame is malformed. Drop it.
+ //
+ Adapter->RxRuntErrors++;
+ break;
+ }
+
+ GET_DESTINATION_OF_FRAME(DestAddress, Frame->Data);
+ FrameType = NICGetFrameTypeFromDestination(DestAddress);
+
+ if(VMQ_ENABLED(Adapter) && FrameType == NDIS_PACKET_TYPE_DIRECTED)
+ {
+ //
+ // Defer decision whether to drop until we check for VMQ matches
+ //
+ }
+ else if (!HWIsFrameAcceptedByPacketFilter(Adapter, DestAddress, FrameType))
+ {
+ //
+ // Our NIC "hardware" has a packet filter that eliminates frames
+ // that weren't sent to us. This frame didn't match the filter,
+ // so pretend we never saw this frame.
+ //
+ break;
+ }
+
+ //
+ // Allocate memory for RCB.
+ //
+ Rcb = GetRCB(Adapter, Nbl1QInfo, Frame);
+ if (!Rcb)
+ {
+ DEBUGP(MP_TRACE, "[%p] GetRCB did not return an RCB.\n", Adapter);
+ break;
+ }
+
+
+ switch (FrameType)
+ {
+ case NDIS_PACKET_TYPE_BROADCAST:
+ Adapter->FramesRxBroadcast++;
+ Adapter->BytesRxBroadcast += Frame->ulSize;
+ break;
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ Adapter->FramesRxMulticast++;
+ Adapter->BytesRxMulticast += Frame->ulSize;
+ break;
+
+ case NDIS_PACKET_TYPE_DIRECTED:
+ default:
+ Adapter->FramesRxDirected++;
+ Adapter->BytesRxDirected += Frame->ulSize;
+ }
+
+
+ //
+ // If VMQ is enabled, queue Rcb on the owner VMQ, otherwise
+ // use global receive wait list
+ //
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ // Queue on owner VMQ receive block
+ //
+ AddPendingRcbToRxQueue(Adapter, Rcb);
+ }
+ else
+ {
+ //
+ // Queue on global receive block
+ //
+ NdisInterlockedInsertTailList(&Adapter->ReceiveBlock[0].ReceiveList, &Rcb->RcbLink, &Adapter->ReceiveBlock[0].ReceiveListLock);
+ }
+
+ RXScheduleTheReceiveIndication(Adapter, Rcb);
+
+
+ } while (FALSE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- RXQueueFrameOnAdapter\n", Adapter);
+}
+
+VOID
+RXScheduleTheReceiveIndication(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PRCB Rcb)
+/*++
+
+Routine Description:
+
+ This function schedules the receive DPC on the receiving miniport.
+
+Arguments:
+
+ FunctionContext Pointer to the adapter that is receiving frames
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Use default DPC unless VMQ is enabled, in which case you use the Queue's DPC
+ //
+ PMP_ADAPTER_RECEIVE_DPC AdapterDpc = Adapter->DefaultRecvDpc;
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ // Add Rcb to owner Queue's pending List
+ //
+ AdapterDpc = GetRxQueueDpc(Adapter, NET_BUFFER_LIST_RECEIVE_QUEUE_ID(Rcb->Nbl));
+ }
+ else
+ {
+ UNREFERENCED_PARAMETER(Rcb);
+ }
+
+ //
+ // Schedule DPC
+ //
+ if(AdapterDpc->WorkItemQueued)
+ {
+ //
+ // We've queued up receive work item to avoid DPC watchdog timeout. Let's wait for it to start rather
+ // than queue up the DPC.
+ //
+ DEBUGP(MP_TRACE, "[%p] Receive DPC not scheduled, receive work item is pending. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber);
+ }
+ else
+ {
+ KeInsertQueueDpc(&AdapterDpc->Dpc, AdapterDpc, NULL);
+ DEBUGP(MP_TRACE, "[%p] Scheduled Receive DPC. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber);
+ }
+
+}
+
+VOID
+RXReceiveIndicateDpc(
+ _In_ struct _KDPC *Dpc,
+ _In_opt_ PVOID DeferredContext,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2)
+/*++
+
+Routine Description:
+
+ DPC function for Receive Indication. Please note that receive
+ timer DPC is not required when you are talking to a real device. In real
+ miniports, this DPC is usually provided by NDIS as MPHandleInterrupt
+ callback whenever the device interrupts for receive indication.
+
+Arguments:
+
+ DeferredContext Pointer to our adapter
+ SystemArgument1 PMP_ADAPTER_RECEIVE_DPC structure for this DPC
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ ASSERT(DeferredContext != NULL);
+ ASSERT(SystemArgument1 != NULL);
+ _Analysis_assume_(DeferredContext != NULL);
+ _Analysis_assume_(SystemArgument1 != NULL);
+
+ RXReceiveIndicate((PMP_ADAPTER)DeferredContext, (PMP_ADAPTER_RECEIVE_DPC)SystemArgument1, TRUE);
+}
+
+_Use_decl_annotations_
+VOID
+RXReceiveIndicateWorkItem(
+ PVOID WorkItemContext,
+ NDIS_HANDLE NdisIoWorkItemHandle)
+/*++
+
+Routine Description:
+
+ Work Item function for Receive Indication. The work item is invoked if the corresponding receive
+ DPC has run enough times on the processor without a transition to PASSIVE to risk hitting the DPC
+ watchdog timer.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ WorkItemContext PMP_ADAPTER_RECEIVE_DPC structure for the corresponding receive DPC
+ NdisIoWorkItemHandle Workitem handle, unused
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER_RECEIVE_DPC AdapterDpc = (PMP_ADAPTER_RECEIVE_DPC)WorkItemContext;
+ UNREFERENCED_PARAMETER(NdisIoWorkItemHandle);
+ ASSERT(AdapterDpc != NULL);
+ _Analysis_assume_(AdapterDpc != NULL);
+ RXReceiveIndicate(AdapterDpc->Adapter, AdapterDpc, FALSE);
+}
+
+VOID
+RXReceiveIndicate(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc,
+ BOOLEAN AtDpc)
+/*++
+
+Routine Description:
+
+ This function performs the receive indications for the specified RECEIVE_DPC structure.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ AdapterDpc PMP_ADAPTER_RECEIVE_DPC structure for this receive
+ AtDpc TRUE if the function was called from the context of the DPC, FALSE if called from work item (to avoid watchdog)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG NumNblsReceived = 0;
+ PNET_BUFFER_LIST FirstNbl = NULL, LastNbl = NULL;
+ USHORT CurrentQueue;
+
+ DEBUGP(MP_TRACE, "[%p] ---> RXReceiveIndicate. Processor: %i, AtDpc: %i\n", Adapter, AdapterDpc->ProcessorNumber, AtDpc);
+
+ //
+ // Exit DPC if we've queued a work item to avoid DPC watchdog timer expiration
+ //
+ if(AtDpc && WorkItemQueuedForWatchdogAvoidance(AdapterDpc->WorkItem,
+ &AdapterDpc->WorkItemQueued,
+ RXReceiveIndicateWorkItem,
+ AdapterDpc))
+ {
+ DEBUGP(MP_TRACE, "[%p] <--- RXReceiveIndicate. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber);
+ return;
+ }
+
+ for(CurrentQueue = 0; CurrentQueue <NIC_SUPPORTED_NUM_QUEUES; ++CurrentQueue)
+ {
+ //
+ // Consume RCBs for queue if we're the assigned consumer
+ //
+ if(AdapterDpc->RecvBlock[CurrentQueue])
+ {
+ PMP_ADAPTER_RECEIVE_BLOCK ReceiveBlock = &Adapter->ReceiveBlock[CurrentQueue];
+ FirstNbl = LastNbl = NULL;
+
+ //
+ // Collect pending NBLs, indicate up to MaxNblCountPerIndicate per receive block
+ //
+ for(NumNblsReceived=0; NumNblsReceived < AdapterDpc->MaxNblCountPerIndicate; ++NumNblsReceived)
+ {
+ PLIST_ENTRY Entry;
+ PRCB Rcb = NULL;
+
+ Entry = NdisInterlockedRemoveHeadList(&ReceiveBlock->ReceiveList, &ReceiveBlock->ReceiveListLock);
+ if(Entry)
+ {
+ Rcb = CONTAINING_RECORD(Entry, RCB, RcbLink);
+ }
+
+ if(!Rcb)
+ {
+ break;
+ }
+
+ ASSERT(Rcb->Data);
+
+ //
+ // The recv NBL's data was filled out by the hardware. Now just update
+ // its bookkeeping.
+ //
+ NET_BUFFER_LIST_STATUS(Rcb->Nbl) = NDIS_STATUS_SUCCESS;
+ Rcb->Nbl->SourceHandle = Adapter->AdapterHandle;
+
+ //
+ // Add this NBL to the chain of NBLs to indicate up.
+ //
+ if (!FirstNbl)
+ {
+ LastNbl = FirstNbl = Rcb->Nbl;
+ }
+ else
+ {
+ NET_BUFFER_LIST_NEXT_NBL(LastNbl) = Rcb->Nbl;
+ LastNbl = Rcb->Nbl;
+ }
+ }
+
+ //
+ // Indicate NBLs
+ //
+ if (FirstNbl)
+ {
+ DEBUGP(MP_TRACE, "[%p] Receive Block %i: %i frames indicated.\n", Adapter, CurrentQueue, NumNblsReceived);
+
+ NET_BUFFER_LIST_NEXT_NBL(LastNbl) = NULL;
+
+ //
+ // Indicate up the NBLs.
+ //
+ // The NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL allows a perf optimization:
+ // NDIS doesn't have to check and raise the current IRQL, since we
+ // promise that the current IRQL is exactly DISPATCH_LEVEL already.
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ Adapter->AdapterHandle,
+ FirstNbl,
+ 0, // default port
+ NumNblsReceived,
+ (AtDpc?NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL:0)
+ | NDIS_RECEIVE_FLAGS_PERFECT_FILTERED
+#if (NDIS_SUPPORT_NDIS620)
+ | NDIS_RECEIVE_FLAGS_SINGLE_QUEUE
+ | (CurrentQueue?NDIS_RECEIVE_FLAGS_SHARED_MEMORY_INFO_VALID:0) //non-default queues use shared memory
+#endif
+ );
+ }
+
+ if(!AtDpc)
+ {
+ //
+ // Clear work item flag to allow DPCs to be queued
+ //
+ InterlockedExchange(&AdapterDpc->WorkItemQueued, FALSE);
+ }
+
+ if (!IsListEmpty(&ReceiveBlock->ReceiveList))
+ {
+ //
+ // More left to indicate for this receive block, queue this DPC again
+ //
+ DEBUGP(MP_TRACE, "[%p] Receive Block %i: Requeued DPC.\n", Adapter, CurrentQueue);
+ KeInsertQueueDpc(&AdapterDpc->Dpc, AdapterDpc, NULL);
+ }
+
+ }
+
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- RXReceiveIndicate. Processor: %i\n", Adapter, AdapterDpc->ProcessorNumber);
+}
+
+
+VOID
+MPReturnNetBufferLists(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PNET_BUFFER_LIST NetBufferLists,
+ _In_ ULONG ReturnFlags)
+/*++
+
+Routine Description:
+
+ NDIS Miniport entry point called whenever protocols are done with one or
+ NBLs that we indicated up with NdisMIndicateReceiveNetBufferLists.
+
+ Note that the list of NBLs may be chained together from multiple separate
+ lists that were indicated up individually.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ NetBufferLists NBLs being returned
+ ReturnFlags May contain the NDIS_RETURN_FLAGS_DISPATCH_LEVEL
+ flag, which if is set, indicates we can get a
+ small perf win by not checking or raising the
+ IRQL
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(ReturnFlags);
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPReturnNetBufferLists\n", Adapter);
+
+ while (NetBufferLists)
+ {
+ PRCB Rcb = RCB_FROM_NBL(NetBufferLists);
+ ReturnRCB(Adapter, Rcb);
+ NetBufferLists = NET_BUFFER_LIST_NEXT_NBL(NetBufferLists);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPReturnNetBufferLists\n", Adapter);
+}
+
+VOID
+RXFlushReceiveQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc)
+/*++
+
+Routine Description:
+
+ This routine is called by the Halt handler to fail all
+ the queued up RecvNbls if it succeeds in cancelling
+ the RecvIndicate timer DPC.
+
+Arguments:
+
+ Adapter Our adapter
+ AdapterDpc DPC to be flushed
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DEBUGP(MP_TRACE, "[%p] ---> RXFlushReceiveQueue\n", Adapter);
+
+ //
+ // If VMQ enabled, then flush the receive queues for this DPC
+ //
+ if(VMQ_ENABLED(Adapter))
+ {
+ USHORT index;
+ for(index =0; index < NIC_SUPPORTED_NUM_QUEUES; index++)
+ {
+ if(AdapterDpc->RecvBlock[index])
+ {
+ NICFlushReceiveBlock(Adapter, index);
+ }
+ }
+ }
+ else
+ {
+ NICFlushReceiveBlock(Adapter, 0);
+ UNREFERENCED_PARAMETER(AdapterDpc);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- RXFlushReceiveQueue\n", Adapter);
+
+}
+
+
+VOID
+MPCancelSend(
+ _In_ NDIS_HANDLE MiniportAdapterContext,
+ _In_ PVOID CancelId)
+/*++
+
+Routine Description:
+
+ MiniportCancelSend cancels the transmission of all NET_BUFFER_LISTs that
+ are marked with a specified cancellation identifier. Miniport drivers
+ that queue send packets for more than one second should export this
+ handler. When a protocol driver or intermediate driver calls the
+ NdisCancelSendNetBufferLists function, NDIS calls the MiniportCancelSend
+ function of the appropriate lower-level driver (miniport driver or
+ intermediate driver) on the binding.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ CancelId All the packets with this Id should be cancelled
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMP_ADAPTER Adapter = MP_ADAPTER_FROM_CONTEXT(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(Adapter);
+ UNREFERENCED_PARAMETER(CancelId);
+
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPCancelSend\n", Adapter);
+
+ //
+ // This miniport completes its sends quickly, so it isn't strictly
+ // neccessary to implement MiniportCancelSend.
+ //
+ // If we did implement it, we'd have to walk the Adapter->SendWaitList
+ // and look for any NB that points to a NBL where the CancelId matches
+ // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl). For any NB that so matches,
+ // we'd remove the NB from the SendWaitList and set the NBL's status to
+ // NDIS_STATUS_SEND_ABORTED, then complete the NBL.
+ //
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPCancelSend\n", Adapter);
+}
+
+
+VOID
+NICStartTheDatapath(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ This function enables sends and receives on the data path. It is the
+ reciprocal of NICStopTheDatapath.
+
+ Runs at IRQL == PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PAGED_CODE();
+
+ MPAttachAdapter(Adapter);
+}
+
+
+VOID
+NICStopTheDatapath(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ This function prevents future sends and receives on the data path, then
+ prepares the adapter to reach an idle state.
+
+ Although the adapter is entering an idle state, there may still be
+ outstanding NBLs that haven't been returned by a protocol. Call NICIsBusy
+ to check if NBLs are still outstanding.
+
+ Runs at IRQL == PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN fResetCancelled, fSendCancelled;
+ PLIST_ENTRY ReceiveListEntry;
+
+ DEBUGP(MP_TRACE, "[%p] ---> NICStopTheDatapath.\n", Adapter);
+
+ PAGED_CODE();
+
+ //
+ // Remove this adapter from consideration for future receives.
+ //
+ MPDetachAdapter(Adapter);
+
+ //
+ // Free any queued send operations
+ //
+ TXFlushSendQueue(Adapter, NDIS_STATUS_FAILURE);
+
+ //
+ // Prevent new calls to NICAsyncResetOrPauseDpc
+ //
+ fResetCancelled = NdisCancelTimerObject(Adapter->AsyncBusyCheckTimer);
+
+ //
+ // Prevent new calls to RXReceiveIndicateDpc.
+ //
+
+ for(ReceiveListEntry = Adapter->RecvDpcList.Flink;
+ ReceiveListEntry != &Adapter->RecvDpcList;
+ ReceiveListEntry = ReceiveListEntry->Flink)
+ {
+ PMP_ADAPTER_RECEIVE_DPC ReceiveDpc = CONTAINING_RECORD(ReceiveListEntry, MP_ADAPTER_RECEIVE_DPC, Entry);
+ KeRemoveQueueDpc(&ReceiveDpc->Dpc);
+ }
+
+ //
+ // Prevent new calls to TXSendCompleteDpc.
+ //
+ fSendCancelled = NdisCancelTimerObject(Adapter->SendCompleteTimer);
+
+ //
+ // Wait for any DPCs (like our reset and recv timers) that were in-progress
+ // to run to completion. This is slightly expensive to call, but we don't
+ // mind calling it during MiniportHaltEx, since it's not a performance-
+ // sensitive path.
+ //
+ KeFlushQueuedDpcs();
+
+ if (fSendCancelled)
+ {
+ // Free resources associated with a pending (but cancelled) send
+ }
+
+ if (fResetCancelled)
+ {
+ // Free resources associated with a pending (but cancelled) reset
+ }
+
+ //
+ // Double-check that there are still no queued receive operations
+ //
+ for(ReceiveListEntry = Adapter->RecvDpcList.Flink;
+ ReceiveListEntry != &Adapter->RecvDpcList;
+ ReceiveListEntry = ReceiveListEntry->Flink)
+ {
+ RXFlushReceiveQueue(Adapter, CONTAINING_RECORD(ReceiveListEntry, MP_ADAPTER_RECEIVE_DPC, Entry));
+ }
+
+ //
+ // Double-check that there are still no queued send operations
+ //
+ TXFlushSendQueue(Adapter, NDIS_STATUS_FAILURE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- NICStopTheDatapath.\n", Adapter);
+}
+
+ULONG
+NICGetFrameTypeFromDestination(
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress)
+/*++
+
+Routine Description:
+
+ Reads the network frame's destination address to determine the type
+ (broadcast, multicast, etc)
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ DestAddress The frame's destination address
+
+Return Value:
+
+ NDIS_PACKET_TYPE_BROADCAST
+ NDIS_PACKET_TYPE_MULTICAST
+ NDIS_PACKET_TYPE_DIRECTED
+
+--*/
+{
+ if (NIC_ADDR_IS_BROADCAST(DestAddress))
+ {
+ return NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else if(NIC_ADDR_IS_MULTICAST(DestAddress))
+ {
+ return NDIS_PACKET_TYPE_MULTICAST;
+ }
+ else
+ {
+ return NDIS_PACKET_TYPE_DIRECTED;
+ }
+}
+
diff --git a/network/ndis/netvmini/6x/datapath.h b/network/ndis/netvmini/6x/datapath.h
new file mode 100644
index 00000000..2926c7ca
--- /dev/null
+++ b/network/ndis/netvmini/6x/datapath.h
@@ -0,0 +1,77 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ DataPath.H
+
+Abstract:
+
+ This module declares the TCB and RCB structures, and the functions to
+ manipulate them.
+
+ See the comments in TcbRcb.c.
+
+--*/
+
+
+
+
+#ifndef _DATAPATH_H
+#define _DATAPATH_H
+
+
+
+
+NDIS_STATUS
+TXNblReference(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER_LIST NetBufferList);
+
+VOID
+TXNblRelease(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNET_BUFFER_LIST NetBufferList,
+ _In_ BOOLEAN fAtDispatch);
+
+NDIS_TIMER_FUNCTION TXSendCompleteDpc;
+
+KDEFERRED_ROUTINE RXReceiveIndicateDpc;
+
+VOID
+RXDeliverFrameToEveryAdapter(
+ _In_ PMP_ADAPTER SendAdapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame,
+ _In_ BOOLEAN fAtDispatch);
+
+VOID
+RXFlushReceiveQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PMP_ADAPTER_RECEIVE_DPC AdapterDpc);
+
+VOID
+TXFlushSendQueue(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_STATUS CompleteStatus);
+
+VOID
+NICStartTheDatapath(
+ _In_ PMP_ADAPTER Adapter);
+
+VOID
+NICStopTheDatapath(
+ _In_ PMP_ADAPTER Adapter);
+
+ULONG
+NICGetFrameTypeFromDestination(
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress);
+
+#endif // _DATAPATH_H
+
diff --git a/network/ndis/netvmini/6x/hardware.h b/network/ndis/netvmini/6x/hardware.h
new file mode 100644
index 00000000..c3076429
--- /dev/null
+++ b/network/ndis/netvmini/6x/hardware.h
@@ -0,0 +1,321 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Hardware.H
+
+Abstract:
+
+ This module defines constants that describe physical characteristics and
+ limits of the underlying hardware. While this miniport is virtual -- it
+ doesn't have any "real" hardware -- it emulates a fast Ethernet (802.3 at
+ 100 Mbit/s) link. Constants (like the 1514 byte frame size) are based on
+ typical Ethernet parameters.
+
+ TODO:
+ 1. Change the vendor name and ID from Microsoft.
+ 2. Update the hardware limits and physical adapter properties to match
+ those of your hardware.
+ 3. If your hardware does not use a 100 Mbit/s Ethernet medium, also
+ update the addressing, framing, and medium sections.
+
+--*/
+
+
+#ifndef _HARDWARE_H
+#define _HARDWARE_H
+
+
+//
+// Link layer addressing
+// -----------------------------------------------------------------------------
+//
+
+// Number of bytes in a hardware address. Ethernet uses 6 byte addresses.
+#define NIC_MACADDR_SIZE ETH_LENGTH_OF_ADDRESS
+
+// True iff the given address is a multicast address
+#define NIC_ADDR_IS_MULTICAST(_addr) ETH_IS_MULTICAST(_addr)
+
+// True iff the given address is a broadcast address
+#define NIC_ADDR_IS_BROADCAST(_addr) ETH_IS_BROADCAST(_addr)
+
+// Copies a hardware address from _src to _dest
+#define NIC_COPY_ADDRESS(_dest,_src) ETH_COPY_NETWORK_ADDRESS(_dest,_src)
+
+// True iff the given address was assigned by the local administrator
+#define NIC_ADDR_IS_LOCALLY_ADMINISTERED(_addr) \
+ (BOOLEAN)(((PUCHAR)(_addr))[0] & ((UCHAR)0x02))
+
+// True iff two addresses are equal
+#define NIC_ADDR_EQUAL(_a,_b) \
+ ((*(ULONG UNALIGNED *)&(_a)[2] == *(ULONG UNALIGNED *)&(_b)[2]) \
+ && (*(USHORT UNALIGNED *)(_a) == *(USHORT UNALIGNED *)(_b)))
+
+
+
+//
+// Frames
+// -----------------------------------------------------------------------------
+//
+
+#define HW_FRAME_HEADER_SIZE 14
+#define HW_FRAME_MAX_DATA_SIZE 1500
+#define HW_MAX_FRAME_SIZE (HW_FRAME_HEADER_SIZE + HW_FRAME_MAX_DATA_SIZE)
+#define HW_MIN_FRAME_SIZE 60
+
+typedef struct tagNIC_FRAME_HEADER
+{
+ UCHAR DestAddress[NIC_MACADDR_SIZE];
+ UCHAR SrcAddress[NIC_MACADDR_SIZE];
+ UCHAR EtherType[2];
+} NIC_FRAME_HEADER, *PNIC_FRAME_HEADER;
+
+C_ASSERT(sizeof(NIC_FRAME_HEADER) == HW_FRAME_HEADER_SIZE);
+
+#define GET_DESTINATION_OF_FRAME(_dest, _frame) NdisMoveMemory(_dest, ((PNIC_FRAME_HEADER)(_frame))->DestAddress, NIC_MACADDR_SIZE)
+
+//
+// Medium properties
+// -----------------------------------------------------------------------------
+//
+
+#define NIC_MEDIUM_TYPE NdisMedium802_3
+
+// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3.
+#define NIC_PHYSICAL_MEDIUM NdisPhysicalMediumUnspecified
+
+
+// Set this value to TRUE if there is a physical adapter.
+#define NIC_HAS_PHYSICAL_CONNECTOR FALSE
+#define NIC_ACCESS_TYPE NET_IF_ACCESS_BROADCAST
+#define NIC_DIRECTION_TYPE NET_IF_DIRECTION_SENDRECEIVE
+#define NIC_CONNECTION_TYPE NET_IF_CONNECTION_DEDICATED
+
+// This value must match the *IfType in the driver .inf file
+#define NIC_IFTYPE IF_TYPE_ETHERNET_CSMACD
+
+// Claim to be 100mbps duplex
+#define MEGABITS_PER_SECOND 1000000ULL
+#define NIC_XMIT_SPEED (100ULL*MEGABITS_PER_SECOND)
+#define NIC_RECV_SPEED (100ULL*MEGABITS_PER_SECOND)
+
+
+
+//
+// Hardware limits
+// -----------------------------------------------------------------------------
+//
+
+// Max number of multicast addresses supported in hardware
+#define NIC_MAX_MCAST_LIST 32
+
+// Maximum number of uncompleted sends that a single adapter will permit
+#define NIC_MAX_BUSY_SENDS 256
+
+// Maximum number of unreturned receives that a single adapter will permit
+#define NIC_MAX_BUSY_RECVS 256
+
+
+
+// Maximum number of send completes that will be processed per DPC.
+#define NIC_MAX_SENDS_PER_DPC 64
+
+//
+// Maximum number of receives that will be processed per DPC.
+// This constraints the amount of time spent for a single receive DPC.
+//
+#define NIC_MAX_RECVS_PER_DPC 64
+
+#define NIC_MAX_LOOKAHEAD HW_FRAME_MAX_DATA_SIZE
+#define NIC_BUFFER_SIZE HW_MAX_FRAME_SIZE
+
+
+// Simulated latency across the link. If this is set to zero, the driver
+// will saturate the link. Unfortunately, when the "link" is simulated in CPU,
+// that means that the CPU is saturated, and you hit DPC timeouts.
+// (This throttling isn't needed with a physical NIC)
+#define NIC_SIMULATED_LATENCY 0 // in 100ns units
+
+//
+// Physical adapter properties
+// -----------------------------------------------------------------------------
+//
+
+// The bus that connects the adapter to the PC.
+// (Example: PCI adapters should use NdisInterfacePci).
+#define NIC_INTERFACE_TYPE NdisInterfaceInternal
+
+// Change to your company name instead of using Microsoft
+#define NIC_VENDOR_DESC "Microsoft"
+
+// Highest byte is the NIC byte plus three vendor bytes. This is normally
+// obtained from the NIC.
+#define NIC_VENDOR_ID 0x00FFFFFF
+
+
+// Wakeup capabilities, as in OID_PNP_CAPABILITIES
+#define NIC_MAGIC_PACKET_WAKEUP NdisDeviceStateUnspecified
+#define NIC_PATTERN_WAKEUP NdisDeviceStateUnspecified
+#define NIC_LINK_CHANGE_WAKEUP NdisDeviceStateUnspecified
+
+
+#define NIC_SUPPORTED_FILTERS ( \
+ NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+
+//
+// This sample is a virtual device, so it can tolerate surprise removal
+// and suspend. Ensure the correct flags are set for your hardware.
+//
+// If your hardware supports busmaster DMA, you must specify
+// NDIS_MINIPORT_ATTRIBUTES_BUS_MASTER. Our virtual miniport will
+// not be allocating hardware resources such as interrupts, so we set the
+// WDM attribute.
+//
+#define NIC_ADAPTER_ATTRIBUTES_FLAGS (\
+ NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM)
+
+
+//
+// Specify a bitmask that defines optional properties of the NIC.
+// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists
+// function. Such a driver should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND
+// flag.
+//
+// NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal
+// loopback support so NDIS will manage loopbacks on behalf of
+// this driver.
+//
+// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that
+// our receive buffer is not on a device-specific card. If
+// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer
+// indications are copied to a single flat buffer.
+//
+#define NIC_MAC_OPTIONS (\
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \
+ NDIS_MAC_OPTION_NO_LOOPBACK | \
+ NDIS_MAC_OPTION_8021P_PRIORITY | \
+ NDIS_MAC_OPTION_8021Q_VLAN)
+
+// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS.
+#define NIC_SUPPORTED_STATISTICS (\
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | \
+ NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | \
+ NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT)
+
+#if (NDIS_SUPPORT_NDIS620)
+
+//
+// VMQ hardware information
+//
+
+//
+// The NIC must reserve at least one filter available HW queue. More filters allows
+// the VMQ queues to be assigned asymmetrically. For this sample we chose to allow
+// twice as many filters as queues.
+//
+#define NIC_SUPPORTED_NUM_QUEUES 8
+#define NIC_MAX_HEADER_FILTERS (NIC_SUPPORTED_NUM_QUEUES*2)
+
+//
+// Determines the minimum and maximum amount of lookahead split that we can do. Real hardware
+// might have tighter constraints on the range depending on the HW design.
+//
+#define NIC_MIN_LOOKAHEAD_SPLIT 64
+#define NIC_MAX_LOOKAHEAD_SPLIT 128
+
+//
+// Determines the minimum amount of receive blocks we will attempt to allocate if the full allocations fail and
+// we retry with a reduced count. If we fail with this amount we fail the allocation.
+//
+#define NIC_MIN_BUSY_RECVS 64
+
+#else
+
+//
+// No VMQ, define the queue count to 1 so that we only allocate the global receive block
+//
+#define NIC_SUPPORTED_NUM_QUEUES 1
+
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+
+//
+// NDIS QoS hardware information
+//
+
+//
+// Total number of general Traffic Classes (TCs) that the hardware supports, each of which is capable of but
+// not just limited to ETS functionality.
+//
+#define NIC_SUPPORTED_NUM_TCS 8
+
+//
+// Total number of TCs that the hardware supports that is capable of only ETS functionality.
+//
+#define NIC_SUPPORTED_NUM_ETS_CAPABLE_TCS NIC_SUPPORTED_NUM_TCS
+C_ASSERT(NIC_SUPPORTED_NUM_ETS_CAPABLE_TCS <= NIC_SUPPORTED_NUM_TCS);
+
+//
+// Number of simultaneous PFC-enabled TCs that the hardware can support.
+//
+#define NIC_SUPPORTED_NUM_PFC_ENABLED_TCS NIC_SUPPORTED_NUM_TCS
+C_ASSERT(NIC_SUPPORTED_NUM_PFC_ENABLED_TCS <= NIC_SUPPORTED_NUM_TCS);
+
+//
+// The Ethertype value for FCoE traffic and the default 802.1p priority assignment.
+//
+#define NIC_FCOE_ETHERTYPE 0x8906
+#define NIC_FCOE_PRIORITY 1
+
+//
+// The TCP port number for iSCSI traffic and the default 802.1p priority assignment.
+//
+#define NIC_ISCSI_TCP_PORT 3260
+#define NIC_ISCSI_PRIORITY 2
+
+//
+// Maximum number of classification entries that the miniport can support.
+//
+// In most cases, a standard NDIS QoS-compliant miniport will look for one or two very specific classification entries
+// and not implement a general classification mechanism as is done here.
+//
+// For example, a DCB-capable NIC with its own FCoE implementation would, in its NDIS QoS-compliant miniport, look for
+// a QoS classification entry specifying Ethertype 0x8906. The associated priority value would then be used in
+// all FCoE packets sent by that NIC.
+//
+#define NIC_SUPPORTED_NUM_CLASSIFICATIONS 2
+
+
+#endif
+
+#endif // _HARDWARE_H
+
diff --git a/network/ndis/netvmini/6x/miniport.c b/network/ndis/netvmini/6x/miniport.c
new file mode 100644
index 00000000..08d8cc3b
--- /dev/null
+++ b/network/ndis/netvmini/6x/miniport.c
@@ -0,0 +1,622 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Miniport.C
+
+Abstract:
+
+ The purpose of this sample is to illustrate functionality of a deserialized
+ NDIS miniport driver without requiring a physical network adapter. This
+ sample is based on E100BEX sample present in the DDK. It is basically a
+ simplified version of E100bex driver. The driver can be installed either
+ manually using Add Hardware wizard as a root enumerated virtual miniport
+ driver or on a virtual bus (like toaster bus). Since the driver does not
+ interact with any hardware, it makes it very easy to understand the miniport
+ interface and the usage of various NDIS functions without the clutter of
+ hardware specific code normally found in a fully functional driver.
+
+ This sample provides an example of minimal driver intended for education
+ purposes. Neither the driver or its sample test programs are intended
+ for use in a production environment.
+
+Revision History:
+
+Notes:
+
+--*/
+#include "netvmin6.h"
+#include "miniport.tmh"
+
+NDIS_STATUS
+DriverEntry(
+ _In_ PVOID DriverObject,
+ _In_ PVOID RegistryPath);
+
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+#pragma NDIS_PAGEABLE_FUNCTION(DriverUnload)
+
+
+MP_GLOBAL GlobalData;
+NDIS_HANDLE NdisDriverHandle;
+
+static
+NDIS_STATUS
+InitializeAdapterListLock();
+
+static
+VOID
+FreeAdapterListLock();
+
+NDIS_STATUS
+DriverEntry(
+ _In_ PVOID DriverObject,
+ _In_ PVOID RegistryPath)
+/*++
+Routine Description:
+
+ In the context of its DriverEntry function, a miniport driver associates
+ itself with NDIS, specifies the NDIS version that it is using, and
+ registers its entry points.
+
+
+Arguments:
+ PVOID DriverObject - pointer to the driver object.
+ PVOID RegistryPath - pointer to the driver registry path.
+
+ Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_MINIPORT_DRIVER_CHARACTERISTICS MPChar;
+
+ WPP_INIT_TRACING(DriverObject,RegistryPath);
+
+ DEBUGP(MP_TRACE, "---> DriverEntry built on "__DATE__" at "__TIME__ "\n");
+ PAGED_CODE();
+
+ do
+ {
+ //
+ // Initialize any driver-global variables here.
+ //
+
+ NdisZeroMemory(&GlobalData, sizeof(GlobalData));
+
+ //
+ // The ApaterList in the GlobalData structure is used to track multiple
+ // adapters controlled by this miniport.
+ //
+ NdisInitializeListHead(&GlobalData.AdapterList);
+
+
+ //
+ // The FrameDataLookaside list is used to help emulate an Ethernet hub.
+ //
+ NdisInitializeNPagedLookasideList(
+ &GlobalData.FrameDataLookaside,
+ HWFrameAllocate,
+ HWFrameFree,
+ 0, // Reserved for system use
+ sizeof(FRAME),
+ NIC_TAG_FRAME,
+ 0); // Reserved for system use
+ GlobalData.Flags |= fGLOBAL_LOOKASIDE_INITIALIZED;
+
+ //
+ // Fill in the Miniport characteristics structure with the version numbers
+ // and the entry points for driver-supplied MiniportXxx
+ //
+
+ NdisZeroMemory(&MPChar, sizeof(MPChar));
+
+
+#if (NDIS_SUPPORT_NDIS620)
+ {C_ASSERT(sizeof(MPChar) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2);}
+ MPChar.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+ MPChar.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+ MPChar.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+#elif (NDIS_SUPPORT_NDIS6)
+ {C_ASSERT(sizeof(MPChar) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1);}
+ MPChar.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+ MPChar.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
+ MPChar.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
+#endif // NDIS MINIPORT VERSION
+
+ MPChar.MajorNdisVersion = MP_NDIS_MAJOR_VERSION;
+ MPChar.MinorNdisVersion = MP_NDIS_MINOR_VERSION;
+
+ MPChar.MajorDriverVersion = NIC_MAJOR_DRIVER_VERSION;
+ MPChar.MinorDriverVersion = NIC_MINOR_DRIVER_VERISON;
+
+ MPChar.Flags = 0;
+
+ MPChar.SetOptionsHandler = MPSetOptions; // Optional
+ MPChar.InitializeHandlerEx = MPInitializeEx;
+ MPChar.HaltHandlerEx = MPHaltEx;
+ MPChar.UnloadHandler = DriverUnload;
+ MPChar.PauseHandler = MPPause;
+ MPChar.RestartHandler = MPRestart;
+ MPChar.OidRequestHandler = MPOidRequest;
+ MPChar.SendNetBufferListsHandler = MPSendNetBufferLists;
+ MPChar.ReturnNetBufferListsHandler = MPReturnNetBufferLists;
+ MPChar.CancelSendHandler = MPCancelSend;
+ MPChar.CheckForHangHandlerEx = MPCheckForHangEx;
+ MPChar.ResetHandlerEx = MPResetEx;
+ MPChar.DevicePnPEventNotifyHandler = MPDevicePnpEventNotify;
+ MPChar.ShutdownHandlerEx = MPShutdownEx;
+ MPChar.CancelOidRequestHandler = MPCancelOidRequest;
+
+ //
+ // Associate the miniport driver with NDIS by calling the
+ // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle.
+ // The miniport driver must retain this handle but it should never attempt
+ // to access or interpret this handle.
+ //
+ // By calling NdisMRegisterMiniportDriver, the driver indicates that it
+ // is ready for NDIS to call the driver's MiniportSetOptions and
+ // MiniportInitializeEx handlers.
+ //
+ DEBUGP(MP_LOUD, "Calling NdisMRegisterMiniportDriver...\n");
+ NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(MP_GLOBAL);
+ Status = NdisMRegisterMiniportDriver(
+ DriverObject,
+ RegistryPath,
+ &GlobalData,
+ &MPChar,
+ &NdisDriverHandle);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "NdisMRegisterMiniportDriver failed: %d\n", Status);
+ DriverUnload(DriverObject);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ GlobalData.Flags |= fGLOBAL_MINIPORT_REGISTERED;
+
+ //
+ // The AdapterListLock protects the AdapterList
+ //
+ Status = InitializeAdapterListLock();
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "InitializeAdapterListLock failed 0x%08x", Status);
+ DriverUnload(DriverObject);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ GlobalData.Flags |= fGLOBAL_LOCK_ALLOCATED;
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "<--- DriverEntry Status 0x%08x\n", Status);
+ return Status;
+}
+
+
+VOID
+DriverUnload(
+ _In_ PDRIVER_OBJECT DriverObject)
+/*++
+
+Routine Description:
+
+ The unload handler is called during driver unload to free up resources
+ acquired in DriverEntry. This handler is registered in DriverEntry through
+ NdisMRegisterMiniportDriver. Note that an unload handler differs from
+ a MiniportHalt function in that this unload handler releases resources that
+ are global to the driver, while the halt handler releases resource for a
+ particular adapter.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ DriverObject Not used
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ DEBUGP(MP_TRACE, "---> DriverUnload\n");
+ PAGED_CODE();
+
+
+ //
+ // Clean up all globals that were allocated in DriverEntry
+ //
+
+
+ ASSERT(IsListEmpty(&GlobalData.AdapterList));
+
+
+ if (GlobalData.Flags & fGLOBAL_MINIPORT_REGISTERED)
+ {
+ //
+ // Since DriverEntry has successfully called NdisMRegisterMiniportDriver,
+ // NdisMDeregisterMiniportDriver must be called to release NDIS's per-driver
+ // resources.
+ //
+ DEBUGP(MP_LOUD, "Calling NdisMDeregisterMiniportDriver...\n");
+ NdisMDeregisterMiniportDriver(NdisDriverHandle);
+ }
+
+ if (GlobalData.Flags & fGLOBAL_LOOKASIDE_INITIALIZED)
+ {
+ NdisDeleteNPagedLookasideList(&GlobalData.FrameDataLookaside);
+ }
+
+ if (GlobalData.Flags & fGLOBAL_LOCK_ALLOCATED)
+ {
+ FreeAdapterListLock();
+ }
+
+ WPP_CLEANUP(DriverObject->DeviceObject);
+
+ DEBUGP(MP_TRACE, "<--- DriverUnload\n");
+}
+
+
+NDIS_STATUS
+MPSetOptions(
+ _In_ NDIS_HANDLE DriverHandle,
+ _In_ NDIS_HANDLE DriverContext)
+/*++
+Routine Description:
+
+ The MiniportSetOptions function registers optional handlers. For each
+ optional handler that should be registered, this function makes a call
+ to NdisSetOptionalHandlers.
+
+ MiniportSetOptions runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ DriverContext The context handle
+
+Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_GLOBAL Global = (PMP_GLOBAL)DriverContext;
+
+ DEBUGP(MP_TRACE, "---> MPSetOptions\n");
+ UNREFERENCED_PARAMETER(DriverHandle);
+ UNREFERENCED_PARAMETER(Global);
+
+
+ //
+ // Set any optional handlers by filling out the appropriate struct and
+ // calling NdisSetOptionalHandlers here.
+ //
+
+
+ DEBUGP(MP_TRACE, "<--- MPSetOptions Status = 0x%08x\n", Status);
+ return Status;
+}
+
+BOOLEAN
+MPIsAdapterAttached(
+ _In_ PMP_ADAPTER Adapter)
+{
+ PLIST_ENTRY CurrentEntry = NULL;
+ for (
+ CurrentEntry = GlobalData.AdapterList.Flink;
+ CurrentEntry != &GlobalData.AdapterList;
+ CurrentEntry = CurrentEntry->Flink)
+ {
+ if(CurrentEntry == &Adapter->List)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+VOID
+MPAttachAdapter(
+ _In_ PMP_ADAPTER Adapter)
+{
+ MP_LOCK_STATE LockState;
+
+ DEBUGP(MP_TRACE, "[%p] ---> MPAttachAdapter\n", Adapter);
+
+ LOCK_ADAPTER_LIST_FOR_WRITE(&LockState, 0);
+
+ if(!MPIsAdapterAttached(Adapter))
+ {
+ InsertTailList(&GlobalData.AdapterList, &Adapter->List);
+ }
+
+ UNLOCK_ADAPTER_LIST(&LockState);
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPAttachAdapter\n", Adapter);
+}
+
+VOID
+MPDetachAdapter(
+ _In_ PMP_ADAPTER Adapter)
+{
+ MP_LOCK_STATE LockState;
+ DEBUGP(MP_TRACE, "[%p] ---> MPDetachAdapter\n", Adapter);
+
+ LOCK_ADAPTER_LIST_FOR_WRITE(&LockState, 0);
+
+ if(MPIsAdapterAttached(Adapter))
+ {
+ RemoveEntryList(&Adapter->List);
+ }
+
+ UNLOCK_ADAPTER_LIST(&LockState);
+
+ DEBUGP(MP_TRACE, "[%p] <--- MPDetachAdapter\n", Adapter);
+}
+
+
+#if (NDIS_SUPPORT_NDIS620)
+
+NDIS_STATUS
+InitializeAdapterListLock()
+{
+ GlobalData.Lock = NdisAllocateRWLock(NdisDriverHandle);
+ if (!GlobalData.Lock)
+ {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+FreeAdapterListLock()
+{
+ ASSERT(GlobalData.Lock);
+ NdisFreeRWLock(GlobalData.Lock);
+ GlobalData.Lock = NULL;
+}
+
+#elif (NDIS_SUPPORT_NDIS6)
+
+NDIS_STATUS
+InitializeAdapterListLock()
+{
+ NdisInitializeReadWriteLock(&GlobalData.Lock);
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+FreeAdapterListLock()
+{
+ // No action needed to clean up a NDIS 6.0 RW lock.
+}
+
+#endif
+
+
+
+#ifndef DBG
+
+VOID
+DbgPrintOidName(
+ _In_ NDIS_OID Oid)
+{
+ UNREFERENCED_PARAMETER(Oid);
+}
+
+VOID
+DbgPrintAddress(
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR Address)
+{
+ UNREFERENCED_PARAMETER(Address);
+}
+
+
+#else // DBG
+
+VOID
+DbgPrintOidName(
+ _In_ NDIS_OID Oid)
+{
+ PCHAR oidName = NULL;
+
+ switch (Oid){
+
+ #undef MAKECASE
+ #define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break;
+
+ /* Operational OIDs */
+ MAKECASE(OID_GEN_SUPPORTED_LIST)
+ MAKECASE(OID_GEN_HARDWARE_STATUS)
+ MAKECASE(OID_GEN_MEDIA_SUPPORTED)
+ MAKECASE(OID_GEN_MEDIA_IN_USE)
+ MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+ MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+ MAKECASE(OID_GEN_LINK_SPEED)
+ MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+ MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+ MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+ MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+ MAKECASE(OID_GEN_VENDOR_ID)
+ MAKECASE(OID_GEN_VENDOR_DESCRIPTION)
+ MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION)
+ MAKECASE(OID_GEN_CURRENT_PACKET_FILTER)
+ MAKECASE(OID_GEN_CURRENT_LOOKAHEAD)
+ MAKECASE(OID_GEN_DRIVER_VERSION)
+ MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+ MAKECASE(OID_GEN_PROTOCOL_OPTIONS)
+ MAKECASE(OID_GEN_MAC_OPTIONS)
+ MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS)
+ MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+ MAKECASE(OID_GEN_SUPPORTED_GUIDS)
+ MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+ MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+ MAKECASE(OID_GEN_MEDIA_CAPABILITIES)
+ MAKECASE(OID_GEN_PHYSICAL_MEDIUM)
+ MAKECASE(OID_GEN_MACHINE_NAME)
+ MAKECASE(OID_GEN_VLAN_ID)
+ MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
+
+ /* Operational OIDs for NDIS 6.0 */
+ MAKECASE(OID_GEN_MAX_LINK_SPEED)
+ MAKECASE(OID_GEN_LINK_STATE)
+ MAKECASE(OID_GEN_LINK_PARAMETERS)
+ MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
+ MAKECASE(OID_GEN_ENUMERATE_PORTS)
+ MAKECASE(OID_GEN_PORT_STATE)
+ MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS)
+ MAKECASE(OID_GEN_INTERRUPT_MODERATION)
+ MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX)
+
+ /* Statistical OIDs */
+ MAKECASE(OID_GEN_XMIT_OK)
+ MAKECASE(OID_GEN_RCV_OK)
+ MAKECASE(OID_GEN_XMIT_ERROR)
+ MAKECASE(OID_GEN_RCV_ERROR)
+ MAKECASE(OID_GEN_RCV_NO_BUFFER)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_RCV)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_RCV_CRC_ERROR)
+ MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+
+ /* Statistical OIDs for NDIS 6.0 */
+ MAKECASE(OID_GEN_STATISTICS)
+ MAKECASE(OID_GEN_BYTES_RCV)
+ MAKECASE(OID_GEN_BYTES_XMIT)
+ MAKECASE(OID_GEN_RCV_DISCARDS)
+ MAKECASE(OID_GEN_XMIT_DISCARDS)
+
+ /* Misc OIDs */
+ MAKECASE(OID_GEN_GET_TIME_CAPS)
+ MAKECASE(OID_GEN_GET_NETCARD_TIME)
+ MAKECASE(OID_GEN_NETCARD_LOAD)
+ MAKECASE(OID_GEN_DEVICE_PROFILE)
+ MAKECASE(OID_GEN_INIT_TIME_MS)
+ MAKECASE(OID_GEN_RESET_COUNTS)
+ MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS)
+
+ /* PnP power management operational OIDs */
+ MAKECASE(OID_PNP_CAPABILITIES)
+ MAKECASE(OID_PNP_SET_POWER)
+ MAKECASE(OID_PNP_QUERY_POWER)
+ MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_ENABLE_WAKE_UP)
+ MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST)
+
+ /* PnP power management statistical OIDs */
+ MAKECASE(OID_PNP_WAKE_UP_ERROR)
+ MAKECASE(OID_PNP_WAKE_UP_OK)
+
+ /* Ethernet operational OIDs */
+ MAKECASE(OID_802_3_PERMANENT_ADDRESS)
+ MAKECASE(OID_802_3_CURRENT_ADDRESS)
+ MAKECASE(OID_802_3_MULTICAST_LIST)
+ MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE)
+ MAKECASE(OID_802_3_MAC_OPTIONS)
+
+ /* Ethernet operational OIDs for NDIS 6.0 */
+ MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS)
+ MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS)
+
+ /* Ethernet statistical OIDs */
+ MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+ MAKECASE(OID_802_3_XMIT_ONE_COLLISION)
+ MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS)
+ MAKECASE(OID_802_3_XMIT_DEFERRED)
+ MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS)
+ MAKECASE(OID_802_3_RCV_OVERRUN)
+ MAKECASE(OID_802_3_XMIT_UNDERRUN)
+ MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+ MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+ MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS)
+
+ /* TCP/IP OIDs */
+ MAKECASE(OID_TCP_TASK_OFFLOAD)
+ MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA)
+ MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA)
+ MAKECASE(OID_TCP_SAN_SUPPORT)
+ MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
+ MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
+ MAKECASE(OID_TCP4_OFFLOAD_STATS)
+ MAKECASE(OID_TCP6_OFFLOAD_STATS)
+ MAKECASE(OID_IP4_OFFLOAD_STATS)
+ MAKECASE(OID_IP6_OFFLOAD_STATS)
+
+ /* TCP offload OIDs for NDIS 6 */
+ MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG)
+ MAKECASE(OID_TCP_OFFLOAD_PARAMETERS)
+ MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES)
+ MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG)
+ MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES)
+ MAKECASE(OID_OFFLOAD_ENCAPSULATION)
+
+#if (NDIS_SUPPORT_NDIS620)
+ /* VMQ OIDs for NDIS 6.20 */
+ MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE)
+ MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER)
+ MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE)
+ MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE)
+ MAKECASE(OID_RECEIVE_FILTER_SET_FILTER)
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+ /* NDIS QoS OIDs for NDIS 6.30 */
+ MAKECASE(OID_QOS_PARAMETERS)
+#endif
+ }
+
+ if (oidName)
+ {
+ DEBUGP(MP_LOUD, "%s", oidName);
+ }
+ else
+ {
+ DEBUGP(MP_LOUD, "<** Unknown OID 0x%08x **>\n", Oid);
+ }
+}
+
+VOID
+DbgPrintAddress(
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR Address)
+{
+ // If your MAC address has a different size, adjust the printf accordingly.
+ {C_ASSERT(NIC_MACADDR_SIZE == 6);}
+
+ DEBUGP(MP_LOUD, "%02x-%02x-%02x-%02x-%02x-%02x\n",
+ Address[0], Address[1], Address[2],
+ Address[3], Address[4], Address[5]);
+}
+
+
+
+#endif //DBG
+
diff --git a/network/ndis/netvmini/6x/miniport.h b/network/ndis/netvmini/6x/miniport.h
new file mode 100644
index 00000000..9b922b1a
--- /dev/null
+++ b/network/ndis/netvmini/6x/miniport.h
@@ -0,0 +1,255 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Miniport.H
+
+Abstract:
+
+ This module contains structure definitons and function prototypes.
+
+ TODO:
+ 1. Set the correct driver version number for your versioning scheme.
+ 2. Create unique memory allocation tags.
+
+ --*/
+
+
+#ifndef _MINIPORT_H
+#define _MINIPORT_H
+
+
+
+//
+// Update the driver version number every time you release a new driver
+// The high word is the major version. The low word is the minor version.
+// Also make sure that VER_FILEVERSION specified in the .RC file also
+// matches with the driver version because NDISTESTER checks for that.
+//
+// Let's say we're version 4.2.
+//
+#define NIC_MAJOR_DRIVER_VERSION 0x04
+#define NIC_MINOR_DRIVER_VERISON 0x02
+#define NIC_VENDOR_DRIVER_VERSION ((NIC_MAJOR_DRIVER_VERSION << 16) | NIC_MINOR_DRIVER_VERISON)
+
+
+
+//
+// Define the NDIS miniport interface version that this driver targets.
+//
+#if defined(NDIS60_MINIPORT)
+# define MP_NDIS_MAJOR_VERSION 6
+# define MP_NDIS_MINOR_VERSION 0
+#elif defined(NDIS620_MINIPORT)
+# define MP_NDIS_MAJOR_VERSION 6
+# define MP_NDIS_MINOR_VERSION 20
+#elif defined(NDIS630_MINIPORT)
+# define MP_NDIS_MAJOR_VERSION 6
+# define MP_NDIS_MINOR_VERSION 30
+#else
+# error Unsupported NDIS version
+#endif
+
+
+//
+// Memory allocation tags to help track and debug memory usage. Change these
+// for your miniport. You can add or remove tags as needed.
+//
+#define NIC_TAG ((ULONG)'_MVN') // NVM_
+#define NIC_TAG_TCB ((ULONG)'TMVN') // NVMT
+#define NIC_TAG_RCB ((ULONG)'RMVN') // NVMR
+#define NIC_TAG_RECV_NBL ((ULONG)'rMVN') // NVMr
+#define NIC_TAG_FRAME ((ULONG)'FMVN') // NVMF
+#define NIC_TAG_DPC ((ULONG)'DMVN') // NVMD
+#define NIC_TAG_TIMER ((ULONG)'tMVN') // NVMt
+
+#if (NDIS_SUPPORT_NDIS620)
+
+#define NIC_TAG_QUEUE_INFO ((ULONG)'QMVN') // NVMQ
+#define NIC_TAG_QUEUE_SHARED_MEM ((ULONG)'MMVN') // NVMM
+#define NIC_TAG_QUEUE_SHARED_MEM_BLOCK ((ULONG)'IMVN') // NVMB
+#define NIC_TAG_QUEUE_WORK_ITEM ((ULONG)'WMVN') // NVMW
+#define NIC_TAG_QUEUE_SG_LIST ((ULONG)'SMVN') // NVMS
+
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+
+#define NIC_TAG_QOS_PARAMS ((ULONG)'PMVN') // NVMP
+
+#endif
+
+#define NIC_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4
+
+
+
+//
+// Buffer size passed in NdisMQueryAdapterResources
+// We should only need three adapter resources (IO, interrupt and memory),
+// Some devices get extra resources, so have room for 10 resources
+//
+#define NIC_RESOURCE_BUF_SIZE \
+ (sizeof(NDIS_RESOURCE_LIST) + \
+ (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)))
+
+
+//
+// Utility macros
+// -----------------------------------------------------------------------------
+//
+
+#ifndef min
+#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif
+
+#ifndef max
+#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif
+
+
+
+#define LIST_ENTRY_FROM_NBL(_NBL) ((PLIST_ENTRY)&(_NBL)->MiniportReserved[0])
+#define NBL_FROM_LIST_ENTRY(_ENTRY) (CONTAINING_RECORD(_ENTRY, NET_BUFFER_LIST, MiniportReserved[0]))
+
+// Get a pointer to a LIST_ENTRY for the receive free list, from an NBL pointer
+#define RECV_FREE_LIST_FROM_NBL(_NBL) LIST_ENTRY_FROM_NBL(_NBL)
+
+// Get a pointer to a NBL, from a pointer to a LIST_ENTRY on the receive free list
+#define NBL_FROM_RECV_FREE_LIST(_ENTRY) NBL_FROM_LIST_ENTRY(_ENTRY)
+
+
+// Get a pointer to a LIST_ENTRY for the cancel list, from an NBL pointer
+#define CANCEL_LIST_FROM_NBL(_NBL) ((PSINGLE_LIST_ENTRY)&(_NBL)->MiniportReserved[0])
+
+// Get a pointer to a NBL, from a pointer to a LIST_ENTRY on the cancel list
+#define NBL_FROM_CANCEL_LIST(_ENTRY) NBL_FROM_LIST_ENTRY(_ENTRY)
+
+
+
+// Get a pointer to a LIST_ENTRY for the send wait list, from an NB pointer
+#define SEND_WAIT_LIST_FROM_NB(_NB) ((PLIST_ENTRY)&(_NB)->MiniportReserved[0])
+
+// Get a pointer to a NB, from a pointer to a LIST_ENTRY on the send wait list
+#define NB_FROM_SEND_WAIT_LIST(_ENTRY) (CONTAINING_RECORD(_ENTRY, NET_BUFFER, MiniportReserved[0]))
+
+
+// Get a pointer to an RCB from an NBL
+#define RCB_FROM_NBL(_NBL) (*((PRCB*)&(_NBL)->MiniportReserved[0]))
+
+// Gets the number of outstanding TCBs/NET_BUFFERs associated with
+// this NET_BUFFER_LIST
+#define SEND_REF_FROM_NBL(_NBL) (*((PLONG)&(_NBL)->MiniportReserved[1]))
+
+
+#define NBL_FROM_SEND_NB(_NB) (*((PNET_BUFFER_LIST*)&(_NB)->MiniportReserved[2]))
+
+#define FRAME_TYPE_FROM_SEND_NB(_NB) (*((PULONG)&(_NB)->MiniportReserved[3]))
+
+
+//
+// The NDIS_RW_LOCK_EX lock is more efficient (especially in the presence of
+// more than 64 CPUs), but it is only available on Windows 7 and later.
+//
+// These macros let us use the better lock if we are a 6.20 or better miniport,
+// or fallback to compiling against the 6.0 lock otherwise.
+//
+
+#if (NDIS_SUPPORT_NDIS620)
+# define MP_RW_LOCK_TYPE PNDIS_RW_LOCK_EX
+# define MP_LOCK_STATE LOCK_STATE_EX
+# define LOCK_ADAPTER_LIST_FOR_READ(STATE, FLAGS) NdisAcquireRWLockRead (GlobalData.Lock, STATE, FLAGS)
+# define LOCK_ADAPTER_LIST_FOR_WRITE(STATE, FLAGS) NdisAcquireRWLockWrite(GlobalData.Lock, STATE, FLAGS)
+# define UNLOCK_ADAPTER_LIST(STATE) NdisReleaseRWLock(GlobalData.Lock, STATE)
+#else
+# define MP_RW_LOCK_TYPE NDIS_RW_LOCK
+# define MP_LOCK_STATE LOCK_STATE
+# define LOCK_ADAPTER_LIST_FOR_READ(STATE, FLAGS) NdisAcquireReadWriteLock(&GlobalData.Lock, FALSE, STATE)
+# define LOCK_ADAPTER_LIST_FOR_WRITE(STATE, FLAGS) NdisAcquireReadWriteLock(&GlobalData.Lock, TRUE, STATE)
+# define UNLOCK_ADAPTER_LIST(STATE) NdisReleaseReadWriteLock(&GlobalData.Lock, STATE)
+#endif
+
+#define ACQUIRE_NDIS_SPINLOCK(_AtDpc, _SpinLock)\
+ if(_AtDpc)\
+ {\
+ NdisDprAcquireSpinLock(_SpinLock);\
+ }\
+ else\
+ {\
+ NdisAcquireSpinLock(_SpinLock);\
+ }
+
+#define RELEASE_NDIS_SPINLOCK(_AtDpc, _SpinLock)\
+ if(_AtDpc)\
+ {\
+ NdisDprReleaseSpinLock(_SpinLock);\
+ }\
+ else\
+ {\
+ NdisReleaseSpinLock(_SpinLock);\
+ }
+
+//
+// The driver has exactly one instance of the MP_GLOBAL structure. NDIS keeps
+// an opaque handle to this data, (it doesn't attempt to read or interpret this
+// data), and it passes the handle back to the miniport in MiniportSetOptions
+// and MiniportInitializeEx.
+//
+typedef struct _MP_GLOBAL
+{
+ LIST_ENTRY AdapterList;
+
+ MP_RW_LOCK_TYPE Lock;
+
+ NPAGED_LOOKASIDE_LIST FrameDataLookaside;
+
+#define fGLOBAL_LOCK_ALLOCATED 0x0001
+#define fGLOBAL_LOOKASIDE_INITIALIZED 0x0002
+#define fGLOBAL_MINIPORT_REGISTERED 0x0004
+ ULONG Flags;
+} MP_GLOBAL, *PMP_GLOBAL;
+
+struct _MP_ADAPTER;
+
+
+// Global data
+extern NDIS_HANDLE NdisDriverHandle;
+extern MP_GLOBAL GlobalData;
+
+
+
+// Miniport routines
+SET_OPTIONS MPSetOptions;
+
+
+void
+MPAttachAdapter(
+ _In_ struct _MP_ADAPTER *Adapter);
+
+void
+MPDetachAdapter(
+ _In_ struct _MP_ADAPTER *Adapter);
+
+BOOLEAN
+MPIsAdapterAttached(
+ _In_ struct _MP_ADAPTER *Adapter);
+
+
+VOID
+DbgPrintOidName(
+ _In_ NDIS_OID OidReqQuery);
+
+VOID
+DbgPrintAddress(
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR Address);
+
+
+#endif // _MINIPORT_H
+
+
diff --git a/network/ndis/netvmini/6x/mphal.c b/network/ndis/netvmini/6x/mphal.c
new file mode 100644
index 00000000..c7747319
--- /dev/null
+++ b/network/ndis/netvmini/6x/mphal.c
@@ -0,0 +1,1002 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ MpHAL.C
+
+Abstract:
+
+ This module implements the adapter's hardware.
+
+--*/
+
+
+#include "netvmin6.h"
+#include "mphal.tmh"
+
+//
+// This registry value saves the permanent MAC address of a netvmini NIC. It is
+// only needed because there's no hardware that keeps track of the permanent
+// address across reboots.
+//
+// It is saved as a NdisParameterBinary configuration value (REG_BINARY) with
+// length NIC_MACADDR_LEN (6 bytes).
+//
+#define NETVMINI_MAC_ADDRESS_KEY L"NetvminiMacAddress"
+
+
+static
+NDIS_STATUS
+HWCopyBytesFromNetBuffer(
+ _In_ PNET_BUFFER NetBuffer,
+ _Inout_ PULONG cbDest,
+ _Out_writes_bytes_to_(*cbDest, *cbDest) PVOID Dest);
+
+
+#pragma NDIS_PAGEABLE_FUNCTION(HWInitialize)
+#pragma NDIS_PAGEABLE_FUNCTION(HWReadPermanentMacAddress)
+
+
+
+
+NDIS_STATUS
+HWInitialize(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_MINIPORT_INIT_PARAMETERS InitParameters)
+/*++
+Routine Description:
+
+ Query assigned resources and initialize the adapter.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ InitParameters Parameters to MiniportInitializeEx
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_ADAPTER_NOT_FOUND
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc;
+ ULONG index;
+
+ UNREFERENCED_PARAMETER(Adapter);
+
+ DEBUGP(MP_TRACE, "[%p] ---> HWInitialize\n", Adapter);
+ PAGED_CODE();
+
+
+ do
+ {
+ if (InitParameters->AllocatedResources)
+ {
+ for (index=0; index < InitParameters->AllocatedResources->Count; index++)
+ {
+ pResDesc = &InitParameters->AllocatedResources->PartialDescriptors[index];
+
+ switch (pResDesc->Type)
+ {
+ case CmResourceTypePort:
+ DEBUGP(MP_INFO, "[%p] IoBaseAddress = 0x%x\n", Adapter,
+ NdisGetPhysicalAddressLow(pResDesc->u.Port.Start));
+ DEBUGP(MP_INFO, "[%p] IoRange = x%x\n", Adapter,
+ pResDesc->u.Port.Length);
+ break;
+
+ case CmResourceTypeInterrupt:
+ DEBUGP(MP_INFO, "[%p] InterruptLevel = x%x\n", Adapter,
+ pResDesc->u.Interrupt.Level);
+ break;
+
+ case CmResourceTypeMemory:
+ DEBUGP(MP_INFO, "[%p] MemPhysAddress(Low) = 0x%0x\n", Adapter,
+ NdisGetPhysicalAddressLow(pResDesc->u.Memory.Start));
+ DEBUGP(MP_INFO, "[%p] MemPhysAddress(High) = 0x%0x\n", Adapter,
+ NdisGetPhysicalAddressHigh(pResDesc->u.Memory.Start));
+ break;
+ }
+ }
+ }
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Map bus-relative IO range to system IO space using
+ // NdisMRegisterIoPortRange
+ //
+
+ //
+ // Map bus-relative registers to virtual system-space
+ // using NdisMMapIoSpace
+ //
+
+
+ //
+ // Disable interrupts here as soon as possible
+ //
+
+ //
+ // Register the interrupt using NdisMRegisterInterruptEx
+ //
+
+ //
+ // Initialize the hardware with mapped resources
+ //
+
+ //
+ // Enable the interrupt
+ //
+
+ } while (FALSE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- HWInitialize Status = 0x%x\n", Adapter, Status);
+ return Status;
+}
+
+VOID
+HWReadPermanentMacAddress(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Out_writes_bytes_(NIC_MACADDR_SIZE) PUCHAR PermanentMacAddress)
+/*++
+
+Routine Description:
+
+ Loads the permanent MAC address that is burnt into the NIC.
+
+ IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ ConfigurationHandle NIC configuration from NdisOpenConfigurationEx
+ PermanentMacAddress On return, receives the NIC's MAC address
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_CONFIGURATION_PARAMETER Parameter = NULL;
+ NDIS_STRING PermanentAddressKey = RTL_CONSTANT_STRING(NETVMINI_MAC_ADDRESS_KEY);
+
+ UNREFERENCED_PARAMETER(Adapter);
+ PAGED_CODE();
+
+ //
+ // We want to figure out what the NIC's physical address is.
+ // If we had a hardware NIC, we would query the physical address from it.
+ // Instead, for the purposes of this sample, we'll read it from the
+ // registry. This will help us keep the permanent address constant, even
+ // if the adapter is disabled/enabled.
+ //
+ // Note that the registry value that saves our permanent MAC address isn't
+ // the one that end-users can configure through the NIC management GUI,
+ // nor is it expected that other miniports would need to use a parameter
+ // like this. We only have it to work around the lack of physical hardware.
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigurationHandle,
+ &PermanentAddressKey,
+ NdisParameterBinary);
+ if (Status == NDIS_STATUS_SUCCESS
+ && Parameter->ParameterType == NdisParameterBinary
+ && Parameter->ParameterData.BinaryData.Length == NIC_MACADDR_SIZE)
+ {
+ //
+ // There is a permanent address stashed in the special netvmini
+ // parameter.
+ //
+ NIC_COPY_ADDRESS(PermanentMacAddress, Parameter->ParameterData.BinaryData.Buffer);
+ }
+ else
+ {
+ NDIS_CONFIGURATION_PARAMETER NewPhysicalAddress;
+ LARGE_INTEGER TickCountValue;
+ UCHAR CurrentMacIndex = 3;
+
+ //
+ // There is no (valid) address stashed in the netvmini parameter, so
+ // this is probably the first time we've loaded this adapter before.
+ //
+ // Just for testing purposes, let us make up a dummy mac address.
+ // In order to avoid conflicts with MAC addresses, it is usually a good
+ // idea to check the IEEE OUI list (e.g. at
+ // http://standards.ieee.org/regauth/oui/oui.txt). According to that
+ // list 00-50-F2 is owned by Microsoft.
+ //
+ // An important rule to "generating" MAC addresses is to have the
+ // "locally administered bit" set in the address, which is bit 0x02 for
+ // LSB-type networks like Ethernet. Also make sure to never set the
+ // multicast bit in any MAC address: bit 0x01 in LSB networks.
+ //
+
+ {C_ASSERT(NIC_MACADDR_SIZE > 3);}
+ NdisZeroMemory(PermanentMacAddress, NIC_MACADDR_SIZE);
+ PermanentMacAddress[0] = 0x02;
+ PermanentMacAddress[1] = 0x50;
+ PermanentMacAddress[2] = 0xF2;
+
+ //
+ // Generated value based on the current tick count value.
+ //
+ KeQueryTickCount(&TickCountValue);
+ do
+ {
+ //
+ // Pick up the value in groups of 8 bits to populate the rest of the MAC address.
+ //
+ PermanentMacAddress[CurrentMacIndex] = (UCHAR)(TickCountValue.LowPart>>((CurrentMacIndex-3)*8));
+ } while(++CurrentMacIndex < NIC_MACADDR_SIZE);
+
+ //
+ // Finally, we should make a best-effort attempt to save this address
+ // to our configuration, so the NIC will always come up with this
+ // permanent address.
+ //
+
+ NewPhysicalAddress.ParameterType = NdisParameterBinary;
+ NewPhysicalAddress.ParameterData.BinaryData.Length = NIC_MACADDR_SIZE;
+ NewPhysicalAddress.ParameterData.BinaryData.Buffer = PermanentMacAddress;
+
+ NdisWriteConfiguration(
+ &Status,
+ ConfigurationHandle,
+ &PermanentAddressKey,
+ &NewPhysicalAddress);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_WARNING, "[%p] NdisWriteConfiguration failed to save the permanent MAC address", Adapter);
+ // No other handling -- this isn't a fatal error
+ }
+ }
+}
+
+
+
+_IRQL_requires_same_
+_Function_class_(ALLOCATE_FUNCTION)
+PVOID
+HWFrameAllocate (
+ _In_ POOL_TYPE PoolType,
+ _In_ SIZE_T NumberOfBytes,
+ _In_ ULONG Tag)
+/*++
+
+Routine Description:
+
+ This routine allocates memory for a FRAME. It is an ALLOCATE_FUNCTION, so
+ its parameters and usage are the same as ExAllocatePoolWithTag.
+
+ This allocator is meant to be used with the send NPAGED_LOOKASIDE_LIST.
+ While you do not normally need to provide your own allocator (and in fact
+ there is a performance penalty for doing so), we use the allocator to
+ initialize the FRAME's MDL. This saves us the effort of (re)initializing
+ the same MDL every time we reuse the FRAME.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ PoolType Must be NonPagedPool, or NonPagedPoolNx for Win8
+ and later
+ NumberOfBytes Must be sizeof(FRAME)
+ Tag The pool allocation tag
+
+Return Value:
+
+ NULL if there are insufficient resources to allocate a FRAME.
+ Else, a pointer to a newly-allocated FRAME. Free it with HWFrameFree.
+
+--*/
+{
+ PFRAME Frame = NULL;
+
+ DEBUGP(MP_TRACE, "---> HWFrameAllocate\n");
+
+ UNREFERENCED_PARAMETER(PoolType);
+ ASSERT(NumberOfBytes == sizeof(FRAME));
+
+ Frame = (PFRAME) NdisAllocateMemoryWithTagPriority(
+ NdisDriverHandle,
+ (UINT)NumberOfBytes,
+ Tag,
+ NormalPoolPriority);
+ if (!Frame)
+ {
+ DEBUGP(MP_ERROR, "NdisAllocateMemoryWithTagPriority failed");
+ return NULL;
+ }
+ NdisZeroMemory(Frame, NumberOfBytes);
+
+ Frame->Mdl = NdisAllocateMdl(
+ NdisDriverHandle,
+ (PVOID)&Frame->Data[0],
+ sizeof(Frame->Data));
+ if (Frame->Mdl == NULL)
+ {
+ DEBUGP(MP_ERROR, "NdisAllocateMdl failed\n");
+ NdisFreeMemory(Frame, (UINT)NumberOfBytes, 0);
+ return NULL;
+ }
+
+ DEBUGP(MP_TRACE, "<--- HWFrameAllocate. Frame: %p\n", Frame);
+
+ return Frame;
+}
+
+
+_Use_decl_annotations_
+VOID
+HWFrameFree (
+ PVOID Memory)
+/*++
+
+Routine Description:
+
+ This routine frees memory for a FRAME. It is a FREE_FUNCTION, the
+ reciprocal of HWFrameAllocate.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Memory A buffer allocated with HWFrameAllocate
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFRAME Frame = (PFRAME) Memory;
+
+ DEBUGP(MP_TRACE, "---> HWFrameFree. Frame: %p\n", Frame);
+
+ ASSERT(Frame && Frame->Mdl);
+
+ NdisFreeMdl(Frame->Mdl);
+ NdisFreeMemory(Frame, sizeof(FRAME), 0);
+
+ DEBUGP(MP_TRACE, "<--- HWFrameFree\n");
+
+}
+
+
+VOID
+HWFrameReference(
+ _In_ PFRAME Frame)
+/*++
+
+Routine Description:
+
+ This routine increments the reference count of a FRAME.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Frame Frame to reference
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DEBUGP(MP_TRACE, "---> HWFrameReference. Frame: %p\n", Frame);
+
+ NdisInterlockedIncrement(&Frame->Ref);
+
+ DEBUGP(MP_TRACE, "<--- HWFrameReference. Frame: %p\n", Frame);
+
+}
+
+
+VOID
+HWFrameRelease(
+ _In_ PFRAME Frame)
+/*++
+
+Routine Description:
+
+ This routine decrements the reference count of a FRAME. If the last
+ refernce was released, the FRAME is freed back to the unused pool.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Frame Frame to release
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DEBUGP(MP_TRACE, "---> HWFrameRelease. Frame: %p\n", Frame);
+
+ if (0 == NdisInterlockedDecrement(&Frame->Ref))
+ {
+ DEBUGP(MP_TRACE, "---> Freeing Frame: %p\n", Frame);
+
+ NdisFreeToNPagedLookasideList(&GlobalData.FrameDataLookaside, Frame);
+ Frame = NULL;
+ }
+
+ DEBUGP(MP_TRACE, "<--- HWFrameRelease. Frame: %p\n", Frame);
+
+}
+
+
+NDIS_STATUS
+HWCopyBytesFromNetBuffer(
+ _In_ PNET_BUFFER NetBuffer,
+ _Inout_ PULONG cbDest,
+ _Out_writes_bytes_to_(*cbDest, *cbDest) PVOID Dest)
+/*++
+
+Routine Description:
+
+ Copies the first cbDest bytes from a NET_BUFFER. In order to show how the various data structures fit together, this
+ implementation copies the data by iterating through the MDLs for the NET_BUFFER. The NdisGetDataBuffer API also allows you
+ to copy a contiguous block of data from a NET_BUFFER.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ NetBuffer The NB to read
+ cbDest On input, the number of bytes in the buffer Dest
+ On return, the number of bytes actually copied
+ Dest On return, receives the first cbDest bytes of
+ the network frame in NetBuffer
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If the output buffer is larger than the NB's frame size, *cbDest will
+ contain the number of bytes in the frame size.
+
+ If the output buffer is smaller than the NB's frame size, only the first
+ *cbDest bytes will be copied (the buffer will receive a truncated copy of
+ the frame).
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ //
+ // Start copy from current MDL
+ //
+ PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
+ //
+ // Data on current MDL may be offset from start of MDL
+ //
+ ULONG DestOffset = 0;
+ while (DestOffset < *cbDest && CurrentMdl)
+ {
+ //
+ // Map MDL memory to System Address Space. LowPagePriority means mapping may fail if
+ // system is low on memory resources.
+ //
+ PUCHAR SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority);
+ ULONG Length = MmGetMdlByteCount(CurrentMdl);
+ if (!SrcMemory)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ if(DestOffset==0)
+ {
+ //
+ // The first MDL segment should be accessed from the current MDL offset
+ //
+ ULONG MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer);
+ SrcMemory += MdlOffset;
+ Length -= MdlOffset;
+ }
+
+ Length = min(Length, *cbDest-DestOffset);
+
+ //
+ // Copy Memory
+ //
+ NdisMoveMemory((PUCHAR)Dest+DestOffset, SrcMemory, Length);
+ DestOffset += Length;
+
+ //
+ // Get next MDL (if any available)
+ //
+ CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl);
+ }
+
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ *cbDest = DestOffset;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+HWGetDestinationAddress(
+ _In_ PNET_BUFFER NetBuffer,
+ _Out_writes_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress)
+/*++
+
+Routine Description:
+
+ Returns the destination address of a NET_BUFFER that is to be sent.
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ NetBuffer The NB containing the frame that is being sent
+ DestAddress On return, receives the frame's destination
+
+Return Value:
+
+ NDIS_STATUS_FAILURE The frame is too short
+ NDIS_STATUS_SUCCESS Else
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NIC_FRAME_HEADER Header;
+ ULONG cbHeader = sizeof(Header);
+
+ Status = HWCopyBytesFromNetBuffer(NetBuffer, &cbHeader, &Header);
+ if(Status == NDIS_STATUS_SUCCESS)
+ {
+ if (cbHeader < sizeof(Header))
+ {
+ NdisZeroMemory(DestAddress, NIC_MACADDR_SIZE);
+ Status = NDIS_STATUS_FAILURE;
+ }
+ else
+ {
+ GET_DESTINATION_OF_FRAME(DestAddress, &Header);
+ }
+ }
+ else
+ {
+ NdisZeroMemory(DestAddress, NIC_MACADDR_SIZE);
+ }
+
+ return Status;
+}
+
+BOOLEAN
+HWIsFrameAcceptedByPacketFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress,
+ _In_ ULONG FrameType)
+/*++
+
+Routine Description:
+
+ This routines checks to see whether the packet can be accepted
+ for transmission based on the currently programmed filter type
+ of the NIC and the mac address of the packet.
+
+ With real adapter, this routine would be implemented in hardware. However,
+ since we don't have any hardware to do the matching for us, we'll do it in
+ the driver.
+
+Arguments:
+
+ Adapter Our adapter that is receiving a frame
+ FrameData The raw frame, starting at the frame header
+ cbFrameData Number of bytes in the FrameData buffer
+
+Return Value:
+
+ TRUE if the frame is accepted by the packet filter, and should be indicated
+ up to the higher levels of the stack.
+
+ FALSE if the frame doesn't match the filter, and should just be dropped.
+
+--*/
+{
+ BOOLEAN result = FALSE;
+
+ DEBUGP(MP_LOUD, "[%p] ---> HWIsFrameAcceptedByPacketFilter PacketFilter = 0x%08x, FrameType = 0x%08x\n",
+ Adapter,
+ Adapter->PacketFilter,
+ FrameType);
+
+ do
+ {
+ //
+ // If the NIC is in promiscuous mode, we will accept anything
+ // and everything.
+ //
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ result = TRUE;
+ break;
+ }
+
+
+ switch (FrameType)
+ {
+ case NDIS_PACKET_TYPE_BROADCAST:
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ //
+ // If it's a broadcast packet and broadcast is enabled,
+ // we can accept that.
+ //
+ result = TRUE;
+ }
+ break;
+
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ //
+ // If it's a multicast packet and multicast is enabled,
+ // we can accept that.
+ //
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ {
+ result = TRUE;
+ break;
+ }
+ else if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST)
+ {
+ ULONG index;
+
+ //
+ // Check to see if the multicast address is in our list
+ //
+ ASSERT(Adapter->ulMCListSize <= NIC_MAX_MCAST_LIST);
+ for (index=0; index < Adapter->ulMCListSize && index < NIC_MAX_MCAST_LIST; index++)
+ {
+ if (NIC_ADDR_EQUAL(DestAddress, Adapter->MCList[index]))
+ {
+ result = TRUE;
+ break;
+ }
+ }
+ }
+ break;
+
+
+ case NDIS_PACKET_TYPE_DIRECTED:
+
+ if (Adapter->PacketFilter & NDIS_PACKET_TYPE_DIRECTED)
+ {
+ //
+ // This has to be a directed packet. If so, does packet dest
+ // address match with the mac address of the NIC.
+ //
+ if (NIC_ADDR_EQUAL(DestAddress, Adapter->CurrentAddress))
+ {
+ result = TRUE;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ } while(FALSE);
+
+
+ DEBUGP(MP_LOUD, "[%p] <--- HWIsFrameAcceptedByPacketFilter Result = %u\n", Adapter, result);
+ return result;
+}
+
+
+NDIS_MEDIA_CONNECT_STATE
+HWGetMediaConnectStatus(
+ _In_ PMP_ADAPTER Adapter)
+/*++
+
+Routine Description:
+
+ This routine will query the hardware and return
+ the media status.
+
+Arguments:
+
+ Adapter Our Adapter
+
+Return Value:
+
+ NdisMediaStateDisconnected or
+ NdisMediaStateConnected
+
+--*/
+{
+ if (MP_TEST_FLAG(Adapter, fMP_DISCONNECTED))
+ {
+ return MediaConnectStateDisconnected;
+ }
+ else
+ {
+ return MediaConnectStateConnected;
+ }
+}
+
+VOID
+HWProgramDmaForSend(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PTCB Tcb,
+ _In_ PNET_BUFFER NetBuffer,
+ _In_ BOOLEAN fAtDispatch)
+/*++
+
+Routine Description:
+
+ Program the hardware to read the data payload from the NET_BUFFER's MDL
+ and queue it for transmission. When the hardware has finished reading the
+ MDL, it will fire an interrupt to indicate that it no longer needs the MDL
+ anymore.
+
+ Our hardware, of course, doesn't have any DMA, so it just copies the data
+ to a FRAME structure and transmits that.
+
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Our adapter that will send a frame
+ Tcb The TCB that tracks the transmit status
+ NetBuffer Contains the data to send
+ fAtDispatch TRUE if the current IRQL is DISPATCH_LEVEL
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFRAME Frame;
+ NDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo = {0};
+ PNET_BUFFER_LIST Nbl = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP(MP_TRACE, "[%p] ---> HWProgramDmaForSend. NB: 0x%p\n", Adapter, NetBuffer);
+
+ do
+ {
+ //
+ // Program the hardware to begin reading the data from NetBuffer's MDL and
+ // queue it for transmission.
+ //
+
+ Tcb->NetBuffer = NetBuffer;
+ Tcb->BytesActuallySent = 0;
+
+ Frame = (PFRAME)NdisAllocateFromNPagedLookasideList(&GlobalData.FrameDataLookaside);
+
+ if (!Frame)
+ {
+ DEBUGP(MP_TRACE, "[%p] ---> No frames available for send.\n", Adapter);
+ //
+ // Oops, we couldn't get any more FRAMEs to send.
+ //
+ // When the SendComplete fires, we'll tell the driver that zero bytes
+ // were sent successfully. It will update the bookkeeping and inform
+ // the protocol that the NBL wasn't completely sent.
+ //
+ break;
+ }
+
+ DEBUGP(MP_TRACE, "[%p] Send Frame: 0x%p\n", Adapter, Frame);
+ ASSERT(NET_BUFFER_DATA_LENGTH(NetBuffer) <= NIC_BUFFER_SIZE);
+
+ Frame->Ref = 1;
+
+ //
+ // Copy the data from the NB to the FRAME's data region. This step roughly
+ // corresponds to a hardware DMA.
+ //
+ Frame->ulSize = min(NET_BUFFER_DATA_LENGTH(NetBuffer), NIC_BUFFER_SIZE);
+ Status = HWCopyBytesFromNetBuffer(NetBuffer, &Frame->ulSize, Frame->Data);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_TRACE, "[%p] ---> Failed to copy frame buffer. Result = %u\n", Adapter, Status);
+ break;
+ }
+
+ if (Frame->ulSize < HW_MIN_FRAME_SIZE)
+ {
+ // Don't leak the contents of kernel memory! Zero out padding bytes.
+ ULONG cbPaddingNeeded = HW_MIN_FRAME_SIZE - Frame->ulSize;
+ NdisZeroMemory(Frame->Data + Frame->ulSize, cbPaddingNeeded);
+ Frame->ulSize += cbPaddingNeeded;
+ }
+
+ ASSERT(Frame->ulSize >= HW_MIN_FRAME_SIZE && Frame->ulSize <= NIC_BUFFER_SIZE);
+
+
+ //
+ // For simplicity in the sample in order to support VLAN we extract the information from the NBL or frame and pass the
+ // NDIS_NET_BUFFER_LIST_8021Q_INFO structure to the code that simulates the send/receive. The code does nothing to convert
+ // modify the frame format.
+ // In real HW, on send the code should extract the information from the NBL and covert it to 802.1Q format for transmission, and
+ // on receive the adapter should detect if the packet is in 802.1Q format and if so convert it back to 802.3 before indicating it up to NDIS
+ // (populating the 8021Q info in the NBL being indicated).
+ //
+ Nbl = NBL_FROM_SEND_NB(NetBuffer);
+ Nbl1QInfo.Value = NET_BUFFER_LIST_INFO(Nbl, Ieee8021QNetBufferListInfo);
+
+ if(Nbl1QInfo.Value)
+ {
+ DEBUGP(MP_TRACE, "[%p] Send NBL (%p) OOB Vlan ID: %i\n", Adapter, Nbl, Nbl1QInfo.TagHeader.VlanId);
+ }
+ else
+ {
+ DEBUGP(MP_TRACE, "[%p] Send NBL (%p) has no OOB VLAN tag, checking frame header.\n", Adapter, Nbl);
+ if(IS_FRAME_8021Q(Frame))
+ {
+ //
+ // The frame has type of 802.1Q. Retrieve the VLAN information
+ //
+ COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(Nbl1QInfo, GET_FRAME_VLAN_TAG_HEADER(Frame));
+ DEBUGP(MP_TRACE, "[%p] Send NBL (%p) frame Vlan ID: %i\n", Adapter, Nbl, Nbl1QInfo.TagHeader.VlanId);
+ }
+ else
+ {
+ DEBUGP(MP_TRACE, "[%p] Send NBL (%p) has no VLAN information in its frame header.\n", Adapter, Nbl);
+ }
+ }
+
+ RXDeliverFrameToEveryAdapter(Adapter, &Nbl1QInfo, Frame, fAtDispatch);
+
+ Tcb->BytesActuallySent = Frame->ulSize;
+
+ } while(FALSE);
+
+ if(Frame)
+ {
+ HWFrameRelease(Frame);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- HWProgramDmaForSend\n", Adapter);
+
+}
+
+
+_IRQL_requires_(DISPATCH_LEVEL)
+ULONG
+HWGetBytesSent(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PTCB Tcb)
+/*++
+
+Routine Description:
+
+ When the adapter indicates it has completed the send operation, call this
+ routine to determine how many bytes were successfully sent (if any).
+
+Arguments:
+
+ Adapter Our adapter that will send a frame
+ Tcb The TCB that tracks the transmit status
+
+Return Value:
+
+ 0 There was an error sending this frame
+ >0 Number of bytes actually sent
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Adapter);
+
+ return Tcb->BytesActuallySent;
+}
+
+NDIS_STATUS
+HWBeginReceiveDma(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PRCB Rcb,
+ _In_ PFRAME Frame)
+/*++
+
+Routine Description:
+
+ Simulate the hardware deciding to receive a FRAME into one of its RCBs. In VMQ enabled scenarios, it will
+ find the matching queue and if matched retrieve the shared memory for the queue for the NBL. Otherwise, it
+ uses the existing Frame for the NBL.
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ Nbl1QInfo 8021Q Tag information for the FRAME being received
+ Rcb The RCB that tracks this receive operation
+ Frame The FRAME that to receive
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(Rcb->Nbl);
+
+ do
+ {
+ DEBUGP(MP_TRACE, "[%p] ---> HWBeginReceiveDma. Frame: 0x%p\n", Adapter, Frame);
+
+ //
+ // Preserve 802.1Q information, if specified.
+ //
+ if(Nbl1QInfo->Value)
+ {
+ DEBUGP(MP_TRACE, "[%p] Preserved VLAN Id=%i\n", Adapter, Nbl1QInfo->TagHeader.VlanId);
+ NET_BUFFER_LIST_INFO(Rcb->Nbl, Ieee8021QNetBufferListInfo) = Nbl1QInfo->Value;
+ }
+ else
+ {
+ DEBUGP(MP_TRACE, "[%p] No VLAN tag to preserve.\n", Adapter);
+ NET_BUFFER_LIST_INFO(Rcb->Nbl, Ieee8021QNetBufferListInfo) = 0;
+ }
+
+ //
+ // If VMQ is enabled, and we're not using the default queue,
+ // we need to copy the FRAME to the NBL's shared memory area
+ //
+ if(VMQ_ENABLED(Adapter))
+ {
+ BOOLEAN Copied;
+ Status = CopyFrameToRxQueueRcb(Adapter, Frame, Nbl1QInfo, Rcb, &Copied);
+ if(Copied || Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+ else
+ {
+ UNREFERENCED_PARAMETER(Adapter);
+ }
+
+ //
+ // Either 6.20 is not supported, VMQ is disabled, or matched default queue, so use existing frame memory for indication
+ //
+ HWFrameReference(Frame);
+ Rcb->Data = Frame;
+
+ NET_BUFFER_FIRST_MDL(NetBuffer) = Frame->Mdl;
+ NET_BUFFER_DATA_LENGTH(NetBuffer) = Frame->ulSize;
+ NET_BUFFER_DATA_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_CURRENT_MDL(NetBuffer) = NET_BUFFER_FIRST_MDL(NetBuffer);
+ NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = 0;
+
+ }
+ while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- HWBeginReceiveDma Status 0x%08x\n", Adapter, Status);
+ return Status;
+
+}
+
diff --git a/network/ndis/netvmini/6x/mphal.h b/network/ndis/netvmini/6x/mphal.h
new file mode 100644
index 00000000..5348545b
--- /dev/null
+++ b/network/ndis/netvmini/6x/mphal.h
@@ -0,0 +1,126 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ MpHAL.H
+
+Abstract:
+
+ This module declares the structures and functions that abstract the
+ adapter and medium's (emulated) hardware capabilities.
+
+--*/
+
+
+#ifndef _MPHAL_H
+#define _MPHAL_H
+
+
+//
+// A FRAME represents the physical bits as they are being transmitted on the
+// wire. Normally, a miniport wouldn't need to implement any such tracking,
+// but we have to simulate our own Ethernet hub.
+//
+typedef struct _FRAME
+{
+ volatile LONG Ref;
+ PMDL Mdl;
+ ULONG ulSize;
+ UCHAR Data[NIC_BUFFER_SIZE];
+} FRAME, *PFRAME;
+
+ALLOCATE_FUNCTION HWFrameAllocate;
+FREE_FUNCTION HWFrameFree;
+
+struct _TCB;
+struct _RCB;
+
+//
+// Structures and utility macros to retrieve and set VLAN tag related data
+//
+#define FRAME_8021Q_ETHER_TYPE 0x81
+#define IS_FRAME_8021Q(_Frame)\
+ (((PNIC_FRAME_HEADER)(_Frame)->Data)->EtherType[0] == FRAME_8021Q_ETHER_TYPE)
+
+typedef struct _VLAN_TAG_HEADER
+{
+ UCHAR TagInfo[2];
+} VLAN_TAG_HEADER, *PVLAN_TAG_HEADER;
+
+#define GET_FRAME_VLAN_TAG_HEADER(_Frame)\
+ ((VLAN_TAG_HEADER UNALIGNED *)((PNIC_FRAME_HEADER)(_Frame)->Data)->EtherType+1)
+
+#define USER_PRIORITY_MASK 0xe0
+#define CANONICAL_FORMAT_ID_MASK 0x10
+#define HIGH_VLAN_ID_MASK 0x0F
+
+#define COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(_Ieee8021qInfo, _pTagHeader) \
+{ \
+ (_Ieee8021qInfo).TagHeader.UserPriority = ((_pTagHeader->TagInfo[0] & USER_PRIORITY_MASK) >> 5); \
+ (_Ieee8021qInfo).TagHeader.CanonicalFormatId = ((_pTagHeader->TagInfo[0] & CANONICAL_FORMAT_ID_MASK) >> 4); \
+ (_Ieee8021qInfo).TagHeader.VlanId = (((USHORT)(_pTagHeader->TagInfo[0] & HIGH_VLAN_ID_MASK) << 8)| (USHORT)(_pTagHeader->TagInfo[1])); \
+}
+
+VOID
+HWFrameReference(
+ _In_ PFRAME Frame);
+
+VOID
+HWFrameRelease(
+ _In_ PFRAME Frame);
+
+NDIS_STATUS
+HWInitialize(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_HANDLE WrapperConfigurationContext);
+
+VOID
+HWReadPermanentMacAddress(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Out_writes_bytes_(NIC_MACADDR_SIZE) PUCHAR PermanentMacAddress);
+
+NDIS_STATUS
+HWGetDestinationAddress(
+ _In_ PNET_BUFFER NetBuffer,
+ _Out_writes_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress);
+
+BOOLEAN
+HWIsFrameAcceptedByPacketFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress,
+ _In_ ULONG FrameType);
+
+NDIS_MEDIA_CONNECT_STATE
+HWGetMediaConnectStatus(
+ _In_ PMP_ADAPTER Adapter);
+
+VOID
+HWProgramDmaForSend(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ struct _TCB *Tcb,
+ _In_ PNET_BUFFER NetBuffer,
+ _In_ BOOLEAN fAtDispatch);
+
+_IRQL_requires_(DISPATCH_LEVEL)
+ULONG
+HWGetBytesSent(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ struct _TCB *Tcb);
+
+NDIS_STATUS
+HWBeginReceiveDma(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ struct _RCB *Rcb,
+ _In_ PFRAME Frame);
+
+#endif // _MPHAL_H
+
diff --git a/network/ndis/netvmini/6x/netvmin6.h b/network/ndis/netvmini/6x/netvmin6.h
new file mode 100644
index 00000000..33419487
--- /dev/null
+++ b/network/ndis/netvmini/6x/netvmin6.h
@@ -0,0 +1,45 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Netvmin6.H
+
+Abstract:
+
+ This module collects all the headers needed to compile the netvmin6 sample.
+
+--*/
+
+
+#ifndef _NETVMIN6_H
+#define _NETVMIN6_H
+
+
+#include <ndis.h>
+
+
+// Tell the analysis tools that this code should be treated as a kernel driver.
+_Analysis_mode_(_Analysis_code_type_kernel_driver_);
+
+#include "trace.h"
+#include "hardware.h"
+#include "miniport.h"
+#include "vmq.h"
+#include "qos.h"
+#include "adapter.h"
+#include "mphal.h"
+#include "tcbrcb.h"
+#include "datapath.h"
+#include "ctrlpath.h"
+
+
+
+#endif // _NETVMIN6_H
+
diff --git a/network/ndis/netvmini/6x/netvmini.sln b/network/ndis/netvmini/6x/netvmini.sln
new file mode 100644
index 00000000..0485a5a1
--- /dev/null
+++ b/network/ndis/netvmini/6x/netvmini.sln
@@ -0,0 +1,59 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "60", "60", "{FB1356F7-2404-4CF8-8FF8-D9D99AB89F12}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "620", "620", "{9164ECBF-12E2-44DA-8038-3BD0F347C637}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "630", "630", "{2212DE82-26A1-46C0-810A-809089EC5623}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini60", "60\netvmini60.vcxproj", "{E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini620", "620\netvmini620.vcxproj", "{9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netvmini630", "630\netvmini630.vcxproj", "{20227FE5-F4F3-4980-98C2-B860C8B2F62C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|Win32.Build.0 = Debug|Win32
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|Win32.ActiveCfg = Release|Win32
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|Win32.Build.0 = Release|Win32
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|x64.ActiveCfg = Debug|x64
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Debug|x64.Build.0 = Debug|x64
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|x64.ActiveCfg = Release|x64
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B}.Release|x64.Build.0 = Release|x64
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|Win32.Build.0 = Debug|Win32
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|Win32.ActiveCfg = Release|Win32
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|Win32.Build.0 = Release|Win32
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|x64.ActiveCfg = Debug|x64
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Debug|x64.Build.0 = Debug|x64
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|x64.ActiveCfg = Release|x64
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D}.Release|x64.Build.0 = Release|x64
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|Win32.Build.0 = Debug|Win32
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|Win32.ActiveCfg = Release|Win32
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|Win32.Build.0 = Release|Win32
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|x64.ActiveCfg = Debug|x64
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Debug|x64.Build.0 = Debug|x64
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|x64.ActiveCfg = Release|x64
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {E1613ED0-DFEF-4C4D-8E06-6DB68964EE8B} = {FB1356F7-2404-4CF8-8FF8-D9D99AB89F12}
+ {9DA1838D-2D4D-4357-9E4A-49BF1A8E6B7D} = {9164ECBF-12E2-44DA-8038-3BD0F347C637}
+ {20227FE5-F4F3-4980-98C2-B860C8B2F62C} = {2212DE82-26A1-46C0-810A-809089EC5623}
+ EndGlobalSection
+EndGlobal
diff --git a/network/ndis/netvmini/6x/qos.c b/network/ndis/netvmini/6x/qos.c
new file mode 100644
index 00000000..a7b2e530
--- /dev/null
+++ b/network/ndis/netvmini/6x/qos.c
@@ -0,0 +1,653 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Qos.c
+
+Abstract:
+
+ This module implements the NDIS QOS related functionality for the adapter.
+
+--*/
+
+#include "netvmin6.h"
+#include "qos.tmh"
+
+
+#pragma NDIS_PAGEABLE_FUNCTION(ReadQOSConfig)
+#pragma NDIS_PAGEABLE_FUNCTION(SetQOSParameters)
+#pragma NDIS_PAGEABLE_FUNCTION(InitializeQOSConfig)
+
+
+//
+// The priority-to-TC assignment table below replicates the recommended mapping in
+// Table 8-4 of the IEEE 802.1Q spec. The table assumes the hardware supports 8
+// traffic classes.
+//
+C_ASSERT(NIC_SUPPORTED_NUM_TCS == 8);
+CONST UCHAR DefaultQOSPriorityAssignmentTable[NDIS_QOS_MAXIMUM_PRIORITIES] = { 1, 0, 2, 3, 4, 5, 6, 7 };
+
+//
+// By default, all TCs use ETS. Split the 100% bandwidth across all 8 TCs.
+//
+#define _S NDIS_QOS_TSA_STRICT
+#define _E NDIS_QOS_TSA_ETS
+CONST UCHAR DefaultQOSTsaAssignmentTable[NDIS_QOS_MAXIMUM_TRAFFIC_CLASSES] = { _E, _E, _E, _E, _E, _E, _E, _E };
+#undef _E
+#undef _S
+CONST UCHAR DefaultQOSTcBandwidthAssignmentTable[NDIS_QOS_MAXIMUM_TRAFFIC_CLASSES] = { 12, 13, 12, 13, 12, 13, 12, 13 };
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PNDIS_QOS_PARAMETERS
+CreateParameters(
+ _In_ ULONG NumTrafficClasses,
+ _In_reads_(NDIS_QOS_MAXIMUM_PRIORITIES) CONST UCHAR *PriorityAssignments,
+ _In_reads_(NDIS_QOS_MAXIMUM_TRAFFIC_CLASSES) CONST UCHAR *TcBandwidthAssignments,
+ _In_reads_(NDIS_QOS_MAXIMUM_TRAFFIC_CLASSES) CONST UCHAR *TsaAssignments,
+ _In_ ULONG PfcEnable,
+ _In_ ULONG NumClassificationElements,
+ _Post_
+ _When_(return != 0, _Deref_out_range_(>=, sizeof(NDIS_QOS_PARAMETERS)))
+ ULONG *MaxParamsSize
+ )
+/*++
+Routine Description:
+
+ This routine creates and initializes a new NDIS_QOS_PARAMETERS structure.
+
+--*/
+{
+ ULONG FirstElementOffset;
+ ULONG ParamSize;
+ PNDIS_QOS_PARAMETERS Parameters;
+
+ *MaxParamsSize = 0;
+
+ //
+ // Figure out the actual size of NDIS_QOS_PARAMETERS if it were to accommodate
+ // NumClassificationElements classification elements. Note that the first
+ // element must be aligned at the end of the parent NDIS_QOS_PARAMETERS
+ // structure.
+ //
+ ParamSize = sizeof(NDIS_QOS_PARAMETERS);
+ FirstElementOffset = ALIGN_UP(ParamSize, NDIS_QOS_CLASSIFICATION_ELEMENT);
+ ParamSize = FirstElementOffset + NumClassificationElements * sizeof(NDIS_QOS_CLASSIFICATION_ELEMENT);
+
+ //
+ // Allocate the NDIS_QOS_PARAMETERS structure.
+ //
+ Parameters =
+ NdisAllocateMemoryWithTagPriority(
+ NdisDriverHandle,
+ ParamSize,
+ NIC_TAG_QOS_PARAMS,
+ NormalPoolPriority);
+
+ if (Parameters == NULL)
+ {
+ DEBUGP(MP_ERROR, "Failed to allocate NDIS_QOS_PARAMETERS.\n");
+ return NULL;
+ }
+
+ //
+ // Initialize the structure.
+ //
+ NdisZeroMemory(Parameters, ParamSize);
+ Parameters->Header.Type = NDIS_OBJECT_TYPE_QOS_PARAMETERS;
+ Parameters->Header.Revision = NDIS_QOS_PARAMETERS_REVISION_1;
+ Parameters->Header.Size = (USHORT)FirstElementOffset;
+ Parameters->Flags = NDIS_QOS_PARAMETERS_ETS_CONFIGURED |
+ NDIS_QOS_PARAMETERS_PFC_CONFIGURED |
+ NDIS_QOS_PARAMETERS_CLASSIFICATION_CONFIGURED;
+ Parameters->NumTrafficClasses = NumTrafficClasses;
+ NdisMoveMemory(
+ Parameters->PriorityAssignmentTable,
+ PriorityAssignments,
+ sizeof(Parameters->PriorityAssignmentTable));
+ NdisMoveMemory(
+ Parameters->TcBandwidthAssignmentTable,
+ TcBandwidthAssignments,
+ sizeof(Parameters->TcBandwidthAssignmentTable));
+ NdisMoveMemory(
+ Parameters->TsaAssignmentTable,
+ TsaAssignments,
+ sizeof(Parameters->TsaAssignmentTable));
+ Parameters->PfcEnable = PfcEnable;
+ Parameters->ClassificationElementSize = sizeof(NDIS_QOS_CLASSIFICATION_ELEMENT);
+ Parameters->FirstClassificationElementOffset = FirstElementOffset;
+
+ *MaxParamsSize = ParamSize;
+
+ return Parameters;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PNDIS_QOS_PARAMETERS
+CreateDefaultOperationalParameters(
+ _In_ ULONG NumClassificationElements,
+ _Deref_out_range_(>=, sizeof(NDIS_QOS_PARAMETERS)) ULONG *MaxParamsSize
+ )
+/*++
+Routine Description:
+
+ This routine creates and initializes the default operational parameters, which is often implementation-
+ dependent.
+
+Remarks:
+
+ This example shows a simple case where a default set of PFC and ETS parameters are defined. When the
+ respective NDIS_QOS_PARAMETERS_ETS_CONFIGURED and NDIS_QOS_PARAMETERS_PFC_CONFIGURED flags are not set
+ in the NDIS_QOS_PARAMETERS structure given during OID_QOS_PARAMETERS, the default parameters will be
+ used instead.
+
+--*/
+{
+ return
+ CreateParameters(
+ NIC_SUPPORTED_NUM_TCS,
+ DefaultQOSPriorityAssignmentTable,
+ DefaultQOSTcBandwidthAssignmentTable,
+ DefaultQOSTsaAssignmentTable,
+ 0, // Flow control disabled on all priorities by default
+ NumClassificationElements,
+ MaxParamsSize);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+AddNewClassification(
+ _Inout_updates_bytes_to_(MaxParamsSize, Parameters->Header.Size) PNDIS_QOS_PARAMETERS Parameters,
+ _In_range_(>=, sizeof(NDIS_QOS_PARAMETERS)) ULONG MaxParamsSize,
+ _In_ USHORT ConditionSelector,
+ _In_ USHORT ConditionField,
+ _In_ USHORT ActionSelector,
+ _In_ USHORT ActionField
+ )
+/*++
+Routine Description:
+
+ This routine adds a new NDIS_QOS_CLASSIFICATION_ELEMENT to an existing NDIS_QOS_PARAMETERS created
+ using the CreateParameters routine.
+
+Remarks:
+
+ The NDIS_QOS_PARAMETERS structure is assumed to have preallocated enough storage to accommodate
+ all the new classification entries.
+
+--*/
+{
+ PNDIS_QOS_CLASSIFICATION_ELEMENT Element;
+
+ Element =
+ (PNDIS_QOS_CLASSIFICATION_ELEMENT)
+ ((PCHAR)Parameters +
+ Parameters->FirstClassificationElementOffset +
+ Parameters->ClassificationElementSize * Parameters->NumClassificationElements);
+
+ if ((PCHAR)Element + Parameters->ClassificationElementSize <= (PCHAR)Parameters + MaxParamsSize)
+ {
+ Element->Header.Type = NDIS_OBJECT_TYPE_QOS_CLASSIFICATION_ELEMENT;
+ Element->Header.Revision = NDIS_QOS_CLASSIFICATION_ELEMENT_REVISION_1;
+ Element->Header.Size = NDIS_SIZEOF_QOS_CLASSIFICATION_ELEMENT_REVISION_1;
+ Element->Flags = 0;
+ Element->ConditionSelector = ConditionSelector;
+ Element->ConditionField = ConditionField;
+ Element->ActionSelector = ActionSelector;
+ Element->ActionField = ActionField;
+
+ NT_ASSERT(Parameters->ClassificationElementSize <= sizeof(*Element));
+ _Analysis_assume_(Parameters->ClassificationElementSize <= sizeof(*Element));
+
+ Parameters->Header.Size += sizeof(*Element);
+ Parameters->NumClassificationElements++;
+ }
+ else
+ {
+ ASSERTMSG("Parameters buffer too small", 0);
+ }
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+IndicateParameters(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ NDIS_STATUS StatusCode,
+ _In_ PNDIS_QOS_PARAMETERS Parameters
+ )
+/*++
+Routine Description:
+
+ This routine indicates to NDIS a NDIS_QOS_PARAMETERS structure.
+
+--*/
+{
+ NDIS_STATUS_INDICATION Status = { 0 };
+
+ DEBUGP(MP_TRACE, "[%p] ---> IndicateParameters\n", Adapter);
+
+ Status.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ Status.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ Status.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+ Status.StatusCode = StatusCode;
+ Status.StatusBuffer = Parameters;
+ Status.StatusBufferSize = Parameters->Header.Size;
+
+ NdisMIndicateStatusEx(Adapter->AdapterHandle, &Status);
+
+ DEBUGP(MP_TRACE, "[%p] <--- IndicateParameters\n", Adapter);
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+ReadQOSConfig(
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will read the QOS configuration from the NDIS registry, and set the results to the QOSData flags field.
+
+Arguments:
+
+ ConfigurationHandle - Adapter configuration handle
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER Parameter;
+ NDIS_STRING QOSKeyword = NDIS_STRING_CONST("*QOS");
+
+ DEBUGP(MP_TRACE, "[%p] ---> ReadQOSConfig\n", Adapter);
+
+ PAGED_CODE();
+
+ do
+ {
+ //
+ // Read the *QOS flag (whether QOS is enabled on the adapter).
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigurationHandle,
+ &QOSKeyword,
+ NdisParameterInteger);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR,
+ "[%p] NdisReadConfiguration for *QOS failed Status 0x%08x, defaulting to disabled.\n",
+ Adapter,
+ Status);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (Parameter->ParameterData.IntegerData != 1)
+ {
+ break;
+ }
+
+ Adapter->QOSData.Flags |= fMP_QOS_ENABLED;
+
+ //
+ // Set up the current QOS capabilities. If QOS is enabled, the current
+ // capabilities will normally match the hardware capabilities, i.e.
+ // they are not configurable.
+ //
+ Adapter->QOSData.CurrentMaxNumTCs = NIC_SUPPORTED_NUM_TCS;
+ Adapter->QOSData.CurrentMaxNumEtsCapableTCs = min(NIC_SUPPORTED_NUM_ETS_CAPABLE_TCS, Adapter->QOSData.CurrentMaxNumTCs);
+ Adapter->QOSData.CurrentMaxNumPfcEnabledTCs = min(NIC_SUPPORTED_NUM_PFC_ENABLED_TCS, Adapter->QOSData.CurrentMaxNumTCs);
+
+ Status = NDIS_STATUS_SUCCESS;
+ } while (FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- ReadQOSConfig Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+SetQOSParameters(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_QOS_PARAMETERS Params)
+/*++
+Routine Description:
+
+ This routine will configure the classification table and validate the ETS and PFC parameters.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Params - Pointer to the new parameters
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_QOS_PARAMETERS OperationalParams;
+ ULONG MaxParamsSize;
+ UCHAR iSCSIPriority = NIC_ISCSI_PRIORITY;
+ UCHAR FCOEPriority = NIC_FCOE_PRIORITY;
+
+ PAGED_CODE();
+
+ DEBUGP(MP_TRACE, "[%p] ---> SetQOSParameters\n", Adapter);
+
+ OperationalParams =
+ CreateDefaultOperationalParameters(
+ NIC_SUPPORTED_NUM_CLASSIFICATIONS,
+ &MaxParamsSize);
+ if (OperationalParams == NULL)
+ {
+ //
+ // Unable to allocate operational parameters structure but this is not a deal breaker.
+ // Proceed to service the incoming NDIS_QOS_PARAMETERS.
+ //
+ DEBUGP(MP_ERROR, "Failed to allocate default NDIS_QOS_PARAMETERS\n");
+ }
+
+ if ((Params->Flags & (NDIS_QOS_PARAMETERS_ETS_CONFIGURED |
+ NDIS_QOS_PARAMETERS_PFC_CONFIGURED |
+ NDIS_QOS_PARAMETERS_CLASSIFICATION_CONFIGURED)) != 0)
+ {
+ if ((Params->Flags & (NDIS_QOS_PARAMETERS_ETS_CONFIGURED | NDIS_QOS_PARAMETERS_PFC_CONFIGURED)) !=
+ (NDIS_QOS_PARAMETERS_ETS_CONFIGURED | NDIS_QOS_PARAMETERS_PFC_CONFIGURED))
+ {
+ //
+ // ETS and PFC must be configured together.
+ //
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ //
+ // Enable ETS using the parameters in:
+ // - Params->PriorityAssignmentTable
+ // - Params->TcBandwidthAssignmentTable
+ // - Params->TsaAssignmentTable
+ //
+ // A real hardware-based implementation would program the ETS hardware here.
+ //
+ if (OperationalParams != NULL)
+ {
+ OperationalParams->NumTrafficClasses = Params->NumTrafficClasses;
+ NdisMoveMemory(
+ OperationalParams->PriorityAssignmentTable,
+ Params->PriorityAssignmentTable,
+ sizeof(Params->PriorityAssignmentTable));
+ NdisMoveMemory(
+ OperationalParams->TcBandwidthAssignmentTable,
+ Params->TcBandwidthAssignmentTable,
+ sizeof(Params->TcBandwidthAssignmentTable));
+ NdisMoveMemory(
+ OperationalParams->TsaAssignmentTable,
+ Params->TsaAssignmentTable,
+ sizeof(Params->TsaAssignmentTable));
+ }
+
+ //
+ // Enable PFC using the bitmap in Params->PfcEnable
+ //
+ // A real hardware-based implementation would program the PFC hardware here.
+ //
+ if (OperationalParams != NULL)
+ {
+ OperationalParams->PfcEnable = Params->PfcEnable;
+ }
+
+ //
+ // Process packet classification parameters.
+ //
+ iSCSIPriority = 0;
+ FCOEPriority = 0;
+
+ if (Params->Flags & NDIS_QOS_PARAMETERS_CLASSIFICATION_CONFIGURED)
+ {
+ //
+ // Packet classification enabled. Search for a classification element that matches the
+ // traffic type that your related hardware device or software driver (e.g. FCoE driver)
+ // sends.
+ //
+ PNDIS_QOS_CLASSIFICATION_ELEMENT Entry;
+ ULONG i;
+
+ Entry = (PNDIS_QOS_CLASSIFICATION_ELEMENT)((PCHAR)Params + Params->FirstClassificationElementOffset);
+
+ for (i = 0; i < Params->NumClassificationElements; i++)
+ {
+ NT_ASSERT((PCHAR)Entry + sizeof(*Entry) <= (PCHAR)Params + Params->Header.Size);
+ _Analysis_assume_((PCHAR)Entry + sizeof(*Entry) <= (PCHAR)Params + Params->Header.Size);
+
+ if (Entry->Header.Type == NDIS_OBJECT_TYPE_QOS_CLASSIFICATION_ELEMENT &&
+ Entry->Header.Revision == NDIS_QOS_CLASSIFICATION_ELEMENT_REVISION_1 &&
+ Entry->Header.Size >= NDIS_SIZEOF_QOS_CLASSIFICATION_ELEMENT_REVISION_1)
+ {
+ NT_ASSERT((PCHAR)Entry + Entry->Header.Size <= (PCHAR)Params + Params->Header.Size);
+ _Analysis_assume_((PCHAR)Entry + Entry->Header.Size <= (PCHAR)Params + Params->Header.Size);
+
+ if (Entry->ConditionSelector == NDIS_QOS_CONDITION_ETHERTYPE &&
+ Entry->ConditionField == NIC_FCOE_ETHERTYPE &&
+ Entry->ActionSelector == NDIS_QOS_ACTION_PRIORITY)
+ {
+ //
+ // Found a classification entry for FCoE. FCoE packets that directly originate
+ // from the device or driver are to be tagged with the 802.1p priority value
+ // stored in Entry->ActionField.
+ //
+ Entry->Flags |= NDIS_QOS_CLASSIFICATION_ENFORCED_BY_MINIPORT; // Acknowledge the classification
+ FCOEPriority = (UCHAR)Entry->ActionField;
+ }
+ else if (Entry->ConditionSelector == NDIS_QOS_CONDITION_TCP_PORT &&
+ Entry->ConditionField == NIC_ISCSI_TCP_PORT &&
+ Entry->ActionSelector == NDIS_QOS_ACTION_PRIORITY)
+ {
+ //
+ // Found a classification entry for iSCSI. iSCSI packets that directly originate
+ // from the device or driver are to be tagged with the 802.1p priority value
+ // stored in Entry->ActionField.
+ //
+ Entry->Flags |= NDIS_QOS_CLASSIFICATION_ENFORCED_BY_MINIPORT; // Acknowledge the classification
+ iSCSIPriority = (UCHAR)Entry->ActionField;
+ }
+ else if (Entry->ConditionSelector == NDIS_QOS_CONDITION_DEFAULT &&
+ Entry->ActionSelector == NDIS_QOS_ACTION_PRIORITY)
+ {
+ //
+ // Found a default classification entry. This entry, if present, is always located
+ // at the start of the classification array.
+ //
+ NT_ASSERT(i == 0);
+ iSCSIPriority = FCOEPriority = (UCHAR)Entry->ActionField;
+ }
+ }
+
+ Entry = (PNDIS_QOS_CLASSIFICATION_ELEMENT)((PCHAR)Entry + Params->ClassificationElementSize);
+ }
+ }
+ }
+ else
+ {
+ //
+ // ETS, PFC, and Classification settings not available. Use default.
+ //
+ }
+
+ if (OperationalParams != NULL)
+ {
+ AddNewClassification(
+ OperationalParams,
+ MaxParamsSize,
+ NDIS_QOS_CONDITION_ETHERTYPE,
+ NIC_FCOE_ETHERTYPE,
+ NDIS_QOS_ACTION_PRIORITY,
+ FCOEPriority);
+
+ AddNewClassification(
+ OperationalParams,
+ MaxParamsSize,
+ NDIS_QOS_CONDITION_TCP_PORT,
+ NIC_ISCSI_TCP_PORT,
+ NDIS_QOS_ACTION_PRIORITY,
+ iSCSIPriority);
+
+ //
+ // 'OperationalParams' contains the new operational parameters. An actual device will
+ // operate on these settings.
+ //
+ IndicateParameters(Adapter, NDIS_STATUS_QOS_OPERATIONAL_PARAMETERS_CHANGE, OperationalParams);
+ }
+
+Exit:
+ if (OperationalParams != NULL)
+ {
+ NdisFreeMemoryWithTagPriority(NdisDriverHandle, OperationalParams, NIC_TAG_QOS_PARAMS);
+ }
+
+ DEBUGP(MP_TRACE, "<--- [%p] SetQOSParameters Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+InitializeQOSConfig(
+ _Inout_ PMP_ADAPTER Adapter)
+/*++
+Routine Description:
+
+ This routine will set the supported and actual QOS capabilities for the miniport.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status;
+ NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES HardwareAssistAttributes;
+ NDIS_QOS_CAPABILITIES HwQosCapabilities;
+ NDIS_QOS_CAPABILITIES CurrentQosCapabilities;
+ PNDIS_QOS_PARAMETERS OperationalParams;
+ ULONG MaxParamsSize;
+
+ DEBUGP(MP_TRACE, "[%p] ---> InitializeQOSConfig\n", Adapter);
+
+ PAGED_CODE();
+
+ NdisZeroMemory(&HardwareAssistAttributes, sizeof(HardwareAssistAttributes));
+ HardwareAssistAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES;
+ HardwareAssistAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_3;
+ HardwareAssistAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_3;
+
+ //
+ // Set NIC QOS capabilities.
+ //
+ NdisZeroMemory(&HwQosCapabilities, sizeof(HwQosCapabilities));
+ HwQosCapabilities.Header.Type = NDIS_OBJECT_TYPE_QOS_CAPABILITIES;
+ HwQosCapabilities.Header.Revision = NDIS_QOS_CAPABILITIES_REVISION_1;
+ HwQosCapabilities.Header.Size = NDIS_SIZEOF_QOS_CAPABILITIES_REVISION_1;
+
+ HwQosCapabilities.Flags = NDIS_QOS_CAPABILITIES_STRICT_TSA_SUPPORTED;
+ HwQosCapabilities.MaxNumTrafficClasses = NIC_SUPPORTED_NUM_TCS;
+ HwQosCapabilities.MaxNumEtsCapableTrafficClasses = NIC_SUPPORTED_NUM_ETS_CAPABLE_TCS;
+ HwQosCapabilities.MaxNumPfcEnabledTrafficClasses = NIC_SUPPORTED_NUM_PFC_ENABLED_TCS;
+
+ HardwareAssistAttributes.HardwareQosCapabilities = &HwQosCapabilities;
+
+ //
+ // Set the actual NIC QOS capabilities.
+ //
+ NdisZeroMemory(&CurrentQosCapabilities, sizeof(CurrentQosCapabilities));
+ CurrentQosCapabilities.Header.Type = NDIS_OBJECT_TYPE_QOS_CAPABILITIES;
+ CurrentQosCapabilities.Header.Revision = NDIS_QOS_CAPABILITIES_REVISION_1;
+ CurrentQosCapabilities.Header.Size = NDIS_SIZEOF_QOS_CAPABILITIES_REVISION_1;
+
+ if (QOS_ENABLED(Adapter))
+ {
+ //
+ // Note: If QOS is disabled, all the following fields are set to 0.
+ //
+ CurrentQosCapabilities.Flags = NDIS_QOS_CAPABILITIES_STRICT_TSA_SUPPORTED;
+ CurrentQosCapabilities.MaxNumTrafficClasses = Adapter->QOSData.CurrentMaxNumTCs;
+ CurrentQosCapabilities.MaxNumEtsCapableTrafficClasses = Adapter->QOSData.CurrentMaxNumEtsCapableTCs;
+ CurrentQosCapabilities.MaxNumPfcEnabledTrafficClasses = Adapter->QOSData.CurrentMaxNumPfcEnabledTCs;
+ }
+
+ HardwareAssistAttributes.CurrentQosCapabilities = &CurrentQosCapabilities;
+
+ Status = NdisMSetMiniportAttributes(
+ Adapter->AdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&HardwareAssistAttributes);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisMSetMiniportAttributes Status 0x%08x\n", Adapter, Status);
+ }
+
+ //
+ // At this point, we can indicate up the default operational parameters.
+ //
+ if (QOS_ENABLED(Adapter))
+ {
+ OperationalParams = CreateDefaultOperationalParameters(NIC_SUPPORTED_NUM_CLASSIFICATIONS, &MaxParamsSize);
+
+ if (OperationalParams != NULL)
+ {
+ //
+ // Add default FCoE classification.
+ //
+ AddNewClassification(
+ OperationalParams,
+ MaxParamsSize,
+ NDIS_QOS_CONDITION_ETHERTYPE,
+ NIC_FCOE_ETHERTYPE,
+ NDIS_QOS_ACTION_PRIORITY,
+ NIC_FCOE_PRIORITY);
+
+ //
+ // Add default iSCSI classification.
+ //
+ AddNewClassification(
+ OperationalParams,
+ MaxParamsSize,
+ NDIS_QOS_CONDITION_TCP_PORT,
+ NIC_ISCSI_TCP_PORT,
+ NDIS_QOS_ACTION_PRIORITY,
+ NIC_ISCSI_PRIORITY);
+
+ IndicateParameters(Adapter, NDIS_STATUS_QOS_OPERATIONAL_PARAMETERS_CHANGE, OperationalParams);
+
+
+ NdisFreeMemoryWithTagPriority(NdisDriverHandle, OperationalParams, NIC_TAG_QOS_PARAMS);
+ }
+ else
+ {
+ DEBUGP(MP_ERROR, "Failed to allocate default NDIS_QOS_PARAMETERS\n");
+ }
+ }
+
+ DEBUGP(MP_TRACE, "<--- [%p] InitializeQOSConfig Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
diff --git a/network/ndis/netvmini/6x/qos.h b/network/ndis/netvmini/6x/qos.h
new file mode 100644
index 00000000..66a27483
--- /dev/null
+++ b/network/ndis/netvmini/6x/qos.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Qos.h
+
+Abstract:
+
+ This module declares the NDIS QoS related data types, flags, macros, and functions.
+
+Revision History:
+
+--*/
+
+#pragma once
+
+#if (NDIS_SUPPORT_NDIS630)
+
+//
+// The MP_ADAPTER_QOS_DATA structure is used to track the global QoS configuration for an adapter
+//
+typedef struct _MP_ADAPTER_QOS_DATA
+{
+ //
+ // Tracks global NDIS QoS state
+ //
+#define fMP_QOS_ENABLED 0x00000001
+ ULONG Flags;
+
+ //
+ // Current QoS capabilities
+ //
+ ULONG CurrentMaxNumTCs;
+ ULONG CurrentMaxNumEtsCapableTCs;
+ ULONG CurrentMaxNumPfcEnabledTCs;
+} MP_ADAPTER_QOS_DATA, *PMP_ADAPTER_QOS_DATA;
+
+#define QOS_ENABLED(_Adapter) \
+ ((_Adapter)->QOSData.Flags & fMP_QOS_ENABLED)
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+ReadQOSConfig(
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+SetQOSParameters(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_QOS_PARAMETERS Params);
+
+_IRQL_requires_(PASSIVE_LEVEL)
+NDIS_STATUS
+InitializeQOSConfig(
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+#else // NDIS_SUPPORT_NDIS630
+
+#define ReadQOSConfig(ConfigurationHandle, Adapter) NDIS_STATUS_SUCCESS
+#define InitializeQOSConfig(Adapter) NDIS_STATUS_SUCCESS
+
+#endif // NDIS_SUPPORT_NDIS630
diff --git a/network/ndis/netvmini/6x/tcbrcb.c b/network/ndis/netvmini/6x/tcbrcb.c
new file mode 100644
index 00000000..1d2faf50
--- /dev/null
+++ b/network/ndis/netvmini/6x/tcbrcb.c
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ TcbRcb.C
+
+Abstract:
+
+ This module contains miniport functions for handling Send & Receive
+ packets and other helper routines called by these miniport functions.
+
+ In order to excercise the send and receive code path of this driver,
+ you should install more than one instance of the miniport. If there
+ is only one instance installed, the driver throws the send packet on
+ the floor and completes the send successfully. If there are more
+ instances present, it indicates the incoming send packet to the other
+ instances. For example, if there 3 instances: A, B, & C installed.
+ Packets coming in for A instance would be indicated to B & C; packets
+ coming into B would be indicated to C, & A; and packets coming to C
+ would be indicated to A & B.
+
+Revision History:
+
+Notes:
+
+--*/
+
+#include "netvmin6.h"
+#include "tcbrcb.tmh"
+
+
+VOID
+ReturnTCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PTCB Tcb)
+{
+ TXNblRelease(Adapter, NBL_FROM_SEND_NB(Tcb->NetBuffer), TRUE);
+ Tcb->NetBuffer = NULL;
+
+ NdisInterlockedInsertTailList(
+ &Adapter->FreeTcbList,
+ &Tcb->TcbLink,
+ &Adapter->FreeTcbListLock);
+}
+
+
+
+_Must_inspect_result_
+_Success_(return != NULL)
+PRCB
+GetRCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame)
+/*++
+
+Routine Description:
+
+ This routine gets an unused RCB from the pool.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter The receiving adapter
+ Nbl1QInfo 8021Q Tag information for the FRAME being received
+ Frame The frame that will be attached to the RCB
+
+Return Value:
+
+ NULL if an RCB could not be allocated.
+ Else, a pointer to an initialized RCB.
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
+ PRCB Rcb = NULL;
+
+ DEBUGP(MP_TRACE, "[%p] ---> GetRCB.\n", Adapter);
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ // Retrieve the RCB from the target VMQ queue for the frame
+ //
+ GetRcbForRxQueue(Adapter, Frame, Nbl1QInfo, &Rcb);
+ }
+ else
+ {
+ //
+ // Retrieve the RCB from the global RCB pool
+ //
+ PLIST_ENTRY pEntry = NdisInterlockedRemoveHeadList(
+ &Adapter->FreeRcbList,
+ &Adapter->FreeRcbListLock);
+ if (pEntry)
+ {
+ Rcb = CONTAINING_RECORD(pEntry, RCB, RcbLink);
+ //
+ // Receiving on the default receive queue, increment its pending count
+ //
+ Status = NICReferenceReceiveBlock(Adapter, 0);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // The adapter is no longer in a ready state, so we were not able to take a reference on the
+ // receive block. Add the RCB back to the free list and fail this receive.
+ //
+ NdisInterlockedInsertTailList(
+ &Adapter->FreeRcbList,
+ &Rcb->RcbLink,
+ &Adapter->FreeRcbListLock);
+ Rcb = NULL;
+ }
+ }
+ }
+
+ if (Rcb)
+ {
+ //
+ // Simulate the hardware DMA'ing the received frame into the NB's MDL.
+ //
+ Status = HWBeginReceiveDma(Adapter, Nbl1QInfo, Rcb, Frame);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_TRACE, "[%p] HWBeginReceiveDma failed with error 0x%08x, aborting RCB allocation.\n", Adapter, Status);
+ //
+ // Increase failure counters if appropriate
+ //
+ if(Status == NDIS_STATUS_RESOURCES)
+ {
+ ++Adapter->RxResourceErrors;
+ }
+ else if(Status != NDIS_STATUS_INVALID_ADDRESS)
+ {
+ ++Adapter->RxRuntErrors;
+ }
+ //
+ // Recover RCB
+ //
+ ReturnRCB(Adapter, Rcb);
+ Rcb = NULL;
+ }
+ }
+ else
+ {
+ DEBUGP(MP_LOUD, "[%p] An RCB could not be retrieved. Status: 0x%08x.\n", Adapter, Status);
+ ++Adapter->RxResourceErrors;
+ }
+
+ DEBUGP(MP_LOUD, "[%p] Allocated RCB: %p.", Adapter, Rcb);
+ DEBUGP(MP_TRACE, "[%p] <--- GetRCB.\n", Adapter);
+
+ return Rcb;
+}
+
+
+VOID
+ReturnRCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PRCB Rcb)
+/*++
+
+Routine Description:
+
+ This routine frees an RCB back to the unused pool, recovers relevant memory used in the RCB.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter - The receiving adapter (the one that owns the RCB).
+ Rcb - The RCB to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUCHAR Data = Rcb->Data;
+ ASSERT(Data);
+
+ DEBUGP(MP_TRACE, "[%p] ---> ReturnRCB. RCB: %p\n", Adapter, Rcb);
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ // Recover RCB back to owner VMQ queue
+ //
+ RecoverRxQueueRcb(Adapter, Rcb);
+ }
+ else
+ {
+ //
+ // Recover RCB to global RCB pool
+ //
+ NdisInterlockedInsertTailList(
+ &Adapter->FreeRcbList,
+ &Rcb->RcbLink,
+ &Adapter->FreeRcbListLock);
+ Rcb = NULL;
+ //
+ // We receive on the default receive queue, decrement its pending count
+ //
+ NICDereferenceReceiveBlock(Adapter, 0, NULL);
+ HWFrameRelease((PFRAME)Data);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- ReturnRCB.\n", Adapter);
+
+}
+
+
diff --git a/network/ndis/netvmini/6x/tcbrcb.h b/network/ndis/netvmini/6x/tcbrcb.h
new file mode 100644
index 00000000..fca8f123
--- /dev/null
+++ b/network/ndis/netvmini/6x/tcbrcb.h
@@ -0,0 +1,81 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ TcbRcb.H
+
+Abstract:
+
+ This module declares the TCB and RCB structures, and the functions to
+ manipulate them.
+
+ See the comments in TcbRcb.c.
+
+--*/
+
+
+#ifndef _TCBRCB_H
+#define _TCBRCB_H
+
+
+
+//
+// TCB (Transmit Control Block)
+// -----------------------------------------------------------------------------
+//
+
+typedef struct _TCB
+{
+ LIST_ENTRY TcbLink;
+ PNET_BUFFER NetBuffer;
+ ULONG FrameType;
+ ULONG BytesActuallySent;
+} TCB, *PTCB;
+
+
+
+VOID
+ReturnTCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PTCB Tcb);
+
+
+//
+// RCB (Receive Control Block)
+// -----------------------------------------------------------------------------
+//
+
+typedef struct _RCB
+{
+ LIST_ENTRY RcbLink;
+ PNET_BUFFER_LIST Nbl;
+ PVOID Data;
+#if (NDIS_SUPPORT_NDIS620)
+ PVOID LookaheadData;
+#endif
+} RCB, *PRCB;
+
+_Must_inspect_result_
+_Success_(return != NULL)
+PRCB
+GetRCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PFRAME Frame);
+
+VOID
+ReturnRCB(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PRCB Rcb);
+
+
+
+#endif // _TCBRCB_H
+
diff --git a/network/ndis/netvmini/6x/trace.h b/network/ndis/netvmini/6x/trace.h
new file mode 100644
index 00000000..b42c5275
--- /dev/null
+++ b/network/ndis/netvmini/6x/trace.h
@@ -0,0 +1,38 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Trace.H
+
+Abstract:
+
+
+ --*/
+
+
+#ifndef _TRACE_H
+#define _TRACE_H
+
+//
+// Debug support macros
+// -----------------------------------------------------------------------------
+//
+
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(NetVMiniGUID,(AF864470,D828,4526,BF2C,22D3A5C98C4C), \
+ WPP_DEFINE_BIT(MP_ERROR) \
+ WPP_DEFINE_BIT(MP_WARNING) \
+ WPP_DEFINE_BIT(MP_TRACE) \
+ WPP_DEFINE_BIT(MP_INFO) \
+ WPP_DEFINE_BIT(MP_LOUD) \
+ )
+
+#endif
diff --git a/network/ndis/netvmini/6x/vmq.c b/network/ndis/netvmini/6x/vmq.c
new file mode 100644
index 00000000..d4e8fa7c
--- /dev/null
+++ b/network/ndis/netvmini/6x/vmq.c
@@ -0,0 +1,3123 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Vmq.c
+
+Abstract:
+
+ This module implements the VMQ related functionality for the adapter.
+
+--*/
+
+#include "netvmin6.h"
+#include "vmq.tmh"
+
+NDIS_STATUS
+FreeAdapterQueueInfo(
+ _In_ PMP_ADAPTER Adapter,
+ USHORT QueueId,
+ _In_opt_ PNDIS_OID_REQUEST NdisSetRequest);
+
+NDIS_STATUS
+InitializeAdapterQueueInfo(
+ _In_ PMP_ADAPTER Adapter,
+ _In_opt_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams,
+ _Out_ PMP_ADAPTER_QUEUE QueueInfo);
+
+NDIS_STATUS
+AllocateRxQueueReceiveMemory(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ PMP_ADAPTER_QUEUE Queue);
+
+NDIS_IO_WORKITEM_FUNCTION FreeRxQueuesWorkItem;
+
+NDIS_STATUS
+AllocateVMQData(
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will initialize the basic fields necessary for a MP_ADAPTER_VMQ_DATA structure. The function
+ should be called during adapter initialization, before any queues or filter requests are fielded.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ UINT i;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AllocateVMQData\n", Adapter);
+
+ do
+ {
+ NdisZeroMemory(VMQData, sizeof(MP_ADAPTER_VMQ_DATA));
+
+ //
+ // Initialize the locks for the queues
+ //
+ for(i=0; i<NIC_SUPPORTED_NUM_QUEUES;i++)
+ {
+ VMQData->RxQueues[i].QueueLock = NdisAllocateRWLock(Adapter->AdapterHandle);
+ if(!VMQData->RxQueues[i].QueueLock)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateRWLock failed for Queue %i.\n", Adapter, i);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ }
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Failed allocating the locks, need to fail this allocation
+ //
+ break;
+ }
+
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "<--- [%p] AllocateVMQData Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+NDIS_STATUS
+AllocateDefaultRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will allocate the default receive queue (MP_ADAPTER_QUEUE). The function
+ should be called during adapter initialization, before any queues or filter requests are fielded.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+
+ do
+ {
+ //
+ // Initialize the default queue.
+ // No need to take lock since this is done during adapter initialization. We won't be fielding receives until this is complete.
+ //
+ Status = InitializeAdapterQueueInfo(Adapter, NULL, &VMQData->RxQueues[0]);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed to initialize the default queue.\n", Adapter);
+ break;
+ }
+
+ //
+ // Allocate the receive memory (no shared memory is necessary)
+ //
+ Status = AllocateRxQueueReceiveMemory(Adapter, &VMQData->RxQueues[0]);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed to allocate the receive memory for the default queue.\n", Adapter);
+ break;
+ }
+
+ //
+ // Set default as completed. At this point the queue is ready for receives.
+ //
+ QUEUE_SET_FLAG(&VMQData->RxQueues[0], fMPAQI_COMPLETION_FINISHED);
+ } while(FALSE);
+
+ return Status;
+}
+
+NDIS_STATUS
+ReadRxQueueConfig(
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will read the VMQ configuration from the NDIS registry, and set the results to the VMQData flags field.
+
+Arguments:
+
+ ConfigurationHandle - Adapter configuration handle
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNDIS_CONFIGURATION_PARAMETER Parameter = NULL;
+ NDIS_STRING VMQKeyword = NDIS_STRING_CONST("*VMQ"),
+ LookaheadKeyword = NDIS_STRING_CONST("*VMQLookaheadSplit"),
+ FilteringKeyword = NDIS_STRING_CONST("*VMQVlanFiltering");
+
+ DEBUGP(MP_TRACE, "[%p] ---> ReadRxQueueConfig\n", Adapter);
+
+ do
+ {
+ //
+ // Read the *VMQ flag (whether VMQ is enabled on the adapter).
+ // Note: RSS and VMQ cannot be active simultaneously. If the miniport supports
+ // RSS, and the *RSS keyword is set to 1, then the *RssOrVmqPreference keyword
+ // must be used to determine which technology should be enabled on the adapter
+ // (0: enabled RSS, disable VMQ, 1: disable RSS, enable VMQ).
+ //
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigurationHandle,
+ &VMQKeyword,
+ NdisParameterInteger);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisReadConfiguration for *VMQ failed Status 0x%08x, defaulting to disabled.\n", Adapter, Status);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if(Parameter->ParameterData.IntegerData==1)
+ {
+ VMQ_SET_FLAG(Adapter, fMPVMQD_FILTERING_ENABLED);
+ }
+
+ //
+ // Read the *VMQLookaheadSplit flag (whether lookahead split is enabled on the adapter)
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigurationHandle,
+ &LookaheadKeyword,
+ NdisParameterInteger);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisReadConfiguration for *VMQLookaheadSplit failed Status 0x%08x, defaulting to disabled.\n", Adapter, Status);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else if(Parameter->ParameterData.IntegerData==1)
+ {
+ VMQ_SET_FLAG(Adapter, fMPVMQD_LOOKAHEAD_ENABLED);
+ }
+
+ //
+ // Read the *VMQVlanFiltering flag (whether lookahead split is enabled on the adapter)
+ //
+ NdisReadConfiguration(
+ &Status,
+ &Parameter,
+ ConfigurationHandle,
+ &FilteringKeyword,
+ NdisParameterInteger);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisReadConfiguration for *VMQVlanFiltering failed Status 0x%08x, defaulting to disabled.\n", Adapter, Status);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else if(Parameter->ParameterData.IntegerData==1)
+ {
+ VMQ_SET_FLAG(Adapter, fMPVMQD_VLANFILTER_ENABLED);
+ }
+
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- ReadRxQueueConfig Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+NDIS_STATUS
+InitializeRxQueueMPConfig(
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will set the supported and actual VMQ configuration for the miniport calling NdisMSetMiniportAttributes.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES HardwareAssistAttributes;
+ NDIS_RECEIVE_FILTER_CAPABILITIES HwCapabilities, CurrentCapabilities;
+ NDIS_NIC_SWITCH_CAPABILITIES HwSwitchCapabilities, CurrentSwitchCapabilities;
+
+ DEBUGP(MP_TRACE, "[%p] ---> InitializeRxQueueMPConfig\n", Adapter);
+
+ do
+ {
+ //
+ // Set the VMQ adapter capabilities.
+ //
+ NdisZeroMemory(&HardwareAssistAttributes, sizeof(HardwareAssistAttributes));
+
+ {C_ASSERT(sizeof(HardwareAssistAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_2);}
+ HardwareAssistAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES;
+ HardwareAssistAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_2;
+ HardwareAssistAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_2;
+
+ //
+ // Filter capabilities for VMQ
+ //
+
+ NdisZeroMemory(&HwCapabilities, sizeof(HwCapabilities));
+
+ //
+ // header fields
+ //
+ HwCapabilities.Header.Revision = NDIS_RECEIVE_FILTER_CAPABILITIES_REVISION_1;
+ HwCapabilities.Header.Size = NDIS_SIZEOF_RECEIVE_FILTER_CAPABILITIES_REVISION_1;
+ HwCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ //
+ // enable VMQ filters
+ //
+ HwCapabilities.EnabledFilterTypes = NDIS_RECEIVE_FILTER_VMQ_FILTERS_ENABLED;
+ //
+ // enable VMQ queues
+ //
+ HwCapabilities.EnabledQueueTypes = NDIS_RECEIVE_FILTER_VM_QUEUES_ENABLED;
+ //
+ // queue properties
+ //
+ HwCapabilities.NumQueues = NIC_SUPPORTED_NUM_QUEUES - 1;// First queue reserved for default
+ HwCapabilities.SupportedQueueProperties = NDIS_RECEIVE_FILTER_VM_QUEUE_SUPPORTED | NDIS_RECEIVE_FILTER_LOOKAHEAD_SPLIT_SUPPORTED;
+
+#if (NDIS_SUPPORT_NDIS630)
+ HwCapabilities.SupportedQueueProperties |= NDIS_RECEIVE_FILTER_DYNAMIC_PROCESSOR_AFFINITY_CHANGE_SUPPORTED;
+#endif
+
+ HwCapabilities.SupportedFilterTests = NDIS_RECEIVE_FILTER_TEST_HEADER_FIELD_EQUAL_SUPPORTED;
+ HwCapabilities.SupportedHeaders = NDIS_RECEIVE_FILTER_MAC_HEADER_SUPPORTED;
+ HwCapabilities.SupportedMacHeaderFields = NDIS_RECEIVE_FILTER_MAC_HEADER_DEST_ADDR_SUPPORTED | NDIS_RECEIVE_FILTER_MAC_HEADER_VLAN_ID_SUPPORTED;
+ HwCapabilities.MaxMacHeaderFilters = NIC_MAX_HEADER_FILTERS;
+ HwCapabilities.MinLookaheadSplitSize = NIC_MIN_LOOKAHEAD_SPLIT;
+ HwCapabilities.MaxLookaheadSplitSize = NIC_MAX_LOOKAHEAD_SPLIT;
+ HardwareAssistAttributes.HardwareReceiveFilterCapabilities = &HwCapabilities;
+
+ //
+ // Set the actual VMQ adapter configuration.
+ //
+
+ NdisZeroMemory(&CurrentCapabilities, sizeof(CurrentCapabilities));
+
+ //
+ // header fields
+ //
+ CurrentCapabilities.Header.Revision = NDIS_RECEIVE_FILTER_CAPABILITIES_REVISION_1;
+ CurrentCapabilities.Header.Size = NDIS_SIZEOF_RECEIVE_FILTER_CAPABILITIES_REVISION_1;
+ CurrentCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ //set equal to HW capabilities, which has all the supported options set, and then remove optional disabled capabilties
+ //
+ memcpy(&CurrentCapabilities, &HwCapabilities, sizeof(CurrentCapabilities));
+ if(!LOOKAHEAD_SPLIT_ENABLED(Adapter))
+ {
+ //
+ // Remove lookahead split capability flag, as it's disabled in the driver configuration
+ //
+ CurrentCapabilities.SupportedQueueProperties &= ~NDIS_RECEIVE_FILTER_LOOKAHEAD_SPLIT_SUPPORTED;
+ }
+ if(!VLAN_FILTER_ENABLED(Adapter))
+ {
+ //
+ // Remove lookahead vlan filtering capability flag, as it's disabled in the driver configuration
+ //
+ CurrentCapabilities.SupportedMacHeaderFields &= ~NDIS_RECEIVE_FILTER_MAC_HEADER_VLAN_ID_SUPPORTED;
+ }
+ }
+
+ //
+ // Set NIC switch adapter capabilities.
+ //
+ HardwareAssistAttributes.CurrentReceiveFilterCapabilities = &CurrentCapabilities;
+
+ NdisZeroMemory(&HwSwitchCapabilities, sizeof(HwSwitchCapabilities));
+
+ HwSwitchCapabilities.Header.Revision = NDIS_NIC_SWITCH_CAPABILITIES_REVISION_1;
+ HwSwitchCapabilities.Header.Size = NDIS_SIZEOF_NIC_SWITCH_CAPABILITIES_REVISION_1;
+ HwSwitchCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+
+ //
+ // The NIC's limits corresponds to the maximum number of filters supported.
+ //
+ HwSwitchCapabilities.NumTotalMacAddresses = NIC_MAX_HEADER_FILTERS;
+ HwSwitchCapabilities.NumMacAddressesPerPort = NIC_MAX_HEADER_FILTERS;
+ HwSwitchCapabilities.NumVlansPerPort = NIC_MAX_HEADER_FILTERS;
+
+ HardwareAssistAttributes.HardwareNicSwitchCapabilities = &HwSwitchCapabilities;
+
+ //
+ // Set the actual NIC switch adapter configuration.
+ //
+ NdisZeroMemory(&CurrentSwitchCapabilities, sizeof(CurrentSwitchCapabilities));
+
+ CurrentSwitchCapabilities.Header.Revision = NDIS_NIC_SWITCH_CAPABILITIES_REVISION_1;
+ CurrentSwitchCapabilities.Header.Size = NDIS_SIZEOF_NIC_SWITCH_CAPABILITIES_REVISION_1;
+ CurrentSwitchCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+
+ if(VMQ_ENABLED(Adapter))
+ {
+ //
+ // Set equal to HW capabilities, which has all the supported options set.
+ //
+ memcpy(&CurrentSwitchCapabilities, &HwSwitchCapabilities, sizeof(CurrentSwitchCapabilities));
+ }
+
+ HardwareAssistAttributes.CurrentNicSwitchCapabilities = &CurrentSwitchCapabilities;
+
+ Status = NdisMSetMiniportAttributes(
+ Adapter->AdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&HardwareAssistAttributes);
+ if (NDIS_STATUS_SUCCESS != Status)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisMSetMiniportAttributes Status 0x%08x\n", Adapter, Status);
+ break;
+ }
+
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- InitializeRxQueueMPConfig Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+BOOLEAN
+ValidGroupAffinity(
+_In_ PGROUP_AFFINITY GroupAffinity)
+/*++
+Routine Description:
+
+ This routine will verify that the passed in group affinity contains valid values.
+
+ Runs at any IRQL.
+
+Arguments:
+
+ GroupAffinity - Affinity to verify
+
+Return Value:
+
+ TRUE - Affinity is valid
+ FALSE - Affinity is invalid
+
+--*/
+{
+ //
+ // GetActiveProcessorCount will validate the group value
+ //
+ #pragma warning( suppress: 28193 ) // we check ProcessorNumber result later in code
+ UCHAR ProcessorNumber = RtlFindLeastSignificantBit((ULONGLONG)GroupAffinity->Mask);
+ ULONG ActiveProcessors = KeQueryActiveProcessorCountEx(GroupAffinity->Group);
+
+ if(!ActiveProcessors)
+ {
+ //
+ // Group was invalid
+ //
+ DEBUGP(MP_TRACE, "ValidGroupAffinity failed (KeQueryActiveProcessorCountEx error). Group: 0x%x, Mask: 0x%I64x\n",
+ GroupAffinity->Group, GroupAffinity->Mask);
+ return FALSE;
+ }
+
+ if(ProcessorNumber == -1)
+ {
+ //
+ // The affinity mask must be non-zero (RtlFindLeastSignificantBit returns -1 if there aren't any non-zero bits)
+ //
+ DEBUGP(MP_TRACE, "ValidGroupAffinity failed (zero mask). Group: 0x%x, Mask: 0x%I64x\n", GroupAffinity->Group, GroupAffinity->Mask);
+ return FALSE;
+ }
+
+ if(ProcessorNumber >= ActiveProcessors)
+ {
+ //
+ // The processor number is out of range
+ //
+ DEBUGP(MP_TRACE, "ValidGroupAffinity failed (processor number out of range). Group: 0x%x, Mask: 0x%I64x, ProcessorNumber: %i, ActiveProcessors: %i\n",
+ GroupAffinity->Group, GroupAffinity->Mask, ProcessorNumber, ActiveProcessors);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+NDIS_STATUS
+InitializeAdapterQueueInfo(
+ _In_ PMP_ADAPTER Adapter,
+ _In_opt_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams,
+ _Out_ PMP_ADAPTER_QUEUE QueueInfo)
+/*++
+Routine Description:
+
+ This routine will allocate the PMP_ADAPTER_QUEUE structure passed in using the QueueParams specified.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueParams - NDIS_RECEIVE_QUEUE_PARAMETERS data that define the configuration for the queue
+ QueueInfo - Pointer to PMP_ADAPTER_QUEUE to derefence and allocate
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_RECEIVE_QUEUE_ID QueueId = 0;
+
+ DEBUGP(MP_TRACE, "[%p] ---> InitializeAdapterQueueInfo\n", Adapter);
+
+ do
+ {
+ if(QueueParams)
+ {
+ if(!ValidGroupAffinity(&QueueParams->ProcessorAffinity))
+ {
+ DEBUGP(MP_ERROR, "[%p] Requested group affinity failed validation\n", Adapter);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ QueueId = QueueParams->QueueId;
+ //
+ // Copy relevant data from the request
+ //
+ QueueInfo->QueueId = QueueId;
+ QueueInfo->NumSuggestedReceiveBuffers = QueueParams->NumSuggestedReceiveBuffers;
+ if(QueueParams->LookaheadSize)
+ {
+ if(QueueParams->LookaheadSize<NIC_MIN_LOOKAHEAD_SPLIT)
+ {
+ //
+ // A smaller lookahead has been requested than what's supported, use our supported minimum
+ //
+ QueueInfo->LookaheadSize = NIC_MIN_LOOKAHEAD_SPLIT;
+ DEBUGP(MP_INFO, "[%p] Requested LA size (%i) for Queue %i is too small, using our minium (%i)\n", Adapter, QueueParams->LookaheadSize, QueueId, NIC_MIN_LOOKAHEAD_SPLIT);
+ }
+ else if(QueueParams->LookaheadSize>NIC_MAX_LOOKAHEAD_SPLIT)
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ DEBUGP(MP_ERROR, "[%p] Requested LA size (%i) for Queue %i is above our maximum (%i), the request has failed.\n", Adapter, QueueParams->LookaheadSize, QueueId, NIC_MAX_LOOKAHEAD_SPLIT);
+ break;
+ }
+ else
+ {
+ QueueInfo->LookaheadSize = QueueParams->LookaheadSize;
+ }
+ }
+
+
+ QueueInfo->NdisFlags = QueueParams->Flags & (~NDIS_RECEIVE_QUEUE_PARAMETERS_CHANGE_MASK);
+ QueueInfo->ProcessorAffinity = QueueParams->ProcessorAffinity;
+ }
+
+ //
+ // Please note that for PCI hardware, rather than maintaining DPCs with differing affinities for receives as we do in this
+ // software implementation, the affinity information would instead be applied to the MSI-X configuration.
+ //
+
+ if(QueueParams)
+ {
+ //
+ // Set processor affininty for receive DPC
+ //
+ PROCESSOR_NUMBER ProcNumber = {0};
+ ProcNumber.Group = QueueInfo->ProcessorAffinity.Group;
+ ProcNumber.Number = RtlFindLeastSignificantBit((ULONGLONG)QueueInfo->ProcessorAffinity.Mask);
+ ASSERT(ProcNumber.Number != -1);
+ if(ProcNumber.Number == -1)
+ {
+ //
+ // Queue has no affinity bits set.
+ //
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ DEBUGP(MP_ERROR,
+ "[%p] Queue %i has no affinity bits set.\n",
+ Adapter,
+ QueueId);
+
+ break;
+ }
+ QueueInfo->ReceiveDpc = NICAllocReceiveDpc(Adapter, ProcNumber.Number, ProcNumber.Group, QueueId);
+ if(!QueueInfo->ReceiveDpc)
+ {
+ //
+ // Could not allocate DPC
+ //
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] Could not allocate receive DPC for Queue %i\n", Adapter, QueueId);
+ break;
+ }
+ }
+ else
+ {
+ //
+ // No configuration specified, use this is the default queue so use default DPC
+ //
+ QueueInfo->ReceiveDpc = NICGetDefaultReceiveDpc(Adapter, QueueId);
+ }
+
+ //
+ // Initialize the receive block for the specified queue
+ //
+ Status = NICInitializeReceiveBlock(Adapter, QueueId);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] Could not initialize receive block for Queue %i\n", Adapter, QueueId);
+ break;
+ }
+
+ //
+ // Mark the Queue as initialized. It will not be used for receives until it is marked as completed.
+ //
+ QUEUE_SET_FLAG(QueueInfo, fMPAQI_INITIALIZED);
+
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- InitializeAdapterQueueInfo Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+
+}
+
+NDIS_STATUS
+AllocateRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams
+)
+/*++
+Routine Description:
+
+ This routine will allocate the corresponding queue in the passed in QueueParams,
+ and persist any relevant configuration from the request.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueParams - Pointer to the queue allocation parameters
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ PMP_ADAPTER_QUEUE QueueInfo = &VMQData->RxQueues[QueueParams->QueueId];
+ LOCK_STATE_EX LockState;
+ BOOLEAN ReleaseLock = FALSE;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AllocateRxQueue\n", Adapter);
+
+ do
+ {
+ //
+ // Verify queue is within the range of supported queues, and that it has not already
+ // been allocated
+ //
+ if(QueueParams->QueueId>=NIC_SUPPORTED_NUM_QUEUES)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Synchronize assigning of allocated memory
+ //
+ NdisAcquireRWLockWrite(VMQData->RxQueues[QueueParams->QueueId].QueueLock, &LockState, 0);
+ ReleaseLock = TRUE;
+
+ if(QUEUE_INITIALIZED(QueueInfo))
+ {
+ //
+ // For this sample, changes are not supported. To support changes check whether
+ // Flags&NDIS_RECEIVE_QUEUE_PARAMETERS_CHANGE_MASK != 0. The
+ // NDIS_RECEIVE_QUEUE_PARAMETERS_*_CHANGED flags can be checked against
+ // to determine which fields are being updated, and apply those changes.
+ //
+ DEBUGP(MP_ERROR, "[%p] Queue %i already allocated, failing request.\n", Adapter, QueueParams->QueueId);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+ else if(QUEUE_FREEING(QueueInfo))
+ {
+ DEBUGP(MP_ERROR, "[%p] Queue %i is in the process of being freed (RefCount of %i).\n", Adapter, QueueParams->QueueId, RECEIVE_BLOCK_REFERENCE_COUNT(Adapter, QueueParams->QueueId));
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Initialize the queue information
+ //
+ Status = InitializeAdapterQueueInfo(Adapter, QueueParams, QueueInfo);
+
+ } while(FALSE);
+
+ if(ReleaseLock)
+ {
+ NdisReleaseRWLock(VMQData->RxQueues[QueueParams->QueueId].QueueLock, &LockState);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- AllocateRxQueue Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+VOID
+FreeQueueReceiveSharedMemory(
+ _In_ PMP_ADAPTER Adapter,
+ ULONG EntryCount,
+ _In_reads_bytes_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR MemoryBlock,
+ PLIST_ENTRY AllocationList)
+/*++
+Routine Description:
+
+ This routine frees up the passed in receive shared and tracking memory.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ EntryCount - Number of memory block entries
+ MemoryBlock - MP_ADAPTER_SHARED_MEMORY_BLOCK memory allocated to track shared memory
+ AllocationList - List of PMP_ADAPTER_SHARED_MEMORY allocations that build up the total amount of shared memory available for receive
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ ULONG BlockIndex;
+ PLIST_ENTRY CurrentAllocation;
+
+ DEBUGP(MP_TRACE, "[%p] ---> FreeQueueReceiveSharedMemory.\n", Adapter);
+
+ if(MemoryBlock)
+ {
+ //
+ // Free the MDLs for the shared memory blocks
+ //
+ for(BlockIndex = 0; BlockIndex < EntryCount; ++BlockIndex)
+ {
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK SMBlock = ((PMP_ADAPTER_SHARED_MEMORY_BLOCK)MemoryBlock)+BlockIndex;
+#pragma prefast(suppress: 6001, "PREfast doees not believe the MDL is initialized.")
+ NdisFreeMdl(SMBlock->Mdl);
+ }
+
+ //
+ // Free the tracking buffers
+ //
+ NdisFreeMemory(MemoryBlock, EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK), 0);
+ }
+
+ //
+ // Free the shared memory
+ //
+ for(CurrentAllocation = RemoveTailList(AllocationList);
+ CurrentAllocation != AllocationList;
+ CurrentAllocation = RemoveTailList(AllocationList))
+ {
+ PMP_ADAPTER_SHARED_MEMORY CurrentSharedMemory = CONTAINING_RECORD(CurrentAllocation, MP_ADAPTER_SHARED_MEMORY, Entry);
+ NdisFreeSharedMemory(Adapter->AdapterHandle, CurrentSharedMemory->AllocationHandle);
+ NdisFreeMemory(CurrentSharedMemory, sizeof(MP_ADAPTER_SHARED_MEMORY), 0);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- FreeQueueReceiveSharedMemory.\n", Adapter);
+
+}
+
+VOID
+ FreeRxQueueReceiveMemory(
+ _Inout_ PMP_ADAPTER Adapter,
+ PMP_ADAPTER_QUEUE QueueInfo)
+/*++
+Routine Description:
+
+ This routine frees up any receive shared memory and tracking memory allocated for this queue.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueInfo - Pointer to shared memory owner queue
+
+Return Value:
+
+ VOID
+
+--*/
+{
+
+ DEBUGP(MP_TRACE, "[%p] ---> FreeRxQueueReceiveMemory. QueueId: %i\n", Adapter, QueueInfo->QueueId);
+
+ //
+ // Free lookahead memory and clear values
+ //
+ FreeQueueReceiveSharedMemory(
+ Adapter,
+ QueueInfo->NumPostLookaheadBlocks,
+ QueueInfo->PostLookaheadBlocks,
+ &QueueInfo->PostLookaheadSharedMemoryList);
+
+ QueueInfo->PostLookaheadBlocks = NULL;
+ QueueInfo->NumPostLookaheadBlocks = 0;
+
+ //
+ // Free postlookahead memory and clear values
+ //
+ FreeQueueReceiveSharedMemory(
+ Adapter,
+ QueueInfo->NumLookaheadBlocks,
+ QueueInfo->LookaheadBlocks,
+ &QueueInfo->LookaheadSharedMemoryList);
+
+ QueueInfo->LookaheadBlocks = NULL;
+ QueueInfo->NumLookaheadBlocks = 0;
+
+ DEBUGP(MP_TRACE, "[%p] <--- FreeRxQueueReceiveMemory.\n", Adapter);
+
+}
+
+NDIS_STATUS
+ AssociateSharedMemoryAndBlocks(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ ULONG EntryCount,
+ ULONG EntrySize,
+ ULONG OffsetSize,
+ _In_ PLIST_ENTRY AllocationList,
+ _In_reads_bytes_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR MemoryBlock)
+/*++
+Routine Description:
+
+ This routine populates each MP_ADAPTER_SHARED_MEMORY_BLOCK entry with its corresponding shared memory allocation.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ EntryCount - Number of memory block entries
+ EntrySize - Unaligned size of each shared memory entry (the actual size is aligned up to a memory aligned size)
+ OffsetSize - If this is a postlookahead buffer, this is the offset from the start of the buffer that must be left for lookahead
+ AllocationList - List of PMP_ADAPTER_SHARED_MEMORY allocations that build up the total amount of shared memory available for receive
+ MemoryBlock - MP_ADAPTER_SHARED_MEMORY_BLOCK memory allocated to track shared memory
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AssociateSharedMemoryAndBlocks.\n", Adapter);
+
+ do
+ {
+ ULONG BlockIndex, AllocationIndex, AlignedEntrySize = ALIGN_UP_BY(EntrySize, NdisGetSharedDataAlignment());
+ PLIST_ENTRY CurrentAllocation = AllocationList->Flink;
+ PMP_ADAPTER_SHARED_MEMORY CurrentSharedMemory;
+
+ //
+ // We should have at least one allocation
+ //
+ ASSERT(CurrentAllocation != AllocationList);
+
+ CurrentSharedMemory = CONTAINING_RECORD(CurrentAllocation, MP_ADAPTER_SHARED_MEMORY, Entry);
+
+ //
+ // Populate the shared memory tracking blocks with the necessary information (MDL, NET_BUFFER_SHARED_MEM macros)
+ //
+ for(BlockIndex = 0, AllocationIndex = 0; BlockIndex < EntryCount; ++BlockIndex, ++AllocationIndex)
+ {
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK CurrentBlock = (PMP_ADAPTER_SHARED_MEMORY_BLOCK)((MemoryBlock) + (BlockIndex*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)));
+
+ //
+ // Find the next free shared memory buffer
+ //
+ if(AllocationIndex >= CurrentSharedMemory->NumberOfEntries)
+ {
+ //
+ // We've exhausted the current shared memory allocation, need to index off of the next one
+ //
+ CurrentAllocation = CurrentAllocation->Flink;
+ ASSERT(CurrentAllocation != AllocationList);
+ AllocationIndex = 0;
+ CurrentSharedMemory = CONTAINING_RECORD(CurrentAllocation, MP_ADAPTER_SHARED_MEMORY, Entry);
+ }
+
+ CurrentBlock->Buffer = CurrentSharedMemory->Buffer+(AllocationIndex*AlignedEntrySize);
+ //
+ // Sanity check that the pointer is cache aligned
+ //
+ ASSERT(((ULONG_PTR)CurrentBlock->Buffer)%NdisGetSharedDataAlignment() == 0);
+
+ //
+ // Allocate the MDL
+ //
+ CurrentBlock->Mdl = NdisAllocateMdl(Adapter->AdapterHandle,
+ CurrentBlock->Buffer + OffsetSize,
+ EntrySize - OffsetSize);
+ if(!CurrentBlock->Mdl)
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed to allocate shared memory MDL.\n", Adapter);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Populate the NET_BUFFER_SHARED_MEMORY information
+ //
+ NET_BUFFER_SHARED_MEM_HANDLE(&CurrentBlock->BufferSharedMemoryData) = CurrentSharedMemory->MemoryHandle;
+ NET_BUFFER_SHARED_MEM_LENGTH(&CurrentBlock->BufferSharedMemoryData) = EntrySize - OffsetSize;
+ NET_BUFFER_SHARED_MEM_OFFSET(&CurrentBlock->BufferSharedMemoryData) = (ULONG)((CurrentBlock->Buffer + OffsetSize) - CurrentSharedMemory->Buffer);
+
+ //
+ // For now clear next segment field. If lookahead and postlookahead are allocated, the segment and MDLs are linked once allocation is complete
+ //
+ NET_BUFFER_SHARED_MEM_NEXT_SEGMENT(&CurrentBlock->BufferSharedMemoryData) = NULL;
+ }
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- AssociateSharedMemoryAndBlocks. Status=0x%x\n", Adapter, Status);
+
+ return Status;
+}
+
+VOID
+ChainMemoryBlocks(
+ ULONG EntryCount,
+ _In_reads_bytes_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR LookaheadBlock,
+ _In_reads_bytes_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK))PUCHAR PostLookaheadBlock)
+/*++
+Routine Description:
+
+ This routine steps through each entry in the lookahead and postlookahead memory blocks and sets up their
+ relationship by linking pointing the lookahead's MDL and NET_BUFFER_SHARED_MEM next fields to the postlookahead.
+
+Arguments:
+
+ EntryCount - Number of entris to step through in the memory block
+ LookaheadBlock - Lookahead tracking memory block
+ PostLookaheadBlock - Postlookahead tracking memory block
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ ULONG BlockIndex;
+ ASSERT(LookaheadBlock);
+ for(BlockIndex = 0; BlockIndex < EntryCount; ++BlockIndex)
+ {
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK CurrentLookaheadBlock = (PMP_ADAPTER_SHARED_MEMORY_BLOCK)((LookaheadBlock) + (BlockIndex*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)));
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK CurrentPostLookaheadBlock = (PMP_ADAPTER_SHARED_MEMORY_BLOCK)((PostLookaheadBlock) + (BlockIndex*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)));
+
+ //
+ // link MDLs
+ //
+ CurrentLookaheadBlock->Mdl->Next = CurrentPostLookaheadBlock->Mdl;
+
+ //
+ // link shared memory info so that lookahead points to the postlookahead block
+ //
+ NET_BUFFER_SHARED_MEM_NEXT_SEGMENT(&CurrentLookaheadBlock->BufferSharedMemoryData) = &CurrentPostLookaheadBlock->BufferSharedMemoryData;
+ }
+}
+
+_Success_(return == NDIS_STATUS_SUCCESS)
+NDIS_STATUS
+ AllocateSharedMemory(
+ _In_ PMP_ADAPTER Adapter,
+ NDIS_RECEIVE_QUEUE_ID QueueId,
+ NDIS_SHARED_MEMORY_USAGE Usage,
+ ULONG BlockSize,
+ _Out_ PNDIS_HANDLE AllocationHandle,
+ _Out_ PNDIS_HANDLE MemoryHandle,
+ _Outptr_result_bytebuffer_(BlockSize) PUCHAR *SharedBuffer
+ )
+/*++
+Routine Description:
+
+ This routine allocates shared memory for the specified QueueId (the default queue is not valid here,
+ since no shared memory is used). This should be called through AllocateRxSharedMemory, to get failure recovery.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - QueueId owning the shared memory
+ Usage - Usage of the shared memory (lookahead, postlookahead, receive)
+ BlockSize - Size of the block to allocate
+ AllocationHandle - Receives the Allocation handle returned from NdisAllocateSharedMemory
+ MemoryHandle - Receives the Memory handle returned from NdisAllocateSharedMemory
+ SharedBuffer - Receives the allocated shared memory
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_SHARED_MEMORY_PARAMETERS MemoryParams;
+ PSCATTER_GATHER_LIST SGListBuffer = NULL;
+ ULONG SGListSize, SGListNumElements;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AllocateSharedMemory\n", Adapter);
+
+ *MemoryHandle = NULL;
+ *SharedBuffer = NULL;
+
+ do
+ {
+ //
+ // Build the scatter gather list
+ //
+
+ //
+ // Calculate the number of pages that would be necessary for the specified block size.
+ //
+ SGListNumElements = BYTES_TO_PAGES(BlockSize);
+ //
+ // Allocate gather list elements to hold information for each of these pages.
+ //
+ SGListSize = sizeof(SCATTER_GATHER_LIST) + sizeof(SCATTER_GATHER_ELEMENT) * SGListNumElements;
+ SGListBuffer = NdisAllocateMemoryWithTagPriority(NdisDriverHandle,
+ SGListSize,
+ NIC_TAG_QUEUE_SG_LIST,
+ NormalPoolPriority);
+ if(SGListBuffer == NULL)
+ {
+ DEBUGP(MP_ERROR, "Failed to allocate scatter gather memory.\n");
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ SGListBuffer->NumberOfElements = SGListNumElements;
+
+ //
+ // Prepare the shared memory parameters to be passed in to the NDIS allocation function
+ //
+ NdisZeroMemory(&MemoryParams, sizeof(NDIS_SHARED_MEMORY_PARAMETERS));
+ MemoryParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ MemoryParams.Header.Revision = NDIS_SHARED_MEMORY_PARAMETERS_REVISION_1;
+ MemoryParams.Header.Size = NDIS_SIZEOF_SHARED_MEMORY_PARAMETERS_REVISION_1;
+
+ //
+ // Memory characteristics
+ //
+ MemoryParams.Length = BlockSize;
+ MemoryParams.QueueId = QueueId;
+ MemoryParams.Usage = Usage;
+
+ //
+ // Scatter gather buffer
+ //
+ MemoryParams.SGListBufferLength = SGListSize;
+ MemoryParams.SGListBuffer = SGListBuffer;
+
+ //
+ // Allocate the memory
+ //
+ Status = NdisAllocateSharedMemory(Adapter->AdapterHandle,
+ &MemoryParams,
+ AllocationHandle);
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateSharedMemory failed Status 0x%x.\n", Adapter, Status);
+ break;
+ }
+
+ //
+ // Set the buffer to return
+ //
+ *SharedBuffer = MemoryParams.VirtualAddress;
+ *MemoryHandle = MemoryParams.SharedMemoryHandle;
+
+ NdisZeroMemory(*SharedBuffer, BlockSize);
+
+ } while(FALSE);
+
+ if(SGListBuffer)
+ {
+ //
+ // This virtual miniport does not actually do DMA, so no need to preserve the SG information
+ //
+ NdisFreeMemoryWithTagPriority(NdisDriverHandle, SGListBuffer, NIC_TAG_QUEUE_SG_LIST);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- AllocateSharedMemory. Status=0x%x\n", Adapter, Status);
+
+ return Status;
+}
+
+NDIS_STATUS
+ AllocateRxSharedMemory(
+ _In_ PMP_ADAPTER Adapter,
+ NDIS_RECEIVE_QUEUE_ID QueueId,
+ NDIS_SHARED_MEMORY_USAGE Usage,
+ _Inout_ ULONG *EntryCount,
+ ULONG EntrySize,
+ ULONG OffsetSize,
+ _In_ PLIST_ENTRY AllocationList,
+ _Outptr_result_bytebuffer_(*EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR *MemoryBlock
+ )
+/*++
+Routine Description:
+
+ This routine wraps the call to AllocateSharedMemory providing failover if the allocation fails. If the original
+ requested number of entries fails to allocate, we try to allocate the same buffer size in smaller chunks.
+
+ Runs at IRQL APC_PASSIVE
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - QueueId owning the shared memory
+ Usage - Usage of the shared memory (lookahead, postlookahead, receive)
+ EntryCount - Number of Entries worth of shared memory to allocate
+ EntrySize - Size of each entry
+ AllocationList - LIST_ENTRY to receive all blocks allocated (MP_ADAPTER_SHARED_MEMORY)
+ MemoryBlock - Receives allocated and populated MP_ADAPTER_SHARED_MEMORY_BLOCK buffer with bookkeeping data on shared memory
+
+Return Value:
+
+ NDIS_STATUS
+
+ On failure, caller needs to call FreeRxQueueReceiveMemory to free any allocations made during the function
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AllocateRxSharedMemory.\n", Adapter);
+
+ do
+ {
+ ULONG AllocatedEntryCount = 0, CurAllocationTarget = *EntryCount;
+ //
+ // Make sure the entry size results in cache aligned segments
+ //
+ ULONG AlignedEntrySize = ALIGN_UP_BY(EntrySize, NdisGetSharedDataAlignment());
+ PMP_ADAPTER_SHARED_MEMORY CurMemory = NULL;
+
+ while(AllocatedEntryCount < *EntryCount)
+ {
+ //
+ // Entry size will be cache aligned, allocate enough memory so that we can be sure the entries start at
+ // a cache boundary
+ //
+ ULONG TotalAllocationSize = (CurAllocationTarget*AlignedEntrySize) + NdisGetSharedDataAlignment();
+
+ if(!CurMemory)
+ {
+ //
+ // Allocate MP_ADAPTER_SHARED_MEMORY we use to track this particular allocation
+ //
+ CurMemory = NdisAllocateMemoryWithTagPriority(NdisDriverHandle,
+ sizeof(MP_ADAPTER_SHARED_MEMORY),
+ NIC_TAG_QUEUE_SHARED_MEM,
+ NormalPoolPriority);
+ if(!CurMemory)
+ {
+ break;
+ }
+ NdisZeroMemory(CurMemory, sizeof(MP_ADAPTER_SHARED_MEMORY));
+ }
+
+ //
+ // Attempt to allocate shared memory block of (EntryCount * EntrySize) size
+ //
+ Status = AllocateSharedMemory(Adapter,
+ QueueId,
+ Usage,
+ TotalAllocationSize,
+ &CurMemory->AllocationHandle,
+ &CurMemory->MemoryHandle,
+ &CurMemory->Buffer);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Allocation failed, lets try multiple smaller allocation
+ //
+ CurAllocationTarget /= 2;
+ if(CurAllocationTarget >= NIC_MIN_RECV_ENTRY_ALLOCATION_COUNT)
+ {
+ DEBUGP(MP_ERROR, "[%p] AllocateSharedMemory failed, will attempt to allocate %i units of memory.\n", Adapter, CurAllocationTarget);
+ }
+ else
+ {
+ DEBUGP(MP_ERROR, "[%p] AllocateSharedMemory failed, reached minimum allocation size. Failing allocation. \n", Adapter);
+ NdisFreeMemory(CurMemory, sizeof(MP_ADAPTER_SHARED_MEMORY), 0);
+ CurMemory = NULL;
+ break;
+ }
+ }
+ else
+ {
+ //
+ // Move base buffer pointer up to a cache aligned boundary
+ //
+ CurMemory->Buffer = ALIGN_UP_POINTER_BY(CurMemory->Buffer, NdisGetSharedDataAlignment());
+
+ //
+ // Store away successful allocation
+ //
+ CurMemory->EntrySize = AlignedEntrySize;
+ CurMemory->NumberOfEntries = CurAllocationTarget;
+ AllocatedEntryCount += CurAllocationTarget;
+ InsertTailList(AllocationList, &CurMemory->Entry);
+ CurMemory = NULL;
+ }
+ }
+
+ //
+ // Verify that we were at least able to allocate up to our minimum number of receive blocks. If not, then we fail the
+ // allocation altogether.
+ //
+ if(AllocatedEntryCount<NIC_MIN_BUSY_RECVS)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Now that the shared memory buffers have been allocated, we need to split them into
+ // individual MP_ADAPTER_SHARED_MEMORY_BLOCK items used for tracking the memory in NB
+ //
+
+ //
+ // Allocate the necessary MP_ADAPTER_SHARED_MEMORY_BLOCK items to track the shared memory
+ //
+ *MemoryBlock = NdisAllocateMemoryWithTagPriority(
+ NdisDriverHandle,
+ AllocatedEntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK),
+ NIC_TAG_QUEUE_SHARED_MEM_BLOCK,
+ NormalPoolPriority);
+ if(!*MemoryBlock)
+ {
+ DEBUGP(MP_ERROR, "[%p] NdisAllocateMemoryWithTagPriority for shared memory block failed.\n", Adapter);
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+ NdisZeroMemory(*MemoryBlock, AllocatedEntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK));
+
+ //
+ // Associate each ADAPTER_SHARED_MEMOR_BLOCK entry with their corresponding ADAPTER_SHARED_MEMORY buffer segment.
+ //
+ Status = AssociateSharedMemoryAndBlocks(
+ Adapter,
+ *EntryCount,
+ EntrySize,
+ OffsetSize,
+ AllocationList,
+ *MemoryBlock);
+
+ }while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- AllocateRxSharedMemory. Status=0x%x\n", Adapter, Status);
+
+ return Status;
+
+}
+
+VOID
+ AssociateSharedMemoryAndRCBs(
+ _In_ ULONG QueueId,
+ _In_reads_bytes_opt_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR LookaheadBlock,
+ _In_reads_bytes_(EntryCount*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)) PUCHAR PostLookaheadBlock,
+ _In_reads_bytes_(EntryCount*sizeof(RCB)) PUCHAR RcbMemoryBlock,
+ ULONG EntryCount)
+/*++
+Routine Description:
+
+ This routine associates populates the fields in each RCB with its corresponding shared memory information
+ contained in the lookahead and postlookahead memory block. Once this function runs, each RCB is ready to
+ be used for receives (all that needs to happen on receive is to copy the receive data to the lookahead and
+ postlookahead memory locations for each RCB).
+
+Arguments:
+
+ QueueId - ID of the queue which owns the various pieces of memory
+ LookaheadBlock - Lookahead shared memory tracking blocks (can be NULL if no lookahead)
+ PostLookaheadBlock - Postlookahead shared memory tracking blocks
+ RcbMemoryBlock - RCB memory blocks
+
+Return Value:
+
+ VOID
+
+--*/
+{
+
+ ULONG BlockIndex;
+ for(BlockIndex = 0; BlockIndex < EntryCount; ++BlockIndex)
+ {
+ //
+ // Populate the RCB NBLs with the queue's shared memory.
+ //
+ PRCB Rcb = (PRCB)(RcbMemoryBlock+(BlockIndex*sizeof(RCB)));
+ PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(Rcb->Nbl);
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK CurrentPostLookaheadBlock = (PMP_ADAPTER_SHARED_MEMORY_BLOCK)((PostLookaheadBlock) + (BlockIndex*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)));
+ Rcb->Data = CurrentPostLookaheadBlock;
+ if(LookaheadBlock)
+ {
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK CurrentLookaheadBlock = (PMP_ADAPTER_SHARED_MEMORY_BLOCK)((LookaheadBlock) + (BlockIndex*sizeof(MP_ADAPTER_SHARED_MEMORY_BLOCK)));
+ Rcb->LookaheadData = CurrentLookaheadBlock;
+ //
+ // Set the shared memory and MDL information
+ //
+ NET_BUFFER_FIRST_SHARED_MEM_INFO(NetBuffer) = &CurrentLookaheadBlock->BufferSharedMemoryData;
+ NET_BUFFER_FIRST_MDL(NetBuffer) = CurrentLookaheadBlock->Mdl;
+ }
+ else
+ {
+ //
+ // Set the shared memory and MDL information
+ //
+ NET_BUFFER_FIRST_SHARED_MEM_INFO(NetBuffer) = &CurrentPostLookaheadBlock->BufferSharedMemoryData;
+ NET_BUFFER_FIRST_MDL(NetBuffer) = CurrentPostLookaheadBlock->Mdl;
+ }
+
+ //
+ // Set the remaining NBL fields
+ //
+ NET_BUFFER_DATA_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_CURRENT_MDL(NetBuffer) = NET_BUFFER_FIRST_MDL(NetBuffer);
+ NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_LIST_RECEIVE_QUEUE_ID(Rcb->Nbl) = (USHORT)QueueId;
+ NET_BUFFER_LIST_RECEIVE_FILTER_ID(Rcb->Nbl) = 0;
+ }
+
+}
+
+NDIS_STATUS
+ AllocateRxQueueReceiveMemory(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ PMP_ADAPTER_QUEUE QueueInfo)
+/*++
+Routine Description:
+
+ This routine allocates the necessary receive memory for the specified Queue.
+
+ Runs at IRQL APC_PASSIVE
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Queue - Queue to allocate
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ NDIS_SHARED_MEMORY_USAGE postMemoryUsage = NdisSharedMemoryUsageReceive;
+
+ //
+ // Queue should already be initialized
+ //
+ if(!QUEUE_INITIALIZED(QueueInfo))
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+
+ if(QueueInfo->NumSuggestedReceiveBuffers)
+ {
+ //
+ // If the number of receive buffers has been passed down for the queue, then we will allocate that suggested amount (as long as it's not below our minimum required amount of receive buffers),
+ // otherwise we use our minimum.
+ //
+ QueueInfo->NumReceiveBuffers = max(QueueInfo->NumSuggestedReceiveBuffers, NIC_MIN_BUSY_RECVS);
+ }
+ else
+ {
+ //
+ // No suggested receive buffer count was set for the queue, so we our preferred maximum amount
+ //
+ QueueInfo->NumReceiveBuffers = NIC_MAX_BUSY_RECVS;
+ }
+
+ //
+ // Initialize the shared memory allocation tracking lists
+ //
+ InitializeListHead(&QueueInfo->LookaheadSharedMemoryList);
+ InitializeListHead(&QueueInfo->PostLookaheadSharedMemoryList);
+
+ //
+ // Initialize list and lock of the free Rcb list
+ //
+ NdisInitializeListHead(&QueueInfo->FreeRcbList);
+ NdisAllocateSpinLock(&QueueInfo->FreeRcbListLock);
+
+
+ //
+ // In our implementation receive memory is only necessary for non-default queues. For default queue
+ // we reuse the Frame copy made during send.
+ //
+ if(QueueInfo->QueueId)
+ {
+ ULONG LookaheadSize=0, PostLookaheadSize=HW_MAX_FRAME_SIZE;
+
+ if(LOOKAHEAD_SPLIT_REQUIRED(QueueInfo))
+ {
+ ASSERT(QueueInfo->LookaheadSize);
+ LookaheadSize = QueueInfo->LookaheadSize;
+ }
+
+ //
+ // Allocate the shared memory that will be used to receive on this non-default queue.
+ //
+ if(LookaheadSize)
+ {
+ //
+ // Lookahead memory
+ //
+ Status = AllocateRxSharedMemory(
+ Adapter,
+ QueueInfo->QueueId,
+ NdisSharedMemoryUsageReceiveLookahead,
+ &QueueInfo->NumReceiveBuffers,
+ LookaheadSize,
+ 0,
+ &QueueInfo->LookaheadSharedMemoryList,
+ &QueueInfo->LookaheadBlocks);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ QueueInfo->NumLookaheadBlocks = QueueInfo->NumReceiveBuffers;
+
+ //
+ // We're doing lookahead split, so the usage for the Postlookahead needs to be
+ // explicitly postlookahead.
+ //
+ postMemoryUsage = NdisSharedMemoryUsageReceivePostLookahead;
+ }
+
+ //
+ // Allocate postlookahead memory
+ //
+ Status = AllocateRxSharedMemory(
+ Adapter,
+ QueueInfo->QueueId,
+ postMemoryUsage,
+ &QueueInfo->NumReceiveBuffers,
+ PostLookaheadSize,
+ LookaheadSize,
+ &QueueInfo->PostLookaheadSharedMemoryList,
+ &QueueInfo->PostLookaheadBlocks);
+
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ QueueInfo->NumPostLookaheadBlocks = QueueInfo->NumReceiveBuffers;
+
+ if(LookaheadSize)
+ {
+ //
+ // Now that we have both lookahead and post-lookahead allocated we need to chain
+ // a few of their fields together
+ //
+ ChainMemoryBlocks(
+ QueueInfo->NumReceiveBuffers,
+ QueueInfo->LookaheadBlocks,
+ QueueInfo->PostLookaheadBlocks);
+
+ }
+
+ }
+
+ //
+ // To finalize the allocation, we need to allocate the RCB & NBL blocks used for receive, and populated them
+ // with the appropriate shared memory data (if non-default queue).
+ //
+
+ //
+ // Ready to allocate the RCB blocks
+ //
+ Status = NICAllocRCBData(
+ Adapter,
+ QueueInfo->NumReceiveBuffers,
+ &QueueInfo->RcbMemoryBlock,
+ &QueueInfo->FreeRcbList,
+ &QueueInfo->FreeRcbListLock,
+ &QueueInfo->RecvNblPoolHandle
+ );
+
+ if(QueueInfo->QueueId && Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Populate the RCB NBLs with the queue's shared memory.
+ //
+ AssociateSharedMemoryAndRCBs(
+ QueueInfo->QueueId,
+ QueueInfo->LookaheadBlocks,
+ QueueInfo->PostLookaheadBlocks,
+ QueueInfo->RcbMemoryBlock,
+ QueueInfo->NumReceiveBuffers);
+ }
+
+ //
+ // At this point, all that is left to do on receive is for the shared memory to get populated with real frame data (e.g. DMA), and set the frame length.
+ // This avoids any expensive allocations on receive.
+ //
+
+ }while(FALSE);
+
+ if(Status != NDIS_STATUS_SUCCESS && QUEUE_INITIALIZED(QueueInfo))
+ {
+ //
+ // Cleanup any left over allocated receive resources from this function
+ //
+ FreeRxQueueReceiveMemory(Adapter, QueueInfo);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- AllocateRxQueueReceiveMemory. Status=0x%x\n", Adapter, Status);
+
+ return Status;
+}
+
+
+NDIS_STATUS
+CompleteAllocationRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY CompleteArray
+ )
+/*++
+Routine Description:
+
+ This routine will complete the process of queue allocation, allocating shared mmemory and
+ flagging queues as complete. Once a Queue is complete, receive indications can begin on it.
+
+ Runs at IRQL APC_PASSIVE
+
+Arguments:
+
+ Adapter - Pointer to our Adapter
+ CompleteArray - Pointer to the complete allocation parameters
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_PARAMETERS CompleteParamArray = (PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_PARAMETERS)((PUCHAR)CompleteArray + CompleteArray->FirstElementOffset);
+ ULONG index;
+ LOCK_STATE_EX LockState;
+
+ DEBUGP(MP_TRACE, "[%p] ---> CompleteAllocationRxQueue\n", Adapter);
+
+ //
+ // Iterate through each complete entry in the parameter array
+ //
+ for (index=0; index<CompleteArray->NumElements; index++)
+ {
+ PMP_ADAPTER_QUEUE CurrentQueue;
+
+ if(CompleteParamArray[index].QueueId >= NIC_SUPPORTED_NUM_QUEUES)
+ {
+ //
+ // Queue out of range
+ //
+ CompleteParamArray[index].CompletionStatus = NDIS_STATUS_INVALID_PARAMETER;
+ continue;
+ }
+
+ //
+ // Verify that the queue is initialized, and not already being completed (or complete)
+ //
+
+ //
+ // Synchronize access to queue status
+ //
+ CurrentQueue = &VMQData->RxQueues[CompleteParamArray[index].QueueId];
+ NdisAcquireRWLockWrite(CurrentQueue->QueueLock, &LockState, 0);
+ if(!QUEUE_INITIALIZED(CurrentQueue) ||
+ QUEUE_COMPLETING(CurrentQueue) ||
+ QUEUE_FREEING(CurrentQueue))
+ {
+ //
+ // Queue should have already been initialized, and should not be already completed or freed.
+ //
+ DEBUGP(MP_ERROR, "[%p] Queue %i does not have the correct status for completion (QueueInfoFlags: 0x%x).\n", Adapter, CompleteParamArray[index].QueueId, CurrentQueue->QueueInfoFlags);
+ CompleteParamArray[index].CompletionStatus = NDIS_STATUS_INVALID_PARAMETER;
+ NdisReleaseRWLock(CurrentQueue->QueueLock, &LockState);
+ continue;
+ }
+ //
+ // Mark that completion has started for the queue
+ //
+ QUEUE_SET_FLAG(CurrentQueue, fMPAQI_COMPLETION_STARTED);
+ NdisReleaseRWLock(CurrentQueue->QueueLock, &LockState);
+
+ Status = AllocateRxQueueReceiveMemory(Adapter, CurrentQueue);
+ CompleteParamArray[index].CompletionStatus = Status;
+ if(Status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP(MP_ERROR, "[%p] Failed while allocating receive memory for Queue %i\n", Adapter, CompleteParamArray[index].QueueId);
+ QUEUE_CLEAR_FLAG(CurrentQueue,fMPAQI_COMPLETION_STARTED);
+ continue;
+ }
+
+ //
+ // Completion done. Update queue status in a synchronized block.
+ //
+ NdisAcquireRWLockWrite(CurrentQueue->QueueLock, &LockState, 0);
+ QUEUE_SET_FLAG(CurrentQueue,fMPAQI_COMPLETION_FINISHED);
+ NdisReleaseRWLock(CurrentQueue->QueueLock, &LockState);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- CompleteAllocationRxQueue Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+NDIS_STATUS
+UpdateRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams
+)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_RECEIVE_QUEUE_ID QueueId = QueueParams->QueueId;
+ PMP_ADAPTER_QUEUE QueueInfo;
+
+ DEBUGP(MP_TRACE, "[%p] ---> UpdateRxQueue\n", Adapter);
+
+ do
+ {
+ if(QueueId >= NIC_SUPPORTED_NUM_QUEUES)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+
+ }
+
+ QueueInfo = &Adapter->VMQData.RxQueues[QueueId];
+ if(QueueParams->Flags&NDIS_RECEIVE_QUEUE_PARAMETERS_CHANGE_MASK)
+ {
+ if (QueueParams->Flags & NDIS_RECEIVE_QUEUE_PARAMETERS_PROCESSOR_AFFINITY_CHANGED)
+ {
+ //
+ // Change the owner DPC
+ //
+ PMP_ADAPTER_RECEIVE_DPC NewDpc;
+ PROCESSOR_NUMBER ProcNumber = {0};
+
+ if(!ValidGroupAffinity(&QueueParams->ProcessorAffinity))
+ {
+ DEBUGP(MP_ERROR, "[%p] Requested group affinity failed validation\n", Adapter);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ ProcNumber.Group = QueueParams->ProcessorAffinity.Group;
+ ProcNumber.Number = RtlFindLeastSignificantBit((ULONGLONG)QueueParams->ProcessorAffinity.Mask);
+ ASSERT(ProcNumber.Number != -1);
+
+ DEBUGP(MP_INFO, "[%p] Updating Queue Affinity Group: 0x%x, Number: 0x%x\n", Adapter, ProcNumber.Group, ProcNumber.Number);
+
+ //
+ // Get the new DPC with different affinity (if one already exists, will reuse it)
+ //
+ NewDpc = NICAllocReceiveDpc(Adapter, ProcNumber.Number, ProcNumber.Group, QueueId);
+ if(!NewDpc)
+ {
+ //
+ // Could not allocate DPC
+ //
+ Status = NDIS_STATUS_RESOURCES;
+ DEBUGP(MP_ERROR, "[%p] Could not allocate receive DPC for Queue %i, will keep original DPC\n", Adapter, QueueId);
+ break;
+ }
+
+ if(NewDpc != QueueInfo->ReceiveDpc)
+ {
+ //
+ // This is a new DPC for the queue, update the existing owner DPC and replace
+ //
+ NICReceiveDpcRemoveOwnership(QueueInfo->ReceiveDpc, QueueId);
+
+ //
+ // Store new DPC
+ //
+ QueueInfo->ReceiveDpc = NewDpc;
+
+ //
+ // Check whether there are any pending receives on the queue, if there are, then schedule the
+ // new DPC to make sure they are not lost
+ //
+ if(!IsListEmpty(&Adapter->ReceiveBlock[QueueId].ReceiveList))
+ {
+ DEBUGP(MP_INFO, "[%p] Receive Block %i: Receives were pending, queued new DPC.\n", Adapter, QueueId);
+ KeInsertQueueDpc(&QueueInfo->ReceiveDpc->Dpc, QueueInfo->ReceiveDpc, NULL);
+ }
+ }
+
+ }
+
+ if (QueueParams->Flags & NDIS_RECEIVE_QUEUE_PARAMETERS_FLAGS_CHANGED)
+ {
+ ULONG Flags = QueueParams->Flags & ~NDIS_RECEIVE_QUEUE_PARAMETERS_CHANGE_MASK;
+ DEBUGP(MP_INFO, "[%p] Updating Queue flags: 0x%x\n", Adapter, Flags);
+ if(Flags&NDIS_RECEIVE_QUEUE_PARAMETERS_LOOKAHEAD_SPLIT_REQUIRED
+ && !LOOKAHEAD_SPLIT_REQUIRED(QueueInfo)
+ && QUEUE_COMPLETE(QueueInfo))
+ {
+ //
+ // Our implementation does not support enabling lookahead after the queue is complete
+ // since our complete handler would not have allocated the lookahead memory.
+ //
+ DEBUGP(MP_ERROR, "[%p] Queue was already completed without lookahead split. Did not update flags. \n", Adapter);
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ else
+ {
+ QueueInfo->NdisFlags = Flags;
+ }
+ }
+
+ if (QueueParams->Flags & NDIS_RECEIVE_QUEUE_PARAMETERS_SUGGESTED_RECV_BUFFER_NUMBERS_CHANGED)
+ {
+ DEBUGP(MP_INFO, "[%p] Updating Queue number of suggested receive buffers: %i\n", Adapter, QueueParams->NumSuggestedReceiveBuffers);
+ QueueInfo->NumSuggestedReceiveBuffers = QueueParams->NumSuggestedReceiveBuffers;
+ }
+ }
+ }while(FALSE);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- UpdateRxQueue Status 0x%08x\n", Adapter, Status);
+ return Status;
+}
+
+
+NDIS_STATUS
+FreeAdapterQueueInfo(
+ _In_ PMP_ADAPTER Adapter,
+ USHORT QueueId,
+ _In_opt_ PNDIS_OID_REQUEST NdisSetRequest)
+/*++
+Routine Description:
+
+ This routine will clean up the memory for the specified queue, and reset it to uninitialized. If the
+ queue still has active references on it (e.g. - still in use), the function does not clean up the queue
+ and instead returns NDIS_STATUS_PENDING. Callers should handle attempting the free at a later time.
+
+ Runs at IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - Queue to free
+ NdisSetRequest - The OID for the free request (NULL if the call is not due to an OID request)
+
+Return Value:
+
+ Void
+
+--*/
+{
+ LOCK_STATE_EX QueueLockState;
+ PMP_ADAPTER_QUEUE QueueInfo = &Adapter->VMQData.RxQueues[QueueId];
+ LONG ReferenceCount = 0;
+ BOOLEAN DmaInProgress;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ PLIST_ENTRY Entry;
+
+ do
+ {
+ //
+ // Check (and possibly update) queue status in synchronized block
+ //
+ NdisAcquireRWLockWrite(QueueInfo->QueueLock, &QueueLockState, 0);
+ if(!QueueInfo->QueueInfoFlags)
+ {
+ //
+ // Queue has already been freed, no need to do anything.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ NdisReleaseRWLock(QueueInfo->QueueLock, &QueueLockState);
+ break;
+ }
+
+ //
+ // Reset the flags to "freeing". This way we will not accumulate any more receives on the queue.
+ //
+ QUEUE_SET_FLAG(QueueInfo,fMPAQI_FREEING);
+
+ //
+ // Make sure the freeing state set operation happens before the DMA in progress check
+ //
+ KeMemoryBarrier();
+
+ //
+ // Check whether the queue has a DMA in progress. This value check has to occur *after* we've updated
+ // the queue state to freeing. The receive code depends on this ordering of operations to avoid taking locks
+ // on its "DMA" path (see CopyFrameToRxQueue).
+ //
+ DmaInProgress = QUEUE_DMA_IN_PROGRESS(QueueInfo);
+ if(!DmaInProgress)
+ {
+ //
+ // There are no DMA's in progress. Update the flags of the queue to DMA stopped to avoid pending receive code
+ // from indicating DMA stopped state later. The indication to NDIS of this change happens outside of our synchronized
+ // block to avoid holding the lock for too long.
+ //
+ QUEUE_SET_FLAG(QueueInfo,fMPAQI_DMA_STOPPED);
+ }
+
+ //
+ // Get the reference count
+ //
+ ReferenceCount = RECEIVE_BLOCK_REFERENCE_COUNT(Adapter, QueueId);
+ if(ReferenceCount != 0)
+ {
+ //
+ // Still have outstanding usage of the queue, so we must pend the free request.
+ //
+ if(NdisSetRequest)
+ {
+ //
+ // Store the OID so that we can complete it later
+ //
+ SetPendingRxQueueFree(Adapter, NdisSetRequest);
+ }
+ else
+ {
+ //
+ // The queue free should only pend on OID request. If this free call came from halt or other operation,
+ // the queue should have been ready to free already, so check that we have a pending request.
+ //
+ ASSERT(Adapter->PendingRequest);
+ }
+
+ }
+
+ NdisReleaseRWLock(QueueInfo->QueueLock, &QueueLockState);
+
+ if(!DmaInProgress)
+ {
+ //
+ // There were no DMA's in progress when we updated that state to freeing, and no more DMA's will occur, so it's safe to indicate that queue DMA is stopped.
+ // Any pending receives that have already completed their copies will still be indicated.
+ //
+ IndicateRxQueue(
+ Adapter,
+ QueueId,
+ NdisReceiveQueueOperationalStateDmaStopped);
+ }
+
+ if(ReferenceCount != 0)
+ {
+ //
+ // Bail out of the free path. Once the ref count reaches zero on the queue and there are no in-progress DMA's, the queue will be freed and the OID will complete.
+ //
+ DEBUGP(MP_LOUD, "[%p] Queue %i has pending references (RefCount %i), returning NDIS_STATUS_PENDING for the free request.\n", Adapter, QueueId, ReferenceCount);
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+
+ DEBUGP(MP_LOUD, "[%p] Queue %i has no outstanding references, queue memory has been freed.\n", Adapter, QueueId);
+
+ NICReceiveDpcRemoveOwnership(QueueInfo->ReceiveDpc, QueueId);
+ QueueInfo->ReceiveDpc = NULL;
+
+ //
+ // Free the RCB & NBL data
+ //
+ if(QueueInfo->FreeRcbList.Flink)
+ {
+ while (NULL != (Entry = NdisInterlockedRemoveHeadList(
+ &QueueInfo->FreeRcbList,
+ &QueueInfo->FreeRcbListLock)))
+ {
+ PRCB Rcb = CONTAINING_RECORD(Entry, RCB, RcbLink);
+ NdisFreeNetBufferList(Rcb->Nbl);
+ }
+ NdisFreeSpinLock(&QueueInfo->FreeRcbListLock);
+ }
+
+ if (QueueInfo->RecvNblPoolHandle)
+ {
+ NdisFreeNetBufferListPool(QueueInfo->RecvNblPoolHandle);
+ QueueInfo->RecvNblPoolHandle = NULL;
+ }
+
+ if (QueueInfo->RcbMemoryBlock)
+ {
+ NdisFreeMemory(
+ QueueInfo->RcbMemoryBlock,
+ sizeof(RCB)*QueueInfo->NumReceiveBuffers,
+ 0);
+ QueueInfo->RcbMemoryBlock = NULL;
+ }
+
+ if(QUEUE_COMPLETE(QueueInfo))
+ {
+ FreeRxQueueReceiveMemory(
+ Adapter,
+ QueueInfo);
+ }
+
+ //
+ // Completed free, clear flags altogether
+ //
+ QueueInfo->QueueInfoFlags = 0;
+
+ if(Adapter->PendingRequest)
+ {
+ PNDIS_OID_REQUEST Request = Adapter->PendingRequest;
+ Adapter->PendingRequest = NULL;
+ NdisMOidRequestComplete(Adapter->AdapterHandle,
+ Request,
+ Status);
+ }
+
+ } while(FALSE);
+
+ return Status;
+}
+
+NDIS_STATUS
+FreeRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_FREE_PARAMETERS QueueFreeParams,
+ _In_opt_ PNDIS_OID_REQUEST NdisSetRequest
+ )
+/*++
+Routine Description:
+
+ This routine will clean up the memory for the specified queue. Queue should already been indicated as DMA stopped
+ using IndicateRxQueue. Callers should handle attempting the free at a later time if NDIS_STATUS_PENDING is returned.
+
+ Runs at IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueFreeParams - Pointer to the complete allocation parameters
+ NdisSetRequest - The OID for the free request (NULL if the call is not due to an OID request)
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP(MP_TRACE, "[%p] ---> FreeRxQueue\n", Adapter);
+
+ //
+ // Verify within valid range
+ //
+ if(QueueFreeParams->QueueId>=NIC_SUPPORTED_NUM_QUEUES)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ //
+ // Attempt to free the queue (pending will be returned if queue still in use)
+ //
+ Status = FreeAdapterQueueInfo(Adapter, (USHORT)QueueFreeParams->QueueId, NdisSetRequest);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- FreeRxQueue Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+_Use_decl_annotations_
+VOID
+FreeRxQueuesWorkItem(
+ PVOID WorkItemContext,
+ NDIS_HANDLE NdisIoWorkItemHandle
+ )
+/*++
+Routine Description:
+
+ This routine retrieves the pending free request (there can only be one at a time), and frees the queue. The work item is used
+ when we pend a queue free OID (because the reference count is non-zero), and when the reference count is finally reduced to
+ zero we are not at PASSIVE_LEVEL.
+
+ Runs at IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ WorkItemContext - Context for work item (PMP_ADAPTER)
+ NdisIoWorkItemHandle - Work item handle
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER Adapter;
+ PNDIS_OID_REQUEST Request;
+
+ Adapter = MP_ADAPTER_FROM_CONTEXT(WorkItemContext);
+ ASSERT(Adapter != NULL);
+ _Analysis_assume_(Adapter != NULL);
+
+ DEBUGP(MP_TRACE, "[%p] ---> FreeRxQueuesWorkItem\n", Adapter);
+
+ Request = Adapter->PendingRequest;
+ if(Request != NULL)
+ {
+ switch(Request->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_RECEIVE_FILTER_FREE_QUEUE:
+ Status = FreeRxQueue(
+ Adapter,
+ (PNDIS_RECEIVE_QUEUE_FREE_PARAMETERS)Request->DATA.SET_INFORMATION.InformationBuffer,
+ NULL //OID should already be held in pending OID member of adapter
+ );
+ //
+ // Should only be called once reference count has reached zero, it should succeed
+ //
+ ASSERT(Status == NDIS_STATUS_SUCCESS);
+ break;
+ default:
+ ASSERT(!"Unsupported Set OID added to pending list");
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ }
+
+ NdisFreeIoWorkItem(NdisIoWorkItemHandle);
+
+ DEBUGP(MP_TRACE, "[%p] <-- FreeRxQueuesWorkItem. Status=0x%x\n", Adapter, Status);
+}
+
+VOID
+FreeVMQData(
+ _Inout_ struct _MP_ADAPTER *Adapter)
+/*++
+Routine Description:
+
+ This routine will clean up the memory for all the queues in the passed in VMQData. It should only be called
+ when all pending receives have stopped (e.g. - miniport halt).
+
+ Runs at IRQL = PASSIVE_LEVEL
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ USHORT index;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ for(index=0; index<NIC_SUPPORTED_NUM_QUEUES; index++)
+ {
+ if(VMQData->RxQueues[index].QueueLock != NULL)
+ {
+ #pragma warning( suppress: 28931 ) // unused assignment of variable Status OK in Fre build
+ Status = FreeAdapterQueueInfo(Adapter, index, NULL);
+ ASSERT(Status == NDIS_STATUS_SUCCESS);
+ NdisFreeRWLock(VMQData->RxQueues[index].QueueLock);
+ }
+ }
+
+}
+
+VOID
+IndicateRxQueue(
+ _In_ PMP_ADAPTER Adapter,
+ NDIS_RECEIVE_QUEUE_ID QueueId,
+ NDIS_RECEIVE_QUEUE_OPERATIONAL_STATE State)
+/*++
+Routine Description:
+
+ This routine will indicate to NDIS the state of the queue.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - Queue to indicate
+ State - Current state of Queue
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS_INDICATION Status;
+ NDIS_RECEIVE_QUEUE_STATE QueueState;
+
+ DEBUGP(MP_TRACE, "[%p] ---> IndicateRxQueue ID: %i, State: 0x%x\n", Adapter, QueueId, State);
+
+ NdisZeroMemory(&Status, sizeof(Status));
+ NdisZeroMemory(&QueueState, sizeof(QueueState));
+
+ QueueState.Header.Revision = NDIS_RECEIVE_QUEUE_STATE_REVISION_1;
+ QueueState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ QueueState.Header.Size = NDIS_SIZEOF_NDIS_RECEIVE_QUEUE_STATE_REVISION_1;
+ QueueState.QueueId = QueueId;
+ QueueState.QueueState = State;
+
+ Status.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ Status.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ Status.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+ Status.StatusCode = NDIS_STATUS_RECEIVE_QUEUE_STATE;
+ Status.StatusBuffer = &QueueState;
+ Status.StatusBufferSize = QueueState.Header.Size;
+
+ NdisMIndicateStatusEx(
+ Adapter->AdapterHandle,
+ &Status);
+
+ DEBUGP(MP_TRACE, "[%p] <--- IndicateRxQueue\n", Adapter);
+
+}
+
+BOOLEAN
+IsSupportedRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_ PNDIS_RECEIVE_FILTER_PARAMETERS FilterParams,
+ _In_ PNDIS_RECEIVE_FILTER_FIELD_PARAMETERS FilterCriteria)
+/*++
+Routine Description:
+
+ This routine will verify whether the filter is well formed and supported by this adapter.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ FilterParams - Filter Parameters
+ FilterCriteria - Filter Field Parameters
+
+Return Value:
+
+ TRUE - filter is supported
+ FALSE - filter is not not
+
+--*/
+{
+
+ BOOLEAN Supported = TRUE;
+ ULONG index;
+ BOOLEAN VlanFilterPresent = FALSE, VlanUntaggedOrZeroFlagPresent = FALSE;
+
+ DEBUGP(MP_TRACE, "[%p] ---> IsSupportedRxFilter. FilterParams: QueueId: %i, FilterId: %i, Flags: 0x%x\n",
+ Adapter, FilterParams->QueueId, FilterParams->FilterId, FilterParams->Flags);
+
+ //
+ // Check all criteria for the filter
+ //
+ for(index = 0; index < FilterParams->FieldParametersArrayNumElements && Supported; index++)
+ {
+ DEBUGP(MP_TRACE, "[%p] FilterCriteris[%i]: FrameHeader: %i, ReceiveFilterTest: %i, MacHeaderField: %i\n",
+ Adapter,
+ index, FilterCriteria[index].FrameHeader, FilterCriteria[index].ReceiveFilterTest,
+ FilterCriteria[index].HeaderField.MacHeaderField);
+
+ //
+ // Verify frame header
+ //
+ if(FilterCriteria[index].FrameHeader != NdisFrameHeaderMac)
+ {
+ DEBUGP(MP_ERROR, "[%p] Unknown filter FrameHeader type %x\n", Adapter, FilterCriteria[index].FrameHeader);
+ Supported = FALSE;
+ break;
+ }
+
+ //
+ // Verify that filter test type is supported
+ //
+ switch(FilterCriteria[index].ReceiveFilterTest)
+ {
+ case NdisReceiveFilterTestEqual:
+ Supported = TRUE;
+ break;
+ default:
+ Supported=FALSE;
+ DEBUGP(MP_ERROR, "[%p] ReceiveFilterTest 0x%x not supported.\n", Adapter, FilterCriteria[index].ReceiveFilterTest);
+ break;
+ };
+
+ if(!Supported)
+ {
+ break;
+ }
+
+ //
+ // Verify header field
+ //
+ switch(FilterCriteria[index].HeaderField.MacHeaderField)
+ {
+ case NdisMacHeaderFieldDestinationAddress:
+ VlanUntaggedOrZeroFlagPresent = FilterCriteria->Flags&NDIS_RECEIVE_FILTER_FIELD_MAC_HEADER_VLAN_UNTAGGED_OR_ZERO;
+ Supported = TRUE;
+ break;
+ case NdisMacHeaderFieldVlanId:
+ VlanFilterPresent = TRUE;
+ Supported = TRUE;
+ break;
+ default:
+ Supported = FALSE;
+ DEBUGP(MP_ERROR, "[%p] MacHeaderField 0x%x not supported.\n", Adapter, FilterCriteria[index].HeaderField.MacHeaderField);
+ break;
+ };
+ }
+
+ if(Supported)
+ {
+ //
+ // NDIS_RECEIVE_FILTER_FIELD_MAC_HEADER_VLAN_UNTAGGED_OR_ZERO should not be set if VLAN filter is specified,
+ // and should be set if no VLAN filter is specified.
+ //
+ if(VlanFilterPresent == VlanUntaggedOrZeroFlagPresent)
+ {
+ //
+ // Both are specified, this is not correct.
+ //
+ DEBUGP(MP_ERROR, "[%p] Invalid VMQ filter configuration. NDIS_RECEIVE_FILTER_FIELD_MAC_HEADER_VLAN_UNTAGGED_OR_ZERO (%s), Vlan ID filter present (%s). Filter not accepted.\n",
+ Adapter,
+ VlanFilterPresent?"TRUE":"FALSE",
+ VlanUntaggedOrZeroFlagPresent?"TRUE":"FALSE");
+ Supported = FALSE;
+ }
+ else if(!VLAN_FILTER_ENABLED(Adapter) && VlanFilterPresent)
+ {
+ //
+ // VLAN based filtering not configured on the adapter
+ //
+ DEBUGP(MP_ERROR, "[%p] Invalid VMQ filter configuration. *VMQVlanFiltering is not set, and Vlan ID filter was specified.\n", Adapter);
+ Supported = FALSE;
+ }
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- IsSupportedRxFilter %s\n", Adapter, Supported?"TRUE":"FALSE");
+ return Supported;
+}
+
+NDIS_STATUS
+SetRxFilter(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_FILTER_PARAMETERS FilterParams
+ )
+/*++
+Routine Description:
+
+ This routine will assign a filter to the specified queue, after verifying that the filter is valid.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ FilterParams - Filter data
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ PNDIS_RECEIVE_FILTER_FIELD_PARAMETERS FilterCriteria = (PNDIS_RECEIVE_FILTER_FIELD_PARAMETERS)((PUCHAR)FilterParams + FilterParams->FieldParametersArrayOffset);
+ UINT FilterIndex = MP_ADAPTER_FILTER_INDEX(FilterParams->FilterId);
+ UINT CriteriaIndex;
+
+ DEBUGP(MP_TRACE, "[%p] ---> SetRxFilter\n", Adapter);
+
+ do
+ {
+ //
+ // Verify the requested queue is within supported range and is initialized
+ //
+ if(FilterParams->QueueId>=NIC_SUPPORTED_NUM_QUEUES
+ ||
+ FilterIndex>=NIC_MAX_HEADER_FILTERS
+ ||
+ !QUEUE_INITIALIZED(&VMQData->RxQueues[FilterParams->QueueId]))
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Verify that the filter itself is valid, and that it hasn't already been set
+ //
+ if(!IsSupportedRxFilter(Adapter, FilterParams, FilterCriteria)
+ ||
+ VMQData->RxFilters[FilterIndex].Valid)
+ {
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Make sure filter data is all zero at the outset
+ //
+ NdisZeroMemory(&VMQData->RxFilters[FilterIndex], sizeof(MP_ADAPTER_FILTER));
+
+ //
+ // Copy filter information. IsSupportedRxFilter will have already verified that this filter definition
+ // only contains MAC and VLAN ID definitions, and equals match criteria.
+ //
+ for(CriteriaIndex = 0; CriteriaIndex < FilterParams->FieldParametersArrayNumElements; CriteriaIndex++)
+ {
+ if(FilterCriteria[CriteriaIndex].HeaderField.MacHeaderField == NdisMacHeaderFieldDestinationAddress)
+ {
+ //
+ // MAC field
+ //
+ memcpy(&VMQData->RxFilters[FilterIndex].MacAddress, FilterCriteria[CriteriaIndex].FieldValue.FieldByteArrayValue, NIC_MACADDR_SIZE);
+ DEBUGP(MP_TRACE, "[%p] Filter Destination: %02x-%02x-%02x-%02x\n",
+ Adapter,
+ VMQData->RxFilters[FilterIndex].MacAddress[0], VMQData->RxFilters[FilterIndex].MacAddress[1],
+ VMQData->RxFilters[FilterIndex].MacAddress[2], VMQData->RxFilters[FilterIndex].MacAddress[3]);
+ }
+ else
+ {
+ //
+ // Vlan ID field
+ //
+ VMQData->RxFilters[FilterIndex].VlanId = FilterCriteria[CriteriaIndex].FieldValue.FieldShortValue;
+ DEBUGP(MP_TRACE, "[%p] Filter VlanId: %i\n", Adapter, VMQData->RxFilters[FilterIndex].VlanId);
+ }
+
+ if(FilterCriteria[CriteriaIndex].Flags&NDIS_RECEIVE_FILTER_FIELD_MAC_HEADER_VLAN_UNTAGGED_OR_ZERO)
+ {
+ VMQData->RxFilters[FilterIndex].VlanUntaggedOrZero = TRUE;
+ DEBUGP(MP_TRACE, "[%p] Filter VlanUntaggedOrZero is TRUE\n", Adapter);
+ }
+ }
+
+ //
+ // Store the QueueId
+ //
+ VMQData->RxFilters[FilterIndex].QueueId = (USHORT)FilterParams->QueueId;
+
+ //
+ // Set to valid
+ //
+ VMQData->RxFilters[FilterIndex].Valid = TRUE;
+
+
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- SetRxFilter Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+NDIS_STATUS
+ClearRxFilter(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_FILTER_CLEAR_PARAMETERS FilterParams
+)
+/*++
+Routine Description:
+
+ This routine will remove the specified filter from a particular queue.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ FilterParams - Parameters for freeing filter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PMP_ADAPTER_VMQ_DATA VMQData = &Adapter->VMQData;
+ UINT FilterIndex = MP_ADAPTER_FILTER_INDEX(FilterParams->FilterId);
+
+ DEBUGP(MP_TRACE, "[%p] ---> ClearRxFilter. FilterParams: QueueId: %i, FilterId: %i\n",
+ Adapter, FilterParams->QueueId, FilterParams->FilterId);
+
+ do
+ {
+
+ //
+ // Make sure the filter id is within the valid range
+ //
+ if(FilterParams->QueueId>=NIC_SUPPORTED_NUM_QUEUES
+ ||
+ FilterIndex>=NIC_MAX_HEADER_FILTERS)
+ {
+ DEBUGP(MP_ERROR, "[%p] Filter Clear request out of valid range. QueueId: %i, FilterId: %i\n",
+ Adapter, FilterParams->QueueId, FilterParams->FilterId);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if(!VMQData->RxFilters[FilterIndex].Valid)
+ {
+ //
+ // The filter is not valid.
+ //
+ DEBUGP(MP_ERROR, "[%p] Filter was not set. QueueId: %i, FilterId: %i\n",
+ Adapter, FilterParams->QueueId, FilterParams->FilterId);
+ Status = NDIS_STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ //
+ // Reset the filter to invalid
+ //
+ VMQData->RxFilters[FilterIndex].Valid = FALSE;
+ }
+
+ } while(FALSE);
+
+ DEBUGP(MP_TRACE, "[%p] <--- ClearRxFilter Status 0x%08x\n", Adapter, Status);
+
+ return Status;
+}
+
+BOOLEAN
+MatchRxFilter(
+ _In_ PMP_ADAPTER Adapter,
+ _In_reads_bytes_(NIC_MACADDR_SIZE) PUCHAR DestAddress,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _In_ PMP_ADAPTER_FILTER Filter)
+/*++
+Routine Description:
+
+ This routine will check whether a particular filter matches the specified destination address
+ and VLAN ID.
+
+Arguments:
+
+ DestAddress - Destination MAC address
+ Nbl1QInfo - VLAN information
+ Filter - Filter to check against
+
+Return Value:
+
+ TRUE - Data matches filter
+ FALSE - Data did not match filter
+
+--*/
+{
+ BOOLEAN MatchResult;
+
+ DEBUGP(MP_TRACE, "[%p] ---> MatchRxFilter\n", Adapter);
+
+
+ DEBUGP(MP_TRACE, "[%p] NBL Destination: %02x-%02x-%02x-%02x, Filter Destination: %02x-%02x-%02x-%02x\n",
+ Adapter,
+ DestAddress[0],DestAddress[1],DestAddress[2],DestAddress[3],
+ Filter->MacAddress[0], Filter->MacAddress[1],
+ Filter->MacAddress[2], Filter->MacAddress[3]);
+
+ //
+ // Match MAC address
+ //
+ MatchResult = NIC_ADDR_EQUAL(Filter->MacAddress, DestAddress);
+
+
+ if(MatchResult)
+ {
+ if(Filter->VlanUntaggedOrZero)
+ {
+ //
+ // VLAN ID should be zero or untagged for match
+ //
+ DEBUGP(MP_TRACE, "[%p] Destination Matched. Making sure VLAN is untagged or zero.\n", Adapter);
+ if(Nbl1QInfo->Value)
+ {
+ MatchResult = (Nbl1QInfo->Value == 0 || Nbl1QInfo->TagHeader.VlanId == 0);
+ if(Nbl1QInfo->Value)
+ {
+ DEBUGP(MP_TRACE, "[%p] NBL Vlan ID: %i\n", Adapter, Nbl1QInfo->TagHeader.VlanId);
+ }
+ }
+ }
+ else
+ {
+ //
+ // Match VLAN ID
+ //
+ if(Nbl1QInfo->Value)
+ {
+ MatchResult = (Nbl1QInfo->TagHeader.VlanId == Filter->VlanId);
+ DEBUGP(MP_TRACE, "[%p] NBL Vlan ID: %i, Filter Vlan ID: %i\n",
+ Adapter,
+ Nbl1QInfo->TagHeader.VlanId, Filter->VlanId);
+ }
+ else
+ {
+ MatchResult = FALSE;
+ DEBUGP(MP_TRACE, "[%p] NBL without VLAN TAG. Filter Vlan ID: %i\n",
+ Adapter,
+ Filter->VlanId);
+ }
+ }
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- MatchRxFilter MatchResult %s\n", Adapter, MatchResult?"TRUE":"FALSE");
+
+ return MatchResult;
+}
+
+BOOLEAN
+FindRxQueueRecipient(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _FRAME *Frame,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _Out_ USHORT *QueueId)
+/*++
+Routine Description:
+
+ This routine will return the matching QueueId and FilterId for a particular Frame and its 802.1Q data.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Frame - Receive frame
+ Nbl1QInfo - Receive VLAN information
+ QueueId - Is assigned the matching QueueId (NDIS_DEFAULT_RECEIVE_QUEUE_GROUP_ID if no queue matches)
+
+Return Value:
+
+ TRUE - Matched a specific queue (even default queue, if filters present on it)
+ FALSE - No queue matched
+
+--*/
+{
+ USHORT index;
+ BOOLEAN Matched=FALSE;
+
+ DEBUGP(MP_TRACE, "[%p] ---> FindRxQueueRecipient\n", Adapter);
+
+ //
+ // Iterate through all the filters and check whether a match exists
+ //
+ *QueueId = NDIS_DEFAULT_RECEIVE_QUEUE_ID;
+ for(index = 0; index < NIC_MAX_HEADER_FILTERS; index++)
+ {
+ //
+ // Only attempt to match a filter when it is valid and its queue has been completed
+ //
+ if(Adapter->VMQData.RxFilters[index].Valid
+ &&
+ QUEUE_COMPLETE(&Adapter->VMQData.RxQueues[Adapter->VMQData.RxFilters[index].QueueId])
+ &&
+ MatchRxFilter(Adapter, ((PNIC_FRAME_HEADER)Frame->Data)->DestAddress, Nbl1QInfo, &Adapter->VMQData.RxFilters[index]))
+ {
+ DEBUGP(MP_TRACE, "[%p] Match Found.\n", Adapter);
+ Matched = TRUE;
+ *QueueId = Adapter->VMQData.RxFilters[index].QueueId;
+ break;
+ }
+ }
+
+ if(!Matched)
+ {
+ UCHAR DestAddress[NIC_MACADDR_SIZE];
+ ULONG FrameType;
+ //
+ // No queue matched, if the packet is destinaed specifically for this NIC we indicate it on the default queue
+ //
+ GET_DESTINATION_OF_FRAME(DestAddress, Frame->Data);
+ FrameType = NICGetFrameTypeFromDestination(DestAddress);
+ Matched = HWIsFrameAcceptedByPacketFilter(Adapter, DestAddress, FrameType);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <-- FindRxQueueRecipient QueueId: %i, Matched: %i\n", Adapter, *QueueId, Matched);
+
+ return Matched;
+
+}
+
+BOOLEAN
+AcquireRxQueueReference(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) USHORT QueueId,
+ BOOLEAN RequireComplete
+ )
+/*++
+Routine Description:
+
+ This routine will increase the reference count on a queue, as long as it is still valid.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - The Queue to take reference
+ RequireComplete - If TRUE, the queue needs to be Completed to be considered valid, otherwise
+ Initialized is enough
+
+Return Value:
+
+ TRUE - Queue was valid, ref count increased
+ FALSE - Queue was not valid, ref count not changed
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ PMP_ADAPTER_QUEUE QueueInfo = &Adapter->VMQData.RxQueues[QueueId];
+ LOCK_STATE_EX LockState;
+
+ DEBUGP(MP_TRACE, "[%p] ---> AcquireRxQueueReference. QueueId: %i\n", Adapter, QueueId);
+ ASSERT(QueueId < NIC_SUPPORTED_NUM_QUEUES);
+
+ //
+ // Acquire read lock on queue to verify that it is valid
+ //
+ NdisAcquireRWLockRead(QueueInfo->QueueLock, &LockState, 0);
+ do
+ {
+ //
+ // Verify queue is initialized and optionally completed before taking reference
+ //
+ if(!QUEUE_INITIALIZED(QueueInfo)
+ ||
+ (RequireComplete && !QUEUE_COMPLETE(QueueInfo)))
+ {
+ DEBUGP(MP_LOUD, "[%p] Queue not in correct state to take reference. QueueInfoFlags: 0x%x.\n", Adapter, QueueInfo->QueueInfoFlags);
+ break;
+ }
+
+ //
+ // Queue is ready for use. Increment the reference count for the receive block.
+ //
+ Status = NICReferenceReceiveBlock(Adapter, QueueInfo->QueueId);
+
+ } while(FALSE);
+
+ NdisReleaseRWLock(QueueInfo->QueueLock, &LockState);
+
+ DEBUGP(MP_TRACE, "[%p] <--- AcquireRxQueueReference.\n", Adapter);
+
+ return Status == NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+ReleaseRxQueueReference(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) USHORT QueueId)
+/*++
+Routine Description:
+
+ This routine will decrease the reference count on a queue
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - The Queue to take reference
+
+Return Value:
+
+ None
+
+--*/
+{
+ ULONG RefCount = 0;
+ PMP_ADAPTER_QUEUE QueueInfo;
+ LOCK_STATE_EX LockState;
+ BOOLEAN PerformFree;
+
+ DEBUGP(MP_TRACE, "[%p] ---> ReleaseRxQueueReference. QueueId: %i\n", Adapter, QueueId);
+ ASSERT(QueueId < NIC_SUPPORTED_NUM_QUEUES);
+
+ QueueInfo = &Adapter->VMQData.RxQueues[QueueId];
+
+ //
+ // Acquire read lock on queue to synchronize our check whether the queue free was pended because reference count was not at zero
+ //
+ NdisAcquireRWLockRead(QueueInfo->QueueLock, &LockState, 0);
+
+ //
+ // Reduce the reference count
+ //
+ NICDereferenceReceiveBlock(Adapter, QueueId, &RefCount);
+
+ //
+ // If the reference count is zero, and the queue is tagged as freeing (which was pended earlier)
+ // then execute the free.
+ //
+ PerformFree = (RefCount == 0 && QUEUE_FREEING(QueueInfo));
+
+ //
+ // Done dereferencing and checking queue state
+ //
+ NdisReleaseRWLock(QueueInfo->QueueLock, &LockState);
+
+ if(PerformFree)
+ {
+ DEBUGP(MP_LOUD, "[%p] RefCount has reached zero and the queue is marked for free. Freeing Queue %i.\n", Adapter, QueueId);
+ //
+ // We've already gotten the call to free this queue, but references were still
+ // active on it. Call the free function now that we're at zero references.
+ //
+ if(NDIS_CURRENT_IRQL() < DISPATCH_LEVEL)
+ {
+ NDIS_STATUS Status = FreeAdapterQueueInfo(Adapter, QueueId, NULL);
+ ASSERT(Status == NDIS_STATUS_SUCCESS);
+ UNREFERENCED_PARAMETER(Status);
+ }
+ else
+ {
+ NDIS_HANDLE WorkItemHandle = NdisAllocateIoWorkItem(Adapter->AdapterHandle);
+ DEBUGP(MP_LOUD, "[%p] Currently at DISPATCH, queueing work item to free Queue %i.\n", Adapter, QueueId);
+ if(WorkItemHandle)
+ {
+ NdisQueueIoWorkItem(WorkItemHandle, FreeRxQueuesWorkItem, Adapter);
+ }
+ else
+ {
+ DEBUGP(MP_ERROR, "[%p] Could not allocate IoWorkItem to free queue.\n", Adapter);
+ }
+ }
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- ReleaseRxQueueReference.\n", Adapter);
+
+}
+
+VOID
+SetPendingRxQueueFree(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest
+ )
+/*++
+Routine Description:
+
+ This routine stores the pending queue free OID request, so that it can be completed
+ at a later time.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ QueueId - The Queue to take reference
+
+Return Value:
+
+ None
+
+--*/
+{
+ DEBUGP(MP_TRACE, "[%p] ---> SetPendingRxQueueFree\n", Adapter);
+
+ ASSERT(!Adapter->PendingRequest);
+ Adapter->PendingRequest = NdisSetRequest;
+
+ DEBUGP(MP_TRACE, "[%p] <--- SetPendingRxQueueFree\n", Adapter);
+}
+
+VOID
+GetRcbForRxQueue(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _FRAME *Frame,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _Outptr_result_maybenull_ PRCB *Rcb)
+/*++
+Routine Description:
+
+ This routine returns an RCB for the passed in Frame & VLAN info. The RCB will originate from the
+ matching queue.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Frame - Data Frame
+ Nbl1QInfo - VLAN information for Frame
+
+Return Value:
+
+ RCB pointer if matched
+ NULL if not matched
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ USHORT QueueId = 0;
+
+ DEBUGP(MP_TRACE, "[%p] ---> GetRcbForRxQueue. Frame: 0x%p.\n", Adapter, Frame);
+
+ *Rcb = NULL;
+
+ //
+ // Find the matching queue for the Frame
+ //
+ if(FindRxQueueRecipient(Adapter, Frame, Nbl1QInfo, &QueueId))
+ {
+ //
+ // Get a reference to the Queue to make sure it is kept valid throughout the receive
+ //
+ if(AcquireRxQueueReference(Adapter, QueueId, TRUE))
+ {
+ PMP_ADAPTER_QUEUE Queue = &Adapter->VMQData.RxQueues[QueueId];
+ //
+ // Get RCB from Queue
+ //
+ PLIST_ENTRY pEntry = NdisInterlockedRemoveHeadList(
+ &Queue->FreeRcbList,
+ &Queue->FreeRcbListLock);
+ if (pEntry)
+ {
+ *Rcb = CONTAINING_RECORD(pEntry, RCB, RcbLink);
+ }
+ else
+ {
+ DEBUGP(MP_ERROR, "[%p] Queue %i has run out of available RCBs for receive.\n", Adapter, QueueId);
+ //
+ // release the acquired reference on the queue
+ //
+ ReleaseRxQueueReference(Adapter, QueueId);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ }
+ else
+ {
+ DEBUGP(MP_LOUD, "[%p] No queue matched Frame: 0x%p.\n", Adapter, Frame);
+ }
+
+ DEBUGP(MP_TRACE, "[%p] <--- GetRcbForRxQueue. RCB: %p\n", Adapter, Rcb);
+
+ return;
+}
+
+NDIS_STATUS
+CopyFrameToRxQueueRcb(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _FRAME *Frame,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _Inout_ struct _RCB *Rcb,
+ _Out_ BOOLEAN *Copied)
+/*++
+Routine Description:
+
+ This routine copies the Frame and VLAN information to the passed in RCB. On a real NIC this copy would
+ occur through a HW DMA.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Frame - Data Frame
+ Nbl1QInfo - VLAN information for Frame
+ Rcb - RCB to receive the data
+ Copied - TRUE if the frame was copied to shared memory
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if copy succeeded.
+ NDIS_STATUS_ADAPTER_NOT_READY if we can no longer copy data to the RCB due to the queue being in freeing state (DMA stopped)
+
+--*/
+{
+ USHORT QueueId = NET_BUFFER_LIST_RECEIVE_QUEUE_ID(Rcb->Nbl);
+ PMP_ADAPTER_QUEUE Queue = &Adapter->VMQData.RxQueues[QueueId];
+ PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(Rcb->Nbl);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ BOOLEAN DMAEnabled = TRUE;
+ *Copied = FALSE;
+
+ DEBUGP(MP_TRACE, "[%p] ---> CopyFrameToRxQueueRcb. RCB: %p\n", Adapter, Rcb);
+
+ //
+ // Mark the queue as having an in progress DMA. This avoids a queue free OID request from causing the queue to
+ // enter DMA stopped state prematurely.
+ //
+ QUEUE_SET_FLAG(Queue,fMPAQI_DMA_IN_PROGRESS);
+
+ //
+ // Make sure the DMA progress set operation happends before the queue freeing check
+ //
+ KeMemoryBarrier();
+
+ //
+ // Verify that the queue is in a state where we can modify receive memory. Please note we set the DMA in progress
+ // first, then check freeing state. The freeing code sets freeing state first, then checks DMA in progress flag. With this
+ // approach, it's safe to check freeing state without synchronization and perform DMA if it's not yet set. If it gets updated
+ // to the pending freeing state after the below check, the freeing code (FreeAdapterQueueInfo) will see the DMA in progress flag
+ // and not set the DMA stopped state.
+ //
+ if(QUEUE_FREEING(Queue))
+ {
+ LOCK_STATE_EX LockState;
+ BOOLEAN InDMAStoppedState;
+ //
+ // A free OID was issued on the queue, which is now pending until reference count reaches zero (we must have
+ // at least one reference to have reached this point). Verify whether we should update the queue to DMA stopped state
+ // (a DMA in progress may have prevented the free code from updating the state).
+ //
+ NdisAcquireRWLockWrite(Queue->QueueLock, &LockState, 0);
+ InDMAStoppedState = QUEUE_DMA_STOPPED(Queue);
+ if(!InDMAStoppedState)
+ {
+ // Set the DMA stopped sate. The indication to NDIS of this change happens outside of our synchronized
+ // block to avoid holding the lock for too long.
+ QUEUE_SET_FLAG(Queue,fMPAQI_DMA_STOPPED);
+ }
+ NdisReleaseRWLock(Queue->QueueLock, &LockState);
+
+ if(!InDMAStoppedState)
+ {
+ //
+ // The queue was marked for free, but a pending DMA prevented it from entering DMA stopped. Enter
+ // DMA stopped state now, as we will not perform any more copies.
+ //
+ IndicateRxQueue(
+ Adapter,
+ QueueId,
+ NdisReceiveQueueOperationalStateDmaStopped);
+ }
+
+ //
+ // Once we've entered the queue free state, we should not perform any more copies to the receive buffers
+ //
+ DMAEnabled = FALSE;
+
+ }
+
+ if(DMAEnabled)
+ {
+ if(QueueId)
+ {
+ PMP_ADAPTER_SHARED_MEMORY_BLOCK PostLookaheadBlock = Rcb->Data, LookaheadBlock = Rcb->LookaheadData;
+ ULONG LookaheadSize = 0;
+
+ if(LOOKAHEAD_SPLIT_REQUIRED(Queue))
+ {
+ LookaheadSize = Queue->LookaheadSize;
+ }
+
+ if(LookaheadSize < Frame->ulSize)
+ {
+
+ //
+ // Copy the PostLookahead data
+ //
+ memcpy(((PUCHAR)PostLookaheadBlock->Buffer) + LookaheadSize, ((PUCHAR)Frame->Data) + LookaheadSize, Frame->ulSize - LookaheadSize);
+ //
+ // Update the MDL to reflect the amount of data present
+ //
+ NdisAdjustMdlLength(PostLookaheadBlock->Mdl, Frame->ulSize - LookaheadSize);
+ }
+
+ if(LookaheadSize)
+ {
+ //
+ // Copy the Lookahead
+ //
+ ULONG DataSize = min(LookaheadSize,Frame->ulSize);
+ memcpy(LookaheadBlock->Buffer, Frame->Data, DataSize);
+ //
+ // Update MDL to reflect the amount of data present
+ //
+ NdisAdjustMdlLength(LookaheadBlock->Mdl, DataSize);
+ }
+
+ *Copied = TRUE;
+
+ NET_BUFFER_DATA_LENGTH(NetBuffer) = Frame->ulSize;
+
+ }
+
+ //
+ // Set the OOB VLAN Information
+ //
+ if(Nbl1QInfo->Value)
+ {
+ NET_BUFFER_LIST_INFO(Rcb->Nbl, Ieee8021QNetBufferListInfo) = Nbl1QInfo->Value;
+ }
+
+ }
+ else
+ {
+ //
+ // We are not in a state where we can copy data to receive buffers
+ //
+ Status = NDIS_STATUS_ADAPTER_NOT_READY;
+ }
+
+ //
+ // Clear the DMA in progress flag
+ //
+ QUEUE_CLEAR_FLAG(Queue,fMPAQI_DMA_IN_PROGRESS);
+
+
+ DEBUGP(MP_TRACE, "[%p] <--- CopyFrameToRxQueueRcb. Copied: %i, Status 0x%08x\n", Adapter, *Copied, Status);
+
+ return Status;
+
+}
+
+VOID
+RecoverRxQueueRcb(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _RCB *Rcb)
+/*++
+Routine Description:
+
+ This routine returns an RCB to its owner VMQ Queue, releasing any references held.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Rcb - RCB to recover
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Return RCB to owner Queue
+ //
+ PMP_ADAPTER_QUEUE Queue = NULL;
+ USHORT QueueId = NET_BUFFER_LIST_RECEIVE_QUEUE_ID(Rcb->Nbl);
+
+ DEBUGP(MP_TRACE, "[%p] ---> RecoverRxQueueRcb. RCB: %p\n", Adapter, Rcb);
+
+ if(QueueId>=NIC_SUPPORTED_NUM_QUEUES)
+ {
+ DEBUGP(MP_ERROR, "[%p] RCB could not be recovered. The NBL QueueId was out of range: %i\n", Adapter, QueueId);
+ ASSERT(FALSE);
+ return;
+ }
+
+ Queue = &Adapter->VMQData.RxQueues[QueueId];
+ if(!QueueId)
+ {
+ //
+ // Default queue uses the send frame, rather than copying the data. Release
+ // the frame reference.
+ //
+ HWFrameRelease((PFRAME)Rcb->Data);
+ Rcb->Data = NULL;
+ }
+
+ //
+ // Add RCB back to free pool
+ //
+ NdisInterlockedInsertTailList(
+ &Queue->FreeRcbList,
+ &Rcb->RcbLink,
+ &Queue->FreeRcbListLock);
+
+ //
+ // Release reference to queue that we took when indicating the NBL
+ //
+ ReleaseRxQueueReference(Adapter, QueueId);
+
+ DEBUGP(MP_TRACE, "[%p] <--- RecoverRxQueueRcb\n", Adapter);
+
+}
+
+VOID
+AddPendingRcbToRxQueue(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _RCB *Rcb)
+/*++
+Routine Description:
+
+ This routine adds an RCB to the pending receive list for its owner VMQ queue.
+
+Arguments:
+
+ Adapter - Pointer to our adapter
+ Rcb - RCB to queue for recieve
+
+Return Value:
+
+ None
+
+--*/
+{
+ NDIS_RECEIVE_QUEUE_ID QueueId = NET_BUFFER_LIST_RECEIVE_QUEUE_ID(Rcb->Nbl);
+ DEBUGP(MP_TRACE, "[%p] ---> AddPendingRcbToRxQueue. RCB: %p\n", Adapter, Rcb);
+ NdisInterlockedInsertTailList(
+ &Adapter->ReceiveBlock[QueueId].ReceiveList,
+ &Rcb->RcbLink,
+ &Adapter->ReceiveBlock[QueueId].ReceiveListLock);
+ DEBUGP(MP_TRACE, "[%p] <--- AddPendingRcbToRxQueue\n", Adapter);
+}
+
diff --git a/network/ndis/netvmini/6x/vmq.h b/network/ndis/netvmini/6x/vmq.h
new file mode 100644
index 00000000..5b949e2a
--- /dev/null
+++ b/network/ndis/netvmini/6x/vmq.h
@@ -0,0 +1,393 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Vmq.h
+
+Abstract:
+
+ This module declares the VMQ related data types, flags, macros, and functions.
+
+Revision History:
+
+Notes:
+
+--*/
+
+
+struct _FRAME;
+struct _RCB;
+
+#if (NDIS_SUPPORT_NDIS620)
+
+
+//
+// VMQ queue structures
+//
+
+//
+// Tracks the shared memory segment allocated for indications
+//
+typedef struct _MP_ADAPTER_SHARED_MEMORY_BLOCK
+{
+ //
+ // MDL for the shared memory segment
+ //
+ PMDL Mdl;
+ //
+ // Pointer to shared memory for this block
+ //
+ PUCHAR Buffer;
+ //
+ // Description of the shared memory block used for the NetBuffer usage
+ //
+ NET_BUFFER_SHARED_MEMORY BufferSharedMemoryData;
+} MP_ADAPTER_SHARED_MEMORY_BLOCK, *PMP_ADAPTER_SHARED_MEMORY_BLOCK;
+
+//
+// Tracks a shared memory buffer allocation, which is then subdivided into individual blocks for indications
+//
+typedef struct _MP_ADAPTER_SHARED_MEMORY
+{
+ LIST_ENTRY Entry;
+ NDIS_HANDLE AllocationHandle;
+ NDIS_HANDLE MemoryHandle;
+ PUCHAR Buffer;
+ ULONG EntrySize;
+ ULONG NumberOfEntries;
+} MP_ADAPTER_SHARED_MEMORY, *PMP_ADAPTER_SHARED_MEMORY;
+
+//
+// The minimum number of shared memory blocks we require. Used when recovering from
+// shared memory allocation failures.
+//
+#define NIC_MIN_RECV_ENTRY_ALLOCATION_COUNT 32
+
+//
+// Flags set to individual queues. Any code changing the flag value should acquire the corresponding
+// lock.
+//
+//
+// The queue is initialized, but not yet completed. Receives disabled.
+//
+#define fMPAQI_INITIALIZED 0x1
+//
+// Completion of the queue has started. Receives disabled.
+//
+#define fMPAQI_COMPLETION_STARTED 0x2
+//
+// Queue completed. Receives enabled.
+//
+#define fMPAQI_COMPLETION_FINISHED 0x4
+//
+// Queue is being freed (pending RefCount). Receives disabled.
+//
+#define fMPAQI_FREEING 0x8
+//
+// DMA is being performed for queue
+//
+#define fMPAQI_DMA_IN_PROGRESS 0x10
+//
+// The queue has entered DMA stopped state. No copies should occur to receive memory for this queue.
+//
+#define fMPAQI_DMA_STOPPED 0x20
+
+#define QUEUE_SET_FLAG(_QueueInfo, _Flag)\
+ ((_QueueInfo)->QueueInfoFlags |= _Flag)
+
+#define QUEUE_CLEAR_FLAG(_QueueInfo, _Flag)\
+ ((_QueueInfo)->QueueInfoFlags &= ~(_Flag))
+
+#define QUEUE_INITIALIZED(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_INITIALIZED)
+
+#define QUEUE_COMPLETING(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_COMPLETION_STARTED)
+
+#define QUEUE_COMPLETE(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_COMPLETION_FINISHED)
+
+#define QUEUE_FREEING(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_FREEING)
+
+#define QUEUE_DMA_IN_PROGRESS(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_DMA_IN_PROGRESS)
+
+#define QUEUE_DMA_STOPPED(_QueueInfo)\
+ ((_QueueInfo)->QueueInfoFlags & fMPAQI_DMA_STOPPED)
+
+//
+// The MP_ADAPTER_QUEUE structure is used to track a specific VMQ queue
+//
+typedef struct DECLSPEC_CACHEALIGN _MP_ADAPTER_QUEUE
+{
+ //
+ // Lock for Read/Write access to QueueInfoFlags and RefCount.
+ //
+ PNDIS_RW_LOCK_EX QueueLock;
+ //
+ // Flags used to track status of Queue (fMPAQI_* flags)
+ //
+ ULONG QueueInfoFlags;
+
+ //
+ // DPC used for receives for this queue
+ //
+ struct _MP_ADAPTER_RECEIVE_DPC *ReceiveDpc;
+
+ //
+ // List of unused RCBs (sliced out of RcbMemoryBlock)
+ //
+ LIST_ENTRY FreeRcbList;
+ NDIS_SPIN_LOCK FreeRcbListLock;
+
+ //
+ // RCB & NBL memory information
+ //
+ PUCHAR RcbMemoryBlock;
+ NDIS_HANDLE RecvNblPoolHandle;
+
+ //
+ // Shared memory information (MP_ADAPTER_SHARED_MEMORY)
+ //
+ ULONG NumReceiveBuffers;
+ //
+ // List of MP_ADAPTER_SHARED_MEMORY, large shared memory buffers subdivided for use when receiving
+ //
+ LIST_ENTRY LookaheadSharedMemoryList;
+ LIST_ENTRY PostLookaheadSharedMemoryList;
+ //
+ // MP_ADAPTER_SHARED_MEMORY_BLOCK buffers to hold book-keeping info on subdivided shared memory buffers
+ //
+ PUCHAR LookaheadBlocks;
+ ULONG NumLookaheadBlocks;
+ PUCHAR PostLookaheadBlocks;
+ ULONG NumPostLookaheadBlocks;
+
+ //
+ // Data passed in through the VMQ Queue configuration related OIDs
+ //
+ NDIS_RECEIVE_QUEUE_ID QueueId;
+ ULONG NumSuggestedReceiveBuffers;
+ ULONG LookaheadSize;
+ ULONG NdisFlags;
+ GROUP_AFFINITY ProcessorAffinity;
+} MP_ADAPTER_QUEUE, *PMP_ADAPTER_QUEUE;
+
+//
+// Structure used to store receive filter data
+//
+typedef struct _MP_ADAPTER_FILTER
+{
+ //
+ // Whether the receive filter should be used
+ //
+ BOOLEAN Valid;
+ //
+ // Filter matching fields
+ //
+ BOOLEAN VlanUntaggedOrZero;
+ USHORT QueueId;
+ USHORT VlanId;
+ UCHAR MacAddress[NIC_MACADDR_SIZE];
+} MP_ADAPTER_FILTER, *PMP_ADAPTER_FILTER;
+
+#define MP_ADAPTER_FILTER_INDEX(_FilterId_)\
+ ((_FilterId_)-1)
+
+//
+// Global VMQ configuration structures
+//
+
+//
+// Flags tracking global VMQ state
+//
+//
+// VMQ is enabled on the adapter.
+//
+#define fMPVMQD_FILTERING_ENABLED 0x0001
+//
+// Lookahead split in VMQ indication is enabled on the adapter.
+//
+#define fMPVMQD_LOOKAHEAD_ENABLED 0x0002
+//
+// VLAN filtering in VMQ is enabled on the adapter.
+//
+#define fMPVMQD_VLANFILTER_ENABLED 0x0004
+
+#define VMQ_SET_FLAG(_Adapter, _Flag) \
+ ((_Adapter)->VMQData.Flags |= (_Flag))
+
+#define VMQ_ENABLED(_Adapter) \
+ ((_Adapter)->VMQData.Flags & fMPVMQD_FILTERING_ENABLED)
+#define LOOKAHEAD_SPLIT_ENABLED(_Adapter)\
+ ((_Adapter)->VMQData.Flags & fMPVMQD_LOOKAHEAD_ENABLED)
+#define VLAN_FILTER_ENABLED(_Adapter)\
+ ((_Adapter)->VMQData.Flags & fMPVMQD_VLANFILTER_ENABLED)
+
+#define LOOKAHEAD_SPLIT_REQUIRED(_QueueInfo)\
+ ((_QueueInfo)->NdisFlags & NDIS_RECEIVE_QUEUE_PARAMETERS_LOOKAHEAD_SPLIT_REQUIRED)
+
+//
+// The MP_ADAPTER_VMQ_DATA structure is used to track the global VMQ configuration for an adapter
+//
+typedef struct _MP_ADAPTER_VMQ_DATA
+{
+ //
+ // Tracks global VMQ state (fMPVMQD_* flags)
+ //
+ ULONG Flags;
+ //
+ // Individual Queues. The MP_ADAPTER_QUEUE array is not dynamically allocated to reduce
+ // pointer dereferencing during receives, which can affect performance.
+ //
+ MP_ADAPTER_QUEUE RxQueues[NIC_SUPPORTED_NUM_QUEUES];
+ //
+ // Filters used to match packets to Queues
+ //
+ MP_ADAPTER_FILTER RxFilters[NIC_MAX_HEADER_FILTERS];
+} MP_ADAPTER_VMQ_DATA, *PMP_ADAPTER_VMQ_DATA;
+
+NDIS_STATUS
+AllocateVMQData(
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+VOID
+FreeVMQData(
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+NDIS_STATUS
+ReadRxQueueConfig(
+ _In_ NDIS_HANDLE ConfigurationHandle,
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+NDIS_STATUS
+InitializeRxQueueMPConfig(
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+NDIS_STATUS
+AllocateDefaultRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter);
+
+
+NDIS_STATUS
+AllocateRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams
+ );
+
+NDIS_STATUS
+CompleteAllocationRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_ALLOCATION_COMPLETE_ARRAY CompleteArray
+ );
+
+NDIS_STATUS
+UpdateRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_PARAMETERS QueueParams
+);
+
+NDIS_STATUS
+FreeRxQueue(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_QUEUE_FREE_PARAMETERS QueueParams,
+ _In_opt_ PNDIS_OID_REQUEST NdisSetRequest
+);
+
+VOID
+IndicateRxQueue(
+ _In_ NDIS_HANDLE AdapterHandle,
+ NDIS_RECEIVE_QUEUE_ID QueueId,
+ NDIS_RECEIVE_QUEUE_OPERATIONAL_STATE State);
+
+NDIS_STATUS
+SetRxFilter(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_FILTER_PARAMETERS FilterParams
+ );
+
+NDIS_STATUS
+ClearRxFilter(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_RECEIVE_FILTER_CLEAR_PARAMETERS FilterParams
+ );
+
+BOOLEAN
+AcquireRxQueueReference(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) USHORT QueueId,
+ BOOLEAN RequireComplete
+ );
+
+VOID
+ReleaseRxQueueReference(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ _In_range_(0, NIC_SUPPORTED_NUM_QUEUES-1) USHORT QueueId
+ );
+
+VOID
+SetPendingRxQueueFree(
+ _Inout_ struct _MP_ADAPTER *Adapter,
+ _In_ PNDIS_OID_REQUEST NdisSetRequest
+ );
+
+VOID
+GetRcbForRxQueue(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _FRAME *Frame,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _Outptr_result_maybenull_ struct _RCB **Rcb);
+
+NDIS_STATUS
+CopyFrameToRxQueueRcb(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _FRAME *Frame,
+ _In_ PNDIS_NET_BUFFER_LIST_8021Q_INFO Nbl1QInfo,
+ _Inout_ struct _RCB *Rcb,
+ _Out_ BOOLEAN *Copied);
+
+VOID
+RecoverRxQueueRcb(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _RCB *Rcb);
+
+VOID
+AddPendingRcbToRxQueue(
+ _In_ struct _MP_ADAPTER *Adapter,
+ _In_ struct _RCB *Rcb);
+
+#define GetRxQueueDpc(Adapter, QueueId) (Adapter)->VMQData.RxQueues[(QueueId)].ReceiveDpc
+
+#else
+
+//
+// In order to avoid excessible "#if defined(NDIS620_MINIPORT)" statements scattered
+// through the miniport implementation, NDIS60 miniports define
+// placeholder macros for the VMQ functions which cause the code to always proceed
+// as if VMQ were disabled on the adapter.
+//
+
+#define VMQ_ENABLED(_Adapter) FALSE
+#define LOOKAHEAD_SPLIT_ENABLED(_Adapter) FALSE
+#define VLAN_FILTER_ENABLED(_Adapter) FALSE
+#define LOOKAHEAD_SPLIT_REQUIRED(_QueueInfo) FALSE
+#define AllocateDefaultRxQueue(Adapter) NDIS_STATUS_NOT_SUPPORTED
+#define AddPendingRcbToRxQueue(Adapter, Rcb)
+#define GetRxQueueDpc(Adapter, QueueId) NULL
+#define AllocateVMQData(Adapter) NDIS_STATUS_SUCCESS
+#define FreeVMQData(Adapter)
+#define ReadRxQueueConfig(ConfigurationHandle, Adapter) NDIS_STATUS_SUCCESS
+#define InitializeRxQueueMPConfig(Adapter) NDIS_STATUS_SUCCESS
+#define CopyFrameToRxQueueRcb(Adapter, Frame, Nbl1QInfo, Rcb, Copied) FALSE
+#define GetRcbForRxQueue(Adapter, Frame, Nbl1QInfo, Rcb) NDIS_STATUS_NOT_SUPPORTED
+#define RecoverRxQueueRcb(Adapter, Rcb)
+
+#endif
diff --git a/network/trans/ddproxy/ReadMe.md b/network/trans/ddproxy/ReadMe.md
new file mode 100644
index 00000000..67a6b213
--- /dev/null
+++ b/network/trans/ddproxy/ReadMe.md
@@ -0,0 +1,66 @@
+Windows Filtering Platform Packet Modification Sample
+=====================================================
+
+The sample driver demonstrates the packet modification capabilities of the Windows Filtering Platform (WFP).
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+Run the sample
+--------------
+
+The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*.
+
+The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy the Windows Filtering Platform Packet Modification Sample driver automatically or manually.
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, navigate to DriverTest\\Drivers, and locate the file ddproxy.inf. Right click ddproxy.inf, and choose **Install**.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). After you have prepared the target computer for manual deployment, continue with these steps:
+
+1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\WfpPacketModificationSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click ddproxy.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+1. On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**ddproxy**\\**Parameters**
+
+2. Create a REG\_SZ entry named **DestinationAddressToIntercept** and set it's value to an IPV4 or IPV6 address (example: 10.0.0.1).
+
+3. Create a REG\_SZ entry named **NewDestinationAddress**, and set it's value to an IPV4 or IPV6 address (example: 10.0.0.2).
+
+You can also create and set values for the following registry entries.
+
+- **InspectUdp** (REG\_DWORD type): 0 for ICMP and 1 for UDP (default)
+- **DestinationPortToIntercept** (REG\_DWORD type): UDP port number (applicable if InspectUdp is set to 1)
+- **NewDestinationPort** (REG\_DWORD type): UDP port number (applicable if InspectUdp is set to 1)
+
+Start the ddproxy service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start ddproxy**. (To stop the driver, enter **net stop ddproxy**.)
+
+Remarks
+-------
+
+This sample driver consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Ddproxy.sys) that intercepts User Datagram Protocol (UDP) and nonerror Internet Control Message Protocol (ICMP) traffic of interest and acts as a redirector. For outbound traffic, Ddproxy.sys redirects the traffic to a new destination address and, for UDP, a new UDP port. For inbound traffic, Ddproxy.sys redirects the traffic back to the original address and UDP port values. This redirection is transparent to the application.
+
+Packet modification is done out-of-band by a system worker thread by using the reference-drop-clone-modify-reinject mechanism. Therefore, the sample can serve as a basis for scenarios in which the filtering/modification decision cannot be made within the `classifyFn()` callout, but instead must be made, for example, by a user-mode application.
+
+Ddproxy.sys acts as a redirector for both Internet Protocol version 4 (IPv4) and Internet Protocol version 6 (IPv6) traffic.
+
+For more information on creating a Windows Filtering Platform Callout Driver, see [Windows Filtering Platform Callout Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571068).
+
diff --git a/network/trans/ddproxy/ddproxy.sln b/network/trans/ddproxy/ddproxy.sln
new file mode 100644
index 00000000..9115b369
--- /dev/null
+++ b/network/trans/ddproxy/ddproxy.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ddproxy", "sys\ddproxy.vcxproj", "{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.Build.0 = Debug|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.ActiveCfg = Release|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.Build.0 = Release|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.ActiveCfg = Debug|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.Build.0 = Debug|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.ActiveCfg = Release|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/ddproxy/sys/DD_drv.c b/network/trans/ddproxy/sys/DD_drv.c
new file mode 100644
index 00000000..18509e53
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_drv.c
@@ -0,0 +1,1059 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Datagram-Data Transparent Proxy Callout Driver Sample.
+
+ This sample callout driver intercepts UDP and non-error ICMP traffic
+ of interest and proxies them to a new destination address and/or port
+ (for UDP); response traffic will be proxied back to have the original
+ tuple values. The proxying is transparent to the application.
+
+ Inspection parameters and proxy settings are configurable via the
+ following registry values --
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ddproxy\Parameters
+
+ o InspectUdp (REG_DWORD) : 0 (ICMP); 1 (UDP, default)
+ o DestinationAddressToIntercept (REG_SZ) : literal IPv4/IPv6 string
+ (e.g. �10.0.0.1�)
+ o DestinationPortToIntercept (REG_DWORD) : applicable if InspectUdp is 1
+ o NewDestinationAddress(REG_SZ) : literal IPv4/IPv6 string
+ o NewDestinationPort(REG_DWORD)
+
+ The sample is IP version agnostic. It performs proxying for both IPv4
+ and IPv6 traffic.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include <ws2ipdef.h>
+#include <in6addr.h>
+#include <ip2string.h>
+
+#include "DD_proxy.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+//
+// Configurable parameters (addresses and ports are in host order)
+//
+
+BOOLEAN configInspectUdp = TRUE;
+
+UINT16 configInspectDestPort = 5001;
+UINT8* configInspectDestAddrV4 = NULL;
+UINT8* configInspectDestAddrV6 = NULL;
+
+UINT16 configNewDestPort = 5001;
+UINT8* configNewDestAddrV4 = NULL;
+UINT8* configNewDestAddrV6 = NULL;
+
+SOCKADDR_STORAGE destAddr, newDestAddr;
+
+//
+// Callout and sublayer GUIDs
+//
+
+// b16b0a6e-2b2a-41a3-8b39-bd3ffc855ff8
+DEFINE_GUID(
+ DD_PROXY_CALLOUT_V4,
+ 0xb16b0a6e,
+ 0x2b2a,
+ 0x41a3,
+ 0x8b, 0x39, 0xbd, 0x3f, 0xfc, 0x85, 0x5f, 0xf8
+);
+// 2cebde39-1f59-48d1-a5d9-3e2458351476
+DEFINE_GUID(
+ DD_PROXY_CALLOUT_V6,
+ 0x2cebde39,
+ 0x1f59,
+ 0x48d1,
+ 0xa5, 0xd9, 0x3e, 0x24, 0x58, 0x35, 0x14, 0x76
+);
+// ee93719d-ad5d-48c9-ae46-7270367d205d
+DEFINE_GUID(
+ DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0xee93719d,
+ 0xad5d,
+ 0x48c9,
+ 0xae, 0x46, 0x72, 0x70, 0x36, 0x7d, 0x20, 0x5d
+);
+
+// 1e3d3d13-0588-4167-82a3-14f68c98de86
+DEFINE_GUID(
+ DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6,
+ 0x1e3d3d13,
+ 0x0588,
+ 0x4167,
+ 0x82, 0xa3, 0x14, 0xf6, 0x8c, 0x98, 0xde, 0x86
+);
+
+// 0104fd7e-c825-414e-94c9-f0d525bbc169
+DEFINE_GUID(
+ DD_PROXY_SUBLAYER,
+ 0x0104fd7e,
+ 0xc825,
+ 0x414e,
+ 0x94, 0xc9, 0xf0, 0xd5, 0x25, 0xbb, 0xc1, 0x69
+);
+
+//
+// Callout driver global variables
+//
+
+DEVICE_OBJECT* gWdmDevice;
+
+HANDLE gEngineHandle;
+UINT32 gFlowEstablishedCalloutIdV4, gCalloutIdV4;
+UINT32 gFlowEstablishedCalloutIdV6, gCalloutIdV6;
+
+HANDLE gInjectionHandle;
+
+LIST_ENTRY gFlowList;
+KSPIN_LOCK gFlowListLock;
+
+LIST_ENTRY gPacketQueue;
+KSPIN_LOCK gPacketQueueLock;
+KEVENT gPacketQueueEvent;
+
+BOOLEAN gDriverUnloading = FALSE;
+void* gThreadObj;
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
+
+//
+// Callout driver implementation
+//
+
+NTSTATUS
+DDProxyLoadIPAddress(
+ _In_ const WDFKEY key,
+ _In_ const UNICODE_STRING* valueName,
+ _Out_ SOCKADDR_STORAGE* result
+ )
+{
+ NTSTATUS status;
+ PWSTR terminator;
+ DECLARE_UNICODE_STRING_SIZE(value, INET6_ADDRSTRLEN);
+ IN_ADDR *resultV4 = &((SOCKADDR_IN*)result)->sin_addr;
+ IN6_ADDR *resultV6 = &((SOCKADDR_IN6*)result)->sin6_addr;
+
+ status = WdfRegistryQueryUnicodeString(key, valueName, NULL, &value);
+ result->ss_family = AF_UNSPEC;
+
+ if (NT_SUCCESS(status))
+ {
+ // The Registry API does not guarantee that the string will be
+ // null-terminated.
+ // Defensively null-terminate the string.
+ value.Length = min(value.Length, value.MaximumLength - sizeof(WCHAR));
+ value.Buffer[value.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ status = RtlIpv4StringToAddressW(
+ value.Buffer,
+ TRUE,
+ &terminator,
+ resultV4
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ resultV4->S_un.S_addr = RtlUlongByteSwap(resultV4->S_un.S_addr);
+ result->ss_family = AF_INET;
+ }
+ else
+ {
+ status = RtlIpv6StringToAddressW(
+ value.Buffer,
+ &terminator,
+ resultV6
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ result->ss_family = AF_INET6;
+ }
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyLoadConfig(
+ _In_ const WDFKEY key
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ DECLARE_CONST_UNICODE_STRING(inspectUdpValueName, L"InspectUdp");
+ DECLARE_CONST_UNICODE_STRING(destAddrValueName, L"DestinationAddressToIntercept");
+ DECLARE_CONST_UNICODE_STRING(destPortValueName, L"DestinationPortToIntercept");
+ DECLARE_CONST_UNICODE_STRING(newDestAddrValueName, L"NewDestinationAddress");
+ DECLARE_CONST_UNICODE_STRING(newDestPortValueName, L"NewDestinationPort");
+
+ ULONG ulongValue;
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &inspectUdpValueName,
+ &ulongValue
+ )))
+ {
+ configInspectUdp = (ulongValue != 0);
+ }
+
+
+ if (NT_SUCCESS(DDProxyLoadIPAddress(
+ key,
+ &destAddrValueName,
+ &destAddr
+ )))
+ {
+ if (destAddr.ss_family == AF_INET)
+ {
+ configInspectDestAddrV4 = &((SOCKADDR_IN*)&destAddr)->sin_addr.S_un.S_un_b.s_b1;
+ }
+ else if (destAddr.ss_family == AF_INET6)
+ {
+ configInspectDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&destAddr)->sin6_addr.u.Byte[0]);
+ }
+ }
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &destPortValueName,
+ &ulongValue
+ )))
+ {
+ configInspectDestPort = (USHORT) ulongValue;
+ }
+
+ if (NT_SUCCESS(DDProxyLoadIPAddress(
+ key,
+ &newDestAddrValueName,
+ &newDestAddr
+ )))
+ {
+ if (destAddr.ss_family == AF_INET)
+ {
+ configNewDestAddrV4 = &((SOCKADDR_IN*)&newDestAddr)->sin_addr.S_un.S_un_b.s_b1;
+ }
+ else if (destAddr.ss_family == AF_INET6)
+ {
+ configNewDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&newDestAddr)->sin6_addr.u.Byte[0]);
+ }
+ }
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &newDestPortValueName,
+ &ulongValue
+ )))
+ {
+ configNewDestPort = (USHORT) ulongValue;
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyAddFilter(
+ _In_ const PWSTR filterName,
+ _In_ const PWSTR filterDesc,
+ _In_reads_(16) const UINT8* remoteAddr,
+ _In_ USHORT remotePort,
+ _In_ FWP_DIRECTION direction,
+ _In_ UINT64 context,
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPM_FILTER filter = {0};
+ FWPM_FILTER_CONDITION filterConditions[3] = {0};
+ UINT conditionIndex;
+
+ filter.layerKey = *layerKey;
+ filter.displayData.name = (wchar_t*)filterName;
+ filter.displayData.description = (wchar_t*)filterDesc;
+
+ filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
+ filter.action.calloutKey = *calloutKey;
+ filter.filterCondition = filterConditions;
+ filter.subLayerKey = DD_PROXY_SUBLAYER;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+ filter.rawContext = context;
+
+ conditionIndex = 0;
+
+ if (remoteAddr != NULL)
+ {
+ filterConditions[conditionIndex].fieldKey =
+ FWPM_CONDITION_IP_REMOTE_ADDRESS;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+
+ if (IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4))
+ {
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
+ filterConditions[conditionIndex].conditionValue.uint32 =
+ *(UINT32*)remoteAddr;
+ }
+ else
+ {
+ filterConditions[conditionIndex].conditionValue.type =
+ FWP_BYTE_ARRAY16_TYPE;
+ filterConditions[conditionIndex].conditionValue.byteArray16 =
+ (FWP_BYTE_ARRAY16*)remoteAddr;
+ }
+
+ conditionIndex++;
+ }
+
+ filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_DIRECTION;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
+ filterConditions[conditionIndex].conditionValue.uint32 = direction;
+
+ conditionIndex++;
+
+ if (configInspectUdp)
+ {
+ filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT16;
+ filterConditions[conditionIndex].conditionValue.uint16 = remotePort;
+
+ conditionIndex++;
+ }
+
+ filter.numFilterConditions = conditionIndex;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterFlowEstablishedCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters at the following layers
+ to intercept flow creations for the original and the proxy flows.
+
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = DDProxyFlowEstablishedClassify;
+ sCallout.notifyFn = DDProxyFlowEstablishedNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Datagram-Data Proxy Flow-Established Callout";
+ displayData.description =
+ L"Intercepts flow creations for the original and the proxy flows";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Flow-Established Filter (Original Flow)",
+ L"Intercepts flow creations for the original flow",
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6,
+ configInspectDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ DD_PROXY_FLOW_ORIGINAL,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Flow-Established Filter (Proxy Flow)",
+ L"Intercepts flow creations for the proxy flow",
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ configNewDestAddrV4 : configNewDestAddrV6,
+ configNewDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ DD_PROXY_FLOW_PROXY,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterDatagramDataCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept TCP traffic at
+ WFP FWPM_LAYER_DATAGRAM_DATA_V4 or FWPM_LAYER_DATAGRAM_DATA_V6 layer.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = DDProxyClassify;
+ sCallout.notifyFn = DDProxyNotify;
+ sCallout.flowDeleteFn = DDProxyFlowDelete;
+ sCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Datagram-Data Proxy Callout";
+ displayData.description = L"Proxies destination address/port for UDP/ICMP";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Filter (Outbound)",
+ L"Proxies destination address/port for UDP/ICMP",
+ IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6,
+ configInspectDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Filter (Inbound)",
+ L"Proxies destination address/port for UDP/ICMP",
+ IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ?
+ configNewDestAddrV4 : configNewDestAddrV6,
+ configNewDestPort,
+ FWP_DIRECTION_INBOUND,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept UDP or
+ non-error ICMP traffic at WFP FWPM_LAYER_DATAGRAM_DATA_V{4|6} and
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4|6} layers.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FWPM_SUBLAYER DDProxySubLayer;
+
+ BOOLEAN engineOpened = FALSE;
+ BOOLEAN inTransaction = FALSE;
+
+ FWPM_SESSION session = {0};
+
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ status = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &gEngineHandle
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ engineOpened = TRUE;
+
+ status = FwpmTransactionBegin(gEngineHandle, 0);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = TRUE;
+
+ RtlZeroMemory(&DDProxySubLayer, sizeof(FWPM_SUBLAYER));
+
+ DDProxySubLayer.subLayerKey = DD_PROXY_SUBLAYER;
+ DDProxySubLayer.displayData.name = L"Datagram-Data Proxy Sub-Layer";
+ DDProxySubLayer.displayData.description =
+ L"Sub-Layer for use by Datagram-Data Proxy callouts";
+ DDProxySubLayer.flags = 0;
+ DDProxySubLayer.weight = FWP_EMPTY; // auto-weight.;
+
+ status = FwpmSubLayerAdd(gEngineHandle, &DDProxySubLayer, NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterFlowEstablishedCallouts(
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,
+ &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4,
+ deviceObject,
+ &gFlowEstablishedCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterFlowEstablishedCallouts(
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6,
+ &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6,
+ deviceObject,
+ &gFlowEstablishedCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterDatagramDataCallouts(
+ &FWPM_LAYER_DATAGRAM_DATA_V4,
+ &DD_PROXY_CALLOUT_V4,
+ deviceObject,
+ &gCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterDatagramDataCallouts(
+ &FWPM_LAYER_DATAGRAM_DATA_V6,
+ &DD_PROXY_CALLOUT_V6,
+ deviceObject,
+ &gCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = FwpmTransactionCommit(gEngineHandle);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = FALSE;
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (inTransaction)
+ {
+ FwpmTransactionAbort(gEngineHandle);
+ _Analysis_assume_lock_not_held_(gEngineHandle); // Potential leak if "FwpmTransactionAbort" fails
+ }
+ if (engineOpened)
+ {
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+void
+DDProxyUnregisterCallouts(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gCalloutIdV6);
+ FwpsCalloutUnregisterById(gCalloutIdV4);
+
+ FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV6);
+ FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV4);
+}
+
+void
+DDProxyRemoveFlows(void)
+{
+ while (!IsListEmpty(&gFlowList))
+ {
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+ LIST_ENTRY* listEntry = NULL;
+ DD_PROXY_FLOW_CONTEXT* flowContext;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ if (!IsListEmpty(&gFlowList))
+ {
+ listEntry = RemoveHeadList(&gFlowList);
+ }
+
+ //
+ // Releasing the lock here since removing the flow context
+ // will invoke the callout's flowDeleteFn synchronously
+ // if there are no active classifications in progress.
+ //
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ if (listEntry != NULL)
+ {
+ flowContext = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_FLOW_CONTEXT,
+ listEntry
+ );
+
+ flowContext->deleted = TRUE;
+
+ FwpsFlowRemoveContext(
+ flowContext->flowId,
+ flowContext->layerId,
+ flowContext->calloutId
+ );
+ }
+ }
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+EvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ gDriverUnloading = TRUE;
+
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ //
+ // Any associated flow contexts must be removed before
+ // a callout can be successfully unregistered.
+ //
+ DDProxyRemoveFlows();
+
+ if (IsListEmpty(&gPacketQueue))
+ {
+ KeSetEvent(
+ &gPacketQueueEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+
+ DDProxyUnregisterCallouts();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+}
+
+//
+// Create the minimal WDF Driver and Device objects required for a WFP callout
+// driver.
+//
+NTSTATUS
+DDProxyInitDriverObjects(
+ _Inout_ DRIVER_OBJECT* driverObject,
+ _In_ const UNICODE_STRING* registryPath,
+ _Out_ WDFDRIVER* pDriver,
+ _Out_ WDFDEVICE* pDevice
+ )
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ WDF_DRIVER_CONFIG_INIT(
+ &config,
+ WDF_NO_EVENT_CALLBACK
+ );
+
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = EvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ pDriver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(
+ *pDriver,
+ &SDDL_DEVOBJ_KERNEL_ONLY
+ );
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WdfDeviceInitSetDeviceType(
+ pInit,
+ FILE_DEVICE_NETWORK
+ );
+
+ WdfDeviceInitSetCharacteristics(
+ pInit,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE
+ );
+
+ WdfDeviceInitSetCharacteristics(
+ pInit,
+ FILE_AUTOGENERATED_DEVICE_NAME,
+ TRUE
+ );
+
+ status = WdfDeviceCreate(
+ &pInit,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ pDevice
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ WdfDeviceInitFree(pInit);
+ goto Exit;
+ }
+
+ WdfControlFinishInitializing(*pDevice);
+
+Exit:
+ return status;
+}
+
+
+NTSTATUS
+DriverEntry(
+ DRIVER_OBJECT* driverObject,
+ UNICODE_STRING* registryPath
+ )
+{
+ NTSTATUS status;
+ WDFDRIVER driver;
+ WDFDEVICE device;
+ WDFKEY configKey;
+ HANDLE threadHandle;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = DDProxyInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyLoadConfig(configKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ //
+ // To proxy UDP traffic, a new destination port or a pair of inspect and
+ // proxy ip address need to be pre-configured. To proxy UDP traffic, a
+ // pair of inspect and proxy ip addresses must be pre-configured.
+ //
+ if (configInspectUdp)
+ {
+ if ((configInspectDestPort == configNewDestPort) &&
+ (((configInspectDestAddrV4 == NULL) ||
+ (configNewDestAddrV4 == NULL)) &&
+ ((configInspectDestAddrV6 == NULL) ||
+ (configNewDestAddrV6 == NULL))))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+ }
+ else
+ {
+ if (((configInspectDestAddrV4 == NULL) ||
+ (configNewDestAddrV4 == NULL)) &&
+ ((configInspectDestAddrV6 == NULL) ||
+ (configNewDestAddrV6 == NULL)))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_TRANSPORT,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InitializeListHead(&gFlowList);
+ KeInitializeSpinLock(&gFlowListLock);
+
+ InitializeListHead(&gPacketQueue);
+ KeInitializeSpinLock(&gPacketQueueLock);
+ KeInitializeEvent(
+ &gPacketQueueEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = DDProxyRegisterCallouts(gWdmDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ DDProxyWorker,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &gThreadObj,
+ NULL
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+
+ ZwClose(threadHandle);
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (gEngineHandle != NULL)
+ {
+ DDProxyUnregisterCallouts();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ }
+
+ return status;
+}
diff --git a/network/trans/ddproxy/sys/DD_proxy.c b/network/trans/ddproxy/sys/DD_proxy.c
new file mode 100644
index 00000000..a75e2cf9
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_proxy.c
@@ -0,0 +1,1039 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the classifyFn, notifiFn, and flowDeleteFn callout
+ functions for the flow-established and datagram-data callouts. In addition
+ the system worker thread that performs the actual packet modifications
+ is also implemented here along with the eventing mechanisms shared between
+ the classify function and the worker thread.
+
+ Packet modification is done out-of-band by a system worker thread using
+ the reference-drop-clone-modify-reinject mechanism. Therefore the sample
+ can serve as a base in scenarios where filtering/modification decision
+ cannot be made within the classifyFn() callout and instead must be made,
+ for example, by an user-mode application.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "DD_proxy.h"
+
+__inline
+void
+DDProxyFreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) DD_PROXY_PENDED_PACKET* packet,
+ _Inout_opt_ __drv_freesMem(Mem) WSACMSGHDR* controlData
+ )
+{
+ FwpsDereferenceNetBufferList(packet->netBufferList, FALSE);
+ DDProxyDereferenceFlowContext(packet->belongingFlow);
+ if (controlData != NULL)
+ {
+ ExFreePoolWithTag(controlData, DD_PROXY_CONTROL_DATA_POOL_TAG);
+ }
+ ExFreePoolWithTag(packet, DD_PROXY_PENDED_PACKET_POOL_TAG);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyFlowEstablishedClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+DDProxyFlowEstablishedClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+/* ++
+
+ This is the classifyFn function of the flow-established callout. It
+ allocates flow context for the original and the proxy flow and associates
+ them with the indicated flow-id. This function also stores information
+ common to both flows in the context. The flow context is inserted into the
+ global flow list.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ BOOLEAN locked = FALSE;
+
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = NULL;
+
+ UNREFERENCED_PARAMETER(layerData);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ flowContextLocal = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(DD_PROXY_FLOW_CONTEXT),
+ DD_PROXY_FLOW_CONTEXT_POOL_TAG
+ );
+
+ if (flowContextLocal == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ RtlZeroMemory(flowContextLocal, sizeof(DD_PROXY_FLOW_CONTEXT));
+
+ flowContextLocal->refCount = 1;
+ flowContextLocal->flowType = (DD_PROXY_FLOW_TYPE)(filter->context);
+ flowContextLocal->addressFamily =
+ (inFixedValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ AF_INET : AF_INET6;
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_FLOW_HANDLE));
+ flowContextLocal->flowId = inMetaValues->flowHandle;
+
+ //
+ // Note that since the consumer of the flow context is the datagram-data
+ // layer classifyFn, layerId and calloutId are set to those of DD and not
+ // flow-established.
+ //
+ flowContextLocal->layerId =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ FWPS_LAYER_DATAGRAM_DATA_V4 : FWPS_LAYER_DATAGRAM_DATA_V6;
+ flowContextLocal->calloutId =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ gCalloutIdV4 : gCalloutIdV6;
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ // Prefast thinks we are ignoring this return value.
+ // If driver is unloading, we give up and ignore it on purpose.
+ // Otherwise, we put the pointer onto the list, but we make it opaque
+ // by casting it as a UINT64, and this tricks Prefast.
+ flowContextLocal->ipv4LocalAddr =
+ RtlUlongByteSwap(
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32
+ );
+ flowContextLocal->protocol =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8;
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&flowContextLocal->localAddr,
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ flowContextLocal->protocol =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;
+ }
+
+ if (flowContextLocal->flowType == DD_PROXY_FLOW_ORIGINAL)
+ {
+ flowContextLocal->toRemoteAddr =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ configNewDestAddrV4 : configNewDestAddrV6;
+ // host-order -> network-order conversion for port.
+ flowContextLocal->toRemotePort = RtlUshortByteSwap(configNewDestPort);
+ }
+ else
+ {
+ NT_ASSERT(flowContextLocal->flowType == DD_PROXY_FLOW_PROXY);
+ flowContextLocal->toRemoteAddr =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6;
+ // host-order -> network-order conversion for port.
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ flowContextLocal->toRemotePort = RtlUshortByteSwap(configInspectDestPort);
+ }
+ if ((flowContextLocal->toRemoteAddr != NULL) &&
+ (flowContextLocal->addressFamily == AF_INET))
+ {
+ // host-order -> network-order conversion for Ipv4 address.
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ flowContextLocal->ipv4NetworkOrderStorage =
+ RtlUlongByteSwap(*(ULONG*)(flowContextLocal->toRemoteAddr));
+ flowContextLocal->toRemoteAddr =
+ (UINT8*)&flowContextLocal->ipv4NetworkOrderStorage;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ locked = TRUE;
+
+ if (!gDriverUnloading)
+ {
+ //
+ // Associate DD_PROXY_FLOW_CONTEXT with the indicated flow-id to be
+ // accessible by the Datagram-Data classifyFn. (i.e. when a packet
+ // belongs to the same flow being classified at Datagram-Data layer,
+ // DD_PROXY_FLOW_CONTEXT will be passed onto the classifyFn as the
+ // "flowContext" parameter.
+ //
+ status = FwpsFlowAssociateContext(
+ flowContextLocal->flowId,
+ flowContextLocal->layerId,
+ flowContextLocal->calloutId,
+ (UINT64)flowContextLocal
+ );
+ if(!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InsertHeadList(&gFlowList, &flowContextLocal->listEntry);
+ flowContextLocal = NULL; // ownership transferred
+ }
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+
+Exit:
+
+ if(locked)
+ {
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+ }
+
+ if (flowContextLocal != NULL)
+ {
+ ExFreePoolWithTag(flowContextLocal, DD_PROXY_FLOW_CONTEXT_POOL_TAG);
+ }
+
+ if(!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+DDProxyClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/* ++
+
+ This is the classifyFn function of the datagram-data callout. It
+ allocates a packet structure to store the classify and meta data and
+ it references the net buffer list for out-of-band modification and
+ re-injection. The packet structure will be queued to the global packet
+ queue. The worker thread will then be signaled, if idle, to process
+ the queue.
+
+-- */
+{
+ DD_PROXY_PENDED_PACKET* packet = NULL;
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext;
+
+ FWPS_PACKET_INJECTION_STATE packetState;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif
+ UNREFERENCED_PARAMETER(filter);
+
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't have the necessary right to alter the packet.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ packet = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(DD_PROXY_PENDED_PACKET),
+ DD_PROXY_PENDED_PACKET_POOL_TAG
+ );
+
+ if (packet == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ RtlZeroMemory(packet, sizeof(DD_PROXY_PENDED_PACKET));
+
+ NT_ASSERT(flowContextLocal != NULL);
+
+ packet->belongingFlow = flowContextLocal;
+ DDProxyReferenceFlowContext(packet->belongingFlow);
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);
+ packet->direction =
+ inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].\
+ value.uint32;
+ }
+ else
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);
+ packet->direction =
+ inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].\
+ value.uint32;
+ }
+ packet->netBufferList = layerData;
+
+ //
+ // Reference the net buffer list to make it accessible outside of
+ // classifyFn.
+ //
+ FwpsReferenceNetBufferList(packet->netBufferList, TRUE);
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPARTMENT_ID));
+ packet->compartmentId = inMetaValues->compartmentId;
+
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
+ packet->endpointHandle = inMetaValues->transportEndpointHandle;
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ packet->ipv4RemoteAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32
+ );
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&packet->remoteAddr,
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+
+ }
+ packet->remoteScopeId = inMetaValues->remoteScopeId;
+
+ if (FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
+ {
+ NT_ASSERT(inMetaValues->controlDataLength > 0);
+
+ packet->controlData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ inMetaValues->controlDataLength,
+ DD_PROXY_CONTROL_DATA_POOL_TAG
+ );
+ if (packet->controlData == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ RtlCopyMemory(
+ packet->controlData,
+ inMetaValues->controlData,
+ inMetaValues->controlDataLength
+ );
+
+ packet->controlDataLength = inMetaValues->controlDataLength;
+ }
+ }
+ else
+ {
+ NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND);
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);
+ packet->interfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
+ packet->subInterfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
+ }
+ else
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);
+ packet->interfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32;
+ packet->subInterfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].value.uint32;
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_IP_HEADER_SIZE));
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE));
+ packet->ipHeaderSize = inMetaValues->ipHeaderSize;
+ packet->transportHeaderSize = inMetaValues->transportHeaderSize;
+
+ packet->nblOffset =
+ NET_BUFFER_DATA_OFFSET(NET_BUFFER_LIST_FIRST_NB(packet->netBufferList));
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gPacketQueue, &packet->listEntry);
+ packet = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any incoming packets.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gPacketQueueEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+Exit:
+
+ if (packet != NULL)
+ {
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ return;
+}
+
+NTSTATUS
+DDProxyFlowEstablishedNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+DDProxyNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+void
+DDProxyFlowDelete(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext
+ )
+/* ++
+
+ This is the flowDeleteFn function of the datagram-data callout. It
+ removes the flow context from the global flow list and dereference the
+ context.
+
+-- */
+{
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext;
+
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ UNREFERENCED_PARAMETER(layerId);
+ UNREFERENCED_PARAMETER(calloutId);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ if (!flowContextLocal->deleted)
+ {
+ RemoveEntryList(&flowContextLocal->listEntry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ DDProxyDereferenceFlowContext(flowContextLocal);
+}
+
+typedef struct UDP_HEADER_ {
+ UINT16 srcPort;
+ UINT16 destPort;
+ UINT16 length;
+ UINT16 checksum;
+} UDP_HEADER;
+
+void DDProxyInjectComplete(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ DD_PROXY_PENDED_PACKET* packet = context;
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+
+ DDProxyFreePendedPacket(packet, packet->controlData);
+}
+
+NTSTATUS
+DDProxyCloneModifyReinjectOutbound(
+ _In_ DD_PROXY_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the outbound net buffer list and, if needed,
+ modifies the destination port of all indicated packets (i.e. NET_BUFFER)
+ and/or send-injects the clone to a new destination address.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ UDP_HEADER* udpHeader;
+ FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0};
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ //
+ // Check to see if port modification is required.
+ //
+ if ((packet->belongingFlow->protocol == IPPROTO_UDP) &&
+ (packet->belongingFlow->toRemotePort != 0))
+ {
+ NET_BUFFER* netBuffer;
+
+ //
+ // The data offset of outbound transport packets is the beginning of
+ // transport header (e.g. UDP header). The IP header has not yet been
+ // constructed at Datagram-Data (or outbound Transport) layer.
+ //
+ // Note the packet offset is inherited by the clone.
+ //
+
+ //
+ // Outbound net buffer list can contain more than one net buffer (e.g.
+ // one UDP packet).
+ //
+
+ for (netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);
+ netBuffer != NULL;
+ netBuffer = NET_BUFFER_NEXT_NB(netBuffer))
+ {
+ udpHeader = NdisGetDataBuffer(
+ netBuffer,
+ sizeof(UDP_HEADER),
+ NULL,
+ sizeof(UINT16),
+ 0
+ );
+ NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer
+ // is contiguous and 2-byte aligned.
+ _Analysis_assume_(udpHeader != NULL);
+
+ udpHeader->destPort = packet->belongingFlow->toRemotePort;
+ udpHeader->checksum = 0;
+ }
+ }
+
+ //
+ // Determine whehter we need to proxy the destination address. If not,
+ // we set the remoteAddress to the same address that was initially
+ // classified.
+ //
+ sendArgs.remoteAddress =
+ (packet->belongingFlow->toRemoteAddr ? packet->belongingFlow->toRemoteAddr
+ : (UINT8*)&packet->remoteAddr);
+ sendArgs.remoteScopeId = packet->remoteScopeId;
+ sendArgs.controlData = packet->controlData;
+ sendArgs.controlDataLength = packet->controlDataLength;
+
+ //
+ // Send-inject the modified net buffer list to the new destination address.
+ //
+
+ status = FwpsInjectTransportSendAsync(
+ gInjectionHandle,
+ NULL,
+ packet->endpointHandle,
+ 0,
+ &sendArgs,
+ packet->belongingFlow->addressFamily,
+ packet->compartmentId,
+ clonedNetBufferList,
+ DDProxyInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyCloneModifyReinjectInbound(
+ _In_ DD_PROXY_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the inbound net buffer list and, if needed,
+ modifies the source port and/or source address and receive-injects
+ the clone back to the tcpip stack.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ NET_BUFFER* netBuffer;
+ UDP_HEADER* udpHeader;
+ ULONG nblOffset;
+ NDIS_STATUS ndisStatus;
+
+ //
+ // For inbound net buffer list, we can assume it contains only one
+ // net buffer.
+ //
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
+
+ nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer);
+
+ //
+ // The TCP/IP stack could have retreated the net buffer list by the
+ // transportHeaderSize amount; detect the condition here to avoid
+ // retreating twice.
+ //
+ if (nblOffset != packet->nblOffset)
+ {
+ NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);
+ packet->transportHeaderSize = 0;
+ }
+
+ //
+ // Adjust the net buffer list offset to the start of the IP header.
+ //
+ ndisStatus = NdisRetreatNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ 0,
+ NULL
+ );
+ _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);
+
+ //
+ // Note that the clone will inherit the original net buffer list's offset.
+ //
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+
+ //
+ // Undo the adjustment on the original net buffer list.
+ //
+
+ NdisAdvanceNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ //
+ // Check to see if port modification is required.
+ //
+ if ((packet->belongingFlow->protocol == IPPROTO_UDP) &&
+ (packet->belongingFlow->toRemotePort != 0))
+ {
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);
+
+ //
+ // Advance to the beginning of the transport header (i.e. UDP header).
+ //
+ NdisAdvanceNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize,
+ FALSE,
+ NULL
+ );
+
+ udpHeader = NdisGetDataBuffer(
+ netBuffer,
+ sizeof(UDP_HEADER),
+ NULL,
+ sizeof(UINT16),
+ 0
+ );
+ NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer
+ // is contiguous and 2-byte aligned.
+ _Analysis_assume_(udpHeader != NULL);
+
+ udpHeader->destPort =
+ packet->belongingFlow->toRemotePort;
+ // This is our new source port -- or
+ // the destination port of the original
+ // outbound traffic.
+ udpHeader->checksum = 0;
+
+ //
+ // Undo the advance. Net buffer list needs to be positioned at the
+ // beginning of IP header for address modification and/or receive-
+ // injection.
+ //
+ ndisStatus = NdisRetreatNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize,
+ 0,
+ NULL
+ );
+ _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);
+
+ }
+
+ if (packet->belongingFlow->toRemoteAddr != NULL)
+ {
+ status = FwpsConstructIpHeaderForTransportPacket(
+ clonedNetBufferList,
+ packet->ipHeaderSize,
+ packet->belongingFlow->addressFamily,
+ packet->belongingFlow->toRemoteAddr,
+ // This is our new source address --
+ // or the destination address of the
+ // original outbound traffic.
+ (UINT8*)&packet->belongingFlow->localAddr,
+ // This is the destination address of
+ // the clone -- or the source of the
+ // original outbound traffic.
+ packet->belongingFlow->protocol,
+ 0,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ status = FwpsInjectTransportReceiveAsync(
+ gInjectionHandle,
+ NULL,
+ NULL,
+ 0,
+ packet->belongingFlow->addressFamily,
+ packet->compartmentId,
+ packet->interfaceIndex,
+ packet->subInterfaceIndex,
+ clonedNetBufferList,
+ DDProxyInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+void
+DDProxyWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This worker thread waits for the packet queue event when the queue is
+ empty; and it will be woken up when there are packets queued needing to
+ be proxied to or from the new destination address/port. Once awaking,
+ It will run in a loop to clone-modify-reinject packets until the packet
+ queue is exhausted (and it will go to sleep waiting for more work).
+
+ The worker thread will end once it detected the driver is unloading.
+
+-- */
+{
+ DD_PROXY_PENDED_PACKET* packet;
+ LIST_ENTRY* listEntry;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ UNREFERENCED_PARAMETER(StartContext);
+
+ for(;;)
+ {
+ KeWaitForSingleObject(
+ &gPacketQueueEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (gDriverUnloading)
+ {
+ break;
+ }
+
+ NT_ASSERT(!IsListEmpty(&gPacketQueue));
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_PENDED_PACKET,
+ listEntry
+ );
+
+ if (!packet->belongingFlow->deleted)
+ {
+ NTSTATUS status;
+
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ status = DDProxyCloneModifyReinjectOutbound(packet);
+ }
+ else
+ {
+ status = DDProxyCloneModifyReinjectInbound(packet);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ packet = NULL; // ownership transferred.
+ }
+ }
+
+ if (packet != NULL)
+ {
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (IsListEmpty(&gPacketQueue) && !gDriverUnloading)
+ {
+ KeClearEvent(&gPacketQueueEvent);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ }
+
+ NT_ASSERT(gDriverUnloading);
+
+ //
+ // Discard all the pended packets if driver is being unloaded.
+ //
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ while (!IsListEmpty(&gPacketQueue))
+ {
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_PENDED_PACKET,
+ listEntry
+ );
+
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ PsTerminateSystemThread(STATUS_SUCCESS);
+
+
+}
diff --git a/network/trans/ddproxy/sys/DD_proxy.h b/network/trans/ddproxy/sys/DD_proxy.h
new file mode 100644
index 00000000..197b0ff9
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_proxy.h
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This header files declares common data types and function prototypes used
+ throughout the Datagram-Data transparent proxy sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _DD_PROXY_H_
+#define _DD_PROXY_H_
+
+typedef enum DD_PROXY_FLOW_TYPE_
+{
+ DD_PROXY_FLOW_ORIGINAL,
+ DD_PROXY_FLOW_PROXY
+} DD_PROXY_FLOW_TYPE;
+
+//
+// DD_PROXY_FLOW_CONTEXT is the object type we used to stored information
+// specific flow. This callout driver maintains two kind of flow contexts --
+// the original flow and the flow being proxied to.
+//
+
+typedef struct DD_PROXY_FLOW_CONTEXT_
+{
+ LIST_ENTRY listEntry;
+
+ BOOLEAN deleted;
+
+ DD_PROXY_FLOW_TYPE flowType;
+ ADDRESS_FAMILY addressFamily;
+
+ #pragma warning(push)
+ #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+ union
+ {
+ FWP_BYTE_ARRAY16 localAddr;
+ UINT32 ipv4LocalAddr;
+ };
+ #pragma warning(pop)
+
+
+ UINT8 protocol;
+
+ UINT64 flowId;
+ UINT16 layerId;
+ UINT32 calloutId;
+
+ UINT32 ipv4NetworkOrderStorage;
+
+ //
+ // For DD_PROXY_FLOW_ORIGINAL type, toRemote* is the new address/port
+ // we are proxing to. For DD_PROXY_FLOW_PROXY type, it is the address/
+ // port that we will need to revert to.
+ //
+ UINT8* toRemoteAddr;
+ UINT16 toRemotePort;
+
+ LONG refCount;
+} DD_PROXY_FLOW_CONTEXT;
+
+//
+// DD_PROXY_PENDED_PACKET is the object type we used to store all information
+// needed for out-of-band packet modification and re-injection. This type
+// also points back to the flow context the packet belongs to.
+
+typedef struct DD_PROXY_PENDED_PACKET_
+{
+ LIST_ENTRY listEntry;
+
+ DD_PROXY_FLOW_CONTEXT* belongingFlow;
+ FWP_DIRECTION direction;
+
+ //
+ // Common fields for inbound and outbound traffic.
+ //
+ NET_BUFFER_LIST* netBufferList;
+ COMPARTMENT_ID compartmentId;
+
+ //
+ // Data fields for outbound packet re-injection.
+ //
+ UINT64 endpointHandle;
+
+ #pragma warning(push)
+ #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+ union
+ {
+ FWP_BYTE_ARRAY16 remoteAddr;
+ UINT32 ipv4RemoteAddr;
+ };
+ #pragma warning(pop)
+
+ SCOPE_ID remoteScopeId;
+ WSACMSGHDR* controlData;
+ ULONG controlDataLength;
+
+ //
+ // Data fields for inbound packet re-injection.
+ //
+ ULONG nblOffset;
+ UINT32 ipHeaderSize;
+ UINT32 transportHeaderSize;
+ IF_INDEX interfaceIndex;
+ IF_INDEX subInterfaceIndex;
+} DD_PROXY_PENDED_PACKET;
+
+//
+// Pooltags used by this callout driver.
+//
+#define DD_PROXY_FLOW_CONTEXT_POOL_TAG 'olfD'
+#define DD_PROXY_PENDED_PACKET_POOL_TAG 'kppD'
+#define DD_PROXY_CONTROL_DATA_POOL_TAG 'dcdD'
+
+//
+// Shared global data.
+//
+extern UINT16 configInspectDestPort;
+extern UINT8* configInspectDestAddrV4;
+extern UINT8* configInspectDestAddrV6;
+
+extern UINT16 configNewDestPort;
+extern UINT8* configNewDestAddrV4;
+extern UINT8* configNewDestAddrV6;
+
+extern HANDLE gInjectionHandle;
+
+extern LIST_ENTRY gFlowList;
+extern KSPIN_LOCK gFlowListLock;
+
+extern LIST_ENTRY gPacketQueue;
+extern KSPIN_LOCK gPacketQueueLock;
+extern KEVENT gPacketQueueEvent;
+
+extern UINT32 gCalloutIdV4;
+extern UINT32 gCalloutIdV6;
+
+extern BOOLEAN gDriverUnloading;
+
+//
+// Utility functions
+//
+
+__inline void
+DDProxyReferenceFlowContext(
+ _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext
+ )
+{
+ NT_ASSERT(flowContext->refCount > 0);
+ InterlockedIncrement(&flowContext->refCount);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+__inline
+void
+DDProxyDereferenceFlowContext(
+ _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext
+ )
+{
+ NT_ASSERT(flowContext->refCount > 0);
+ InterlockedDecrement(&flowContext->refCount);
+ if (flowContext->refCount == 0)
+ {
+ ExFreePoolWithTag(flowContext, DD_PROXY_FLOW_CONTEXT_POOL_TAG);
+ }
+}
+
+//
+// Shared function prototypes
+//
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyFlowEstablishedClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+DDProxyClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else
+
+void
+DDProxyFlowEstablishedClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+DDProxyClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyFlowDelete(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext
+ );
+
+NTSTATUS
+DDProxyFlowEstablishedNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+
+NTSTATUS
+DDProxyNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+KSTART_ROUTINE DDProxyWorker;
+
+#endif // _DD_PROXY_H_
diff --git a/network/trans/ddproxy/sys/ddproxy.inf b/network/trans/ddproxy/sys/ddproxy.inf
new file mode 100644
index 00000000..dd504967
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.inf
@@ -0,0 +1,63 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; DatagramData Proxy Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = DDProxy.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %DDProxyDisk%,,,""
+
+[SourceDisksFiles]
+ DDProxy.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ DDProxy.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %DDProxyServiceDesc%
+ CopyFiles = DDProxy.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %DDProxyServiceName%,,DDProxy.Service
+
+[DefaultUninstall]
+ DelFiles = DDProxy.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %DDProxyServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = DDProxy.DelRegistry
+
+[DDProxy.DriverFiles]
+ DDProxy.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[DDProxy.Service]
+ DisplayName = %DDProxyServiceName%
+ Description = %DDProxyServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\DDProxy.sys ; %WinDir%\System32\Drivers\DDProxy.sys
+ AddReg = DDProxy.AddRegistry
+
+[DDProxy.AddRegistry]
+ HKR,"Parameters","DestinationAddressToIntercept",0x00000000,"10.0.0.1" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","NewDestinationAddress",0x00000000,"10.0.0.2" ; FLG_ADDREG_TYPE_SZ
+
+[DDProxy.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ DDProxyDisk = "DatagramData Proxy Installation Disk"
+ DDProxyServiceDesc = "DatagramData Proxy Callout Driver"
+ DDProxyServiceName = "DDProxy" \ No newline at end of file
diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj b/network/trans/ddproxy/sys/ddproxy.vcxproj
new file mode 100644
index 00000000..9fd6e6af
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.vcxproj
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{91B8C3EC-EC68-40D0-BDAE-FECDC2A5A69E}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="dd_drv.c" />
+ <ClCompile Include="dd_proxy.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters
new file mode 100644
index 00000000..9728a6bb
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{667070D4-ABD3-4134-83D9-C2E8E3B4D990}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{55D8461C-9BC4-4CBA-8364-1C9E8628AD2E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{89C687B6-C04D-48DD-BFC4-36AB091E7E94}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3E15A537-E520-445D-AFC4-4CFCEF6234E6}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dd_drv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dd_proxy.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/inspect/ReadMe.md b/network/trans/inspect/ReadMe.md
new file mode 100644
index 00000000..a288e694
--- /dev/null
+++ b/network/trans/inspect/ReadMe.md
@@ -0,0 +1,55 @@
+Windows Filtering Platform Traffic Inspection Sample
+====================================================
+
+This sample driver demonstrates the traffic inspection capabilities of the Windows Filtering Platform (WFP).
+
+The sample driver consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Inspect.sys) that intercepts all transport layer traffic (for example, Transmission Control Protocol (TCP), User Datagram Protocol (UDP), and nonerror Internet Control Message Protocol (ICMP)) sent to or received from a configurable remote peer and queues then to a worker thread for out-of-band processing.
+
+Inspect.sys inspects inbound and outbound connections and all packets that belong to those connections. Additionally, Inspect.sys demonstrates the special considerations that are required to be compatible with Internet Protocol security (IPsec) in Windows Vista and Windows Server 2008.
+
+Inspect.sys implements the `ClassifyFn` callout functions for the ALE Connect, Recv-Accept, and Transport callouts. In addition, the system worker thread that performs the actual packet inspection is also implemented along with the event mechanisms that are shared between the Classify function and the worker thread.
+
+Connect/Packet inspection is done out-of-band by a system worker thread by using the reference-drop-clone-reinject mechanism as well as the ALE pend/complete mechanism. Therefore, the sample can serve as a basis for scenarios in which a filtering decision cannot be made within the `classifyFn()` callout and instead must be made, for example, by a user-mode application.
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, navigate to DriverTest\\Drivers, and locate the file inspect.inf. Right click inspect.inf, and choose **Install**.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). After you have prepared the target computer for manual deployment, continue with these steps:
+
+1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\WfpTrafficInspectionSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click inspect.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+1. On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**inspect**\\**Parameters**
+
+2. Create a REG\_DWORD entry named **BlockTraffic** and set it's value to 0 for permit or 1 to block.
+
+3. Create a REG\_SZ entry named **RemoteAddressToInspect**, and set it's value to an IPV4 or IPV6 address (example: 10.0.0.2).
+
+Start the inspect service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start inspect**. (To stop the driver, enter **net stop inspect**.)
+
+Remarks
+-------
+
+For more information on creating a Windows Filtering Platform Callout Driver, see [Windows Filtering Platform Callout Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571068).
+
diff --git a/network/trans/inspect/inspect.sln b/network/trans/inspect/inspect.sln
new file mode 100644
index 00000000..79901c54
--- /dev/null
+++ b/network/trans/inspect/inspect.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inspect", "sys\inspect.vcxproj", "{43AC1739-03F1-4465-8A16-F5FCD06BC2E9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.Build.0 = Debug|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.ActiveCfg = Release|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.Build.0 = Release|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.ActiveCfg = Debug|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.Build.0 = Debug|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.ActiveCfg = Release|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/inspect/sys/TL_drv.c b/network/trans/inspect/sys/TL_drv.c
new file mode 100644
index 00000000..5186b69c
--- /dev/null
+++ b/network/trans/inspect/sys/TL_drv.c
@@ -0,0 +1,927 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Transport Inspect Proxy Callout Driver Sample.
+
+ This sample callout driver intercepts all transport layer traffic (e.g.
+ TCP, UDP, and non-error ICMP) sent to or receive from a (configurable)
+ remote peer and queue them to a worker thread for out-of-band processing.
+ The sample performs inspection of inbound and outbound connections as
+ well as all packets belong to those connections. In addition the sample
+ demonstrates special considerations required to be compatible with Windows
+ Vista and Windows Server 2008�s IpSec implementation.
+
+ Inspection parameters are configurable via the following registry
+ values --
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Inspect\Parameters
+
+ o BlockTraffic (REG_DWORD) : 0 (permit, default); 1 (block)
+ o RemoteAddressToInspect (REG_SZ) : literal IPv4/IPv6 string
+ (e.g. �10.0.0.1�)
+ The sample is IP version agnostic. It performs inspection for
+ both IPv4 and IPv6 traffic.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include <ws2ipdef.h>
+#include <in6addr.h>
+#include <ip2string.h>
+
+#include "inspect.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+
+//
+// Configurable parameters (addresses and ports are in host order)
+//
+
+BOOLEAN configPermitTraffic = TRUE;
+
+UINT8* configInspectRemoteAddrV4 = NULL;
+UINT8* configInspectRemoteAddrV6 = NULL;
+
+IN_ADDR remoteAddrStorageV4;
+IN6_ADDR remoteAddrStorageV6;
+
+//
+// Callout and sublayer GUIDs
+//
+
+// bb6e405b-19f4-4ff3-b501-1a3dc01aae01
+DEFINE_GUID(
+ TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V4,
+ 0xbb6e405b,
+ 0x19f4,
+ 0x4ff3,
+ 0xb5, 0x01, 0x1a, 0x3d, 0xc0, 0x1a, 0xae, 0x01
+);
+// cabf7559-7c60-46c8-9d3b-2155ad5cf83f
+DEFINE_GUID(
+ TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V6,
+ 0xcabf7559,
+ 0x7c60,
+ 0x46c8,
+ 0x9d, 0x3b, 0x21, 0x55, 0xad, 0x5c, 0xf8, 0x3f
+);
+// 07248379-248b-4e49-bf07-24d99d52f8d0
+DEFINE_GUID(
+ TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V4,
+ 0x07248379,
+ 0x248b,
+ 0x4e49,
+ 0xbf, 0x07, 0x24, 0xd9, 0x9d, 0x52, 0xf8, 0xd0
+);
+// 6d126434-ed67-4285-925c-cb29282e0e06
+DEFINE_GUID(
+ TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V6,
+ 0x6d126434,
+ 0xed67,
+ 0x4285,
+ 0x92, 0x5c, 0xcb, 0x29, 0x28, 0x2e, 0x0e, 0x06
+);
+// 76b743d4-1249-4614-a632-6f9c4d08d25a
+DEFINE_GUID(
+ TL_INSPECT_ALE_CONNECT_CALLOUT_V4,
+ 0x76b743d4,
+ 0x1249,
+ 0x4614,
+ 0xa6, 0x32, 0x6f, 0x9c, 0x4d, 0x08, 0xd2, 0x5a
+);
+
+// ac80683a-5b84-43c3-8ae9-eddb5c0d23c2
+DEFINE_GUID(
+ TL_INSPECT_ALE_CONNECT_CALLOUT_V6,
+ 0xac80683a,
+ 0x5b84,
+ 0x43c3,
+ 0x8a, 0xe9, 0xed, 0xdb, 0x5c, 0x0d, 0x23, 0xc2
+);
+
+// 7ec7f7f5-0c55-4121-adc5-5d07d2ac0cef
+DEFINE_GUID(
+ TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V4,
+ 0x7ec7f7f5,
+ 0x0c55,
+ 0x4121,
+ 0xad, 0xc5, 0x5d, 0x07, 0xd2, 0xac, 0x0c, 0xef
+);
+
+// b74ac2ed-4e71-4564-9975-787d5168a151
+DEFINE_GUID(
+ TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V6,
+ 0xb74ac2ed,
+ 0x4e71,
+ 0x4564,
+ 0x99, 0x75, 0x78, 0x7d, 0x51, 0x68, 0xa1, 0x51
+);
+
+// 2e207682-d95f-4525-b966-969f26587f03
+DEFINE_GUID(
+ TL_INSPECT_SUBLAYER,
+ 0x2e207682,
+ 0xd95f,
+ 0x4525,
+ 0xb9, 0x66, 0x96, 0x9f, 0x26, 0x58, 0x7f, 0x03
+);
+
+//
+// Callout driver global variables
+//
+
+DEVICE_OBJECT* gWdmDevice;
+WDFKEY gParametersKey;
+
+HANDLE gEngineHandle;
+UINT32 gAleConnectCalloutIdV4, gOutboundTlCalloutIdV4;
+UINT32 gAleRecvAcceptCalloutIdV4, gInboundTlCalloutIdV4;
+UINT32 gAleConnectCalloutIdV6, gOutboundTlCalloutIdV6;
+UINT32 gAleRecvAcceptCalloutIdV6, gInboundTlCalloutIdV6;
+
+HANDLE gInjectionHandle;
+
+LIST_ENTRY gConnList;
+KSPIN_LOCK gConnListLock;
+LIST_ENTRY gPacketQueue;
+KSPIN_LOCK gPacketQueueLock;
+
+KEVENT gWorkerEvent;
+
+BOOLEAN gDriverUnloading = FALSE;
+void* gThreadObj;
+
+//
+// Callout driver implementation
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD TLInspectEvtDriverUnload;
+
+NTSTATUS
+TLInspectLoadConfig(
+ _In_ const WDFKEY key
+ )
+{
+ NTSTATUS status;
+ DECLARE_CONST_UNICODE_STRING(valueName, L"RemoteAddressToInspect");
+ DECLARE_UNICODE_STRING_SIZE(value, INET6_ADDRSTRLEN);
+
+ status = WdfRegistryQueryUnicodeString(key, &valueName, NULL, &value);
+
+ if (NT_SUCCESS(status))
+ {
+ PWSTR terminator;
+ // Defensively null-terminate the string
+ value.Length = min(value.Length, value.MaximumLength - sizeof(WCHAR));
+ value.Buffer[value.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ status = RtlIpv4StringToAddressW(
+ value.Buffer,
+ TRUE,
+ &terminator,
+ &remoteAddrStorageV4
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ remoteAddrStorageV4.S_un.S_addr =
+ RtlUlongByteSwap(remoteAddrStorageV4.S_un.S_addr);
+ configInspectRemoteAddrV4 = &remoteAddrStorageV4.S_un.S_un_b.s_b1;
+ }
+ else
+ {
+ status = RtlIpv6StringToAddressW(
+ value.Buffer,
+ &terminator,
+ &remoteAddrStorageV6
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ configInspectRemoteAddrV6 = (UINT8*)(&remoteAddrStorageV6.u.Byte[0]);
+ }
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectAddFilter(
+ _In_ const wchar_t* filterName,
+ _In_ const wchar_t* filterDesc,
+ _In_reads_opt_(16) const UINT8* remoteAddr,
+ _In_ UINT64 context,
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPM_FILTER filter = {0};
+ FWPM_FILTER_CONDITION filterConditions[3] = {0};
+ UINT conditionIndex;
+
+ filter.layerKey = *layerKey;
+ filter.displayData.name = (wchar_t*)filterName;
+ filter.displayData.description = (wchar_t*)filterDesc;
+
+ filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
+ filter.action.calloutKey = *calloutKey;
+ filter.filterCondition = filterConditions;
+ filter.subLayerKey = TL_INSPECT_SUBLAYER;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+ filter.rawContext = context;
+
+ conditionIndex = 0;
+
+ if (remoteAddr != NULL)
+ {
+ filterConditions[conditionIndex].fieldKey =
+ FWPM_CONDITION_IP_REMOTE_ADDRESS;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+
+ if (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_INBOUND_TRANSPORT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4))
+ {
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
+ filterConditions[conditionIndex].conditionValue.uint32 =
+ *(UINT32*)remoteAddr;
+ }
+ else
+ {
+ filterConditions[conditionIndex].conditionValue.type =
+ FWP_BYTE_ARRAY16_TYPE;
+ filterConditions[conditionIndex].conditionValue.byteArray16 =
+ (FWP_BYTE_ARRAY16*)remoteAddr;
+ }
+
+ conditionIndex++;
+ }
+
+ filter.numFilterConditions = conditionIndex;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterALEClassifyCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters at the following layers
+ to intercept inbound or outbound connect attempts.
+
+ FWPM_LAYER_ALE_AUTH_CONNECT_V4
+ FWPM_LAYER_ALE_AUTH_CONNECT_V6
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+
+ if (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V6))
+ {
+ sCallout.classifyFn = TLInspectALEConnectClassify;
+ sCallout.notifyFn = TLInspectALEConnectNotify;
+ }
+ else
+ {
+ sCallout.classifyFn = TLInspectALERecvAcceptClassify;
+ sCallout.notifyFn = TLInspectALERecvAcceptNotify;
+ }
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Transport Inspect ALE Classify Callout";
+ displayData.description =
+ L"Intercepts inbound or outbound connect attempts";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectAddFilter(
+ L"Transport Inspect ALE Classify",
+ L"Intercepts inbound or outbound connect attempts",
+ (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4)) ?
+ configInspectRemoteAddrV4 : configInspectRemoteAddrV6,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterTransportCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept transport
+ traffic at the following layers --
+
+ FWPM_LAYER_OUTBOUND_TRANSPORT_V4
+ FWPM_LAYER_OUTBOUND_TRANSPORT_V6
+ FWPM_LAYER_INBOUND_TRANSPORT_V4
+ FWPM_LAYER_INBOUND_TRANSPORT_V6
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = TLInspectTransportClassify;
+ sCallout.notifyFn = TLInspectTransportNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Transport Inspect Callout";
+ displayData.description = L"Inspect inbound/outbound transport traffic";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectAddFilter(
+ L"Transport Inspect Filter (Outbound)",
+ L"Inspect inbound/outbound transport traffic",
+ (IsEqualGUID(layerKey, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_INBOUND_TRANSPORT_V4))?
+ configInspectRemoteAddrV4 : configInspectRemoteAddrV6,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept
+ transport traffic at ALE AUTH_CONNECT/AUTH_RECV_ACCEPT and
+ INBOUND/OUTBOUND transport layers.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FWPM_SUBLAYER TLInspectSubLayer;
+
+ BOOLEAN engineOpened = FALSE;
+ BOOLEAN inTransaction = FALSE;
+
+ FWPM_SESSION session = {0};
+
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ status = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &gEngineHandle
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ engineOpened = TRUE;
+
+ status = FwpmTransactionBegin(gEngineHandle, 0);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = TRUE;
+
+ RtlZeroMemory(&TLInspectSubLayer, sizeof(FWPM_SUBLAYER));
+
+ TLInspectSubLayer.subLayerKey = TL_INSPECT_SUBLAYER;
+ TLInspectSubLayer.displayData.name = L"Transport Inspect Sub-Layer";
+ TLInspectSubLayer.displayData.description =
+ L"Sub-Layer for use by Transport Inspect callouts";
+ TLInspectSubLayer.flags = 0;
+ TLInspectSubLayer.weight = 0; // must be less than the weight of
+ // FWPM_SUBLAYER_UNIVERSAL to be
+ // compatible with Vista's IpSec
+ // implementation.
+
+ status = FwpmSubLayerAdd(gEngineHandle, &TLInspectSubLayer, NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (configInspectRemoteAddrV4 != NULL)
+ {
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+ &TL_INSPECT_ALE_CONNECT_CALLOUT_V4,
+ deviceObject,
+ &gAleConnectCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
+ &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V4,
+ deviceObject,
+ &gAleRecvAcceptCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
+ &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V4,
+ deviceObject,
+ &gOutboundTlCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_INBOUND_TRANSPORT_V4,
+ &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V4,
+ deviceObject,
+ &gInboundTlCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ if (configInspectRemoteAddrV6 != NULL)
+ {
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+ &TL_INSPECT_ALE_CONNECT_CALLOUT_V6,
+ deviceObject,
+ &gAleConnectCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
+ &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V6,
+ deviceObject,
+ &gAleRecvAcceptCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_OUTBOUND_TRANSPORT_V6,
+ &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V6,
+ deviceObject,
+ &gOutboundTlCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_INBOUND_TRANSPORT_V6,
+ &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V6,
+ deviceObject,
+ &gInboundTlCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ status = FwpmTransactionCommit(gEngineHandle);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = FALSE;
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (inTransaction)
+ {
+ FwpmTransactionAbort(gEngineHandle);
+ _Analysis_assume_lock_not_held_(gEngineHandle); // Potential leak if "FwpmTransactionAbort" fails
+ }
+ if (engineOpened)
+ {
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+void
+TLInspectUnregisterCallouts(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gOutboundTlCalloutIdV6);
+ FwpsCalloutUnregisterById(gOutboundTlCalloutIdV4);
+ FwpsCalloutUnregisterById(gInboundTlCalloutIdV6);
+ FwpsCalloutUnregisterById(gInboundTlCalloutIdV4);
+
+ FwpsCalloutUnregisterById(gAleConnectCalloutIdV6);
+ FwpsCalloutUnregisterById(gAleConnectCalloutIdV4);
+ FwpsCalloutUnregisterById(gAleRecvAcceptCalloutIdV6);
+ FwpsCalloutUnregisterById(gAleRecvAcceptCalloutIdV4);
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+TLInspectEvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ gDriverUnloading = TRUE;
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue))
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+ }
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+
+ TLInspectUnregisterCallouts();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+}
+
+NTSTATUS
+TLInspectInitDriverObjects(
+ _Inout_ DRIVER_OBJECT* driverObject,
+ _In_ const UNICODE_STRING* registryPath,
+ _Out_ WDFDRIVER* pDriver,
+ _Out_ WDFDEVICE* pDevice
+ )
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = TLInspectEvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ pDriver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(*pDriver, &SDDL_DEVOBJ_KERNEL_ONLY);
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, FALSE);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
+
+ status = WdfDeviceCreate(&pInit, WDF_NO_OBJECT_ATTRIBUTES, pDevice);
+ if (!NT_SUCCESS(status))
+ {
+ WdfDeviceInitFree(pInit);
+ goto Exit;
+ }
+
+ WdfControlFinishInitializing(*pDevice);
+
+Exit:
+ return status;
+}
+
+NTSTATUS
+DriverEntry(
+ DRIVER_OBJECT* driverObject,
+ UNICODE_STRING* registryPath
+ )
+{
+ NTSTATUS status;
+ WDFDRIVER driver;
+ WDFDEVICE device;
+ HANDLE threadHandle;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = TLInspectInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &gParametersKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectLoadConfig(gParametersKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ if ((configInspectRemoteAddrV4 == NULL) &&
+ (configInspectRemoteAddrV6 == NULL))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_TRANSPORT,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InitializeListHead(&gConnList);
+ KeInitializeSpinLock(&gConnListLock);
+
+ InitializeListHead(&gPacketQueue);
+ KeInitializeSpinLock(&gPacketQueueLock);
+
+ KeInitializeEvent(
+ &gWorkerEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = TLInspectRegisterCallouts(gWdmDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ TLInspectWorker,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &gThreadObj,
+ NULL
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+
+ ZwClose(threadHandle);
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (gEngineHandle != NULL)
+ {
+ TLInspectUnregisterCallouts();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ }
+
+ return status;
+};
+
diff --git a/network/trans/inspect/sys/inspect.c b/network/trans/inspect/sys/inspect.c
new file mode 100644
index 00000000..26b01e9b
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.c
@@ -0,0 +1,1418 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the classifyFn callout functions for the ALE connect,
+ recv-accept, and transport callouts. In addition the system worker thread
+ that performs the actual packet inspection is also implemented here along
+ with the eventing mechanisms shared between the classify function and the
+ worker thread.
+
+ connect/Packet inspection is done out-of-band by a system worker thread
+ using the reference-drop-clone-reinject as well as ALE pend/complete
+ mechanism. Therefore the sample can serve as a base in scenarios where
+ filtering decision cannot be made within the classifyFn() callout and
+ instead must be made, for example, by an user-mode application.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#include <ntddk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inspect.h"
+#include "utils.h"
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+/* ++
+
+ This is the classifyFn function for the ALE connect (v4 and v6) callout.
+ For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
+ is not set), it is queued to the connection list for inspection by the
+ worker thread. For re-auth, we first check if it is triggered by an ealier
+ FwpsCompleteOperation call by looking for an pended connect that has been
+ inspected. If found, we remove it from the connect list and return the
+ inspection result; otherwise we can conclude that the re-auth is triggered
+ by policy change so we queue it to the packet queue to be process by the
+ worker thread like any other regular packets.
+
+-- */
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedConnect = NULL;
+ TL_INSPECT_PENDED_PACKET* connEntry;
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ if (layerData != NULL)
+ {
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ if (!IsAleReauthorize(inFixedValues))
+ {
+ //
+ // If the classify is the initial authorization for a connection, we
+ // queue it to the pended connection list and notify the worker thread
+ // for out-of-band processing.
+ //
+ pendedConnect = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_CONNECT_PACKET,
+ FWP_DIRECTION_OUTBOUND
+ );
+
+ if (pendedConnect == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPLETION_HANDLE));
+
+ //
+ // Pend the ALE_AUTH_CONNECT classify.
+ //
+ status = FwpsPendOperation(
+ inMetaValues->completionHandle,
+ &pendedConnect->completionContext
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gConnList) &&
+ IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gConnList, &pendedConnect->listEntry);
+ pendedConnect = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+ else // re-auth @ ALE_AUTH_CONNECT
+ {
+ FWP_DIRECTION packetDirection;
+ //
+ // The classify is the re-authorization for an existing connection, it
+ // could have been triggered for one of the three cases --
+ //
+ // 1) The re-auth is triggered by a FwpsCompleteOperation call to
+ // complete a ALE_AUTH_CONNECT classify pended earlier.
+ // 2) The re-auth is triggered by an outbound packet sent immediately
+ // after a policy change at ALE_AUTH_CONNECT layer.
+ // 3) The re-auth is triggered by an inbound packet received
+ // immediately after a policy change at ALE_AUTH_CONNECT layer.
+ //
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_PACKET_DIRECTION));
+ packetDirection = inMetaValues->packetDirection;
+
+ if (packetDirection == FWP_DIRECTION_OUTBOUND)
+ {
+ LIST_ENTRY* listEntry;
+ BOOLEAN authComplete = FALSE;
+
+ //
+ // We first check whether this is a FwpsCompleteOperation-triggered
+ // reauth by looking for a pended connect that has the inspection
+ // decision recorded. If found, we return that decision and remove
+ // the pended connect from the list.
+ //
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ for (listEntry = gConnList.Flink;
+ listEntry != &gConnList;
+ listEntry = listEntry->Flink)
+ {
+ connEntry = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+
+ if (IsMatchingConnectPacket(
+ inFixedValues,
+ addressFamily,
+ packetDirection,
+ connEntry
+ ) && (connEntry->authConnectDecision != 0))
+ {
+ // We found a match.
+ pendedConnect = connEntry;
+
+ NT_ASSERT((pendedConnect->authConnectDecision == FWP_ACTION_PERMIT) ||
+ (pendedConnect->authConnectDecision == FWP_ACTION_BLOCK));
+
+ classifyOut->actionType = pendedConnect->authConnectDecision;
+ if (classifyOut->actionType == FWP_ACTION_BLOCK ||
+ filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ RemoveEntryList(&pendedConnect->listEntry);
+
+ if (!gDriverUnloading &&
+ (pendedConnect->netBufferList != NULL) &&
+ (pendedConnect->authConnectDecision == FWP_ACTION_PERMIT))
+ {
+ //
+ // Now the outbound connection has been authorized. If the
+ // pended connect has a net buffer list in it, we need it
+ // morph it into a data packet and queue it to the packet
+ // queue for send injecition.
+ //
+ pendedConnect->type = TL_INSPECT_DATA_PACKET;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedConnect->listEntry);
+ pendedConnect = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+
+ authComplete = TRUE;
+ break;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (authComplete)
+ {
+ goto Exit;
+ }
+ }
+
+ //
+ // If we reach here it means this is a policy change triggered re-auth
+ // for an pre-existing connection. For such a packet (inbound or
+ // outbound) we queue it to the packet queue and inspect it just like
+ // other regular data packets from TRANSPORT layers.
+ //
+
+ NT_ASSERT(layerData != NULL);
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_REAUTH_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+ if (pendedConnect != NULL)
+ {
+ FreePendedPacket(pendedConnect);
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/* ++
+
+ This is the classifyFn function for the ALE Recv-Accept (v4 and v6) callout.
+ For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
+ is not set), it is queued to the connection list for inspection by the
+ worker thread. For re-auth, it is queued to the packet queue to be process
+ by the worker thread like any other regular packets.
+
+-- */
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedRecvAccept = NULL;
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(layerData != NULL);
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ if (!IsAleReauthorize(inFixedValues))
+ {
+ //
+ // If the classify is the initial authorization for a connection, we
+ // queue it to the pended connection list and notify the worker thread
+ // for out-of-band processing.
+ //
+ pendedRecvAccept = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_CONNECT_PACKET,
+ FWP_DIRECTION_INBOUND
+ );
+
+ if (pendedRecvAccept == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPLETION_HANDLE));
+
+ //
+ // Pend the ALE_AUTH_RECV_ACCEPT classify.
+ //
+ status = FwpsPendOperation(
+ inMetaValues->completionHandle,
+ &pendedRecvAccept->completionContext
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gConnList) &&
+ IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gConnList, &pendedRecvAccept->listEntry);
+ pendedRecvAccept = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ }
+ else // re-auth @ ALE_AUTH_RECV_ACCEPT
+ {
+ FWP_DIRECTION packetDirection;
+ //
+ // The classify is the re-authorization for a existing connection, it
+ // could have been triggered for one of the two cases --
+ //
+ // 1) The re-auth is triggered by an outbound packet sent immediately
+ // after a policy change at ALE_AUTH_RECV_ACCEPT layer.
+ // 2) The re-auth is triggered by an inbound packet received
+ // immediately after a policy change at ALE_AUTH_RECV_ACCEPT layer.
+ //
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_PACKET_DIRECTION));
+ packetDirection = inMetaValues->packetDirection;
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_REAUTH_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+ if (pendedRecvAccept != NULL)
+ {
+ FreePendedPacket(pendedRecvAccept);
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif
+/* ++
+
+ This is the classifyFn function for the Transport (v4 and v6) callout.
+ packets (inbound or outbound) are ueued to the packet queue to be processed
+ by the worker thread.
+
+-- */
+{
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+ FWP_DIRECTION packetDirection;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(layerData != NULL);
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ packetDirection =
+ GetPacketDirectionForLayer(inFixedValues->layerId);
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ if (IsAleClassifyRequired(inFixedValues, inMetaValues))
+ {
+ //
+ // Inbound transport packets that are destined to ALE Recv-Accept
+ // layers, for initial authorization or reauth, should be inspected
+ // at the ALE layer. We permit it from Tranport here.
+ //
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ goto Exit;
+ }
+ else
+ {
+ //
+ // To be compatible with Vista's IpSec implementation, we must not
+ // intercept not-yet-detunneled IpSec traffic.
+ //
+ FWPS_PACKET_LIST_INFORMATION packetInfo = {0};
+ FwpsGetPacketListSecurityInformation(
+ layerData,
+ FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC |
+ FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND,
+ &packetInfo
+ );
+
+ if (packetInfo.ipsecInformation.inbound.isTunnelMode &&
+ !packetInfo.ipsecInformation.inbound.isDeTunneled)
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ goto Exit;
+ }
+ }
+ }
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_DATA_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+
+ return;
+}
+
+NTSTATUS
+TLInspectALEConnectNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+TLInspectALERecvAcceptNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+TLInspectTransportNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+void TLInspectInjectComplete(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ TL_INSPECT_PENDED_PACKET* packet = context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+
+ FreePendedPacket(packet);
+}
+
+NTSTATUS
+TLInspectCloneReinjectOutbound(
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the outbound net buffer list and reinject it back.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0};
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ sendArgs.remoteAddress = (UINT8*)(&packet->remoteAddr);
+ sendArgs.remoteScopeId = packet->remoteScopeId;
+ sendArgs.controlData = packet->controlData;
+ sendArgs.controlDataLength = packet->controlDataLength;
+
+ //
+ // Send-inject the cloned net buffer list.
+ //
+
+ status = FwpsInjectTransportSendAsync(
+ gInjectionHandle,
+ NULL,
+ packet->endpointHandle,
+ 0,
+ &sendArgs,
+ packet->addressFamily,
+ packet->compartmentId,
+ clonedNetBufferList,
+ TLInspectInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectCloneReinjectInbound(
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the inbound net buffer list and, if needed,
+ rebuild the IP header to remove the IpSec headers and receive-injects
+ the clone back to the tcpip stack.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ NET_BUFFER* netBuffer;
+ ULONG nblOffset;
+ NDIS_STATUS ndisStatus;
+
+ //
+ // For inbound net buffer list, we can assume it contains only one
+ // net buffer.
+ //
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
+
+ nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer);
+
+ //
+ // The TCP/IP stack could have retreated the net buffer list by the
+ // transportHeaderSize amount; detect the condition here to avoid
+ // retreating twice.
+ //
+ if (nblOffset != packet->nblOffset)
+ {
+ NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);
+ packet->transportHeaderSize = 0;
+ }
+
+ //
+ // Adjust the net buffer list offset to the start of the IP header.
+ //
+ ndisStatus = NdisRetreatNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ 0,
+ NULL
+ );
+ _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);
+
+ //
+ // Note that the clone will inherit the original net buffer list's offset.
+ //
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+
+ //
+ // Undo the adjustment on the original net buffer list.
+ //
+
+ NdisAdvanceNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (packet->ipSecProtected)
+ {
+ //
+ // When an IpSec protected packet is indicated to AUTH_RECV_ACCEPT or
+ // INBOUND_TRANSPORT layers, for performance reasons the tcpip stack
+ // does not remove the AH/ESP header from the packet. And such
+ // packets cannot be recv-injected back to the stack w/o removing the
+ // AH/ESP header. Therefore before re-injection we need to "re-build"
+ // the cloned packet.
+ //
+ status = FwpsConstructIpHeaderForTransportPacket(
+ clonedNetBufferList,
+ packet->ipHeaderSize,
+ packet->addressFamily,
+ (UINT8*)&packet->remoteAddr,
+ (UINT8*)&packet->localAddr,
+ packet->protocol,
+ 0,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ if (packet->completionContext != NULL)
+ {
+ NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);
+
+ FwpsCompleteOperation(
+ packet->completionContext,
+ clonedNetBufferList
+ );
+
+ packet->completionContext = NULL;
+ }
+
+ status = FwpsInjectTransportReceiveAsync(
+ gInjectionHandle,
+ NULL,
+ NULL,
+ 0,
+ packet->addressFamily,
+ packet->compartmentId,
+ packet->interfaceIndex,
+ packet->subInterfaceIndex,
+ clonedNetBufferList,
+ TLInspectInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+void
+TlInspectCompletePendedConnection(
+ _Inout_ TL_INSPECT_PENDED_PACKET** pendedConnect,
+ _In_ BOOLEAN permitTraffic
+ )
+/* ++
+
+ This function completes the pended connection (inbound or outbound)
+ with the inspection result.
+
+-- */
+{
+
+ TL_INSPECT_PENDED_PACKET* pendedConnectLocal = *pendedConnect;
+
+ if (pendedConnectLocal->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ HANDLE completionContext = pendedConnectLocal->completionContext;
+
+ pendedConnectLocal->authConnectDecision =
+ permitTraffic ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK;
+
+ //
+ // For pended ALE_AUTH_CONNECT, FwpsCompleteOperation will trigger
+ // a re-auth during which the inspection decision is to be returned.
+ // Here we don't remove the pended entry from the list such that the
+ // re-auth can find it along with the recorded inspection result.
+ //
+ pendedConnectLocal->completionContext = NULL;
+
+ FwpsCompleteOperation(
+ completionContext,
+ NULL
+ );
+
+ *pendedConnect = NULL; // ownership transferred to the re-auth path.
+ }
+ else
+ {
+ if (!configPermitTraffic)
+ {
+ FreePendedPacket(pendedConnectLocal);
+ *pendedConnect = NULL;
+ }
+
+ //
+ // Permitted ALE_RECV_ACCEPT will pass thru and be processed by
+ // TLInspectCloneReinjectInbound. FwpsCompleteOperation will be called
+ // then when the net buffer list is cloned; after which the clone will
+ // be recv-injected.
+ //
+ }
+}
+
+void
+TLInspectWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This worker thread waits for the connect and packet queue event when the
+ queues are empty; and it will be woken up when there are connects/packets
+ queued needing to be inspected. Once awaking, It will run in a loop to
+ complete the pended ALE classifies and/or clone-reinject packets back
+ until both queues are exhausted (and it will go to sleep waiting for more
+ work).
+
+ The worker thread will end once it detected the driver is unloading.
+
+-- */
+{
+ NTSTATUS status;
+
+ TL_INSPECT_PENDED_PACKET* packet = NULL;
+ LIST_ENTRY* listEntry;
+
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+
+ UNREFERENCED_PARAMETER(StartContext);
+
+ for(;;)
+ {
+ KeWaitForSingleObject(
+ &gWorkerEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (gDriverUnloading)
+ {
+ break;
+ }
+
+ configPermitTraffic = IsTrafficPermitted();
+
+ listEntry = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ if (!IsListEmpty(&gConnList))
+ {
+ _Analysis_assume_(gConnList.Flink != NULL);
+ listEntry = gConnList.Flink;
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ if (packet->direction == FWP_DIRECTION_INBOUND)
+ {
+ RemoveEntryList(&packet->listEntry);
+ }
+
+ //
+ // Leave the pended ALE_AUTH_CONNECT in the connection list, it will
+ // be processed and removed from the list during re-auth.
+ //
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (listEntry == NULL)
+ {
+ NT_ASSERT(!IsListEmpty(&gPacketQueue));
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ }
+
+ if (packet->type == TL_INSPECT_CONNECT_PACKET)
+ {
+ TlInspectCompletePendedConnection(
+ &packet,
+ configPermitTraffic);
+ }
+
+ if ((packet != NULL) && configPermitTraffic)
+ {
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ status = TLInspectCloneReinjectOutbound(packet);
+ }
+ else
+ {
+ status = TLInspectCloneReinjectInbound(packet);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ packet = NULL; // ownership transferred.
+ }
+
+ }
+
+ if (packet != NULL)
+ {
+ FreePendedPacket(packet);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue) &&
+ !gDriverUnloading)
+ {
+ KeClearEvent(&gWorkerEvent);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+ }
+
+ NT_ASSERT(gDriverUnloading);
+
+ while (!IsListEmpty(&gConnList))
+ {
+ packet = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ if (!IsListEmpty(&gConnList))
+ {
+ listEntry = gConnList.Flink;
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (packet != NULL)
+ {
+ TlInspectCompletePendedConnection(&packet, FALSE);
+ NT_ASSERT(packet == NULL);
+ }
+ }
+
+ //
+ // Discard all the pended packets if driver is being unloaded.
+ //
+
+ while (!IsListEmpty(&gPacketQueue))
+ {
+ packet = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!IsListEmpty(&gPacketQueue))
+ {
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ if (packet != NULL)
+ {
+ FreePendedPacket(packet);
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+
+}
diff --git a/network/trans/inspect/sys/inspect.h b/network/trans/inspect/sys/inspect.h
new file mode 100644
index 00000000..baff6485
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.h
@@ -0,0 +1,214 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This header files declares common data types and function prototypes used
+ throughout the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _TL_INSPECT_H_
+#define _TL_INSPECT_H_
+
+typedef enum TL_INSPECT_PACKET_TYPE_
+{
+ TL_INSPECT_CONNECT_PACKET,
+ TL_INSPECT_DATA_PACKET,
+ TL_INSPECT_REAUTH_PACKET
+} TL_INSPECT_PACKET_TYPE;
+
+//
+// TL_INSPECT_PENDED_PACKET is the object type we used to store all information
+// needed for out-of-band packet modification and re-injection. This type
+// also points back to the flow context the packet belongs to.
+
+#pragma warning(push)
+#pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+
+typedef struct TL_INSPECT_PENDED_PACKET_
+{
+ LIST_ENTRY listEntry;
+
+ ADDRESS_FAMILY addressFamily;
+ TL_INSPECT_PACKET_TYPE type;
+ FWP_DIRECTION direction;
+
+ UINT32 authConnectDecision;
+ HANDLE completionContext;
+
+ //
+ // Common fields for inbound and outbound traffic.
+ //
+ UINT8 protocol;
+ NET_BUFFER_LIST* netBufferList;
+ COMPARTMENT_ID compartmentId;
+ union
+ {
+ FWP_BYTE_ARRAY16 localAddr;
+ UINT32 ipv4LocalAddr;
+ };
+ union
+ {
+ UINT16 localPort;
+ UINT16 icmpType;
+ };
+ union
+ {
+ UINT16 remotePort;
+ UINT16 icmpCode;
+ };
+
+ //
+ // Data fields for outbound packet re-injection.
+ //
+ UINT64 endpointHandle;
+ union
+ {
+ FWP_BYTE_ARRAY16 remoteAddr;
+ UINT32 ipv4RemoteAddr;
+ };
+
+ SCOPE_ID remoteScopeId;
+ WSACMSGHDR* controlData;
+ ULONG controlDataLength;
+
+ //
+ // Data fields for inbound packet re-injection.
+ //
+ BOOLEAN ipSecProtected;
+ ULONG nblOffset;
+ UINT32 ipHeaderSize;
+ UINT32 transportHeaderSize;
+ IF_INDEX interfaceIndex;
+ IF_INDEX subInterfaceIndex;
+} TL_INSPECT_PENDED_PACKET;
+
+#pragma warning(pop)
+
+//
+// Pooltags used by this callout driver.
+//
+#define TL_INSPECT_CONNECTION_POOL_TAG 'olfD'
+#define TL_INSPECT_PENDED_PACKET_POOL_TAG 'kppD'
+#define TL_INSPECT_CONTROL_DATA_POOL_TAG 'dcdD'
+
+//
+// Shared global data.
+//
+extern BOOLEAN configPermitTraffic;
+
+extern HANDLE gInjectionHandle;
+
+extern LIST_ENTRY gConnList;
+extern KSPIN_LOCK gConnListLock;
+
+extern LIST_ENTRY gPacketQueue;
+extern KSPIN_LOCK gPacketQueueLock;
+
+extern KEVENT gWorkerEvent;
+
+extern BOOLEAN gDriverUnloading;
+
+//
+// Shared function prototypes
+//
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS
+TLInspectALEConnectNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+NTSTATUS
+TLInspectALERecvAcceptNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+NTSTATUS
+TLInspectTransportNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+KSTART_ROUTINE TLInspectWorker;
+
+#endif // _TL_INSPECT_H_
diff --git a/network/trans/inspect/sys/inspect.inf b/network/trans/inspect/sys/inspect.inf
new file mode 100644
index 00000000..125f9601
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.inf
@@ -0,0 +1,63 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Traffic Inspect Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = Inspect.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %InspectDisk%,,,""
+
+[SourceDisksFiles]
+ Inspect.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ Inspect.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %InspectServiceDesc%
+ CopyFiles = Inspect.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %InspectServiceName%,,Inspect.Service
+
+[DefaultUninstall]
+ DelFiles = Inspect.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %InspectServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = Inspect.DelRegistry
+
+[Inspect.DriverFiles]
+ Inspect.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[Inspect.Service]
+ DisplayName = %InspectServiceName%
+ Description = %InspectServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\Inspect.sys ; %WinDir%\System32\Drivers\Inspect.sys
+ AddReg = Inspect.AddRegistry
+
+[Inspect.AddRegistry]
+ HKR,"Parameters","BlockTraffic",0x00010001,"0" ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","RemoteAddressToInspect",0x00000000,"10.0.0.1" ; FLG_ADDREG_TYPE_SZ
+
+[Inspect.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ InspectDisk = "Traffic Inspect Installation Disk"
+ InspectServiceDesc = "Traffic Inspect Callout Driver"
+ InspectServiceName = "Inspect" \ No newline at end of file
diff --git a/network/trans/inspect/sys/inspect.vcxproj b/network/trans/inspect/sys/inspect.vcxproj
new file mode 100644
index 00000000..d403b025
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.vcxproj
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{43AC1739-03F1-4465-8A16-F5FCD06BC2E9}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{CA2EEED8-4078-42F4-947A-29D46ACCC30F}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="inspect.c" />
+ <ClCompile Include="tl_drv.c" />
+ <ClCompile Include="utils.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/inspect/sys/inspect.vcxproj.Filters b/network/trans/inspect/sys/inspect.vcxproj.Filters
new file mode 100644
index 00000000..7fbd1b25
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.vcxproj.Filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{89A4FDF7-7B2B-42A3-A13C-4855905159BF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{893A15B9-96A4-4181-9353-D9C59D6D343C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{174E13A1-2D15-477C-9E80-060424681A41}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3D55D549-7A89-4DEB-9C7B-149E8332DD7C}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="inspect.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tl_drv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/inspect/sys/utils.c b/network/trans/inspect/sys/utils.c
new file mode 100644
index 00000000..b6cbf0ce
--- /dev/null
+++ b/network/trans/inspect/sys/utils.c
@@ -0,0 +1,448 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the utility/helper functions for use by the classify
+ functions and worker thread of the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inspect.h"
+#include "utils.h"
+
+
+BOOLEAN IsAleReauthorize(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ )
+{
+ UINT flagsIndex;
+
+ GetFlagsIndexesForLayer(
+ inFixedValues->layerId,
+ &flagsIndex
+ );
+
+ if((flagsIndex != UINT_MAX) && ((inFixedValues->incomingValue\
+ [flagsIndex].value.uint32 & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN IsSecureConnection(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ )
+{
+ UINT flagsIndex;
+
+ GetFlagsIndexesForLayer(
+ inFixedValues->layerId,
+ &flagsIndex
+ );
+
+ if ((flagsIndex != UINT_MAX) && ((inFixedValues->incomingValue\
+ [flagsIndex].value.uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+IsAleClassifyRequired(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues
+ )
+{
+ //
+ // Note that use of FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY has been
+ // deprecated in Vista SP1 and Windows Server 2008.
+ //
+ UNREFERENCED_PARAMETER(inFixedValues);
+ return FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED
+ );
+}
+
+BOOLEAN
+IsMatchingConnectPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _In_ FWP_DIRECTION direction,
+ _Inout_ TL_INSPECT_PENDED_PACKET* pendedPacket
+ )
+{
+ UINT localAddrIndex;
+ UINT remoteAddrIndex;
+ UINT localPortIndex;
+ UINT remotePortIndex;
+ UINT protocolIndex;
+
+ NT_ASSERT(pendedPacket->type == TL_INSPECT_CONNECT_PACKET);
+
+ GetNetwork5TupleIndexesForLayer(
+ inFixedValues->layerId,
+ &localAddrIndex,
+ &remoteAddrIndex,
+ &localPortIndex,
+ &remotePortIndex,
+ &protocolIndex
+ );
+
+ if(localAddrIndex == UINT_MAX)
+ {
+ return FALSE;
+ }
+
+ if (addressFamily != pendedPacket->addressFamily)
+ {
+ return FALSE;
+ }
+
+ if (direction != pendedPacket->direction)
+ {
+ return FALSE;
+ }
+
+ if (inFixedValues->incomingValue[protocolIndex].value.uint8 !=
+ pendedPacket->protocol)
+ {
+ return FALSE;
+ }
+
+ if (RtlUshortByteSwap(
+ inFixedValues->incomingValue[localPortIndex].value.uint16
+ ) != pendedPacket->localPort)
+ {
+ return FALSE;
+ }
+
+ if (RtlUshortByteSwap(
+ inFixedValues->incomingValue[remotePortIndex].value.uint16
+ ) != pendedPacket->remotePort)
+ {
+ return FALSE;
+ }
+
+ if (addressFamily == AF_INET)
+ {
+ UINT32 ipv4LocalAddr =
+ RtlUlongByteSwap(
+ inFixedValues->incomingValue[localAddrIndex].value.uint32
+ );
+ UINT32 ipv4RemoteAddr =
+ // Prefast thinks we are ignoring this return value.
+ // If driver is unloading, we give up and ignore it on purpose.
+ // Otherwise, we put the pointer onto the list, but we make it opaque
+ // by casting it as a UINT64, and this tricks Prefast.
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[remoteAddrIndex].value.uint32
+ );
+ if (ipv4LocalAddr != pendedPacket->ipv4LocalAddr)
+ {
+ return FALSE;
+ }
+
+ if (ipv4RemoteAddr != pendedPacket->ipv4RemoteAddr)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (RtlCompareMemory(
+ inFixedValues->incomingValue[localAddrIndex].value.byteArray16,
+ &pendedPacket->localAddr,
+ sizeof(FWP_BYTE_ARRAY16)) != sizeof(FWP_BYTE_ARRAY16))
+ {
+ return FALSE;
+ }
+
+ if (RtlCompareMemory(
+ inFixedValues->incomingValue[remoteAddrIndex].value.byteArray16,
+ &pendedPacket->remoteAddr,
+ sizeof(FWP_BYTE_ARRAY16)) != sizeof(FWP_BYTE_ARRAY16))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void
+FillNetwork5Tuple(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+{
+ UINT localAddrIndex;
+ UINT remoteAddrIndex;
+ UINT localPortIndex;
+ UINT remotePortIndex;
+ UINT protocolIndex;
+
+ GetNetwork5TupleIndexesForLayer(
+ inFixedValues->layerId,
+ &localAddrIndex,
+ &remoteAddrIndex,
+ &localPortIndex,
+ &remotePortIndex,
+ &protocolIndex
+ );
+
+ if (addressFamily == AF_INET)
+ {
+ packet->ipv4LocalAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[localAddrIndex].value.uint32
+ );
+ packet->ipv4RemoteAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[remoteAddrIndex].value.uint32
+ );
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&packet->localAddr,
+ inFixedValues->incomingValue[localAddrIndex].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ RtlCopyMemory(
+ (UINT8*)&packet->remoteAddr,
+ inFixedValues->incomingValue[remoteAddrIndex].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ }
+
+ packet->localPort =
+ RtlUshortByteSwap(
+ inFixedValues->incomingValue[localPortIndex].value.uint16
+ );
+ packet->remotePort =
+ RtlUshortByteSwap(
+ inFixedValues->incomingValue[remotePortIndex].value.uint16
+ );
+
+ packet->protocol = inFixedValues->incomingValue[protocolIndex].value.uint8;
+
+ return;
+}
+
+void
+FreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) TL_INSPECT_PENDED_PACKET* packet
+ )
+{
+ if (packet->netBufferList != NULL)
+ {
+ FwpsDereferenceNetBufferList(packet->netBufferList, FALSE);
+ }
+ if (packet->controlData != NULL)
+ {
+ ExFreePoolWithTag(packet->controlData, TL_INSPECT_CONTROL_DATA_POOL_TAG);
+ }
+ if (packet->completionContext != NULL)
+ {
+ NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);
+ NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND); // complete for ALE connect
+ // is done prior to freeing
+ // of the packet.
+ FwpsCompleteOperation(packet->completionContext, NULL);
+ }
+ ExFreePoolWithTag(packet, TL_INSPECT_PENDED_PACKET_POOL_TAG);
+}
+
+__drv_allocatesMem(Mem)
+TL_INSPECT_PENDED_PACKET*
+AllocateAndInitializePendedPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_opt_ void* layerData,
+ _In_ TL_INSPECT_PACKET_TYPE packetType,
+ _In_ FWP_DIRECTION packetDirection
+ )
+{
+ TL_INSPECT_PENDED_PACKET* pendedPacket;
+
+ pendedPacket = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(TL_INSPECT_PENDED_PACKET),
+ TL_INSPECT_PENDED_PACKET_POOL_TAG
+ );
+
+ if (pendedPacket == NULL)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(pendedPacket, sizeof(TL_INSPECT_PENDED_PACKET));
+
+ pendedPacket->type = packetType;
+ pendedPacket->direction = packetDirection;
+
+ pendedPacket->addressFamily = addressFamily;
+
+ FillNetwork5Tuple(
+ inFixedValues,
+ addressFamily,
+ pendedPacket
+ );
+
+ if (layerData != NULL)
+ {
+ pendedPacket->netBufferList = layerData;
+
+ //
+ // Reference the net buffer list to make it accessible outside of
+ // classifyFn.
+ //
+ FwpsReferenceNetBufferList(pendedPacket->netBufferList, TRUE);
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPARTMENT_ID));
+ pendedPacket->compartmentId = inMetaValues->compartmentId;
+
+ if ((pendedPacket->direction == FWP_DIRECTION_OUTBOUND) &&
+ (layerData != NULL))
+ {
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
+ pendedPacket->endpointHandle = inMetaValues->transportEndpointHandle;
+
+ pendedPacket->remoteScopeId = inMetaValues->remoteScopeId;
+
+ if (FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
+ {
+ NT_ASSERT(inMetaValues->controlDataLength > 0);
+
+ pendedPacket->controlData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ inMetaValues->controlDataLength,
+ TL_INSPECT_CONTROL_DATA_POOL_TAG
+ );
+ if (pendedPacket->controlData == NULL)
+ {
+ goto Exit;
+ }
+
+ RtlCopyMemory(
+ pendedPacket->controlData,
+ inMetaValues->controlData,
+ inMetaValues->controlDataLength
+ );
+
+ pendedPacket->controlDataLength = inMetaValues->controlDataLength;
+ }
+ }
+ else if (pendedPacket->direction == FWP_DIRECTION_INBOUND)
+ {
+ UINT interfaceIndexIndex = 0;
+ UINT subInterfaceIndexIndex = 0;
+
+ GetDeliveryInterfaceIndexesForLayer(
+ inFixedValues->layerId,
+ &interfaceIndexIndex,
+ &subInterfaceIndexIndex
+ );
+
+ pendedPacket->interfaceIndex =
+ inFixedValues->incomingValue[interfaceIndexIndex].value.uint32;
+ pendedPacket->subInterfaceIndex =
+ inFixedValues->incomingValue[subInterfaceIndexIndex].value.uint32;
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_IP_HEADER_SIZE));
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE));
+ pendedPacket->ipHeaderSize = inMetaValues->ipHeaderSize;
+ pendedPacket->transportHeaderSize = inMetaValues->transportHeaderSize;
+
+ if (pendedPacket->netBufferList != NULL)
+ {
+ FWPS_PACKET_LIST_INFORMATION packetInfo = {0};
+ FwpsGetPacketListSecurityInformation(
+ pendedPacket->netBufferList,
+ FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC |
+ FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND,
+ &packetInfo
+ );
+
+ pendedPacket->ipSecProtected =
+ (BOOLEAN)packetInfo.ipsecInformation.inbound.isSecure;
+
+ pendedPacket->nblOffset =
+ NET_BUFFER_DATA_OFFSET(\
+ NET_BUFFER_LIST_FIRST_NB(pendedPacket->netBufferList));
+ }
+ }
+
+ return pendedPacket;
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+
+ return NULL;
+}
+
+extern WDFKEY gParametersKey;
+
+BOOLEAN
+IsTrafficPermitted(void)
+{
+ NTSTATUS status;
+
+ DECLARE_CONST_UNICODE_STRING(valueName, L"PermitTraffic");
+ ULONG result;
+
+ status = WdfRegistryQueryULong(
+ gParametersKey,
+ &valueName,
+ &result
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ result = 1;
+ }
+
+ return (result != 0);
+}
+
+
diff --git a/network/trans/inspect/sys/utils.h b/network/trans/inspect/sys/utils.h
new file mode 100644
index 00000000..3570cd8a
--- /dev/null
+++ b/network/trans/inspect/sys/utils.h
@@ -0,0 +1,298 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file declares the utility/helper functions for use by the classify
+ functions and worker thread of the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <limits.h>
+
+#ifndef _TL_INSPECT_UTILS_H_
+#define _TL_INSPECT_UTILS_H_
+
+__inline
+ADDRESS_FAMILY GetAddressFamilyForLayer(
+ _In_ UINT16 layerId
+ )
+{
+ ADDRESS_FAMILY addressFamily;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ addressFamily = AF_INET;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ addressFamily = AF_INET6;
+ break;
+ default:
+ addressFamily = AF_UNSPEC;
+ NT_ASSERT(0);
+ }
+
+ return addressFamily;
+}
+
+__inline
+FWP_DIRECTION GetPacketDirectionForLayer(
+ _In_ UINT16 layerId
+ )
+{
+ FWP_DIRECTION direction;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ direction = FWP_DIRECTION_OUTBOUND;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ direction = FWP_DIRECTION_INBOUND;
+ break;
+ default:
+ direction = FWP_DIRECTION_MAX;
+ NT_ASSERT(0);
+ }
+
+ return direction;
+}
+
+__inline
+void
+GetFlagsIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* flagsIndex
+ )
+{
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ *flagsIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ *flagsIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *flagsIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *flagsIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_FLAGS;
+ break;
+ default:
+ *flagsIndex = UINT_MAX;
+ NT_ASSERT(0);
+ break;
+ }
+}
+
+__inline
+void
+GetDeliveryInterfaceIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* interfaceIndexIndex,
+ _Out_ UINT* subInterfaceIndexIndex
+ )
+{
+ *interfaceIndexIndex = 0;
+
+ *subInterfaceIndexIndex = 0;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V6_SUB_INTERFACE_INDEX;
+ break;
+ default:
+ NT_ASSERT(0);
+ break;
+ }
+}
+
+__inline
+void
+GetNetwork5TupleIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* localAddressIndex,
+ _Out_ UINT* remoteAddressIndex,
+ _Out_ UINT* localPortIndex,
+ _Out_ UINT* remotePortIndex,
+ _Out_ UINT* protocolIndex
+ )
+{
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ *localAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ *localAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *localAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *localAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_PROTOCOL;
+ break;
+ default:
+ *localAddressIndex = UINT_MAX;
+ *remoteAddressIndex = UINT_MAX;
+ *localPortIndex = UINT_MAX;
+ *remotePortIndex = UINT_MAX;
+ *protocolIndex = UINT_MAX;
+ NT_ASSERT(0);
+ }
+}
+
+BOOLEAN IsAleReauthorize(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ );
+
+BOOLEAN IsSecureConnection(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ );
+
+BOOLEAN
+IsAleClassifyRequired(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues
+ );
+
+void
+FillNetwork5Tuple(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ );
+
+BOOLEAN
+IsMatchingConnectPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _In_ FWP_DIRECTION direction,
+ _Inout_ TL_INSPECT_PENDED_PACKET* pendedPacket
+ );
+
+__drv_allocatesMem(Mem)
+TL_INSPECT_PENDED_PACKET*
+AllocateAndInitializePendedPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_opt_ void* layerData,
+ _In_ TL_INSPECT_PACKET_TYPE packetType,
+ _In_ FWP_DIRECTION packetDirection
+ );
+
+void
+FreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) TL_INSPECT_PENDED_PACKET* packet
+ );
+
+BOOLEAN
+IsTrafficPermitted(void);
+
+#endif // _TL_INSPECT_UTILS_H_
diff --git a/network/trans/msnmntr/ReadMe.md b/network/trans/msnmntr/ReadMe.md
new file mode 100644
index 00000000..9f247ff5
--- /dev/null
+++ b/network/trans/msnmntr/ReadMe.md
@@ -0,0 +1,79 @@
+Windows Filtering Platform MSN Messenger Monitor Sample
+=======================================================
+
+This sample application and driver demonstrate the stream inspection capabilities of the Windows Filtering Platform (WFP).
+
+The sample consists of a user mode application (Monitor.exe) that registers traffic of interest. In this case, all Transmission Control Protocol (TCP) data segments that are sent and received by an application of your choice.
+
+**Note**  Originally this sample was written to monitor the MSN Messenger application. Now it can monitor any application that you specify.
+
+Monitor.exe adds filters and callouts to Windows through the Windows Filtering Platform (WFP) Win32 API. A kernel-mode WFP callout driver (Msnmntr.sys) intercepts TCP traffic and parses out communication patterns. Monitor.exe controls the operations of the callout driver through I/O controls (IOCTLs).
+
+The filters and callouts added by Monitor.exe are persistent across system restarts and removed only by Monitor.exe. Adding filters and callouts requires administrator privileges. Therefore, Monitor.exe must be run from an elevated command prompt.
+
+Msnmntr.sys registers itself at two different WFP layers: FLOW-ESTABLISHED and STREAM. For simplicity, only Internet Protocol version 4 (IPv4) traffic is inspected. Msnmntr.sys registers at the FLOW-ESTABLISHED layer to associate a callout driver-specific data structure with application identity (that is, path) recorded such that the STREAM layer will only be invoked if traffic is sent or received from that particular application.
+
+After the filters and callouts are in place and registered, WFP indicates TCP data segments to the Msnmntr.sys for inspection. As the data flows through Msnmntr.sys, it copies them (described by a chain of NET\_BUFFER\_LIST structures) to a flat buffer, parses out the communication patterns (such as client-to-server/client-to-client), and sends them to the Windows Software Trace Preprocessor (WPP) for tracing.
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, navigate to DriverTest\\Drivers, and locate the file msnmntr.inf. Right click msnmntr.inf, and choose **Install**.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). After you have prepared the target computer for manual deployment, continue with these steps:
+
+1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\WfpMsnMessengerMonitorSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click msnmntr.inf, and choose **Install**
+
+Copy additional files to the target computer
+--------------------------------------------
+
+Copy the user-mode application, monitor.exe to a folder on the target computer (for example, c:\\WfpMsnMessengerMonitorSampleApp).
+
+Copy the PDB file, msnmntr.pdb to a folder on the target computer (for example, c:\\Symbols).
+
+Copy the tool TraceView.exe to a folder on the target computer (for example c:\\Tools). TraceView.exe comes with the WDK. You can find it in your WDK installation folder under Tools (for example, c:\\Program Files (x86)\\Windows Kits\\8.1\\Tools\\x64\\TraceView.exe).
+
+Start the msnmntr service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start msnmntr**. (To stop the driver, enter **net stop msnmntr**.)
+
+Running the user-mode application
+---------------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and navigate to the folder that contains monitor.exe. Enter **monitor.exe addcallouts**. Then enter **monitor.exe monitor** *TargetAppPath*, where *TargetAppPath* is the path to the application that you want to monitor. Here is an example that initiates monitoring of Internet Explorer.
+
+``` {.syntax xml:space="preserve"}
+monitor.exe addcallouts
+monitor.exe monitor "C:\Program Files (x86)\Internet Explorer\iexplore.exe"
+```
+
+Start a logging session in TraceView
+------------------------------------
+
+On the target computer, open TraceView.exe as Administrator. On the **File** menu, choose **Create New Log Session**. Click **Add Provider**. Select **PDB (Debug Information File)**, and enter the path to your PDB file, msnmntr.pdb. Click **OK**, and finish working through the setup procedure. Open Internet Explorer, and watch the communication patterns being displayed in the Traceview.exe tool.
+
+Tracing for the sample driver can be started at any time before the driver is started or while the driver is already running.
+
+For more information on creating a Windows Filtering Platform Callout Driver, see [Windows Filtering Platform Callout Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571068).
+
+Using MSBuild
+-------------
+
+As an alternative to building the WFP MSN Messenger Monitor Sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, msnmntr.sln. Use the [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) command to build the solution. Here are some examples:
+
+**msbuild /p:configuration=”Win7 Debug” /p:platform=”x64” msnmntr.sln**
+
+**msbuild /p:configuration=”Win8 Release” /p:platform=”win32” msnmntr.sln**
+
+For more information about using [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644).
+
diff --git a/network/trans/msnmntr/exe/monitor.cpp b/network/trans/msnmntr/exe/monitor.cpp
new file mode 100644
index 00000000..def6625c
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.cpp
@@ -0,0 +1,715 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream monitor sample executable
+
+Environment:
+
+ User mode
+
+--*/
+
+#include "windows.h"
+#include "winioctl.h"
+#include "strsafe.h"
+
+#ifndef _CTYPE_DISABLE_MACROS
+#define _CTYPE_DISABLE_MACROS
+#endif
+
+#include "fwpmu.h"
+
+#include "winsock2.h"
+#include "ws2def.h"
+
+#include <conio.h>
+#include <stdio.h>
+
+#include "ioctl.h"
+
+#define INITGUID
+#include <guiddef.h>
+#include "mntrguid.h"
+
+
+#define MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION L"Monitor Sample - Flow Established Callout"
+#define MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME L"Flow Established Callout"
+
+#define MONITOR_STREAM_CALLOUT_DESCRIPTION L"Monitor Sample - Stream Callout"
+#define MONITOR_STREAM_CALLOUT_NAME L"Stream Callout"
+
+HANDLE quitEvent;
+
+DWORD
+MonitorAppOpenMonitorDevice(
+ _Out_ HANDLE* monitorDevice)
+/*++
+
+Routine Description:
+
+ Opens the Monitor Sample monitorDevice
+
+Arguments:
+
+ [out] HANDLE* monitorDevice
+
+Return Value:
+
+ NO_ERROR, ERROR_INVALID_PARAMETER or a CreateFile specific result.
+
+--*/
+{
+ if (!monitorDevice)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+ *monitorDevice = CreateFileW(MONITOR_DOS_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ if (*monitorDevice == INVALID_HANDLE_VALUE)
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+BOOL MonitorAppCloseMonitorDevice(
+ _In_ HANDLE monitorDevice)
+/*++
+
+Routine Description:
+
+ Closes the Monitor Sample monitorDevice
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return CloseHandle(monitorDevice);
+}
+
+DWORD
+MonitorAppAddCallouts()
+/*++
+
+Routine Description:
+
+ Adds the callouts during installation
+
+Arguments:
+
+ [in] PCWSTR AppPath - The path to the application to monitor.
+
+Return Value:
+
+ NO_ERROR or a specific FWP result.
+
+--*/
+{
+ FWPM_CALLOUT callout;
+ DWORD result;
+ FWPM_DISPLAY_DATA displayData;
+ HANDLE engineHandle = NULL;
+ FWPM_SESSION session;
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Non-Dynamic Session";
+ session.displayData.description = L"For Adding callouts";
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Starting Transaction for adding callouts\n");
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully started the Transaction\n");
+
+ RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));
+ displayData.description = MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION;
+ displayData.name = MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME;
+
+ callout.calloutKey = MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4;
+ callout.displayData = displayData;
+ callout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
+ callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; // Make this a persistent callout.
+
+ printf("Adding Persistent Flow Established callout through the Filtering Engine\n");
+
+ result = FwpmCalloutAdd(engineHandle, &callout, NULL, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Added Persistent Flow Established callout.\n");
+
+ RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));
+
+ displayData.description = MONITOR_STREAM_CALLOUT_DESCRIPTION;
+ displayData.name = MONITOR_STREAM_CALLOUT_DESCRIPTION;
+
+ callout.calloutKey = MONITOR_SAMPLE_STREAM_CALLOUT_V4;
+ callout.displayData = displayData;
+ callout.applicableLayer = FWPM_LAYER_STREAM_V4;
+ callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; // Make this a persistent callout.
+
+ printf("Adding Persistent Stream callout through the Filtering Engine\n");
+
+ result = FwpmCalloutAdd(engineHandle, &callout, NULL, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Added Persistent Stream callout.\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction.\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction.\n");
+ }
+
+cleanup:
+
+ if (engineHandle)
+ {
+ FwpmEngineClose(engineHandle);
+ }
+ return result;
+}
+
+DWORD
+MonitorAppRemoveCallouts()
+/*++
+
+Routine Description:
+
+ Sets the kernel callout ID's through the Monitor Sample device
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device
+ [in] CALLOUTS* callouts - Callout structure with ID's set
+ [in] DWORD size - Size of the callout structure.
+
+Return Value:
+
+ NO_ERROR or a specific DeviceIoControl result.
+
+--*/
+{
+ DWORD result;
+ HANDLE engineHandle = NULL;
+ FWPM_SESSION session;
+
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Non-Dynamic Session";
+ session.displayData.description = L"For Adding callouts";
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Starting Transaction for Removing callouts\n");
+
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully started the Transaction\n");
+
+ printf("Deleting Flow Established callout\n");
+ result = FwpmCalloutDeleteByKey(engineHandle,
+ &MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Deleted Flow Established callout\n");
+
+ printf("Deleting Stream callout\n");
+
+ result = FwpmCalloutDeleteByKey(engineHandle,
+ &MONITOR_SAMPLE_STREAM_CALLOUT_V4);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully Deleted Stream callout\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction.\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction.\n");
+ }
+
+cleanup:
+
+ if (engineHandle)
+ {
+ FwpmEngineClose(engineHandle);
+ }
+
+ return result;
+}
+
+DWORD
+MonitorAppEnableMonitoring(
+ _In_ HANDLE monitorDevice,
+ _In_ MONITOR_SETTINGS* monitorSettings)
+/*++
+
+Routine Description:
+
+ Enables monitoring on new connections.
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device
+ [in] MONITOR_SETTINGS* monitorSettings - Settings for the Monitor Sample driver.
+
+Return Value:
+
+ NO_ERROR or a specific DeviceIoControl result.
+
+--*/
+{
+ DWORD bytesReturned;
+
+ if (!DeviceIoControl(monitorDevice,
+ MONITOR_IOCTL_ENABLE_MONITOR,
+ monitorSettings,
+ sizeof(MONITOR_SETTINGS),
+ NULL,
+ 0,
+ &bytesReturned,
+ NULL))
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+DWORD
+MonitorAppDisableMonitoring(
+ _In_ HANDLE monitorDevice)
+/*++
+
+Routine Description:
+
+ Disables monitoring of new flows (existing flows will continue to be
+ monitored until the driver is stopped or the flows end).
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device handle.
+
+Return Value:
+
+ NO_ERROR or DeviceIoControl specific code.
+
+--*/
+{
+ DWORD bytesReturned;
+
+ if (!DeviceIoControl(monitorDevice,
+ MONITOR_IOCTL_DISABLE_MONITOR,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesReturned,
+ NULL))
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+DWORD
+MonitorAppAddFilters(
+ _In_ HANDLE engineHandle,
+ _In_ FWP_BYTE_BLOB* applicationPath)
+/*++
+
+Routine Description:
+
+ Adds the required sublayer, filters and callouts to the Windows
+ Filtering Platform (WFP).
+
+Arguments:
+
+ [in] HANDLE engineHandle - Handle to the base Filtering engine
+ [in] FWP_BYTE_BLOB* applicationPath - full path to the application including
+ the NULL terminator and size also
+ including the NULL the terminator
+ [in] CALLOUTS* callouts - The callouts that need to be added.
+
+Return Value:
+
+ NO_ERROR or a specific result
+
+--*/
+{
+ DWORD result = NO_ERROR;
+ FWPM_SUBLAYER monitorSubLayer;
+ FWPM_FILTER filter;
+ FWPM_FILTER_CONDITION filterConditions[2]; // We only need two for this call.
+
+ RtlZeroMemory(&monitorSubLayer, sizeof(FWPM_SUBLAYER));
+
+ monitorSubLayer.subLayerKey = MONITOR_SAMPLE_SUBLAYER;
+ monitorSubLayer.displayData.name = L"Monitor Sample Sub layer";
+ monitorSubLayer.displayData.description = L"Monitor Sample Sub layer";
+ monitorSubLayer.flags = 0;
+ // We don't really mind what the order of invocation is.
+ monitorSubLayer.weight = 0;
+
+ printf("Starting Transaction\n");
+
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully Started Transaction\n");
+
+ printf("Adding Sublayer\n");
+
+ result = FwpmSubLayerAdd(engineHandle, &monitorSubLayer, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Sucessfully added Sublayer\n");
+
+ RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
+
+ filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
+ filter.displayData.name = L"Flow established filter.";
+ filter.displayData.description = L"Sets up flow for traffic that we are interested in.";
+ filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
+ filter.action.calloutKey = MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4;
+ filter.filterCondition = filterConditions;
+ filter.subLayerKey = monitorSubLayer.subLayerKey;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filter.numFilterConditions = 2;
+
+ RtlZeroMemory(filterConditions, sizeof(filterConditions));
+
+ //
+ // Add the application path to the filter conditions.
+ //
+ filterConditions[0].fieldKey = FWPM_CONDITION_ALE_APP_ID;
+ filterConditions[0].matchType = FWP_MATCH_EQUAL;
+ filterConditions[0].conditionValue.type = FWP_BYTE_BLOB_TYPE;
+ filterConditions[0].conditionValue.byteBlob = applicationPath;
+
+ //
+ // For the purposes of this sample, we will monitor TCP traffic only.
+ //
+ filterConditions[1].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
+ filterConditions[1].matchType = FWP_MATCH_EQUAL;
+ filterConditions[1].conditionValue.type = FWP_UINT8;
+ filterConditions[1].conditionValue.uint8 = IPPROTO_TCP;
+
+ printf("Adding Flow Established Filter\n");
+
+ result = FwpmFilterAdd(engineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully added Flow Established filter\n");
+
+ RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
+
+ filter.layerKey = FWPM_LAYER_STREAM_V4;
+ filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
+ filter.action.calloutKey = MONITOR_SAMPLE_STREAM_CALLOUT_V4;
+ filter.subLayerKey = monitorSubLayer.subLayerKey;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filter.numFilterConditions = 0;
+
+ RtlZeroMemory(filterConditions, sizeof(filterConditions));
+
+ filter.filterCondition = filterConditions;
+
+ filter.displayData.name = L"Stream Layer Filter";
+ filter.displayData.description = L"Monitors TCP traffic.";
+
+ printf("Adding Stream Filter\n");
+
+ result = FwpmFilterAdd(engineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully added Stream filter\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction\n");
+ }
+
+cleanup:
+
+ return result;
+}
+
+DWORD
+MonitorAppIDFromPath(
+ _In_ PCWSTR fileName,
+ _Out_ FWP_BYTE_BLOB** appId)
+{
+ DWORD result = NO_ERROR;
+
+ result = FwpmGetAppIdFromFileName(fileName, appId);
+
+ return result;
+}
+
+DWORD
+MonitorAppDoMonitoring(PCWSTR AppPath)
+{
+ HANDLE monitorDevice = NULL;
+ HANDLE engineHandle = NULL;
+ DWORD result;
+ MONITOR_SETTINGS monitorSettings;
+ FWPM_SESSION session;
+ FWP_BYTE_BLOB* applicationId = NULL;
+
+ RtlZeroMemory(&monitorSettings, sizeof(MONITOR_SETTINGS));
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Session";
+ session.displayData.description = L"Monitors traffic at the Stream layer.";
+
+ // Let the Base Filtering Engine cleanup after us.
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully opened Filtering Engine\n");
+
+ printf("Looking up Application ID from BFE\n");
+ result = MonitorAppIDFromPath(AppPath, &applicationId);
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully retrieved Application ID\n");
+
+ printf("Opening Monitor Sample Device\n");
+
+ result = MonitorAppOpenMonitorDevice(&monitorDevice);
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully opened Monitor Device\n");
+
+ printf("Adding Filters through the Filtering Engine\n");
+
+ result = MonitorAppAddFilters(engineHandle,
+ applicationId);
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully added Filters through the Filtering Engine\n");
+
+ printf("Enabling monitoring through the Monitor Sample Device\n");
+
+ monitorSettings.monitorOperation = monitorTraffic;
+
+ result = MonitorAppEnableMonitoring(monitorDevice,
+ &monitorSettings);
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully enabled monitoring.\n");
+
+ printf("Events will be traced through WMI. Please press any key to exit and cleanup filters.\n");
+
+#pragma prefast(push)
+#pragma prefast(disable:6031, "by design the return value of _getch() is ignored here")
+ _getch();
+#pragma prefast(pop)
+
+cleanup:
+
+ if (NO_ERROR != result)
+ {
+ printf("Monitor.\tError 0x%x occurred during execution\n", result);
+ }
+
+ if (monitorDevice)
+ {
+ MonitorAppCloseMonitorDevice(monitorDevice);
+ }
+
+ //
+ // Free the application Id that we retrieved.
+ //
+ if (applicationId)
+ {
+ FwpmFreeMemory((void**)&applicationId);
+ }
+
+ if (engineHandle)
+ {
+ result = FwpmEngineClose(engineHandle);
+ engineHandle = NULL;
+ }
+
+ return result;
+}
+
+void
+MonitorPrintUsage()
+{
+ wprintf(L"Usage: monitor ( addcallouts | delcallouts | monitor <targetApp.exe> )\n");
+}
+
+DWORD
+MonitorAppProcessArguments(_In_ int argc, _In_reads_(argc) PCWSTR argv[])
+{
+ if (argc == 2)
+ {
+ if (_wcsicmp(argv[1], L"addcallouts") == 0)
+ {
+ return MonitorAppAddCallouts();
+ }
+ if (_wcsicmp(argv[1], L"delcallouts") == 0)
+ {
+ return MonitorAppRemoveCallouts();
+ }
+ }
+
+ if (argc == 3)
+ {
+ if (_wcsicmp(argv[1], L"monitor") == 0)
+ {
+ return MonitorAppDoMonitoring(argv[2]);
+ }
+ }
+
+ MonitorPrintUsage();
+ return ERROR_INVALID_PARAMETER;
+}
+
+int __cdecl wmain(_In_ int argc, _In_reads_(argc) PCWSTR argv[])
+{
+ DWORD result;
+
+ result = MonitorAppProcessArguments(argc, argv);
+
+ return (int)result;
+}
diff --git a/network/trans/msnmntr/exe/monitor.vcxproj b/network/trans/msnmntr/exe/monitor.vcxproj
new file mode 100644
index 00000000..06902c7c
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.vcxproj
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{BF8F75F9-23E9-4925-96A1-76FD729EBA93}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{DED4B73F-AFBE-4142-AD53-004F9F079AA7}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="monitor.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/exe/monitor.vcxproj.Filters b/network/trans/msnmntr/exe/monitor.vcxproj.Filters
new file mode 100644
index 00000000..2838b33f
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.vcxproj.Filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{AB53852E-BB5F-49F9-8184-98DAFA476C33}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{253A5086-E26E-4352-B8E1-BBBEB6A81F31}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{714E88E3-7CAD-4F49-8A28-32DD65C6691E}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="monitor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/exe/mtrace.cmd b/network/trans/msnmntr/exe/mtrace.cmd
new file mode 100644
index 00000000..f7c6147f
--- /dev/null
+++ b/network/trans/msnmntr/exe/mtrace.cmd
@@ -0,0 +1,288 @@
+@echo off
+@setlocal
+
+@rem -------------------------------------------------------------------------
+@rem OBTAIN INPUT
+@rem -------------------------------------------------------------------------
+
+set TR_MODULE=%1
+shift
+set TR_LEVEL=%1
+shift
+set TR_VERB=%1
+
+@rem -------------------------------------------------------------------------
+@rem VALIDATE COMPONENT & TRACING LEVEL
+@rem -------------------------------------------------------------------------
+
+if /i "%TR_MODULE%"=="MONITOR" (
+ set TR_GUID={dd65554d-9925-49d1-83b6-46125feb4207}
+ set TR_MODULE=MsnMntrMonitor
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Monitor component does not support this trace detail.
+ goto :show_usage_MsnMntrMonitor
+ )
+) else if /i "%TR_MODULE%"=="NOTIFY" (
+ set TR_GUID={aca2f74a-7a0d-4f47-be4b-66900813b8e5}
+ set TR_MODULE=MsnMntrNotify
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="3" (
+ set TR_BITS=
+ set TR_LEVEL=3
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Notify component does not support this trace detail.
+ goto :show_usage_MsnMntrNotify
+ )
+
+) else if /i "%TR_MODULE%"=="CONTROL" (
+ set TR_GUID={eab718af-52de-477c-874d-cb49746bb131}
+ set TR_MODULE=MsnMntrCtl
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Control component does not support this trace detail.
+ goto :show_usage_MsnMntrCtl
+ )
+
+) else if /i "%TR_MODULE%"=="INIT" (
+ set TR_GUID={e7db16bb-41be-4c05-b73e-5feca06f8207}
+ set TR_MODULE=MsnMntrInit
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Init component does not support this trace detail.
+ goto :show_usage_MsnMntrInit
+ )
+
+) else (
+ echo.
+ echo Error: No module was selected.
+ goto :show_usage
+)
+
+set TR_NAME=%TR_MODULE%
+set TR_DIR=%SystemRoot%\Tracing\%TR_NAME%
+set TR_LOG=%TR_DIR%\%TR_NAME%.etl
+set TR_BITS=0xFFFFFFFF
+set TR_OPTS=
+set TR_RT_OPTS=-rt -ft 1
+
+set TRACE_FORMAT_PREFIX=%%9!d!:%%3!04X! %%!FUNC!:
+set TRACE_FORMAT_SEARCH_PATH=%TR_DIR%
+
+@rem -------------------------------------------------------------------------
+@rem VALIDATE VERB
+@rem -------------------------------------------------------------------------
+
+if /i "%TR_VERB%"=="start" (
+ call :start_trace
+) else if /i "%TR_VERB%"=="stop" (
+ call :stop_trace
+) else if /i "%TR_VERB%"=="pdb" (
+ call :extract_format_info %1
+) else if /i "%TR_VERB%"=="rt" (
+ call :format_realtime
+) else if /i "%TR_VERB%"=="fmt" (
+ call :format_offline
+) else (
+ echo.
+ echo Error: A supported verb has not been specified.
+ goto :show_usage
+)
+
+goto :eof
+
+:ShowSummary
+ echo.
+ echo Trace name : %TR_NAME%
+ echo Trace directory : %TR_DIR%
+ echo Trace log : %TR_LOG%
+ echo Trace level : %TR_LEVEL%
+
+@rem -------------------------------------------------------------------------
+@rem START TRACING
+@rem -------------------------------------------------------------------------
+:start_trace
+ if not exist %TR_DIR% mkdir %TR_DIR%
+ logman query %TR_NAME% -ets 1 > NUL
+ if errorlevel 1 (
+ logman start %TR_NAME% %TR_OPTS% -p %TR_GUID% %TR_BITS% %TR_LEVEL% -o %TR_LOG% -ets
+ ) else (
+ echo Collection is already started.
+ )
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem STOP TRACING
+@rem -------------------------------------------------------------------------
+:stop_trace
+ logman query %TR_NAME% -ets 1>NUL
+ if NOT errorlevel 1 (
+ logman stop %TR_NAME% -ets
+ )
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem EXTRACT FORMAT INFO
+@rem -------------------------------------------------------------------------
+:extract_format_info
+ if "%1" == "" (
+ set TR_PDB=.\%TR_MODULE%.pdb
+ )else (
+ set TR_PDB=%1
+ )
+ tracepdb -f %TR_PDB% -p %TR_DIR%
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem FORMAT REALTIME
+@rem -------------------------------------------------------------------------
+:format_realtime
+ call :stop_trace
+ set TR_OPTS=%TR_RT_OPTS%
+ call :start_trace
+ start "%TR_NAME% Tracing" /low tracefmt -displayonly -rt %TR_NAME%
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem FORMAT OFFLINE
+@rem -------------------------------------------------------------------------
+:format_offline
+ tracefmt -o %TR_NAME%.txt %TR_LOG% -display
+ goto :eof
+
+goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem CONTEXT SENSITIVE HELP
+@rem -------------------------------------------------------------------------
+:show_usage
+ call :show_usage_header
+ echo 9 Display all trace events
+ echo Select a component to see individual supported tracing levels.
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrMonitor
+ call :show_usage_header
+ echo 0 Established flow
+ echo 1 Change of state information
+ echo 2 Layer notifications
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrNotify
+ call :show_usage_header
+ echo 0 Client to server
+ echo 1 Peer to peer
+ echo 2 Unknown
+ echo 3 All traffic
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrCtl
+ call :show_usage_header
+ echo 0 Initialization
+ echo 1 Device control
+ echo 2 State
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrInit
+ call :show_usage_header
+ echo 0 Initialization
+ echo 1 Shutdown
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_header
+ echo.
+ echo Usage: monitor_trace COMPONENT LEVEL VERB
+ echo.
+ echo Components:
+ echo MONITOR, NOTIFY, CONTROL and INIT
+ echo.
+ echo Trace detail:
+ goto :eof
+
+:show_usage_footer
+ echo.
+ echo Verbs:
+ echo start Start collection.
+ echo stop Stop collection.
+ echo pdb Extract format information from the pdb in the current
+ echo directory.
+ echo pdb [file] Like the above, but allows the full path to the pdb
+ echo to be specified.
+ echo rt Displays the trace output in real-time. This
+ echo automatically stops any existing collection and begins
+ echo a new one with appropriate parameters for real-time.
+ echo fmt Format the trace logfile to the console.
+ echo.
+ echo Note:
+ echo The most common scenario is to extract the format information from
+ echo the pdb, and then display the output in real-time.
+ echo.
+ echo Example:
+ echo cd /d MySymbolDir
+ echo monitor_trace init 0 pdb
+ echo monitor_trace init 0 rt
+
+ goto :eof \ No newline at end of file
diff --git a/network/trans/msnmntr/inc/ioctl.h b/network/trans/msnmntr/inc/ioctl.h
new file mode 100644
index 00000000..ea08dc42
--- /dev/null
+++ b/network/trans/msnmntr/inc/ioctl.h
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample callout driver IOCTL header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+#define MONITOR_DEVICE_NAME L"\\Device\\MonitorSample"
+#define MONITOR_SYMBOLIC_NAME L"\\DosDevices\\Global\\MonitorSample"
+#define MONITOR_DOS_NAME L"\\\\.\\MonitorSample"
+
+typedef enum _MONITOR_OPERATION_MODE
+{
+ invalidOperation = 0,
+ monitorTraffic = 1,
+ monitorOperationMax
+} MONITOR_OPERATION_MODE;
+
+typedef struct _MONITOR_SETTINGS
+{
+ MONITOR_OPERATION_MODE monitorOperation;
+ UINT32 flags;
+} MONITOR_SETTINGS;
+
+#define MONITOR_IOCTL_ENABLE_MONITOR CTL_CODE(FILE_DEVICE_NETWORK, 0x1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define MONITOR_IOCTL_DISABLE_MONITOR CTL_CODE(FILE_DEVICE_NETWORK, 0x2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
diff --git a/network/trans/msnmntr/inc/mntrguid.h b/network/trans/msnmntr/inc/mntrguid.h
new file mode 100644
index 00000000..8b072853
--- /dev/null
+++ b/network/trans/msnmntr/inc/mntrguid.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample callout driver IOCTL header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+// b3241f1d-7cd2-4e7a-8721-2e97d07702e5
+DEFINE_GUID(
+ MONITOR_SAMPLE_SUBLAYER,
+ 0xb3241f1d,
+ 0x7cd2,
+ 0x4e7a,
+ 0x87, 0x21, 0x2e, 0x97, 0xd0, 0x77, 0x02, 0xe5
+);
+
+// 3aaccbc0-2c29-455f-bb91-0e801c8994a4
+DEFINE_GUID(
+ MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0x3aaccbc0,
+ 0x2c29,
+ 0x455f,
+ 0xbb, 0x91, 0x0e, 0x80, 0x1c, 0x89, 0x94, 0xa4
+);
+
+// cea0131a-6ed3-4ed6-b40c-8a8fe8434b0a
+DEFINE_GUID(
+ MONITOR_SAMPLE_STREAM_CALLOUT_V4,
+ 0xcea0131a,
+ 0x6ed3,
+ 0x4ed6,
+ 0xb4, 0x0c, 0x8a, 0x8f, 0xe8, 0x43, 0x4b, 0x0a
+);
+
+
diff --git a/network/trans/msnmntr/msnmntr.sln b/network/trans/msnmntr/msnmntr.sln
new file mode 100644
index 00000000..ac6d8e3e
--- /dev/null
+++ b/network/trans/msnmntr/msnmntr.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{18ABBE0C-EBB5-4181-AB5D-AD526B2CB283}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{B9075E40-A5B9-42B8-A185-CB3290C4EC12}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monitor", "exe\monitor.vcxproj", "{BF8F75F9-23E9-4925-96A1-76FD729EBA93}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msnmntr", "sys\msnmntr.vcxproj", "{A0314F39-C7C2-463C-B2BE-DF387AB755F5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.Build.0 = Debug|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.ActiveCfg = Release|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.Build.0 = Release|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.ActiveCfg = Debug|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.Build.0 = Debug|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.ActiveCfg = Release|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.Build.0 = Release|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.Build.0 = Debug|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.ActiveCfg = Release|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.Build.0 = Release|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.ActiveCfg = Debug|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.Build.0 = Debug|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.ActiveCfg = Release|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93} = {18ABBE0C-EBB5-4181-AB5D-AD526B2CB283}
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5} = {B9075E40-A5B9-42B8-A185-CB3290C4EC12}
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/msnmntr/sys/ctl.c b/network/trans/msnmntr/sys/ctl.c
new file mode 100644
index 00000000..09a418c3
--- /dev/null
+++ b/network/trans/msnmntr/sys/ctl.c
@@ -0,0 +1,149 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver IO control routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "ctl.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrCtl,(eab718af, 52de, 477c, 874d, cb49746bb131), \
+ WPP_DEFINE_BIT(TRACE_INIT) \
+ WPP_DEFINE_BIT(TRACE_DEVICE_CONTROL) \
+ WPP_DEFINE_BIT(TRACE_STATE) )
+
+#include "ctl.tmh"
+
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL MonitorEvtDeviceControl;
+
+NTSTATUS
+MonitorCtlDriverInit(
+ _In_ WDFDEVICE* pDevice
+ )
+/*++
+
+Routine Description:
+
+ Initializes the request queue for our driver. This is how
+ DeviceIoControl requests are sent to KMDF drivers.
+
+Arguments:
+
+ [in] WDFDEVICE* pDevice - Our device.
+
+--*/
+{
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ DoTraceMessage(TRACE_INIT, "MonitorSample Control Initialization in progress.");
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchSequential
+ );
+
+ queueConfig.EvtIoDeviceControl = MonitorEvtDeviceControl;
+
+ status = WdfIoQueueCreate(
+ *pDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ NULL
+ );
+
+ return status;
+}
+
+VOID
+MonitorEvtDeviceControl (
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+ Handles device IO control requests. This callback drives all communication
+ between the usermode exe and this driver.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Queue);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ DoTraceMessage(TRACE_DEVICE_CONTROL, "MonitorSample Dispatch Device Control: 0x%x", IoControlCode);
+
+ switch (IoControlCode)
+ {
+ case MONITOR_IOCTL_ENABLE_MONITOR:
+ {
+ WDFMEMORY pMemory;
+ void* pBuffer;
+
+ if (InputBufferLength < sizeof(MONITOR_SETTINGS))
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ status = WdfRequestRetrieveInputMemory(Request, &pMemory);
+
+ if (NT_SUCCESS(status))
+ {
+ pBuffer = WdfMemoryGetBuffer(pMemory, NULL);
+ status = MonitorCoEnableMonitoring((MONITOR_SETTINGS*) pBuffer);
+ }
+ }
+ break;
+ }
+
+ case MONITOR_IOCTL_DISABLE_MONITOR:
+ {
+ status = STATUS_SUCCESS;
+
+ MonitorCoDisableMonitoring();
+
+ break;
+ }
+
+ default:
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ WdfRequestComplete(Request, status);
+}
diff --git a/network/trans/msnmntr/sys/ctl.h b/network/trans/msnmntr/sys/ctl.h
new file mode 100644
index 00000000..6e268be2
--- /dev/null
+++ b/network/trans/msnmntr/sys/ctl.h
@@ -0,0 +1,19 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver IO control header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+NTSTATUS
+MonitorCtlDriverInit(
+ _In_ WDFDEVICE* pDevice
+ );
+
diff --git a/network/trans/msnmntr/sys/init.c b/network/trans/msnmntr/sys/init.c
new file mode 100644
index 00000000..a85ff103
--- /dev/null
+++ b/network/trans/msnmntr/sys/init.c
@@ -0,0 +1,244 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver initialization routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ndis.h>
+#include <ntddk.h>
+#include <wdf.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "ctl.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrInit,(e7db16bb, 41be, 4c05, b73e, 5feca06f8207), \
+ WPP_DEFINE_BIT(TRACE_INIT) \
+ WPP_DEFINE_BIT(TRACE_SHUTDOWN) )
+
+#include "init.tmh"
+
+DEVICE_OBJECT* gWdmDevice;
+
+// ===========================================================================
+//
+// LOCAL PROTOTYPES
+//
+// ===========================================================================
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD MonitorEvtDriverUnload;
+
+// We're using what looks like a EVT_WDF_DRIVER_DEVICE_ADD callback, to keep
+// this looking like a normal KMDF driver. However, since this is a non-pnp
+// driver, it will not be used as a callback; we will call it ourselves at the
+// end of DriverEntry. So, do not declare it as a callback.
+// The NONPNP sample demonstrates this as well.
+NTSTATUS
+MonitorEvtDeviceAdd(
+ _In_ PWDFDEVICE_INIT pInit
+ );
+
+// ===========================================================================
+//
+// PUBLIC FUNCTIONS
+//
+// ===========================================================================
+
+NTSTATUS
+DriverEntry(
+ _In_ DRIVER_OBJECT* driverObject,
+ _In_ UNICODE_STRING* registryPath
+ )
+/*++
+
+Routine Description:
+
+ Main driver entry point. Called at driver load time
+
+Arguments:
+
+ driverObject Our driver
+ registryPath A reg key where we can keep parameters
+
+Return Value:
+
+ status of our initialization. A status != STATUS_SUCCESS aborts the
+ driver load and we don't get called again.
+
+ Each component is responsible for logging any error that causes the
+ driver load to fail.
+
+--*/
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ WDFDRIVER driver;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ //
+ // This macro is required to initialize software tracing on XP and beyond
+ // For XP and beyond use the DriverObject as the first argument.
+ //
+
+ WPP_INIT_TRACING(driverObject,registryPath);
+
+ DoTraceMessage(TRACE_INIT, "Initializing MonitorSample Driver");
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = MonitorEvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ &driver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(driver, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL);
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ status = MonitorEvtDeviceAdd(pInit);
+
+cleanup:
+ if (!NT_SUCCESS(status))
+ {
+ DoTraceMessage(TRACE_INIT, "MonitorSample Initialization Failed.");
+
+ WPP_CLEANUP(driverObject);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorEvtDeviceAdd(
+ _In_ PWDFDEVICE_INIT pInit
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ DECLARE_CONST_UNICODE_STRING(ntDeviceName, MONITOR_DEVICE_NAME);
+ DECLARE_CONST_UNICODE_STRING(symbolicName, MONITOR_SYMBOLIC_NAME);
+
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, FALSE);
+ status = WdfDeviceInitAssignName(pInit, &ntDeviceName);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = WdfDeviceCreate(&pInit, WDF_NO_OBJECT_ATTRIBUTES, &device);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = WdfDeviceCreateSymbolicLink(device, &symbolicName);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = MonitorCtlDriverInit(&device);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+ status = MonitorCoInitialize(gWdmDevice);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = MonitorNfInitialize(gWdmDevice);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ WdfControlFinishInitializing(device);
+
+cleanup:
+ // If WdfDeviceCreate was successful, it will set pInit to NULL.
+ if (pInit)
+ {
+ WdfDeviceInitFree(pInit);
+ }
+
+ return status;
+}
+
+void
+MonitorEvtDriverUnload(
+ _In_ WDFDRIVER Driver
+ )
+/*++
+
+Routine Description:
+
+ Called to indicate that we are being unloaded and to cause an orderly
+ shutdown
+
+Arguments:
+
+ driverObject Our driver
+
+Return Value:
+
+ None
+
+--*/
+{
+ DRIVER_OBJECT* driverObject;
+
+ MonitorCoUninitialize();
+ MonitorNfUninitialize();
+
+ DoTraceMessage(TRACE_SHUTDOWN, "MonitorSample Driver Shutting Down");
+
+ driverObject = WdfDriverWdmGetDriverObject(Driver);
+ WPP_CLEANUP(driverObject);
+}
diff --git a/network/trans/msnmntr/sys/msnmntr.c b/network/trans/msnmntr/sys/msnmntr.c
new file mode 100644
index 00000000..1aa33431
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.c
@@ -0,0 +1,883 @@
+/*++
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver callout routines
+
+Environment:
+
+ Kernel mode
+--*/
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "notify.h"
+#include "intsafe.h"
+
+#define INITGUID
+#include <guiddef.h>
+#include "mntrguid.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrMonitor,(dd65554d, 9925, 49d1, 83b6, 46125feb4207), \
+ WPP_DEFINE_BIT(TRACE_FLOW_ESTABLISHED) \
+ WPP_DEFINE_BIT(TRACE_STATE_CHANGE) \
+ WPP_DEFINE_BIT(TRACE_LAYER_NOTIFY) )
+
+#include "msnmntr.tmh"
+
+#define TAG_NAME_CALLOUT 'CnoM'
+
+UINT32 flowEstablishedId = 0;
+UINT32 streamId = 0;
+long monitoringEnabled = 0;
+LIST_ENTRY flowContextList;
+KSPIN_LOCK flowContextListLock;
+
+NTSTATUS MonitorCoFlowEstablishedNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter);
+
+NTSTATUS MonitorCoStreamNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter);
+
+void MonitorCoStreamFlowDeletion(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+#else
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS
+MonitorCoRegisterCallout(
+ _Inout_ void* deviceObject,
+ _In_ FWPS_CALLOUT_CLASSIFY_FN ClassifyFunction,
+ _In_ FWPS_CALLOUT_NOTIFY_FN NotifyFunction,
+ _In_opt_ FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN FlowDeleteFunction,
+ _In_ const GUID* calloutKey,
+ _In_ UINT32 flags,
+ _Out_ UINT32* calloutId
+ )
+{
+ FWPS_CALLOUT sCallout;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ memset(&sCallout, 0, sizeof(FWPS_CALLOUT));
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.flags = flags;
+ sCallout.classifyFn = ClassifyFunction;
+ sCallout.notifyFn = NotifyFunction;
+ sCallout.flowDeleteFn = FlowDeleteFunction;
+
+ status = FwpsCalloutRegister(deviceObject, &sCallout, calloutId);
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+{
+ NTSTATUS status;
+
+ //
+ // We won't be called for flow deletion for the flow established layer
+ // since we only establish a flow for the stream layer, so we don't
+ // specify a flow deletion function.
+ //
+ status = MonitorCoRegisterCallout(deviceObject,
+ MonitorCoFlowEstablishedCalloutV4,
+ MonitorCoFlowEstablishedNotifyV4,
+ NULL, // We don't need a flow delete function at this layer.
+ &MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0, // No flags.
+ &flowEstablishedId);
+
+ if (NT_SUCCESS(status))
+ {
+ status = MonitorCoRegisterCallout(deviceObject,
+ MonitorCoStreamCalloutV4,
+ MonitorCoStreamNotifyV4,
+ MonitorCoStreamFlowDeletion,
+ &MONITOR_SAMPLE_STREAM_CALLOUT_V4,
+ FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW,
+ &streamId);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoUnregisterCallout(
+ _In_ const GUID* calloutKey
+ )
+{
+ NTSTATUS status;
+
+ status = FwpsCalloutUnregisterByKey(calloutKey);
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoUnregisterCallouts(void)
+{
+ NTSTATUS status;
+
+ status = MonitorCoUnregisterCallout(&MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4);
+
+ if (NT_SUCCESS(status))
+ {
+ status = MonitorCoUnregisterCallout(&MONITOR_SAMPLE_STREAM_CALLOUT_V4);
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+MonitorCoInsertFlowContext(
+ _Inout_ FLOW_DATA* flowContext)
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+ NTSTATUS status;
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ // Catch the case where we disabled monitoring after we had intended to
+ // associate the context to the flow so that we don't bugcheck due to
+ // our driver being unloaded and then receiving a call for a particular
+ // flow or leak the memory because we unloaded without freeing it.
+ if (monitoringEnabled)
+ {
+ DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Creating flow for traffic.\r\n");
+
+ InsertTailList(&flowContextList, &flowContext->listEntry);
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Unable to create flow, driver shutting down.\r\n");
+
+ // Our driver is shutting down.
+ status = STATUS_SHUTDOWN_IN_PROGRESS;
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ return status;
+}
+
+void
+MonitorCoCleanupFlowContext(
+ _In_ __drv_freesMem(Mem) FLOW_DATA* flowContext
+ )
+/*
+Routine Description
+
+ Called to cleanup a flow context on flow deletion. ProcessPath is passed
+ as a second parameter so Prefast can see that it's being freed here.
+
+*/
+{
+ if (flowContext->processPath)
+ {
+ ExFreePoolWithTag(flowContext->processPath, TAG_NAME_CALLOUT);
+ }
+ ExFreePoolWithTag(flowContext, TAG_NAME_CALLOUT);
+}
+
+NTSTATUS
+MonitorCoAllocFlowContext(
+ _In_ SIZE_T processPathSize,
+ _Out_ FLOW_DATA** flowContextOut
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FLOW_DATA* flowContext = NULL;
+
+ *flowContextOut = NULL;
+
+ flowContext = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(FLOW_DATA),
+ TAG_NAME_CALLOUT);
+
+ if (!flowContext)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+
+ RtlZeroMemory(flowContext,
+ sizeof(FLOW_DATA));
+
+
+ flowContext->processPath = ExAllocatePoolWithTag(NonPagedPool,
+ processPathSize,
+ TAG_NAME_CALLOUT);
+ if (!flowContext->processPath)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+
+ }
+
+ *flowContextOut = flowContext;
+
+ cleanup:
+ if (!NT_SUCCESS(status))
+ {
+ if (flowContext)
+ {
+ if (flowContext->processPath)
+ {
+ ExFreePoolWithTag(flowContext->processPath, TAG_NAME_CALLOUT);
+ }
+ ExFreePoolWithTag(flowContext, TAG_NAME_CALLOUT);
+ }
+ }
+
+ return status;
+}
+
+
+UINT64
+MonitorCoCreateFlowContext(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Out_ UINT64* flowHandle)
+/*
+Routine Description
+
+ Creates a flow context that is associated with the current flow
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ FLOW_DATA* flowContext = NULL;
+ NTSTATUS status;
+ FWP_BYTE_BLOB* processPath;
+ UINT32 index;
+
+ *flowHandle = 0;
+
+ if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PROCESS_PATH))
+ {
+ status = STATUS_NOT_FOUND;
+ goto cleanup;
+ }
+
+ processPath = inMetaValues->processPath;
+
+ status = MonitorCoAllocFlowContext(processPath->size, &flowContext);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ // Flow context is always created at the Flow established layer.
+
+ // flowContext gets deleted in MonitorCoCleanupFlowContext
+
+ flowContext->deleting = FALSE;
+ flowContext->flowHandle = inMetaValues->flowHandle;
+ *flowHandle = flowContext->flowHandle;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS;
+ flowContext->localAddressV4 = inFixedValues->incomingValue[index].value.uint32;
+
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT;
+ flowContext->localPort = inFixedValues->incomingValue[index].value.uint16;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS;
+ flowContext->remoteAddressV4 = inFixedValues->incomingValue[index].value.uint32;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT;
+ flowContext->remotePort = inFixedValues->incomingValue[index].value.uint16;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL;
+ flowContext->ipProto = inFixedValues->incomingValue[index].value.uint16;
+
+ // flowContext->processPath gets deleted in MonitorCoCleanupFlowContext
+ memcpy(flowContext->processPath, processPath->data, processPath->size);
+
+ status = MonitorCoInsertFlowContext(flowContext);
+
+cleanup:
+
+ if (!NT_SUCCESS(status))
+ {
+ flowContext = NULL;
+ }
+
+ return (UINT64) flowContext;
+}
+
+NTSTATUS MonitorCoInitialize(_Inout_ DEVICE_OBJECT* deviceObject)
+/*
+Routine Description
+
+ Initializes our flow tracking so that we can handle the case where
+ the driver is shutdown with flows that are still active.
+
+Arguments
+
+ None.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ NTSTATUS status;
+
+ // Initialize the flow context list and lock. We need this to be able
+ // to handle the case where our driver is stopped while we still have
+ // contexts associated with flows.
+ InitializeListHead(&flowContextList);
+ KeInitializeSpinLock(&flowContextListLock);
+
+ status = MonitorCoRegisterCallouts(deviceObject);
+
+ return status;
+}
+
+void MonitorCoUninitialize(void)
+/*
+Routine Description
+
+ Uninitializes the callouts module (this module) by ensuring that all
+ flow contexts are no longer associated with a flow to ensure that
+ our driver is not called after it is unloaded.
+
+Arguments
+
+ None.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ LIST_ENTRY list;
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ // Make sure we don't associate any more contexts to flows.
+ MonitorCoDisableMonitoring();
+
+ InitializeListHead(&list);
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ while (!IsListEmpty(&flowContextList))
+ {
+ FLOW_DATA* flowContext;
+ LIST_ENTRY* entry;
+
+ entry = RemoveHeadList(&flowContextList);
+
+ flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);
+ flowContext->deleting = TRUE; // We don't want our flow deletion function
+ // to try to remove this from the list.
+
+ InsertHeadList(&list, entry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ while (!IsListEmpty(&list))
+ {
+ FLOW_DATA* flowContext;
+ LIST_ENTRY* entry;
+ NTSTATUS status;
+
+ entry = RemoveHeadList(&list);
+
+ flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);
+
+ status = FwpsFlowRemoveContext(flowContext->flowHandle,
+ FWPS_LAYER_STREAM_V4,
+ streamId);
+ NT_ASSERT(NT_SUCCESS(status));
+ _Analysis_assume_(NT_SUCCESS(status));
+ }
+
+ MonitorCoUnregisterCallouts();
+}
+
+NTSTATUS MonitorCoEnableMonitoring(
+ _In_ MONITOR_SETTINGS* monitorSettings)
+/*
+Routine Description
+
+ Enables monitoring of traffic. Before this is called the driver will not
+ associate any context to flows and will therefore not do any inspection.
+ Once this is called we will start to track flows for the applications that
+ we are interested in.
+
+Arguments
+ [IN] MONITOR_SETTINS monitorSettings - Settings that govern our behavior.
+ Nothing is specified at this time.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ if (!monitorSettings)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DoTraceMessage(TRACE_STATE_CHANGE, "Enabling monitoring.\r\n");
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ monitoringEnabled = 1;
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ return STATUS_SUCCESS;
+}
+
+void
+MonitorCoDisableMonitoring(void)
+/*
+Routine Description
+
+ Disables monitoring of new connections so that we can safely shutdown.
+
+Arguments
+
+ None.
+
+Return values
+
+ None.
+
+Notes
+
+
+*/
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ DoTraceMessage(TRACE_STATE_CHANGE, "Disabling monitoring.\r\n");
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ monitoringEnabled = 0;
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#else
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/*
+Routine Description
+
+ Our flow established callout for Ipv4 traffic.
+
+Arguments
+ [IN] const FWPS_INCOMING_VALUES* inFixedValues - The fixed values passed in
+ based on the traffic.
+ [IN] const FWPS_INCOMING_METADATA_VALUES* inMetaValues - Metadata the
+ provides additional
+ information about the
+ connection.
+ [IN] void* packet - Depending on the layer and protocol this can be NULL or a
+ layer specific type.
+ [IN, OPTIONAL] const VOID* classifyContext - context data associated with the callout driver
+ [IN] const FWPS_FILTER* filter - The filter that has specified this callout.
+ [IN] UINT64 flowContext - Flow context associated with a flow
+ [OUT] FWPS_CLASSIFY_OUT* classifyOut - Out parameter that is used to inform
+ the filter engine of our decision
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+
+ NTSTATUS status = STATUS_SUCCESS;
+ UINT64 flowHandle;
+ UINT64 flowContextLocal;
+
+ UNREFERENCED_PARAMETER(packet);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ if (monitoringEnabled)
+ {
+ flowContextLocal = MonitorCoCreateFlowContext(inFixedValues, inMetaValues, &flowHandle);
+
+ if (!flowContextLocal)
+ {
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+ goto cleanup;
+ }
+
+ status = FwpsFlowAssociateContext(flowHandle,
+ FWPS_LAYER_STREAM_V4,
+ streamId,
+ flowContextLocal);
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+ goto cleanup;
+ }
+ }
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+cleanup:
+
+ return status;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#else
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/*
+Routine Description
+
+ Our stream layer callout for traffic to/from the application we're
+ interested in. Since we specified the filter that matches this callout
+ as conditional on flow, we only get called if we've associated a flow with
+ the traffic.
+
+Arguments
+ [IN] const FWPS_INCOMING_VALUES* inFixedValues - The fixed values passed in
+ based on the traffic.
+ [IN] const FWPS_INCOMING_METADATA_VALUES* inMetaValues - Metadata the
+ provides additional
+ information about the
+ connection.
+ [IN] void* packet - Depending on the layer and protocol this can be NULL or a
+ layer specific type.
+ [IN] const FWPS_FILTER* filter - The filter that has specified this callout.
+ [IN, OPTIONAL] const VOID* classifyContext - context data associated with the callout driver
+ [IN] UINT64 flowContext - Flow context associated with a flow
+ [OUT] FWPS_CLASSIFY_OUT* classifyOut - Out parameter that is used to inform
+ the filter engine of our decision
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ FLOW_DATA* flowData;
+ FWPS_STREAM_CALLOUT_IO_PACKET* streamPacket;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN inbound;
+
+ UNREFERENCED_PARAMETER(inFixedValues);
+ UNREFERENCED_PARAMETER(inMetaValues);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ _Analysis_assume_(packet != NULL);
+
+ if (!monitoringEnabled)
+ {
+ goto cleanup;
+ }
+
+ streamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*) packet;
+
+ if (streamPacket->streamData != NULL &&
+ streamPacket->streamData->dataLength != 0)
+ {
+ flowData = *(FLOW_DATA**)(UINT64*) &flowContext;
+
+ inbound = (BOOLEAN) ((streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE) == FWPS_STREAM_FLAG_RECEIVE);
+
+ status = MonitorNfNotifyMessage(streamPacket->streamData,
+ inbound,
+ flowData->localPort,
+ flowData->remotePort);
+ }
+
+cleanup:
+
+ // Return CONTINUE to the filter engine, we're just monitoring.
+
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+
+ return status;
+}
+
+NTSTATUS MonitorCoFlowEstablishedNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter)
+/*
+Routine Description
+
+ Notification routine that is called whenever a filter is added, deleted or
+ modified on the layer that our callout is registered against.
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ switch (notifyType)
+ {
+ case FWPS_CALLOUT_NOTIFY_ADD_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Added to Flow Established layer.\r\n");
+
+ break;
+ case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Deleted from Flow Established layer.\r\n");
+ break;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void MonitorCoStreamFlowDeletion(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext)
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+ FLOW_DATA* flowData;
+ HRESULT result;
+ ULONG_PTR flowPtr;
+
+
+ UNREFERENCED_PARAMETER(layerId);
+ UNREFERENCED_PARAMETER(calloutId);
+
+ result = ULongLongToULongPtr(flowContext, &flowPtr);
+ ASSERT(result == S_OK);
+ _Analysis_assume_(result == S_OK);
+
+
+ flowData = ((FLOW_DATA*)flowPtr);
+
+ //
+ // If we're already being deleted from the list then we mustn't try to
+ // remove ourselves here.
+ //
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ if (!flowData->deleting)
+ {
+ RemoveEntryList(&flowData->listEntry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ MonitorCoCleanupFlowContext(flowData);
+}
+
+NTSTATUS MonitorCoStreamNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter)
+/*
+Routine Description
+
+ Notification routine that is called whenever a filter is added, deleted or
+ modified on the layer that our callout is registered against.
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ switch (notifyType)
+ {
+ case FWPS_CALLOUT_NOTIFY_ADD_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Added to Stream layer.\r\n");
+
+ break;
+ case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Deleted from Stream layer.\r\n");
+ break;
+ }
+ return STATUS_SUCCESS;
+}
diff --git a/network/trans/msnmntr/sys/msnmntr.h b/network/trans/msnmntr/sys/msnmntr.h
new file mode 100644
index 00000000..adb470c0
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver callout header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+typedef struct _FLOW_DATA
+{
+ UINT64 flowHandle;
+ UINT64 flowContext;
+ UINT64 calloutId;
+ ULONG localAddressV4;
+ USHORT localPort;
+ USHORT ipProto;
+ ULONG remoteAddressV4;
+ USHORT remotePort;
+ WCHAR* processPath;
+ LIST_ENTRY listEntry;
+ BOOLEAN deleting;
+} FLOW_DATA;
+
+NTSTATUS
+MonitorCoInitialize(_Inout_ DEVICE_OBJECT* deviceObject);
+
+void
+MonitorCoUninitialize(void);
+
+NTSTATUS
+MonitorCoRegisterCallouts(_Inout_ void* deviceObject);
+
+NTSTATUS
+MonitorCoUnregisterCallouts(void);
+
+NTSTATUS
+MonitorCoSetApplication(
+ _In_reads_(size) wchar_t* fileName,
+ _In_ ULONG size);
+
+NTSTATUS
+MonitorCoEnableMonitoring(
+ _In_ MONITOR_SETTINGS* monitorSettings);
+
+void
+MonitorCoDisableMonitoring(void);
+
diff --git a/network/trans/msnmntr/sys/msnmntr.inf b/network/trans/msnmntr/sys/msnmntr.inf
new file mode 100644
index 00000000..30d012b1
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.inf
@@ -0,0 +1,54 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Monitor Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = MSNMntr.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %MSNMntrDisk%,,,""
+
+[SourceDisksFiles]
+ MSNMntr.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ MSNMntr.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %MSNMntrServiceDesc%
+ CopyFiles = MSNMntr.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %MSNMntrServiceName%,,MSNMntr.Service
+
+[DefaultUninstall]
+ DelFiles = MSNMntr.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %MSNMntrServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+
+[MSNMntr.DriverFiles]
+ MSNMntr.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[MSNMntr.Service]
+ DisplayName = %MSNMntrServiceName%
+ Description = %MSNMntrServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\MSNMntr.sys ; %WinDir%\System32\Drivers\MSNMntr.sys
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ MSNMntrDisk = "Monitor Installation Disk"
+ MSNMntrServiceDesc = "Monitor Callout Driver"
+ MSNMntrServiceName = "MSNMntr" \ No newline at end of file
diff --git a/network/trans/msnmntr/sys/msnmntr.vcxproj b/network/trans/msnmntr/sys/msnmntr.vcxproj
new file mode 100644
index 00000000..19d05a61
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.vcxproj
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{A0314F39-C7C2-463C-B2BE-DF387AB755F5}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2235E7F5-485C-4A50-AC6E-7D5127C63D50}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="init.c; msnmntr.c; ctl.c; notify.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters
new file mode 100644
index 00000000..7a507ae9
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{061ABC02-158F-4210-A282-D00E6E173776}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{EAF55685-C4D1-47E0-A3A8-B3E417170A02}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{7449D543-948C-4CDB-AB03-EE885873121D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{E3258914-96DA-44CC-9DB9-3F58E7232911}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="ctl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="init.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="msnmntr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="notify.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/sys/notify.c b/network/trans/msnmntr/sys/notify.c
new file mode 100644
index 00000000..22253797
--- /dev/null
+++ b/network/trans/msnmntr/sys/notify.c
@@ -0,0 +1,294 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver notification routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrNotify,(aca2f74a, 7a0d, 4f47, be4b, 66900813b8e5), \
+ WPP_DEFINE_BIT(TRACE_CLIENT_SERVER) \
+ WPP_DEFINE_BIT(TRACE_PEER_TO_PEER) \
+ WPP_DEFINE_BIT(TRACE_UNKNOWN) \
+ WPP_DEFINE_BIT(TRACE_ALL_TRAFFIC) )
+
+#include "notify.tmh" // This file will be auto generated
+
+
+#define TAG_NAME_NOTIFY 'oNnM'
+
+NTSTATUS
+MonitorNfInitialize(
+ _In_ DEVICE_OBJECT* deviceObject)
+{
+ UNREFERENCED_PARAMETER(deviceObject);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfUninitialize(void)
+{
+ return STATUS_SUCCESS;
+}
+
+__forceinline
+void*
+MonitorNfpFindCharacters(
+ _In_reads_bytes_(streamLength) const char* stream,
+ _In_ size_t streamLength,
+ _In_reads_bytes_(subStreamLength) const char* subStream,
+ _In_ size_t subStreamLength,
+ _Out_ size_t* bytesLeft)
+{
+ size_t currentOffset = 0;
+ void* subStreamPtr = NULL;
+
+ *bytesLeft = streamLength;
+
+ if (subStreamLength > streamLength)
+ {
+ return NULL;
+ }
+
+ while (currentOffset+subStreamLength <= streamLength)
+ {
+ if (0 == memcmp((void*)(stream+currentOffset), subStream, subStreamLength))
+ {
+ subStreamPtr = (void*)(char*)(stream+currentOffset);
+ *bytesLeft = streamLength;
+ *bytesLeft -= currentOffset;
+ *bytesLeft -= subStreamLength;
+ break;
+ }
+ currentOffset += subStreamLength;
+ }
+
+ return subStreamPtr;
+}
+
+NTSTATUS
+MonitorNfParseMessageInbound(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ UNREFERENCED_PARAMETER(stream);
+
+ DoTraceMessage(TRACE_CLIENT_SERVER,
+ "%Id bytes received. Local Port: %d Remote Port: %d.",
+ streamLength,
+ localPort,
+ remotePort);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfParseMessageInboundHttpHeader(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ BYTE* msgStart = NULL;
+ size_t bytesLeft;
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ // Walk past the HTTP header.
+ msgStart = (BYTE*) MonitorNfpFindCharacters((char*)stream,
+ streamLength,
+ "\r\n\r\n",
+ (ULONG)strlen("\r\n\r\n"),
+ &bytesLeft);
+ if (msgStart && (bytesLeft > 0))
+ {
+ size_t msgLength;
+
+ msgStart += 4; // step past \r\n\r\n.
+
+ msgLength = streamLength - (ULONG)(ULONG_PTR)(msgStart - stream);
+
+ // Do the final inbound message processing.
+ status = MonitorNfParseMessageInbound(msgStart,
+ msgLength,
+ localPort,
+ remotePort);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorNfParseMessageOutbound(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ UNREFERENCED_PARAMETER(stream);
+
+ DoTraceMessage(TRACE_CLIENT_SERVER,
+ "%Id bytes sent. Local Port: %d Remote Port: %d.",
+ streamLength,
+ localPort,
+ remotePort);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfParseMessageOutboundHttpHeader(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ BYTE* msgStart = NULL;
+ size_t bytesLeft;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Walk past the HTTP header.
+ msgStart = (BYTE*) MonitorNfpFindCharacters((char*)stream,
+ streamLength,
+ "\r\n\r\n",
+ (ULONG)strlen("\r\n\r\n"),
+ &bytesLeft);
+ if (msgStart && (bytesLeft > 0))
+ {
+ size_t msgLength;
+
+ msgStart += 4; // step past \r\n\r\n.
+
+ msgLength = streamLength - (ULONG)(ULONG_PTR)(msgStart - stream);
+ status = MonitorNfParseMessageOutbound(msgStart,
+ msgLength,
+ localPort,
+ remotePort);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorNfParseStreamAndTraceMessage(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ NTSTATUS status;
+
+ if (!inbound)
+ {
+ if ((_strnicmp((const char*)stream, "POST", streamLength) == 0)
+ || (_strnicmp((const char*)stream, "GET", streamLength) == 0))
+ {
+ if ((MonitorNfParseMessageOutboundHttpHeader(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ if ((MonitorNfParseMessageOutbound(stream,
+ streamLength,
+ localPort,
+ remotePort)!= STATUS_SUCCESS))
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ if (_strnicmp((const char*)stream, "HTTP", streamLength) == 0)
+ {
+ if ((MonitorNfParseMessageInboundHttpHeader(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ if ((MonitorNfParseMessageInbound(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+
+NTSTATUS MonitorNfNotifyMessage(
+ _In_ const FWPS_STREAM_DATA* streamBuffer,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort
+)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ BYTE* stream = NULL;
+ SIZE_T streamLength = streamBuffer->dataLength;
+ SIZE_T bytesCopied = 0;
+
+ if(streamLength == 0)
+ return status;
+
+ stream = ExAllocatePoolWithTag(NonPagedPool,
+ streamLength,
+ TAG_NAME_NOTIFY);
+ if (!stream)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(stream,streamLength);
+
+ FwpsCopyStreamDataToBuffer(
+ streamBuffer,
+ stream,
+ streamLength,
+ &bytesCopied);
+
+ NT_ASSERT(bytesCopied == streamLength);
+
+ status = MonitorNfParseStreamAndTraceMessage(stream, streamLength, inbound, localPort, remotePort);
+
+ ExFreePoolWithTag(stream, TAG_NAME_NOTIFY);
+
+ return status;
+}
diff --git a/network/trans/msnmntr/sys/notify.h b/network/trans/msnmntr/sys/notify.h
new file mode 100644
index 00000000..ba37fab2
--- /dev/null
+++ b/network/trans/msnmntr/sys/notify.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver notification header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+#define TAG_NOTIFY 'yftN'
+
+NTSTATUS
+MonitorNfInitialize(
+ _In_ DEVICE_OBJECT* deviceObject);
+
+NTSTATUS
+MonitorNfUninitialize(void);
+
+NTSTATUS MonitorNfNotifyMessage(
+ _In_ const FWPS_STREAM_DATA* streamBuffer,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort);
+
+
diff --git a/network/trans/stmedit/ReadMe.md b/network/trans/stmedit/ReadMe.md
new file mode 100644
index 00000000..da921272
--- /dev/null
+++ b/network/trans/stmedit/ReadMe.md
@@ -0,0 +1,60 @@
+Windows Filtering Platform Stream Edit Sample
+=============================================
+
+This sample driver demonstrates replacing a string pattern for a Transmission Control Protocol (TCP) connection using the Windows Filtering Platform (WFP).
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+The sample consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Stmedit.sys) that can operate in one of the following modes:
+
+- Inline editing where all modification is done within the `ClassifyFn` callout function.
+- Out-of-band editing where all modification is done by a worker thread (the default).
+
+The sample performs inspection for both Internet Protocol version 4 (IPv4) and Internet Protocol version 6 (IPv6) traffic.
+
+Before experimenting with the sample, add an exception for the InspectionPort to your host firewall.
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, navigate to DriverTest\\Drivers, and locate the file stmedit.inf. Right click stmedit.inf, and choose **Install**.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). After you have prepared the target computer for manual deployment, continue with these steps:
+
+1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\WfpStreamEditSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click stmedit.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+- On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**strmedit**\\**Parameters**
+
+You can create and set values for the following registry entries.
+
+- **EditInline** (REG\_DWORD type): 1 for inline editing, 0 for out-of-band editing (the default)
+- **StringToFind** (REG\_SZ type): default = "rainy"
+- **StringToReplace** (REG\_SZ type): default = "sunny"
+- **InspectionPort** (REG\_DWORD type): TCP port (default = 5001)
+- **InspectOutbound** (REG\_DWORD type): TCP port (default = 0)
+
+Start the stmedit service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start stmedit**. (To stop the driver, enter **net stop stmedit**.)
+
+Remarks
+-------
+
+For more information on creating a Windows Filtering Platform Callout Driver, see [Windows Filtering Platform Callout Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571068).
+
diff --git a/network/trans/stmedit/stmedit.sln b/network/trans/stmedit/stmedit.sln
new file mode 100644
index 00000000..7f1cb436
--- /dev/null
+++ b/network/trans/stmedit/stmedit.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stmedit", "sys\stmedit.vcxproj", "{98513F1C-C28D-4F03-99A8-88FD4BD707C7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.Build.0 = Debug|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.ActiveCfg = Release|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.Build.0 = Release|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.ActiveCfg = Debug|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.Build.0 = Debug|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.ActiveCfg = Release|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/stmedit/sys/inline_edit.c b/network/trans/stmedit/sys/inline_edit.c
new file mode 100644
index 00000000..16685a9e
--- /dev/null
+++ b/network/trans/stmedit/sys/inline_edit.c
@@ -0,0 +1,546 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates inline stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+void
+InlineEditInit(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ streamEditor->editInline = TRUE;
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+}
+
+void
+NTAPI StreamInjectCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ MDL* mdl = (MDL*)context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+
+ FwpsFreeNetBufferList(netBufferList);
+}
+
+NTSTATUS
+StreamEditFlushData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT64 flowId,
+ UINT32 calloutId,
+ UINT16 layerId,
+ UINT32 streamFlags
+ )
+/* ++
+
+ This function re-injects buffered data back to the data stream upon
+ receiving a FIN. The data was buffered because it was not big enough
+ (size wise) to make an editing decision.
+
+-- */
+{
+ NTSTATUS status;
+
+ MDL* mdl = NULL;
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ NT_ASSERT(streamEditor->dataOffset == 0);
+
+ mdl = IoAllocateMdl(
+ streamEditor->scratchBuffer,
+ (ULONG)(streamEditor->dataLength),
+ FALSE,
+ FALSE,
+ NULL
+ );
+
+ if (mdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ mdl,
+ 0,
+ streamEditor->dataLength,
+ &netBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamFlags &= ~(FWPS_STREAM_FLAG_SEND_DISCONNECT | FWPS_STREAM_FLAG_RECEIVE_DISCONNECT);
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ flowId,
+ calloutId,
+ layerId,
+ streamFlags,
+ netBufferList,
+ streamEditor->dataLength,
+ StreamInjectCompletionFn,
+ mdl
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ mdl = NULL;
+ netBufferList = NULL;
+
+Exit:
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+
+ return status;
+}
+
+void
+StreamInlineEdit(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ const FWPS_FILTER* filter,
+ _In_ const FWPS_STREAM_DATA* streamData,
+ _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+/* ++
+
+ This function implements the state machine that scans the content
+ and computes the number of bytes to permit, bytes to block, and
+ performs stream injection to replace the blocked data.
+
+-- */
+{
+ UINT findLength = (UINT) strlen(configStringToFind);
+ UINT replaceLength = (UINT) strlen(configStringToReplace);
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ if (streamEditor->dataLength > 0)
+ {
+ StreamEditFlushData(
+ streamEditor,
+ inMetaValues->flowHandle,
+ filter->action.calloutId,
+ inFixedValues->layerId,
+ streamData->flags
+ );
+
+ streamEditor->dataLength = 0;
+ streamEditor->dataOffset = 0;
+ }
+
+ NT_ASSERT(streamEditor->inlineEditState == INLINE_EDIT_WAITING_FOR_DATA);
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if (streamData->dataLength == 0)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if (streamEditor->inlineEditState != INLINE_EDIT_SKIPPING)
+ {
+ if ((streamData->dataLength < findLength) &&
+ !(classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
+ ioPacket->countBytesRequired = findLength;
+
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+ }
+
+ switch (streamEditor->inlineEditState)
+ {
+ case INLINE_EDIT_WAITING_FOR_DATA:
+ {
+ if (StreamCopyDataForInspection(
+ streamEditor,
+ streamData
+ ) == FALSE)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ //
+ // Pass-thru to scanning
+ //
+ }
+ case INLINE_EDIT_SCANNING:
+ {
+ UINT i;
+ BYTE* dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+ BOOLEAN found = FALSE;
+
+ for (i = 0; i < streamEditor->dataLength; ++i)
+ {
+ if (i + findLength <= streamEditor->dataLength)
+ {
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ findLength
+ ) == findLength)
+ {
+ found = TRUE;
+
+ streamEditor->inlineEditState = INLINE_EDIT_MODIFYING;
+
+ if (i != 0)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = i;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ streamEditor->dataOffset += i;
+ streamEditor->dataLength -= i;
+
+ break;
+ }
+ else
+ {
+ goto modify_data;
+ }
+ }
+ }
+ else
+ {
+ if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)
+ {
+ break;
+ }
+
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ streamEditor->dataLength - i
+ ) == streamEditor->dataLength - i)
+ {
+ found = TRUE; // this is a partial find
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = i;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ RtlMoveMemory(
+ streamEditor->scratchBuffer,
+ dataStart + i,
+ streamEditor->dataLength - i
+ );
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = streamEditor->dataLength - i;
+
+ streamEditor->inlineEditState = INLINE_EDIT_SKIPPING;
+
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+ }
+
+ break;
+ }
+ case INLINE_EDIT_SKIPPING:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+
+ break;
+ }
+ case INLINE_EDIT_MODIFYING:
+
+modify_data:
+
+ {
+ NTSTATUS status;
+ NET_BUFFER_LIST* netBufferList;
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ gStringToReplaceMdl,
+ 0,
+ replaceLength,
+ &netBufferList
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ inMetaValues->flowHandle,
+ filter->action.calloutId,
+ inFixedValues->layerId,
+ streamData->flags,
+ netBufferList,
+ replaceLength,
+ StreamInjectCompletionFn,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ FwpsFreeNetBufferList(netBufferList);
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = findLength;
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+
+ streamEditor->dataOffset += findLength;
+ streamEditor->dataLength -= findLength;
+
+ if (streamEditor->dataLength > 0)
+ {
+ streamEditor->inlineEditState = INLINE_EDIT_SCANNING;
+ }
+ else
+ {
+ streamEditor->dataOffset = 0;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+ }
+
+ break;
+ }
+ default:
+ NT_ASSERT(FALSE);
+ break;
+ };
+
+Exit:
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Out_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+/* ++
+
+ This is the ClassifyFn function registered by the inline stream edit callout.
+
+ An inline stream modification callout performs editing from within the
+ ClassifyFn call by permitting sections of the content and replacing other
+ sections by removing them and injecting new content.
+
+-- */
+{
+ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket;
+ FWPS_STREAM_DATA* streamData;
+
+ ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)layerData;
+ NT_ASSERT(ioPacket != NULL);
+
+ streamData = ioPacket->streamData;
+ NT_ASSERT(streamData != NULL);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ RtlZeroMemory(classifyOut, sizeof(FWPS_CLASSIFY_OUT));
+
+ //
+ // Let go the traffic that the editor does not care about.
+ //
+
+ if ((configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_RECEIVE)) ||
+ (!configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_SEND)))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ //
+ // In this sample we don't edit TCP urgent data
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_EXPEDITED) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_EXPEDITED))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ StreamInlineEdit(
+ &gStreamEditor,
+ inFixedValues,
+ inMetaValues,
+ filter,
+ streamData,
+ ioPacket,
+ classifyOut
+ );
+
+Exit:
+
+ return;
+}
diff --git a/network/trans/stmedit/sys/inline_edit.h b/network/trans/stmedit/sys/inline_edit.h
new file mode 100644
index 00000000..a9345324
--- /dev/null
+++ b/network/trans/stmedit/sys/inline_edit.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates inline stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _INLINE_EDIT_H
+#define _INLINE_EDIT_H
+
+typedef enum INLINE_EDIT_STATE_
+{
+ INLINE_EDIT_WAITING_FOR_DATA,
+ INLINE_EDIT_SKIPPING,
+ INLINE_EDIT_MODIFYING,
+ INLINE_EDIT_SCANNING
+} INLINE_EDIT_STATE;
+
+typedef struct STREAM_EDITOR_ STREAM_EDITOR;
+
+void
+InlineEditInit(
+ _Out_ STREAM_EDITOR*
+ );
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+#endif // _INLINE_EDIT_H
diff --git a/network/trans/stmedit/sys/oob_edit.c b/network/trans/stmedit/sys/oob_edit.c
new file mode 100644
index 00000000..ee53bc5e
--- /dev/null
+++ b/network/trans/stmedit/sys/oob_edit.c
@@ -0,0 +1,1363 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates Out-of-band (OOB) stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+#define STREAM_EDITOR_OUTGOING_DATA_TAG 'doeS'
+#define STREAM_EDITOR_MDL_DATA_TAG 'dmeS'
+
+void* gThreadObj;
+
+KSTART_ROUTINE StreamOobEditWorker;
+
+NTSTATUS
+OobEditInit(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ HANDLE threadHandle;
+
+ streamEditor->editInline = FALSE;
+
+ KeInitializeSpinLock(&streamEditor->oobEditInfo.editLock);
+
+ KeInitializeEvent(
+ &streamEditor->oobEditInfo.editEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ streamEditor->oobEditInfo.busyThreshold = 32 * 1024;
+ streamEditor->oobEditInfo.editState = OOB_EDIT_IDLE;
+
+ InitializeListHead(&streamEditor->oobEditInfo.outgoingDataQueue);
+
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ StreamOobEditWorker,
+ &gStreamEditor
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &gThreadObj,
+ NULL
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+
+ ZwClose(threadHandle);
+
+Exit:
+
+ return status;
+}
+
+void
+OobEditShutdown(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ streamEditor->oobEditInfo.shuttingDown = TRUE;
+
+ switch (streamEditor->oobEditInfo.editState)
+ {
+ case OOB_EDIT_IDLE:
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;
+
+ KeSetEvent(
+ &gStreamEditor.oobEditInfo.editEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+
+ break;
+ }
+ default:
+ break;
+ };
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+}
+
+__inline
+NET_BUFFER_LIST*
+TailOfNetBufferListChain(
+ _In_ NET_BUFFER_LIST* netBufferListChain
+ )
+{
+ NT_ASSERT(netBufferListChain != NULL);
+
+ while (netBufferListChain->Next != NULL)
+ {
+ netBufferListChain = netBufferListChain->Next;
+ }
+
+ return netBufferListChain;
+}
+
+void
+NTAPI
+StreamOobInjectCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN dispatchLevel
+ )
+/* ++
+
+ Injection completion function for injecting an NBL created using
+ FwpsAllocateNetBufferAndNetBufferList. This function frees up
+ resources allocated during StreamOobReinjectData().
+
+-- */
+{
+ MDL* mdl = (MDL*)context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeNetBufferList(netBufferList);
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+
+ //
+ // The MDL mapped over a pool alloc which we need to free here.
+ //
+
+ ExFreePoolWithTag(
+ mdl->MappedSystemVa,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+}
+
+void
+NTAPI StreamOobInjectCloneCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN dispatchLevel
+ )
+/* ++
+
+ Injection completion function for injecting one of the NBLs cloned
+ via FwpsCloneStreamData.
+
+ FwpsCloneStreamData can return a chain of cloned NBLs; each NBL will
+ complete separately.
+
+-- */
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+}
+
+NTSTATUS
+StreamOobQueueUpIncomingData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ FWPS_STREAM_DATA* streamData
+ )
+/* ++
+
+ This function clones the indicated stream data into a NBL chain and
+ appends the chain at the end of the existing chain (if exists) inside
+ the streamEditor.
+
+ This function assumes that the oobEditInfo lock inside streamEditor is
+ being held.
+
+-- */
+{
+ NTSTATUS status;
+
+ NET_BUFFER_LIST* clonedNetBufferListChain;
+
+ status = FwpsCloneStreamData(
+ streamData,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferListChain
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ //
+ // TCP Fin (EOF) is indicated by an empty NBL with disconnect flag
+ // set, since it does not contain any data we queue it up separately.
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.noMoreData);
+ NT_ASSERT(streamEditor->oobEditInfo.nblEof == NULL);
+ NT_ASSERT(streamData->dataLength == 0);
+
+ streamEditor->oobEditInfo.nblEof = clonedNetBufferListChain;
+
+ status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ if (streamEditor->oobEditInfo.nblTail != NULL)
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblHead != NULL);
+ NT_ASSERT(streamEditor->oobEditInfo.nblTail->Next == NULL);
+
+ streamEditor->oobEditInfo.nblTail->Next = clonedNetBufferListChain;
+ }
+ else
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblHead == NULL);
+
+ streamEditor->oobEditInfo.nblHead = clonedNetBufferListChain;
+ }
+
+ streamEditor->oobEditInfo.nblTail =
+ TailOfNetBufferListChain(clonedNetBufferListChain);
+
+ streamEditor->oobEditInfo.totalDataLength += streamData->dataLength;
+
+ streamEditor->oobEditInfo.streamFlags = streamData->flags;
+
+Exit:
+
+ return status;
+}
+
+void
+StreamOobEdit(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_INCOMING_VALUES* inFixedValues,
+ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ const FWPS_FILTER* filter,
+ _Inout_ FWPS_STREAM_DATA* streamData,
+ _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+/* ++
+
+ This function queues up incoming data and notifies the worker thread
+ to process them. The incoming data is blocked and removed from the
+ stream while data is pending.
+
+ If the editor is shutdown (e.g. during driverUnload) as indicated
+ by OOB_EDIT_SHUT_DOWN state, it permits the indicated data inline after
+ flushing all pended data (to be carried out by the caller).
+
+-- */
+
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ //
+ // A new flow arrives before we finish processing an earlier flow. Production
+ // code should create 1:1 between streamEditor and flow to handle this
+ // condition. See the "MSN Monitor sample" for how that can be implemented.
+ //
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+
+ goto Exit;
+ }
+
+ if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblEof == NULL);
+
+ streamEditor->oobEditInfo.noMoreData = TRUE;
+ }
+
+ //
+ // Record needed flow information etc for data (re-)injection.
+ //
+
+ streamEditor->oobEditInfo.calloutId = filter->action.calloutId;
+ streamEditor->oobEditInfo.flowId = inMetaValues->flowHandle;
+ streamEditor->oobEditInfo.layerId = inFixedValues->layerId;
+
+ switch (streamEditor->oobEditInfo.editState)
+ {
+ case OOB_EDIT_PROCESSING:
+ {
+ if ((streamEditor->oobEditInfo.totalDataLength + streamData->dataLength) >
+ streamEditor->oobEditInfo.busyThreshold)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DEFER;
+ classifyOut->actionType = FWP_ACTION_NONE;
+
+ streamEditor->oobEditInfo.editState = OOB_EDIT_BUSY;
+ }
+ else
+ {
+ status = StreamOobQueueUpIncomingData(
+ streamEditor,
+ streamData
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ else
+ {
+ //
+ // State remains at OOB_EDIT_PROCESSING state. Since the worker thread
+ // is active there is no need to set the event (to wake it up)
+ //
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ break;
+ }
+ case OOB_EDIT_IDLE:
+ {
+ status = StreamOobQueueUpIncomingData(
+ streamEditor,
+ streamData
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ else
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;
+
+ //
+ // The worker thread is idle waiting for more work, now wake it up.
+ //
+ KeSetEvent(
+ &streamEditor->oobEditInfo.editEvent,
+ 0,
+ FALSE
+ );
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ break;
+ }
+ case OOB_EDIT_SHUT_DOWN:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ break;
+ }
+ case OOB_EDIT_ERROR:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ break;
+ }
+ default:
+ NT_ASSERT(FALSE);
+ };
+
+Exit:
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+}
+
+NTSTATUS
+StreamOobQueueUpOutgoingData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN isClone,
+ size_t dataLength,
+ DWORD streamFlags,
+ _In_opt_ MDL* mdl
+ )
+/* ++
+
+ This function queues up processed data (either sections of the indicated
+ data or newly created data) such that they can be (re-)injected back to
+ the data stream during the following context.
+
+ 1. Before FWP_ACTION_BLOCK is returned from the ClassifyFn, or
+ 2. After EOF is indicated.
+
+ Under the conditions above, the incoming data (which we pend) and the
+ outgoing data (which we (re-)inject) can be synchronized properly).
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ KLOCK_QUEUE_HANDLE editLockHandle;
+ OUTGOING_STREAM_DATA* outgoingStreamData;
+
+ outgoingStreamData = (OUTGOING_STREAM_DATA*) ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(OUTGOING_STREAM_DATA),
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+
+ if (outgoingStreamData == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ return status;
+ }
+
+ RtlZeroMemory(outgoingStreamData, sizeof(OUTGOING_STREAM_DATA));
+
+ outgoingStreamData->netBufferList = netBufferList;
+ outgoingStreamData->isClone = isClone;
+ outgoingStreamData->dataLength = dataLength;
+ outgoingStreamData->streamFlags = streamFlags;
+ outgoingStreamData->mdl = mdl;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ InsertTailList(
+ &streamEditor->oobEditInfo.outgoingDataQueue,
+ &outgoingStreamData->listEntry
+ );
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ return status;
+}
+
+NTSTATUS
+StreamOobFlushOutgoingData(
+ _Inout_ STREAM_EDITOR* streamEditor
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ KLOCK_QUEUE_HANDLE editLockHandle;
+ OUTGOING_STREAM_DATA* outgoingStreamData = NULL;
+
+ for(;;)
+ {
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (!IsListEmpty(&streamEditor->oobEditInfo.outgoingDataQueue))
+ {
+ LIST_ENTRY* listEntry =
+ RemoveHeadList(&streamEditor->oobEditInfo.outgoingDataQueue);
+
+ outgoingStreamData = CONTAINING_RECORD(
+ listEntry,
+ OUTGOING_STREAM_DATA,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ if (outgoingStreamData == NULL)
+ {
+ break;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ outgoingStreamData->streamFlags,
+ outgoingStreamData->netBufferList,
+ outgoingStreamData->dataLength,
+ outgoingStreamData->isClone ? StreamOobInjectCloneCompletionFn :
+ StreamOobInjectCompletionFn,
+ outgoingStreamData->mdl
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ ExFreePoolWithTag(
+ outgoingStreamData,
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+
+ outgoingStreamData = NULL;
+ }
+
+Exit:
+
+ if (outgoingStreamData != NULL)
+ {
+ NT_ASSERT(!NT_SUCCESS(status));
+
+ if (outgoingStreamData->isClone)
+ {
+ FwpsDiscardClonedStreamData(
+ outgoingStreamData->netBufferList,
+ 0,
+ FALSE
+ );
+ }
+ else
+ {
+ FwpsFreeNetBufferList(outgoingStreamData->netBufferList);
+
+ if (outgoingStreamData->mdl != NULL)
+ {
+ IoFreeMdl(outgoingStreamData->mdl);
+
+ ExFreePoolWithTag(
+ outgoingStreamData->mdl->MappedSystemVa,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+ }
+
+ ExFreePoolWithTag(
+ outgoingStreamData,
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+StreamOobReinjectData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT32 streamFlags,
+ const void* data,
+ size_t length
+ )
+/* ++
+
+ This function injects a section of the original indicated data back
+ to the data stream.
+
+ An MDL is allocated to describe the data section.
+
+-- */
+{
+ NTSTATUS status;
+
+ void* dataCopy = NULL;
+ MDL* mdl = NULL;
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ dataCopy = ExAllocatePoolWithTag(
+ NonPagedPool,
+ length,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+
+ if (dataCopy == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ RtlCopyMemory(dataCopy, data, length);
+
+ mdl = IoAllocateMdl(
+ dataCopy,
+ (ULONG)length,
+ FALSE,
+ FALSE,
+ NULL
+ );
+ if (mdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ mdl,
+ 0,
+ length,
+ &netBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferList,
+ FALSE,
+ length,
+ streamFlags,
+ mdl
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ dataCopy = NULL;
+ mdl = NULL;
+ netBufferList = NULL;
+
+Exit:
+
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+ if (dataCopy != NULL)
+ {
+ ExFreePoolWithTag(
+ dataCopy,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+ return status;
+}
+
+NTSTATUS
+StreamOobInjectReplacement(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT32 streamFlags,
+ _In_opt_ MDL* data,
+ size_t length
+ )
+/* ++
+
+ This function injects a section of replacement data (in place of data
+ removed from the stream) into the data stream.
+
+ The MDL describes the replacement data is allocated during DriverEntry
+ and does not need to be freed during injection completion.
+
+-- */
+{
+ NTSTATUS status;
+
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ data,
+ 0,
+ length,
+ &netBufferList
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferList,
+ FALSE,
+ length,
+ streamFlags,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ goto Exit;
+ }
+
+ netBufferList = NULL;
+
+Exit:
+
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamOobCopyDataToFlatBuffer(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferListChain,
+ size_t totalDataLength,
+ DWORD streamFlags
+ )
+/* ++
+
+ This function copies the data described by NBL(s) into a flat buffer.
+
+ It reuses the FwpsCopyStreamDataToBuffer API (via StreamCopyDataForInspection)
+ by creating a FWPS_STREAM_DATA struct.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_STREAM_DATA streamData = {0};
+
+ if (totalDataLength > 0)
+ {
+ streamData.netBufferListChain = netBufferListChain;
+ streamData.dataLength = totalDataLength;
+ streamData.flags = streamFlags;
+
+ streamData.dataOffset.netBufferList = netBufferListChain;
+ streamData.dataOffset.netBuffer =
+ NET_BUFFER_LIST_FIRST_NB(streamData.dataOffset.netBufferList);
+ streamData.dataOffset.mdl =
+ NET_BUFFER_CURRENT_MDL(streamData.dataOffset.netBuffer);
+ streamData.dataOffset.mdlOffset =
+ NET_BUFFER_CURRENT_MDL_OFFSET(streamData.dataOffset.netBuffer);
+
+ if (StreamCopyDataForInspection(
+ streamEditor,
+ &streamData
+ ) == FALSE)
+ {
+ status = STATUS_NO_MEMORY;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamOobEditData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferListChain,
+ size_t totalDataLength,
+ DWORD streamFlags
+ )
+/* ++
+
+ This function first copies the stream data into a flat inspection buffer;
+ it then parses the buffer looking for the matching pattern. For
+ non-matching sections it re-injects the data back; for a match it skips
+ over and injects an replacement section.
+
+ If a match can not be determined due to lack of data, it injects the
+ non-matching section back and moves the potential match to the beginning
+ of the inspection buffer.
+
+ When an EOF is reached, it flushes all processed stream sections back
+ and re-injects the FIN back to end the stream.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UINT i = 0;
+ BOOLEAN streamModified = FALSE;
+ BOOLEAN potentialMatch = FALSE;
+
+ BYTE* dataStart;
+
+ UINT findLength = (UINT) strlen(configStringToFind);
+
+ status = StreamOobCopyDataToFlatBuffer(
+ streamEditor,
+ netBufferListChain,
+ totalDataLength,
+ streamFlags
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+
+ for (; i < streamEditor->dataLength; ++i)
+ {
+ if (i + findLength <= streamEditor->dataLength)
+ {
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ findLength
+ ) == findLength)
+ {
+ if (i != 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ i
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset += i;
+ streamEditor->dataLength -= i;
+
+ i = 0;
+ }
+
+ status = StreamOobInjectReplacement(
+ streamEditor,
+ streamFlags,
+ gStringToReplaceMdl,
+ strlen(configStringToReplace)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset += findLength;
+ streamEditor->dataLength -= findLength;
+
+ streamModified = TRUE;
+
+ if (streamEditor->dataLength > 0)
+ {
+ dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+
+ --i;
+
+ continue;
+ }
+ else
+ {
+ streamEditor->dataOffset = 0;
+ }
+ }
+ }
+ else
+ {
+ if (streamEditor->oobEditInfo.noMoreData)
+ {
+ break;
+ }
+
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ streamEditor->dataLength - i
+ ) == streamEditor->dataLength - i)
+ {
+ potentialMatch = TRUE; // this is a partial find
+
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ i
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ RtlMoveMemory(
+ (BYTE*)streamEditor->scratchBuffer,
+ dataStart + i,
+ streamEditor->dataLength - i
+ );
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = streamEditor->dataLength - i;
+
+ break;
+ }
+ }
+ }
+
+ if (streamModified && streamEditor->dataLength > 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ streamEditor->dataLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (!streamModified && !potentialMatch)
+ {
+ if (totalDataLength > 0)
+ {
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferListChain,
+ TRUE,
+ totalDataLength,
+ streamFlags,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ netBufferListChain = NULL;
+ }
+ else if (streamEditor->dataLength > 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ streamEditor->dataLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ status = StreamOobFlushOutgoingData(streamEditor);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ streamFlags | (configInspectionOutbound ? FWPS_STREAM_FLAG_SEND_DISCONNECT :
+ FWPS_STREAM_FLAG_RECEIVE_DISCONNECT),
+ streamEditor->oobEditInfo.nblEof,
+ 0,
+ StreamOobInjectCompletionFn,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->oobEditInfo.nblEof = NULL;
+ streamEditor->oobEditInfo.noMoreData = FALSE;
+ }
+
+Exit:
+
+ if (netBufferListChain != NULL)
+ {
+ FwpsDiscardClonedStreamData(
+ netBufferListChain,
+ 0,
+ FALSE
+ );
+ }
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ FwpsDiscardClonedStreamData(
+ streamEditor->oobEditInfo.nblEof,
+ 0,
+ FALSE
+ );
+
+ streamEditor->oobEditInfo.nblEof = NULL;
+ }
+
+ return status;
+}
+
+_IRQL_requires_same_
+_Function_class_(KSTART_ROUTINE)
+void
+StreamOobEditWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This function waits for an event which gets signalled when there is data
+ waiting to be inspected.
+
+ Once awaken, the worker thread edits the stream until all stream data is
+ processed (and then it waits for more work again).
+
+ When requested to shutdown, it will finish the editing task and enters
+ "shutdown" state.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* netBufferListChain = NULL;
+ size_t totalDataLength;
+ STREAM_EDITOR* streamEditor = (STREAM_EDITOR*)StartContext;
+ DWORD streamFlags;
+
+ for(;;)
+ {
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeWaitForSingleObject(
+ &streamEditor->oobEditInfo.editEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (streamEditor->oobEditInfo.editState == OOB_EDIT_ERROR ||
+ streamEditor->oobEditInfo.editState == OOB_EDIT_SHUT_DOWN)
+ {
+ break;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ NT_ASSERT(streamEditor->oobEditInfo.editState == OOB_EDIT_PROCESSING ||
+ streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY);
+
+ netBufferListChain = streamEditor->oobEditInfo.nblHead;
+ totalDataLength = streamEditor->oobEditInfo.totalDataLength;
+ streamFlags = streamEditor->oobEditInfo.streamFlags;
+
+ streamEditor->oobEditInfo.nblHead = NULL;
+ streamEditor->oobEditInfo.nblTail = NULL;
+ streamEditor->oobEditInfo.totalDataLength = 0;
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ _Analysis_assume_(netBufferListChain != NULL);
+ status = StreamOobEditData(
+ streamEditor,
+ netBufferListChain,
+ totalDataLength,
+ streamFlags
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+ break;
+ }
+
+ if (streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY)
+ {
+ NTSTATUS streamContinueStatus;
+ streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;
+
+ streamContinueStatus = FwpsStreamContinue(
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ streamEditor->oobEditInfo.streamFlags
+ );
+
+ if (!NT_SUCCESS(streamContinueStatus))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+ break;
+ }
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (streamEditor->oobEditInfo.nblHead == NULL)
+ {
+ if (!streamEditor->oobEditInfo.shuttingDown)
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_IDLE;
+ KeClearEvent(&streamEditor->oobEditInfo.editEvent);
+ }
+ else
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+ }
+
+ PsTerminateSystemThread(status);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/* ++
+
+ This is the ClassifyFn function registered by the OOB stream edit callout.
+
+ An OOB stream modification callout blocks all indicated data after cloning
+ them for processing by a kernel mode worker thread (or marshalling the data
+ to user mode for inspection); the resultant/edited data will then be put
+ back to the stream via the stream injection API.
+
+ For such a callout, the processed data must be (re-)injected back to the
+ stream from within the ClassifyFn.
+
+-- */
+{
+ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket;
+ FWPS_STREAM_DATA* streamData;
+
+ UINT findLength = (UINT) strlen(configStringToFind);
+
+ ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)layerData;
+ NT_ASSERT(ioPacket != NULL);
+
+ streamData = ioPacket->streamData;
+ NT_ASSERT(streamData != NULL);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ RtlZeroMemory(classifyOut, sizeof(FWPS_CLASSIFY_OUT));
+
+ //
+ // Let go the traffic that the editor does not care about.
+ //
+
+ if ((configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_RECEIVE)) ||
+ (!configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_SEND)))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ //
+ // In this sample we don't edit TCP urgent data
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_EXPEDITED) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_EXPEDITED))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if ((streamData->dataLength < findLength) &&
+ !(classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
+ ioPacket->countBytesRequired = findLength;
+
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ StreamOobEdit(
+ &gStreamEditor,
+ inFixedValues,
+ inMetaValues,
+ filter,
+ streamData,
+ ioPacket,
+ classifyOut
+ );
+
+ if (classifyOut->actionType == FWP_ACTION_BLOCK ||
+ classifyOut->actionType == FWP_ACTION_PERMIT)
+ {
+ if (!(streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ NTSTATUS status = StreamOobFlushOutgoingData( &gStreamEditor);
+ if (!NT_SUCCESS(status))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ }
+ }
+
+Exit:
+
+ return;
+}
diff --git a/network/trans/stmedit/sys/oob_edit.h b/network/trans/stmedit/sys/oob_edit.h
new file mode 100644
index 00000000..e5a0e506
--- /dev/null
+++ b/network/trans/stmedit/sys/oob_edit.h
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates Out-of-band (OOB) stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _OOB_EDIT_H
+#define _OOB_EDIT_H
+
+typedef enum OOB_EDIT_STATE_
+{
+ OOB_EDIT_IDLE,
+ OOB_EDIT_PROCESSING,
+ OOB_EDIT_BUSY,
+ OOB_EDIT_SHUT_DOWN,
+ OOB_EDIT_ERROR
+} OOB_EDIT_STATE;
+
+typedef struct OUTGOING_STREAM_DATA_
+{
+ LIST_ENTRY listEntry;
+
+ NET_BUFFER_LIST* netBufferList;
+ BOOLEAN isClone;
+ size_t dataLength;
+ DWORD streamFlags;
+ MDL* mdl;
+} OUTGOING_STREAM_DATA;
+
+typedef struct STREAM_EDITOR_ STREAM_EDITOR;
+
+NTSTATUS
+OobEditInit(
+ _Out_ STREAM_EDITOR*
+ );
+
+void
+OobEditShutdown(
+ _Out_ STREAM_EDITOR* streamEditor
+ );
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+
+#endif // _OOB_EDIT_H
diff --git a/network/trans/stmedit/sys/stmedit.inf b/network/trans/stmedit/sys/stmedit.inf
new file mode 100644
index 00000000..1e19c787
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.inf
@@ -0,0 +1,66 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Stream Edit Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = StmEdit.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %StmEditDisk%,,,""
+
+[SourceDisksFiles]
+ StmEdit.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ StmEdit.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %StmEditServiceDesc%
+ CopyFiles = StmEdit.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %StmEditServiceName%,,StmEdit.Service
+
+[DefaultUninstall]
+ DelFiles = StmEdit.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %StmEditServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = StmEdit.DelRegistry
+
+[StmEdit.DriverFiles]
+ StmEdit.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[StmEdit.Service]
+ DisplayName = %StmEditServiceName%
+ Description = %StmEditServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\StmEdit.sys ; %WinDir%\System32\Drivers\StmEdit.sys
+ AddReg = StmEdit.AddRegistry
+
+[StmEdit.AddRegistry]
+ HKR,"Parameters","EditInline",0x00010001,0 ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","StringToFind",0x00000000,"rainy" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","StringToReplace",0x00000000,"sunny" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","InspectionPort",0x00010001,5001 ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","InspectOutbound",0x00010001,0 ; FLG_ADDREG_TYPE_DWORD
+
+[StmEdit.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ StmEditDisk = "Stream Edit Installation Disk"
+ StmEditServiceDesc = "Stream Edit Callout Driver"
+ StmEditServiceName = "StmEdit" \ No newline at end of file
diff --git a/network/trans/stmedit/sys/stmedit.vcxproj b/network/trans/stmedit/sys/stmedit.vcxproj
new file mode 100644
index 00000000..bc3ef00b
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.vcxproj
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{98513F1C-C28D-4F03-99A8-88FD4BD707C7}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{72C54687-6A7C-47CA-9E90-E2D689DC07FF}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="inline_edit.c" />
+ <ClCompile Include="oob_edit.c" />
+ <ClCompile Include="stream_callout.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/stmedit/sys/stmedit.vcxproj.Filters b/network/trans/stmedit/sys/stmedit.vcxproj.Filters
new file mode 100644
index 00000000..54528237
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.vcxproj.Filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{C9744BA5-8ED9-44CA-83D6-EFDEDA84812B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{2B1C683F-EF24-453C-B303-9CAE8061F7C3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{FF447D8A-41FE-4980-B0AE-27782414E0C0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A061D6F2-D701-4D44-9CAB-055FBD8E95A9}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="inline_edit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="oob_edit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stream_callout.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/stmedit/sys/stream_callout.c b/network/trans/stmedit/sys/stream_callout.c
new file mode 100644
index 00000000..7816c46d
--- /dev/null
+++ b/network/trans/stmedit/sys/stream_callout.c
@@ -0,0 +1,772 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates finding and replacing a string pattern from a
+ live TCP stream via the WFP stream API.
+
+ The driver can function in one of the two modes --
+
+ o Inline Editing where all modification is carried out within the
+ WFP ClassifyFn callout function.
+
+ o Out-of-band (OOB) Editing where all modification is done by a
+ worker thread. (this is the default)
+
+ The mode setting, along with other inspection parameters are configurable
+ via the following registry values
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\stmedit\Parameters
+
+ o StringToFind (REG_SZ, default = "rainy")
+ o StringToReplace (REG_SZ, default = "sunny")
+ o InspectionPort (REG_DWORD, default = 5001)
+ o InspectOutbound (REG_DWORD, default = 0)
+ o EditInline (REG_DWORD, default = 0)
+
+ The sample is IP version agnostic. It performs inspection on both IPv4 and
+ IPv6 data streams.
+
+ Before experimenting with the sample, please be sure to add an exception for
+ the InspectionPort configured to the firewall.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntifs.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+//
+// Configurable parameters
+//
+
+USHORT configInspectionPort = 5001;
+BOOLEAN configInspectionOutbound = FALSE;
+BOOLEAN configEditInline = FALSE;
+
+CHAR configStringToFind[128] = "rainy";
+CHAR configStringToReplace[128] = "sunny";
+
+//
+// Callout driver keys
+//
+
+// e6011cdc-440b-4a6f-8499-6fdb55fb1f92
+DEFINE_GUID(
+ STREAM_EDITOR_STREAM_CALLOUT_V4,
+ 0xe6011cdc,
+ 0x440b,
+ 0x4a6f,
+ 0x84, 0x99, 0x6f, 0xdb, 0x55, 0xfb, 0x1f, 0x92
+);
+// c0bc07b4-aaf6-4242-a3dc-3ef341ffde5d
+DEFINE_GUID(
+ STREAM_EDITOR_STREAM_CALLOUT_V6,
+ 0xc0bc07b4,
+ 0xaaf6,
+ 0x4242,
+ 0xa3, 0xdc, 0x3e, 0xf3, 0x41, 0xff, 0xde, 0x5d
+);
+
+//
+// Callout driver global variables
+//
+
+MDL* gStringToReplaceMdl;
+
+STREAM_EDITOR gStreamEditor;
+
+HANDLE gEngineHandle;
+UINT32 gCalloutIdV4;
+UINT32 gCalloutIdV6;
+
+DEVICE_OBJECT* gWdmDevice;
+
+HANDLE gInjectionHandle;
+
+NDIS_GENERIC_OBJECT* gNdisGenericObj;
+NDIS_HANDLE gNetBufferListPool;
+
+#define STREAM_EDITOR_NDIS_OBJ_TAG 'oneS'
+#define STREAM_EDITOR_NBL_POOL_TAG 'pneS'
+#define STREAM_EDITOR_FLAT_BUFFER_TAG 'bfeS'
+
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD StreamEditEvtDriverUnload;
+
+NTSTATUS
+StreamEditNotify(
+ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ const GUID* filterKey,
+ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RegisterCalloutForLayer(
+ const GUID* layerKey,
+ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept TCP
+ traffic at WFP FWPM_LAYER_STREAM_V4 or FWPM_LAYER_STREAM_V6 layer.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+
+ FWPM_FILTER filter = {0};
+ FWPM_FILTER_CONDITION filterConditions[1] = {0};
+
+ FWPM_CALLOUT mCallout = {0};
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = (configEditInline ? StreamInlineEditClassify :
+ StreamOobEditClassify);
+ sCallout.notifyFn = StreamEditNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Stream Edit Callout";
+ displayData.description = L"Callout that finds and replaces a token from a TCP stream";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ filter.layerKey = *layerKey;
+ filter.displayData.name = L"Stream Edit Filter";
+ filter.displayData.description = L"Filter that finds and replaces a token from a TCP stream";
+
+ filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
+ filter.action.calloutKey = *calloutKey;
+ filter.filterCondition = filterConditions;
+ filter.numFilterConditions = 1;
+ filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filterConditions[0].fieldKey = (configInspectionOutbound ? FWPM_CONDITION_IP_REMOTE_PORT :
+ FWPM_CONDITION_IP_LOCAL_PORT);
+ filterConditions[0].matchType = FWP_MATCH_EQUAL;
+ filterConditions[0].conditionValue.type = FWP_UINT16;
+ filterConditions[0].conditionValue.uint16 = configInspectionPort;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamEditRegisterCallout(
+ const STREAM_EDITOR* streamEditor,
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept
+ TCP traffic at WFP FWPM_LAYER_STREAM_V4 and FWPM_LAYER_STREAM_V6
+ layer.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ BOOLEAN engineOpened = FALSE;
+ BOOLEAN inTransaction = FALSE;
+
+ FWPM_SESSION session = {0};
+
+ UNREFERENCED_PARAMETER(streamEditor);
+
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ status = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &gEngineHandle
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ engineOpened = TRUE;
+
+ status = FwpmTransactionBegin(gEngineHandle, 0);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = TRUE;
+
+ status = RegisterCalloutForLayer(
+ &FWPM_LAYER_STREAM_V4,
+ &STREAM_EDITOR_STREAM_CALLOUT_V4,
+ deviceObject,
+ &gCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = RegisterCalloutForLayer(
+ &FWPM_LAYER_STREAM_V6,
+ &STREAM_EDITOR_STREAM_CALLOUT_V6,
+ deviceObject,
+ &gCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = FwpmTransactionCommit(gEngineHandle);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = FALSE;
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (inTransaction)
+ {
+ NTSTATUS abortStatus;
+ abortStatus = FwpmTransactionAbort(gEngineHandle);
+ _Analysis_assume_(NT_SUCCESS(abortStatus));
+ }
+ if (engineOpened)
+ {
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+void
+StreamEditUnregisterCallout(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gCalloutIdV6);
+ FwpsCalloutUnregisterById(gCalloutIdV4);
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+StreamEditEvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ if (!configEditInline)
+ {
+ OobEditShutdown(&gStreamEditor);
+ }
+
+ if (gStreamEditor.scratchBuffer != NULL)
+ {
+ ExFreePoolWithTag(
+ gStreamEditor.scratchBuffer,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ }
+
+ StreamEditUnregisterCallout();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+
+ NdisFreeNetBufferListPool(gNetBufferListPool);
+ NdisFreeGenericObject(gNdisGenericObj);
+
+ IoFreeMdl(gStringToReplaceMdl);
+}
+
+NTSTATUS
+StreamEditLoadConfig(
+ const WDFKEY key
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ DECLARE_CONST_UNICODE_STRING(stringToFindKey, L"StringToFind");
+ DECLARE_CONST_UNICODE_STRING(stringToReplaceKey, L"StringToReplace");
+ DECLARE_CONST_UNICODE_STRING(inspectionPortKey, L"InspectionPort");
+ DECLARE_CONST_UNICODE_STRING(editInlineKey, L"EditInline");
+ DECLARE_CONST_UNICODE_STRING(inspectOutboundKey, L"InspectOutbound");
+
+ UNICODE_STRING stringValue;
+ WCHAR buffer[128];
+ USHORT requiredSize;
+ ULONG valueSize;
+ ULONG ulongValue;
+
+ stringValue.Buffer = buffer;
+ stringValue.Length = 0;
+ stringValue.MaximumLength = sizeof(buffer) - sizeof(buffer[0]);
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryUnicodeString(
+ key,
+ &stringToFindKey,
+ &requiredSize,
+ &stringValue
+ )))
+ {
+ stringValue.Buffer[stringValue.Length/sizeof(stringValue.Buffer[0])] =
+ UNICODE_NULL;
+
+ status = RtlUnicodeToMultiByteN(
+ configStringToFind,
+ sizeof(configStringToFind) - 1,
+ &valueSize,
+ stringValue.Buffer,
+ (ULONG)requiredSize
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ configStringToFind[valueSize] = '\0';
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryUnicodeString(
+ key,
+ &stringToReplaceKey,
+ &requiredSize,
+ &stringValue
+ )))
+ {
+ status = RtlUnicodeToMultiByteN(
+ configStringToReplace,
+ sizeof(configStringToReplace) - 1,
+ &valueSize,
+ stringValue.Buffer,
+ (ULONG)requiredSize
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ configStringToReplace[valueSize] = '\0';
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &inspectionPortKey,
+ &ulongValue
+ )))
+ {
+ configInspectionPort = (USHORT) ulongValue;
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &editInlineKey,
+ &ulongValue
+ )))
+ {
+ configEditInline = (ulongValue != 0);
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &inspectOutboundKey,
+ &ulongValue
+ )))
+ {
+ configInspectionOutbound = (ulongValue != 0);
+ }
+
+Exit:
+ return status;
+}
+
+NTSTATUS
+StreamEditInitDriverObjects(
+ _Inout_ DRIVER_OBJECT* driverObject,
+ const UNICODE_STRING* registryPath,
+ _Out_ WDFDRIVER* pDriver,
+ _Out_ WDFDEVICE* pDevice
+ )
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = StreamEditEvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ pDriver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(*pDriver, &SDDL_DEVOBJ_KERNEL_ONLY);
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WdfDeviceInitSetCharacteristics(pInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, TRUE);
+ status = WdfDeviceCreate(&pInit, WDF_NO_OBJECT_ATTRIBUTES, pDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ WdfDeviceInitFree(pInit);
+ goto Exit;
+ }
+
+ WdfControlFinishInitializing(*pDevice);
+
+Exit:
+ return status;
+}
+
+NTSTATUS
+DriverEntry(
+ DRIVER_OBJECT* driverObject,
+ UNICODE_STRING* registryPath
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ WDFDRIVER driver;
+ WDFKEY configKey;
+ NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParams = {0};
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = StreamEditInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = StreamEditLoadConfig(configKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ gStringToReplaceMdl = IoAllocateMdl(
+ configStringToReplace,
+ (ULONG) strlen(configStringToReplace),
+ FALSE,
+ FALSE,
+ NULL
+ );
+ if (gStringToReplaceMdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(gStringToReplaceMdl);
+
+ gNdisGenericObj = NdisAllocateGenericObject(
+ driverObject,
+ STREAM_EDITOR_NDIS_OBJ_TAG,
+ 0
+ );
+
+ if (gNdisGenericObj == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ nblPoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ nblPoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ nblPoolParams.Header.Size = sizeof(nblPoolParams);
+
+ nblPoolParams.fAllocateNetBuffer = TRUE;
+ nblPoolParams.DataSize = 0;
+
+ nblPoolParams.PoolTag = STREAM_EDITOR_NBL_POOL_TAG;
+
+ gNetBufferListPool = NdisAllocateNetBufferListPool(
+ gNdisGenericObj,
+ &nblPoolParams
+ );
+
+ if (gNetBufferListPool == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_STREAM,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = StreamEditRegisterCallout(
+ &gStreamEditor,
+ gWdmDevice
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (configEditInline)
+ {
+ InlineEditInit(&gStreamEditor);
+ }
+ else
+ {
+
+ status = OobEditInit(&gStreamEditor);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (gEngineHandle != NULL)
+ {
+ StreamEditUnregisterCallout();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ if (gNetBufferListPool != NULL)
+ {
+ NdisFreeNetBufferListPool(gNetBufferListPool);
+ }
+ if (gNdisGenericObj != NULL)
+ {
+ NdisFreeGenericObject(gNdisGenericObj);
+ }
+ if (gStringToReplaceMdl != NULL)
+ {
+ IoFreeMdl(gStringToReplaceMdl);
+ }
+ }
+
+ return status;
+}
+
+BOOLEAN
+StreamCopyDataForInspection(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_STREAM_DATA* streamData
+ )
+/* ++
+
+ This function copies stream data described by the FWPS_STREAM_DATA
+ structure into a flat buffer.
+
+-- */
+
+{
+ SIZE_T bytesCopied;
+
+ size_t existingDataLength = streamEditor->dataLength;
+ NT_ASSERT(streamEditor->dataOffset == 0);
+ if (streamEditor->bufferSize - existingDataLength < streamData->dataLength)
+ {
+ size_t newBufferSize = (streamData->dataLength + existingDataLength) * 2;
+ void* newBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ newBufferSize,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ if (newBuffer != NULL)
+ {
+ if (existingDataLength > 0)
+ {
+ NT_ASSERT(streamEditor->scratchBuffer != NULL);
+ RtlCopyMemory(
+ newBuffer,
+ streamEditor->scratchBuffer,
+ existingDataLength
+ );
+ }
+ }
+
+ if (streamEditor->scratchBuffer != NULL)
+ {
+ ExFreePoolWithTag(
+ streamEditor->scratchBuffer,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ streamEditor->scratchBuffer = NULL;
+ streamEditor->bufferSize = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (newBuffer != NULL)
+ {
+ streamEditor->scratchBuffer = newBuffer;
+ streamEditor->bufferSize = newBufferSize;
+ streamEditor->dataLength = existingDataLength;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ FwpsCopyStreamDataToBuffer(
+ streamData,
+ (BYTE*)streamEditor->scratchBuffer + streamEditor->dataLength,
+ streamData->dataLength,
+ &bytesCopied
+ );
+
+ NT_ASSERT(bytesCopied == streamData->dataLength);
+
+ streamEditor->dataLength += bytesCopied;
+
+ return TRUE;
+}
diff --git a/network/trans/stmedit/sys/stream_callout.h b/network/trans/stmedit/sys/stream_callout.h
new file mode 100644
index 00000000..7fff047f
--- /dev/null
+++ b/network/trans/stmedit/sys/stream_callout.h
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates finding and replacing a string pattern from a
+ live TCP stream via the WFP stream API.
+
+--*/
+
+#ifndef _STREAM_CALLOUT_H
+#define _STREAM_CALLOUT_H
+
+extern MDL* gStringToReplaceMdl;
+extern HANDLE gInjectionHandle;
+extern NDIS_HANDLE gNetBufferListPool;
+extern STREAM_EDITOR gStreamEditor;
+
+//
+// Configurable parameters
+//
+
+extern USHORT configInspectionPort;
+extern BOOLEAN configInspectionOutbound;
+extern BOOLEAN configEditInline;
+
+extern CHAR configStringToFind[];
+extern CHAR configStringToReplace[];
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+typedef struct STREAM_EDITOR_
+{
+ BOOLEAN editInline;
+
+ union
+ {
+ INLINE_EDIT_STATE inlineEditState;
+ struct
+ {
+ OOB_EDIT_STATE editState;
+ BOOLEAN shuttingDown;
+
+ KSPIN_LOCK editLock;
+ NET_BUFFER_LIST* nblHead;
+ NET_BUFFER_LIST* nblTail;
+ size_t totalDataLength;
+ BOOLEAN noMoreData;
+ NET_BUFFER_LIST* nblEof;
+ size_t busyThreshold;
+ UINT64 flowId;
+ UINT32 calloutId;
+ UINT16 layerId;
+ DWORD streamFlags;
+ KEVENT editEvent;
+ LIST_ENTRY outgoingDataQueue;
+ } oobEditInfo;
+ };
+
+ void* scratchBuffer;
+ size_t bufferSize;
+ size_t dataOffset;
+ size_t dataLength;
+
+}STREAM_EDITOR;
+
+#pragma warning(pop)
+
+BOOLEAN
+StreamCopyDataForInspection(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_STREAM_DATA* streamData
+ );
+
+#endif // _STREAM_CALLOUT_H
diff --git a/network/wlan/ReadMe.md b/network/wlan/ReadMe.md
new file mode 100644
index 00000000..a90b2a5b
--- /dev/null
+++ b/network/wlan/ReadMe.md
@@ -0,0 +1,91 @@
+Native Wifi IHV Service
+=======================
+
+This sample code demonstrates IHV extensibility for Native WiFi.
+
+In particular, this sample contains the following features:
+
+- IHV profile validation
+- IHV discovery profile creation
+- IHV extension for interactive UI and Profile UI
+- 802.1x extension
+
+The sample, after you compile and install it, enables you to connect to an Open WEP Network by using 802.1X through IHV Service extension.
+
+Run the sample
+--------------
+
+The fully compiled sample consists of two DLLs: IHVSample.dll and IHVSampleUI.dll. The functions of those DLLs are outlined below:
+
+### IHVSample.dll
+
+The IHVSample DLL supports connecting to a wireless network by using Open authentication and WEP encryption. The sample is capable of connecting to an 802.1X network and a non-802.1X network.
+
+During the discovery phase, the sample generates a temporary profile that the operating system uses to establish a wireless connection. The operating system requests that the IHV provide a temporary profile to use when trying to connect through Discovery. In this case, IHVSample returns a list of usable profiles for connecting by using open-WEP with and without 802.1X. The RC4 algorithm is implemented in a DLL that is provided as part of the sample.
+
+The sample is loaded by the IHV process and uses the public interfaces that are provided by the same process. The IHV process host initializes IHVSample in its process.
+
+The sample gets called to perform pre-associate security and post-associate security. The sample does not implement any of the pre-associate security. For the post-associate security, in the case of open-WEP without 802.1X, IHVSample prompts for UI in case the profile does not exist or does not already have a valid key. In the case of 802.1X networks, the post-associate security portion sets the driver packet exemptions, starts up the Microsoft 802.1X module authentication, and waits for the result that indicates a success or a failure. During this period, IHVSample forwards all 802.1X packets to the IHV process. However, it caches the EAPOL key packets. In either case, after the key is obtained, IHVSample sends it to the driver and establishes the connection.
+
+The operating system validates network profiles before they can be applied and persisted. The operating system performs validation of the non-IHV portion of the profile and passes the rest of data to IHVSample if IHV settings exist. IHVSample does limited XML schema validation.
+
+### UI Sample (IHVSampleUI.dll)
+
+The IHVSampleUI DLL extends the Wireless Profile UI to display IHV connectivity and security information. The security information that is displayed is for both security types based on IHV proprietary security and those based on Microsoft 802.1X. The sample adds custom IHV authentication and encryption types to illustrate the different ways the various types can be embedded in the UI. The configuration UI saves the IHV portion of the profile in accordance with the IHV schema. The sample pages that enable modification of the IHV parameters are displayed from the configuration UI. The sample also displays a wizard-based connection time UI with three sample pages. This connection time UI integrates in both the wizard and non-wizard flows.
+
+Installation
+------------
+
+After the sample is compiled, you must copy the binaries on to the target system and associate them with the matching Native Wifi-capable adapter. You can copy the binaries by adding an appropriate **CopyFiles** directive in the **DDInstall** section in the INF file for installing the adapter. You can associate the binaries by adding an appropriate **AddReg** directive in the **DDInstall** section in the INF file for installing the adapter.
+
+### CopyFiles Directive
+
+The CopyFiles Directive should name a File-List-Section. The contents of this section should have the following:
+
+IHVSpecifiedDLLName,,,2
+
+IHVSpecifiedOtherFile,,,2
+
+There should be an associated entry in the DestinationDirs section that specifies the destination to copy the file to. This section should have a directive like one of the following:
+
+File-List-Section= 11 ; \\system32 directory
+
+DefaultDestDir= 11 ; \\system32 directory
+
+### AddReg Directive
+
+The AddReg directive should name an Add-Registry-Section.
+
+The contents of the Miniport INF file must include the following, in order for the correct IHV Service to be started:
+
+- HKR,Ndi\\IHVExtensions, ExtensibilityDLL,0,"%SystemRoot%\\system32\\IhvExt.dll"
+
+ This registry key is used to determine the location of the IHVSample.dll.
+
+- HKR,Ndi\\IHVExtensions,UIExtensibilityCLSID,0, "\<CLSID\>"
+
+ This registry key is used to determine the class ID of the COM interface that extends the 802.11 configuration UI.
+
+- HKR,Ndi\\IHVExtensions,GroupName,0, "IHV provided group name"
+- HKR,Ndi\\IHVExtensions, AdapterOUI, 0x00010001, 0x00123456
+
+ This registry key is used to verify the OUI when the profile is applied to the adapter. If the AdapterOUI value is 0x??123456 in the registry, it needs to look like the following in the profile:
+
+ \<OUIHeader\>
+
+ \<OUI\>123456\</OUI\>
+
+ \<type\>??\</type\>
+
+ \</OUHeader\>
+
+ Note that ?? stands for bits ignored.
+
+- HKR,Ndi\\IHVExtensions, DiagnosticsID,0, "\<Diagnostics ID GUID\>"
+
+### Uninstallation Instructions
+
+To uninstall this sample, you must undo the AddReg directive and undo the CopyFiles directive.
+
+For more information about creating a Native Wi-Fi package, see [Native 802.11 Wireless LAN](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560690).
+
diff --git a/network/wlan/ihvsample/adapters.cpp b/network/wlan/ihvsample/adapters.cpp
new file mode 100644
index 00000000..919e47a6
--- /dev/null
+++ b/network/wlan/ihvsample/adapters.cpp
@@ -0,0 +1,439 @@
+/*++
+
+Copyright (c) 2005 Microsoft Corporation
+
+Abstract:
+
+ Sample IHV Extensibility DLL to extend
+ 802.11 LWF driver for third party protocols.
+
+
+--*/
+
+#include "precomp.h"
+
+LIST_ENTRY g_AdaptersList = {0};
+
+
+
+//
+// Copied Macros from wdm.h
+//
+
+#define CONTAINING_RECORD(address, type, field) ((type *)( \
+ (PCHAR)(address) - \
+ (ULONG_PTR)(&((type *)0)->field)))
+
+
+#define InitializeListHead(ListHead) (\
+ (ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+
+
+#define RemoveEntryList(Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_Flink;\
+ _EX_Flink = (Entry)->Flink;\
+ _EX_Blink = (Entry)->Blink;\
+ _EX_Blink->Flink = _EX_Flink;\
+ _EX_Flink->Blink = _EX_Blink;\
+ }
+
+
+#define InsertTailList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Blink = _EX_ListHead->Blink;\
+ (Entry)->Flink = _EX_ListHead;\
+ (Entry)->Blink = _EX_Blink;\
+ _EX_Blink->Flink = (Entry);\
+ _EX_ListHead->Blink = (Entry);\
+ }
+
+
+
+
+//
+// Initialize the AdapterList data structure.
+//
+VOID
+InitAdapterDetailsList
+(
+ VOID
+)
+{
+ EnterCriticalSection( &g_csSynch );
+
+ // Assuming that memory in g_AdaptersList
+ // could be garbage - just initialize the
+ // fields appropriately.
+
+ InitializeListHead( &g_AdaptersList );
+
+ LeaveCriticalSection( &g_csSynch );
+
+ return;
+}
+
+
+
+
+//
+// Free the AdapterList data structure - contention is not supported.
+//
+VOID
+DeinitAdapterDetailsList
+(
+ VOID
+)
+{
+ EnterCriticalSection( &g_csSynch );
+
+ // ASSERT that the list is empty. The call
+ // to InitializeListHead is not really required
+ // if the following conditions are true.
+ ASSERT(g_AdaptersList.Flink == &g_AdaptersList );
+ ASSERT(g_AdaptersList.Blink == &g_AdaptersList );
+
+ // clear the memory any way.
+ InitializeListHead( &g_AdaptersList );
+
+ LeaveCriticalSection( &g_csSynch );
+
+ return;
+}
+
+
+
+
+
+//
+// Add a single adapter to the list. Starting refcount is one.
+//
+DWORD
+InitAdapterDetails
+(
+ HANDLE hDot11SvcHandle,
+ PHANDLE phIhvExtAdapter
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ HANDLE hIhvExtAdapter = NULL;
+
+
+ // acquire global lock.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // verify state. this check prevents new adapters from
+ // being added when service is being deinited.
+ if (!g_bAllowInit)
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // allocate memory.
+ pAdapterDetails = (PADAPTER_DETAILS) PrivateMemoryAlloc( sizeof( ADAPTER_DETAILS ) );
+ if ( !pAdapterDetails )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // add the new object to the list. if anything fails
+ // in this function the object would be automatically
+ // dereferenced and removed from the list.
+ InsertTailList( &g_AdaptersList, &(pAdapterDetails->Link) );
+
+ // initialize fields that are used by object lifetime management.
+ hIhvExtAdapter = (HANDLE) &(pAdapterDetails->Link);
+ pAdapterDetails->dwRefCount = 1;
+ pAdapterDetails->hDot11SvcHandle = hDot11SvcHandle;
+ pAdapterDetails->NicState = nic_state_initialized;
+
+
+ // Event that gets triggered
+ // once UI response is received.
+ pAdapterDetails->hUIResponse =
+ CreateEvent
+ (
+ NULL,
+ FALSE, // Auto Reset
+ FALSE, // Start in non-signaled state.
+ NULL
+ );
+ if ( !(pAdapterDetails->hUIResponse) )
+ {
+ dwResult = GetLastError( );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+
+ // fill out-params. release responsibility to
+ // for deiniting object to caller.
+ (*phIhvExtAdapter) = hIhvExtAdapter;
+ hIhvExtAdapter = NULL;
+
+error:
+ if ( hIhvExtAdapter )
+ {
+ // something failed after adding the object to
+ // the global list. so it needs to be removed.
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ // leave global lock.
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+
+//
+// Add a reference to a particular adapter and find the pointer to the context.
+//
+DWORD
+ReferenceAdapterDetails
+(
+ HANDLE hIhvExtAdapter,
+ PADAPTER_DETAILS* ppAdapterDetails
+)
+{
+ DWORD dwResult = ERROR_NOT_FOUND;
+ BOOL bLocked = FALSE;
+ PLIST_ENTRY pEntry = NULL;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+ ASSERT( ppAdapterDetails );
+
+ // acquire global lock.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+
+ // search the global list of adapters for a match.
+ for
+ (
+ pEntry = g_AdaptersList.Flink;
+ pEntry != &g_AdaptersList;
+ pEntry = pEntry->Flink
+ )
+ {
+ // Get the adapter data structure for current entry.
+ pAdapterDetails = CONTAINING_RECORD( pEntry, ADAPTER_DETAILS, Link );
+ ASSERT( pAdapterDetails );
+
+ // conditions could be converted to an ASSERT.
+ if
+ (
+ ( pAdapterDetails->NicState == nic_state_uninitialized ) ||
+ ( pAdapterDetails->NicState >= nic_state_max )
+ )
+ {
+ ASSERTFAILURE();
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // if match found - bail with success.
+ if ( hIhvExtAdapter == ((HANDLE) pEntry) )
+ {
+ (pAdapterDetails->dwRefCount)++;
+ (*ppAdapterDetails) = pAdapterDetails;
+
+ dwResult = ERROR_SUCCESS;
+ BAIL( );
+ }
+ }
+
+error:
+ if ( bLocked )
+ {
+ // release global lock.
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+//
+// Find adapter context pointer using UI request GUID.
+//
+DWORD
+ReferenceAdapterDetailsByUIRequestGuid
+(
+ GUID* pguidUIRequest,
+ PADAPTER_DETAILS* ppAdapterDetails,
+ HANDLE* phIhvExtAdapter
+)
+{
+ DWORD dwResult = ERROR_NOT_FOUND;
+ BOOL bLocked = FALSE;
+ PLIST_ENTRY pEntry = NULL;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+ ASSERT( ppAdapterDetails );
+ ASSERT( phIhvExtAdapter );
+
+ // acquire global lock.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // look for adapter with matching ui request guid in the global list.
+ for
+ (
+ pEntry = g_AdaptersList.Flink;
+ pEntry != &g_AdaptersList;
+ pEntry = pEntry->Flink
+ )
+ {
+ // get the current adapter's context info.
+ pAdapterDetails = CONTAINING_RECORD( pEntry, ADAPTER_DETAILS, Link );
+ ASSERT( pAdapterDetails );
+
+ // could be an ASSERT.
+ if
+ (
+ ( pAdapterDetails->NicState == nic_state_uninitialized ) ||
+ ( pAdapterDetails->NicState >= nic_state_max )
+ )
+ {
+ ASSERTFAILURE();
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // if match found, bail with success.
+ if ( pAdapterDetails->currentGuidUIRequest == (*pguidUIRequest) )
+ {
+ (pAdapterDetails->dwRefCount)++;
+ (*ppAdapterDetails) = pAdapterDetails;
+ (*phIhvExtAdapter) = (HANDLE) pEntry;
+
+ dwResult = ERROR_SUCCESS;
+ BAIL( );
+ }
+ }
+
+error:
+ if ( bLocked )
+ {
+ // leave global lock.
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+
+//
+// Dereference an adapter - resources will be freed when the refcount
+// goes to zero.
+//
+VOID
+DerefenceAdapterDetails
+(
+ HANDLE hIhvExtAdapter
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ BOOL bOk = TRUE;
+
+
+ // acquire global lock.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // trying to reference the adapter. the part of the
+ // code that increments the refcount is not useful
+ // here, we are only using the algorithm to find
+ // the context pointer. the refcount would be decremented
+ // after the function call if the call succeeds.
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ ASSERT( pAdapterDetails );
+
+ // Undoing the refcount increment in the previous call.
+ (pAdapterDetails->dwRefCount)--;
+
+ // could be an ASSERT - the adapter
+ // context should not be in this state.
+ if ( 0 == pAdapterDetails->dwRefCount )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // performing the intended dereferencing.
+ (pAdapterDetails->dwRefCount)--;
+
+ // checking if the adapter entry can go.
+ if ( pAdapterDetails->dwRefCount )
+ {
+ BAIL( );
+ }
+
+ // Since this was the last reference,
+ // it is time to deinitialize the memory.
+
+ // remove the adapter from the global list.
+ RemoveEntryList( &(pAdapterDetails->Link) );
+
+ // Close handle to the UI response event.
+ if ( pAdapterDetails->hUIResponse )
+ {
+ bOk = CloseHandle( pAdapterDetails->hUIResponse );
+ ASSERT( bOk );
+ }
+
+ // free the UI response memory.
+ if ( pAdapterDetails->pbResponse )
+ {
+ PrivateMemoryFree( pAdapterDetails->pbResponse );
+ pAdapterDetails->pbResponse = NULL;
+ }
+
+ // frees the connection specific data in the adapter data structure.
+ FreeOnexData( &(pAdapterDetails->pOnexData) );
+
+ // frees the profiles.
+ FreeIhvConnectivityProfile( &(pAdapterDetails->pConnectivityProfile) );
+ FreeIhvSecurityProfile( &(pAdapterDetails->pSecurityProfile) );
+
+ // frees the context.
+ SecureZeroMemory( pAdapterDetails, sizeof( ADAPTER_DETAILS ) );
+ PrivateMemoryFree( pAdapterDetails );
+
+error:
+ if ( bLocked )
+ {
+ // release global lock.
+ LeaveCriticalSection( &g_csSynch );
+ }
+ ASSERT( ERROR_SUCCESS == dwResult );
+ return;
+}
+
diff --git a/network/wlan/ihvsample/adapters.h b/network/wlan/ihvsample/adapters.h
new file mode 100644
index 00000000..ad0f9779
--- /dev/null
+++ b/network/wlan/ihvsample/adapters.h
@@ -0,0 +1,125 @@
+
+
+
+//
+// Different states of current NIC.
+//
+typedef
+enum _NIC_STATE
+{
+ nic_state_uninitialized,
+ nic_state_initialized,
+ nic_state_pre_assoc_started,
+ nic_state_pre_assoc_ended,
+ nic_state_post_assoc_started,
+ nic_state_onex_in_progress,
+ nic_state_post_assoc_ended,
+
+ nic_state_max // should be the last one.
+}
+NIC_STATE, *PNIC_STATE;
+
+
+//////////////////////////////////
+// Adapter lifetime management //
+//////////////////////////////////
+
+//
+// Adapter Data Structure
+//
+
+struct _ADAPTER_DETAILS
+{
+ // Adapter list and lifetime management.
+ LIST_ENTRY Link;
+ DWORD dwRefCount;
+ NIC_STATE NicState;
+
+
+ // Framework reference.
+ HANDLE hDot11SvcHandle;
+
+ // Handler functions for different stages of connection.
+ LPTHREAD_START_ROUTINE pPerformPostAssociateCompletionRoutine;
+ POST_ASSOCIATE_FUNCTION pPerformPostAssociateRoutine;
+ STOP_POST_ASSOCIATE_FUNCTION pStopPostAssociateRoutine;
+
+
+ // Data for current connection.
+ HANDLE hConnectSession;
+ BOOL bModifyCurrentProfile;
+ PONEX_DATA pOnexData;
+ GUID currentGuidUIRequest;
+ DWORD dwResponseLen;
+ _Field_size_bytes_(dwResponseLen) BYTE* pbResponse;
+ HANDLE hUIResponse;
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile;
+ PIHV_SECURITY_PROFILE pSecurityProfile;
+};
+
+
+
+//
+// Initialize the AdapterList data structure.
+//
+VOID
+InitAdapterDetailsList
+(
+ VOID
+);
+
+
+//
+// Free the AdapterList data structure - contention is not supported.
+//
+VOID
+DeinitAdapterDetailsList
+(
+ VOID
+);
+
+//
+// Add a single adapter to the list. Starting refcount is one.
+//
+DWORD
+InitAdapterDetails
+(
+ HANDLE hDot11SvcHandle,
+ PHANDLE phIhvExtAdapter
+);
+
+
+//
+// Add a reference to a particular adapter and find the pointer to the context.
+//
+DWORD
+ReferenceAdapterDetails
+(
+ HANDLE hIhvExtAdapter,
+ PADAPTER_DETAILS* ppAdapterDetails
+);
+
+
+//
+// Find adapter context pointer using UI request GUID.
+//
+DWORD
+ReferenceAdapterDetailsByUIRequestGuid
+(
+ GUID* pguidUIRequest,
+ PADAPTER_DETAILS* ppAdapterDetails,
+ HANDLE* phIhvExtAdapter
+);
+
+
+
+//
+// Dereference an adapter - resources will be freed when the refcount
+// goes to zero.
+//
+VOID
+DerefenceAdapterDetails
+(
+ HANDLE hIhvExtAdapter
+);
+
diff --git a/network/wlan/ihvsample/ihv1xext.xml b/network/wlan/ihvsample/ihv1xext.xml
new file mode 100644
index 00000000..77ae471f
--- /dev/null
+++ b/network/wlan/ihvsample/ihv1xext.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihv1xext</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>manual</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvconn.xml b/network/wlan/ihvsample/ihvconn.xml
new file mode 100644
index 00000000..0bb09694
--- /dev/null
+++ b/network/wlan/ihvsample/ihvconn.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvconn</name>
+
+ <SSIDConfig>
+ <SSID>
+ <name>_SSID_</name>
+ </SSID>
+ </SSIDConfig>
+
+ <connectionType>ESS</connectionType>
+ <connectionMode>manual</connectionMode>
+
+ <MSM>
+ <connectivity>
+
+ </connectivity>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ </authEncryption>
+ </security>
+
+
+ </MSM>
+
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+
+ <IHVConnectivityParam2>wrongkey</IHVConnectivityParam2>
+
+ </IhvConnectivity>
+ </connectivity>
+
+ </IHV>
+
+</WLANProfile>
+
diff --git a/network/wlan/ihvsample/ihvmachine.xml b/network/wlan/ihvsample/ihvmachine.xml
new file mode 100644
index 00000000..04b7ba21
--- /dev/null
+++ b/network/wlan/ihvsample/ihvmachine.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvmachine</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>manual</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ <useOneX>true</useOneX>
+ </authEncryption>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <maxAuthFailures>3</maxAuthFailures>
+
+ <!-- This would not work if any UI prompt is required by the backend. -->
+ <authMode>machine</authMode>
+
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvonexext.cpp b/network/wlan/ihvsample/ihvonexext.cpp
new file mode 100644
index 00000000..8e80ab8a
--- /dev/null
+++ b/network/wlan/ihvsample/ihvonexext.cpp
@@ -0,0 +1,1113 @@
+
+/*++
+
+Copyright (c) 2005 Microsoft Corporation
+
+Abstract:
+
+ Sample IHV Extensibility DLL to extend
+ 802.11 LWF driver for third party protocols.
+
+
+--*/
+
+#include "precomp.h"
+
+
+
+
+
+#define MAX_BACKLOG 32
+#define MAX_EXEMPTIONS 1
+#define MAX_REGISTRATIONS 2
+#define ETHTYPE_EAPOL 0x888e
+#define EapolTypeEapolKey 0x03
+
+
+DWORD
+PlumbWEPKey
+(
+ HANDLE hDot11SvcHandle,
+ ULONG uKeyIndex,
+ DOT11_DIRECTION direction,
+ LPBYTE pbKey,
+ ULONG uKeyLen
+);
+
+
+DWORD
+ProcessRC4Key
+(
+ HANDLE hIhvExtAdapter,
+ PDOT11_MSONEX_RESULT_PARAMS pOneXResultParams,
+ HANDLE hDot11SvcHandle,
+ HANDLE hSecuritySessionID,
+ ULONG uPktLen,
+ PBYTE pbEapolPkt
+);
+
+
+
+// initialize onex data structure.
+DWORD
+GetNewOnexData
+(
+ PONEX_DATA* ppOnexData
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PONEX_DATA pOnexData = NULL;
+
+ ASSERT( ppOnexData );
+
+ if (*ppOnexData)
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // allocate memory.
+ pOnexData = (PONEX_DATA) PrivateMemoryAlloc( sizeof( ONEX_DATA ) );
+ if (!pOnexData)
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // init fields here.
+ pOnexData->lpfnReceivePacket = Do1xReceivePacket;
+ pOnexData->lpfnIndicateResult = Do1xIndicateResult;
+
+ // transfer data to caller.
+ (*ppOnexData) = pOnexData;
+ pOnexData = NULL;
+
+error:
+ if ( pOnexData )
+ {
+ FreeOnexData( &pOnexData );
+ }
+ return dwResult;
+}
+
+
+
+
+// free onex data structure.
+VOID
+FreeOnexData
+(
+ PONEX_DATA* ppOnexData
+)
+{
+ PONEX_DATA pOnexData = NULL;
+
+ if ( ppOnexData && (*ppOnexData) )
+ {
+ // Freeing caller's variable.
+ pOnexData = (*ppOnexData);
+ (*ppOnexData) = NULL;
+
+ RC4UtilsFreeResultParams( &(pOnexData->pOnexResultParams) );
+ ZeroMemory( pOnexData , sizeof( ONEX_DATA ) );
+ PrivateMemoryFree( pOnexData );
+ }
+}
+
+
+// verify if result params are available and valid.
+BOOL
+IsOneXResultParamsAvailable
+(
+ PDOT11_MSONEX_RESULT_PARAMS pOneXResultParams
+)
+{
+ BOOL bResult = FALSE;
+
+
+ bResult =
+ (
+ pOneXResultParams &&
+ pOneXResultParams->pbMPPERecvKey &&
+ pOneXResultParams->dwMPPERecvKeyLen &&
+ pOneXResultParams->pbMPPESendKey &&
+ pOneXResultParams->dwMPPESendKeyLen
+ );
+
+ TRACE_MESSAGE_VAL( "Onex Result Params Available = ", bResult );
+
+ return bResult;
+}
+
+
+// free rc4 packet.
+VOID
+FreeRC4Pkt
+(
+ PCACHED_PKT pPkt
+)
+{
+ if ( pPkt )
+ {
+ PrivateMemoryFree( pPkt->pbPkt );
+ pPkt->pbPkt = NULL;
+ pPkt->uPktLen = 0;
+ }
+}
+
+// flush rc4 packet cache.
+VOID
+FlushRC4PktCache
+(
+ PONEX_DATA pOnexData
+)
+{
+ ULONG i = 0;
+
+ ASSERT( pOnexData );
+
+ for (i = 0; i< RC4_CACHE_SIZE; i++)
+ {
+ FreeRC4Pkt( &(pOnexData->RC4Cache[i]) );
+ }
+}
+
+
+// cache rc4 packet
+DWORD
+CacheRC4Pkt
+(
+ PONEX_DATA pOnexData,
+ ULONG uPktLen,
+ PBYTE pbEapolPkt
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PBYTE pbPktCopy = NULL;
+
+ if ( !(pOnexData && uPktLen && pbEapolPkt) )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // copy the packet.
+ pbPktCopy = (PBYTE) PrivateMemoryAlloc(uPktLen);
+ if (!pbPktCopy)
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ CopyMemory
+ (
+ pbPktCopy,
+ pbEapolPkt,
+ uPktLen
+ );
+
+ // free packet destination.
+ FreeRC4Pkt( &(pOnexData->RC4Cache[pOnexData->uCacheFreeIdx]) );
+
+ // move packet copy to cache.
+ pOnexData->RC4Cache[ pOnexData->uCacheFreeIdx ].pbPkt = pbPktCopy;
+ pOnexData->RC4Cache[ pOnexData->uCacheFreeIdx ].uPktLen = uPktLen;
+
+
+ TRACE_MESSAGE_VAL( "RC4 Packet cached, Index = ", pOnexData->uCacheFreeIdx );
+
+ // increment index.
+ pOnexData->uCacheFreeIdx = (pOnexData->uCacheFreeIdx + 1 ) % RC4_CACHE_SIZE;
+
+error:
+ return dwResult;
+}
+
+// process cached rc4 packets.
+DWORD
+ProcessCachedRC4Packets
+(
+ PADAPTER_DETAILS pAdapterDetails
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ ULONG ulIndex = 0;
+ ULONG uProcessIndex = 0;
+ PONEX_DATA pOnexData = NULL;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pAdapterDetails->pOnexData );
+
+ pOnexData = pAdapterDetails->pOnexData;
+
+ // If no 1x result available, bail
+ if (!IsOneXResultParamsAvailable( pOnexData->pOnexResultParams ))
+ {
+ dwResult = ERROR_SUCCESS;
+ BAIL( );
+ }
+
+ TRACE_MESSAGE( "Processing cached RC4 packets." );
+
+ // We process last 2 received frames
+
+ for ( ulIndex = 1; ulIndex <= RC4_CACHE_SIZE; ulIndex++ )
+ {
+ uProcessIndex = ( pOnexData->uCacheFreeIdx - ulIndex) % RC4_CACHE_SIZE;
+
+ if
+ (
+ ( pOnexData->RC4Cache[uProcessIndex].pbPkt ) &&
+ ( pOnexData->RC4Cache[uProcessIndex].uPktLen )
+ )
+ {
+ dwResult =
+ ProcessRC4Key
+ (
+ (HANDLE) &(pAdapterDetails->Link),
+ pOnexData->pOnexResultParams,
+ pAdapterDetails->hDot11SvcHandle,
+ pOnexData->hSecuritySessionID,
+ pOnexData->RC4Cache[uProcessIndex].uPktLen,
+ pOnexData->RC4Cache[uProcessIndex].pbPkt
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ FreeRC4Pkt( &(pOnexData->RC4Cache[uProcessIndex]) );
+
+ }
+ }
+
+error:
+ return dwResult;
+}
+
+
+
+
+
+// pre-associate function for onex profile.
+DWORD
+WINAPI
+Do1xPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ ULONG uNumExemptions = 0;
+ ULONG uNumRegistrations = 0;
+ DOT11_PRIVACY_EXEMPTION PrivacyExemption[MAX_EXEMPTIONS] = {0};
+ USHORT usRegistration[MAX_REGISTRATIONS] = {0};
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pdwReasonCode );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_INVALID_STATE;
+
+ if ( nic_state_pre_assoc_started != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_OUTOFMEMORY;
+
+ dwResult =
+ GetNewOnexData
+ (
+ &(pAdapterDetails->pOnexData)
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_HARDWARE_FAILURE;
+
+
+ TRACE_MESSAGE( "Setting Auth Algorithm." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetAuthAlgorithm)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ DOT11_AUTH_ALGO_80211_OPEN
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Setting Unicast cipher algorithm." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetUnicastCipherAlgorithm)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ DOT11_CIPHER_ALGO_WEP
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Setting Multicast cipher algorithm." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetMulticastCipherAlgorithm)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ DOT11_CIPHER_ALGO_WEP
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Setting exclude unencrypted flag." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetExcludeUnencrypted)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ TRUE
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ // set the exemption handler
+
+ // In vanilla 1x, 802.1x packets are never encrypted
+ PrivacyExemption[uNumExemptions].usExemptionActionType = DOT11_EXEMPT_ALWAYS;
+ PrivacyExemption[uNumExemptions].usEtherType = htons(ETHTYPE_EAPOL);
+ PrivacyExemption[uNumExemptions].usExemptionPacketType = DOT11_EXEMPT_UNICAST;
+ uNumExemptions++;
+ ASSERT(uNumExemptions <= MAX_EXEMPTIONS);
+
+ usRegistration[uNumRegistrations] = htons(ETHTYPE_EAPOL);
+ uNumRegistrations++;
+ ASSERT(uNumRegistrations <= MAX_REGISTRATIONS);
+
+ TRACE_MESSAGE( "Setting ethertype handling." );
+ dwResult =
+ g_pDot11ExtApi->Dot11ExtSetEtherTypeHandling
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ MAX_BACKLOG,
+ uNumExemptions,
+ PrivacyExemption,
+ uNumRegistrations,
+ usRegistration
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+
+ // Verified before, just after acquiring lock.
+ ASSERT( nic_state_pre_assoc_started == pAdapterDetails->NicState );
+
+ pAdapterDetails->NicState = nic_state_pre_assoc_ended;
+
+ // Reason code is set to SUCCESS.
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+ // populate post associate handler functions.
+ pAdapterDetails->pPerformPostAssociateCompletionRoutine = NULL;
+ pAdapterDetails->pPerformPostAssociateRoutine = Do1xPostAssociate;
+ pAdapterDetails->pStopPostAssociateRoutine = Do1xStopPostAssociate;
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+// post-associate function for onex profile.
+DWORD
+WINAPI
+Do1xPostAssociate
+(
+ IN PADAPTER_DETAILS pAdapterDetails,
+ IN HANDLE hSecuritySessionID,
+ IN PDOT11_PORT_STATE pPortState,
+ IN ULONG uDot11AssocParamsBytes,
+ IN PDOT11_ASSOCIATION_COMPLETION_PARAMETERS pDot11AssocParams
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+
+ ASSERT( pAdapterDetails );
+
+ UNREFERENCED_PARAMETER( pPortState );
+ UNREFERENCED_PARAMETER( uDot11AssocParamsBytes );
+ UNREFERENCED_PARAMETER( pDot11AssocParams );
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // verify and change state.
+ if
+ (
+ ( nic_state_post_assoc_started != pAdapterDetails->NicState &&
+ nic_state_post_assoc_ended != pAdapterDetails->NicState
+ ) ||
+ ( !(pAdapterDetails->pOnexData) )
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+ pAdapterDetails->NicState = nic_state_onex_in_progress;
+
+ // no need to free old id handle.
+ pAdapterDetails->pOnexData->hSecuritySessionID = hSecuritySessionID;
+
+ TRACE_MESSAGE( "Starting OneX." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtStartOneX)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ NULL // EAP attributes
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ pAdapterDetails->pOnexData->fMSOneXStarted = TRUE;
+
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+// receive rc4 key.
+DWORD
+ReceiveRC4Key
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ ULONG uPktLen,
+ PEAPOL_PACKET pEapolPkt
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( uPktLen );
+ ASSERT( pEapolPkt );
+
+ EnterCriticalSection(&g_csSynch);
+ bLocked = TRUE;
+
+ ASSERT( pAdapterDetails->pOnexData );
+
+ TRACE_MESSAGE( "Received RC4 Key packet." );
+
+ if ( IsOneXResultParamsAvailable( pAdapterDetails->pOnexData->pOnexResultParams ) )
+ {
+ // 1x params are available
+ dwResult =
+ ProcessRC4Key
+ (
+ (HANDLE) &(pAdapterDetails->Link),
+ pAdapterDetails->pOnexData->pOnexResultParams,
+ pAdapterDetails->hDot11SvcHandle,
+ pAdapterDetails->pOnexData->hSecuritySessionID,
+ uPktLen,
+ (PBYTE)pEapolPkt
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+ else
+ {
+ dwResult =
+ CacheRC4Pkt
+ (
+ pAdapterDetails->pOnexData,
+ uPktLen,
+ (PBYTE) pEapolPkt
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+error:
+ if (bLocked)
+ {
+ LeaveCriticalSection(&g_csSynch);
+ }
+ return dwResult;
+}
+
+
+
+
+// receive packet function for onex profile.
+DWORD
+WINAPI
+Do1xReceivePacket
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD dwInBufferSize,
+ LPVOID pvInBuffer
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ HANDLE hDot11SvcHandle = NULL;
+ BOOL bLocked = FALSE;
+ PDOT11_SECURITY_PACKET_HEADER pSecurityPkt = NULL;
+ PEAPOL_PACKET pEapolPkt = NULL;
+ DWORD uReqdPktLen = 0;
+
+ ASSERT( pAdapterDetails );
+
+ // Must include at least one byte of data
+ uReqdPktLen = FIELD_OFFSET(DOT11_SECURITY_PACKET_HEADER, Data) + 1;
+
+ if ( dwInBufferSize < uReqdPktLen )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ if ( !pvInBuffer )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ pSecurityPkt = (PDOT11_SECURITY_PACKET_HEADER) pvInBuffer;
+ pEapolPkt = (PEAPOL_PACKET) pSecurityPkt->Data;
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // validate state.
+ if
+ (
+ (!(pAdapterDetails->pOnexData)) ||
+ (
+ ( nic_state_onex_in_progress != pAdapterDetails->NicState ) &&
+ ( nic_state_post_assoc_ended != pAdapterDetails->NicState )
+ )
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ hDot11SvcHandle = pAdapterDetails->hDot11SvcHandle;
+
+ TRACE_MESSAGE( "Received security packet." );
+
+ // Ignoring version
+ if ( EapolTypeEapolKey == pEapolPkt->PacketType )
+ {
+ dwResult =
+ ReceiveRC4Key
+ (
+ pAdapterDetails,
+ dwInBufferSize - FIELD_OFFSET(DOT11_SECURITY_PACKET_HEADER, Data),
+ pEapolPkt
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+ else
+ {
+ // leave lock before sending security packet to AC.
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtProcessSecurityPacket)
+ (
+ hDot11SvcHandle,
+ dwInBufferSize - FIELD_OFFSET(DOT11_SECURITY_PACKET_HEADER, Data),
+ pSecurityPkt->Data
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+// parameters for calling AC with post assoc completion.
+typedef
+struct _POST_ASSOC_COMPL_DATA
+{
+ HANDLE hIhvExtAdapter;
+ HANDLE hDot11SvcHandle;
+ HANDLE hSecuritySessionID;
+ DOT11_MAC_ADDRESS PeerMacAddress;
+ DWORD dwSecurityReasonCode;
+ DWORD dwSecurityWin32Error;
+}
+POST_ASSOC_COMPL_DATA, *PPOST_ASSOC_COMPL_DATA;
+
+
+// function to make the actual post assoc completion call.
+// this function is started in a separate thread.
+DWORD
+WINAPI
+PostAssocComplWorker
+(
+ LPVOID pvCtxt
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PPOST_ASSOC_COMPL_DATA pCtxt = (PPOST_ASSOC_COMPL_DATA) pvCtxt;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+ ASSERT( pCtxt );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ pCtxt->hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+ if ( nic_state_onex_in_progress != pAdapterDetails->NicState &&
+ nic_state_post_assoc_ended != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ pAdapterDetails->NicState = nic_state_post_assoc_ended;
+
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ TRACE_MESSAGE_VAL( "Calling PostAssocCompletion, Status = ", pCtxt->dwSecurityWin32Error );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtPostAssociateCompletion)
+ (
+ pCtxt->hDot11SvcHandle,
+ pCtxt->hSecuritySessionID,
+ &(pCtxt->PeerMacAddress),
+ pCtxt->dwSecurityReasonCode,
+ pCtxt->dwSecurityWin32Error
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( pCtxt->hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ PrivateMemoryFree( pvCtxt );
+ return dwResult;
+}
+
+
+// starts a worker thread for the post association completion.
+DWORD
+Do1xPostAssocCompletion
+(
+ HANDLE hIhvExtAdapter,
+ HANDLE hDot11SvcHandle,
+ HANDLE hSecuritySessionID,
+ PDOT11_MAC_ADDRESS pPeer,
+ DWORD dwSecurityReasonCode,
+ DWORD dwSecurityWin32Error
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PPOST_ASSOC_COMPL_DATA pCtxt = NULL;
+
+ // allocate memory and copy parameters.
+ pCtxt = (PPOST_ASSOC_COMPL_DATA) PrivateMemoryAlloc(sizeof(POST_ASSOC_COMPL_DATA));
+ if (!pCtxt)
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ pCtxt->hIhvExtAdapter = hIhvExtAdapter;
+ pCtxt->hDot11SvcHandle = hDot11SvcHandle;
+ pCtxt->hSecuritySessionID = hSecuritySessionID;
+
+ if (pPeer)
+ {
+ CopyMemory
+ (
+ &(pCtxt->PeerMacAddress),
+ pPeer,
+ sizeof(DOT11_MAC_ADDRESS)
+ );
+ }
+
+ pCtxt->dwSecurityReasonCode = dwSecurityReasonCode;
+ pCtxt->dwSecurityWin32Error = dwSecurityWin32Error;
+
+ // start the new thread.
+ dwResult =
+ StartNewProtectedThread
+ (
+ hIhvExtAdapter,
+ PostAssocComplWorker,
+ pCtxt
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ pCtxt = NULL;
+
+error:
+ PrivateMemoryFree( pCtxt );
+ return dwResult;
+}
+
+
+// indicate result function for onex profile.
+DWORD
+WINAPI
+Do1xIndicateResult
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DOT11_MSONEX_RESULT msOneXResult,
+ PDOT11_MSONEX_RESULT_PARAMS pDot11MsOneXResultParams
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pAdapterDetails->pOnexData );
+
+ // validate state.
+ if ( nic_state_onex_in_progress != pAdapterDetails->NicState &&
+ nic_state_post_assoc_ended != pAdapterDetails->NicState
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ if ( msOneXResult == DOT11_MSONEX_IN_PROGRESS )
+ {
+ // free the onex params if they exist
+ RC4UtilsFreeResultParams( &( pAdapterDetails->pOnexData->pOnexResultParams) );
+ FlushRC4PktCache( pAdapterDetails->pOnexData );
+ TRACE_MESSAGE( "Received DOT11_MSONEX_IN_PROGRESS." );
+ }
+ else if ( msOneXResult == DOT11_MSONEX_FAILURE )
+ {
+ TRACE_MESSAGE( "Received DOT11_MSONEX_FAILURE." );
+
+ // If failure, indicate right away
+ dwResult =
+ Do1xPostAssocCompletion
+ (
+ (HANDLE) &(pAdapterDetails->Link),
+ pAdapterDetails->hDot11SvcHandle,
+ pAdapterDetails->pOnexData->hSecuritySessionID,
+ NULL,
+ (pDot11MsOneXResultParams &&
+ pDot11MsOneXResultParams->Dot11OneXReasonCode != ONEX_REASON_CODE_SUCCESS)?
+ pDot11MsOneXResultParams->Dot11OneXReasonCode:
+ L2_REASON_CODE_IHV_ONEX_FAILURE,
+ msOneXResult
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+ else if ( msOneXResult == DOT11_MSONEX_SUCCESS )
+ {
+ // success case.
+ TRACE_MESSAGE( "Received DOT11_MSONEX_SUCCESS." );
+
+ // free result params and get new result params.
+ RC4UtilsFreeResultParams( &(pAdapterDetails->pOnexData->pOnexResultParams) );
+
+ dwResult =
+ RC4UtilsDecryptResultParams
+ (
+ pDot11MsOneXResultParams,
+ &(pAdapterDetails->pOnexData->pOnexResultParams)
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ // Process cached RC4 packets if any
+ dwResult =
+ ProcessCachedRC4Packets
+ (
+ pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+// stop-post-associate function for onex profile.
+DWORD
+WINAPI
+Do1xStopPostAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ PDOT11_MAC_ADDRESS pPeer,
+ DOT11_ASSOC_STATUS dot11AssocStatus
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+
+ UNREFERENCED_PARAMETER( pPeer );
+ UNREFERENCED_PARAMETER( dot11AssocStatus );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ TRACE_MESSAGE( "Performing StopPostAssociate." );
+
+ if
+ (
+ ( nic_state_post_assoc_ended != pAdapterDetails->NicState ) &&
+ ( nic_state_onex_in_progress != pAdapterDetails->NicState ) &&
+ ( nic_state_post_assoc_started != pAdapterDetails->NicState )
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // Reset the port specific variables.
+
+ if ( pAdapterDetails->pOnexData )
+ {
+ if(pAdapterDetails->pOnexData->fMSOneXStarted)
+ {
+ // NOTE THAT THE OS WILL STOP THE AUTH EVEN IF THIS CALL IS NOT MADE.
+ // The sample should keep track of port downs and call start auth
+ // once a port up is received.
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtStopOneX)
+ (
+ pAdapterDetails->hDot11SvcHandle
+ );
+ if(dwResult != ERROR_SUCCESS)
+ {
+ // log error
+ dwResult = ERROR_SUCCESS;
+ }
+ else
+ {
+ pAdapterDetails->pOnexData->fMSOneXStarted = FALSE;
+ }
+ }
+
+ // flush the rc4 packet cache.
+ FlushRC4PktCache( pAdapterDetails->pOnexData );
+
+ // free the result params.
+ RC4UtilsFreeResultParams( &(pAdapterDetails->pOnexData->pOnexResultParams) );
+ }
+
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+
+DWORD
+PlumbWEPKey
+(
+ HANDLE hDot11SvcHandle,
+ ULONG uKeyIndex,
+ DOT11_DIRECTION direction,
+ LPBYTE pbKey,
+ ULONG uKeyLen
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PDOT11_CIPHER_DEFAULT_KEY_VALUE pDefaultKey = NULL;
+ ULONG uAllocLen = 0;
+ BOOL bLocked = FALSE;
+
+ uAllocLen = FIELD_OFFSET(DOT11_CIPHER_DEFAULT_KEY_VALUE, ucKey) + uKeyLen;
+
+ if (uAllocLen < uKeyLen)
+ {
+ dwResult = ERROR_ARITHMETIC_OVERFLOW;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ pDefaultKey = (PDOT11_CIPHER_DEFAULT_KEY_VALUE) PrivateMemoryAlloc(uAllocLen);
+ if (!pDefaultKey)
+ {
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ pDefaultKey->AlgorithmId = DOT11_CIPHER_ALGO_WEP;
+ pDefaultKey->uKeyIndex = uKeyIndex;
+ pDefaultKey->bDelete = FALSE;
+ pDefaultKey->bStatic = FALSE;
+ pDefaultKey->usKeyLength = (USHORT) uKeyLen;
+
+ ZeroMemory(&(pDefaultKey->MacAddr), sizeof(DOT11_MAC_ADDRESS));
+
+ CopyMemory
+ (
+ pDefaultKey->ucKey,
+ pbKey,
+ uKeyLen
+ );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ TRACE_MESSAGE( "Setting default key." );
+ TRACE_MESSAGE_VAL( " Key Index = ", uKeyIndex );
+ TRACE_MESSAGE_VAL( " Key Length = ", uKeyLen );
+ TRACE_MESSAGE_VAL( " Direction = ", direction );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetDefaultKey)
+ (
+ hDot11SvcHandle,
+ pDefaultKey,
+ direction
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+
+error:
+ if (pDefaultKey)
+ {
+ SecureZeroMemory( pDefaultKey, uAllocLen );
+ PrivateMemoryFree( pDefaultKey );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+DWORD
+ProcessRC4Key
+(
+ HANDLE hIhvExtAdapter,
+ PDOT11_MSONEX_RESULT_PARAMS pOneXResultParams,
+ HANDLE hDot11SvcHandle,
+ HANDLE hSecuritySessionID,
+ ULONG uPktLen,
+ PBYTE pbEapolPkt
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PEAPOL_PACKET pEapolPkt = NULL;
+ DWORD dwKeyLen = 0;
+ DWORD dwKeyIndex = 0;
+ LPBYTE pbDecryptedKey = NULL;
+ BOOL bUCast = FALSE;
+ BOOL bLocked = FALSE;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ ASSERT( IsOneXResultParamsAvailable ( pOneXResultParams ) );
+
+ TRACE_MESSAGE( "Processing RC4 key." );
+
+ pEapolPkt = (PEAPOL_PACKET) pbEapolPkt;
+
+ dwResult =
+ RC4UtilsParseKeyPacket
+ (
+ pEapolPkt,
+ uPktLen,
+ pOneXResultParams,
+ &bUCast,
+ &pbDecryptedKey,
+ &dwKeyLen,
+ &dwKeyIndex
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ dwResult =
+ PlumbWEPKey
+ (
+ hDot11SvcHandle,
+ dwKeyIndex,
+ bUCast ? DOT11_DIR_BOTH : DOT11_DIR_INBOUND,
+ pbDecryptedKey,
+ dwKeyLen
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ if ( bUCast )
+ {
+ TRACE_MESSAGE_VAL( "Setting default key ID, Key Index = ", dwKeyIndex );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetDefaultKeyId)
+ (
+ hDot11SvcHandle,
+ dwKeyIndex
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ dwResult =
+ Do1xPostAssocCompletion
+ (
+ hIhvExtAdapter,
+ hDot11SvcHandle,
+ hSecuritySessionID,
+ NULL,
+ L2_REASON_CODE_SUCCESS,
+ ERROR_SUCCESS
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+error:
+ RC4UtilsFreeKeyMaterial( pbDecryptedKey, dwKeyLen );
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
diff --git a/network/wlan/ihvsample/ihvonexext.h b/network/wlan/ihvsample/ihvonexext.h
new file mode 100644
index 00000000..574bbdfa
--- /dev/null
+++ b/network/wlan/ihvsample/ihvonexext.h
@@ -0,0 +1,108 @@
+
+
+
+// cache size.
+#define RC4_CACHE_SIZE 2
+
+
+// cached packet.
+typedef
+struct _CACHED_PKT
+{
+ ULONG uPktLen;
+ PBYTE pbPkt;
+}
+CACHED_PKT, *PCACHED_PKT;
+
+
+// connection specific data for onex profiles.
+typedef
+struct _ONEX_DATA
+{
+ HANDLE hSecuritySessionID;
+ BOOL fMSOneXStarted;
+ CACHED_PKT RC4Cache[RC4_CACHE_SIZE];
+ ULONG uCacheFreeIdx;
+ PDOT11_MSONEX_RESULT_PARAMS pOnexResultParams;
+ IHV_RECEIVE_PACKET_HANDLER lpfnReceivePacket;
+ IHV_INDICATE_RESULT_HANDLER lpfnIndicateResult;
+}
+ONEX_DATA, *PONEX_DATA;
+
+
+// initialize onex data structure.
+DWORD
+GetNewOnexData
+(
+ PONEX_DATA* ppOnexData
+);
+
+// free onex data structure.
+VOID
+FreeOnexData
+(
+ PONEX_DATA* ppOnexData
+);
+
+
+
+
+// pre-associate function for onex profile.
+DWORD
+WINAPI
+Do1xPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+);
+
+
+
+// post-associate function for onex profile.
+DWORD
+WINAPI
+Do1xPostAssociate
+(
+ IN PADAPTER_DETAILS pAdapterDetails,
+ IN HANDLE hSecuritySessionID,
+ IN PDOT11_PORT_STATE pPortState,
+ IN ULONG uDot11AssocParamsBytes,
+ IN PDOT11_ASSOCIATION_COMPLETION_PARAMETERS pDot11AssocParams
+);
+
+
+// stop-post-associate function for onex profile.
+DWORD
+WINAPI
+Do1xStopPostAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ PDOT11_MAC_ADDRESS pPeer,
+ DOT11_ASSOC_STATUS dot11AssocStatus
+);
+
+
+
+// receive packet function for onex profile.
+DWORD
+WINAPI
+Do1xReceivePacket
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD dwInBufferSize,
+ LPVOID pvInBuffer
+);
+
+
+
+// indicate result function for onex profile.
+DWORD
+WINAPI
+Do1xIndicateResult
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DOT11_MSONEX_RESULT msOneXResult,
+ PDOT11_MSONEX_RESULT_PARAMS pDot11MsOneXResultParams
+);
+
+
diff --git a/network/wlan/ihvsample/ihvplapmachineoruser.xml b/network/wlan/ihvsample/ihvplapmachineoruser.xml
new file mode 100644
index 00000000..cd86060e
--- /dev/null
+++ b/network/wlan/ihvsample/ihvplapmachineoruser.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvplapmachineoruser</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>auto</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ <useOneX>true</useOneX>
+ </authEncryption>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <maxAuthFailures>3</maxAuthFailures>
+ <authMode>machineOrUser</authMode>
+
+ <singleSignOn>
+ <type>preLogon</type>
+ <maxDelay>50</maxDelay>
+ </singleSignOn>
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvplapuser.xml b/network/wlan/ihvsample/ihvplapuser.xml
new file mode 100644
index 00000000..37334800
--- /dev/null
+++ b/network/wlan/ihvsample/ihvplapuser.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvplapuser</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>auto</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ <useOneX>true</useOneX>
+ </authEncryption>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <maxAuthFailures>3</maxAuthFailures>
+ <authMode>user</authMode>
+
+ <singleSignOn>
+ <type>preLogon</type>
+ <maxDelay>50</maxDelay>
+ </singleSignOn>
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvsample.cpp b/network/wlan/ihvsample/ihvsample.cpp
new file mode 100644
index 00000000..2b73a7ed
--- /dev/null
+++ b/network/wlan/ihvsample/ihvsample.cpp
@@ -0,0 +1,1554 @@
+/*++
+
+Copyright (c) 2005 Microsoft Corporation
+
+Abstract:
+
+ Sample IHV Extensibility DLL to extend
+ 802.11 LWF driver for third party protocols.
+
+
+--*/
+
+#include "precomp.h"
+
+
+
+//
+// Get Version info.
+//
+DWORD
+WINAPI
+Dot11ExtIhvGetVersionInfo
+(
+ OUT PDOT11_IHV_VERSION_INFO pDot11IHVVersionInfo
+)
+{
+ if ( pDot11IHVVersionInfo )
+ {
+ pDot11IHVVersionInfo->dwVerMin = 0;
+ pDot11IHVVersionInfo->dwVerMax = 0;
+ }
+ return ERROR_SUCCESS;
+}
+
+
+//
+// Initialize service.
+//
+
+DWORD
+WINAPI
+Dot11ExtIhvInitService
+(
+ IN DWORD dwVerNumUsed,
+ IN PDOT11EXT_APIS pDot11ExtAPI,
+ IN LPVOID pvReserved,
+ OUT PDOT11EXT_IHV_HANDLERS pDot11IHVHandlers
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+
+ UNREFERENCED_PARAMETER( pvReserved );
+
+ if
+ (
+ ( 0 != dwVerNumUsed ) ||
+ ( !pDot11ExtAPI ) ||
+ ( !pDot11IHVHandlers )
+ )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ InitAdapterDetailsList( );
+
+ g_pDot11ExtApi = (PDOT11EXT_APIS) PrivateMemoryAlloc( sizeof( DOT11EXT_APIS ) );
+ if ( !g_pDot11ExtApi )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+ (*g_pDot11ExtApi) = (*pDot11ExtAPI);
+
+ HandlerInit( pDot11IHVHandlers );
+
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+//
+// Deinitialize service.
+//
+VOID
+WINAPI
+IhvDeinitService
+(
+ VOID
+)
+{
+
+ EnterCriticalSection( &g_csSynch );
+
+ // disable starting new threads or adding new adapters.
+ StartShutdown( );
+
+ LeaveCriticalSection( &g_csSynch );
+
+
+ WaitOnZeroThreads( );
+ DeinitAdapterDetailsList( );
+
+ if ( g_pDot11ExtApi )
+ {
+ PrivateMemoryFree( g_pDot11ExtApi );
+ g_pDot11ExtApi = NULL;
+ }
+
+ return;
+}
+
+
+
+//
+// Initialize adapter
+//
+DWORD
+WINAPI
+IhvInitAdapter
+(
+ IN PDOT11_ADAPTER pDot11Adapter,
+ IN HANDLE hDot11SvcHandle,
+ OUT PHANDLE phIhvExtAdapter
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ HANDLE hIhvExtAdapter = NULL;
+ USHORT usEtherTypeReg[] = { 0x888e, 0x8333 };
+
+ if (( !pDot11Adapter ) || (!hDot11SvcHandle) || (!phIhvExtAdapter) )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ InitAdapterDetails
+ (
+ hDot11SvcHandle,
+ &hIhvExtAdapter
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetEtherTypeHandling)
+ (
+ hDot11SvcHandle,
+ 3,
+ 0,
+ NULL,
+ 2,
+ usEtherTypeReg
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ (*phIhvExtAdapter) = hIhvExtAdapter;
+ hIhvExtAdapter = NULL;
+
+error:
+
+ if ( hIhvExtAdapter )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+//
+// Deinit adapter.
+//
+VOID
+WINAPI
+IhvDeinitAdapter
+(
+ IN HANDLE hIhvExtAdapter
+)
+{
+ DerefenceAdapterDetails( hIhvExtAdapter );
+
+ return;
+}
+
+
+
+
+
+//
+// Handle session change notification.
+//
+DWORD
+WINAPI
+IhvProcessSessionChange
+(
+ IN ULONG uEventType,
+ IN PWTSSESSION_NOTIFICATION pSessionNotification
+)
+{
+ UNREFERENCED_PARAMETER( pSessionNotification );
+
+ if ( WTS_CONSOLE_CONNECT == uEventType )
+ {
+ // The sample does not use this session ID
+ // anywhere. In an actual application, IHV
+ // developers may want to use this session ID to
+ // get/set the user data.
+ g_dwSessionID = WTSGetActiveConsoleSessionId( );
+ }
+ return ERROR_SUCCESS;
+}
+
+
+
+
+
+//
+// Checks if UI request is pending.
+//
+DWORD
+WINAPI
+IhvIsUIRequestPending
+(
+ IN GUID guidUIRequest,
+ OUT PBOOL pbIsRequestPending
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ HANDLE hIhvExtAdapter = NULL;
+
+
+ ASSERT( pbIsRequestPending );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // obtain reference to the adapter using
+ // UI request GUID.
+ dwResult =
+ ReferenceAdapterDetailsByUIRequestGuid
+ (
+ &guidUIRequest,
+ &pAdapterDetails,
+ &hIhvExtAdapter
+ );
+ if ( ERROR_NOT_FOUND == dwResult )
+ {
+ dwResult = ERROR_SUCCESS;
+ (*pbIsRequestPending) = FALSE;
+ BAIL( );
+ }
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ (*pbIsRequestPending) = TRUE;
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+//
+// Handle NIC specific notifications.
+//
+DWORD
+WINAPI
+IhvReceiveIndication
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11EXT_IHV_INDICATION_TYPE indicationType,
+ IN ULONG uBufferLength,
+ IN LPVOID pvBuffer
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PDOT11_PMKID_CANDIDATE_LIST_PARAMETERS pPMKCandidateListParams = NULL;
+ PDOT11_TKIPMIC_FAILURE_PARAMETERS pTkipMicFailureParams = NULL;
+ PDOT11_PHY_STATE_PARAMETERS pPHYStateChange = NULL;
+ PDOT11_LINK_QUALITY_PARAMETERS pDot11LinkQualityParams = NULL;
+
+ ASSERT( pvBuffer );
+
+ // Note that sample does not really use the buffer.
+ UNREFERENCED_PARAMETER( hIhvExtAdapter );
+ UNREFERENCED_PARAMETER( uBufferLength );
+
+ switch ( indicationType )
+ {
+ case IndicationTypeNicSpecificNotification:
+ // The pointer pvBuffer can be interpreted by IHV appropriately. Format
+ // is a contract between the miniport driver and the IHV extensibility module.
+ break;
+
+ case IndicationTypePmkidCandidateList:
+ pPMKCandidateListParams = (PDOT11_PMKID_CANDIDATE_LIST_PARAMETERS) pvBuffer;
+ // Ihv extensibility module may choose to use this data appropriately.
+ break;
+
+ case IndicationTypeTkipMicFailure:
+ pTkipMicFailureParams = (PDOT11_TKIPMIC_FAILURE_PARAMETERS) pvBuffer;
+ // Ihv extensibility module may choose to use this data appropriately.
+ break;
+
+ case IndicationTypePhyStateChange:
+ pPHYStateChange = (PDOT11_PHY_STATE_PARAMETERS) pvBuffer;
+ // Ihv extensibility module may choose to use this data appropriately.
+ break;
+
+ case IndicationTypeLinkQuality:
+ pDot11LinkQualityParams = (PDOT11_LINK_QUALITY_PARAMETERS) pvBuffer;
+ // Ihv extensibility module may choose to use this data appropriately.
+ break;
+
+ default:
+ ASSERTFAILURE();
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ break;
+ }
+
+error:
+ return dwResult;
+}
+
+
+
+
+
+
+//
+// Perform the capabiity match.
+//
+DWORD
+WINAPI
+IhvPerformCapabilityMatch
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDWORD pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PBYTE pbCurrPos = NULL;
+ ULONG uRemainBytes = 0;
+ ULONG uBssEntryBytes = 0;
+ PULDOT11_BSS_ENTRY pBssEntry = NULL;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile = NULL;
+ PIHV_SECURITY_PROFILE pSecurityProfile = NULL;
+
+ ASSERT( hIhvExtAdapter );
+ ASSERT( pdwReasonCode );
+
+ (*pdwReasonCode) = L2_REASON_CODE_UNKNOWN;
+
+ if ( !pConnectableBssid )
+ {
+ dwResult =
+ IhvValidateProfile
+ (
+ hIhvExtAdapter,
+ pIhvProfileParams,
+ pIhvConnProfile,
+ pIhvSecProfile,
+ pdwReasonCode
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ // Only validate profile if
+ // pConnectableBssid is NULL.
+ BAIL( );
+ }
+
+ // Validating data in pConnectableBssid
+ if (( 0 == pConnectableBssid->uNumOfBytes ) || ( NULL == pConnectableBssid->pucBuffer ))
+ {
+ dwResult = ERROR_NO_MATCH;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_BAD_PROFILE;
+
+ // parse the connectivity profile.
+ dwResult =
+ GetIhvConnectivityProfile
+ (
+ pIhvConnProfile,
+ &pConnectivityProfile
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pConnectivityProfile );
+
+ // parse the security profile.
+ dwResult =
+ GetIhvSecurityProfile
+ (
+ pIhvSecProfile,
+ &pSecurityProfile
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pSecurityProfile );
+
+ (*pdwReasonCode) = L2_REASON_CODE_UNKNOWN;
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // reference the adapter.
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ // try matching each BSS description field with the profile
+ // and see if there is a match.
+ uRemainBytes = pConnectableBssid->uNumOfBytes;
+ pbCurrPos = pConnectableBssid->pucBuffer;
+
+ // BSS Description might not contain any buffer!
+ while (uRemainBytes >= FIELD_OFFSET(DOT11_BSS_ENTRY, ucBuffer))
+ {
+ pBssEntry = (PULDOT11_BSS_ENTRY)pbCurrPos;
+ uBssEntryBytes = pBssEntry->uBufferLength + FIELD_OFFSET(DOT11_BSS_ENTRY, ucBuffer);
+
+ ASSERT (uRemainBytes >= uBssEntryBytes);
+ uRemainBytes -= uBssEntryBytes;
+ pbCurrPos += uBssEntryBytes;
+
+ if
+ (
+ MatchBssDescription
+ (
+ pIhvProfileParams,
+ pConnectivityProfile,
+ pSecurityProfile,
+ pBssEntry
+ )
+ )
+ {
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+ dwResult = ERROR_SUCCESS;
+ BAIL( );
+ }
+ }
+
+ // Since none of the BSS entries matched.
+ dwResult = ERROR_NO_MATCH;
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ FreeIhvConnectivityProfile( &pConnectivityProfile );
+ FreeIhvSecurityProfile( &pSecurityProfile );
+ return dwResult;
+}
+
+
+
+
+
+//
+// Function to validate profile.
+//
+DWORD
+WINAPI
+IhvValidateProfile
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ OUT PDWORD pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile = NULL;
+ PIHV_SECURITY_PROFILE pSecurityProfile = NULL;
+
+
+ ASSERT( hIhvExtAdapter );
+ ASSERT( pdwReasonCode );
+
+ UNREFERENCED_PARAMETER( hIhvExtAdapter );
+ UNREFERENCED_PARAMETER( pIhvProfileParams );
+
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_BAD_PROFILE;
+
+ // parse ihv connectivity profile.
+ dwResult =
+ GetIhvConnectivityProfile
+ (
+ pIhvConnProfile,
+ &pConnectivityProfile
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pConnectivityProfile );
+
+ // parse ihv security profile.
+ dwResult =
+ GetIhvSecurityProfile
+ (
+ pIhvSecProfile,
+ &pSecurityProfile
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pSecurityProfile );
+
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+error:
+ FreeIhvConnectivityProfile( &pConnectivityProfile );
+ FreeIhvSecurityProfile( &pSecurityProfile );
+ return dwResult;
+}
+
+
+//
+// This function does the actual preassociation work.
+//
+DWORD
+WINAPI
+DoPreAssociate
+(
+ LPVOID pvPreAssociate
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwStatus = ERROR_SUCCESS;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ PRE_ASSOCIATE_FUNCTION lpfnPreAssociate = NULL;
+ BOOL bLocked = FALSE;
+ DWORD dwReasonCode = L2_REASON_CODE_UNKNOWN;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ (HANDLE) pvPreAssociate,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ dwReasonCode = L2_REASON_CODE_IHV_BAD_PROFILE;
+
+ if ( !(pAdapterDetails->pConnectivityProfile && pAdapterDetails->pSecurityProfile) )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // choose pre-association function based on profile content.
+ if
+ (
+ ( pAdapterDetails->pSecurityProfile->bUseFullSecurity ) ||
+ ( pAdapterDetails->pSecurityProfile->bUseIhvConnectivityOnly )
+ )
+ {
+ if ( pAdapterDetails->pSecurityProfile->bUseIhvConnectivityOnly )
+ {
+ lpfnPreAssociate = DoIhvConnPreAssociate;
+ }
+ else if ( NULL == pAdapterDetails->pConnectivityProfile->pszParam2 )
+ {
+ lpfnPreAssociate = DoMissingKeyWepPreAssociate;
+ }
+ else if ( 0 == pAdapterDetails->pConnectivityProfile->pszParam2[0] )
+ {
+ lpfnPreAssociate = DoMissingKeyWepPreAssociate;
+ }
+ else
+ {
+ lpfnPreAssociate = DoWepPreAssociate;
+ }
+ }
+ else if
+ (
+ ( !(pAdapterDetails->pSecurityProfile->bUseFullSecurity) ) &&
+ ( IHVAuthV1 == pAdapterDetails->pSecurityProfile->AuthType )
+ )
+ {
+ lpfnPreAssociate = Do1xPreAssociate;
+ }
+ else
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ dwReasonCode = L2_REASON_CODE_UNKNOWN;
+
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ ASSERT( lpfnPreAssociate );
+ ASSERT( !bLocked );
+
+ dwResult =
+ (lpfnPreAssociate)
+ (
+ pAdapterDetails,
+ &dwReasonCode
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( (HANDLE) &(pAdapterDetails->Link) );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ if ( pAdapterDetails )
+ {
+ // call the completion function directly in this thread.
+ dwStatus =
+ (g_pDot11ExtApi->Dot11ExtPreAssociateCompletion)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ pAdapterDetails->hConnectSession,
+ dwReasonCode,
+ dwResult
+ );
+ }
+ if ( ERROR_SUCCESS != dwStatus )
+ {
+ // IHV specific logging can happen here.
+ }
+ return dwResult;
+}
+
+
+
+//
+// Function to start the preassociation thread.
+//
+DWORD
+WINAPI
+IhvPerformPreAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN HANDLE hConnectSession,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDWORD pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwStatus = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+
+ ASSERT ( pIhvProfileParams );
+ ASSERT ( pdwReasonCode );
+
+ UNREFERENCED_PARAMETER( pIhvProfileParams );
+ UNREFERENCED_PARAMETER( pConnectableBssid );
+
+ (*pdwReasonCode) = L2_REASON_CODE_UNKNOWN;
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+ if ( nic_state_initialized != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // Connection specific parameters should be properly initialized.
+ if
+ (
+ ( pAdapterDetails->pOnexData ) ||
+ ( pAdapterDetails->hConnectSession ) ||
+ ( pAdapterDetails->pPerformPostAssociateCompletionRoutine ) ||
+ ( pAdapterDetails->pPerformPostAssociateRoutine ) ||
+ ( pAdapterDetails->pStopPostAssociateRoutine )
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+
+
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_BAD_PROFILE;
+
+ // parse connectivity profile
+ dwResult =
+ GetIhvConnectivityProfile
+ (
+ pIhvConnProfile,
+ &(pAdapterDetails->pConnectivityProfile)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails->pConnectivityProfile );
+
+ // parse security profile.
+ dwResult =
+ GetIhvSecurityProfile
+ (
+ pIhvSecProfile,
+ &(pAdapterDetails->pSecurityProfile)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails->pSecurityProfile );
+
+ (*pdwReasonCode) = L2_REASON_CODE_UNKNOWN;
+
+ pAdapterDetails->NicState = nic_state_pre_assoc_started;
+
+ pAdapterDetails->hConnectSession = hConnectSession;
+ pAdapterDetails->bModifyCurrentProfile = FALSE;
+
+
+ // post a new thread to do the pre-association work.
+ dwResult =
+ StartNewProtectedThread
+ (
+ hIhvExtAdapter,
+ DoPreAssociate,
+ (LPVOID) hIhvExtAdapter
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+
+error:
+ if ( ERROR_SUCCESS != dwResult )
+ {
+ dwStatus =
+ IhvAdapterReset
+ (
+ hIhvExtAdapter
+ );
+ ASSERT( ERROR_SUCCESS == dwStatus );
+ }
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+//
+// This function starts post associate routine
+// in a separate thread and returns.
+//
+DWORD
+WINAPI
+IhvPerformPostAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN HANDLE hSecuritySessionID,
+ IN PDOT11_PORT_STATE pPortState,
+ IN ULONG uDot11AssocParamsBytes,
+ IN PDOT11_ASSOCIATION_COMPLETION_PARAMETERS pDot11AssocParams
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PPOST_ASSOC_DATA ppostAssocData = NULL;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+
+ ASSERT ( pDot11AssocParams );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ if ( nic_state_pre_assoc_ended != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+ pAdapterDetails->NicState = nic_state_post_assoc_started;
+
+ // is any post-association work required ??
+ if ( pAdapterDetails->pPerformPostAssociateRoutine )
+ {
+ dwResult =
+ ( pAdapterDetails->pPerformPostAssociateRoutine )
+ (
+ pAdapterDetails,
+ hSecuritySessionID,
+ pPortState,
+ uDot11AssocParamsBytes,
+ pDot11AssocParams
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // The post association completion thread may have been
+ // started by the perform post association routine for
+ // the current profile. Check if the completion thread
+ // needs to be started and start the routine.
+ if ( pAdapterDetails->pPerformPostAssociateCompletionRoutine )
+ {
+ ppostAssocData = (PPOST_ASSOC_DATA) PrivateMemoryAlloc( sizeof( POST_ASSOC_DATA ) );
+ if ( !ppostAssocData )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ ppostAssocData->hIhvExtAdapter = hIhvExtAdapter;
+ ppostAssocData->hDot11SvcHandle = pAdapterDetails->hDot11SvcHandle;
+ ppostAssocData->hSecuritySessionId = hSecuritySessionID;
+
+
+ dwResult =
+ StartNewProtectedThread
+ (
+ hIhvExtAdapter,
+ pAdapterDetails->pPerformPostAssociateCompletionRoutine,
+ ppostAssocData
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+
+ ppostAssocData = NULL;
+ }
+
+
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ PrivateMemoryFree( ppostAssocData );
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+//
+// Reset the adapter to initialized state.
+//
+DWORD
+WINAPI
+IhvAdapterReset
+(
+ IN HANDLE hIhvExtAdapter
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ DWORD dwRefCount = 0;
+ BOOL bOk = FALSE;
+ BOOL bLocked = FALSE;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ for ( ;; )
+ {
+ ASSERT( bLocked );
+
+ dwRefCount = pAdapterDetails->dwRefCount;
+
+ if ( 2 == dwRefCount ) // For adapter init and self call.
+ {
+ break;
+ }
+
+ if ( nic_state_pre_assoc_started == pAdapterDetails->NicState )
+ {
+ pAdapterDetails->NicState = nic_state_pre_assoc_ended;
+ bOk = SetEvent( pAdapterDetails->hUIResponse );
+ ASSERT( bOk );
+ }
+
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ Sleep( 100 );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+ }
+
+ ASSERT( bLocked );
+
+ // Resetting adapter.
+
+ pAdapterDetails->NicState = nic_state_initialized;
+ pAdapterDetails->hConnectSession = NULL;
+ pAdapterDetails->bModifyCurrentProfile = FALSE;
+ pAdapterDetails->pPerformPostAssociateCompletionRoutine = NULL;
+ pAdapterDetails->pPerformPostAssociateRoutine = NULL;
+ pAdapterDetails->pStopPostAssociateRoutine = NULL;
+
+ // freeing UI response data.
+ pAdapterDetails->dwResponseLen = 0;
+
+ PrivateMemoryFree( pAdapterDetails->pbResponse );
+ pAdapterDetails->pbResponse = NULL;
+
+ ZeroMemory( &(pAdapterDetails->currentGuidUIRequest), sizeof( GUID ) );
+
+ // freeing profile and onex data
+ FreeOnexData( &(pAdapterDetails->pOnexData) );
+ FreeIhvConnectivityProfile( &(pAdapterDetails->pConnectivityProfile) );
+ FreeIhvSecurityProfile( &(pAdapterDetails->pSecurityProfile) );
+
+ // unblocking UI thread.
+ bOk = ResetEvent( pAdapterDetails->hUIResponse );
+ if ( !bOk )
+ {
+ dwResult = GetLastError( );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ return dwResult;
+}
+
+
+
+
+//
+// Stop post association. Get back
+// to the state before post association started.
+//
+DWORD
+WINAPI
+IhvStopPostAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11_MAC_ADDRESS pPeer,
+ IN DOT11_ASSOC_STATUS dot11AssocStatus
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ DWORD dwRefCount = 0;
+ BOOL bLocked = FALSE;
+
+ // The dot11AssocStatus parameter can be compared with
+ // values DOT11_ASSOC_STATUS_* defined in the public
+ // headers.
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+ for ( ;; )
+ {
+ ASSERT( bLocked );
+
+ dwRefCount = pAdapterDetails->dwRefCount;
+
+ if ( 2 == dwRefCount ) // For adapter init and self call.
+ {
+ break;
+ }
+
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ Sleep( 100 );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+ }
+
+ ASSERT( bLocked );
+
+ if ( nic_state_initialized == pAdapterDetails->NicState )
+ {
+ // NO OP
+ // To handle the case when stop post associate
+ // call comes after adapter reset.
+ BAIL( );
+ }
+
+ // Call the post association routine - if there is any.
+ if ( pAdapterDetails->pStopPostAssociateRoutine )
+ {
+ dwResult =
+ (pAdapterDetails->pStopPostAssociateRoutine)
+ (
+ pAdapterDetails,
+ pPeer,
+ dot11AssocStatus
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ pAdapterDetails->NicState = nic_state_pre_assoc_ended;
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ return dwResult;
+}
+
+
+//
+// Process received packets.
+//
+DWORD
+WINAPI
+IhvReceivePacket
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DWORD dwInBufferSize,
+ IN LPVOID pvInBuffer
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ IHV_RECEIVE_PACKET_HANDLER lpfnReceivePacket = NULL;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ if ( pAdapterDetails->pOnexData && pAdapterDetails->pOnexData->lpfnReceivePacket )
+ {
+ lpfnReceivePacket = pAdapterDetails->pOnexData->lpfnReceivePacket;
+ }
+ else
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+ ASSERT( lpfnReceivePacket );
+
+ // Call the receive packet routine.
+ dwResult =
+ (lpfnReceivePacket)
+ (
+ pAdapterDetails,
+ dwInBufferSize,
+ pvInBuffer
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+//
+// Local copy of possible discovery profiles.
+//
+DOT11EXT_IHV_DISCOVERY_PROFILE
+g_IhvDiscoveryProfiles[] =
+{
+ // discovery profile 1.
+ {
+ {
+ L"<IhvConnectivity xmlns=\"http://www.someihv.com/nwifi/profile\">"
+ L"<IHVConnectivityParam1>0</IHVConnectivityParam1>"
+ L"<IHVConnectivityParam2></IHVConnectivityParam2>"
+ L"</IhvConnectivity>"
+ },
+
+ // Use MS Onex.
+ {
+ L"<IhvSecurity xmlns=\"http://www.someihv.com/nwifi/profile\">"
+ L"<IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>"
+ L"<IHVAuthentication>IHVAuthV1</IHVAuthentication>"
+ L"<IHVEncryption>IHVCipher1</IHVEncryption>"
+ L"<IHVSecurityParam1>0</IHVSecurityParam1>"
+ L"<IHVSecurityParam2></IHVSecurityParam2>"
+ L"</IhvSecurity>",
+
+ TRUE
+ }
+ },
+
+ // discovery profile 2
+ {
+ // Open Wep
+ {
+ L"<IhvConnectivity xmlns=\"http://www.someihv.com/nwifi/profile\">"
+ L"<IHVConnectivityParam1>0</IHVConnectivityParam1>"
+ L"<IHVConnectivityParam2></IHVConnectivityParam2>"
+ L"</IhvConnectivity>"
+ },
+
+ // Full IHV Security
+ {
+ L"<IhvSecurity xmlns=\"http://www.someihv.com/nwifi/profile\">"
+ L"<IHVUsesFullSecurity>TRUE</IHVUsesFullSecurity>"
+ L"<IHVAuthentication>IHVAuthV1</IHVAuthentication>"
+ L"<IHVEncryption>IHVCipher1</IHVEncryption>"
+ L"<IHVSecurityParam1>0</IHVSecurityParam1>"
+ L"<IHVSecurityParam2></IHVSecurityParam2>"
+ L"</IhvSecurity>",
+
+ FALSE
+ }
+ }
+};
+
+
+
+
+
+
+
+//
+// Create discovery profiles.
+//
+DWORD
+WINAPI
+IhvCreateDiscoveryProfiles
+(
+ IN HANDLE hIhvExtAdapter,
+ IN BOOL bInsecure,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDOT11EXT_IHV_DISCOVERY_PROFILE_LIST pIhvDiscoveryProfileList,
+ OUT PDWORD pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwIndex = 0;
+ DWORD dwIHVNumProfiles = ARRAY_LENGTH( g_IhvDiscoveryProfiles );
+
+ ASSERT( pIhvDiscoveryProfileList );
+ ASSERT( pdwReasonCode );
+
+ UNREFERENCED_PARAMETER( hIhvExtAdapter );
+ UNREFERENCED_PARAMETER( bInsecure );
+ UNREFERENCED_PARAMETER( pIhvProfileParams );
+ UNREFERENCED_PARAMETER( pConnectableBssid );
+
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_OUTOFMEMORY;
+
+ // allocate buffer for the array.
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtAllocateBuffer)
+ (
+ dwIHVNumProfiles * sizeof( DOT11EXT_IHV_DISCOVERY_PROFILE ),
+ (LPVOID*) &(pIhvDiscoveryProfileList->pIhvDiscoveryProfiles)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ ASSERT( pIhvDiscoveryProfileList->pIhvDiscoveryProfiles );
+ ZeroMemory
+ (
+ pIhvDiscoveryProfileList->pIhvDiscoveryProfiles,
+ dwIHVNumProfiles * sizeof( DOT11EXT_IHV_DISCOVERY_PROFILE )
+ );
+
+
+
+ // prepare each discovery profile.
+ for ( dwIndex = 0; dwIndex < dwIHVNumProfiles; dwIndex++ )
+ {
+ dwResult =
+ CopyDiscoveryProfile
+ (
+ g_IhvDiscoveryProfiles + dwIndex,
+ pIhvDiscoveryProfileList->pIhvDiscoveryProfiles + dwIndex
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ }
+
+ pIhvDiscoveryProfileList->dwCount = dwIHVNumProfiles;
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+error:
+ if ( ERROR_SUCCESS != dwResult )
+ {
+ if ( pIhvDiscoveryProfileList->pIhvDiscoveryProfiles )
+ {
+ for ( dwIndex = 0; dwIndex < dwIHVNumProfiles; dwIndex++ )
+ {
+ FreeDiscoveryProfile( pIhvDiscoveryProfileList->pIhvDiscoveryProfiles + dwIndex );
+ }
+ (g_pDot11ExtApi->Dot11ExtFreeBuffer)( pIhvDiscoveryProfileList->pIhvDiscoveryProfiles );
+ }
+ pIhvDiscoveryProfileList->dwCount = 0;
+ }
+ return dwResult;
+}
+
+
+
+//
+// Process UI Response function.
+//
+DWORD
+WINAPI
+IhvProcessUIResponse
+(
+ IN GUID guidUIRequest,
+ IN DWORD dwByteCount,
+ IN LPVOID pvResponseBuffer
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ HANDLE hIhvExtAdapter = NULL;
+
+ if ( !( dwByteCount && pvResponseBuffer ) )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // find the adapter from the UI response guid.
+ dwResult =
+ ReferenceAdapterDetailsByUIRequestGuid
+ (
+ &guidUIRequest,
+ &pAdapterDetails,
+ &hIhvExtAdapter
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+ ZeroMemory( &(pAdapterDetails->currentGuidUIRequest), sizeof( GUID ) );
+
+ // Copy the UI response to the adapter data structure.
+ PrivateMemoryFree( pAdapterDetails->pbResponse );
+
+ pAdapterDetails->pbResponse = (BYTE*) PrivateMemoryAlloc( dwByteCount );
+ if ( !(pAdapterDetails->pbResponse) )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+ CopyMemory( pAdapterDetails->pbResponse, pvResponseBuffer, dwByteCount );
+
+ (pAdapterDetails->dwResponseLen) = dwByteCount;
+
+ // Waiting thread can pick up the response now.
+ SetEvent( pAdapterDetails->hUIResponse );
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+//
+// Handler to clear memory after sending packet.
+//
+DWORD
+WINAPI
+IhvSendPacketCompletion
+(
+ IN HANDLE hSendCompletion
+)
+{
+ // The sample is not sending any packets.
+ // So send packet completion should
+ // not be called.
+ ASSERTFAILURE();
+
+ // The freeing function used here
+ // should be the reverse of the function
+ // used to allocate memory before calling
+ // Send Packet.
+ PrivateMemoryFree( (LPVOID) hSendCompletion );
+ return ERROR_SUCCESS;
+}
+
+
+
+
+//
+// Function to return UI Request on OS query.
+//
+DWORD
+WINAPI
+IhvQueryUIRequest
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11EXT_IHV_CONNECTION_PHASE connectionPhase,
+ OUT PDOT11EXT_IHV_UI_REQUEST* ppIhvUIRequest
+)
+{
+ // This IHV handler is a post Vista extensibility point.
+ // It is currently unused.
+ ASSERTFAILURE();
+
+ UNREFERENCED_PARAMETER( hIhvExtAdapter );
+ UNREFERENCED_PARAMETER( connectionPhase );
+ UNREFERENCED_PARAMETER( ppIhvUIRequest );
+
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+
+
+//
+// Handler to receive the Onex Result.
+//
+DWORD
+WINAPI
+IhvOnexIndicateResult
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11_MSONEX_RESULT msOneXResult,
+ IN PDOT11_MSONEX_RESULT_PARAMS pDot11MsOneXResultParams
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ // If indication of result is required.
+ if ( pAdapterDetails->pOnexData && pAdapterDetails->pOnexData->lpfnIndicateResult )
+ {
+ dwResult =
+ (pAdapterDetails->pOnexData->lpfnIndicateResult)
+ (
+ pAdapterDetails,
+ msOneXResult,
+ pDot11MsOneXResultParams
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ }
+ else
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+
+//
+// Handler to receive Control.
+//
+DWORD
+WINAPI
+IhvControl
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DWORD dwInBufferSize,
+ IN PBYTE pInBuffer,
+ IN DWORD dwOutBufferSize,
+ OUT PBYTE pOutBuffer,
+ OUT PDWORD pdwBytesReturned
+)
+{
+ // Sample does not demonstrate use of IHV control.
+
+ UNREFERENCED_PARAMETER( hIhvExtAdapter );
+ UNREFERENCED_PARAMETER( dwInBufferSize );
+ UNREFERENCED_PARAMETER( pInBuffer );
+ UNREFERENCED_PARAMETER( dwOutBufferSize );
+ UNREFERENCED_PARAMETER( pOutBuffer );
+ UNREFERENCED_PARAMETER( pdwBytesReturned );
+
+ return ERROR_SUCCESS;
+}
+
+
diff --git a/network/wlan/ihvsample/ihvsample.def b/network/wlan/ihvsample/ihvsample.def
new file mode 100644
index 00000000..dbbfe637
--- /dev/null
+++ b/network/wlan/ihvsample/ihvsample.def
@@ -0,0 +1,8 @@
+; Test Ihv Extensibility DLL
+
+LIBRARY IhvSample.dll
+
+EXPORTS
+ DllMain
+ Dot11ExtIhvGetVersionInfo
+ Dot11ExtIhvInitService
diff --git a/network/wlan/ihvsample/ihvsample.h b/network/wlan/ihvsample/ihvsample.h
new file mode 100644
index 00000000..0b0484bd
--- /dev/null
+++ b/network/wlan/ihvsample/ihvsample.h
@@ -0,0 +1,261 @@
+
+
+
+
+//
+// IHV can start defining reason codes in the IHV range.
+//
+enum
+{
+ L2_REASON_CODE_IHV_BAD_USER_KEY = L2_REASON_CODE_IHV_BASE,
+ L2_REASON_CODE_IHV_OUTOFMEMORY,
+ L2_REASON_CODE_IHV_BAD_PROFILE,
+ L2_REASON_CODE_IHV_HARDWARE_FAILURE,
+ L2_REASON_CODE_IHV_ONEX_FAILURE,
+ L2_REASON_CODE_IHV_INVALID_STATE
+};
+
+
+
+
+
+
+////////////////////////////////////
+// IHV provided Handler functions //
+////////////////////////////////////
+
+
+
+VOID
+WINAPI
+IhvDeinitService
+(
+ VOID
+);
+
+
+
+
+DWORD
+WINAPI
+IhvInitAdapter
+(
+ IN PDOT11_ADAPTER pDot11Adapter,
+ IN HANDLE hDot11SvcHandle,
+ OUT PHANDLE phIhvExtAdapter
+);
+
+
+
+
+VOID
+WINAPI
+IhvDeinitAdapter
+(
+ IN HANDLE hIhvExtAdapter
+);
+
+
+
+
+DWORD
+WINAPI
+IhvProcessSessionChange
+(
+ IN ULONG uEventType,
+ IN PWTSSESSION_NOTIFICATION pSessionNotification
+);
+
+
+
+
+DWORD
+WINAPI
+IhvIsUIRequestPending
+(
+ IN GUID guidUIRequest,
+ OUT PBOOL pbIsRequestPending
+);
+
+
+
+
+DWORD
+WINAPI
+IhvReceiveIndication
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11EXT_IHV_INDICATION_TYPE indicationType,
+ IN ULONG uBufferLength,
+ IN LPVOID pvBuffer
+);
+
+
+
+
+DWORD
+WINAPI
+IhvPerformCapabilityMatch
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDWORD pdwReasonCode
+);
+
+
+
+
+DWORD
+WINAPI
+IhvValidateProfile
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ OUT PDWORD pdwReasonCode
+);
+
+
+
+
+DWORD
+WINAPI
+IhvPerformPreAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN HANDLE hConnectSession,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pIhvConnProfile,
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pIhvSecProfile,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDWORD pdwReasonCode
+);
+
+
+
+
+DWORD
+WINAPI
+IhvPerformPostAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN HANDLE hSecuritySessionID,
+ IN PDOT11_PORT_STATE pPortState,
+ IN ULONG uDot11AssocParamsBytes,
+ IN PDOT11_ASSOCIATION_COMPLETION_PARAMETERS pDot11AssocParams
+);
+
+
+
+
+DWORD
+WINAPI
+IhvAdapterReset
+(
+ IN HANDLE hIhvExtAdapter
+);
+
+
+
+
+DWORD
+WINAPI
+IhvStopPostAssociate
+(
+ IN HANDLE hIhvExtAdapter,
+ IN PDOT11_MAC_ADDRESS pPeer,
+ IN DOT11_ASSOC_STATUS dot11AssocStatus
+);
+
+
+
+
+
+DWORD
+WINAPI
+IhvReceivePacket
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DWORD dwInBufferSize,
+ IN LPVOID pvInBuffer
+);
+
+
+
+
+DWORD
+WINAPI
+IhvCreateDiscoveryProfiles
+(
+ IN HANDLE hIhvExtAdapter,
+ IN BOOL bInsecure,
+ IN PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ IN PDOT11_BSS_LIST pConnectableBssid,
+ OUT PDOT11EXT_IHV_DISCOVERY_PROFILE_LIST pIhvDiscoveryProfileList,
+ OUT PDWORD pdwReasonCode
+);
+
+
+
+
+DWORD
+WINAPI
+IhvProcessUIResponse
+(
+ IN GUID guidUIRequest,
+ IN DWORD dwByteCount,
+ IN LPVOID pvResponseBuffer
+);
+
+
+
+
+DWORD
+WINAPI
+IhvSendPacketCompletion
+(
+ IN HANDLE hSendCompletion
+);
+
+
+
+
+DWORD
+WINAPI
+IhvQueryUIRequest
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11EXT_IHV_CONNECTION_PHASE connectionPhase,
+ OUT PDOT11EXT_IHV_UI_REQUEST* ppIhvUIRequest
+);
+
+
+
+
+DWORD
+WINAPI
+IhvOnexIndicateResult
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DOT11_MSONEX_RESULT msOneXResult,
+ IN PDOT11_MSONEX_RESULT_PARAMS pDot11MsOneXResultParams
+);
+
+
+
+
+DWORD
+WINAPI
+IhvControl
+(
+ IN HANDLE hIhvExtAdapter,
+ IN DWORD dwInBufferSize,
+ IN PBYTE pInBuffer,
+ IN DWORD dwOutBufferSize,
+ OUT PBYTE pOutBuffer,
+ OUT PDWORD pdwBytesReturned
+);
diff --git a/network/wlan/ihvsample/ihvsample.vcxproj b/network/wlan/ihvsample/ihvsample.vcxproj
new file mode 100644
index 00000000..8b0dde8a
--- /dev/null
+++ b/network/wlan/ihvsample/ihvsample.vcxproj
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C2DB15CB-342E-4E84-BFD0-5E839DE380DE}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{D58AEDC0-211B-4E2E-B92B-D297D272865F}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ihvsample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ihvsample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ihvsample</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ihvsample</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);RPC_NO_WINDOWS_H;UNICODE;_UNICODE;NO_STRICT;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;ntdll.lib;advapi32.lib;rpcrt4.lib;uuid.lib;user32.lib;wmip.lib;ole32.lib;oleaut32.lib;ws2_32.lib;..\ihvfrm\$(DDKPlatform)\rc4utils.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>ihvsample.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;ntdll.lib;advapi32.lib;rpcrt4.lib;uuid.lib;user32.lib;wmip.lib;ole32.lib;oleaut32.lib;ws2_32.lib;..\ihvfrm\$(DDKPlatform)\rc4utils.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>ihvsample.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;ntdll.lib;advapi32.lib;rpcrt4.lib;uuid.lib;user32.lib;wmip.lib;ole32.lib;oleaut32.lib;ws2_32.lib;..\ihvfrm\$(DDKPlatform)\rc4utils.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>ihvsample.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;ntdll.lib;advapi32.lib;rpcrt4.lib;uuid.lib;user32.lib;wmip.lib;ole32.lib;oleaut32.lib;ws2_32.lib;..\ihvfrm\$(DDKPlatform)\rc4utils.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>ihvsample.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(WDKContentRoot)\net\wlan\ihvfrm\test\rc4utils</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="adapters.cpp" />
+ <ClCompile Include="ihvonexext.cpp" />
+ <ClCompile Include="ihvsample.cpp" />
+ <ClCompile Include="ihvwep.cpp" />
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="profile.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/wlan/ihvsample/ihvsample.vcxproj.Filters b/network/wlan/ihvsample/ihvsample.vcxproj.Filters
new file mode 100644
index 00000000..7a93e51c
--- /dev/null
+++ b/network/wlan/ihvsample/ihvsample.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{C3AD44B7-58F4-43D6-8928-4E57B6E0C023}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{76ABC86D-F7B4-4BB5-8600-84AEDE01171B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{25477ACB-EF62-4C7A-9AAC-8DF8119A6070}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="adapters.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ihvonexext.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ihvsample.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ihvwep.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="profile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="ihvsample.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/wlan/ihvsample/ihvtimelymachineoruser.xml b/network/wlan/ihvsample/ihvtimelymachineoruser.xml
new file mode 100644
index 00000000..d115ee11
--- /dev/null
+++ b/network/wlan/ihvsample/ihvtimelymachineoruser.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvtimelymachineoruser</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>auto</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ <useOneX>true</useOneX>
+ </authEncryption>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <maxAuthFailures>3</maxAuthFailures>
+ <authMode>machineOrUser</authMode>
+
+ <singleSignOn>
+ <type>postLogon</type>
+ <maxDelay>50</maxDelay>
+ </singleSignOn>
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvtimelyuser.xml b/network/wlan/ihvsample/ihvtimelyuser.xml
new file mode 100644
index 00000000..83af761f
--- /dev/null
+++ b/network/wlan/ihvsample/ihvtimelyuser.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" ?>
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvtimelyuser</name>
+ <SSIDConfig>
+ <SSID>
+ <name>_1x_SSID_</name>
+ </SSID>
+ <nonBroadcast>false</nonBroadcast>
+ </SSIDConfig>
+ <connectionType>ESS</connectionType>
+ <connectionMode>auto</connectionMode>
+ <autoSwitch>false</autoSwitch>
+ <MSM>
+ <security>
+ <authEncryption>
+ <authentication>open</authentication>
+ <encryption>WEP</encryption>
+ <useOneX>true</useOneX>
+ </authEncryption>
+ <OneX xmlns="http://www.microsoft.com/networking/OneX/v1">
+ <maxAuthFailures>3</maxAuthFailures>
+ <authMode>user</authMode>
+ <singleSignOn>
+ <type>postLogon</type>
+ <maxDelay>50</maxDelay>
+ </singleSignOn>
+ <EAPConfig>
+ <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig">
+ <EapMethod>
+ <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type>
+ <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId>
+ <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType>
+ <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId>
+ </EapMethod>
+ <ConfigBlob></ConfigBlob>
+ </EapHostConfig>
+ </EAPConfig>
+ </OneX>
+ </security>
+ </MSM>
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+ </IhvConnectivity>
+ </connectivity>
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+ <IHVUsesFullSecurity>FALSE</IHVUsesFullSecurity>
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+ <IHVSecurityParam2></IHVSecurityParam2>
+ </IhvSecurity>
+ </security>
+ <useMSOneX>true</useMSOneX>
+ </IHV>
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvwep.cpp b/network/wlan/ihvsample/ihvwep.cpp
new file mode 100644
index 00000000..3f4b1c6d
--- /dev/null
+++ b/network/wlan/ihvsample/ihvwep.cpp
@@ -0,0 +1,837 @@
+/*++
+
+Copyright (c) 2005 Microsoft Corporation
+
+Abstract:
+
+ Sample IHV Extensibility DLL to extend
+ 802.11 LWF driver for third party protocols.
+
+
+--*/
+
+#include "precomp.h"
+
+
+
+//
+// UI Request structure to
+// be parsed by IHV UI DLL.
+//
+typedef struct _IHV_UI_REQUEST
+{
+ CHAR szTitle [80];
+ CHAR szHelp [80];
+}
+IHV_UI_REQUEST, *PIHV_UI_REQUEST;
+
+
+DWORD
+ConvertHexCharToNibble
+(
+ CHAR chData,
+ BOOL bUpper,
+ PBYTE pbtData
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BYTE btNibble = 0xF0;
+
+ ASSERT( pbtData );
+
+ if ( (chData >= '0') && (chData <= '9') )
+ {
+ btNibble = (BYTE) (chData - '0');
+ }
+ else if ( (chData >= 'a') && (chData <= 'f') )
+ {
+ btNibble = (BYTE) (chData - 'a') + 0xA;
+ }
+ else if ( (chData >= 'A') && (chData <= 'F') )
+ {
+ btNibble = (BYTE) (chData - 'A') + 0xA;
+ }
+ else
+ {
+ // Wrong type input
+ dwResult = ERROR_BAD_FORMAT;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ ASSERT( btNibble < 0xF0 );
+
+ if ( bUpper )
+ {
+ (*pbtData) = (*pbtData) & 0x0F;
+ (*pbtData) = (*pbtData) | (btNibble << 4);
+ }
+ else
+ {
+ (*pbtData) = (*pbtData) & 0xF0;
+ (*pbtData) = (*pbtData) | btNibble;
+ }
+
+error:
+ return dwResult;
+}
+
+
+// For a 13 byte key, user can choose to input upto 26 hex digits
+
+#define MAX_KEY_STRING_LENGTH 26
+
+#define MAX_RESPONSE_SIZE (( MAX_KEY_STRING_LENGTH + 1 ) * sizeof( WCHAR ) )
+
+//
+// The UI Response is a UNICODE string since
+// the UI module has just passed a BSTR to this
+// module. This UNICODE string needs to converted
+// to a key. Any IHV specific algorithm can be
+// used here.
+//
+
+DWORD
+ConvertStringToKey
+(
+ BYTE* pbKeyData,
+ DWORD* pdwKeyLen
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ HRESULT hr = S_OK;
+ CHAR szKey[ MAX_KEY_STRING_LENGTH + 2 ] = {0};
+ DWORD dwKeyStringLen = 0;
+ DWORD dwIndex = 0;
+
+
+ if
+ (
+ (!pbKeyData) ||
+ (!pdwKeyLen) ||
+ ( 0 == (*pdwKeyLen) ) ||
+ ( (*pdwKeyLen) % sizeof( WCHAR ) )
+ )
+ {
+ dwResult = ERROR_INVALID_PARAMETER;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ dwKeyStringLen = (DWORD) wcslen( (LPWSTR) pbKeyData );
+ if ( MAX_KEY_STRING_LENGTH < dwKeyStringLen )
+ {
+ dwResult = ERROR_BAD_FORMAT;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // Converting the UNICODE string to
+ // ANSI string in scratch pad.
+ hr =
+ StringCchPrintfA
+ (
+ szKey,
+ MAX_KEY_STRING_LENGTH + 1,
+ "%S",
+ (WCHAR*) pbKeyData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ ASSERT( dwKeyStringLen == (DWORD) strlen( szKey ));
+
+
+ if ( ( 5 == dwKeyStringLen ) || ( 13 == dwKeyStringLen ) )
+ {
+ // Copying the ANSI string back to original buffer.
+ hr =
+ StringCchPrintfA
+ (
+ (CHAR*) pbKeyData,
+ (*pdwKeyLen),
+ "%s",
+ szKey
+ );
+ BAIL_ON_FAILURE( hr );
+
+ // The strings are direct representations
+ // of the Wep Key and can be directly returned.
+ (*pdwKeyLen) = dwKeyStringLen;
+
+ TRACE_MESSAGE_VAL( "Received WEP key of length = ", (*pdwKeyLen) );
+
+ BAIL( );
+ }
+
+ if (( 10 != dwKeyStringLen ) && ( 26 != dwKeyStringLen ))
+ {
+ // Wrong length input
+ dwResult = ERROR_BAD_FORMAT;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ for( dwIndex = 0; dwIndex < (dwKeyStringLen / 2); dwIndex++ )
+ {
+ dwResult =
+ ConvertHexCharToNibble
+ (
+ szKey[ 2 * dwIndex ],
+ TRUE,
+ &(pbKeyData[ dwIndex ])
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ dwResult =
+ ConvertHexCharToNibble
+ (
+ szKey[ 1 + (2 * dwIndex) ],
+ FALSE,
+ &(pbKeyData[ dwIndex ])
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ }
+
+ (*pdwKeyLen) = dwKeyStringLen / 2;
+
+ TRACE_MESSAGE_VAL( "Received WEP key of length = ", (*pdwKeyLen) );
+
+error:
+ return WIN32_COMBINED_ERROR( dwResult, hr );
+}
+
+
+
+
+
+//
+// Defining UI help strings. In a realistic
+// implementation these values would be numbers
+// to be interpreted the IHV UI DLL that could
+// be converted to strings using resource files.
+//
+#define UI_TITLE_STRING "Title"
+#define UI_HELP_STRING "Help"
+
+
+
+
+// Send the UI request and wait for the UI response.
+DWORD
+SendUIRequestToReceiveKey
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwKeyLen,
+ BYTE** ppbKeyData
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DOT11EXT_IHV_UI_REQUEST uiRequest = {0};
+ PIHV_UI_REQUEST pIHVRequest = NULL;
+ CHAR szTitle[] = UI_TITLE_STRING;
+ CHAR szHelp[] = UI_HELP_STRING;
+ BOOL bLocked = FALSE;
+ HANDLE hUIResponse = NULL;
+
+
+
+ // CLSID of COM class that implements the UI page. In a real
+ // implementation this GUID could be dynamically obtained.
+ CLSID uiPageClsid =
+ {
+ /* 4A01F9F9-6012-4343-A8C4-10B5DF32672A */
+ 0x4A01F9F9,
+ 0x6012,
+ 0x4343,
+ {0xA8, 0xC4, 0x10, 0xB5, 0xDF, 0x32, 0x67, 0x2A}
+ };
+
+ ASSERT( pAdapterDetails );
+
+ // prepare the IHV request.
+ uiRequest.dwByteCount = sizeof(IHV_UI_REQUEST);
+ uiRequest.pvUIRequest = (BYTE*) PrivateMemoryAlloc( sizeof(IHV_UI_REQUEST) );
+ if ( !(uiRequest.pvUIRequest) )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL( );
+ }
+
+ pIHVRequest = (IHV_UI_REQUEST*)uiRequest.pvUIRequest;
+
+
+ memcpy( pIHVRequest->szTitle , szTitle , sizeof(szTitle) );
+ memcpy( pIHVRequest->szHelp , szHelp , sizeof(szHelp) );
+
+ uiRequest.dwSessionId = WTSGetActiveConsoleSessionId( );
+ uiRequest.UIPageClsid = uiPageClsid;
+
+ // acquire the lock to register the request.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // create new request guid.
+ dwResult = UuidCreate( &(uiRequest.guidUIRequest) );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ // free the existing response.
+ PrivateMemoryFree( pAdapterDetails->pbResponse );
+ pAdapterDetails->pbResponse = NULL;
+
+ // register the guid.
+ pAdapterDetails->currentGuidUIRequest = uiRequest.guidUIRequest;
+
+ // Initializing the event this thread
+ // would be waiting on later.
+ ResetEvent( pAdapterDetails->hUIResponse );
+
+ hUIResponse = pAdapterDetails->hUIResponse;
+
+ // leave the lock since this thread needs
+ // to wait for the response.
+ LeaveCriticalSection( &g_csSynch );
+ bLocked = FALSE;
+
+
+ // send the request.
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSendUIRequest)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ &uiRequest
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Sent UI request to receive key." );
+
+ // Waiting for UI response.
+ // This would be triggered
+ // off if no UI response
+ // is received.
+ dwResult =
+ WaitForSingleObject
+ (
+ hUIResponse,
+ 1000 * 60 * 5 // 5 minutes
+ );
+
+ // acquire the lock - required for both success and failure.
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ ZeroMemory( &(pAdapterDetails->currentGuidUIRequest), sizeof( GUID ) );
+
+ if ( WAIT_OBJECT_0 == dwResult )
+ {
+ dwResult = ERROR_SUCCESS;
+ }
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ if ( NULL == pAdapterDetails->pbResponse )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+
+ // At this point in the code a response
+ // has been received, and the thread
+ // has not been aborted.
+
+ (*ppbKeyData) = pAdapterDetails->pbResponse;
+ pAdapterDetails->pbResponse = NULL;
+
+ (*pdwKeyLen) = pAdapterDetails->dwResponseLen;
+
+
+ // Convert the Unicode string to ASCII.
+ dwResult =
+ ConvertStringToKey
+ (
+ *ppbKeyData,
+ pdwKeyLen
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ pAdapterDetails->bModifyCurrentProfile = TRUE;
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ PrivateMemoryFree( uiRequest.pvUIRequest );
+ return dwResult;
+}
+
+
+//
+// Key index limits.
+//
+#define MIN_KEY_INDEX 0
+#define MAX_KEY_INDEX 3
+
+
+//
+// Perform Wep based pre-association once the key is known.
+//
+DWORD
+WINAPI
+DoWepPreAssociateCommon
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD dwKeyLen,
+ BYTE* pbKeyData,
+ DWORD* pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ LONG lIndex = 0;
+ PDOT11_CIPHER_DEFAULT_KEY_VALUE pKey = 0;
+ ULONG uLen = 0;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( dwKeyLen );
+ ASSERT( pbKeyData );
+ ASSERT( pdwReasonCode );
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_OUTOFMEMORY;
+
+ uLen = FIELD_OFFSET(DOT11_CIPHER_DEFAULT_KEY_VALUE, ucKey) + dwKeyLen * sizeof(UCHAR);
+ pKey = (PDOT11_CIPHER_DEFAULT_KEY_VALUE) PrivateMemoryAlloc(uLen);
+ if (!pKey)
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+ CopyMemory( &(pKey->ucKey), pbKeyData, dwKeyLen );
+
+ // Prepare the key.
+ pKey->AlgorithmId = DOT11_CIPHER_ALGO_WEP;
+ pKey->usKeyLength = (USHORT) dwKeyLen;
+ pKey->bStatic = TRUE;
+ pKey->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pKey->Header.Revision = DOT11_CIPHER_DEFAULT_KEY_VALUE_REVISION_1;
+ pKey->Header.Size = sizeof(DOT11_CIPHER_DEFAULT_KEY_VALUE);
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_INVALID_STATE;
+
+ if ( nic_state_pre_assoc_started != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_HARDWARE_FAILURE;
+
+ // plumb the settings and keys down.
+
+ TRACE_MESSAGE( "Setting Auth Algorithm." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetAuthAlgorithm)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ DOT11_AUTH_ALGO_80211_OPEN
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Setting Unicast cipher algorithm." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetUnicastCipherAlgorithm)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ DOT11_CIPHER_ALGO_WEP
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ TRACE_MESSAGE( "Setting exclude unencrypted flag." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetExcludeUnencrypted)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ TRUE
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ for ( lIndex = MAX_KEY_INDEX; lIndex >= MIN_KEY_INDEX; lIndex-- )
+ {
+ pKey->uKeyIndex = lIndex;
+
+ TRACE_MESSAGE( "Setting default key." );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetDefaultKey)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ pKey,
+ DOT11_DIR_BOTH
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ TRACE_MESSAGE( "Setting default key ID." );
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetDefaultKeyId)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ 0
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+
+ // Verified before, just after acquiring lock.
+ ASSERT( nic_state_pre_assoc_started == pAdapterDetails->NicState );
+
+ pAdapterDetails->NicState = nic_state_pre_assoc_ended;
+
+ // Reason code is set to SUCCESS.
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+ // register the post-association handlers with the adapter.
+
+ pAdapterDetails->pPerformPostAssociateCompletionRoutine = DoWepPostAssociate;
+ pAdapterDetails->pPerformPostAssociateRoutine = NULL;
+ pAdapterDetails->pStopPostAssociateRoutine = NULL;
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ PrivateMemoryFree( pKey );
+ return dwResult;
+}
+
+
+// Pre-association when the profile does not have the key.
+DWORD
+WINAPI
+DoMissingKeyWepPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwKeyLen = ERROR_SUCCESS;
+ BYTE* pbKeyData = NULL;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pdwReasonCode );
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_BAD_USER_KEY;
+
+ // Possible enhancement - try to call Dot11ExtGetProfileCustomUserData
+ // function in IHV Framework to see if the key is
+ // available there. Else, send UI Request.
+
+
+ // try to obtain the key through an UI request.
+ dwResult =
+ SendUIRequestToReceiveKey
+ (
+ pAdapterDetails,
+ &dwKeyLen,
+ &pbKeyData
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+ ASSERT ( pbKeyData );
+ ASSERT ( dwKeyLen );
+
+ // use the key for connection.
+ dwResult =
+ DoWepPreAssociateCommon
+ (
+ pAdapterDetails,
+ dwKeyLen,
+ pbKeyData,
+ pdwReasonCode
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+
+ // Possible enhancement - try to call Dot11ExtSetProfileCustomUserData
+ // to store the key if the key was obtained by a UI request.
+
+error:
+ PrivateMemoryFree( pbKeyData );
+ return dwResult;
+}
+
+
+
+
+
+
+
+// Pre-association when the profile does have the key.
+DWORD
+WINAPI
+DoWepPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ BOOL bLocked = FALSE;
+ DWORD dwKeyLen = ERROR_SUCCESS;
+ CHAR szKey[MAX_RESPONSE_SIZE+1] = {0};
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pdwReasonCode );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_BAD_USER_KEY;
+
+ if
+ (
+ (!( pAdapterDetails->pConnectivityProfile )) ||
+ (!( pAdapterDetails->pConnectivityProfile->pszParam2 )) ||
+ ( 0 == pAdapterDetails->pConnectivityProfile->pszParam2[0] )
+ )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+ // Convert the profile string to a usable key.
+ dwKeyLen = (DWORD)wcslen( pAdapterDetails->pConnectivityProfile->pszParam2 );
+ dwKeyLen = sizeof(WCHAR) * ( 1 + dwKeyLen );
+
+ if ( dwKeyLen > sizeof( szKey ) )
+ {
+ dwResult = ERROR_BAD_PROFILE;
+ BAIL_ON_WIN32_ERROR(dwResult);
+ }
+
+
+ // Copy string.
+ CopyMemory
+ (
+ (BYTE*) szKey,
+ pAdapterDetails->pConnectivityProfile->pszParam2,
+ dwKeyLen
+ );
+
+ // Convert UNICODE to ASCII.
+ dwResult =
+ ConvertStringToKey
+ (
+ (BYTE*) szKey,
+ &dwKeyLen
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ ASSERT ( dwKeyLen );
+
+
+ // Do pre-association with the key in the profile.
+ dwResult =
+ DoWepPreAssociateCommon
+ (
+ pAdapterDetails,
+ dwKeyLen,
+ (BYTE*) szKey,
+ pdwReasonCode
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+
+
+extern
+DOT11EXT_IHV_DISCOVERY_PROFILE
+g_IhvDiscoveryProfiles[];
+
+
+//
+// This function is responsible for the post association
+// operations and completing the post association call
+// for WEP scenario.
+//
+DWORD
+WINAPI
+DoWepPostAssociate
+(
+ LPVOID pvPostAssociate
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwStatus = ERROR_SUCCESS;
+ DWORD dwReasonCode = L2_REASON_CODE_IHV_INVALID_STATE;
+ BOOL bLocked = FALSE;
+ PPOST_ASSOC_DATA ppostAssocData = (PPOST_ASSOC_DATA) pvPostAssociate;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+
+
+ ASSERT( ppostAssocData );
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ ppostAssocData->hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ if ( nic_state_post_assoc_started != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ // This could be an appropriate place to modify the current profile
+
+ if ( pAdapterDetails->bModifyCurrentProfile )
+ {
+ pAdapterDetails->bModifyCurrentProfile = FALSE;
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtSetCurrentProfile)
+ (
+ pAdapterDetails->hDot11SvcHandle,
+ pAdapterDetails->hConnectSession,
+ &(g_IhvDiscoveryProfiles[1].IhvConnectivityProfile),
+ &(g_IhvDiscoveryProfiles[1].IhvSecurityProfile)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+
+ // In wep connection case, function only changes the adapter state.
+ pAdapterDetails->NicState = nic_state_post_assoc_ended;
+
+
+ // Reason Code is set to success.
+ dwReasonCode = L2_REASON_CODE_SUCCESS;
+
+error:
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( ppostAssocData->hIhvExtAdapter );
+ }
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+
+ // call completion function.
+ dwStatus =
+ (g_pDot11ExtApi->Dot11ExtPostAssociateCompletion)
+ (
+ ppostAssocData->hDot11SvcHandle,
+ ppostAssocData->hSecuritySessionId,
+ NULL,
+ dwReasonCode,
+ dwResult
+ );
+ if ( ERROR_SUCCESS != dwStatus )
+ {
+ // IHV specific logging can happen here.
+ }
+ PrivateMemoryFree( ppostAssocData );
+ return dwResult;
+}
+
+
+// no op function for preassociation when
+// ihv is used only for connectivity. in a
+// realistic implementation there would probably
+// be calls to Dot11ExtNicSpecificExtension
+// in this function to prepare the driver for
+// additional connectivity settings.
+DWORD
+WINAPI
+DoIhvConnPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwKeyLen = 0;
+ PBYTE pbKeyData = NULL;
+ BOOL bLocked = FALSE;
+
+ ASSERT( pAdapterDetails );
+ ASSERT( pdwReasonCode );
+
+ // try to send UI request to obtain some data that could be useful here.
+ // the sample does not really use the data.
+ dwResult =
+ SendUIRequestToReceiveKey
+ (
+ pAdapterDetails,
+ &dwKeyLen,
+ &pbKeyData
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ ASSERT ( pbKeyData );
+
+ PrivateMemoryFree( pbKeyData );
+ pbKeyData = NULL;
+
+ // try to send UI request to obtain some data that could be useful here.
+ // the sample does not really use the data.
+ dwResult =
+ SendUIRequestToReceiveKey
+ (
+ pAdapterDetails,
+ &dwKeyLen,
+ &pbKeyData
+ );
+ BAIL_ON_WIN32_ERROR(dwResult);
+ ASSERT ( pbKeyData );
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ // Reason code is set before making calls that could fail.
+ (*pdwReasonCode) = L2_REASON_CODE_IHV_INVALID_STATE;
+
+ if ( nic_state_pre_assoc_started != pAdapterDetails->NicState )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ pAdapterDetails->NicState = nic_state_pre_assoc_ended;
+
+ // Reason code is set to SUCCESS.
+ (*pdwReasonCode) = L2_REASON_CODE_SUCCESS;
+
+ pAdapterDetails->pPerformPostAssociateCompletionRoutine = NULL;
+ pAdapterDetails->pPerformPostAssociateRoutine = NULL;
+ pAdapterDetails->pStopPostAssociateRoutine = NULL;
+
+error:
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ PrivateMemoryFree( pbKeyData );
+ return dwResult;
+}
diff --git a/network/wlan/ihvsample/ihvwep.h b/network/wlan/ihvsample/ihvwep.h
new file mode 100644
index 00000000..d8aabe71
--- /dev/null
+++ b/network/wlan/ihvsample/ihvwep.h
@@ -0,0 +1,62 @@
+
+//
+// Structure to marshal information for
+// postassociation thread.
+//
+typedef
+struct _POST_ASSOC_DATA
+{
+ HANDLE hIhvExtAdapter;
+ HANDLE hDot11SvcHandle;
+ HANDLE hSecuritySessionId;
+}
+POST_ASSOC_DATA, *PPOST_ASSOC_DATA;
+
+
+// Pre-association when the profile does have the key.
+DWORD
+WINAPI
+DoWepPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+);
+
+
+// Pre-association when the profile does not have the key.
+DWORD
+WINAPI
+DoMissingKeyWepPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+);
+
+
+// no op function for preassociation when
+// ihv is used only for connectivity. in a
+// realistic implementation there would probably
+// be calls to Dot11ExtNicSpecificExtension
+// in this function to prepare the driver for
+// additional connectivity settings.
+DWORD
+WINAPI
+DoIhvConnPreAssociate
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+);
+
+
+// This function is responsible for the post association
+// operations and completing the post association call
+// for WEP scenario.
+DWORD
+WINAPI
+DoWepPostAssociate
+(
+ LPVOID pvPostAssociate
+);
+
+
+
diff --git a/network/wlan/ihvsample/ihvwep1.xml b/network/wlan/ihvsample/ihvwep1.xml
new file mode 100644
index 00000000..2e4403f9
--- /dev/null
+++ b/network/wlan/ihvsample/ihvwep1.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvwep1</name>
+
+ <SSIDConfig>
+ <SSID>
+ <name>_SSID_</name>
+ </SSID>
+ </SSIDConfig>
+
+ <connectionType>ESS</connectionType>
+ <connectionMode>manual</connectionMode>
+
+ <MSM>
+ <connectivity>
+ </connectivity>
+
+ </MSM>
+
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+
+ <IHVConnectivityParam2></IHVConnectivityParam2>
+
+ </IhvConnectivity>
+ </connectivity>
+
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+
+ <IHVUsesFullSecurity>TRUE</IHVUsesFullSecurity>
+
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+
+ <IHVSecurityParam2></IHVSecurityParam2>
+
+ </IhvSecurity>
+ </security>
+ </IHV>
+
+</WLANProfile>
diff --git a/network/wlan/ihvsample/ihvwep2.xml b/network/wlan/ihvsample/ihvwep2.xml
new file mode 100644
index 00000000..32b538ba
--- /dev/null
+++ b/network/wlan/ihvsample/ihvwep2.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
+ <name>ihvwep2</name>
+
+ <SSIDConfig>
+ <SSID>
+ <name>_SSID_</name>
+ </SSID>
+ </SSIDConfig>
+
+ <connectionType>ESS</connectionType>
+ <connectionMode>manual</connectionMode>
+
+ <MSM>
+ <connectivity>
+ </connectivity>
+
+ </MSM>
+
+ <IHV>
+ <OUIHeader>
+ <OUI>123456</OUI>
+ <type>01</type>
+ </OUIHeader>
+
+ <connectivity>
+ <IhvConnectivity xmlns="http://www.someihv.com/nwifi/profile">
+
+ <IHVConnectivityParam1>0</IHVConnectivityParam1>
+
+ <IHVConnectivityParam2>_KEY_</IHVConnectivityParam2>
+
+ </IhvConnectivity>
+ </connectivity>
+
+ <security>
+ <IhvSecurity xmlns="http://www.someihv.com/nwifi/profile">
+
+ <IHVUsesFullSecurity>TRUE</IHVUsesFullSecurity>
+
+ <IHVAuthentication>IHVAuthV1</IHVAuthentication>
+
+ <IHVEncryption>IHVCipher1</IHVEncryption>
+
+ <IHVSecurityParam1>0</IHVSecurityParam1>
+
+ <IHVSecurityParam2></IHVSecurityParam2>
+
+ </IhvSecurity>
+ </security>
+ </IHV>
+
+</WLANProfile>
diff --git a/network/wlan/ihvsample/precomp.h b/network/wlan/ihvsample/precomp.h
new file mode 100644
index 00000000..244ad664
--- /dev/null
+++ b/network/wlan/ihvsample/precomp.h
@@ -0,0 +1,36 @@
+
+#ifndef __WLAN_IHV_SAMPLE_PRECOMP_H__
+#define __WLAN_IHV_SAMPLE_PRECOMP_H__
+
+
+#pragma once
+
+#include <driverspecs.h>
+_Analysis_mode_(_Analysis_code_type_user_code_)
+
+
+#include <windows.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <strsafe.h>
+#include <rpc.h>
+#include <Winsock2.h>
+#include <wlanihv.h>
+#include <objbase.h>
+
+#include "profile.h"
+#include "utils.h"
+#include "ihvwep.h"
+#include "ihvonexext.h"
+#include "adapters.h"
+#include "rc4utils.h"
+#include "ihvsample.h"
+
+#ifdef __cplusplus
+#include <new>
+#endif
+
+
+
+#endif // __WLAN_IHV_SAMPLE_PRECOMP_H__
+
diff --git a/network/wlan/ihvsample/precompsrc.c b/network/wlan/ihvsample/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/network/wlan/ihvsample/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/network/wlan/ihvsample/profile.cpp b/network/wlan/ihvsample/profile.cpp
new file mode 100644
index 00000000..c6988990
--- /dev/null
+++ b/network/wlan/ihvsample/profile.cpp
@@ -0,0 +1,1222 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+
+
+
+//
+// Free BSTR
+//
+#define SYS_FREE_STRING( _s ) \
+ if ( _s ) \
+ { \
+ SysFreeString( _s ); \
+ (_s) = NULL; \
+ } \
+
+
+//
+// Release interface.
+//
+#define RELEASE_INTERFACE( _p ) \
+ if ( _p ) \
+ { \
+ (_p)->Release( ); \
+ (_p) = NULL; \
+ } \
+
+
+// XPath strings for parsing xml blobs,
+
+#define CON_PARAM1_XPATH L"/IhvConnectivity/IHVConnectivityParam1"
+#define CON_PARAM2_XPATH L"/IhvConnectivity/IHVConnectivityParam2"
+
+
+#define SEC_FSFLAG_XPATH L"/IhvSecurity/IHVUsesFullSecurity"
+#define SEC_ATYPE_XPATH L"/IhvSecurity/IHVAuthentication"
+#define SEC_ETYPE_XPATH L"/IhvSecurity/IHVEncryption"
+#define SEC_PARAM1_XPATH L"/IhvSecurity/IHVSecurityParam1"
+#define SEC_PARAM2_XPATH L"/IhvSecurity/IHVSecurityParam2"
+
+
+// Strings to match the profile with internal data types.
+LPCWSTR
+gppszIhvAuthTypes[] =
+{
+ L"IHVAuthV1",
+ L"IHVAuthV2",
+ L"IHVAuthV3"
+};
+
+
+LPCWSTR
+gppszIhvCipherTypes[] =
+{
+ L"None",
+ L"IHVCipher1",
+ L"IHVCipher2",
+ L"IHVCipher3"
+};
+
+
+//
+// Base class for profile APIs.
+//
+class CIhvProfileBase
+{
+public:
+
+ // Constructor
+ CIhvProfileBase( )
+ {
+ m_pRootNode = NULL;
+ }
+
+ // Destructor
+ ~CIhvProfileBase( )
+ {
+ RELEASE_INTERFACE( m_pRootNode );
+ }
+
+ HRESULT
+ LoadXml
+ (
+ IN BSTR bstrIhvProfile
+ );
+
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the free( ) function.
+ virtual
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ )
+ = 0;
+
+protected:
+
+ HRESULT
+ GetTextFromNode
+ (
+ IN LPCWSTR pszQuery,
+ OUT BSTR* pbstrText
+ );
+
+
+ IXMLDOMElement* m_pRootNode;
+
+};
+
+
+
+
+
+//
+// Derived class for connectivity profiles.
+//
+class CIhvConnectivityProfile : public CIhvProfileBase
+{
+
+public:
+
+ // Constructor Destructor
+ CIhvConnectivityProfile( ) { }
+ ~CIhvConnectivityProfile( ) { }
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the PrivateMemoryFree( ) function.
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ );
+
+
+ // Accessor dwParam1
+ HRESULT
+ GetParam1
+ (
+ DWORD* pdwParam1
+ );
+
+
+ // Accessor for pszParam2
+ HRESULT
+ GetParam2
+ (
+ BSTR* pbstrValue
+ );
+
+
+};
+
+
+
+
+
+
+//
+// Derived class for security profiles.
+//
+
+class CIhvSecurityProfile
+ : public CIhvProfileBase
+{
+
+public:
+
+ // Constructor Destructor
+ CIhvSecurityProfile( ) { }
+ ~CIhvSecurityProfile( ) { }
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the PrivateMemoryFree( ) function.
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ );
+
+
+ // Accessor and Modifier for bUseFullSecurity
+ HRESULT
+ GetFullSecurityFlag
+ (
+ BOOL* pbUseFullSecurity
+ );
+
+
+ // Accessor for AuthType
+ HRESULT
+ GetAuthType
+ (
+ PIHV_AUTH_TYPE pAuthType
+ );
+
+ // Accessor for CipherType
+ HRESULT
+ GetCipherType
+ (
+ PIHV_CIPHER_TYPE pCipherType
+ );
+
+ // Accessor for dwParam1
+ HRESULT
+ GetParam1
+ (
+ DWORD* pdwParam1
+ );
+
+ // Accessor for pszParam2
+ HRESULT
+ GetParam2
+ (
+ BSTR* pbstrValue
+ );
+
+};
+
+
+// Convert unicode string to BSTR. NULL safe.
+HRESULT
+Wstr2Bstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pbstrDest) = NULL;
+ if ( !pszSrc )
+ {
+ BAIL( );
+ }
+
+ (*pbstrDest) = SysAllocString( pszSrc );
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+
+
+// Convert unicode string to unicode string. NULL safe.
+// string allocated by malloc and freed by free.
+HRESULT
+Wstr2Wstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ LPWSTR* ppszDest
+)
+{
+ HRESULT hr = S_OK;
+ size_t len = 0;
+
+ if ( !ppszDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*ppszDest) = NULL;
+ if ( !pszSrc )
+ {
+ BAIL( );
+ }
+
+ len = 1 + wcslen( pszSrc );
+ len *= sizeof( WCHAR );
+
+ (*ppszDest) = (LPWSTR) PrivateMemoryAlloc( len );
+ if ( !(*ppszDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ CopyMemory( (*ppszDest), pszSrc, len );
+
+error:
+ return hr;
+}
+
+
+
+//
+// convert unicode string to DWORD
+//
+HRESULT
+Wstr2Dword
+(
+ _In_ LPCWSTR pszSrc,
+ _Out_ DWORD* pdwDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( (!pdwDest) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pdwDest) = (DWORD) _wtol( pszSrc );
+
+error:
+ return hr;
+}
+
+
+
+
+//
+// convert unicode string to BOOL
+//
+HRESULT
+Wstr2Bool
+(
+ _In_ LPCWSTR pszSrc,
+ _Out_ BOOL* pbDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( (!pbDest) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( 0 == wcscmp( L"TRUE", pszSrc ) )
+ {
+ (*pbDest) = TRUE;
+ }
+ else if ( 0 == wcscmp( L"FALSE", pszSrc ) )
+ {
+ (*pbDest) = FALSE;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+
+
+
+
+
+//
+// convert unicode string to auth type
+//
+HRESULT
+Wstr2AuthType
+(
+ _In_ LPCWSTR pszSrc,
+ _Out_ PIHV_AUTH_TYPE pAuthType
+)
+{
+ HRESULT hr = S_OK;
+ DWORD dwIndex = 0;
+
+ if ( (!pAuthType) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ for ( dwIndex = 0; dwIndex < MAX_AUTH_TYPES; dwIndex++ )
+ {
+ if ( 0 == wcscmp( gppszIhvAuthTypes[dwIndex], pszSrc ) )
+ {
+ (*pAuthType) = (IHV_AUTH_TYPE) dwIndex;
+ BAIL( );
+ }
+ }
+
+ // String not found.
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+
+
+
+
+
+//
+// convert unicode string to cipher type
+//
+HRESULT
+Wstr2CipherType
+(
+ _In_ LPCWSTR pszSrc,
+ _Out_ PIHV_CIPHER_TYPE pCipherType
+)
+{
+ HRESULT hr = S_OK;
+ DWORD dwIndex = 0;
+
+ if ( (!pCipherType) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ for ( dwIndex = 0; dwIndex < MAX_CIPHER_TYPES; dwIndex++ )
+ {
+ if ( 0 == wcscmp( gppszIhvCipherTypes[dwIndex], pszSrc ) )
+ {
+ (*pCipherType) = (IHV_CIPHER_TYPE) dwIndex;
+ BAIL( );
+ }
+ }
+
+ // String not found.
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+
+
+// base function to obtain text from
+// node described by XPATH.
+HRESULT
+CIhvProfileBase::GetTextFromNode
+(
+ IN LPCWSTR pszQuery,
+ OUT BSTR* pbstrText
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrQuery = NULL;
+ IXMLDOMNode* pQueryNode = NULL;
+
+ ASSERT( pszQuery );
+ ASSERT( pbstrText );
+
+ // if node is NULL, return empty string.
+ if ( !m_pRootNode )
+ {
+ hr =
+ Wstr2Bstr
+ (
+ L"",
+ pbstrText
+ );
+ BAIL( );
+ }
+
+ hr =
+ Wstr2Bstr
+ (
+ pszQuery,
+ &bstrQuery
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr = m_pRootNode->selectSingleNode( bstrQuery, &pQueryNode );
+ BAIL_ON_FAILURE( hr );
+
+ if (!pQueryNode)
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr = pQueryNode->get_text( pbstrText );
+ BAIL_ON_FAILURE( hr );
+
+ if ( !(*pbstrText) )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ RELEASE_INTERFACE( pQueryNode );
+ SYS_FREE_STRING( bstrQuery );
+ return hr;
+}
+
+
+
+// Load node from xml string. If xml string is null this
+// function is a NO_OP.
+HRESULT
+CIhvProfileBase::LoadXml
+(
+ IN BSTR bstrIhvProfile
+)
+{
+ HRESULT hr = S_OK;
+ IXMLDOMDocument* pDOMDoc = NULL;
+ IXMLDOMElement* pDocElem = NULL;
+ VARIANT_BOOL vfSuccess;
+
+ if ( m_pRootNode )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( !bstrIhvProfile )
+ {
+ BAIL( );
+ }
+
+ hr =
+ CoCreateInstance
+ (
+ CLSID_DOMDocument,
+ NULL,
+ CLSCTX_ALL,
+ IID_IXMLDOMDocument,
+ (LPVOID *) &pDOMDoc
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pDOMDoc->loadXML
+ (
+ bstrIhvProfile,
+ &vfSuccess
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( VARIANT_TRUE != vfSuccess )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ pDOMDoc->get_documentElement
+ (
+ &pDocElem
+ );
+ BAIL_ON_FAILURE( hr );
+
+ // Caching the pointer to the document element
+ // in a member variable.
+ m_pRootNode = pDocElem;
+ pDocElem = NULL;
+
+
+error:
+ RELEASE_INTERFACE( pDOMDoc );
+ RELEASE_INTERFACE( pDocElem );
+ return hr;
+}
+
+
+
+
+
+// Accessor.
+HRESULT
+CIhvConnectivityProfile::GetParam1
+(
+ DWORD* pdwParam1
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ CON_PARAM1_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrData )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Dword
+ (
+ bstrData,
+ pdwParam1
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+
+// Accessor.
+HRESULT
+CIhvConnectivityProfile::GetParam2
+(
+ BSTR* pbstrValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ GetTextFromNode
+ (
+ CON_PARAM2_XPATH,
+ pbstrValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+
+
+//
+// Calls the accessors to build native data.
+//
+HRESULT
+CIhvConnectivityProfile::GetNativeData
+(
+ LPVOID* ppvData
+)
+{
+ HRESULT hr = S_OK;
+ PIHV_CONNECTIVITY_PROFILE pIhvProfile = NULL;
+ BSTR bstrParam2 = NULL;
+
+ if ( !ppvData )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ pIhvProfile = (PIHV_CONNECTIVITY_PROFILE) PrivateMemoryAlloc( sizeof( IHV_CONNECTIVITY_PROFILE ) );
+ if ( !pIhvProfile )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ // Ignoring errors since structure is already
+ // populated with defaults.
+
+ hr =
+ GetParam2
+ (
+ &bstrParam2
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrParam2 )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Wstr
+ (
+ bstrParam2,
+ &(pIhvProfile->pszParam2)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetParam1
+ (
+ &(pIhvProfile->dwParam1)
+ );
+
+ // Consuming earlier failures.
+ hr = S_OK;
+
+ // Transfering local cache to OUT parameter.
+ (*ppvData) = pIhvProfile;
+ pIhvProfile = NULL;
+
+error:
+ if ( pIhvProfile )
+ {
+ PrivateMemoryFree( pIhvProfile->pszParam2 ); // NULL Safe.
+ PrivateMemoryFree( pIhvProfile );
+ }
+ SYS_FREE_STRING( bstrParam2 );
+ return hr;
+}
+
+
+
+
+
+// Accessor.
+HRESULT
+CIhvSecurityProfile::GetFullSecurityFlag
+(
+ BOOL* pbUseFullSecurity
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_FSFLAG_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrData )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Bool
+ (
+ bstrData,
+ pbUseFullSecurity
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+
+
+
+// Accessor.
+HRESULT
+CIhvSecurityProfile::GetAuthType
+(
+ PIHV_AUTH_TYPE pAuthType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_ATYPE_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrData )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2AuthType
+ (
+ bstrData,
+ pAuthType
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+
+
+// Accessor.
+HRESULT
+CIhvSecurityProfile::GetCipherType
+(
+ PIHV_CIPHER_TYPE pCipherType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_ETYPE_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrData )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2CipherType
+ (
+ bstrData,
+ pCipherType
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+
+
+
+// Accessor.
+HRESULT
+CIhvSecurityProfile::GetParam1
+(
+ DWORD* pdwParam1
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_PARAM1_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrData )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Dword
+ (
+ bstrData,
+ pdwParam1
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+
+
+
+
+// Accessor.
+HRESULT
+CIhvSecurityProfile::GetParam2
+(
+ BSTR* pbstrValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_PARAM2_XPATH,
+ pbstrValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+//
+// Calls the accessors to build native data.
+//
+HRESULT
+CIhvSecurityProfile::GetNativeData
+(
+ LPVOID* ppvData
+)
+{
+ HRESULT hr = S_OK;
+ PIHV_SECURITY_PROFILE pIhvProfile = NULL;
+ BSTR bstrParam2 = NULL;
+
+ if ( !ppvData )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ pIhvProfile = (PIHV_SECURITY_PROFILE) PrivateMemoryAlloc( sizeof( IHV_SECURITY_PROFILE ) );
+ if ( !pIhvProfile )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ pIhvProfile->bUseIhvConnectivityOnly = ( m_pRootNode == NULL );
+
+ // Ignoring errors since structure is already
+ // populated with defaults.
+ hr =
+ GetFullSecurityFlag
+ (
+ &(pIhvProfile->bUseFullSecurity)
+ );
+
+ hr =
+ GetAuthType
+ (
+ &(pIhvProfile->AuthType)
+ );
+
+ hr =
+ GetCipherType
+ (
+ &(pIhvProfile->CipherType)
+ );
+
+ hr =
+ GetParam1
+ (
+ &(pIhvProfile->dwParam1)
+ );
+
+ hr =
+ GetParam2
+ (
+ &bstrParam2
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrParam2 )
+ {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Wstr
+ (
+ bstrParam2,
+ &(pIhvProfile->pszParam2)
+ );
+
+ // Consuming earlier failures.
+ hr = S_OK;
+
+ // Transfering local cache to OUT parameter.
+ (*ppvData) = pIhvProfile;
+ pIhvProfile = NULL;
+
+error:
+ if ( pIhvProfile )
+ {
+ PrivateMemoryFree( pIhvProfile->pszParam2 ); // NULL Safe.
+ PrivateMemoryFree( pIhvProfile );
+ }
+ SYS_FREE_STRING( bstrParam2 );
+ return hr;
+}
+
+
+// Converts string to connectivity profile.
+DWORD
+GetIhvConnectivityProfile
+(
+ PDOT11EXT_IHV_CONNECTIVITY_PROFILE pDot11ExtIhvConnProfile,
+ PIHV_CONNECTIVITY_PROFILE* ppConnectivityProfile
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bComInitialized = FALSE;
+ BSTR bstrIhvProfile = NULL;
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile = NULL;
+
+ CIhvConnectivityProfile* pIhvProfile = NULL;
+
+ ASSERT( pDot11ExtIhvConnProfile );
+ ASSERT( ppConnectivityProfile );
+
+
+ // Data structure is multi-thread safe because
+ // it is both allocated and freed by current
+ // function.
+ hr =
+ CoInitializeEx
+ (
+ NULL,
+ COINIT_MULTITHREADED
+ );
+ BAIL_ON_FAILURE( hr );
+ bComInitialized = TRUE;
+
+
+ pIhvProfile = new(std::nothrow) CIhvConnectivityProfile;
+ if (!pIhvProfile)
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Bstr
+ (
+ pDot11ExtIhvConnProfile->pszXmlFragmentIhvConnectivity,
+ &bstrIhvProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pIhvProfile->LoadXml
+ (
+ bstrIhvProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pIhvProfile->GetNativeData
+ (
+ (LPVOID*) &pConnectivityProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+ (*ppConnectivityProfile) = pConnectivityProfile;
+ pConnectivityProfile = NULL;
+
+
+error:
+ SYS_FREE_STRING( bstrIhvProfile );
+
+ FreeIhvConnectivityProfile ( &pConnectivityProfile );
+
+ delete pIhvProfile;
+
+ if ( bComInitialized )
+ {
+ CoUninitialize( );
+ }
+ return WIN32_FROM_HRESULT( hr );
+}
+
+
+
+
+// free connectivity profile.
+
+VOID
+FreeIhvConnectivityProfile
+(
+ PIHV_CONNECTIVITY_PROFILE* ppConnectivityProfile
+)
+{
+ if ( ppConnectivityProfile && (*ppConnectivityProfile) )
+ {
+ PrivateMemoryFree( (*ppConnectivityProfile)->pszParam2 );
+ PrivateMemoryFree( (*ppConnectivityProfile) );
+ (*ppConnectivityProfile) = NULL;
+ }
+}
+
+
+// Converts string to security profile.
+DWORD
+GetIhvSecurityProfile
+(
+ PDOT11EXT_IHV_SECURITY_PROFILE pDot11ExtIhvSecProfile,
+ PIHV_SECURITY_PROFILE* ppSecurityProfile
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bComInitialized = FALSE;
+ BSTR bstrIhvProfile = NULL;
+ PIHV_SECURITY_PROFILE pSecurityProfile = NULL;
+
+ CIhvSecurityProfile* pIhvProfile = NULL;
+
+ ASSERT( pDot11ExtIhvSecProfile );
+ ASSERT( ppSecurityProfile );
+
+
+ // Data structure is multi-thread safe because
+ // it is both allocated and freed by current
+ // function.
+ hr =
+ CoInitializeEx
+ (
+ NULL,
+ COINIT_MULTITHREADED
+ );
+ BAIL_ON_FAILURE( hr );
+ bComInitialized = TRUE;
+
+
+
+ pIhvProfile = new(std::nothrow) CIhvSecurityProfile;
+ if (!pIhvProfile)
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Bstr
+ (
+ pDot11ExtIhvSecProfile->pszXmlFragmentIhvSecurity,
+ &bstrIhvProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pIhvProfile->LoadXml
+ (
+ bstrIhvProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pIhvProfile->GetNativeData
+ (
+ (LPVOID*) &pSecurityProfile
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( pDot11ExtIhvSecProfile->bUseMSOnex && pSecurityProfile->bUseFullSecurity )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*ppSecurityProfile) = pSecurityProfile;
+ pSecurityProfile = NULL;
+
+
+error:
+ SYS_FREE_STRING( bstrIhvProfile );
+
+ FreeIhvSecurityProfile ( &pSecurityProfile );
+
+ delete pIhvProfile;
+
+ if ( bComInitialized )
+ {
+ CoUninitialize( );
+ }
+ return WIN32_FROM_HRESULT( hr );
+}
+
+
+
+
+
+// free security profile.
+VOID
+FreeIhvSecurityProfile
+(
+ PIHV_SECURITY_PROFILE* ppSecurityProfile
+)
+{
+ if ( ppSecurityProfile && (*ppSecurityProfile) )
+ {
+ PrivateMemoryFree( (*ppSecurityProfile)->pszParam2 );
+ PrivateMemoryFree( (*ppSecurityProfile) );
+ (*ppSecurityProfile) = NULL;
+ }
+}
diff --git a/network/wlan/ihvsample/profile.h b/network/wlan/ihvsample/profile.h
new file mode 100644
index 00000000..cf676908
--- /dev/null
+++ b/network/wlan/ihvsample/profile.h
@@ -0,0 +1,108 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#pragma once
+
+#ifndef _IHVSAMPLEPROFILE_H
+#define _IHVSAMPLEPROFILE_H
+
+
+
+#define MAX_AUTH_TYPES 3
+
+
+// IHV Auth types
+typedef enum _IHV_AUTH_TYPE
+{
+ IHVAuthV1,
+ IHVAuthV2,
+ IHVAuthV3,
+ IHVAuthInvalid
+}
+IHV_AUTH_TYPE, *PIHV_AUTH_TYPE;
+
+
+#define MAX_CIPHER_TYPES 4
+
+
+// IHV cipher types
+typedef enum _IHV_CIPHER_TYPE
+{
+ None,
+ IHVCipher1,
+ IHVCipher2,
+ IHVCipher3,
+ IHVCipherInvalid
+}
+IHV_CIPHER_TYPE, *PIHV_CIPHER_TYPE;
+
+
+
+
+
+// Ihv connectivity profile data type.
+typedef
+struct _IHV_CONNECTIVITY_PROFILE
+{
+ DWORD dwParam1;
+ LPWSTR pszParam2;
+}
+IHV_CONNECTIVITY_PROFILE, *PIHV_CONNECTIVITY_PROFILE;
+
+
+
+
+
+
+// Ihv security profile data type.
+typedef struct _IHV_SECURITY_PROFILE
+{
+ BOOL bUseIhvConnectivityOnly;
+ BOOL bUseFullSecurity;
+ IHV_AUTH_TYPE AuthType;
+ IHV_CIPHER_TYPE CipherType;
+ DWORD dwParam1;
+ LPWSTR pszParam2;
+}
+IHV_SECURITY_PROFILE, *PIHV_SECURITY_PROFILE;
+
+
+
+// Converts string to connectivity profile.
+DWORD
+GetIhvConnectivityProfile
+(
+ PDOT11EXT_IHV_CONNECTIVITY_PROFILE pDot11ExtIhvConnProfile,
+ PIHV_CONNECTIVITY_PROFILE* ppConnectivityProfile
+);
+
+
+// free connectivity profile.
+VOID
+FreeIhvConnectivityProfile
+(
+ PIHV_CONNECTIVITY_PROFILE* ppConnectivityProfile
+);
+
+
+// Converts string to security profile.
+DWORD
+GetIhvSecurityProfile
+(
+ PDOT11EXT_IHV_SECURITY_PROFILE pDot11ExtIhvSecProfile,
+ PIHV_SECURITY_PROFILE* ppSecurityProfile
+);
+
+
+// free security profile.
+VOID
+FreeIhvSecurityProfile
+(
+ PIHV_SECURITY_PROFILE* ppSecurityProfile
+);
+
+
+#endif _IHVSAMPLEPROFILE_H
+
diff --git a/network/wlan/ihvsample/rc4utils.h b/network/wlan/ihvsample/rc4utils.h
new file mode 100644
index 00000000..41ff9936
--- /dev/null
+++ b/network/wlan/ihvsample/rc4utils.h
@@ -0,0 +1,67 @@
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#include <packon.h>
+
+typedef struct EAPOL_PACKET
+{
+ BYTE ProtocolVersion;
+ BYTE PacketType;
+ BYTE PacketBodyLength[2];
+ BYTE PacketBody[1];
+} EAPOL_PACKET, *UNALIGNED PEAPOL_PACKET;
+
+#include <packoff.h>
+
+
+VOID
+WINAPI
+RC4UtilsFreeKeyMaterial
+(
+ PBYTE pbDecryptedKey,
+ DWORD dwKeyLen
+);
+
+
+DWORD
+WINAPI
+RC4UtilsParseKeyPacket
+(
+ PEAPOL_PACKET pEapolPkt,
+ ULONG uPktLen,
+ PDOT11_MSONEX_RESULT_PARAMS pOneXResultParams,
+ BOOL* pbUCast,
+ PBYTE* ppbDecryptedKey,
+ DWORD* pdwKeyLen,
+ DWORD* pdwKeyIndex
+);
+
+
+
+DWORD
+WINAPI
+RC4UtilsDecryptResultParams
+(
+ PDOT11_MSONEX_RESULT_PARAMS pResultParamsOrig,
+ PDOT11_MSONEX_RESULT_PARAMS* ppResultParamsCopy
+);
+
+
+VOID
+WINAPI
+RC4UtilsFreeResultParams
+(
+ PDOT11_MSONEX_RESULT_PARAMS* ppResultParams
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/network/wlan/ihvsample/utils.cpp b/network/wlan/ihvsample/utils.cpp
new file mode 100644
index 00000000..f7dae91e
--- /dev/null
+++ b/network/wlan/ihvsample/utils.cpp
@@ -0,0 +1,662 @@
+/*++
+
+Copyright (c) 2005 Microsoft Corporation
+
+Abstract:
+
+ Sample IHV Extensibility DLL to extend
+ 802.11 LWF driver for third party protocols.
+
+
+--*/
+
+#include "precomp.h"
+
+//
+// Service specific global Variables
+//
+PDOT11EXT_APIS g_pDot11ExtApi = NULL;
+
+CRITICAL_SECTION g_csSynch = {0};
+DWORD g_dwThreadCount = 0;
+DWORD g_dwSessionID = 0;
+BOOL g_bAllowInit = TRUE;
+
+
+
+
+//
+// Structure to store data
+// required to start a new
+// thread. The thread count
+// needs to be protected.
+//
+typedef
+struct _THREAD_PROTECTOR
+{
+ LPTHREAD_START_ROUTINE pStartRoutine;
+ LPVOID pvParams;
+ HANDLE hIhvExtAdapter;
+}
+THREAD_PROTECTOR, *PTHREAD_PROTECTOR;
+
+
+
+//
+// Logical copy function macro.
+//
+#define COPY_FUNCTION( _p, _FuncName, _Preface ) \
+ (_p)->Dot11ExtIhv##_FuncName = \
+ _Preface##_FuncName; \
+
+
+
+//
+// Trace utility function
+//
+VOID
+SampleTraceFn
+(
+ LPCSTR pszFormat,
+ LPCSTR pszVal1,
+ DWORD dwVal1
+)
+{
+ CHAR szMsgString[ 512 ] = {0};
+ HRESULT hr = S_OK;
+
+ hr =
+ StringCchPrintfA
+ (
+ szMsgString,
+ sizeof( szMsgString ) - 1,
+ pszFormat,
+ pszVal1,
+ dwVal1
+ );
+
+ if ( S_OK == hr )
+ {
+ OutputDebugStringA( szMsgString );
+ }
+ else
+ {
+ OutputDebugStringA( "ERROR: Trace message generation failed.\n" );
+ }
+
+ return;
+}
+
+// Private Memory alloc function
+LPVOID
+PrivateMemoryAlloc
+(
+ size_t MemSize
+)
+{
+ LPVOID pvBuffer = NULL;
+
+ if (!MemSize)
+ {
+ BAIL( );
+ }
+
+ pvBuffer = malloc( MemSize );
+ if ( pvBuffer )
+ {
+ ZeroMemory( pvBuffer, MemSize );
+ }
+
+error:
+ return pvBuffer;
+}
+
+// Private Memory free function
+VOID
+PrivateMemoryFree
+(
+ LPVOID pvBuffer
+)
+{
+ if ( pvBuffer )
+ {
+ free( pvBuffer );
+ }
+}
+
+
+
+//
+// Initialize the handler functions
+//
+VOID
+HandlerInit
+(
+ OUT PDOT11EXT_IHV_HANDLERS pDot11IHVHandlers
+)
+{
+
+ COPY_FUNCTION( pDot11IHVHandlers, DeinitService , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, InitAdapter , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, DeinitAdapter , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, ProcessSessionChange , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, IsUIRequestPending , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, ReceiveIndication , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, PerformCapabilityMatch , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, ValidateProfile , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, PerformPreAssociate , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, PerformPostAssociate , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, AdapterReset , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, StopPostAssociate , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, ReceivePacket , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, CreateDiscoveryProfiles , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, ProcessUIResponse , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, SendPacketCompletion , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, QueryUIRequest , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, OnexIndicateResult , Ihv );
+ COPY_FUNCTION( pDot11IHVHandlers, Control , Ihv );
+
+}
+
+#define ASSERT_MSG_LEN 768
+
+//
+// Calling DebugBreak indirectly
+// to facilitate frame stepping
+// in a debugger.
+//
+VOID
+AssertFunc
+(
+ _In_ LPCSTR pszFile,
+ int nLine
+)
+{
+ HRESULT hr = S_OK;
+ CHAR Message[ ASSERT_MSG_LEN ] = {0};
+
+ hr =
+ StringCchPrintfA
+ (
+ Message,
+ ASSERT_MSG_LEN-1,
+ "\n\nAssertion failed in File %s, Line %d\n\n",
+ pszFile,
+ nLine
+ );
+ if ( S_OK == hr )
+ {
+ OutputDebugStringA( Message );
+ }
+ else
+ {
+ OutputDebugStringA( "Assertion Failed\n" );
+ }
+
+ DebugBreak( );
+}
+
+//
+// Initialize global synchronization structure.
+//
+DWORD
+InitCritSect
+(
+ CRITICAL_SECTION* pCritSect
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+
+ __try
+ {
+ InitializeCriticalSection( pCritSect );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwResult = GetExceptionCode( );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+error:
+ return dwResult;
+}
+
+
+
+
+
+//
+// Dll Main function.
+//
+BOOL
+WINAPI
+DllMain
+(
+ IN HINSTANCE Dll,
+ IN DWORD Reason,
+ IN PVOID Reserved
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+
+ UNREFERENCED_PARAMETER( Dll );
+ UNREFERENCED_PARAMETER( Reserved );
+
+ switch (Reason)
+ {
+ case DLL_PROCESS_ATTACH:
+
+ dwResult = InitCritSect( &g_csSynch );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+ g_dwThreadCount = 0;
+ g_dwSessionID = 0;
+ g_bAllowInit = TRUE;
+
+ break;
+
+ case DLL_PROCESS_DETACH:
+ DeleteCriticalSection( &g_csSynch );
+ break;
+
+ default:
+ break;
+ }
+
+error:
+ return ( ERROR_SUCCESS == dwResult );
+}
+
+
+
+
+//
+// Disable starting new threads or adding new adapters..
+//
+VOID
+StartShutdown
+(
+ VOID
+)
+{
+ g_bAllowInit = FALSE;
+}
+
+
+
+//
+// Wait for spawned threadcount
+// to come down to zero.
+//
+VOID
+WaitOnZeroThreads
+(
+ VOID
+)
+{
+ BOOL bZeroThreads = FALSE;
+
+ for ( ;; )
+ {
+ EnterCriticalSection( &g_csSynch );
+ bZeroThreads = ( 0 == g_dwThreadCount );
+ LeaveCriticalSection( &g_csSynch );
+
+ if ( bZeroThreads )
+ {
+ break;
+ }
+
+ Sleep( 100 );
+ }
+}
+
+
+
+
+
+
+//
+// Function uses pThreadProtector structure
+// to start a new thread. Decrements the
+// global thread count after this thread has
+// returned.
+//
+DWORD
+WINAPI
+ProtectedThreadEntry
+(
+ LPVOID pvThreadProtector
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ PTHREAD_PROTECTOR pThreadProtector = NULL;
+ LPTHREAD_START_ROUTINE pStartRoutine = NULL;
+ LPVOID pvParams = NULL;
+ HANDLE hIhvExtAdapter = NULL;
+
+ pThreadProtector = (PTHREAD_PROTECTOR) pvThreadProtector;
+ ASSERT ( pThreadProtector )
+
+ pStartRoutine = pThreadProtector->pStartRoutine;
+ pvParams = pThreadProtector->pvParams;
+ hIhvExtAdapter = pThreadProtector->hIhvExtAdapter;
+
+ PrivateMemoryFree( pThreadProtector );
+ pThreadProtector = NULL;
+
+
+ if ( pStartRoutine )
+ {
+ dwResult = pStartRoutine( pvParams );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+error:
+ EnterCriticalSection( &g_csSynch );
+
+ // decrement thread count.
+ g_dwThreadCount--;
+
+ // decrement adapter reference.
+ DerefenceAdapterDetails( hIhvExtAdapter );
+
+ LeaveCriticalSection( &g_csSynch );
+
+ return dwResult;
+}
+
+
+//
+// Start a new thread.
+//
+DWORD
+StartNewProtectedThread
+(
+ HANDLE hIhvExtAdapter,
+ LPTHREAD_START_ROUTINE pStartRoutine,
+ LPVOID pvParams
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ HANDLE hThread = NULL;
+ PTHREAD_PROTECTOR pThreadProtector = NULL;
+ BOOL bLocked = FALSE;
+ PADAPTER_DETAILS pAdapterDetails = NULL;
+ BOOL bCloseHandle = FALSE;
+ BOOL bOk = TRUE;
+
+
+ EnterCriticalSection( &g_csSynch );
+ bLocked = TRUE;
+
+ if (( !g_bAllowInit ) || (g_dwThreadCount >= MAX_THREAD_COUNT) )
+ {
+ dwResult = ERROR_INVALID_STATE;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ dwResult =
+ ReferenceAdapterDetails
+ (
+ hIhvExtAdapter,
+ &pAdapterDetails
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pAdapterDetails );
+
+
+ // This memory is initialized, used and freed entirely by the Extensibility
+ // DLL. Hence this memory can be allocated and freed using any method.
+ pThreadProtector = (PTHREAD_PROTECTOR) PrivateMemoryAlloc( sizeof( THREAD_PROTECTOR ) );
+ if ( !pThreadProtector )
+ {
+ dwResult = ERROR_OUTOFMEMORY;
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+
+ pThreadProtector->pStartRoutine = pStartRoutine;
+ pThreadProtector->pvParams = pvParams;
+ pThreadProtector->hIhvExtAdapter = hIhvExtAdapter;
+
+ hThread =
+ CreateThread
+ (
+ NULL, // security attributes
+ 0, // default stack size
+ ProtectedThreadEntry, // pointer to function to run
+ pThreadProtector, // parameter
+ 0, // run thread immediately
+ NULL // Thread ID receiver
+ );
+ if ( !hThread )
+ {
+ dwResult = GetLastError( );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ }
+ bCloseHandle = TRUE;
+
+ // Thread successfully started, memory
+ // would be freed by ProtectedThreadEntry
+ pThreadProtector = NULL;
+
+ // Transfering dereference duty to ProtectedThreadEntry function.
+ pAdapterDetails = NULL;
+
+ g_dwThreadCount++;
+
+error:
+ if ( bCloseHandle )
+ {
+ bOk = CloseHandle( hThread );
+ ASSERT( bOk );
+ }
+
+ PrivateMemoryFree( pThreadProtector );
+
+ if ( pAdapterDetails )
+ {
+ DerefenceAdapterDetails( hIhvExtAdapter );
+ }
+
+ if ( bLocked )
+ {
+ LeaveCriticalSection( &g_csSynch );
+ }
+ return dwResult;
+}
+
+
+//
+// Function to match beacon and profile.
+//
+BOOL
+WINAPI
+MatchBssDescription
+(
+ PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile,
+ PIHV_SECURITY_PROFILE pSecurityProfile,
+ PULDOT11_BSS_ENTRY pBssEntry
+)
+{
+ UNREFERENCED_PARAMETER( pIhvProfileParams );
+ UNREFERENCED_PARAMETER( pConnectivityProfile );
+ UNREFERENCED_PARAMETER( pSecurityProfile );
+ UNREFERENCED_PARAMETER( pBssEntry );
+
+ // Try to match the current profile with the beacon.
+ return TRUE;
+}
+
+
+
+DWORD
+CopyConnectivityProfile
+(
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_CONNECTIVITY_PROFILE pDst
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwLen = 0;
+
+ ASSERT( pSrc );
+ ASSERT( pDst );
+
+ ZeroMemory( pDst, sizeof( DOT11EXT_IHV_CONNECTIVITY_PROFILE ) );
+
+ if ( pSrc->pszXmlFragmentIhvConnectivity )
+ {
+ dwLen = (DWORD) wcslen( pSrc->pszXmlFragmentIhvConnectivity );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtAllocateBuffer)
+ (
+ (dwLen+1) * sizeof( WCHAR ),
+ (LPVOID*) &(pDst->pszXmlFragmentIhvConnectivity)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pDst->pszXmlFragmentIhvConnectivity );
+
+ CopyMemory
+ (
+ (LPVOID) pDst->pszXmlFragmentIhvConnectivity,
+ (LPVOID) pSrc->pszXmlFragmentIhvConnectivity,
+ (dwLen+1) * sizeof( WCHAR )
+ );
+ }
+
+error:
+ return dwResult;
+}
+
+
+VOID
+FreeConnectivityProfile
+(
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pSrc
+)
+{
+ if ( pSrc && pSrc->pszXmlFragmentIhvConnectivity )
+ {
+ (g_pDot11ExtApi->Dot11ExtFreeBuffer)( (LPVOID) pSrc->pszXmlFragmentIhvConnectivity );
+ pSrc->pszXmlFragmentIhvConnectivity = NULL;
+ }
+}
+
+
+
+DWORD
+CopySecurityProfile
+(
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_SECURITY_PROFILE pDst
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+ DWORD dwLen = 0;
+
+ ASSERT( pSrc );
+ ASSERT( pDst );
+
+ ZeroMemory( pDst, sizeof( DOT11EXT_IHV_SECURITY_PROFILE ) );
+
+ pDst->bUseMSOnex = pSrc->bUseMSOnex;
+
+ if ( pSrc->pszXmlFragmentIhvSecurity )
+ {
+ dwLen = (DWORD) wcslen( pSrc->pszXmlFragmentIhvSecurity );
+
+ dwResult =
+ (g_pDot11ExtApi->Dot11ExtAllocateBuffer)
+ (
+ (dwLen+1) * sizeof( WCHAR ),
+ (LPVOID*) &(pDst->pszXmlFragmentIhvSecurity)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+ ASSERT( pDst->pszXmlFragmentIhvSecurity );
+
+ CopyMemory
+ (
+ (LPVOID) pDst->pszXmlFragmentIhvSecurity,
+ (LPVOID) pSrc->pszXmlFragmentIhvSecurity,
+ (dwLen+1) * sizeof( WCHAR )
+ );
+ }
+
+
+error:
+ return dwResult;
+}
+
+
+VOID
+FreeSecurityProfile
+(
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pSrc
+)
+{
+ if ( pSrc && pSrc->pszXmlFragmentIhvSecurity )
+ {
+ (g_pDot11ExtApi->Dot11ExtFreeBuffer)( (LPVOID) pSrc->pszXmlFragmentIhvSecurity );
+ pSrc->pszXmlFragmentIhvSecurity = NULL;
+ }
+}
+
+
+
+
+DWORD
+CopyDiscoveryProfile
+(
+ IN PDOT11EXT_IHV_DISCOVERY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_DISCOVERY_PROFILE pDst
+)
+{
+ DWORD dwResult = ERROR_SUCCESS;
+
+ ASSERT( pSrc );
+ ASSERT( pDst );
+
+ dwResult =
+ CopyConnectivityProfile
+ (
+ &(pSrc->IhvConnectivityProfile),
+ &(pDst->IhvConnectivityProfile)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+
+ dwResult =
+ CopySecurityProfile
+ (
+ &(pSrc->IhvSecurityProfile),
+ &(pDst->IhvSecurityProfile)
+ );
+ BAIL_ON_WIN32_ERROR( dwResult );
+
+error:
+ if ( ERROR_SUCCESS != dwResult )
+ {
+ FreeDiscoveryProfile( pDst );
+ }
+ return dwResult;
+}
+
+
+VOID
+FreeDiscoveryProfile
+(
+ IN PDOT11EXT_IHV_DISCOVERY_PROFILE pSrc
+)
+{
+ if ( pSrc )
+ {
+ FreeConnectivityProfile( &(pSrc->IhvConnectivityProfile) );
+ FreeSecurityProfile( &(pSrc->IhvSecurityProfile) );
+ }
+}
+
+
+
diff --git a/network/wlan/ihvsample/utils.h b/network/wlan/ihvsample/utils.h
new file mode 100644
index 00000000..d2d4a80c
--- /dev/null
+++ b/network/wlan/ihvsample/utils.h
@@ -0,0 +1,318 @@
+
+
+//////////////////
+// Macros //
+//////////////////
+
+
+// Trace Macros
+
+
+VOID
+SampleTraceFn
+(
+ LPCSTR pszFormat,
+ LPCSTR pszVal1,
+ DWORD dwVal1
+);
+
+#define TRACE_MESSAGE( _x ) SampleTraceFn( "INFO: %s\n",_x, 0 );
+#define TRACE_MESSAGE_VAL( _x, _y ) SampleTraceFn( "INFO: %s %lu\n", _x, _y );
+
+
+//
+// Error Handling
+//
+#define BAIL_ON_WIN32_ERROR( __x ) \
+ if ( ERROR_SUCCESS != (__x) ) \
+ { \
+ goto error; \
+ } \
+
+
+//
+// COM failure
+//
+#define BAIL_ON_FAILURE( __hr ) \
+ if ( FAILED( __hr ) ) \
+ { \
+ goto error; \
+ } \
+
+//
+// combine win32 and com error codes.
+//
+#define WIN32_FROM_HRESULT(hr) \
+ (SUCCEEDED(hr) ? ERROR_SUCCESS : \
+ (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : (hr)))
+
+
+// Combined Error Macro
+#define WIN32_COMBINED_ERROR( _dwError, _hr ) ( (_dwError)?(_dwError):WIN32_FROM_HRESULT((_hr)))
+
+//
+// Unconditional bail
+//
+#define BAIL( ) goto error;
+
+
+//
+// Maximum number of new threads
+// to spawn at any given time.
+//
+#define MAX_THREAD_COUNT 100
+
+
+
+//
+// Debug Macro.
+//
+#ifdef DBG
+#define ASSERT(exp) \
+ if (!(exp)) \
+ { \
+ AssertFunc( __FILE__, __LINE__ ); \
+ }
+
+#define ASSERTFAILURE() \
+ AssertFunc( __FILE__, __LINE__ );
+#else
+#define ASSERT(exp)
+#define ASSERTFAILURE()
+#endif // DBG
+
+
+
+// Private Memory alloc function
+LPVOID
+PrivateMemoryAlloc
+(
+ size_t MemSize
+);
+
+// Private Memory free function
+VOID
+PrivateMemoryFree
+(
+ LPVOID pvBuffer
+);
+
+
+//
+// Array length.
+//
+#define ARRAY_LENGTH( _x ) (sizeof( (_x) ) / sizeof( (_x)[0] ))
+
+//
+// Declarations for service specific global Variables
+//
+extern PDOT11EXT_APIS g_pDot11ExtApi;
+extern CRITICAL_SECTION g_csSynch;
+extern DWORD g_dwThreadCount;
+extern DWORD g_dwSessionID;
+extern BOOL g_bAllowInit;
+
+
+
+
+
+
+
+
+// Pre-declaration for the ADAPTER_DETAILS structure.
+typedef
+struct _ADAPTER_DETAILS
+ADAPTER_DETAILS, *PADAPTER_DETAILS;
+
+
+
+
+//
+// Handler type for pre-association.
+//
+typedef
+DWORD
+(WINAPI *PRE_ASSOCIATE_FUNCTION)
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD* pdwReasonCode
+);
+
+
+//
+// Handler type for post-association.
+//
+typedef
+DWORD
+(WINAPI *POST_ASSOCIATE_FUNCTION)
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ HANDLE hSecuritySessionID,
+ PDOT11_PORT_STATE pPortState,
+ ULONG uDot11AssocParamsBytes,
+ PDOT11_ASSOCIATION_COMPLETION_PARAMETERS pDot11AssocParams
+);
+
+
+
+//
+// Handler type for stop-post-association.
+//
+typedef
+DWORD
+(WINAPI *STOP_POST_ASSOCIATE_FUNCTION)
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ PDOT11_MAC_ADDRESS pPeer,
+ DOT11_ASSOC_STATUS dot11AssocStatus
+);
+
+
+
+//
+// Handler type for receive packet.
+//
+typedef
+DWORD
+(WINAPI *IHV_RECEIVE_PACKET_HANDLER)
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DWORD dwInBufferSize,
+ LPVOID pvInBuffer
+);
+
+
+
+//
+// Handler type for IHV result indication.
+//
+typedef
+DWORD
+(WINAPI *IHV_INDICATE_RESULT_HANDLER)
+(
+ PADAPTER_DETAILS pAdapterDetails,
+ DOT11_MSONEX_RESULT msOneXResult,
+ PDOT11_MSONEX_RESULT_PARAMS pDot11MsOneXResultParams
+);
+
+
+
+// Assert function in debug builds.
+VOID
+AssertFunc
+(
+ _In_ LPCSTR pszFile,
+ int nLine
+);
+
+
+//
+// Register intention to start shut down.
+//
+VOID
+StartShutdown
+(
+ VOID
+);
+
+
+//
+// Wait for posted thread count to go down to zero.
+//
+VOID
+WaitOnZeroThreads
+(
+ VOID
+);
+
+
+//
+// Populate IHV handler function pointers to IHV Framework.
+//
+VOID
+HandlerInit
+(
+ OUT PDOT11EXT_IHV_HANDLERS pDot11IHVHandlers
+);
+
+
+//
+// Call createthread to start a new thread and ensure
+// the adapter stays active till the thread finishes
+// by putting a refcount increment/decrement around
+// the lifetime of the thread.
+//
+DWORD
+StartNewProtectedThread
+(
+ HANDLE hIhvExtAdapter,
+ LPTHREAD_START_ROUTINE pStartRoutine,
+ LPVOID pvParams
+);
+
+
+// Typedef for unaligned BSS Entry to process beacons.
+typedef UNALIGNED DOT11_BSS_ENTRY* PULDOT11_BSS_ENTRY;
+
+//
+// Function to match beacon and profile.
+//
+BOOL
+WINAPI
+MatchBssDescription
+(
+ PDOT11EXT_IHV_PROFILE_PARAMS pIhvProfileParams,
+ PIHV_CONNECTIVITY_PROFILE pConnectivityProfile,
+ PIHV_SECURITY_PROFILE pSecurityProfile,
+ PULDOT11_BSS_ENTRY pBssEntry
+);
+
+
+//
+// Functions to copy and free discovery profiles.
+//
+
+DWORD
+CopyConnectivityProfile
+(
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_CONNECTIVITY_PROFILE pDst
+);
+
+
+VOID
+FreeConnectivityProfile
+(
+ IN PDOT11EXT_IHV_CONNECTIVITY_PROFILE pSrc
+);
+
+
+DWORD
+CopySecurityProfile
+(
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_SECURITY_PROFILE pDst
+);
+
+VOID
+FreeSecurityProfile
+(
+ IN PDOT11EXT_IHV_SECURITY_PROFILE pSrc
+);
+
+
+
+VOID
+FreeDiscoveryProfile
+(
+ IN PDOT11EXT_IHV_DISCOVERY_PROFILE pSrc
+);
+
+
+
+DWORD
+CopyDiscoveryProfile
+(
+ IN PDOT11EXT_IHV_DISCOVERY_PROFILE pSrc,
+ OUT PDOT11EXT_IHV_DISCOVERY_PROFILE pDst
+);
diff --git a/network/wlan/ihvsampleui/IHVClassFactory.cpp b/network/wlan/ihvsampleui/IHVClassFactory.cpp
new file mode 100644
index 00000000..7da337d5
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVClassFactory.cpp
@@ -0,0 +1,166 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+#include "ihvuiinc_i.c"
+
+extern long g_serverLock; //lock count on server
+
+//
+// IUnknown Implementation
+//
+CIHVClassFactory::CIHVClassFactory() : m_refCount(1)
+{
+}
+
+CIHVClassFactory::~CIHVClassFactory()
+{
+}
+
+STDMETHODIMP_(ULONG)
+CIHVClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_refCount);
+}
+
+STDMETHODIMP_(ULONG)
+CIHVClassFactory::Release()
+{
+ ULONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0)
+ {
+ delete this;
+ }
+ return refCount;
+}
+
+STDMETHODIMP
+CIHVClassFactory::QueryInterface(
+ REFIID riid,
+ void **ppvObject
+ )
+{
+ HRESULT hr = E_INVALIDARG;
+ if (NULL != ppvObject)
+ {
+ hr = S_OK;
+ if (riid == IID_IUnknown)
+ {
+ *ppvObject = static_cast<IUnknown *>(this);
+ }
+ else if (riid == IID_IClassFactory)
+ {
+ *ppvObject = static_cast<IClassFactory *>(this);
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();
+ }
+
+ return hr;
+}
+
+
+//
+// IClassFactory Implementaion
+//
+STDMETHODIMP
+CIHVClassFactory::CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject
+ )
+{
+ HRESULT hr = E_NOINTERFACE;
+
+ // aggregation not supported
+ if (pUnkOuter != NULL)
+ {
+ return CLASS_E_NOAGGREGATION;
+ }
+
+ if (NULL == ppvObject)
+ {
+ return E_INVALIDARG;
+ }
+
+ // Figure out which interface is wanted
+ // the ui will call us only as IID_IDot11ExtUI
+ if (IID_IDot11SampleExtUI == riid ||
+ IID_IDot11ExtUI == riid ||
+ IID_IWizardExtension == riid)
+ {
+ CDot11SampleExtUI *pExtUI = new(std::nothrow) CDot11SampleExtUI();
+ if (NULL == pExtUI)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ pExtUI->AddRef();
+ hr = pExtUI->QueryInterface(riid, ppvObject);
+
+ pExtUI->Release();
+ }
+ else if (IID_IDot11SampleExtUIConProperty == riid)
+ {
+ CDot11SampleExtUIConProperty *pCDot11SampleExtUIConProperty = new(std::nothrow) CDot11SampleExtUIConProperty();
+ if (NULL == pCDot11SampleExtUIConProperty)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ pCDot11SampleExtUIConProperty->AddRef();
+ hr = pCDot11SampleExtUIConProperty->QueryInterface(riid, ppvObject);
+
+ pCDot11SampleExtUIConProperty->Release();
+ }
+ else if (IID_IDot11SampleExtUISecProperty == riid)
+ {
+ CDot11SampleExtUISecProperty *pCDot11SampleExtUISecProperty = new(std::nothrow) CDot11SampleExtUISecProperty();
+ if (NULL == pCDot11SampleExtUISecProperty)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ pCDot11SampleExtUISecProperty->AddRef();
+ hr = pCDot11SampleExtUISecProperty->QueryInterface(riid, ppvObject);
+
+ pCDot11SampleExtUISecProperty->Release();
+ }
+ else if (IID_IDot11SampleExtUIKeyProperty == riid)
+ {
+ CDot11SampleExtUIKeyProperty *pCDot11SampleExtUIKeyProperty = new(std::nothrow) CDot11SampleExtUIKeyProperty();
+ if (NULL == pCDot11SampleExtUIKeyProperty)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ pCDot11SampleExtUIKeyProperty->AddRef();
+ hr = pCDot11SampleExtUIKeyProperty->QueryInterface(riid, ppvObject);
+
+ pCDot11SampleExtUIKeyProperty->Release();
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP
+CIHVClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ {
+ InterlockedIncrement(&g_serverLock);
+ }
+ else
+ {
+ InterlockedDecrement(&g_serverLock);
+ }
+
+ return S_OK;
+}
diff --git a/network/wlan/ihvsampleui/IHVClassFactory.h b/network/wlan/ihvsampleui/IHVClassFactory.h
new file mode 100644
index 00000000..60f814c3
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVClassFactory.h
@@ -0,0 +1,28 @@
+
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#pragma once
+
+// The class factory
+class CIHVClassFactory : public IClassFactory
+{
+public:
+ // Constructor
+ CIHVClassFactory();
+ ~CIHVClassFactory();
+
+ // IUnknown
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
+ STDMETHODIMP LockServer(BOOL fLock);
+
+private:
+ long m_refCount;
+};
diff --git a/network/wlan/ihvsampleui/IHVRegistryHelper.cpp b/network/wlan/ihvsampleui/IHVRegistryHelper.cpp
new file mode 100644
index 00000000..ebe8622c
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVRegistryHelper.cpp
@@ -0,0 +1,284 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+#define CLSIDSTR_CALLBACK L"{4A01f9f9-6012-4343-A8C4-10B5DF32672A}" // IHV Ext UI CLSID
+#define CLSID_CALLBACK_FRIENDLY_NAME L"Wireless 802.11 IHV Sample Config UI"
+
+#define REGCLSID L"CLSID"
+#define INPROCSERVER32 L"InprocServer32"
+#define THREADINGMODEL L"ThreadingModel"
+#define FREETHREADING L"Both"
+
+#define ARRAY_SIZE(s) (sizeof(s) / sizeof(s[0]))
+
+extern HINSTANCE g_hInst;
+
+
+typedef HRESULT (APIENTRY *RegisterPageWithPageProc) (
+ const GUID *pguidParentPage,
+ const GUID *pguidChildPage,
+ const LPWSTR pszChildModuleFileName,
+ const LPWSTR pszFriendlyName,
+ const DWORD dwBehaviorFlags,
+ const DWORD dwUserFlags,
+ const LPWSTR pszCommandLine);
+
+typedef HRESULT (APIENTRY *UnregisterPageProc) (
+ const GUID *pguidPage,
+ const BOOL fUnregisterFromCOM);
+
+
+
+//
+// RegisterServer - Register the COM Server by creating required keys
+//
+
+#pragma warning (push)
+#pragma warning (disable:6262)
+
+HRESULT
+CRegHelper::RegisterServer ()
+{
+ HRESULT hr = S_OK;
+ wchar_t wszModule[_MAX_PATH] = {0};
+ DWORD result = 0;
+
+ result = GetModuleFileName(g_hInst, wszModule, ARRAY_SIZE(wszModule));
+
+ if (result == 0)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ wchar_t wszCLSIDKey[MAX_LENGTH] = {0}; // CLSID\\wszCLSID.
+ wchar_t wszInprocKey[MAX_LENGTH + 2] = {0}; // CLSID\\InprocServer32
+
+ // get the class ID strings.
+ StringCchCopyW(wszCLSIDKey, MAX_LENGTH, REGCLSID);
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, L"\\");
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, CLSIDSTR_CALLBACK);
+
+ // create entries under CLSID.
+ // Description
+ FAILHR(SetKeyAndValue(wszCLSIDKey, NULL, CLSID_CALLBACK_FRIENDLY_NAME));
+ // set the server path.
+ FAILHR(SetKeyAndValue(wszCLSIDKey, INPROCSERVER32, wszModule));
+
+ // add the threading model information.
+ hr = StringCchPrintfW(wszInprocKey, MAX_LENGTH + 2, L"%s\\%s", wszCLSIDKey, INPROCSERVER32);
+ if(FAILED(hr))
+ {
+ hr = S_FALSE;
+ return hr;
+ }
+
+ FAILHR(SetRegValue(wszInprocKey, THREADINGMODEL, FREETHREADING));
+
+ // register the extension UI wizard page
+ HINSTANCE hinstLib = LoadLibrary(TEXT("connect.dll"));
+ if (hinstLib != NULL)
+ {
+
+ // get the export function used for registering
+ RegisterPageWithPageProc registerPageWithPageProc =
+ (RegisterPageWithPageProc) GetProcAddress(hinstLib, (LPCSTR)("RegisterPageWithPage"));
+
+ if (NULL != registerPageWithPageProc)
+ {
+ hr = (registerPageWithPageProc) (NULL, // stand alone page (no parent)
+ &GUID_SAMPLE_IHVUI_CLSID, // clsid of the extension UI wizard page
+ NULL, // filename already registered through COM
+ CLSID_CALLBACK_FRIENDLY_NAME, // friendly name
+ 0x2, // allow duplicate instances
+ 0, // no user flags
+ NULL); // no command line
+ }
+
+ FreeLibrary(hinstLib);
+ }
+
+ return hr;
+}
+#pragma warning (pop)
+
+//
+// UnRegisterServer - Register the COM Server by creating required keys
+//
+HRESULT
+CRegHelper::UnregisterServer()
+{
+ HRESULT hr = S_OK;
+ wchar_t wszCLSIDKey[MAX_LENGTH] = {0}; // CLSID\\wszCLSID.
+
+
+ // get the class ID strings.
+ StringCchCopyW(wszCLSIDKey,MAX_LENGTH, REGCLSID);
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, L"\\");
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, CLSIDSTR_CALLBACK);
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, L"\\");
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, INPROCSERVER32);
+
+
+ // delete the sub key of the Class ID key
+ FAILHR(DeleteKey(wszCLSIDKey));
+
+ StringCchCopyW(wszCLSIDKey,MAX_LENGTH, REGCLSID);
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, L"\\");
+ StringCchCatW(wszCLSIDKey, MAX_LENGTH, CLSIDSTR_CALLBACK);
+
+ // delete Class ID key
+ FAILHR(DeleteKey(wszCLSIDKey));
+
+ // unregister the extension UI wizard page
+ HINSTANCE hinstLib = LoadLibrary(TEXT("connect.dll"));
+ if (hinstLib != NULL)
+ {
+
+ // get the export function used for unregistering
+ UnregisterPageProc unregisterPageProc =
+ (UnregisterPageProc) GetProcAddress(hinstLib, (LPCSTR)("UnregisterPage"));
+
+ if (NULL != unregisterPageProc)
+ {
+ hr = (unregisterPageProc) (&GUID_SAMPLE_IHVUI_CLSID, // clsid of the extension UI wizard page
+ FALSE); // already unregistered from COM
+ }
+
+ FreeLibrary(hinstLib);
+ }
+
+ return hr;
+
+}
+
+//
+// Set an entry in the registry of the form:
+// HKEY_CLASSES_ROOT\wszKey\wszSubkey = wszValue
+//
+BOOL
+CRegHelper::SetKeyAndValue(
+ const wchar_t* pwszKey,
+ const wchar_t* pwszSubkey,
+ const wchar_t* pwszValue
+ )
+{
+ HKEY hKey; // handle to the new reg key.
+ wchar_t wszRegKey[MAX_LENGTH] = {0}; // buffer for the full key name.
+
+
+ // init the key with the base key name.
+ StringCchCopyW(wszRegKey, MAX_LENGTH, pwszKey);
+ // append the subkey name (if there is one).
+ if (pwszSubkey != NULL)
+ {
+ StringCchCatW(wszRegKey, MAX_LENGTH, L"\\");
+ StringCchCatW(wszRegKey, MAX_LENGTH, pwszSubkey);
+ }
+
+ // create the registry key.
+ if (RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ wszRegKey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hKey,
+ NULL) == ERROR_SUCCESS)
+ {
+ // set the value (if there is one).
+ if (pwszValue != NULL)
+ {
+ RegSetValueEx(
+ hKey,
+ NULL,
+ 0,
+ REG_SZ,
+ (BYTE *)pwszValue,
+ (DWORD) ((wcslen(pwszValue) + 1) * sizeof (wchar_t))
+ );
+ }
+
+ RegCloseKey(hKey);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//
+// SetRegValue - Open the key, create a new keyword and value pair under it.
+//
+BOOL
+CRegHelper::SetRegValue(
+ const wchar_t* pwszKeyName,
+ const wchar_t* pwszKeyword,
+ const wchar_t* pwszValue
+ )
+{
+ HKEY hKey; // handle to the new reg key.
+
+ // create the registration key.
+ if (RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ pwszKeyName,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hKey,
+ NULL) == ERROR_SUCCESS)
+ {
+ // set the value (if there is one).
+ if (pwszValue != NULL)
+ {
+ RegSetValueEx(
+ hKey,
+ pwszKeyword,
+ 0,
+ REG_SZ,
+ (BYTE *)pwszValue,
+ (DWORD) ((wcslen(pwszValue) + 1) * sizeof (wchar_t))
+ );
+ }
+
+ RegCloseKey(hKey);
+
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+//
+// Delete an entry in the registry of the form:
+// HKEY_CLASSES_ROOT\wszKey\wszSubkey = wszValue
+//
+BOOL
+CRegHelper::DeleteKey(const wchar_t* pwszSubkey)
+{
+ DWORD result = 0;
+
+ if (pwszSubkey != NULL)
+ {
+ // delete the registry key.
+ result = RegDeleteKey(HKEY_CLASSES_ROOT, pwszSubkey);
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ return ((ERROR_SUCCESS == result)?TRUE:FALSE);
+}
+
+
diff --git a/network/wlan/ihvsampleui/IHVRegistryHelper.h b/network/wlan/ihvsampleui/IHVRegistryHelper.h
new file mode 100644
index 00000000..76c85b1c
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVRegistryHelper.h
@@ -0,0 +1,40 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#pragma once
+
+#define FAILHR(result) \
+ if (result == FALSE) \
+ {\
+ hr = S_FALSE;\
+ return hr;\
+ }
+
+
+#define MAX_LENGTH 256
+
+
+class CRegHelper
+{
+ public:
+ static HRESULT STDMETHODCALLTYPE RegisterServer();
+ static HRESULT STDMETHODCALLTYPE UnregisterServer();
+
+private:
+ static BOOL SetKeyAndValue(
+ const wchar_t *pszKey,
+ const wchar_t *pszSubkey,
+ const wchar_t *pszValue
+ );
+
+ static BOOL DeleteKey(const wchar_t *pszSubkey);
+
+ static BOOL SetRegValue(
+ const wchar_t *pszKeyName,
+ const wchar_t *pszKeyword,
+ const wchar_t *pszValue
+ );
+};
+
diff --git a/network/wlan/ihvsampleui/IHVSample.idl b/network/wlan/ihvsampleui/IHVSample.idl
new file mode 100644
index 00000000..81e05140
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSample.idl
@@ -0,0 +1,71 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+import "unknwn.idl";
+import "wtypes.idl";
+import "ihvuiinc.idl"; // For wireless UI extensions
+
+interface IWizardExtension;
+interface IObjectWithSite;
+
+interface IDot11SampleExtUI;
+interface IDot11SampleExtUIConProperty;
+interface IDot11SampleExtUISecProperty;
+
+[
+ uuid(7ca89d4b-2c5b-4368-b53a-ffa14e031179),
+ helpstring(" Dot11 IHV Extensibility UI Interface"),
+ dual
+]
+
+interface IDot11SampleExtUI: IDot11ExtUI
+{
+}
+
+
+
+[
+ uuid(61055513-2f27-4962-b29c-d6d7d1500fec),
+ helpstring(" Dot11 IHV Extensibility UI Connection Properties Interface"),
+ dual
+]
+
+interface IDot11SampleExtUIConProperty: IDot11ExtUIProperty
+{
+ [id(1), hidden, helpstring("method Initialize")]
+ HRESULT
+ Initialize([in] BSTR bstrPropertyName);
+}
+
+
+[
+ uuid(12c211ae-1b6d-471c-9c1b-698bcc9b9d97),
+ helpstring(" Dot11 IHV Extensibility UI Security Properties Interface"),
+ dual
+]
+
+interface IDot11SampleExtUISecProperty: IDot11ExtUIProperty
+{
+ [id(1), hidden, helpstring("method Initialize")]
+ HRESULT
+ Initialize([in] BSTR bstrPropertyName, [in] DWORD dwIhvSecurity);
+}
+
+
+[
+ uuid(a18bae3c-39c2-4b34-ba49-0130e431d2ca),
+ helpstring(" Dot11 IHV Extensibility UI Key Properties Interface"),
+ dual
+]
+
+interface IDot11SampleExtUIKeyProperty: IDot11ExtUIProperty
+{
+ [id(1), hidden, helpstring("method Initialize")]
+ HRESULT
+ Initialize([in] BYTE* pvData);
+}
+
+
+
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUI.cpp b/network/wlan/ihvsampleui/IHVSampleExtUI.cpp
new file mode 100644
index 00000000..a5e60d7a
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUI.cpp
@@ -0,0 +1,971 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+#include "ihvsample_i.c"
+
+extern HINSTANCE g_hInst;
+
+LPWSTR g_IHVAuthFriendlyName[] = {
+ L"IHVAuth V1",
+ L"IHVAuth V2",
+ L"IHVAuth V3"
+};
+
+LPWSTR g_IHVCipherFriendlyName[] = {
+ L"None",
+ L"IHVCipher 1",
+ L"IHVCipher 2",
+ L"IHVCipher 3"
+};
+
+IHV_AUTH_CIPHER_CAPABILITY g_IHVOneXExtCapability =
+{
+ 3,
+ {
+ {
+ IHVAuthV1,
+ 1,
+ {IHVCipher1}
+ },
+ {
+ IHVAuthV2,
+ 3,
+ {None, IHVCipher1, IHVCipher2}
+ },
+ {
+ IHVAuthV3,
+ 2,
+ {IHVCipher2, IHVCipher3}
+ }
+ }
+};
+
+
+static const WCHAR c_szIhvUIRequest[] = L"_UI_Request";
+static const WCHAR c_szIhvUIResponse[] = L"_UI_Response";
+
+template<typename T>
+T* GetThis(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static const WCHAR c_szThisPointer[]= L"_Win32_this_";
+ UNREFERENCED_PARAMETER(wParam);
+
+ T* pThis = NULL;
+ if (uMsg == WM_INITDIALOG)
+ {
+ if (sizeof(PROPSHEETPAGE) == ((LPPROPSHEETPAGE)lParam)->dwSize)
+ {
+ // This corresponds to MSDN
+ pThis = (T *)((LPPROPSHEETPAGE)lParam)->lParam;
+ }
+ else
+ {
+ // TODO: Need to determine when this abnormality happens...
+ pThis = (T *)lParam;
+ }
+
+ SetProp(hwnd, c_szThisPointer, (HANDLE)pThis);
+
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ RemoveProp(hwnd, c_szThisPointer);
+ }
+ else
+ {
+ pThis = (T *)GetProp(hwnd, c_szThisPointer);
+ }
+
+ return pThis;
+}
+
+
+CDot11SampleExtUI::CDot11SampleExtUI(): m_crefCount(0)
+{
+ InterlockedIncrement(&g_objRefCount);
+
+ m_pUnkSite = NULL;
+ m_hFirstPagePsp = NULL;
+ m_hLastPagePsp = NULL;
+ m_pUIRequest = NULL;
+}
+
+CDot11SampleExtUI::~CDot11SampleExtUI()
+{
+ InterlockedDecrement(&g_objRefCount);
+
+ if( m_pUIRequest)
+ {
+ delete m_pUIRequest;
+ }
+
+ if( m_pUnkSite)
+ {
+ m_pUnkSite ->Release();
+ m_pUnkSite = NULL;
+ }
+}
+
+// Used to get the IHV friendly name
+STDMETHODIMP
+CDot11SampleExtUI::GetDot11ExtUIFriendlyName(
+ BSTR* bstrFriendlyName)
+{
+ HRESULT hr = E_INVALIDARG;
+
+ if (NULL != bstrFriendlyName)
+ {
+ *bstrFriendlyName = SysAllocString(IHV_SAMPLE_IHV_NAME);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+
+// Returns the requested property type
+STDMETHODIMP
+CDot11SampleExtUI::GetDot11ExtUIProperties(
+ DOT11_EXT_UI_PROPERTY_TYPE ExtType,
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ )
+{
+ HRESULT hr = S_OK;
+ if (!pcExtensions || !ppDot11ExtUIProperty)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ // Initialize the out parameters
+ *pcExtensions = 0;
+ *ppDot11ExtUIProperty = NULL;
+
+ switch(ExtType)
+ {
+ case DOT11_EXT_UI_CONNECTION:
+ hr = CreateConnectionProperties(pcExtensions, ppDot11ExtUIProperty);
+ break;
+
+ case DOT11_EXT_UI_SECURITY:
+ hr = CreateSecurityProperties(pcExtensions, ppDot11ExtUIProperty);
+ break;
+
+ case DOT11_EXT_UI_KEYEXTENSION:
+ hr = CreateKeyProperties(pcExtensions, ppDot11ExtUIProperty);
+ break;
+
+ default:
+ hr = E_NOTIMPL;
+ break;
+ }
+
+error:
+ return hr;
+}
+
+#define IHV_BALLOON_TEXT L"Please enter key information"
+
+STDMETHODIMP
+CDot11SampleExtUI::GetDot11ExtUIBalloonText(
+ BSTR pIHVUIRequest, // the UI request structure from IHV
+ BSTR* pwszBalloonText // the balloon text to be displayed
+ )
+{
+ HRESULT hr = E_INVALIDARG;
+ PDOT11EXT_IHV_UI_REQUEST pIhvUiRequest = (PDOT11EXT_IHV_UI_REQUEST) pIHVUIRequest;
+
+ if (NULL != pwszBalloonText)
+ {
+ // Ihv could choose to parse the UI request data here ...
+ UNREFERENCED_PARAMETER( pIhvUiRequest );
+
+ *pwszBalloonText = SysAllocString( IHV_BALLOON_TEXT );
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+
+
+HRESULT
+CDot11SampleExtUI::CreateConnectionProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ )
+{
+ HRESULT hr = ERROR_SUCCESS;
+ BSTR strName = NULL;
+ ULONG uCount = 0;
+
+ IDot11SampleExtUIConProperty **pprgProps = NULL;
+
+ uCount = PROP_COUNT_CONNECTION;
+ pprgProps = (IDot11SampleExtUIConProperty**)
+ CoTaskMemAlloc(sizeof(IDot11SampleExtUIConProperty*) * uCount);
+
+ if (!pprgProps)
+ {
+ hr = E_UNEXPECTED;
+ goto error;
+ }
+
+ // Since we just have one property of each, we'll
+ // create one interface first and initialize it separately
+ IDot11SampleExtUIConProperty *pTempIProp = NULL;
+ hr = CoCreateInstance(
+ GUID_SAMPLE_IHVUI_CLSID,
+ NULL,
+ CLSCTX_INPROC,
+ IID_IDot11SampleExtUIConProperty,
+ (PVOID*)&pTempIProp
+ );
+
+ if (FAILED(hr))
+ {
+ goto error;
+ }
+
+ // this will probably never be displayed
+ strName = SysAllocString(L"IHV Connection Settings");
+ hr = pTempIProp->Initialize(strName);
+ pprgProps[0] = pTempIProp;
+
+ if (SUCCEEDED(hr))
+ {
+ *pcExtensions = uCount;
+ *ppDot11ExtUIProperty = (IDot11ExtUIProperty*)pprgProps;
+
+ // Set the current pointer to NULL so it doesn't get freed at the bottom
+ pprgProps = NULL;
+ }
+
+error:
+ if (FAILED(hr) && pprgProps)
+ {
+ CoTaskMemFree(pprgProps);
+ pprgProps = NULL;
+ }
+ SysFreeString(strName);
+ return hr;
+}
+
+HRESULT
+CDot11SampleExtUI::CreateSecurityProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ )
+{
+ HRESULT hr = ERROR_SUCCESS;
+ BSTR strName = NULL;
+ ULONG uCount = 0;
+ DWORD i = 0;
+ WCHAR wbuf[128];
+
+ IDot11SampleExtUISecProperty **pprgProps = NULL;
+
+ uCount = PROP_COUNT_SECURITY;
+ pprgProps = (IDot11SampleExtUISecProperty**)
+ CoTaskMemAlloc(sizeof(IDot11SampleExtUISecProperty*) * uCount);
+
+ if (!pprgProps)
+ {
+ hr = E_UNEXPECTED;
+ goto error;
+ }
+
+ // Since we just have one property of each, we'll
+ // create one interface first and initialize it separately
+ IDot11SampleExtUISecProperty *pTempIProp = NULL;
+
+ for (i = 0; i < uCount; ++i)
+ {
+ ZeroMemory(
+ wbuf,
+ 128
+ );
+ pTempIProp = NULL;
+ SysFreeString(strName);
+ strName = NULL;
+
+ hr = CoCreateInstance(
+ GUID_SAMPLE_IHVUI_CLSID,
+ NULL,
+ CLSCTX_INPROC,
+ IID_IDot11SampleExtUISecProperty,
+ (PVOID*)&pTempIProp
+ );
+
+ if (FAILED(hr))
+ {
+ continue;
+ }
+
+ StringCchPrintf(
+ wbuf,
+ 128,
+ wstrSecurityTypes[i]
+ );
+
+ strName = SysAllocString(wbuf);
+ hr = pTempIProp->Initialize(strName, i);
+ pprgProps[i] = pTempIProp;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *pcExtensions = uCount;
+ *ppDot11ExtUIProperty = (IDot11ExtUIProperty*)pprgProps;
+
+ // Set the current pointer to NULL so it doesn't get freed at the bottom
+ pprgProps = NULL;
+ }
+
+error:
+ if (FAILED(hr) && pprgProps)
+ {
+ CoTaskMemFree(pprgProps);
+ pprgProps = NULL;
+ }
+ SysFreeString(strName);
+ return hr;
+}
+
+HRESULT
+CDot11SampleExtUI::CreateKeyProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ )
+{
+ HRESULT hr = ERROR_SUCCESS;
+ BSTR strName = NULL;
+ ULONG uCount = 0;
+ DWORD i = 0;
+ WCHAR wbuf[128];
+ IDot11SampleExtUIKeyProperty **pprgProps = NULL;
+
+ uCount = g_IHVOneXExtCapability.dwAuthCount;
+
+ pprgProps = (IDot11SampleExtUIKeyProperty**)
+ CoTaskMemAlloc(sizeof(IDot11SampleExtUIKeyProperty*) * uCount);
+
+ if (!pprgProps)
+ {
+ hr = E_UNEXPECTED;
+ goto error;
+ }
+
+ // Since we just have one property of each, we'll
+ // create one interface first and initialize it separately
+ IDot11SampleExtUIKeyProperty *pTempIProp = NULL;
+
+ for (i = 0; i < uCount; ++i)
+ {
+ ZeroMemory(
+ wbuf,
+ 128
+ );
+ pTempIProp = NULL;
+ SysFreeString(strName);
+ strName = NULL;
+
+ hr = CoCreateInstance(
+ GUID_SAMPLE_IHVUI_CLSID,
+ NULL,
+ CLSCTX_INPROC,
+ IID_IDot11SampleExtUIKeyProperty,
+ (PVOID*)&pTempIProp
+ );
+
+ if (FAILED(hr))
+ {
+ continue;
+ }
+
+ StringCchPrintf(
+ wbuf,
+ 128,
+ g_IHVAuthFriendlyName[g_IHVOneXExtCapability.IhvAuthCiphers[i].IHVAuth]
+ );
+
+ strName = SysAllocString(wbuf);
+ hr = pTempIProp->Initialize((BYTE *) &(g_IHVOneXExtCapability.IhvAuthCiphers[i]));
+ pprgProps[i] = pTempIProp;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *pcExtensions = uCount;
+ *ppDot11ExtUIProperty = (IDot11ExtUIProperty*)pprgProps;
+
+ // Set the current pointer to NULL so it doesn't get freed at the bottom
+ pprgProps = NULL;
+ }
+
+error:
+ if (FAILED(hr) && pprgProps)
+ {
+ CoTaskMemFree(pprgProps);
+ pprgProps = NULL;
+ }
+ SysFreeString(strName);
+ return hr;
+}
+
+
+HRESULT
+CDot11SampleExtUI::FinalConstruct()
+{
+ m_pUnkSite = NULL;
+ m_hFirstPagePsp = NULL;
+ m_hLastPagePsp = NULL;
+ m_pUIRequest = NULL;
+
+ return S_OK;
+}
+
+VOID
+CDot11SampleExtUI::FinalRelease()
+{
+ if( m_pUnkSite)
+ {
+ m_pUnkSite ->Release();
+ m_pUnkSite = NULL;
+ }
+
+ if( m_pUIRequest)
+ {
+ delete m_pUIRequest;
+ m_pUIRequest = NULL;
+ }
+
+}
+
+// IObjectWithSite
+STDMETHODIMP
+CDot11SampleExtUI::SetSite (
+ IUnknown* pUnkSite
+ )
+{
+ if( m_pUnkSite)
+ m_pUnkSite ->Release();
+
+ m_pUnkSite = pUnkSite;
+
+ if( m_pUnkSite)
+ m_pUnkSite ->AddRef();
+
+ return S_OK;
+}
+
+STDMETHODIMP
+CDot11SampleExtUI::GetSite (
+ REFIID riid,
+ void** ppvSite
+ )
+{
+ *ppvSite = NULL;
+
+ if( m_pUnkSite == NULL)
+ return E_FAIL;
+
+ return m_pUnkSite ->QueryInterface(riid, ppvSite);
+}
+
+//IWizardExtension
+STDMETHODIMP CDot11SampleExtUI::AddPages (
+ HPROPSHEETPAGE* aPages,
+ UINT cPages,
+ UINT *pnPagesAdded
+ )
+{
+ IPropertyBag *pIPropertyBag = NULL;
+
+ UNREFERENCED_PARAMETER(cPages);
+
+ HRESULT hr = m_pUnkSite->QueryInterface(IID_IPropertyBag,
+ (VOID **)&pIPropertyBag);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT v;
+ VariantInit(&v);
+
+ WCHAR ihvKeyName[IHV_KEY_LENGTH];
+ GetClsidPropertyName (
+ & GUID_SAMPLE_IHVUI_CLSID,
+ (LPWSTR) c_szIhvUIRequest,
+ ihvKeyName,
+ IHV_KEY_LENGTH
+ );
+ hr = pIPropertyBag->Read(
+ ihvKeyName,
+ &v,
+ NULL);
+
+ if (SUCCEEDED(hr) && (VT_BSTR == V_VT(&v)))
+ {
+ if( m_pUIRequest == NULL)
+ {
+ m_pUIRequest = new(std::nothrow) IHV_UI_REQUEST;
+ if (m_pUIRequest == NULL)
+ {
+ VariantClear(&v);
+ pIPropertyBag->Release();
+ return E_OUTOFMEMORY;
+ }
+ }
+ memcpy(m_pUIRequest, v.bstrVal, sizeof(IHV_UI_REQUEST));
+ }
+
+ VariantClear(&v);
+
+ pIPropertyBag->Release();
+ }
+
+ ////////////////
+
+ *pnPagesAdded = 0;
+
+ PROPSHEETPAGE psp = {0};
+
+ psp.dwSize = sizeof( psp);
+ psp.hInstance = g_hInst;
+ psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_USEHEADERTITLE;
+ psp.lParam = (LPARAM) this;
+
+ psp.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG_SHOWHELP);
+ psp.pfnDlgProc = (DLGPROC) CDot11SampleExtUI::HelpDlgProc;
+ psp.pszHeaderTitle = MAKEINTRESOURCE( IDS_TITLE_SHOWHELP);
+ m_hFirstPagePsp = CreatePropertySheetPage(& psp);
+
+ psp.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG_GETKEY);
+ psp.pfnDlgProc = (DLGPROC) CDot11SampleExtUI::GetKeyDlgProc;
+ psp.pszHeaderTitle = MAKEINTRESOURCE( IDS_TITLE_GETKEY);
+ HPROPSHEETPAGE hPsp= CreatePropertySheetPage(& psp);
+
+ psp.pszTemplate = MAKEINTRESOURCE(IDD_DIALOG_LASTPAGE);
+ psp.pfnDlgProc = (DLGPROC) CDot11SampleExtUI::LastPageDlgProc;
+ psp.pszHeaderTitle = MAKEINTRESOURCE( IDS_TITLE_LASTPAGE);
+ m_hLastPagePsp = CreatePropertySheetPage(& psp);
+
+ if( m_hFirstPagePsp
+ && hPsp
+ && m_hLastPagePsp)
+ {
+ aPages[0] = m_hFirstPagePsp;
+ aPages[1] = hPsp;
+ aPages[2] = m_hLastPagePsp;
+
+ *pnPagesAdded = 3;
+
+ return S_OK;
+ }
+ else
+ {
+ if(m_hFirstPagePsp)
+ {
+ DestroyPropertySheetPage(m_hFirstPagePsp);
+ }
+
+ if(hPsp)
+ {
+ DestroyPropertySheetPage(hPsp);
+ }
+
+ if(m_hLastPagePsp)
+ {
+ DestroyPropertySheetPage(m_hLastPagePsp);
+ }
+
+ m_hFirstPagePsp = hPsp = m_hLastPagePsp = NULL;
+
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CDot11SampleExtUI::GetFirstPage (
+ HPROPSHEETPAGE *phpage
+ )
+{
+ *phpage = m_hFirstPagePsp;
+ return S_OK;
+}
+
+STDMETHODIMP
+CDot11SampleExtUI::GetLastPage (HPROPSHEETPAGE *phpage)
+{
+ * phpage = m_hLastPagePsp;
+ return S_OK;
+}
+
+
+BOOL CALLBACK
+CDot11SampleExtUI::HelpDlgProc (
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ CDot11SampleExtUI* pthis = NULL;
+
+ switch (uMsg)
+ {
+
+ case WM_INITDIALOG:
+ {
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ if(pthis && pthis->m_pUIRequest)
+ {
+ //
+ // Convert the ANSI string into a WCHAR string and display it
+ //
+ int iBufferSize = MultiByteToWideChar(CP_ACP, 0, pthis->m_pUIRequest->title, -1, NULL, 0);
+ if (iBufferSize > 0)
+ {
+ WCHAR *pwszBuffer = new WCHAR[iBufferSize];
+
+ if (NULL != pwszBuffer)
+ {
+ pwszBuffer[0] = 0;
+
+ (VOID)MultiByteToWideChar(CP_ACP, 0, pthis->m_pUIRequest->title, -1, pwszBuffer, iBufferSize);
+
+ SetDlgItemText(hwndDlg, IDC_EDIT_HELPER, pwszBuffer);
+
+ delete[] pwszBuffer;
+ }
+ }
+ }
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ {
+ // Don't release our properties here, wait
+ // rather for Abort or Commit event notifications.
+ // Then we will have the same values when resurrected.
+ }
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pnmh = (LPNMHDR) lParam;
+ switch (pnmh->code)
+ {
+
+ case PSN_SETACTIVE :
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
+ return TRUE;
+
+ case PSN_QUERYCANCEL:
+ {
+ IWizardSite *pIWizardSite = NULL;
+ HRESULT hr = S_OK;
+
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ if(pthis != NULL)
+ {
+ hr = pthis->m_pUnkSite->QueryInterface(IID_IWizardSite, (VOID **)&pIWizardSite);
+ if (SUCCEEDED(hr))
+ {
+ HPROPSHEETPAGE hpage = NULL;
+
+ hr = pIWizardSite->GetCancelledPage(&hpage);
+ if (SUCCEEDED(hr))
+ {
+ PropSheet_SetCurSel(GetParent(hwndDlg), hpage, 0);
+ }
+ pIWizardSite->Release();
+ }
+ }
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ return FALSE;
+
+}
+
+BOOL CALLBACK
+CDot11SampleExtUI::GetKeyDlgProc (
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+
+{
+ CDot11SampleExtUI* pthis = NULL;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ (VOID)GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ {
+ // Don't release our properties here, wait
+ // rather for Abort or Commit event notifications.
+ // Then we will have the same values when resurrected.
+ }
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pnmh = (LPNMHDR) lParam;
+ switch (pnmh->code)
+ {
+ case PSN_SETACTIVE :
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ return TRUE;
+
+ case PSN_WIZNEXT :
+ {
+ WCHAR szBuffer[50 + 1] = {0};
+ HRESULT hr = S_OK;
+ IPropertyBag *pIPropertyBag = NULL;
+
+ GetDlgItemText(hwndDlg, IDC_EDIT_KEY, szBuffer, 50);
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+
+ if(pthis)
+ {
+ hr = pthis->m_pUnkSite->QueryInterface(IID_IPropertyBag, (VOID **)&pIPropertyBag);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT v;
+ VariantInit(&v);
+
+ WCHAR ihvKeyName[IHV_KEY_LENGTH] = {0};
+ pthis->GetClsidPropertyName(
+ &GUID_SAMPLE_IHVUI_CLSID,
+ (LPWSTR) c_szIhvUIResponse,
+ ihvKeyName,
+ IHV_KEY_LENGTH
+ );
+
+ // Make sure we remove the previous property if any
+ hr = pIPropertyBag->Read(ihvKeyName, &v, NULL);
+
+ VariantClear(&v);
+ V_VT(&v) = VT_BSTR;
+ v.bstrVal = SysAllocStringByteLen((LPCSTR)szBuffer, IHV_KEY_LENGTH);
+
+ // Write the updated property if any
+ hr = pIPropertyBag->Write(ihvKeyName, &v);
+ pIPropertyBag->Release();
+
+ //
+ // hr is not used below
+ //
+ hr;
+ }
+ }
+ }
+ return TRUE;
+
+ case PSN_QUERYCANCEL:
+ {
+ IWizardSite *pIWizardSite = NULL;
+ HRESULT hr = S_OK;
+
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+
+ if(pthis)
+ {
+ hr = pthis->m_pUnkSite->QueryInterface(IID_IWizardSite,(VOID **)&pIWizardSite);
+ if (SUCCEEDED(hr))
+ {
+ HPROPSHEETPAGE hpage = NULL;
+ hr = pIWizardSite->GetCancelledPage(&hpage);
+ if (SUCCEEDED(hr))
+ {
+ PropSheet_SetCurSel(GetParent(hwndDlg), hpage, 0);
+ }
+ pIWizardSite->Release();
+ }
+ }
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ return FALSE;
+
+}
+
+BOOL CALLBACK
+CDot11SampleExtUI::LastPageDlgProc(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ CDot11SampleExtUI* pthis = NULL;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ (VOID)GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ {
+ (VOID)GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ }
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pnmh = (LPNMHDR) lParam;
+ switch (pnmh->code)
+ {
+ case PSN_SETACTIVE :
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ return TRUE;
+
+ case PSN_WIZNEXT :
+ {
+ IWizardSite *pIWizardSite = NULL;
+ HRESULT hr = S_OK;
+
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ if(pthis)
+ {
+ hr = pthis->m_pUnkSite->QueryInterface(IID_IWizardSite,(VOID **)&pIWizardSite);
+ if (SUCCEEDED(hr))
+ {
+ HPROPSHEETPAGE hpage = NULL;
+
+ hr = pIWizardSite->GetNextPage(&hpage);
+ if (SUCCEEDED(hr))
+ {
+ PropSheet_SetCurSel(GetParent(hwndDlg), hpage, 0);
+ }
+ pIWizardSite->Release();
+ }
+ }
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)-1);
+ }
+ return TRUE;
+
+ case PSN_QUERYCANCEL:
+ {
+ IWizardSite *pIWizardSite = NULL;
+ HRESULT hr = S_OK;
+
+ pthis = GetThis<CDot11SampleExtUI>(hwndDlg, uMsg, wParam, lParam);
+ if(pthis)
+ {
+ hr = pthis->m_pUnkSite->QueryInterface(IID_IWizardSite,(VOID **)&pIWizardSite);
+ if (SUCCEEDED(hr))
+ {
+ HPROPSHEETPAGE hpage = NULL;
+ hr = pIWizardSite->GetCancelledPage(&hpage);
+ if (SUCCEEDED(hr))
+ {
+ PropSheet_SetCurSel(GetParent(hwndDlg), hpage, 0);
+ }
+ pIWizardSite->Release();
+ }
+ }
+ }
+ return TRUE;
+
+ }
+ }
+ return FALSE;
+ }
+ return FALSE;
+
+}
+
+HRESULT CDot11SampleExtUI::GetClsidPropertyName (
+ _In_ const CLSID* pCLSID,
+ _In_opt_ PCWSTR pwszPropertyName,
+ _Out_writes_(maxResultLen) PWSTR pwszResultStr,
+ _In_ UINT maxResultLen)
+{
+ #define MIN_BUFFER_SIZE 50
+
+ wchar_t *pwszCLSID = NULL;
+ wchar_t *pwszKeyName = NULL;
+ HRESULT hRetCode = S_OK;
+ size_t iCharCount = 0;
+
+ // Sanity
+ //=======
+
+ if( pCLSID == NULL ||
+ pwszResultStr == NULL ||
+ maxResultLen < MIN_BUFFER_SIZE
+ )
+ {
+ return E_INVALIDARG;
+ }
+
+ // Convert CLSID to string
+ //========================
+
+ hRetCode = StringFromCLSID(*pCLSID, &pwszCLSID);
+ if(FAILED(hRetCode))
+ {
+ goto Done;
+ }
+
+ // Allocate buffer for entire CLSID\PropertyName string
+ //=====================================================
+
+ iCharCount = wcslen(pwszCLSID) + 1;
+ if(pwszPropertyName)
+ {
+ iCharCount += wcslen(pwszPropertyName);
+ }
+
+ pwszKeyName = new(std::nothrow) wchar_t[iCharCount];
+ if(pwszKeyName == NULL)
+ {
+ hRetCode = E_OUTOFMEMORY;
+ goto Done;
+ }
+
+ swprintf_s(pwszKeyName, iCharCount, L"%s%s", pwszCLSID, pwszPropertyName ? pwszPropertyName : L"");
+
+ // Copy as much as we can to the target buffer
+ //============================================
+
+ wcsncpy_s(pwszResultStr, maxResultLen, pwszKeyName, _TRUNCATE);
+
+Done:
+
+ if(pwszKeyName != NULL)
+ {
+ delete [] pwszKeyName;
+ }
+
+ if(pwszCLSID != NULL)
+ {
+ CoTaskMemFree(pwszCLSID);
+ }
+
+ return hRetCode;
+}
+
+
+
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUI.h b/network/wlan/ihvsampleui/IHVSampleExtUI.h
new file mode 100644
index 00000000..474c56a3
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUI.h
@@ -0,0 +1,238 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#ifndef _IHVSAMPLEEXTUI_H_
+#define _IHVSAMPLEEXTUI_H_
+
+#include "precomp.h"
+
+// object ref count
+extern long g_objRefCount;
+
+//lock count on server
+extern long g_serverLock;
+
+#define IHV_KEY_LENGTH 64
+
+#define MAX_IHV_CIPHERS 6
+#define MAX_IHV_AUTHS 6
+
+// IHV Auth types
+typedef enum _IHV_AUTH_TYPE {
+ IHVAuthV1,
+ IHVAuthV2,
+ IHVAuthV3,
+ IHVAuthInvalid
+} IHV_AUTH_TYPE, *PIHV_AUTH_TYPE;
+
+// IHV cipher types
+typedef enum _IHV_CIPHER_TYPE {
+ None,
+ IHVCipher1,
+ IHVCipher2,
+ IHVCipher3,
+ IHVCipherInvalid
+} IHV_CIPHER_TYPE, *PIHV_CIPHER_TYPE;
+
+// structure holding valid ciphers for a given auth
+typedef struct _IHV_AUTH_CIPHERS {
+ IHV_AUTH_TYPE IHVAuth;
+ DWORD dwCipherCount;
+ IHV_CIPHER_TYPE IHVCiphers[MAX_IHV_CIPHERS];
+} IHV_AUTH_CIPHERS, *PIHV_AUTH_CIPHERS;
+
+// structure for all auths and corresponding ciphers
+typedef struct _IHV_AUTH_CIPHER_CAPABILITY {
+ DWORD dwAuthCount;
+ IHV_AUTH_CIPHERS IhvAuthCiphers[MAX_IHV_AUTHS];
+} IHV_AUTH_CIPHER_CAPABILITY, *PIHV_AUTH_CIPHER_CAPABILITY;
+
+typedef struct _IHV_SECURITY_CONFIG {
+ IHV_AUTH_TYPE Auth;
+ IHV_CIPHER_TYPE Cipher;
+} IHV_SECURITY_CONFIG, *PIHV_SECURITY_CONFIG;
+
+extern IHV_AUTH_CIPHER_CAPABILITY g_IHVOneXExtCapability;
+
+extern LPWSTR g_IHVAuthFriendlyName[];
+extern LPWSTR g_IHVCipherFriendlyName[];
+
+
+#define PROP_COUNT_CONNECTION 1
+
+#define PROP_COUNT_SECURITY 2
+#define PROP_COUNT_SEC_CIPHERS 2
+typedef enum _IHV_SECURITY_TYPE {
+ IHVSecurityV1,
+ IHVSecurityV2,
+ IHVSecurityInvalid
+} IHV_SECURITY_TYPE, *PIHV_SECURITY_TYPE;
+static LPWSTR wstrSecurityTypes[] = { L"IHV Security v1", L"IHV Security v2" };
+
+#define PROP_COUNT_KEYEXTENSION 3
+static LPWSTR wstrAuthArray[] = { L"IHVAuth Open-with-1X", L"IHVAuth v1", L"IHVAuth v2" };
+
+
+
+
+#define IHV_CIPHER_COUNT 3
+static LPWSTR wstrCipherArray[] = { L"None", L"IHVCipher v1", L"IHVCipher v2" };
+static LPWSTR wstr1XCipherArray[] = { L"IHVCipher WEP"};
+static BSTR bstrCipherArray[IHV_CIPHER_COUNT] = {0};
+
+typedef struct _IHV_CIPHERS_FOR_AUTH_INFO
+{
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO displayInfo[IHV_CIPHER_COUNT];
+} IHV_CIPHERS_FOR_AUTH_INFO;
+static DOT11_EXT_UI_PROPERTY_DISPLAY_INFO cipherOne = {1, DOT11_EXT_UI_DISPLAY_INFO_CIPHER, 0};
+static DOT11_EXT_UI_PROPERTY_DISPLAY_INFO cipherTwo = {2, DOT11_EXT_UI_DISPLAY_INFO_CIPHER, 0};
+static DOT11_EXT_UI_PROPERTY_DISPLAY_INFO cipherThree = {3, DOT11_EXT_UI_DISPLAY_INFO_CIPHER, 0};
+static DOT11_EXT_UI_PROPERTY_DISPLAY_INFO ciphersInfoArray[MAX_IHV_AUTHS][MAX_IHV_CIPHERS] = {0};
+
+
+//////// structures for balloon /////////
+
+struct IHV_UI_REQUEST
+{
+ char title[80];
+ char help[80];
+
+ IHV_UI_REQUEST()
+ {
+ memset(this, 0, sizeof(IHV_UI_REQUEST));
+ }
+};
+
+struct IHV_UI_RESPONSE
+{
+ char key[100];
+ int num[150];
+
+ IHV_UI_RESPONSE()
+ {
+ memset(this, 0, sizeof(IHV_UI_RESPONSE));
+ }
+};
+
+
+class CDot11SampleExtUI: public IDot11SampleExtUI, public IWizardExtension, public IObjectWithSite
+{
+public:
+ CDot11SampleExtUI();
+
+ ~CDot11SampleExtUI();
+
+ // IUnknown Implementation
+ BEGIN_INTERFACE_TABLE()
+ IMPLEMENTS_INTERFACE(IDot11ExtUI)
+ IMPLEMENTS_INTERFACE(IDot11SampleExtUI)
+ IMPLEMENTS_INTERFACE(IWizardExtension)
+ IMPLEMENTS_INTERFACE(IObjectWithSite)
+ END_INTERFACE_TABLE();
+
+ // Used to get the IHV friendly name
+ STDMETHODIMP
+ GetDot11ExtUIFriendlyName(BSTR* bstrFriendlyName);
+
+ // Used to display an IHV specific connection page
+ STDMETHODIMP
+ GetDot11ExtUIProperties(
+ DOT11_EXT_UI_PROPERTY_TYPE ExtType,
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ );
+
+ STDMETHODIMP
+ GetDot11ExtUIBalloonText(
+ BSTR pIHVUIRequest, // the UI request structure from IHV
+ BSTR* pwszBalloonText // the balloon text to be displayed
+ );
+
+ HRESULT
+ CreateConnectionProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ );
+
+ HRESULT
+ CreateSecurityProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ );
+
+ HRESULT
+ CreateKeyProperties(
+ ULONG *pcExtensions,
+ IDot11ExtUIProperty **ppDot11ExtUIProperty
+ );
+
+ // IObjectWithSite
+ STDMETHOD (SetSite) (
+ IUnknown* pUnkSite
+ );
+
+ STDMETHOD (GetSite) (
+ REFIID riid,
+ void** ppvSite
+ );
+
+ //IWizardExtension
+ STDMETHOD (AddPages) (
+ HPROPSHEETPAGE* aPages,
+ UINT cPages,
+ UINT *pnPagesAdded
+ );
+
+ STDMETHOD (GetFirstPage) (
+ HPROPSHEETPAGE *phpage
+ );
+
+ STDMETHOD (GetLastPage) (
+ HPROPSHEETPAGE *phpage
+ );
+
+private:
+ HRESULT FinalConstruct();
+ void FinalRelease();
+ static BOOL CALLBACK GetKeyDlgProc (
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+
+ static BOOL CALLBACK HelpDlgProc (
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+ static BOOL CALLBACK LastPageDlgProc (
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+ HRESULT GetClsidPropertyName (
+ _In_ const CLSID* pCLSID,
+ _In_opt_ PCWSTR pwszPropertyName,
+ _Out_writes_(maxResultLen) PWSTR pResultStr,
+ _In_ UINT maxResultLen);
+
+private:
+ IHV_UI_REQUEST* m_pUIRequest;
+ IHV_UI_RESPONSE m_UIResponse;
+
+ IUnknown* m_pUnkSite;
+
+ HPROPSHEETPAGE m_hFirstPagePsp;
+ HPROPSHEETPAGE m_hLastPagePsp;
+};
+
+
+#endif _IHVSAMPLEEXTUI_H_
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUICon.cpp b/network/wlan/ihvsampleui/IHVSampleExtUICon.cpp
new file mode 100644
index 00000000..e5eeb6cd
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUICon.cpp
@@ -0,0 +1,345 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+extern HINSTANCE g_hInst;
+
+// used by the con prop extensions
+CIhvConnectivityProfile* pIhvConProfile;
+
+
+CDot11SampleExtUIConProperty::CDot11SampleExtUIConProperty():
+ m_crefCount(0), m_fInitialized(false),
+ m_ExtType(DOT11_EXT_UI_CONNECTION), m_fModified(FALSE)
+{
+ m_bstrFN = NULL;
+ InterlockedIncrement(&g_objRefCount);
+}
+
+CDot11SampleExtUIConProperty::~CDot11SampleExtUIConProperty()
+{
+ SysFreeString(m_bstrFN);
+ InterlockedDecrement(&g_objRefCount);
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIConProperty::GetDot11ExtUIPropertyFriendlyName(BSTR* bstrPropertyName)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (false == m_fInitialized)
+ {
+ return hr;
+ }
+
+ if (NULL != bstrPropertyName)
+ {
+ *bstrPropertyName = SysAllocString(m_bstrFN);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//Used to extend property
+STDMETHODIMP
+CDot11SampleExtUIConProperty::DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if (!m_fInitialized)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ // Store the passed-in string in a member variable so dialog box can display it
+ pIhvConProfile = new(std::nothrow) CIhvConnectivityProfile();
+ if (pIhvConProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvConProfile->LoadXml(bstrIHVProfile);
+ m_fModified = FALSE;
+
+ // Dialog will store the string in a member variable
+ DialogBoxParam(
+ g_hInst,
+ MAKEINTRESOURCE(IDD_PROPPAGE_SMALL),
+ hParent,
+ SimpleDialogProcCon,
+ (LPARAM)pIhvConProfile
+ );
+
+ m_fModified = pIhvConProfile->GetModified();
+
+ if (NULL != bstrModifiedIHVProfile)
+ {
+ if (m_fModified)
+ {
+ pIhvConProfile->EmitXml(bstrModifiedIHVProfile);
+ }
+ }
+
+ if (NULL != pbIsModified)
+ {
+ *pbIsModified = m_fModified;
+ }
+
+error:
+ if(pIhvConProfile)
+ {
+ delete pIhvConProfile;
+ pIhvConProfile = NULL;
+ }
+
+ return hr;
+}
+
+
+//Used to get the currently chosen entry to display as selected in the dropdown list
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(bstrIHVProfile);
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ // since there is only one connection profile always set it to true
+ *pfIsSelected = TRUE;
+
+ return hr;
+}
+
+//Used to set the current entry as chosen from the dropdown list
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(bstrModifiedIHVProfile == NULL || pbIsModified == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ // in case the profile is NULL this will supply the default
+ pIhvConProfile = new(std::nothrow) CIhvConnectivityProfile();
+ if (pIhvConProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvConProfile->LoadXml(bstrIHVProfile);
+
+ pIhvConProfile->EmitXml(bstrModifiedIHVProfile);
+ *pbIsModified = pIhvConProfile->GetModified();
+
+error:
+ if(pIhvConProfile != NULL)
+ {
+ delete pIhvConProfile;
+ pIhvConProfile = NULL;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertyHasConfigurationUI(
+ BOOL *fHasConfigurationUI
+ )
+{
+ // this page always wants to show a config UI
+ *fHasConfigurationUI = TRUE;
+ return S_OK;
+}
+
+//Used to get additional display data (ciphers for auth types)
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ )
+{
+ UNREFERENCED_PARAMETER(dot11ExtUIDisplayInfoType);
+ UNREFERENCED_PARAMETER(pIHVParams);
+ UNREFERENCED_PARAMETER(bstrIHVProfile);
+ // we have no additional data to display
+ *pcEntries = 0;
+ *puDefaultSelection = 0;
+ *ppDot11ExtUIProperty = NULL;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ UNREFERENCED_PARAMETER(dot11ExtUIDisplayInfoType);
+ UNREFERENCED_PARAMETER(bstrIHVProfile);
+ UNREFERENCED_PARAMETER(pIHVParams);
+ UNREFERENCED_PARAMETER(pDot11ExtUIProperty);
+ UNREFERENCED_PARAMETER(bstrModifiedIHVProfile);
+ UNREFERENCED_PARAMETER(pbIsModified);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ )
+{
+ UNREFERENCED_PARAMETER(dot11ExtUISecurityType);
+ *fIsStandardSecurity = FALSE;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP
+CDot11SampleExtUIConProperty::Initialize(BSTR bstrPropertyName)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (false == m_fInitialized)
+ {
+ // Set the FriendlyName
+ m_bstrFN = SysAllocString(bstrPropertyName);
+ m_fInitialized = true;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+INT_PTR CALLBACK
+SimpleDialogProcCon(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ BOOL fRetVal = FALSE;
+ WCHAR szBuf[256] = {0};
+ DWORD dwValue = 0;
+ BSTR bstrText = NULL;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if(!pIhvConProfile)
+ {
+ goto error;
+ }
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // Dialog title
+ WCHAR strDialogTitle[MAX_PATH] = {0};
+ (VOID)::LoadString(
+ g_hInst,
+ IDS_IHV_DEFAULT_CON_TITLE,
+ strDialogTitle,
+ MAX_PATH
+ );
+
+ SetWindowText(hwndDlg, strDialogTitle);
+ }
+
+ // check the checkbox if needed
+ if(FAILED(pIhvConProfile->GetParamDWORD(&dwValue)))
+ {
+ dwValue = 0;
+ }
+ ::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_SETCHECK,
+ (WPARAM)(int)dwValue,
+ 0L
+ );
+
+ // Set text in the textbox
+ if(FAILED(pIhvConProfile->GetParamBSTR(&bstrText)))
+ {
+ bstrText = NULL;
+ }
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), bstrText);
+
+ fRetVal = TRUE;
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_OK:
+ GetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), szBuf, 255);
+ if(szBuf)
+ {
+ DWORD dwNewValue = 0;
+
+ // get the button state and record it
+ dwNewValue = (int)::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_GETCHECK,
+ 0L,
+ 0L
+ );
+
+ pIhvConProfile->SetParamDWORD(dwNewValue);
+ pIhvConProfile->SetParamBSTR(szBuf);
+
+ // Notify the owner window to carry out the task.
+ EndDialog(hwndDlg, 1);
+ fRetVal = TRUE;
+ }
+ break;
+
+ case ID_CANCEL:
+ EndDialog(hwndDlg, 0);
+ fRetVal = TRUE;
+ break;
+ }
+ break;
+ }
+
+error:
+ return fRetVal;
+}
+
+
+
+
+
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUICon.h b/network/wlan/ihvsampleui/IHVSampleExtUICon.h
new file mode 100644
index 00000000..fd58c106
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUICon.h
@@ -0,0 +1,103 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#ifndef _IHVSAMPLEEXTUICON_H_
+#define _IHVSAMPLEEXTUICON_H_
+
+class CDot11SampleExtUIConProperty: public IDot11SampleExtUIConProperty
+{
+public:
+ CDot11SampleExtUIConProperty();
+
+ ~CDot11SampleExtUIConProperty();
+
+ // IUnknown Implementation
+ BEGIN_INTERFACE_TABLE()
+ IMPLEMENTS_INTERFACE(IDot11SampleExtUIConProperty)
+ END_INTERFACE_TABLE();
+
+ STDMETHODIMP
+ GetDot11ExtUIPropertyFriendlyName(
+ BSTR* bstrPropertyName // IHV friendly name
+ );
+
+ //Used to extend property
+ STDMETHODIMP
+ DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ //Used to get the currently chosen entry to display as selected in the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ );
+
+ //Used to set the current entry as chosen from the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyHasConfigurationUI(BOOL *fHasConfigurationUI);
+
+ //Used to get additional display data (ciphers for auth types)
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ );
+
+ // initialize the connection page
+ STDMETHODIMP
+ Initialize(BSTR bstrPropertyName);
+
+private:
+ bool m_fInitialized;
+ BSTR m_bstrFN;
+ DOT11_EXT_UI_PROPERTY_TYPE m_ExtType;
+ BOOL m_fModified;
+};
+
+
+INT_PTR CALLBACK
+SimpleDialogProcCon(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+);
+
+#endif _IHVSAMPLEEXTUICON_H_
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUIKey.cpp b/network/wlan/ihvsampleui/IHVSampleExtUIKey.cpp
new file mode 100644
index 00000000..19c9610a
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUIKey.cpp
@@ -0,0 +1,462 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+extern HINSTANCE g_hInst;
+
+// used by the con prop extensions
+CIhvSecurityProfile* pIhvKeyProfile;
+
+
+CDot11SampleExtUIKeyProperty::CDot11SampleExtUIKeyProperty():
+ m_crefCount(0), m_fInitialized(false),
+ m_ExtType(DOT11_EXT_UI_KEYEXTENSION), m_fModified(FALSE)
+{
+ InterlockedIncrement(&g_objRefCount);
+ memset(
+ &m_IHVAuthCiphers,
+ 0,
+ sizeof(IHV_AUTH_CIPHERS)
+ );
+ m_bstrFN = NULL;
+}
+
+CDot11SampleExtUIKeyProperty::~CDot11SampleExtUIKeyProperty()
+{
+ if(m_bstrFN != NULL) {
+ SysFreeString(m_bstrFN);
+ }
+
+ InterlockedDecrement(&g_objRefCount);
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::GetDot11ExtUIPropertyFriendlyName(BSTR* bstrPropertyName)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (false == m_fInitialized)
+ {
+ return hr;
+ }
+
+ if (NULL != g_IHVAuthFriendlyName[m_IHVAuthCiphers.IHVAuth])
+ {
+ *bstrPropertyName = SysAllocString(g_IHVAuthFriendlyName[m_IHVAuthCiphers.IHVAuth]);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//Used to extend property
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if (!m_fInitialized)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ // Store the passed-in string in a member variable so dialog box can display it
+ pIhvKeyProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvKeyProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvKeyProfile->LoadXml(bstrIHVProfile);
+ m_fModified = FALSE;
+
+ // Dialog will store the string in a member variable
+ DialogBoxParam(
+ g_hInst,
+ MAKEINTRESOURCE(IDD_PROPPAGE_SMALL),
+ hParent,
+ SimpleDialogProcKey,
+ (LPARAM)pIhvKeyProfile
+ );
+
+ m_fModified = pIhvKeyProfile->GetModified();
+
+ if (NULL != bstrModifiedIHVProfile)
+ {
+ if (m_fModified)
+ {
+ pIhvKeyProfile->EmitXml(bstrModifiedIHVProfile);
+ }
+ }
+
+ if (NULL != pbIsModified)
+ {
+ *pbIsModified = m_fModified;
+ }
+
+error:
+ if(pIhvKeyProfile)
+ {
+ delete pIhvKeyProfile;
+ pIhvKeyProfile = NULL;
+ }
+
+ return hr;
+}
+
+
+//Used to get the currently chosen entry to display as selected in the dropdown list
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ )
+{
+ HRESULT hr = S_OK;
+ IHV_AUTH_TYPE currentAuthType = IHVAuthInvalid;
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(pfIsSelected == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ *pfIsSelected = FALSE;
+
+ pIhvKeyProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvKeyProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvKeyProfile->LoadXml(bstrIHVProfile);
+
+ hr = pIhvKeyProfile->GetAuthType(&currentAuthType);
+ if(FAILED(hr))
+ {
+ // if it fails then choose a default selected auth
+ hr = S_OK;
+ if(IHVAuthV1 == m_IHVAuthCiphers.IHVAuth)
+ {
+ *pfIsSelected = TRUE;
+ }
+ }
+ else if(currentAuthType == m_IHVAuthCiphers.IHVAuth)
+ {
+ *pfIsSelected = TRUE;
+ }
+
+error:
+ if(pIhvKeyProfile != NULL)
+ {
+ delete pIhvKeyProfile;
+ pIhvKeyProfile = NULL;
+ }
+ return hr;
+}
+
+//Used to set the current entry as chosen from the dropdown list
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(bstrModifiedIHVProfile == NULL || pbIsModified == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ pIhvKeyProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvKeyProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvKeyProfile->LoadXml(bstrIHVProfile);
+
+ pIhvKeyProfile->SetAuthType(m_IHVAuthCiphers.IHVAuth);
+ pIhvKeyProfile->SetFullSecurityFlag(FALSE);
+
+ pIhvKeyProfile->EmitXml(bstrModifiedIHVProfile);
+ *pbIsModified = pIhvKeyProfile->GetModified();
+
+error:
+ if(pIhvKeyProfile != NULL)
+ {
+ delete pIhvKeyProfile;
+ pIhvKeyProfile = NULL;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertyHasConfigurationUI(
+ BOOL *fHasConfigurationUI)
+{
+ // this page always wants to show a config UI unless its of IHVAuthOpen1X auth
+ *fHasConfigurationUI = (m_IHVAuthCiphers.IHVAuth == IHVAuthV3)?FALSE:TRUE;
+ return S_OK;
+}
+
+//Used to get additional display data (ciphers for auth types)
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ )
+{
+ HRESULT hr = S_OK;
+ DWORD i = 0;
+ DWORD dwDefaultSelection = 0;
+ CIhvSecurityProfile IhvSecurityProfile;
+ IHV_CIPHER_TYPE cipherType = IHVCipherInvalid;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(dot11ExtUIDisplayInfoType != DOT11_EXT_UI_DISPLAY_INFO_CIPHER)
+ {
+ hr = E_NOTIMPL;
+ goto error;
+ }
+
+ IhvSecurityProfile.LoadXml(bstrIHVProfile);
+ hr = IhvSecurityProfile.GetCipherType(&cipherType);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+
+ for(i = 0; i < m_IHVAuthCiphers.dwCipherCount; ++i)
+ {
+ ciphersInfoArray[m_IHVAuthCiphers.IHVAuth][i].dwDataKey = m_IHVAuthCiphers.IHVCiphers[i];
+ ciphersInfoArray[m_IHVAuthCiphers.IHVAuth][i].dot11ExtUIDisplayInfoType = DOT11_EXT_UI_DISPLAY_INFO_CIPHER;
+ ciphersInfoArray[m_IHVAuthCiphers.IHVAuth][i].bstrDisplayText = SysAllocString(g_IHVCipherFriendlyName[m_IHVAuthCiphers.IHVCiphers[i]]);
+
+ if(m_IHVAuthCiphers.IHVCiphers[i] == cipherType)
+ {
+ dwDefaultSelection = i;
+ }
+ }
+
+ // for the given auth type we want to return the list of compatible ciphers
+ *ppDot11ExtUIProperty = ciphersInfoArray[m_IHVAuthCiphers.IHVAuth];
+ *pcEntries = m_IHVAuthCiphers.dwCipherCount;
+ *puDefaultSelection = dwDefaultSelection;
+
+error:
+ return hr;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+
+ CIhvSecurityProfile IhvSecurityProfile;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(dot11ExtUIDisplayInfoType != DOT11_EXT_UI_DISPLAY_INFO_CIPHER)
+ {
+ hr = E_NOTIMPL;
+ goto error;
+ }
+
+ if(pDot11ExtUIProperty == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ hr = IhvSecurityProfile.LoadXml(bstrIHVProfile);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+ hr = IhvSecurityProfile.SetCipherType((IHV_CIPHER_TYPE)pDot11ExtUIProperty->dwDataKey);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+
+ hr = IhvSecurityProfile.EmitXml(bstrModifiedIHVProfile);
+ *pbIsModified = IhvSecurityProfile.GetModified();
+
+error:
+ return hr;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ )
+{
+ *fIsStandardSecurity = FALSE;
+
+ if (m_IHVAuthCiphers.IHVAuth == IHVAuthV1)
+ {
+ *fIsStandardSecurity = TRUE;
+ *dot11ExtUISecurityType = DOT11_EXT_UI_SECURITY_8021X;
+ }
+
+ return S_OK;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUIKeyProperty::Initialize(BYTE* pbData)
+{
+ HRESULT hr = E_INVALIDARG;
+ PIHV_AUTH_CIPHERS pIhvAuthCiphers = NULL;
+ pIhvAuthCiphers = (PIHV_AUTH_CIPHERS) pbData;
+
+ if (false == m_fInitialized)
+ {
+ // Set the FriendlyName
+ m_fInitialized = true;
+ memcpy(
+ &m_IHVAuthCiphers,
+ pIhvAuthCiphers,
+ sizeof(IHV_AUTH_CIPHERS)
+ );
+ hr = S_OK;
+ }
+ return hr;
+}
+
+INT_PTR CALLBACK
+SimpleDialogProcKey(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ BOOL fRetVal = FALSE;
+ WCHAR szBuf[256] = {0};
+ DWORD dwValue = 0;
+ BSTR bstrText = NULL;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if(!pIhvKeyProfile)
+ {
+ goto error;
+ }
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // Dialog title
+ WCHAR strDialogTitle[MAX_PATH] = {0};
+ (VOID)::LoadString(
+ g_hInst,
+ IDS_IHV_DEFAULT_KEY_TITLE,
+ strDialogTitle,
+ MAX_PATH
+ );
+
+ SetWindowText(hwndDlg, strDialogTitle);
+ }
+
+ // check the checkbox if needed
+ if(FAILED(pIhvKeyProfile->GetParamDWORD(&dwValue)))
+ {
+ dwValue = 0;
+ }
+ ::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_SETCHECK,
+ (WPARAM)(int)dwValue,
+ 0L
+ );
+
+ // Set text in the textbox
+ if(FAILED(pIhvKeyProfile->GetParamBSTR(&bstrText)))
+ {
+ bstrText = NULL;
+ }
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), bstrText);
+
+ fRetVal = TRUE;
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_OK:
+ GetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), szBuf, 255);
+ if(szBuf)
+ {
+ DWORD dwNewValue = 0;
+
+ // get the button state and record it
+ dwNewValue = (int)::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_GETCHECK,
+ 0L,
+ 0L
+ );
+
+ pIhvKeyProfile->SetParamDWORD(dwNewValue);
+ pIhvKeyProfile->SetParamBSTR(szBuf);
+ pIhvKeyProfile->SetFullSecurityFlag(FALSE);
+
+ // Notify the owner window to carry out the task.
+ EndDialog(hwndDlg, 1);
+ fRetVal = TRUE;
+ }
+ break;
+
+ case ID_CANCEL:
+ EndDialog(hwndDlg, 0);
+ fRetVal = TRUE;
+ break;
+ }
+ break;
+ }
+
+error:
+ return fRetVal;
+}
+
+
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUIKey.h b/network/wlan/ihvsampleui/IHVSampleExtUIKey.h
new file mode 100644
index 00000000..c106e549
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUIKey.h
@@ -0,0 +1,104 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#ifndef _IHVSAMPLEEXTUIKEY_H_
+#define _IHVSAMPLEEXTUIKEY_H_
+
+class CDot11SampleExtUIKeyProperty: public IDot11SampleExtUIKeyProperty
+{
+public:
+ CDot11SampleExtUIKeyProperty();
+
+ ~CDot11SampleExtUIKeyProperty();
+
+ // IUnknown Implementation
+ BEGIN_INTERFACE_TABLE()
+ IMPLEMENTS_INTERFACE(IDot11SampleExtUIKeyProperty)
+ END_INTERFACE_TABLE();
+
+ STDMETHODIMP
+ GetDot11ExtUIPropertyFriendlyName(
+ BSTR* bstrPropertyName // IHV friendly name
+ );
+
+ //Used to extend property
+ STDMETHODIMP
+ DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ //Used to get the currently chosen entry to display as selected in the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ );
+
+ //Used to set the current entry as chosen from the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyHasConfigurationUI(BOOL *fHasConfigurationUI);
+
+ //Used to get additional display data (ciphers for auth types)
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ );
+
+ // initialize the key extension page
+ STDMETHODIMP
+ Initialize(BYTE* pbData);
+
+private:
+ bool m_fInitialized;
+ BSTR m_bstrFN;
+ DOT11_EXT_UI_PROPERTY_TYPE m_ExtType;
+ BOOL m_fModified;
+ IHV_AUTH_CIPHERS m_IHVAuthCiphers;
+};
+
+
+INT_PTR CALLBACK
+SimpleDialogProcKey(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+);
+
+#endif _IHVSAMPLEEXTUIKEY_H_
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUISec.cpp b/network/wlan/ihvsampleui/IHVSampleExtUISec.cpp
new file mode 100644
index 00000000..1cfa3714
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUISec.cpp
@@ -0,0 +1,434 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+extern HINSTANCE g_hInst;
+
+// used by the con prop extensions
+CIhvSecurityProfile* pIhvSecProfile;
+
+CDot11SampleExtUISecProperty::CDot11SampleExtUISecProperty():
+ m_crefCount(0), m_fInitialized(false),
+ m_ExtType(DOT11_EXT_UI_SECURITY), m_fModified(FALSE),
+ m_IhvSecurityType(IHVSecurityInvalid)
+{
+ m_bstrFN = NULL;
+ InterlockedIncrement(&g_objRefCount);
+}
+
+CDot11SampleExtUISecProperty::~CDot11SampleExtUISecProperty()
+{
+ SysFreeString(m_bstrFN);
+ InterlockedDecrement(&g_objRefCount);
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUISecProperty::GetDot11ExtUIPropertyFriendlyName(BSTR* bstrPropertyName)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (false == m_fInitialized)
+ {
+ return hr;
+ }
+
+ if (NULL != bstrPropertyName)
+ {
+ *bstrPropertyName = SysAllocString(m_bstrFN);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//Used to extend property
+STDMETHODIMP
+CDot11SampleExtUISecProperty::DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if (!m_fInitialized)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ // Store the passed-in string in a member variable so dialog box can display it
+ pIhvSecProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvSecProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+ pIhvSecProfile->LoadXml(bstrIHVProfile);
+ m_fModified = FALSE;
+
+ // Dialog will store the string in a member variable
+ DialogBoxParam(
+ g_hInst,
+ MAKEINTRESOURCE(IDD_PROPPAGE_SMALL),
+ hParent,
+ SimpleDialogProcSec,
+ (LPARAM)pIhvSecProfile
+ );
+
+ m_fModified = pIhvSecProfile->GetModified();
+
+ if (NULL != bstrModifiedIHVProfile)
+ {
+ if (m_fModified)
+ {
+ pIhvSecProfile->EmitXml(bstrModifiedIHVProfile);
+ }
+ }
+
+ if (NULL != pbIsModified)
+ {
+ *pbIsModified = m_fModified;
+ }
+
+error:
+ if(pIhvSecProfile)
+ {
+ delete pIhvSecProfile;
+ pIhvSecProfile = NULL;
+ }
+
+ return hr;
+}
+
+
+//Used to get the currently chosen entry to display as selected in the dropdown list
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ )
+{
+ HRESULT hr = S_OK;
+ IHV_SECURITY_TYPE currentSecurityType = IHVSecurityInvalid;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(pfIsSelected == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ *pfIsSelected = FALSE;
+
+ pIhvSecProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvSecProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvSecProfile->LoadXml(bstrIHVProfile);
+
+ hr = pIhvSecProfile->GetSecurityType(&currentSecurityType);
+ if(FAILED(hr))
+ {
+ hr = S_OK;
+ if(IHVSecurityV1 == m_IhvSecurityType)
+ {
+ *pfIsSelected = TRUE;
+ }
+ }
+ else if(currentSecurityType == m_IhvSecurityType)
+ {
+ *pfIsSelected = TRUE;
+ }
+
+error:
+ if(pIhvSecProfile != NULL)
+ {
+ delete pIhvSecProfile;
+ pIhvSecProfile = NULL;
+ }
+ return hr;
+}
+
+//Used to set the current entry as chosen from the dropdown list
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(bstrModifiedIHVProfile == NULL || pbIsModified == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ pIhvSecProfile = new(std::nothrow) CIhvSecurityProfile();
+ if (pIhvSecProfile == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+
+ pIhvSecProfile->LoadXml(bstrIHVProfile);
+
+ pIhvSecProfile->SetSecurityType(m_IhvSecurityType);
+ pIhvSecProfile->SetFullSecurityFlag(TRUE);
+
+ pIhvSecProfile->EmitXml(bstrModifiedIHVProfile );
+ *pbIsModified = pIhvSecProfile->GetModified();
+
+error:
+ if(pIhvSecProfile != NULL)
+ {
+ delete pIhvSecProfile;
+ pIhvSecProfile = NULL;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertyHasConfigurationUI(
+ BOOL *fHasConfigurationUI)
+{
+ // this page always wants to show a config UI
+ *fHasConfigurationUI = TRUE;
+ return S_OK;
+}
+
+//Used to get additional display data (ciphers for auth types)
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ )
+{
+ HRESULT hr = S_OK;
+ DWORD i = 0;
+ CIhvSecurityProfile IhvSecurityProfile;
+ IHV_CIPHER_TYPE cipherType = IHVCipherInvalid;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ if(dot11ExtUIDisplayInfoType != DOT11_EXT_UI_DISPLAY_INFO_CIPHER)
+ {
+ hr = E_NOTIMPL;
+ goto error;
+ }
+
+ IhvSecurityProfile.LoadXml(bstrIHVProfile);
+ hr = IhvSecurityProfile.GetCipherType(&cipherType);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+
+ for(i = 0; i < PROP_COUNT_SEC_CIPHERS; ++i)
+ {
+ ciphersInfoArray[m_IhvSecurityType][i].dwDataKey = i;
+ ciphersInfoArray[m_IhvSecurityType][i].dot11ExtUIDisplayInfoType = DOT11_EXT_UI_DISPLAY_INFO_CIPHER;
+ ciphersInfoArray[m_IhvSecurityType][i].bstrDisplayText = SysAllocString(g_IHVCipherFriendlyName[i]);
+ }
+
+ // for the given auth type we want to return the list of compatible ciphers
+ *ppDot11ExtUIProperty = ciphersInfoArray[m_IhvSecurityType];
+ *pcEntries = PROP_COUNT_SEC_CIPHERS;
+ *puDefaultSelection = cipherType >= IHVCipherInvalid ? 0 : cipherType;
+
+error:
+ return hr;
+}
+
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(pIHVParams);
+
+ CIhvSecurityProfile IhvSecurityProfile;
+
+ if(dot11ExtUIDisplayInfoType != DOT11_EXT_UI_DISPLAY_INFO_CIPHER)
+ {
+ hr = E_NOTIMPL;
+ goto error;
+ }
+
+ if(pDot11ExtUIProperty == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto error;
+ }
+
+ hr = IhvSecurityProfile.LoadXml(bstrIHVProfile);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+ hr = IhvSecurityProfile.SetCipherType((IHV_CIPHER_TYPE)pDot11ExtUIProperty->dwDataKey);
+ if(FAILED(hr))
+ {
+ goto error;
+ }
+
+ hr = IhvSecurityProfile.EmitXml(bstrModifiedIHVProfile);
+ *pbIsModified = IhvSecurityProfile.GetModified();
+
+error:
+ return hr;
+}
+
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ )
+{
+ UNREFERENCED_PARAMETER(dot11ExtUISecurityType);
+ *fIsStandardSecurity = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP
+CDot11SampleExtUISecProperty::Initialize(BSTR bstrPropertyName, DWORD dwIhvSecurity)
+{
+ HRESULT hr = E_INVALIDARG;
+ if (false == m_fInitialized)
+ {
+ // Set the FriendlyName
+ m_bstrFN = SysAllocString(bstrPropertyName);
+ m_IhvSecurityType = (IHV_SECURITY_TYPE)dwIhvSecurity;
+ m_fInitialized = true;
+ hr = S_OK;
+ }
+ return hr;
+}
+
+INT_PTR CALLBACK
+SimpleDialogProcSec(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ BOOL fRetVal = FALSE;
+ WCHAR szBuf[256] = {0};
+ DWORD dwValue = 0;
+ BSTR bstrText = NULL;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if(!pIhvSecProfile)
+ {
+ goto error;
+ }
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ // Dialog title
+ WCHAR strDialogTitle[MAX_PATH] = {0};
+ (VOID)::LoadString(
+ g_hInst,
+ IDS_IHV_DEFAULT_SEC_TITLE,
+ strDialogTitle,
+ MAX_PATH
+ );
+
+ SetWindowText(hwndDlg, strDialogTitle);
+ }
+
+ // check the checkbox if needed
+ if(FAILED(pIhvSecProfile->GetParamDWORD(&dwValue)))
+ {
+ dwValue = 0;
+ }
+ ::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_SETCHECK,
+ (WPARAM)(int)dwValue,
+ 0L
+ );
+
+ // Set text in the textbox
+ if(FAILED(pIhvSecProfile->GetParamBSTR(&bstrText)))
+ {
+ bstrText = NULL;
+ }
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), bstrText);
+
+ fRetVal = TRUE;
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_OK:
+ GetWindowText(GetDlgItem(hwndDlg, IDC_PARAM_BOX), szBuf, 255);
+ if(szBuf)
+ {
+ DWORD dwNewValue = 0;
+
+ // get the button state and record it
+ dwNewValue = (int)::SendMessage(
+ GetDlgItem(hwndDlg, IDC_USE_FASTHANDOFF),
+ BM_GETCHECK,
+ 0L,
+ 0L
+ );
+
+ pIhvSecProfile->SetParamDWORD(dwNewValue);
+ pIhvSecProfile->SetParamBSTR(szBuf);
+ pIhvSecProfile->SetFullSecurityFlag(TRUE);
+
+ // Notify the owner window to carry out the task.
+ EndDialog(hwndDlg, 1);
+ fRetVal = TRUE;
+ }
+ break;
+
+ case ID_CANCEL:
+ EndDialog(hwndDlg, 0);
+ fRetVal = TRUE;
+ break;
+ }
+ break;
+ }
+
+error:
+ return fRetVal;
+}
+
+
diff --git a/network/wlan/ihvsampleui/IHVSampleExtUISec.h b/network/wlan/ihvsampleui/IHVSampleExtUISec.h
new file mode 100644
index 00000000..fc8caa2e
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleExtUISec.h
@@ -0,0 +1,105 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#ifndef _IHVSAMPLEEXTUISEC_H_
+#define _IHVSAMPLEEXTUISEC_H_
+
+class CDot11SampleExtUISecProperty: public IDot11SampleExtUISecProperty
+{
+public:
+ CDot11SampleExtUISecProperty();
+
+ ~CDot11SampleExtUISecProperty();
+
+ // IUnknown Implementation
+ BEGIN_INTERFACE_TABLE()
+ IMPLEMENTS_INTERFACE(IDot11SampleExtUISecProperty)
+ END_INTERFACE_TABLE();
+
+ STDMETHODIMP
+ GetDot11ExtUIPropertyFriendlyName(
+ BSTR* bstrPropertyName // IHV friendly name
+ );
+
+ //Used to extend property
+ STDMETHODIMP
+ DisplayDot11ExtUIProperty(
+ HWND hParent, // Parent Window Handle
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ //Used to get the currently chosen entry to display as selected in the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BOOL* pfIsSelected // flag denoting if this is the selected profile
+ );
+
+ //Used to set the current entry as chosen from the dropdown list
+ STDMETHODIMP
+ Dot11ExtUIPropertySetSelected(
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyHasConfigurationUI(BOOL *fHasConfigurationUI);
+
+ //Used to get additional display data (ciphers for auth types)
+ STDMETHODIMP
+ Dot11ExtUIPropertyGetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be described
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ ULONG *pcEntries, // number of dependent strings
+ ULONG *puDefaultSelection, // the entry in the array to be selected by default
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO **ppDot11ExtUIProperty // array of returned info structure
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertySetDisplayInfo(
+ DOT11_EXT_UI_DISPLAY_INFO_TYPE dot11ExtUIDisplayInfoType, // the diapaly type to be modified
+ BSTR bstrIHVProfile, // IHV data from the profile
+ PDOT11EXT_IHV_PARAMS pIHVParams, // Select profile MS security settings
+ DOT11_EXT_UI_PROPERTY_DISPLAY_INFO *pDot11ExtUIProperty, // selected info structure
+ BSTR* bstrModifiedIHVProfile, // modified IHV data to be stored in the profile
+ BOOL* pbIsModified // flag to denote if profile was modified
+ );
+
+ STDMETHODIMP
+ Dot11ExtUIPropertyIsStandardSecurity(
+ BOOL *fIsStandardSecurity, // if this interface is a standard auth method
+ DOT11_EXT_UI_SECURITY_TYPE *dot11ExtUISecurityType // which of the standard auth methods it is
+ );
+
+ // initialize the security page
+ STDMETHODIMP
+ Initialize(BSTR bstrPropertyName, DWORD dwIhvSecurity);
+
+private:
+ bool m_fInitialized;
+ BSTR m_bstrFN;
+ DOT11_EXT_UI_PROPERTY_TYPE m_ExtType;
+ BOOL m_fModified;
+ IHV_SECURITY_TYPE m_IhvSecurityType;
+ IHV_CIPHER_TYPE m_IHVCipherList[MAX_CIPHER_TYPES];
+};
+
+
+INT_PTR CALLBACK
+SimpleDialogProcSec(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+);
+
+#endif _IHVSAMPLEEXTUISEC_H_
diff --git a/network/wlan/ihvsampleui/IHVSampleProfile.cpp b/network/wlan/ihvsampleui/IHVSampleProfile.cpp
new file mode 100644
index 00000000..d4b0b060
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleProfile.cpp
@@ -0,0 +1,918 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+HRESULT
+CIhvProfileBase::GetTextFromNode
+(
+ IN LPCWSTR pszQuery,
+ OUT BSTR* pbstrText
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrQuery = NULL;
+ IXMLDOMNode* pQueryNode = NULL;
+
+ if ( !m_pRootNode )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( (!pszQuery) || (!pbstrText) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Bstr
+ (
+ pszQuery,
+ &bstrQuery
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr = m_pRootNode->selectSingleNode( bstrQuery, &pQueryNode );
+ BAIL_ON_FAILURE( hr );
+
+ if (!pQueryNode)
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr = pQueryNode->get_text( pbstrText );
+ BAIL_ON_FAILURE( hr );
+
+ if ( !(*pbstrText) )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ RELEASE_INTERFACE( pQueryNode );
+ SYS_FREE_STRING( bstrQuery );
+ return hr;
+}
+
+
+HRESULT
+CIhvProfileBase::PutTextInNode
+(
+ IN LPCWSTR pszQuery,
+ IN BSTR bstrText
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrQuery = NULL;
+ BSTR bstrOrig = NULL;
+ BOOL bPut = TRUE;
+ IXMLDOMNode* pQueryNode = NULL;
+
+ if ( !m_pRootNode )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( (!pszQuery) || (!bstrText) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Bstr
+ (
+ pszQuery,
+ &bstrQuery
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr = m_pRootNode->selectSingleNode( bstrQuery, &pQueryNode );
+ BAIL_ON_FAILURE( hr );
+
+ if (!pQueryNode)
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr = pQueryNode->get_text( &bstrOrig );
+ BAIL_ON_FAILURE( hr );
+
+ if ( bstrOrig && ( 0 == wcscmp( bstrOrig, bstrText ) ) )
+ {
+ bPut = FALSE;
+ }
+
+ if ( bPut )
+ {
+ hr = pQueryNode->put_text( bstrText );
+ BAIL_ON_FAILURE( hr );
+
+ SetModified( );
+ }
+
+error:
+ RELEASE_INTERFACE( pQueryNode );
+ SYS_FREE_STRING( bstrQuery );
+ SYS_FREE_STRING( bstrOrig );
+ return hr;
+}
+
+
+HRESULT
+CIhvProfileBase::LoadXml
+(
+ IN BSTR bstrProfileData
+)
+{
+ HRESULT hr = S_OK;
+ IXMLDOMDocument* pDOMDoc = NULL;
+ IXMLDOMElement* pDocElem = NULL;
+ BSTR bstrIhvProfile = NULL;
+ VARIANT_BOOL vfSuccess;
+
+ if ( !bstrProfileData )
+ {
+ hr = GetDefaultXml( &bstrIhvProfile );
+ BAIL_ON_FAILURE( hr );
+ }
+ else
+ {
+ bstrIhvProfile = bstrProfileData;
+ }
+
+ if ( m_pRootNode )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ CoCreateInstance
+ (
+ CLSID_DOMDocument,
+ NULL,
+ CLSCTX_ALL,
+ IID_IXMLDOMDocument,
+ (LPVOID *) &pDOMDoc
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ pDOMDoc->loadXML
+ (
+ bstrIhvProfile,
+ &vfSuccess
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( VARIANT_TRUE != vfSuccess )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ pDOMDoc->get_documentElement
+ (
+ &pDocElem
+ );
+ BAIL_ON_FAILURE( hr );
+
+ // Caching the pointer to the document element
+ // in a member variable.
+ m_pRootNode = pDocElem;
+ pDocElem = NULL;
+
+
+error:
+ if ( !bstrProfileData )
+ {
+ SYS_FREE_STRING( bstrIhvProfile );
+ }
+ RELEASE_INTERFACE( pDOMDoc );
+ RELEASE_INTERFACE( pDocElem );
+ return hr;
+}
+
+
+HRESULT
+CIhvProfileBase::EmitXml
+(
+ OUT BSTR* pbstrIhvProfile
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrIhvProfile )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( !m_pRootNode )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr = m_pRootNode->get_xml( pbstrIhvProfile );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ return hr;
+}
+
+
+//////////////////////////////////////////////////////////
+
+WCHAR g_szDefaultConnectivityProfile[] =
+L"<IhvConnectivity xmlns=\"http://www.sampleihv.com/nwifi/profile\">"
+L" <IHVConnectivityParam1>0</IHVConnectivityParam1>"
+L" <IHVConnectivityParam2>parameter value</IHVConnectivityParam2>"
+L"</IhvConnectivity>"
+;
+
+
+
+HRESULT
+CIhvConnectivityProfile::GetDefaultXml
+(
+ BSTR* pbstrDefault
+)
+{
+ SetModified();
+ return Wstr2Bstr( g_szDefaultConnectivityProfile, pbstrDefault );
+}
+
+
+
+HRESULT
+CIhvConnectivityProfile::GetParamDWORD
+(
+ DWORD* pdwParam1
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ CON_PARAM2_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2Dword
+ (
+ bstrData,
+ pdwParam1
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+HRESULT
+CIhvConnectivityProfile::SetParamDWORD
+(
+ DWORD dwNewValue
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ Dword2Bstr
+ (
+ dwNewValue,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ CON_PARAM2_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+
+HRESULT
+CIhvConnectivityProfile::GetParamBSTR
+(
+ BSTR* pbstrValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ GetTextFromNode
+ (
+ CON_PARAM1_XPATH,
+ pbstrValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+
+HRESULT
+CIhvConnectivityProfile::SetParamBSTR
+(
+ BSTR bstrNewValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ PutTextInNode
+ (
+ CON_PARAM1_XPATH,
+ bstrNewValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+HRESULT
+CIhvConnectivityProfile::GetNativeData
+(
+ LPVOID* ppvData
+)
+{
+ HRESULT hr = S_OK;
+ PIHV_CONNECTIVITY_PROFILE pIhvProfile = NULL;
+ BSTR bstrParam2 = NULL;
+
+ if ( !ppvData )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ pIhvProfile = (PIHV_CONNECTIVITY_PROFILE) malloc( sizeof( IHV_CONNECTIVITY_PROFILE ) );
+ if ( !pIhvProfile )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+ ZeroMemory( pIhvProfile, sizeof( IHV_CONNECTIVITY_PROFILE ) );
+
+ hr =
+ GetParamBSTR
+ (
+ &bstrParam2
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrParam2 ) {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Wstr
+ (
+ bstrParam2,
+ &(pIhvProfile->pszParam2)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetParamDWORD
+ (
+ &(pIhvProfile->dwParam1)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ // Transfering local cache to OUT parameter.
+ (*ppvData) = pIhvProfile;
+ pIhvProfile = NULL;
+
+error:
+ if ( pIhvProfile )
+ {
+ free( pIhvProfile->pszParam2 ); // NULL Safe.
+ free( pIhvProfile );
+ }
+ SYS_FREE_STRING( bstrParam2 );
+ return hr;
+}
+
+
+
+///////////////////////////////////////////
+
+LPCWSTR gppszIhvAuthTypes[] =
+{
+ L"IHVAuthV1",
+ L"IHVAuthV2",
+ L"IHVAuthV3"
+};
+
+LPCWSTR gppszIhvSecurityTypes[] =
+{
+ L"IHVSecurityV1",
+ L"IHVSecurityV2",
+};
+
+LPCWSTR gppszIhvCipherTypes[] =
+{
+ L"None",
+ L"IHVCipher1",
+ L"IHVCipher2",
+ L"IHVCipher3"
+};
+
+
+WCHAR g_szDefaultSecurityProfile[] =
+L"<IhvSecurity xmlns=\"http://www.sampleihv.com/nwifi/profile\">"
+L" <IHVUsesFullSecurity>TRUE</IHVUsesFullSecurity>"
+L" <IHVAuthentication>IHVAuthV1</IHVAuthentication>"
+L" <IHVEncryption>IHVCipher1</IHVEncryption>"
+L" <IHVSecurityParam1>0</IHVSecurityParam1>"
+L" <IHVSecurityParam2>parameter value</IHVSecurityParam2>"
+L"</IhvSecurity>";
+
+
+
+HRESULT
+CIhvSecurityProfile::GetDefaultXml
+(
+ BSTR* pbstrDefault
+)
+{
+ SetModified();
+ return Wstr2Bstr( g_szDefaultSecurityProfile, pbstrDefault );
+}
+
+HRESULT
+CIhvSecurityProfile::GetNativeData
+(
+ LPVOID* ppvData
+)
+{
+ HRESULT hr = S_OK;
+ PIHV_SECURITY_PROFILE pIhvProfile = NULL;
+ BSTR bstrParam2 = NULL;
+
+ if ( !ppvData )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ pIhvProfile = (PIHV_SECURITY_PROFILE) malloc( sizeof( IHV_SECURITY_PROFILE ) );
+ if ( !pIhvProfile )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+ ZeroMemory( pIhvProfile, sizeof( IHV_SECURITY_PROFILE ) );
+
+ hr =
+ GetFullSecurityFlag
+ (
+ &(pIhvProfile->bUseFullSecurity)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetAuthType
+ (
+ &(pIhvProfile->AuthType)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetCipherType
+ (
+ &(pIhvProfile->CipherType)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetParamDWORD
+ (
+ &(pIhvProfile->dwParam1)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ GetParamBSTR
+ (
+ &bstrParam2
+ );
+ BAIL_ON_FAILURE( hr );
+
+ if ( NULL == bstrParam2 ) {
+ hr = E_POINTER;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ hr =
+ Wstr2Wstr
+ (
+ bstrParam2,
+ &(pIhvProfile->pszParam2)
+ );
+ BAIL_ON_FAILURE( hr );
+
+ // Transfering local cache to OUT parameter.
+ (*ppvData) = pIhvProfile;
+ pIhvProfile = NULL;
+
+error:
+ if ( pIhvProfile )
+ {
+ free( pIhvProfile->pszParam2 ); // NULL Safe.
+ free( pIhvProfile );
+ }
+ SYS_FREE_STRING( bstrParam2 );
+ return hr;
+
+}
+
+
+
+HRESULT
+CIhvSecurityProfile::GetFullSecurityFlag
+(
+ BOOL* pbUseFullSecurity
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_FSFLAG_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2Bool
+ (
+ bstrData,
+ pbUseFullSecurity
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::SetFullSecurityFlag
+(
+ BOOL bUseFullSecurity
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ Bool2Bstr
+ (
+ bUseFullSecurity,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ SEC_FSFLAG_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+
+HRESULT
+CIhvSecurityProfile::GetAuthType
+(
+ PIHV_AUTH_TYPE pAuthType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_ATYPE_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2AuthType
+ (
+ bstrData,
+ pAuthType
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::SetAuthType
+(
+ IHV_AUTH_TYPE AuthType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ AuthType2Bstr
+ (
+ AuthType,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ SEC_ATYPE_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::GetSecurityType
+(
+ PIHV_SECURITY_TYPE pSecurityType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_ATYPE_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2SecurityType
+ (
+ bstrData,
+ pSecurityType
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+HRESULT
+CIhvSecurityProfile::SetSecurityType
+(
+ IHV_SECURITY_TYPE SecurityType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ SecurityType2Bstr
+ (
+ SecurityType,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ SEC_ATYPE_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::GetCipherType
+(
+ PIHV_CIPHER_TYPE pCipherType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_ETYPE_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2CipherType
+ (
+ bstrData,
+ pCipherType
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::SetCipherType
+(
+ IHV_CIPHER_TYPE CipherType
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ CipherType2Bstr
+ (
+ CipherType,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ SEC_ETYPE_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::GetParamDWORD
+(
+ DWORD* pdwParam1
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrData = NULL;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_PARAM2_XPATH,
+ &bstrData
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2Dword
+ (
+ bstrData,
+ pdwParam1
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrData );
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::SetParamDWORD
+(
+ DWORD dwNewValue
+)
+{
+ HRESULT hr = S_OK;
+ BSTR bstrText = NULL;
+
+ hr =
+ Dword2Bstr
+ (
+ dwNewValue,
+ &bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ PutTextInNode
+ (
+ SEC_PARAM2_XPATH,
+ bstrText
+ );
+ BAIL_ON_FAILURE( hr );
+
+error:
+ SYS_FREE_STRING( bstrText );
+ return hr;
+}
+
+
+
+HRESULT
+CIhvSecurityProfile::GetParamBSTR
+(
+ BSTR* pbstrValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ GetTextFromNode
+ (
+ SEC_PARAM1_XPATH,
+ pbstrValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+HRESULT
+CIhvSecurityProfile::SetParamBSTR
+(
+ BSTR bstrNewValue
+)
+{
+ HRESULT hr = S_OK;
+
+ hr =
+ PutTextInNode
+ (
+ SEC_PARAM1_XPATH,
+ bstrNewValue
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
diff --git a/network/wlan/ihvsampleui/IHVSampleProfile.h b/network/wlan/ihvsampleui/IHVSampleProfile.h
new file mode 100644
index 00000000..66e8ce3f
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleProfile.h
@@ -0,0 +1,296 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#pragma once
+
+#ifndef _IHVSAMPLEPROFILE_H
+#define _IHVSAMPLEPROFILE_H
+
+#define RELEASE_INTERFACE( _p ) if ( _p ) { (_p)->Release( ); (_p) = NULL;}
+
+
+class CIhvProfileBase
+{
+public:
+
+ // Constructor
+ CIhvProfileBase( )
+ {
+ m_bModified = FALSE;
+ m_pRootNode = NULL;
+ }
+
+ // Destructor
+ ~CIhvProfileBase( )
+ {
+ RELEASE_INTERFACE( m_pRootNode );
+ }
+
+ HRESULT
+ LoadXml
+ (
+ IN BSTR bstrIhvProfile
+ );
+
+ HRESULT
+ EmitXml
+ (
+ OUT BSTR* pbstrIhvProfile
+ );
+
+ BOOL GetModified( ) { return m_bModified; }
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the free( ) function.
+ virtual
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ )
+ = 0;
+
+protected:
+
+ virtual
+ HRESULT
+ GetDefaultXml
+ (
+ BSTR* pbstrDefault
+ )
+ = 0;
+
+ HRESULT
+ GetTextFromNode
+ (
+ IN LPCWSTR pszQuery,
+ OUT BSTR* pbstrText
+ );
+
+ HRESULT
+ PutTextInNode
+ (
+ IN LPCWSTR pszQuery,
+ IN BSTR bstrText
+ );
+
+
+ VOID SetModified( ) { m_bModified = TRUE; }
+
+ IXMLDOMElement* m_pRootNode;
+
+private:
+ BOOL m_bModified;
+};
+
+///////////////////////////////////////////
+
+
+typedef struct _IHV_CONNECTIVITY_PROFILE
+{
+#define CON_PARAM1_XPATH L"/IhvConnectivity/IHVConnectivityParam1"
+#define CON_PARAM2_XPATH L"/IhvConnectivity/IHVConnectivityParam2"
+
+ DWORD dwParam1;
+ LPWSTR pszParam2;
+}
+IHV_CONNECTIVITY_PROFILE, *PIHV_CONNECTIVITY_PROFILE;
+
+
+extern WCHAR g_szDefaultConnectivityProfile[];
+
+class CIhvConnectivityProfile
+ : public CIhvProfileBase
+{
+protected:
+ HRESULT
+ GetDefaultXml
+ (
+ BSTR* pbstrDefault
+ );
+
+public:
+
+ // Constructor Destructor
+ CIhvConnectivityProfile( ) { }
+ ~CIhvConnectivityProfile( ) { }
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the free( ) function.
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ );
+
+
+ // Accessor and Modifier for dwParam1
+ HRESULT
+ GetParamDWORD
+ (
+ DWORD* pdwParam1
+ );
+ HRESULT
+ SetParamDWORD
+ (
+ DWORD dwNewValue
+ );
+
+ // Accessor and Modifier for pszParam2
+ HRESULT
+ GetParamBSTR
+ (
+ BSTR* pbstrValue
+ );
+ HRESULT
+ SetParamBSTR
+ (
+ BSTR bstrNewValue
+ );
+
+};
+
+
+
+///////////////////////////////////////////
+
+extern LPCWSTR gppszIhvSecurityTypes[];
+
+#define MAX_AUTH_TYPES 3
+extern LPCWSTR gppszIhvAuthTypes[];
+
+#define MAX_CIPHER_TYPES 4
+extern LPCWSTR gppszIhvCipherTypes[];
+
+typedef struct _IHV_SECURITY_PROFILE
+{
+#define SEC_FSFLAG_XPATH L"/IhvSecurity/IHVUsesFullSecurity"
+#define SEC_ATYPE_XPATH L"/IhvSecurity/IHVAuthentication"
+#define SEC_ETYPE_XPATH L"/IhvSecurity/IHVEncryption"
+#define SEC_PARAM1_XPATH L"/IhvSecurity/IHVSecurityParam1"
+#define SEC_PARAM2_XPATH L"/IhvSecurity/IHVSecurityParam2"
+
+ BOOL bUseFullSecurity;
+ IHV_AUTH_TYPE AuthType;
+ IHV_CIPHER_TYPE CipherType;
+ DWORD dwParam1;
+ LPWSTR pszParam2;
+}
+IHV_SECURITY_PROFILE, *PIHV_SECURITY_PROFILE;
+
+
+extern WCHAR g_szDefaultSecurityProfile[];
+
+class CIhvSecurityProfile
+ : public CIhvProfileBase
+{
+protected:
+ HRESULT
+ GetDefaultXml
+ (
+ BSTR* pbstrDefault
+ );
+
+public:
+
+ // Constructor Destructor
+ CIhvSecurityProfile( ) { }
+ ~CIhvSecurityProfile( ) { }
+
+ // Caller needs to know what type to
+ // cast the pointer to depending upon
+ // the type of the derived class.
+ // Caller needs to free memory recursively
+ // by using the free( ) function.
+ HRESULT
+ GetNativeData
+ (
+ LPVOID* ppvData
+ );
+
+
+ // Accessor and Modifier for bUseFullSecurity
+ HRESULT
+ GetFullSecurityFlag
+ (
+ BOOL* pbUseFullSecurity
+ );
+ HRESULT
+ SetFullSecurityFlag
+ (
+ BOOL bUseFullSecurity
+ );
+
+
+ // Accessor and Modifier for AuthType
+ HRESULT
+ GetAuthType
+ (
+ PIHV_AUTH_TYPE pAuthType
+ );
+ HRESULT
+ SetAuthType
+ (
+ IHV_AUTH_TYPE AuthType
+ );
+
+ // Accessor and Modifier for SecurityType
+ HRESULT
+ GetSecurityType
+ (
+ PIHV_SECURITY_TYPE pSecurityType
+ );
+ HRESULT
+ SetSecurityType
+ (
+ IHV_SECURITY_TYPE SecurityType
+ );
+
+ // Accessor and Modifier for CipherType
+ HRESULT
+ GetCipherType
+ (
+ PIHV_CIPHER_TYPE pCipherType
+ );
+ HRESULT
+ SetCipherType
+ (
+ IHV_CIPHER_TYPE CipherType
+ );
+
+ // Accessor and Modifier for dwParam1
+ HRESULT
+ GetParamDWORD
+ (
+ DWORD* pdwParam1
+ );
+ HRESULT
+ SetParamDWORD
+ (
+ DWORD dwNewValue
+ );
+
+ // Accessor and Modifier for pszParam2
+ HRESULT
+ GetParamBSTR
+ (
+ BSTR* pbstrValue
+ );
+ HRESULT
+ SetParamBSTR
+ (
+ BSTR bstrNewValue
+ );
+
+};
+
+#endif _IHVSAMPLEPROFILE_H
+
diff --git a/network/wlan/ihvsampleui/IHVSampleUI.cpp b/network/wlan/ihvsampleui/IHVSampleUI.cpp
new file mode 100644
index 00000000..f93218bc
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleUI.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+
+#include "precomp.h"
+
+CIHVClassFactory *g_pIHVClassFactory = NULL;
+
+// instance handle to dll
+HINSTANCE g_hInst;
+
+// object ref count
+long g_objRefCount = 0;
+long g_serverLock = 0; //lock count on server
+
+//
+// DllRegisterServer - Adds entries to the system registry
+//
+STDAPI DllRegisterServer()
+{
+ HRESULT hr = S_OK;
+
+ hr = CRegHelper::RegisterServer();
+
+ return hr;
+}
+
+//
+// DllUnregisterServer - Removes entries from the system registry
+//
+STDAPI DllUnregisterServer()
+{
+ HRESULT hr = S_OK;
+
+ hr = CRegHelper::UnregisterServer();
+
+ return hr;
+}
+
+
+
+//
+// Used to determine whether the DLL can be unloaded by COM
+//
+STDAPI DllCanUnloadNow(void)
+{
+ if ((g_objRefCount == 0) && (g_serverLock == 0) /*&& (_Module.GetLockCount() == 0)*/)
+ {
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+STDAPI
+DllGetClassObject(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Outptr_ LPVOID *ppv)
+{
+ HRESULT hr = E_NOINTERFACE;
+
+ if (NULL == g_pIHVClassFactory)
+ {
+ g_pIHVClassFactory = new(std::nothrow) CIHVClassFactory();
+ if (NULL == g_pIHVClassFactory)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+
+ if(NULL != g_pIHVClassFactory &&
+ (rclsid == GUID_SAMPLE_IHVUI_CLSID || rclsid == IID_IWizardExtension))
+ {
+ hr = g_pIHVClassFactory->QueryInterface(riid, ppv);
+ }
+ return hr;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Function: DllMain
+//
+// Synopsis: Main entry point into the DLL.
+//
+// Arguments: HINSTANCE hinstDLL - Our HINSTANCE
+// DWORD fdwReason - The reason we are being called.
+// LPVOID lpvReserved - Reserved
+//
+// Returns: BOOL WINAPI - TRUE - always
+//
+//+----------------------------------------------------------------------------
+extern "C"
+BOOL WINAPI
+DllMain(
+ HINSTANCE hInstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved
+ )
+{
+ UNREFERENCED_PARAMETER(lpvReserved);
+
+ if (DLL_PROCESS_ATTACH == fdwReason)
+ {
+ // Set our global instance handle
+ g_hInst = hInstDLL;
+ (VOID)DisableThreadLibraryCalls(hInstDLL);
+ }
+ else if (DLL_PROCESS_DETACH == fdwReason)
+ {
+ }
+
+ return TRUE;
+}
+
diff --git a/network/wlan/ihvsampleui/IHVSampleUI.def b/network/wlan/ihvsampleui/IHVSampleUI.def
new file mode 100644
index 00000000..2882c292
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleUI.def
@@ -0,0 +1,7 @@
+LIBRARY "IhvSampleUI.dll"
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/network/wlan/ihvsampleui/IHVSampleUI.rc b/network/wlan/ihvsampleui/IHVSampleUI.rc
new file mode 100644
index 00000000..2c6563d8
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleUI.rc
@@ -0,0 +1,129 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "TODO: <Company name>"
+ VALUE "FileDescription", "TODO: <File description>"
+ VALUE "FileVersion", "1.0.0.1"
+ VALUE "LegalCopyright", "TODO: (c) <Company name>. All rights reserved."
+ VALUE "InternalName", "IHVSampleUI.dll"
+ VALUE "OriginalFilename", "IHVSampleUI.dll"
+ VALUE "ProductName", "TODO: <Product name>"
+ VALUE "ProductVersion", "1.0.0.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PROPPAGE_SMALL DIALOGEX 0, 0, 227, 244
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "IHV Profile String"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "This is a sample IHV extended dialog.",IDC_TITLE_TXT,
+ 20,19,135,8
+ LTEXT "Parameter 1",IDC_PARAM_TXT,20,49,80,8
+ EDITTEXT IDC_PARAM_BOX,101,48,96,14
+ CONTROL "Parameter 2",IDC_USE_FASTHANDOFF,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,20,72,178,10
+ PUSHBUTTON "OK",ID_OK,96,210,49,14
+ PUSHBUTTON "Cancel",ID_CANCEL,167,209,50,14
+END
+
+IDD_DIALOG_SHOWHELP DIALOGEX 0, 0, 317, 143
+STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Dialog"
+FONT 9, "Segoe UI", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_EDIT_HELPER,8,7,171,81,ES_AUTOHSCROLL
+END
+
+IDD_DIALOG_GETKEY DIALOGEX 0, 0, 317, 143
+STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Dialog"
+FONT 9, "Segoe UI", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_EDIT_KEY,23,46,142,14,ES_AUTOHSCROLL
+ LTEXT "Please enter IHV keys:",IDC_STATIC,25,17,74,8
+END
+
+IDD_DIALOG_LASTPAGE DIALOGEX 0, 0, 317, 143
+STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Dialog"
+FONT 9, "Segoe UI", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32",
+ DTS_RIGHTALIGN | WS_TABSTOP,7,7,172,12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_PROJNAME "SampleIHVExt"
+ IDS_TITLE_GETKEY "IHV Get Key Page"
+ IDS_TITLE_SHOWHELP "IHV Helper Page"
+ IDS_TITLE_LASTPAGE "IHV Last Page"
+ IDS_IHV_DEFAULT_TITLE "IHV Properties"
+ IDS_IHV_DEFAULT_CON_TITLE "IHV Connection Properties"
+ IDS_IHV_DEFAULT_KEY_TITLE "IHV Security Properties"
+ IDS_IHV_DEFAULT_SEC_TITLE "IHV Security Properties"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj
new file mode 100644
index 00000000..c4fe2319
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{A6B24475-C40B-4105-9896-6076AB284D92}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{BFF15FF4-CA6C-4126-AE5C-43FEAC2373DA}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>IHVSampleUI</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>IHVSampleUI</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>IHVSampleUI</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>IHVSampleUI</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;WIN32</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /EHa</AdditionalOptions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;user32.lib;uuid.lib;Kernel32.lib;Advapi32.lib;comctl32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>IHVSampleUI.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /EHa</AdditionalOptions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;user32.lib;uuid.lib;Kernel32.lib;Advapi32.lib;comctl32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>IHVSampleUI.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /EHa</AdditionalOptions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;user32.lib;uuid.lib;Kernel32.lib;Advapi32.lib;comctl32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>IHVSampleUI.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>%(AdditionalOptions) /EHa</AdditionalOptions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);ole32.lib;oleaut32.lib;user32.lib;uuid.lib;Kernel32.lib;Advapi32.lib;comctl32.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>IHVSampleUI.def</ModuleDefinitionFile>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="IHVClassFactory.cpp" />
+ <ClCompile Include="IHVRegistryHelper.cpp" />
+ <ClCompile Include="IHVSampleExtUI.cpp" />
+ <ClCompile Include="IHVSampleExtUICon.cpp" />
+ <ClCompile Include="IHVSampleExtUIKey.cpp" />
+ <ClCompile Include="IHVSampleExtUISec.cpp" />
+ <ClCompile Include="IHVSampleProfile.cpp" />
+ <ClCompile Include="IHVSampleUI.cpp" />
+ <ClCompile Include="utils.cpp" />
+ <Midl Include="IHVSample.idl" />
+ <Midl Include="IhvUIInc.idl" />
+ <ResourceCompile Include="IHVSampleUI.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters
new file mode 100644
index 00000000..35f3326f
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVSampleUI.vcxproj.Filters
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{94F31788-CC51-4779-82A7-949AF23515AB}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{2AFE8613-F5FD-4251-B520-F5354B519860}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{4C783C36-ECB3-435F-B739-9B522EEF773A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="IHVClassFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVRegistryHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleExtUI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleExtUICon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleExtUIKey.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleExtUISec.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleProfile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IHVSampleUI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <Midl Include="IHVSample.idl">
+ <Filter>Source Files</Filter>
+ </Midl>
+ <Midl Include="IhvUIInc.idl">
+ <Filter>Source Files</Filter>
+ </Midl>
+ <None Include="IHVSampleUI.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="IHVSampleUI.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/wlan/ihvsampleui/IHVUIInc.idl b/network/wlan/ihvsampleui/IHVUIInc.idl
new file mode 100644
index 00000000..1ef82407
--- /dev/null
+++ b/network/wlan/ihvsampleui/IHVUIInc.idl
@@ -0,0 +1 @@
+#include "wlanihvui.idl" \ No newline at end of file
diff --git a/network/wlan/ihvsampleui/iunk.h b/network/wlan/ihvsampleui/iunk.h
new file mode 100644
index 00000000..9b8242c5
--- /dev/null
+++ b/network/wlan/ihvsampleui/iunk.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+// Common macro based implementation of IUnknown
+// using a interface table approach
+
+#define IMPLEMENT_REFCOUNT()\
+ ULONG m_crefCount;\
+ \
+ STDMETHODIMP_(ULONG) AddRef(void)\
+ {\
+ return InterlockedIncrement((PLONG)&m_crefCount);\
+ }\
+ \
+ _At_(this, __drv_aliasesMem)\
+ STDMETHODIMP_(ULONG) Release(void)\
+ {\
+ ULONG res = InterlockedDecrement((PLONG)&m_crefCount);\
+ if (res == 0)\
+ {\
+ delete this;\
+ }\
+ return res;\
+ }
+
+#define BEGIN_INTERFACE_TABLE()\
+ IMPLEMENT_REFCOUNT()\
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)\
+ {\
+ if (riid == IID_IUnknown)\
+ {\
+ *ppvObject = reinterpret_cast<IUnknown*>(this);\
+ }
+
+#define IMPLEMENTS_INTERFACE(Itf)\
+ else if (riid == IID_ ## Itf)\
+ {\
+ *ppvObject = static_cast<Itf*>(this);\
+ }
+
+#define END_INTERFACE_TABLE()\
+ else \
+ {\
+ *ppvObject = NULL;\
+ return E_NOINTERFACE;\
+ }\
+ \
+ reinterpret_cast<IUnknown *>(*ppvObject)->AddRef();\
+ \
+ return S_OK;\
+ }
+
diff --git a/network/wlan/ihvsampleui/precomp.h b/network/wlan/ihvsampleui/precomp.h
new file mode 100644
index 00000000..1037884d
--- /dev/null
+++ b/network/wlan/ihvsampleui/precomp.h
@@ -0,0 +1,43 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#pragma once
+
+#include <driverspecs.h>
+_Analysis_mode_(_Analysis_code_type_user_code_)
+
+#include <shlobj.h>
+#include <windows.h>
+#include <objbase.h>
+#include <unknwn.h>
+#include <strsafe.h>
+#include <assert.h>
+#include <wlanihv.h>
+
+// MIDL generated
+#include "ihvsample.h"
+
+#include "iunk.h"
+#include "resource.h"
+#include "utils.h"
+#include "IHVRegistryHelper.h"
+#include "IHVSampleExtUI.h"
+#include "IHVSampleProfile.h"
+#include "IHVSampleExtUICon.h"
+#include "IHVSampleExtUISec.h"
+#include "IHVSampleExtUIKey.h"
+#include "IHVClassFactory.h"
+#include <new>
+
+const GUID GUID_SAMPLE_IHVUI_CLSID =
+{ 0x4a01f9f9, 0x6012, 0x4343, { 0xa8, 0xc4, 0x10, 0xb5, 0xdf, 0x32, 0x67, 0x2a } };
+
+
+#define IHV_SAMPLE_IHV_NAME L"IHV"
+
+#define BAIL_ON_FAILURE( _hr ) if (FAILED(_hr)) goto error;
+#define BAIL( ) goto error;
+#define SYS_FREE_STRING( _s ) if ( _s ) { SysFreeString( _s ); (_s) = NULL;}
+
diff --git a/network/wlan/ihvsampleui/resource.h b/network/wlan/ihvsampleui/resource.h
new file mode 100644
index 00000000..e60f854e
--- /dev/null
+++ b/network/wlan/ihvsampleui/resource.h
@@ -0,0 +1,31 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by TestIHV.rc
+//
+#define IDD_PROPPAGE_SMALL 502
+
+#define IDC_PARAM_BOX 1000
+#define IDC_PARAM_TXT 1001
+#define IDC_USE_FASTHANDOFF 1002
+#define ID_OK 1003
+#define ID_CANCEL 1004
+#define IDC_TITLE_TXT 1005
+
+#define IDS_PROJNAME 100
+#define IDR_SAMPLEIHVEXT 101
+#define IDS_TITLE_GETKEY 101
+#define IDR_IHVBALLOONHANDLER 102
+#define IDS_TITLE_SHOWHELP 102
+#define IDS_TITLE_LASTPAGE 103
+#define IDC_EDIT_KEY 201
+#define IDC_EDIT_HELPER 203
+#define IDD_DIALOG_GETKEY 204
+#define IDC_DATETIMEPICKER1 204
+#define IDD_DIALOG_SHOWHELP 205
+#define IDD_DIALOG_LASTPAGE 206
+
+
+#define IDS_IHV_DEFAULT_TITLE 300
+#define IDS_IHV_DEFAULT_CON_TITLE 301
+#define IDS_IHV_DEFAULT_KEY_TITLE 302
+#define IDS_IHV_DEFAULT_SEC_TITLE 303
diff --git a/network/wlan/ihvsampleui/utils.cpp b/network/wlan/ihvsampleui/utils.cpp
new file mode 100644
index 00000000..1f9bbe10
--- /dev/null
+++ b/network/wlan/ihvsampleui/utils.cpp
@@ -0,0 +1,408 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+#include "precomp.h"
+
+HRESULT
+Wstr2Bstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pbstrDest) = NULL;
+ if ( !pszSrc )
+ {
+ BAIL( );
+ }
+
+ (*pbstrDest) = SysAllocString( pszSrc );
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+
+
+HRESULT
+Wstr2Wstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ LPWSTR* ppszDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !ppszDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*ppszDest) = NULL;
+ if ( !pszSrc )
+ {
+ BAIL( );
+ }
+
+ *ppszDest = _wcsdup( pszSrc );
+
+ if ( !(*ppszDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+error:
+ return hr;
+}
+
+
+
+
+HRESULT
+Wstr2Dword
+(
+ IN LPCWSTR pszSrc,
+ OUT DWORD* pdwDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( (!pdwDest) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pdwDest) = (DWORD) _wtol( pszSrc );
+
+error:
+ return hr;
+}
+
+/*
+Note:
+2^32 = 2^(4*8) = 16^8 < 100^8 = 10^16
+This implies that 20 decimal digits
+are more than enough for a DWORD.
+*/
+
+HRESULT
+Dword2Bstr
+(
+ IN DWORD dwSrc,
+ OUT BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+ WCHAR szBuffer[25] = {0};
+
+ hr =
+ StringCchPrintf
+ (
+ szBuffer,
+ sizeof(szBuffer)/sizeof(szBuffer[0]),
+ L"%u",
+ dwSrc
+ );
+ BAIL_ON_FAILURE( hr );
+
+ hr =
+ Wstr2Bstr
+ (
+ szBuffer,
+ pbstrDest
+ );
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+HRESULT
+Wstr2Bool
+(
+ IN LPCWSTR pszSrc,
+ OUT BOOL* pbDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( (!pbDest) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( 0 == wcscmp( L"TRUE", pszSrc ) )
+ {
+ (*pbDest) = TRUE;
+ }
+ else if ( 0 == wcscmp( L"FALSE", pszSrc ) )
+ {
+ (*pbDest) = FALSE;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+HRESULT
+Bool2Bstr
+(
+ IN BOOL bSrc,
+ OUT BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( bSrc )
+ {
+ (*pbstrDest) = SysAllocString( L"TRUE" );
+ }
+ else
+ {
+ (*pbstrDest) = SysAllocString( L"FALSE" );
+ }
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+
+
+HRESULT
+Wstr2AuthType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_AUTH_TYPE pAuthType
+)
+{
+ HRESULT hr = S_OK;
+ DWORD dwIndex = 0;
+
+ if ( (!pAuthType) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ for ( dwIndex = 0; dwIndex < MAX_AUTH_TYPES; dwIndex++ )
+ {
+ if ( 0 == wcscmp( gppszIhvAuthTypes[dwIndex], pszSrc ) )
+ {
+ (*pAuthType) = (IHV_AUTH_TYPE) dwIndex;
+ BAIL( );
+ }
+ }
+
+ // String not found.
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+HRESULT
+AuthType2Bstr
+(
+ IN IHV_AUTH_TYPE AuthType,
+ OUT BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( AuthType < 0 || AuthType >= IHVAuthInvalid )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pbstrDest) = SysAllocString( gppszIhvAuthTypes[(DWORD) AuthType] );
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+
+HRESULT
+Wstr2SecurityType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_SECURITY_TYPE pSecurityType
+)
+{
+ HRESULT hr = S_OK;
+ DWORD dwIndex = 0;
+
+ if ( (!pSecurityType) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ for ( dwIndex = 0; dwIndex < MAX_AUTH_TYPES; dwIndex++ )
+ {
+ if ( 0 == wcscmp( gppszIhvSecurityTypes[dwIndex], pszSrc ) )
+ {
+ (*pSecurityType) = (IHV_SECURITY_TYPE) dwIndex;
+ BAIL( );
+ }
+ }
+
+ // String not found.
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+HRESULT
+SecurityType2Bstr
+(
+ IN IHV_SECURITY_TYPE SecurityType,
+ OUT BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( SecurityType < 0 || SecurityType >= IHVSecurityInvalid )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pbstrDest) = SysAllocString( gppszIhvSecurityTypes[(DWORD) SecurityType] );
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
+
+HRESULT
+Wstr2CipherType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_CIPHER_TYPE pCipherType
+)
+{
+ HRESULT hr = S_OK;
+ DWORD dwIndex = 0;
+
+ if ( (!pCipherType) || (!pszSrc) )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ for ( dwIndex = 0; dwIndex < MAX_CIPHER_TYPES; dwIndex++ )
+ {
+ if ( 0 == wcscmp( gppszIhvCipherTypes[dwIndex], pszSrc ) )
+ {
+ (*pCipherType) = (IHV_CIPHER_TYPE) dwIndex;
+ BAIL( );
+ }
+ }
+
+ // String not found.
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+
+
+error:
+ return hr;
+}
+
+
+HRESULT
+CipherType2Bstr
+(
+ IN IHV_CIPHER_TYPE CipherType,
+ OUT BSTR* pbstrDest
+)
+{
+ HRESULT hr = S_OK;
+
+ if ( !pbstrDest )
+ {
+ hr = E_INVALIDARG;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ if ( CipherType < None || CipherType >= IHVCipherInvalid )
+ {
+ hr = E_UNEXPECTED;
+ BAIL_ON_FAILURE( hr );
+ }
+
+ (*pbstrDest) = SysAllocString( gppszIhvCipherTypes[(DWORD) CipherType] );
+ if ( !(*pbstrDest) )
+ {
+ hr = E_OUTOFMEMORY;
+ BAIL_ON_FAILURE( hr );
+ }
+
+error:
+ return hr;
+}
diff --git a/network/wlan/ihvsampleui/utils.h b/network/wlan/ihvsampleui/utils.h
new file mode 100644
index 00000000..015e94dd
--- /dev/null
+++ b/network/wlan/ihvsampleui/utils.h
@@ -0,0 +1,98 @@
+//
+// Copyright (C) Microsoft Corporation 2005
+// IHV UI Extension sample
+//
+
+
+typedef enum _IHV_SECURITY_TYPE IHV_SECURITY_TYPE, *PIHV_SECURITY_TYPE;
+typedef enum _IHV_AUTH_TYPE IHV_AUTH_TYPE, *PIHV_AUTH_TYPE;
+typedef enum _IHV_CIPHER_TYPE IHV_CIPHER_TYPE, *PIHV_CIPHER_TYPE;
+
+
+HRESULT
+Wstr2Bstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ BSTR* pbstrDest
+);
+
+HRESULT
+Wstr2Wstr
+(
+ _In_ LPCWSTR pszSrc,
+ _Outptr_ LPWSTR* ppszDest
+);
+
+
+HRESULT
+Wstr2Dword
+(
+ IN LPCWSTR pszSrc,
+ OUT DWORD* pdwDest
+);
+
+
+HRESULT
+Dword2Bstr
+(
+ IN DWORD dwSrc,
+ OUT BSTR* pbstrDest
+);
+
+
+HRESULT
+Wstr2Bool
+(
+ IN LPCWSTR pszSrc,
+ OUT BOOL* pbDest
+);
+
+HRESULT
+Bool2Bstr
+(
+ IN BOOL bSrc,
+ OUT BSTR* pbstrDest
+);
+
+
+HRESULT
+Wstr2AuthType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_AUTH_TYPE pAuthType
+);
+
+HRESULT
+AuthType2Bstr
+(
+ IN IHV_AUTH_TYPE AuthType,
+ OUT BSTR* pbstrDest
+);
+
+HRESULT
+Wstr2SecurityType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_SECURITY_TYPE pSecurityType
+);
+
+HRESULT
+SecurityType2Bstr
+(
+ IN IHV_SECURITY_TYPE SecurityType,
+ OUT BSTR* pbstrDest
+);
+
+HRESULT
+Wstr2CipherType
+(
+ IN LPCWSTR pszSrc,
+ OUT PIHV_CIPHER_TYPE pCipherType
+);
+
+HRESULT
+CipherType2Bstr
+(
+ IN IHV_CIPHER_TYPE CipherType,
+ OUT BSTR* pbstrDest
+);
diff --git a/network/wlan/wlan.sln b/network/wlan/wlan.sln
new file mode 100644
index 00000000..4d92aa78
--- /dev/null
+++ b/network/wlan/wlan.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsample", "Ihvsample", "{7ECA32F1-551B-4AF3-9726-A319C35A19D3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ihvsampleui", "Ihvsampleui", "{42757992-DA8D-4434-9B9C-ED549C43BA83}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ihvsample", "ihvsample\ihvsample.vcxproj", "{C2DB15CB-342E-4E84-BFD0-5E839DE380DE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IHVSampleUI", "ihvsampleui\IHVSampleUI.vcxproj", "{A6B24475-C40B-4105-9896-6076AB284D92}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|Win32.Build.0 = Debug|Win32
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|Win32.ActiveCfg = Release|Win32
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|Win32.Build.0 = Release|Win32
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|x64.ActiveCfg = Debug|x64
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Debug|x64.Build.0 = Debug|x64
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|x64.ActiveCfg = Release|x64
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE}.Release|x64.Build.0 = Release|x64
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|Win32.Build.0 = Debug|Win32
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Release|Win32.ActiveCfg = Release|Win32
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Release|Win32.Build.0 = Release|Win32
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|x64.ActiveCfg = Debug|x64
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Debug|x64.Build.0 = Debug|x64
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Release|x64.ActiveCfg = Release|x64
+ {A6B24475-C40B-4105-9896-6076AB284D92}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {C2DB15CB-342E-4E84-BFD0-5E839DE380DE} = {7ECA32F1-551B-4AF3-9726-A319C35A19D3}
+ {A6B24475-C40B-4105-9896-6076AB284D92} = {42757992-DA8D-4434-9B9C-ED549C43BA83}
+ EndGlobalSection
+EndGlobal
diff --git a/network/wsk/echosrv/ReadMe.md b/network/wsk/echosrv/ReadMe.md
new file mode 100644
index 00000000..826e09f4
--- /dev/null
+++ b/network/wsk/echosrv/ReadMe.md
@@ -0,0 +1,58 @@
+WSK TCP Echo Server
+===================
+
+This sample driver is a minimal driver meant to demonstrate the usage of the Winsock Kernel (WSK) programming interface.
+
+The sample implements a simple kernel-mode application by using the Winsock Kernel (WSK) programming interface. The application accepts incoming TCP connection requests on port 40007 over both IPv4 and IPv6 and, on each connection, it echoes all received data back to the peer until the connection is closed by the peer. The application is designed to use a single worker thread to perform all of its processing. For better performance on a multi-processor computer, the sample can be enhanced to use more worker threads. This sample is designed such that operations on a given connection should always be processed by the same worker thread. This provides a simple form of synchronization that ensures proper socket closure in a setting where multiple operations might be outstanding and completed asynchronously on a given connection. For the sake of simplicity, this sample does not enforce any limit on the number of connections accepted (other than the natural limit imposed by the available system memory) or on the amount of time that a connection stays alive. A production server application should be designed with these security points in mind.
+
+This sample is not intended for use in a production environment.
+
+
+WPP SOFTWARE TRACING
+--------------------
+
+This sample driver uses WPP Software Tracing in order to log its actions. You can find detailed information on WPP Software Tracing in the WDK documentation. Here is a quick overview of one way to collect trace logs from the sample driver by using the tracing tools that are available in the \\tools\\tracing directory in the WDK. All code for this sample is located in the src\\network\\WSK\\echosrv directory.
+
+1. In a Command Prompt window, copy Echosrv.ctl and Echosrv.pdb into a directory and change to that directory (cd).
+2. Start software tracing for the sample driver by typing the following command:
+
+ **tracelog -start echosrvtrace -guid echosrv.ctl -f logfile.etl -flags 0x3**
+
+ The value that is provided for the -flags option determines which events will be logged by the sample driver. The sample currently has two event types denoted by the TRCERROR and TRCINFO macros where TRCERROR is 0x1 and TRCINFO is 0x2. Thus, a flag value of 0x3 (0x1 combined in a bitwise OR with 0x2) in the previous tracelog command tells the sample driver to log both TRCERROR and TRCINFO events.
+
+3. In order to stop tracing, type the following command:
+
+ tracelog -stop echosrvtrace
+
+4. Convert the trace logs in Logfile.etl into a human-readable format by typing the following command:
+
+ **tracefmt -o logfile.txt -f logfile.etl -r . -i \\***full-path***\\ echosrv.sys**
+
+5. Open Logfile.txt to view the trace logs.
+
+Be aware that tracing for the sample driver can be started at any time before the driver is started or while the driver is already running.
+
+To run the sample
+-----------------
+
+Install and run this sample driver by using the following steps:
+
+1. Copy the Echosrv.sys file to a directory on the test machine.
+2. In a Command Prompt window, type the following command:
+
+ **sc create echosrv type= kernel binpath= \\***full-path***\\ echosrv.sys**
+
+ where \\*full-path*\\ is the directory that contains the Echosrv.sys file.
+
+3. To start the driver, type:
+
+ **sc start echosrv**
+
+4. To stop the driver, type:
+
+ **sc stop echosrv**
+
+After the driver is installed and started, it will listen for incoming TCP connection requests on port 40007 over both IPv4 and IPv6 protocols until the driver is stopped. On each connection, the driver will echo all the received data back to the peer until the connection is closed by the peer.
+
+For more information on the usage of the Winsock Kernel (WSK) programming interface, see [Winsock Kernel](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571084).
+
diff --git a/network/wsk/echosrv/echosrv.ctl b/network/wsk/echosrv/echosrv.ctl
new file mode 100644
index 00000000..c66661ee
--- /dev/null
+++ b/network/wsk/echosrv/echosrv.ctl
@@ -0,0 +1 @@
+998bdf51-0349-4fbc-870c-d6130a955a5f WskSampleCtlGuid \ No newline at end of file
diff --git a/network/wsk/echosrv/echosrv.sln b/network/wsk/echosrv/echosrv.sln
new file mode 100644
index 00000000..ce0d54fc
--- /dev/null
+++ b/network/wsk/echosrv/echosrv.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echosrv", "echosrv.vcxproj", "{FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|Win32.Build.0 = Debug|Win32
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|Win32.ActiveCfg = Release|Win32
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|Win32.Build.0 = Release|Win32
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|x64.ActiveCfg = Debug|x64
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Debug|x64.Build.0 = Debug|x64
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|x64.ActiveCfg = Release|x64
+ {FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/wsk/echosrv/echosrv.vcxproj b/network/wsk/echosrv/echosrv.vcxproj
new file mode 100644
index 00000000..670bbe52
--- /dev/null
+++ b/network/wsk/echosrv/echosrv.vcxproj
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{FFEE1E8D-35BB-4B3B-A59E-CC8D6DE39B5D}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{356832D6-4003-4E04-991A-8885A867DFF1}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="wsksmple.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ <OtherWpp Include="wsksmple.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>echosrv</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>echosrv</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>echosrv</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>echosrv</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\netio.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\netio.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\netio.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\netio.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="wsksmple.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/wsk/echosrv/echosrv.vcxproj.Filters b/network/wsk/echosrv/echosrv.vcxproj.Filters
new file mode 100644
index 00000000..f0757e26
--- /dev/null
+++ b/network/wsk/echosrv/echosrv.vcxproj.Filters
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{7A5FF825-82E8-4B8C-A384-AFE5DDF0241F}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{7BD60EFA-8AB3-4BA8-8624-F096458DF6FD}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{02D631B3-0A60-43EF-A6F1-92F34CD3105C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{81350963-697B-4F08-9AEA-8A5426D14C60}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="wsksmple.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="wsksmple.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/wsk/echosrv/wsksmple.c b/network/wsk/echosrv/wsksmple.c
new file mode 100644
index 00000000..a16d0a3e
--- /dev/null
+++ b/network/wsk/echosrv/wsksmple.c
@@ -0,0 +1,1361 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ wsksample.c
+
+Abstract:
+
+ This module implements a simple kernel-mode application by using the
+ Winsock Kernel (WSK) programming interface. The application accepts
+ incoming connection requests and, on each connection, echoes all received
+ data back to the peer until the connection is closed by the peer.
+ The application is designed to use a single worker thread to perform all of
+ its processing. For better performance on MP machines, the sample may be
+ enhanced to use more worker threads. Operations on a given connection
+ should always be processed by the same worker thread. This provides a
+ simple form of synchronization ensuring proper socket closure in a setting
+ where multiple operations may be outstanding and completed asynchronously
+ on a given connection. For the sake of simplicty, this sample does not
+ enforce any limit on the number of connections accepted (other than the
+ natural limit imposed by the available system memory) or on the amount of
+ time a connection stays around. A full-fledged server application should be
+ designed with these points in mind from a security viewpoint.
+
+Author:
+
+Environment:
+
+ Kernel-Mode only
+
+Revision History:
+
+--*/
+
+#pragma warning(push)
+#pragma warning(disable:4201) // nameless struct/union
+#pragma warning(disable:4214) // bit field types other than int
+
+#include <ntddk.h>
+#include <wsk.h>
+
+#pragma warning(pop)
+
+// Software Tracing definitions
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(WskSampleCtlGuid, \
+ (998bdf51, 0349, 4fbc, 870c, d6130a955a5f), \
+ WPP_DEFINE_BIT(TRCERROR) \
+ WPP_DEFINE_BIT(TRCINFO) )
+
+#include "wsksmple.tmh"
+
+// Pool tags used for memory allocations
+#define WSKSAMPLE_SOCKET_POOL_TAG ((ULONG)'sksw')
+#define WSKSAMPLE_BUFFER_POOL_TAG ((ULONG)'bksw')
+#define WSKSAMPLE_GENERIC_POOL_TAG ((ULONG)'xksw')
+
+// Default length for data buffers used in send and receive operations
+#define WSKSAMPLE_DATA_BUFFER_LENGTH 2048
+
+// Forward declaration for the socket context structure
+typedef struct _WSKSAMPLE_SOCKET_CONTEXT *PWSKSAMPLE_SOCKET_CONTEXT;
+
+// Forward declaration for the socket operation context structure
+typedef struct _WSKSAMPLE_SOCKET_OP_CONTEXT *PWSKSAMPLE_SOCKET_OP_CONTEXT;
+
+// Function prototype for socket operation handling routines
+typedef
+VOID
+(* PWSKSAMPLE_OP_HANDLER_FN)(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext);
+
+// Structure that represents a work queue processed by a dedicated worker thread
+typedef struct _WSKSAMPLE_WORK_QUEUE {
+
+ // List head
+ SLIST_HEADER Head;
+
+ // Wake up event
+ KEVENT Event;
+
+ // Worker thread can exit safely only if queue is empty and Stop is TRUE
+ BOOLEAN Stop;
+
+ // Worker thread pointer
+ PETHREAD Thread;
+
+} WSKSAMPLE_WORK_QUEUE, *PWSKSAMPLE_WORK_QUEUE;
+
+// Structure that represents the context for a WSK socket operation.
+typedef struct _WSKSAMPLE_SOCKET_OP_CONTEXT {
+
+ // Work queue linkage
+ SLIST_ENTRY QueueEntry;
+
+ // Pointer to the function that will handle the operation
+ PWSKSAMPLE_OP_HANDLER_FN OpHandler;
+
+ // Pointer to the WSK socket context.
+ PWSKSAMPLE_SOCKET_CONTEXT SocketContext;
+
+ // IRP to use for the operation
+ PIRP Irp;
+
+ // Data buffer and MDL used by send and receive operations
+ _Field_size_bytes_part_(BufferLength,DataLength) PVOID DataBuffer;
+ PMDL DataMdl;
+ SIZE_T BufferLength; // size of the buffer
+ SIZE_T DataLength; // length of actual data stored in the buffer
+
+} WSKSAMPLE_SOCKET_OP_CONTEXT;
+
+// Maximum number of operations that can be outstanding on a socket at any time
+#define WSKSAMPLE_OP_COUNT 2
+
+// Structure that represents the context for a WSK socket.
+typedef struct _WSKSAMPLE_SOCKET_CONTEXT {
+
+ // Pointer to the WSK socket.
+ PWSK_SOCKET Socket;
+
+ // Work queue used for enqueueing operations on the socket
+ PWSKSAMPLE_WORK_QUEUE WorkQueue;
+
+ // Socket is being closed.
+ BOOLEAN Closing;
+
+ // Peer has gracefully disconnected its half of the connection and we are
+ // about to disconnect (or have disconnected) our half.
+ BOOLEAN Disconnecting;
+
+ // Stop accepting incoming connections. Valid for listening sockets only.
+ BOOLEAN StopListening;
+
+ // Embedded array of contexts for outstanding operations on the socket.
+ // Note that operation contexts could also be allocated separately. This
+ // sample preallocates a fixed number of operation contexts along with
+ // the socket context for a new socket.
+ WSKSAMPLE_SOCKET_OP_CONTEXT OpContext[WSKSAMPLE_OP_COUNT];
+
+} WSKSAMPLE_SOCKET_CONTEXT;
+
+// Forward declaration for WskAcceptEvent in WSK_CLIENT_LISTEN_DISPATCH
+NTSTATUS
+WSKAPI
+WskSampleAcceptEvent(
+ _In_ PVOID SocketContext,
+ _In_ ULONG Flags,
+ _In_ PSOCKADDR LocalAddress,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_SOCKET AcceptSocket,
+ _Outptr_result_maybenull_ PVOID *AcceptSocketContext,
+ _Outptr_result_maybenull_ CONST WSK_CLIENT_CONNECTION_DISPATCH **AcceptSocketDispatch
+ );
+
+// Client-level callback table
+const WSK_CLIENT_DISPATCH WskSampleClientDispatch = {
+ MAKE_WSK_VERSION(1, 0), // This sample uses WSK version 1.0
+ 0, // Reserved
+ NULL // WskClientEvent callback is not required in WSK version 1.0
+};
+
+// WSK Registration object
+WSK_REGISTRATION WskSampleRegistration;
+
+// Socket-level callback table for listening sockets
+const WSK_CLIENT_LISTEN_DISPATCH WskSampleClientListenDispatch = {
+ WskSampleAcceptEvent,
+ NULL, // WskInspectEvent is required only if conditional-accept is used.
+ NULL // WskAbortEvent is required only if conditional-accept is used.
+};
+
+// Global reference to the socket context for the listening socket
+PWSKSAMPLE_SOCKET_CONTEXT WskSampleListeningSocketContext;
+
+// Global work queue used for enqueueing all socket operations
+WSKSAMPLE_WORK_QUEUE WskSampleWorkQueue;
+
+// IPv6 wildcard address and port number 40007 to listen on
+SOCKADDR_IN6 IPv6ListeningAddress = {
+ AF_INET6,
+ 0x479c, // 40007 in hex in network byte order
+ 0,
+ IN6ADDR_ANY_INIT,
+ 0};
+
+// Forward function declarations
+
+DRIVER_INITIALIZE DriverEntry;
+DRIVER_UNLOAD WskSampleUnload;
+KSTART_ROUTINE WskSampleWorkerThread;
+IO_COMPLETION_ROUTINE WskSampleSyncIrpCompletionRoutine;
+IO_COMPLETION_ROUTINE WskSampleReceiveIrpCompletionRoutine;
+IO_COMPLETION_ROUTINE WskSampleSendIrpCompletionRoutine;
+IO_COMPLETION_ROUTINE WskSampleDisconnectIrpCompletionRoutine;
+IO_COMPLETION_ROUTINE WskSampleCloseIrpCompletionRoutine;
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ );
+
+_Must_inspect_result_
+__drv_allocatesMem(Mem)
+_Success_(return != NULL)
+PWSKSAMPLE_SOCKET_CONTEXT
+WskSampleAllocateSocketContext(
+ _In_ PWSKSAMPLE_WORK_QUEUE WorkQueue,
+ _In_ ULONG BufferLength
+ );
+
+_At_(SocketContext, __drv_freesMem(Mem))
+VOID
+WskSampleFreeSocketContext(
+ _In_ PWSKSAMPLE_SOCKET_CONTEXT SocketContext
+ );
+
+_At_(SocketOpContext, __drv_aliasesMem)
+VOID
+WskSampleEnqueueOp(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext,
+ _In_ PWSKSAMPLE_OP_HANDLER_FN OpHandler
+ );
+
+VOID
+WskSampleWorkerThread (
+ _In_ PVOID Context
+ );
+
+VOID
+WskSampleSetupListeningSocket(
+ _In_ PWSK_PROVIDER_NPI WskProviderNpi,
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpStartListen(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpStopListen(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpReceive(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpSend(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpDisconnect(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpClose(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+VOID
+WskSampleOpFree(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ );
+
+NTSTATUS
+WskSampleStartWorkQueue(
+ _Out_ PWSKSAMPLE_WORK_QUEUE WorkQueue
+ );
+
+VOID
+WskSampleStopWorkQueue(
+ _In_ PWSKSAMPLE_WORK_QUEUE WorkQueue
+ );
+
+VOID
+WskSampleUnload(
+ _In_ PDRIVER_OBJECT DriverObject
+ );
+
+#ifdef ALLOC_PRAGMA
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(INIT, WskSampleStartWorkQueue)
+#pragma alloc_text(PAGE, WskSampleUnload)
+#pragma alloc_text(PAGE, WskSampleStopWorkQueue)
+#pragma alloc_text(PAGE, WskSampleWorkerThread)
+#pragma alloc_text(PAGE, WskSampleOpStartListen)
+#pragma alloc_text(PAGE, WskSampleOpStopListen)
+#pragma alloc_text(PAGE, WskSampleSetupListeningSocket)
+#pragma alloc_text(PAGE, WskSampleOpReceive)
+#pragma alloc_text(PAGE, WskSampleOpSend)
+#pragma alloc_text(PAGE, WskSampleOpDisconnect)
+#pragma alloc_text(PAGE, WskSampleOpClose)
+#pragma alloc_text(PAGE, WskSampleOpFree)
+
+#endif
+
+// Driver entry routine
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ NTSTATUS status;
+ WSK_CLIENT_NPI wskClientNpi;
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ PAGED_CODE();
+
+ // Allocate a socket context that will be used for queueing an operation
+ // to setup a listening socket that will accept incoming connections
+ WskSampleListeningSocketContext = WskSampleAllocateSocketContext(
+ &WskSampleWorkQueue, 0);
+
+ if(WskSampleListeningSocketContext == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Register with WSK.
+ wskClientNpi.ClientContext = NULL;
+ wskClientNpi.Dispatch = &WskSampleClientDispatch;
+ status = WskRegister(&wskClientNpi, &WskSampleRegistration);
+
+ if(!NT_SUCCESS(status)) {
+ WskSampleFreeSocketContext(WskSampleListeningSocketContext);
+ return status;
+ }
+
+ // Initialize and start the global work queue
+ status = WskSampleStartWorkQueue(&WskSampleWorkQueue);
+
+ if(!NT_SUCCESS(status)) {
+ WskDeregister(&WskSampleRegistration);
+ WskSampleFreeSocketContext(WskSampleListeningSocketContext);
+ return status;
+ }
+
+ // Enqueue the first operation to setup the listening socket
+ WskSampleEnqueueOp(&WskSampleListeningSocketContext->OpContext[0],
+ WskSampleOpStartListen);
+
+ // Everything has been initiated successfully. Now we can enable the
+ // unload routine and return.
+ DriverObject->DriverUnload = WskSampleUnload;
+
+ // Initialize software tracing
+ WPP_INIT_TRACING(DriverObject, RegistryPath);
+
+ DoTraceMessage(TRCINFO, "LOADED");
+
+ return STATUS_SUCCESS;
+}
+
+// Driver unload routine
+VOID
+WskSampleUnload(
+ _In_ PDRIVER_OBJECT DriverObject
+ )
+{
+ C_ASSERT(WSKSAMPLE_OP_COUNT >= 2);
+
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ PAGED_CODE();
+
+ DoTraceMessage(TRCINFO, "UNLOAD START");
+
+ // Enqueue an operation to stop listening for any new connections.
+ // This will close the listening socket, but there may still be
+ // connection-oriented sockets that are open. The WskDeregister call
+ // below will block until all sockets including the connection-oriented
+ // ones that were accepted over the listening socket are closed. Since
+ // this sample currently closes the connection-oriented sockets
+ // only when an error occurs or when the remote peer disconnects, the
+ // unload of the driver will be blocked until the last connection is
+ // disconnected by the peer. If the requirements for a full-fledged
+ // application are such that the unload of the driver (or any other
+ // similar event) proactively closes all the sockets (that may
+ // otherwise stay open indefinitely), then the application must keep
+ // track of all the sockets in a fashion that allows enumerating them and
+ // closing each socket. In such a scheme, the application must still ensure
+ // that a socket is closed only when other calls can NOT anymore be issued
+ // on the socket.
+ WskSampleEnqueueOp(&WskSampleListeningSocketContext->OpContext[1],
+ WskSampleOpStopListen);
+
+ // Deregister with WSK. This call will wait until all the references to
+ // the WSK provider NPI are released and all the sockets are closed. Note
+ // that if the worker thread has not started yet, then when it eventually
+ // starts, its WskCaptureProviderNPI call will fail and the work queue
+ // will be flushed and cleaned up properly.
+ WskDeregister(&WskSampleRegistration);
+
+ // WskDeregister returns only if all the sockets are closed. Thus, at this
+ // point, it's guaranteed that all socket are closed, which also means that
+ // there can not be any further outstanding operations on any socket. So,
+ // the worker thread can now safely stop processing the work queue if there
+ // are no queued items. Signal the worker thread to stop and wait for it.
+ WskSampleStopWorkQueue(&WskSampleWorkQueue);
+
+ DoTraceMessage(TRCINFO, "UNLOAD END");
+
+ WPP_CLEANUP(DriverObject);
+}
+
+// Initialize a given work queue and start the worker thread for it
+NTSTATUS
+WskSampleStartWorkQueue(
+ _Out_ PWSKSAMPLE_WORK_QUEUE WorkQueue
+ )
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ PAGED_CODE();
+
+ InitializeSListHead(&WorkQueue->Head);
+ KeInitializeEvent(&WorkQueue->Event, SynchronizationEvent, FALSE);
+ WorkQueue->Stop = FALSE;
+
+ status = PsCreateSystemThread(
+ &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL,
+ WskSampleWorkerThread, WorkQueue);
+
+ if(!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode,
+ &WorkQueue->Thread, NULL);
+
+ ZwClose(threadHandle);
+
+ if(!NT_SUCCESS(status)) {
+ WorkQueue->Stop = TRUE;
+ KeSetEvent(&WorkQueue->Event, 0, FALSE);
+ }
+
+ return status;
+}
+
+// Stop a given work queue and wait for its worker thread to exit
+VOID
+WskSampleStopWorkQueue(
+ _In_ PWSKSAMPLE_WORK_QUEUE WorkQueue
+ )
+{
+ PAGED_CODE();
+
+ ASSERT(WorkQueue->Stop == FALSE);
+ ASSERT(WorkQueue->Thread);
+ WorkQueue->Stop = TRUE;
+ KeSetEvent(&WorkQueue->Event, 0, FALSE);
+ KeWaitForSingleObject(WorkQueue->Thread, Executive, KernelMode, FALSE,NULL);
+ ObDereferenceObject(WorkQueue->Thread);
+}
+
+// Allocate and setup a socket context
+_Must_inspect_result_
+__drv_allocatesMem(Mem)
+_Success_(return != NULL)
+PWSKSAMPLE_SOCKET_CONTEXT
+WskSampleAllocateSocketContext(
+ _In_ PWSKSAMPLE_WORK_QUEUE WorkQueue,
+ _In_ ULONG BufferLength
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ // Allocate and setup a socket context with optional data buffers, and
+ // attach the socket to the given work queue. Even though this sample uses
+ // only a single global work queue, the sample is designed to be easily
+ // adaptable to using multiple work queues. If the sample is changed to
+ // use multiple work queues (say a work queue per processor), a given
+ // socket will/must always use the same work queue.
+
+ socketContext = ExAllocatePoolWithTag(
+ NonPagedPool, sizeof(*socketContext), WSKSAMPLE_SOCKET_POOL_TAG);
+
+ if(socketContext != NULL) {
+
+ ULONG i;
+
+ RtlZeroMemory(socketContext, sizeof(WSKSAMPLE_SOCKET_CONTEXT));
+
+ socketContext->WorkQueue = WorkQueue;
+
+ for(i = 0; i < WSKSAMPLE_OP_COUNT; i++) {
+
+ socketContext->OpContext[i].SocketContext = socketContext;
+
+ socketContext->OpContext[i].Irp = IoAllocateIrp(1, FALSE);
+ if(socketContext->OpContext[i].Irp == NULL) {
+ goto failure;
+ }
+
+ if(BufferLength > 0) {
+ socketContext->OpContext[i].DataBuffer = ExAllocatePoolWithTag(
+ NonPagedPool, BufferLength, WSKSAMPLE_BUFFER_POOL_TAG);
+ if(socketContext->OpContext[i].DataBuffer == NULL) {
+ goto failure;
+ }
+ socketContext->OpContext[i].DataMdl = IoAllocateMdl(
+ socketContext->OpContext[i].DataBuffer,
+ BufferLength, FALSE, FALSE, NULL);
+ if(socketContext->OpContext[i].DataMdl == NULL) {
+ goto failure;
+ }
+ MmBuildMdlForNonPagedPool(socketContext->OpContext[i].DataMdl);
+ socketContext->OpContext[i].BufferLength = BufferLength;
+ }
+ }
+
+ DoTraceMessage(TRCINFO, "AllocateSocketContext: %p", socketContext);
+
+ return socketContext;
+ }
+
+failure:
+
+ DoTraceMessage(TRCERROR, "AllocateSocketContext: FAIL");
+
+ if(socketContext) {
+ WskSampleFreeSocketContext(socketContext);
+ }
+
+ return NULL;
+}
+
+// Cleanup and free a socket context
+_At_(SocketContext, __drv_freesMem(Mem))
+VOID
+WskSampleFreeSocketContext(
+ _In_ PWSKSAMPLE_SOCKET_CONTEXT SocketContext
+ )
+{
+ ULONG i;
+
+ // Socket context is freed only after all the WSK calls on the
+ // socket are completed and all enqueued operations for the socket
+ // are dequeued. So, we can safely free the Irp, Mdl, and data buffer
+ // pointed by the socket operation contexts.
+
+ for(i = 0; i < WSKSAMPLE_OP_COUNT; i++) {
+
+ if(SocketContext->OpContext[i].Irp != NULL) {
+ IoFreeIrp(SocketContext->OpContext[i].Irp);
+ SocketContext->OpContext[i].Irp = NULL;
+ }
+ if(SocketContext->OpContext[i].DataMdl != NULL) {
+ IoFreeMdl(SocketContext->OpContext[i].DataMdl);
+ SocketContext->OpContext[i].DataMdl = NULL;
+ }
+ if(SocketContext->OpContext[i].DataBuffer != NULL) {
+ ExFreePool(SocketContext->OpContext[i].DataBuffer);
+ SocketContext->OpContext[i].DataBuffer = NULL;
+ }
+ }
+
+ DoTraceMessage(TRCINFO, "FreeSocketContext: %p", SocketContext);
+
+ ExFreePool(SocketContext);
+}
+
+// Enqueue an operation on a socket
+_At_(SocketOpContext, __drv_aliasesMem)
+VOID
+WskSampleEnqueueOp(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext,
+ _In_ PWSKSAMPLE_OP_HANDLER_FN OpHandler
+ )
+{
+ PWSKSAMPLE_WORK_QUEUE workQueue = SocketOpContext->SocketContext->WorkQueue;
+
+ SocketOpContext->OpHandler = OpHandler;
+
+ #pragma warning(disable:4054) // turn off typecast warning
+
+ if(NULL == InterlockedPushEntrySList(
+ &workQueue->Head,
+ &SocketOpContext->QueueEntry)) {
+ DoTraceMessage(TRCINFO, "EnqueueOp: %p %p (%p) SetEvent",
+ SocketOpContext->SocketContext, SocketOpContext, (PVOID)OpHandler);
+ // Work queue was empty. So, signal the work queue event in case the
+ // worker thread is waiting on the event for more operations.
+ KeSetEvent(&workQueue->Event, 0, FALSE);
+ }
+ else
+ DoTraceMessage(TRCINFO, "EnqueueOp: %p %p (%p)",
+ SocketOpContext->SocketContext, SocketOpContext, (PVOID)OpHandler);
+
+ #pragma warning(default:4054) // restore typecast warning
+}
+
+// Worker thread which drains and processes a given work queue
+VOID
+WskSampleWorkerThread (
+ _In_ PVOID Context
+ )
+{
+ PWSKSAMPLE_WORK_QUEUE workQueue;
+ PSLIST_ENTRY listEntryRev, listEntry, next;
+
+ PAGED_CODE();
+
+ workQueue = (PWSKSAMPLE_WORK_QUEUE)Context;
+
+ for(;;) {
+
+ // Flush all the queued operations into a local list
+ listEntryRev = InterlockedFlushSList(&workQueue->Head);
+
+ if(listEntryRev == NULL) {
+
+ // There's no work to do. If we are allowed to stop, then stop.
+ if(workQueue->Stop) {
+ DoTraceMessage(TRCINFO, "WorkerThread: WQ %p exit", workQueue);
+ break;
+ }
+
+ DoTraceMessage(TRCINFO, "WorkerThread: WQ %p wait", workQueue);
+
+ // Otherwise, wait for more operations to be enqueued.
+ KeWaitForSingleObject(&workQueue->Event,
+ Executive, KernelMode, FALSE, 0);
+ continue;
+ }
+
+ DoTraceMessage(TRCINFO, "WorkerThread: WQ %p process", workQueue);
+
+ // Need to reverse the flushed list in order to preserve the FIFO order
+ listEntry = NULL;
+ while (listEntryRev != NULL) {
+ next = listEntryRev->Next;
+ listEntryRev->Next = listEntry;
+ listEntry = listEntryRev;
+ listEntryRev = next;
+ }
+
+ // Now process the correctly ordered list of operations one by one
+ while(listEntry) {
+
+ PWSKSAMPLE_SOCKET_OP_CONTEXT socketOpContext =
+ CONTAINING_RECORD(listEntry,
+ WSKSAMPLE_SOCKET_OP_CONTEXT, QueueEntry);
+ PWSKSAMPLE_OP_HANDLER_FN opHandler = socketOpContext->OpHandler;
+
+ listEntry = listEntry->Next;
+
+ opHandler(socketOpContext);
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+// Operation handler for creating and setting up a listening socket
+VOID
+WskSampleOpStartListen(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ NTSTATUS status;
+ WSK_PROVIDER_NPI wskProviderNpi;
+
+ PAGED_CODE();
+
+ // This is the very first operation that runs in the worker thread.
+ // This operation is made up of multiple WSK calls, and no other
+ // operations will be processed until this compound operation is
+ // finished synchronously in the context of the worker thread.
+
+ // Capture the WSK Provider NPI
+ status = WskCaptureProviderNPI(
+ &WskSampleRegistration,
+ WSK_INFINITE_WAIT,
+ &wskProviderNpi);
+
+ if(NT_SUCCESS(status)) {
+
+ // Create a listening socket
+ WskSampleSetupListeningSocket(&wskProviderNpi, SocketOpContext);
+
+ // Release the WSK provider NPI since we won't use it anymore
+ WskReleaseProviderNPI(&WskSampleRegistration);
+ }
+ else {
+ // WskCaptureProviderNPI will fail if WskDeregister is called
+ // from the Driver Unload routine before the WSK subsystem
+ // becomes ready.
+ DoTraceMessage(TRCINFO,
+ "OpStartListen: WskCaptureProviderNPI failed 0x%lx", status);
+ }
+}
+
+// Create and prepare a listening socket for accepting incoming connections
+VOID
+WskSampleSetupListeningSocket(
+ _In_ PWSK_PROVIDER_NPI WskProviderNpi,
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ NTSTATUS status;
+ WSK_EVENT_CALLBACK_CONTROL callbackControl;
+ KEVENT compEvent;
+ ULONG optionValue;
+ PWSK_SOCKET listeningSocket = NULL;
+ PWSK_PROVIDER_LISTEN_DISPATCH dispatch = NULL;
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext = SocketOpContext->SocketContext;
+ PIRP irp = SocketOpContext->Irp;
+
+ PAGED_CODE();
+
+ KeInitializeEvent(&compEvent, SynchronizationEvent, FALSE);
+
+ if(socketContext->Socket != NULL) {
+
+ // If there's already a socket then we must be getting called because
+ // the WskAcceptevent indicated a NULL AcceptSocket, i.e. the listening
+ // socket is no longer functional. So, we will close the existing
+ // listening socket and try to create a new one.
+
+ if(socketContext->StopListening) {
+ // Listening socket is already being closed because the driver
+ // is being unloaded. So, there's no need to recreate it.
+ return;
+ }
+
+ IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
+
+ IoSetCompletionRoutine(irp,
+ WskSampleSyncIrpCompletionRoutine,
+ &compEvent, TRUE, TRUE, TRUE);
+
+ ((PWSK_PROVIDER_LISTEN_DISPATCH)
+ socketContext->Socket->Dispatch)->
+ WskCloseSocket(socketContext->Socket, irp);
+
+ KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
+
+ ASSERT(NT_SUCCESS(irp->IoStatus.Status));
+ socketContext->Socket = NULL;
+
+ IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
+ }
+ else {
+ // First, configure the WSK client such that WskAcceptEvent callback
+ // will be automatically enabled on the listening socket upon creation.
+ callbackControl.NpiId = (PNPIID)&NPI_WSK_INTERFACE_ID;
+ callbackControl.EventMask = WSK_EVENT_ACCEPT;
+ status = WskProviderNpi->Dispatch->WskControlClient(
+ WskProviderNpi->Client,
+ WSK_SET_STATIC_EVENT_CALLBACKS,
+ sizeof(callbackControl),
+ &callbackControl,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ if(!NT_SUCCESS(status)) {
+ DoTraceMessage(TRCERROR,
+ "SetupListeningSocket: WSK_SET_STATIC_EVENT_CALLBACKS FAIL 0x%lx",
+ status);
+ goto failexit;
+ }
+ }
+
+ // Create a listening socket over AF_INET6 address family. Put the socket
+ // into dual-family mode by setting IPV6_V6ONLY option to FALSE so that
+ // AF_INET traffic is also handled over the same socket.
+
+ IoSetCompletionRoutine(irp,
+ WskSampleSyncIrpCompletionRoutine,
+ &compEvent, TRUE, TRUE, TRUE);
+
+ // We do not need to check the return status since the actual completion
+ // status will be captured from the IRP after the IRP is completed.
+ WskProviderNpi->Dispatch->WskSocket(
+ WskProviderNpi->Client,
+ AF_INET6,
+ SOCK_STREAM,
+ IPPROTO_TCP,
+ WSK_FLAG_LISTEN_SOCKET,
+ socketContext,
+ &WskSampleClientListenDispatch,
+ NULL, // Process
+ NULL, // Thread
+ NULL, // SecurityDescriptor
+ irp);
+
+ KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
+
+ if(!NT_SUCCESS(irp->IoStatus.Status)) {
+ DoTraceMessage(TRCERROR, "SetupListeningSocket: WskSocket FAIL 0x%lx",
+ irp->IoStatus.Status);
+ goto failexit;
+ }
+
+ listeningSocket = (PWSK_SOCKET)irp->IoStatus.Information;
+ dispatch = (PWSK_PROVIDER_LISTEN_DISPATCH)listeningSocket->Dispatch;
+
+ // Set IPV6_V6ONLY to FALSE before the bind operation
+
+ optionValue = 0;
+
+ IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(irp,
+ WskSampleSyncIrpCompletionRoutine,
+ &compEvent, TRUE, TRUE, TRUE);
+
+ // We do not need to check the return status since the actual completion
+ // status will be captured from the IRP after the IRP is completed.
+ dispatch->WskControlSocket(
+ listeningSocket,
+ WskSetOption,
+ IPV6_V6ONLY,
+ IPPROTO_IPV6,
+ sizeof(optionValue),
+ &optionValue,
+ 0,
+ NULL,
+ NULL,
+ irp);
+
+ KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
+
+ if(!NT_SUCCESS(irp->IoStatus.Status)) {
+ DoTraceMessage(TRCERROR, "SetupListeningSocket: IPV6_V6ONLY FAIL 0x%lx",
+ irp->IoStatus.Status);
+ goto failexit;
+ }
+
+ // Bind the socket to the wildcard address. Once bind is completed,
+ // WSK provider will make WskAcceptEvent callbacks as connections arrive.
+ IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(irp,
+ WskSampleSyncIrpCompletionRoutine,
+ &compEvent, TRUE, TRUE, TRUE);
+
+ // We do not need to check the return status since the actual completion
+ // status will be captured from the IRP after the IRP is completed.
+ dispatch->WskBind(
+ listeningSocket,
+ (PSOCKADDR)&IPv6ListeningAddress,
+ 0,
+ irp);
+
+ KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
+
+ if(!NT_SUCCESS(irp->IoStatus.Status)) {
+ DoTraceMessage(TRCERROR, "SetupListeningSocket: WskBind FAIL 0x%lx",
+ irp->IoStatus.Status);
+ goto failexit;
+ }
+
+ // Store the WSK socket pointer in the socket context only if everthing
+ // has succeeded. Otherwise, the listening WSK socket, if one was created
+ // successfully, will be closed inline below.
+ ASSERT(socketContext->Socket == NULL);
+ socketContext->Socket = listeningSocket;
+
+ DoTraceMessage(TRCINFO, "SetupListeningSocket: %p %p",
+ socketContext, SocketOpContext);
+
+ return;
+
+failexit:
+
+ if(listeningSocket) {
+
+ IoReuseIrp(irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(irp,
+ WskSampleSyncIrpCompletionRoutine,
+ &compEvent, TRUE, TRUE, TRUE);
+
+ dispatch->WskCloseSocket(listeningSocket, irp);
+ KeWaitForSingleObject(&compEvent, Executive, KernelMode, FALSE, NULL);
+ }
+}
+
+// IRP completion routine used for synchronously waiting for completion
+_Use_decl_annotations_
+NTSTATUS
+WskSampleSyncIrpCompletionRoutine(
+ PDEVICE_OBJECT Reserved,
+ PIRP Irp,
+ PVOID Context
+ )
+{
+ PKEVENT compEvent = (PKEVENT)Context;
+ _Analysis_assume_(Context != NULL);
+ UNREFERENCED_PARAMETER(Reserved);
+ UNREFERENCED_PARAMETER(Irp);
+ KeSetEvent(compEvent, 2, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+// Operation handler for stopping listening
+VOID
+WskSampleOpStopListen(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ DoTraceMessage(TRCINFO, "OpStopListen: %p %p",
+ socketContext, SocketOpContext);
+
+ socketContext->StopListening = TRUE;
+
+ if(socketContext->Socket == NULL) {
+ // Listening socket was NOT created due to some failure.
+ // All we need to do is to free up the socket context.
+ WskSampleEnqueueOp(SocketOpContext, WskSampleOpFree);
+ }
+ else {
+ // Enqueue an operation to close the listening socket
+ WskSampleEnqueueOp(SocketOpContext, WskSampleOpClose);
+ }
+}
+
+// Listening socket callback which is invoked whenever a new connection arrives.
+NTSTATUS
+WSKAPI
+WskSampleAcceptEvent(
+ _In_ PVOID SocketContext,
+ _In_ ULONG Flags,
+ _In_ PSOCKADDR LocalAddress,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_SOCKET AcceptSocket,
+ _Outptr_result_maybenull_ PVOID *AcceptSocketContext,
+ _Outptr_result_maybenull_ CONST WSK_CLIENT_CONNECTION_DISPATCH **AcceptSocketDispatch
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext = NULL;
+ PWSKSAMPLE_SOCKET_CONTEXT listeningSocketContext;
+ ULONG i;
+
+ UNREFERENCED_PARAMETER(Flags);
+ UNREFERENCED_PARAMETER(LocalAddress);
+ UNREFERENCED_PARAMETER(RemoteAddress);
+
+ listeningSocketContext = (PWSKSAMPLE_SOCKET_CONTEXT)SocketContext;
+
+ if(AcceptSocket == NULL) {
+ // If WSK provider makes a WskAcceptEvent callback with NULL
+ // AcceptSocket, this means that the listening socket is no longer
+ // functional. The WSK client may handle this situation by trying
+ // to create a new listening socket or by restarting the driver, etc.
+ // In this sample, we will attempt to close the existing listening
+ // socket and create a new one. Note that the WskSampleAcceptEvent
+ // callback is guaranteed to be invoked with a NULL AcceptSocket
+ // by the WSK subsystem only *once*. So, we can safely use the same
+ // operation context that was originally used for enqueueing the first
+ // WskSampleStartListen operation on the listening socket. The
+ // WskSampleStartListen operation will close the existing listening
+ // socket and create a new one.
+ WskSampleEnqueueOp(&listeningSocketContext->OpContext[0],
+ WskSampleOpStartListen);
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ // Allocate socket context for the newly accepted socket.
+ socketContext = WskSampleAllocateSocketContext(
+ &WskSampleWorkQueue, WSKSAMPLE_DATA_BUFFER_LENGTH);
+
+ if(socketContext == NULL) {
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ socketContext->Socket = AcceptSocket;
+
+ DoTraceMessage(TRCINFO, "AcceptEvent: %p", socketContext);
+
+ // Enqueue receive operations on the accepted socket. Whenever a receive
+ // operation is completed successfully, the received data will be echoed
+ // back to the peer via a send operation. Whenever a send operation is
+ // completed, a new receive request will be issued over the connection.
+ // This will continue until the connection is closed by the peer.
+ for(i = 0; i < WSKSAMPLE_OP_COUNT; i++) {
+ _Analysis_assume_(socketContext == socketContext->OpContext[i].SocketContext);
+ WskSampleEnqueueOp(&socketContext->OpContext[i], WskSampleOpReceive);
+ }
+
+ // Since we will not use any callbacks on the accepted socket, we specify no
+ // socketContext or callback dispatch table pointer for the accepted socket.
+ *AcceptSocketContext = NULL;
+ *AcceptSocketDispatch = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+// Operation handler for issuing a receive request on a connected socket
+VOID
+WskSampleOpReceive(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ if(socketContext->Closing || socketContext->Disconnecting) {
+ // Do not call WskReceive if socket is being disconnected
+ // or closed. The operation context will not be used any more.
+ DoTraceMessage(TRCINFO, "OpReceive: %p %p SKIP",
+ socketContext, SocketOpContext);
+ }
+ else {
+ WSK_BUF wskbuf;
+ CONST WSK_PROVIDER_CONNECTION_DISPATCH *dispatch;
+
+ dispatch = socketContext->Socket->Dispatch;
+
+ wskbuf.Offset = 0;
+ wskbuf.Length = SocketOpContext->BufferLength;
+ wskbuf.Mdl = SocketOpContext->DataMdl;
+
+ IoReuseIrp(SocketOpContext->Irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(SocketOpContext->Irp,
+ WskSampleReceiveIrpCompletionRoutine,
+ SocketOpContext, TRUE, TRUE, TRUE);
+
+ DoTraceMessage(TRCINFO, "OpReceive: %p %p %Iu",
+ socketContext, SocketOpContext, wskbuf.Length);
+
+ // No need to check the return status here. The IRP completion
+ // routine will take action based on the completion status.
+ dispatch->WskReceive(
+ socketContext->Socket,
+ &wskbuf,
+ 0,
+ SocketOpContext->Irp);
+ }
+}
+
+// IRP completion routine for WskReceive requests
+_Use_decl_annotations_
+NTSTATUS
+WskSampleReceiveIrpCompletionRoutine(
+ PDEVICE_OBJECT Reserved,
+ PIRP Irp,
+ PVOID Context
+ )
+{
+ PWSKSAMPLE_SOCKET_OP_CONTEXT socketOpContext;
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ UNREFERENCED_PARAMETER(Reserved);
+
+ _Analysis_assume_(Context != NULL);
+
+ socketOpContext = (PWSKSAMPLE_SOCKET_OP_CONTEXT)Context;
+ socketContext = socketOpContext->SocketContext;
+
+ DoTraceMessage(TRCINFO,
+ "ReceiveIrpCompletionRoutine: %p %p 0x%lx %Iu",
+ socketContext, socketOpContext, Irp->IoStatus.Status,
+ Irp->IoStatus.Information);
+
+ if(!NT_SUCCESS(Irp->IoStatus.Status)) {
+ // Receive failed. Enqueue an operation to close the socket
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpClose);
+ }
+ else {
+ if(Irp->IoStatus.Information == 0) {
+ // Successful receive completion with 0 bytes means the peer
+ // has gracefully disconnected its half of the connection.
+ // So, we enqueue an operation to disconnect our half.
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpDisconnect);
+ }
+ else {
+ // Receive has completed with some data. So, we enqueue an
+ // operation to send the data back. Note that the data
+ // buffer is attached to the operation context that is being
+ // queued. We just need to remember the actual length of
+ // data received into the buffer.
+ socketOpContext->DataLength = Irp->IoStatus.Information;
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpSend);
+ }
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+// Operation handler for issuing a send request on a connected socket
+VOID
+WskSampleOpSend(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ if(socketContext->Closing || socketContext->Disconnecting) {
+ // Do not call WskSend if socket is being disconnected
+ // or closed. The operation context will not be used any more.
+ DoTraceMessage(TRCINFO, "OpSend: %p %p SKIP",
+ socketContext, SocketOpContext);
+ }
+ else {
+ WSK_BUF wskbuf;
+ CONST WSK_PROVIDER_CONNECTION_DISPATCH *dispatch;
+
+ dispatch = socketContext->Socket->Dispatch;
+
+ wskbuf.Offset = 0;
+ wskbuf.Length = SocketOpContext->DataLength;
+ wskbuf.Mdl = SocketOpContext->DataMdl;
+
+ IoReuseIrp(SocketOpContext->Irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(SocketOpContext->Irp,
+ WskSampleSendIrpCompletionRoutine,
+ SocketOpContext, TRUE, TRUE, TRUE);
+
+ DoTraceMessage(TRCINFO, "OpSend: %p %p %Iu",
+ socketContext, SocketOpContext, wskbuf.Length);
+
+ // No need to check the return status here. The IRP completion
+ // routine will take action based on the completion status.
+ dispatch->WskSend(
+ socketContext->Socket,
+ &wskbuf,
+ 0,
+ SocketOpContext->Irp);
+ }
+}
+
+// IRP completion routine for WskSend requests
+_Use_decl_annotations_
+NTSTATUS
+WskSampleSendIrpCompletionRoutine(
+ PDEVICE_OBJECT Reserved,
+ PIRP Irp,
+ PVOID Context
+ )
+{
+ PWSKSAMPLE_SOCKET_OP_CONTEXT socketOpContext;
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ UNREFERENCED_PARAMETER(Reserved);
+
+ _Analysis_assume_(Context != NULL);
+
+ socketOpContext = (PWSKSAMPLE_SOCKET_OP_CONTEXT)Context;
+ socketContext = socketOpContext->SocketContext;
+
+ DoTraceMessage(TRCINFO,
+ "SendIrpCompletionRoutine: %p %p 0x%lx %Iu", socketContext,
+ socketOpContext, Irp->IoStatus.Status, Irp->IoStatus.Information);
+
+ if(!NT_SUCCESS(Irp->IoStatus.Status)) {
+ // Send failed. Enqueue an operation to close the socket.
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpClose);
+ }
+ else {
+ // Send succeeded. Enqueue an operation to receive more data.
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpReceive);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+// Operation handler for issuing a disconnect request on a connected socket
+VOID
+WskSampleOpDisconnect(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ if(socketContext->Closing || socketContext->Disconnecting) {
+ // Do not call WskDisconnect if socket is already being
+ // disconnected or closed. A disconnect operation may get
+ // enqueued multiple times as a result of multiple outstanding
+ // receive requests getting completed with success and 0 bytes.
+ DoTraceMessage(TRCINFO, "OpDisconnect: %p %p SKIP",
+ socketContext, SocketOpContext);
+ }
+ else {
+ CONST WSK_PROVIDER_CONNECTION_DISPATCH *dispatch;
+
+ dispatch = socketContext->Socket->Dispatch;
+
+ socketContext->Disconnecting = TRUE;
+
+ IoReuseIrp(SocketOpContext->Irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(SocketOpContext->Irp,
+ WskSampleDisconnectIrpCompletionRoutine,
+ SocketOpContext, TRUE, TRUE, TRUE);
+
+ DoTraceMessage(TRCINFO, "OpDisconnect: %p %p",
+ socketContext, SocketOpContext);
+
+ // No need to check the return status here. The IRP completion
+ // routine will take action based on the completion status.
+ dispatch->WskDisconnect(
+ socketContext->Socket,
+ NULL,
+ 0,
+ SocketOpContext->Irp);
+ }
+}
+
+// IRP completion routine for WskDisconnect requests
+_Use_decl_annotations_
+NTSTATUS
+WskSampleDisconnectIrpCompletionRoutine(
+ PDEVICE_OBJECT Reserved,
+ PIRP Irp,
+ PVOID Context
+ )
+{
+ PWSKSAMPLE_SOCKET_OP_CONTEXT socketOpContext;
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ UNREFERENCED_PARAMETER(Reserved);
+ UNREFERENCED_PARAMETER(Irp);
+
+ _Analysis_assume_(Context != NULL);
+
+ socketOpContext = (PWSKSAMPLE_SOCKET_OP_CONTEXT)Context;
+ socketContext = socketOpContext->SocketContext;
+
+ DoTraceMessage(TRCINFO, "DisconnectIrpCompletionRoutine: %p %p 0x%lx",
+ socketContext, socketOpContext, Irp->IoStatus.Status);
+
+ // Disconnect completed. Enqueue an operation to close the socket.
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpClose);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+// Operation handler for closing a socket
+VOID
+WskSampleOpClose(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ if(socketContext->Closing) {
+ // Do not call WskClose if socket is already being closed.
+ // A close operation may get enqueued multiple times as a result
+ // of multiple outstanding send/receive/disconnect operations
+ // getting completed with failure.
+ DoTraceMessage(TRCINFO, "OpClose: %p %p SKIP",
+ socketContext, SocketOpContext);
+ }
+ else {
+ CONST WSK_PROVIDER_BASIC_DISPATCH *dispatch;
+
+ socketContext->Closing = TRUE;
+
+ dispatch = socketContext->Socket->Dispatch;
+
+ IoReuseIrp(SocketOpContext->Irp, STATUS_UNSUCCESSFUL);
+ IoSetCompletionRoutine(SocketOpContext->Irp,
+ WskSampleCloseIrpCompletionRoutine,
+ SocketOpContext, TRUE, TRUE, TRUE);
+
+ DoTraceMessage(TRCINFO,"OpClose: %p %p", socketContext,SocketOpContext);
+
+ // No need to check the return status here. The IRP completion
+ // routine will take action based on the completion status.
+ dispatch->WskCloseSocket(
+ socketContext->Socket,
+ SocketOpContext->Irp);
+ }
+}
+
+// IRP completion routine for WskCloseSocket requests
+_Use_decl_annotations_
+NTSTATUS
+WskSampleCloseIrpCompletionRoutine(
+ PDEVICE_OBJECT Reserved,
+ PIRP Irp,
+ PVOID Context
+ )
+{
+ PWSKSAMPLE_SOCKET_OP_CONTEXT socketOpContext;
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ UNREFERENCED_PARAMETER(Reserved);
+ UNREFERENCED_PARAMETER(Irp);
+
+ _Analysis_assume_(Context != NULL);
+
+ socketOpContext = (PWSKSAMPLE_SOCKET_OP_CONTEXT)Context;
+ socketContext = socketOpContext->SocketContext;
+
+ // WskCloseSocket can never fail.
+ ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
+
+ DoTraceMessage(TRCINFO, "CloseIrpCompletionRoutine: %p %p 0x%lx",
+ socketContext, socketOpContext, Irp->IoStatus.Status);
+
+ // Enqueue an operation to free the socket context. Since the
+ // completion of WskCloseSocket guarantees that there are no
+ // outstanding requests or callbacks on the socket, we can
+ // safely free the socket context. However, we still can NOT
+ // free the socket context directly here since there may still be
+ // queued operations not yet issued over the socket. Thus, we need
+ // to queue this "free" operation behind any other queued
+ // operations (which will not be issued over the socket since the
+ // socket context is marked as "closing"). Note that NO new
+ // operations can be queued behind the "free" operation for a
+ // given socket since we enqueue new operations only from the
+ // context of IRP completions on the socket.
+ WskSampleEnqueueOp(socketOpContext, WskSampleOpFree);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+// Operation handler for freeing the context block for a closed socket
+VOID
+WskSampleOpFree(
+ _In_ PWSKSAMPLE_SOCKET_OP_CONTEXT SocketOpContext
+ )
+{
+ PWSKSAMPLE_SOCKET_CONTEXT socketContext;
+
+ PAGED_CODE();
+
+ socketContext = SocketOpContext->SocketContext;
+
+ DoTraceMessage(TRCINFO, "OpFree: %p %p", socketContext, SocketOpContext);
+
+ ASSERT(socketContext->Closing || socketContext->StopListening);
+ WskSampleFreeSocketContext(socketContext);
+}
+
diff --git a/network/wsk/echosrv/wsksmple.rc b/network/wsk/echosrv/wsksmple.rc
new file mode 100644
index 00000000..572afe1c
--- /dev/null
+++ b/network/wsk/echosrv/wsksmple.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "WSK Sample TCP Echo Server"
+#define VER_INTERNALNAME_STR "wsksample.sys"
+#define VER_ORIGINALFILENAME_STR "wsksample.sys"
+
+#include "common.ver"
+