VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp@ 59742

Last change on this file since 59742 was 59742, checked in by vboxsync, 9 years ago

NetLwf/Win(bugref:7933): Log system error events on failures

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 110.0 KB
Line 
1/* $Id: VBoxNetLwf-win.cpp 59742 2016-02-19 15:18:15Z vboxsync $ */
2/** @file
3 * VBoxNetLwf-win.cpp - NDIS6 Bridged Networking Driver, Windows-specific code.
4 */
5/*
6 * Copyright (C) 2014-2015 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
17
18//#define VBOXNETLWF_SYNC_SEND
19/* Payload + Ethernet header + VLAN tag = Max Ethernet frame size */
20#define VBOXNETLWF_MAX_FRAME_SIZE(mtu) (mtu + sizeof(RTNETETHERHDR) + 4)
21
22#include <VBox/version.h>
23#include <VBox/err.h>
24#include <iprt/initterm.h>
25#include <iprt/net.h>
26#include <iprt/list.h>
27#include <VBox/intnetinline.h>
28
29/// @todo Not sure why, but can it help with build errors?
30RT_C_DECLS_BEGIN
31/* ntddk.h has a missing #pragma pack(), work around it
32 * see #ifdef VBOX_WITH_WORKAROUND_MISSING_PACK below for detail */
33#define VBOX_WITH_WORKAROUND_MISSING_PACK
34#if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
35# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
36# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
37# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
38# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
39# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap
40# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap
41# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap
42# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap
43# pragma warning(disable : 4163)
44# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
45# pragma warning(disable : 4103)
46# endif
47# include <ntddk.h>
48# pragma warning(default : 4163)
49# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
50# pragma pack()
51# pragma warning(default : 4103)
52# endif
53# undef _InterlockedExchange
54# undef _InterlockedExchangeAdd
55# undef _InterlockedCompareExchange
56# undef _InterlockedAddLargeStatistic
57# undef _interlockedbittestandset
58# undef _interlockedbittestandreset
59# undef _interlockedbittestandset64
60# undef _interlockedbittestandreset64
61# include <ndis.h>
62# include <netioapi.h>
63#else
64# include <ntddk.h>
65# include <netioapi.h>
66/* can include ndis.h right away */
67# include <ndis.h>
68#endif
69#include <mstcpip.h>
70RT_C_DECLS_END
71
72#define LogError(x) DbgPrint x
73
74#if 0
75#undef Log
76#define Log(x) DbgPrint x
77#undef LogFlow
78#define LogFlow(x) DbgPrint x
79#endif
80
81/** We have an entirely different structure than the one defined in VBoxNetFltCmn-win.h */
82typedef struct VBOXNETFLTWIN
83{
84 /** filter module context handle */
85 NDIS_HANDLE hModuleCtx;
86 /** IP address change notifier handle */
87 HANDLE hNotifier; /* Must be here as hModuleCtx may already be NULL when vboxNetFltOsDeleteInstance is called */
88} VBOXNETFLTWIN, *PVBOXNETFLTWIN;
89#define VBOXNETFLT_NO_PACKET_QUEUE
90#define VBOXNETFLT_OS_SPECFIC 1
91#include "VBoxNetFltInternal.h"
92
93#include "VBoxNetLwf-win.h"
94#include "VBox/VBoxNetCmn-win.h"
95
96/* Forward declarations */
97FILTER_ATTACH vboxNetLwfWinAttach;
98FILTER_DETACH vboxNetLwfWinDetach;
99FILTER_RESTART vboxNetLwfWinRestart;
100FILTER_PAUSE vboxNetLwfWinPause;
101FILTER_OID_REQUEST vboxNetLwfWinOidRequest;
102FILTER_OID_REQUEST_COMPLETE vboxNetLwfWinOidRequestComplete;
103//FILTER_CANCEL_OID_REQUEST vboxNetLwfWinCancelOidRequest;
104FILTER_STATUS vboxNetLwfWinStatus;
105//FILTER_NET_PNP_EVENT vboxNetLwfWinPnPEvent;
106FILTER_SEND_NET_BUFFER_LISTS vboxNetLwfWinSendNetBufferLists;
107FILTER_SEND_NET_BUFFER_LISTS_COMPLETE vboxNetLwfWinSendNetBufferListsComplete;
108FILTER_RECEIVE_NET_BUFFER_LISTS vboxNetLwfWinReceiveNetBufferLists;
109FILTER_RETURN_NET_BUFFER_LISTS vboxNetLwfWinReturnNetBufferLists;
110KSTART_ROUTINE vboxNetLwfWinInitIdcWorker;
111
112typedef enum {
113 LwfState_Detached = 0,
114 LwfState_Attaching,
115 LwfState_Paused,
116 LwfState_Restarting,
117 LwfState_Running,
118 LwfState_Pausing,
119 LwfState_32BitHack = 0x7fffffff
120} VBOXNETLWFSTATE;
121
122/*
123 * Valid state transitions are:
124 * 1) Disconnected -> Connecting : start the worker thread, attempting to init IDC;
125 * 2) Connecting -> Disconnected : failed to start IDC init worker thread;
126 * 3) Connecting -> Connected : IDC init successful, terminate the worker;
127 * 4) Connecting -> Stopping : IDC init incomplete, but the driver is being unloaded, terminate the worker;
128 * 5) Connected -> Stopping : IDC init was successful, no worker, the driver is being unloaded;
129 *
130 * Driver terminates in Stopping state.
131 */
132typedef enum {
133 LwfIdcState_Disconnected = 0, /* Initial state */
134 LwfIdcState_Connecting, /* Attemping to init IDC, worker thread running */
135 LwfIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
136 LwfIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
137} VBOXNETLWFIDCSTATE;
138
139struct _VBOXNETLWF_MODULE;
140
141typedef struct VBOXNETLWFGLOBALS
142{
143 /** synch event used for device creation synchronization */
144 //KEVENT SynchEvent;
145 /** Device reference count */
146 //int cDeviceRefs;
147 /** ndis device */
148 NDIS_HANDLE hDevice;
149 /** device object */
150 PDEVICE_OBJECT pDevObj;
151 /** our filter driver handle */
152 NDIS_HANDLE hFilterDriver;
153 /** lock protecting the module list */
154 NDIS_SPIN_LOCK Lock;
155 /** the head of module list */
156 RTLISTANCHOR listModules;
157 /** IDC initialization state */
158 volatile uint32_t enmIdcState;
159 /** IDC init thread handle */
160 HANDLE hInitIdcThread;
161} VBOXNETLWFGLOBALS, *PVBOXNETLWFGLOBALS;
162
163/**
164 * The (common) global data.
165 */
166static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
167/* win-specific global data */
168VBOXNETLWFGLOBALS g_VBoxNetLwfGlobals;
169
170typedef struct _VBOXNETLWF_MODULE {
171 RTLISTNODE node;
172
173 NDIS_HANDLE hFilter;
174 NDIS_HANDLE hPool;
175 PVBOXNETLWFGLOBALS pGlobals;
176 /** Associated instance of NetFlt, one-to-one relationship */
177 PVBOXNETFLTINS pNetFlt; /// @todo Consider automic access!
178 /** Module state as described in http://msdn.microsoft.com/en-us/library/windows/hardware/ff550017(v=vs.85).aspx */
179 volatile uint32_t enmState; /* No lock needed yet, atomic should suffice. */
180 /** Mutex to prevent pausing while transmitting on behalf of NetFlt */
181 NDIS_MUTEX InTransmit;
182#ifdef VBOXNETLWF_SYNC_SEND
183 /** Event signalled when sending to the wire is complete */
184 KEVENT EventWire;
185 /** Event signalled when NDIS returns our receive notification */
186 KEVENT EventHost;
187#else /* !VBOXNETLWF_SYNC_SEND */
188 /** Event signalled when all pending sends (both to wire and host) have completed */
189 NDIS_EVENT EventSendComplete;
190 /** Counter for pending sends (both to wire and host) */
191 int32_t cPendingBuffers;
192 /** Work Item to deliver offloading indications at passive IRQL */
193 NDIS_HANDLE hWorkItem;
194#endif /* !VBOXNETLWF_SYNC_SEND */
195 /** MAC address of underlying adapter */
196 RTMAC MacAddr;
197 /** Saved MTU size */
198 ULONG uMtuSize;
199 /** Saved offload configuration */
200 NDIS_OFFLOAD SavedOffloadConfig;
201 /** the cloned request we have passed down */
202 PNDIS_OID_REQUEST pPendingRequest;
203 /** true if the underlying miniport supplied offloading config */
204 bool fOffloadConfigValid;
205 /** true if the trunk expects data from us */
206 bool fActive;
207 /** true if the host wants the adapter to be in promisc mode */
208 bool fHostPromisc;
209 /** Name of underlying adapter */
210 char szMiniportName[1];
211} VBOXNETLWF_MODULE;
212typedef VBOXNETLWF_MODULE *PVBOXNETLWF_MODULE;
213
214/*
215 * A structure to wrap OID requests in.
216 */
217typedef struct _VBOXNETLWF_OIDREQ {
218 NDIS_OID_REQUEST Request;
219 NDIS_STATUS Status;
220 NDIS_EVENT Event;
221} VBOXNETLWF_OIDREQ;
222typedef VBOXNETLWF_OIDREQ *PVBOXNETLWF_OIDREQ;
223
224/* Forward declarations */
225static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver);
226static int vboxNetLwfWinInitBase();
227static int vboxNetLwfWinFini();
228
229/**
230 * Logs an error to the system event log.
231 *
232 * @param ErrCode Error to report to event log.
233 * @param ReturnedStatus Error that was reported by the driver to the caller.
234 * @param uErrId Unique error id representing the location in the driver.
235 * @param cbDumpData Number of bytes at pDumpData.
236 * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
237 */
238static void vboxNetLwfLogErrorEvent(NTSTATUS uErrCode, NTSTATUS uReturnedStatus, ULONG uErrId)
239{
240 /* Figure out how many modules are attached and if they are going to fit into the dump data. */
241 unsigned cMaxModules = (ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) / sizeof(RTMAC);
242 unsigned cModules = 0;
243 PVBOXNETLWF_MODULE pModuleCtx = NULL;
244 NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
245 RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
246 ++cModules;
247 NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
248 /* Prevent overflow */
249 if (cModules > cMaxModules)
250 cModules = cMaxModules;
251
252 /* DumpDataSize must be a multiple of sizeof(ULONG). */
253 unsigned cbDumpData = (cModules * sizeof(RTMAC) + 3) & ~3;
254 /* Prevent underflow */
255 unsigned cbTotal = RT_MAX(FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData,
256 sizeof(IO_ERROR_LOG_PACKET));
257
258 PIO_ERROR_LOG_PACKET pErrEntry;
259 pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxNetLwfGlobals.pDevObj,
260 (UCHAR)cbTotal);
261 if (pErrEntry)
262 {
263 PRTMAC pDump = (PRTMAC)pErrEntry->DumpData;
264 /*
265 * Initialize the whole structure with zeros in case we are suddenly short
266 * of data because the list is empty or has become smaller.
267 */
268 memset(pErrEntry, 0, cbTotal);
269
270 NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
271 RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
272 {
273 /* The list could have been modified while we were allocating the entry, rely on cModules instead! */
274 if (cModules-- == 0)
275 break;
276 *pDump++ = pModuleCtx->MacAddr;
277 }
278 NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
279
280 pErrEntry->DumpDataSize = cbDumpData;
281 pErrEntry->ErrorCode = uErrCode;
282 pErrEntry->UniqueErrorValue = uErrId;
283 pErrEntry->FinalStatus = uReturnedStatus;
284 IoWriteErrorLogEntry(pErrEntry);
285 }
286 else
287 {
288 DbgPrint("Failed to allocate error log entry (cb=%u)\n", cbTotal);
289 }
290}
291
292#ifdef DEBUG
293static const char *vboxNetLwfWinStatusToText(NDIS_STATUS code)
294{
295 switch (code)
296 {
297 case NDIS_STATUS_MEDIA_CONNECT: return "NDIS_STATUS_MEDIA_CONNECT";
298 case NDIS_STATUS_MEDIA_DISCONNECT: return "NDIS_STATUS_MEDIA_DISCONNECT";
299 case NDIS_STATUS_RESET_START: return "NDIS_STATUS_RESET_START";
300 case NDIS_STATUS_RESET_END: return "NDIS_STATUS_RESET_END";
301 case NDIS_STATUS_MEDIA_BUSY: return "NDIS_STATUS_MEDIA_BUSY";
302 case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: return "NDIS_STATUS_MEDIA_SPECIFIC_INDICATION";
303 case NDIS_STATUS_LINK_SPEED_CHANGE: return "NDIS_STATUS_LINK_SPEED_CHANGE";
304 case NDIS_STATUS_LINK_STATE: return "NDIS_STATUS_LINK_STATE";
305 case NDIS_STATUS_PORT_STATE: return "NDIS_STATUS_PORT_STATE";
306 case NDIS_STATUS_OPER_STATUS: return "NDIS_STATUS_OPER_STATUS";
307 case NDIS_STATUS_NETWORK_CHANGE: return "NDIS_STATUS_NETWORK_CHANGE";
308 case NDIS_STATUS_PACKET_FILTER: return "NDIS_STATUS_PACKET_FILTER";
309 case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: return "NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG";
310 case NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES";
311 case NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE: return "NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE";
312 case NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES";
313 }
314 return "unknown";
315}
316
317static void vboxNetLwfWinDumpFilterTypes(ULONG uFlags)
318{
319 if (uFlags & NDIS_PACKET_TYPE_DIRECTED) Log5((" NDIS_PACKET_TYPE_DIRECTED\n"));
320 if (uFlags & NDIS_PACKET_TYPE_MULTICAST) Log5((" NDIS_PACKET_TYPE_MULTICAST\n"));
321 if (uFlags & NDIS_PACKET_TYPE_ALL_MULTICAST) Log5((" NDIS_PACKET_TYPE_ALL_MULTICAST\n"));
322 if (uFlags & NDIS_PACKET_TYPE_BROADCAST) Log5((" NDIS_PACKET_TYPE_BROADCAST\n"));
323 if (uFlags & NDIS_PACKET_TYPE_PROMISCUOUS) Log5((" NDIS_PACKET_TYPE_PROMISCUOUS\n"));
324 if (uFlags & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_ALL_FUNCTIONAL\n"));
325 if (uFlags & NDIS_PACKET_TYPE_ALL_LOCAL) Log5((" NDIS_PACKET_TYPE_ALL_LOCAL\n"));
326 if (uFlags & NDIS_PACKET_TYPE_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_FUNCTIONAL\n"));
327 if (uFlags & NDIS_PACKET_TYPE_GROUP) Log5((" NDIS_PACKET_TYPE_GROUP\n"));
328 if (uFlags & NDIS_PACKET_TYPE_MAC_FRAME) Log5((" NDIS_PACKET_TYPE_MAC_FRAME\n"));
329 if (uFlags & NDIS_PACKET_TYPE_SMT) Log5((" NDIS_PACKET_TYPE_SMT\n"));
330 if (uFlags & NDIS_PACKET_TYPE_SOURCE_ROUTING) Log5((" NDIS_PACKET_TYPE_SOURCE_ROUTING\n"));
331 if (uFlags == 0) Log5((" NONE\n"));
332}
333
334DECLINLINE(void) vboxNetLwfWinDumpEncapsulation(const char *pcszText, ULONG uEncapsulation)
335{
336 if (uEncapsulation == NDIS_ENCAPSULATION_NOT_SUPPORTED)
337 Log5(("%s not supported\n", pcszText));
338 else
339 {
340 Log5(("%s", pcszText));
341 if (uEncapsulation & NDIS_ENCAPSULATION_NULL)
342 Log5((" null"));
343 if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3)
344 Log5((" 802.3"));
345 if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q)
346 Log5((" 802.3pq"));
347 if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q_IN_OOB)
348 Log5((" 802.3pq(oob)"));
349 if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_LLC_SNAP_ROUTED)
350 Log5((" LLC"));
351 Log5(("\n"));
352 }
353}
354
355DECLINLINE(const char *) vboxNetLwfWinSetOnOffText(ULONG uOnOff)
356{
357 switch (uOnOff)
358 {
359 case NDIS_OFFLOAD_SET_NO_CHANGE: return "no change";
360 case NDIS_OFFLOAD_SET_ON: return "on";
361 case NDIS_OFFLOAD_SET_OFF: return "off";
362 }
363 return "unknown";
364}
365
366DECLINLINE(const char *) vboxNetLwfWinOnOffText(ULONG uOnOff)
367{
368 switch (uOnOff)
369 {
370 case NDIS_OFFLOAD_NOT_SUPPORTED: return "off";
371 case NDIS_OFFLOAD_SUPPORTED: return "on";
372 }
373 return "unknown";
374}
375
376DECLINLINE(const char *) vboxNetLwfWinSupportedText(ULONG uSupported)
377{
378 switch (uSupported)
379 {
380 case NDIS_OFFLOAD_NOT_SUPPORTED: return "not supported";
381 case NDIS_OFFLOAD_SUPPORTED: return "supported";
382 }
383 return "unknown";
384}
385
386static void vboxNetLwfWinDumpSetOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
387{
388 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
389 Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
390 Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
391 Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
392 Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
393 Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
394 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
395 Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
396 Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
397 Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
398 Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
399 Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
400 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
401 Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
402 Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
403 Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
404 Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
405 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
406 Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
407 Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
408 Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
409 Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
410 vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
411 Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
412 Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
413 vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
414 vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
415 Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
416 Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
417}
418
419static void vboxNetLwfWinDumpOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
420{
421 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
422 Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
423 Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
424 Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
425 Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
426 Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
427 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
428 Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
429 Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
430 Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
431 Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
432 Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
433 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
434 Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
435 Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
436 Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
437 Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
438 vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
439 Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
440 Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
441 Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
442 Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
443 vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
444 Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
445 Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
446 vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
447 vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
448 Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
449 Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
450}
451
452static const char *vboxNetLwfWinStateToText(uint32_t enmState)
453{
454 switch (enmState)
455 {
456 case LwfState_Detached: return "Detached";
457 case LwfState_Attaching: return "Attaching";
458 case LwfState_Paused: return "Paused";
459 case LwfState_Restarting: return "Restarting";
460 case LwfState_Running: return "Running";
461 case LwfState_Pausing: return "Pausing";
462 }
463 return "invalid";
464}
465
466#else /* !DEBUG */
467#define vboxNetLwfWinDumpFilterTypes(uFlags)
468#define vboxNetLwfWinDumpOffloadSettings(p)
469#define vboxNetLwfWinDumpSetOffloadSettings(p)
470#endif /* DEBUG */
471
472DECLINLINE(bool) vboxNetLwfWinChangeState(PVBOXNETLWF_MODULE pModuleCtx, uint32_t enmNew, uint32_t enmOld = LwfState_32BitHack)
473{
474 AssertReturn(pModuleCtx, false);
475
476 bool fSuccess = true;
477 if (enmOld != LwfState_32BitHack)
478 {
479 fSuccess = ASMAtomicCmpXchgU32(&pModuleCtx->enmState, enmNew, enmOld);
480 if (fSuccess)
481 Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
482 vboxNetLwfWinStateToText(enmOld),
483 vboxNetLwfWinStateToText(enmNew)));
484 else
485 Log(("ERROR! vboxNetLwfWinChangeState: failed state change %s (actual=%s) -> %s\n",
486 vboxNetLwfWinStateToText(enmOld),
487 vboxNetLwfWinStateToText(ASMAtomicReadU32(&pModuleCtx->enmState)),
488 vboxNetLwfWinStateToText(enmNew)));
489 Assert(fSuccess);
490 }
491 else
492 {
493 uint32_t enmPrevState = ASMAtomicXchgU32(&pModuleCtx->enmState, enmNew);
494 Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
495 vboxNetLwfWinStateToText(enmPrevState),
496 vboxNetLwfWinStateToText(enmNew)));
497 }
498 return fSuccess;
499}
500
501DECLINLINE(void) vboxNetLwfWinInitOidRequest(PVBOXNETLWF_OIDREQ pRequest)
502{
503 NdisZeroMemory(pRequest, sizeof(VBOXNETLWF_OIDREQ));
504
505 NdisInitializeEvent(&pRequest->Event);
506
507 pRequest->Request.Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
508 pRequest->Request.Header.Revision = NDIS_OID_REQUEST_REVISION_1;
509 pRequest->Request.Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
510
511 pRequest->Request.RequestId = (PVOID)VBOXNETLWF_REQ_ID;
512}
513
514static NDIS_STATUS vboxNetLwfWinSyncOidRequest(PVBOXNETLWF_MODULE pModuleCtx, PVBOXNETLWF_OIDREQ pRequest)
515{
516 NDIS_STATUS Status = NdisFOidRequest(pModuleCtx->hFilter, &pRequest->Request);
517 if (Status == NDIS_STATUS_PENDING)
518 {
519 NdisWaitEvent(&pRequest->Event, 0);
520 Status = pRequest->Status;
521 }
522 return Status;
523}
524
525DECLINLINE(void) vboxNetLwfWinCopyOidRequestResults(PNDIS_OID_REQUEST pFrom, PNDIS_OID_REQUEST pTo)
526{
527 switch (pFrom->RequestType)
528 {
529 case NdisRequestSetInformation:
530 pTo->DATA.SET_INFORMATION.BytesRead = pFrom->DATA.SET_INFORMATION.BytesRead;
531 pTo->DATA.SET_INFORMATION.BytesNeeded = pFrom->DATA.SET_INFORMATION.BytesNeeded;
532 break;
533 case NdisRequestMethod:
534 pTo->DATA.METHOD_INFORMATION.OutputBufferLength = pFrom->DATA.METHOD_INFORMATION.OutputBufferLength;
535 pTo->DATA.METHOD_INFORMATION.BytesWritten = pFrom->DATA.METHOD_INFORMATION.BytesWritten;
536 pTo->DATA.METHOD_INFORMATION.BytesRead = pFrom->DATA.METHOD_INFORMATION.BytesRead;
537 pTo->DATA.METHOD_INFORMATION.BytesNeeded = pFrom->DATA.METHOD_INFORMATION.BytesNeeded;
538 break;
539 case NdisRequestQueryInformation:
540 case NdisRequestQueryStatistics:
541 default:
542 pTo->DATA.QUERY_INFORMATION.BytesWritten = pFrom->DATA.QUERY_INFORMATION.BytesWritten;
543 pTo->DATA.QUERY_INFORMATION.BytesNeeded = pFrom->DATA.QUERY_INFORMATION.BytesNeeded;
544 }
545}
546
547void inline vboxNetLwfWinOverridePacketFiltersUp(PVBOXNETLWF_MODULE pModuleCtx, ULONG *pFilters)
548{
549 if (ASMAtomicReadBool(&pModuleCtx->fActive) && !ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
550 *pFilters &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
551}
552
553NDIS_STATUS vboxNetLwfWinOidRequest(IN NDIS_HANDLE hModuleCtx,
554 IN PNDIS_OID_REQUEST pOidRequest)
555{
556 LogFlow(("==>vboxNetLwfWinOidRequest: module=%p\n", hModuleCtx));
557 vboxNetCmnWinDumpOidRequest(__FUNCTION__, pOidRequest);
558 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
559 PNDIS_OID_REQUEST pClone = NULL;
560 NDIS_STATUS Status = NdisAllocateCloneOidRequest(pModuleCtx->hFilter,
561 pOidRequest,
562 VBOXNETLWF_MEM_TAG,
563 &pClone);
564 if (Status == NDIS_STATUS_SUCCESS)
565 {
566 /* Save the pointer to the original */
567 *((PNDIS_OID_REQUEST*)(pClone->SourceReserved)) = pOidRequest;
568
569 pClone->RequestId = pOidRequest->RequestId;
570 /* We are not supposed to get another request until we are through with the one we "postponed" */
571 PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, pClone, PNDIS_OID_REQUEST);
572 Assert(pPrev == NULL);
573 pModuleCtx->pPendingRequest = pClone;
574 if (pOidRequest->RequestType == NdisRequestSetInformation
575 && pOidRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
576 {
577 ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer & NDIS_PACKET_TYPE_PROMISCUOUS));
578 Log(("vboxNetLwfWinOidRequest: host wanted to set packet filter value to:\n"));
579 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
580 /* Keep adapter in promisc mode as long as we are active. */
581 if (ASMAtomicReadBool(&pModuleCtx->fActive))
582 *(ULONG*)pClone->DATA.SET_INFORMATION.InformationBuffer |= NDIS_PACKET_TYPE_PROMISCUOUS;
583 Log5(("vboxNetLwfWinOidRequest: pass the following packet filters to miniport:\n"));
584 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
585 }
586 if (pOidRequest->RequestType == NdisRequestSetInformation
587 && pOidRequest->DATA.SET_INFORMATION.Oid == OID_TCP_OFFLOAD_CURRENT_CONFIG)
588 {
589 Log5(("vboxNetLwfWinOidRequest: offloading set to:\n"));
590 vboxNetLwfWinDumpSetOffloadSettings((PNDIS_OFFLOAD)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
591 }
592
593 /* Forward the clone to underlying filters/miniport */
594 Status = NdisFOidRequest(pModuleCtx->hFilter, pClone);
595 if (Status != NDIS_STATUS_PENDING)
596 {
597 /* Synchronous completion */
598 pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
599 Assert(pPrev == pClone);
600 Log5(("vboxNetLwfWinOidRequest: got the following packet filters from miniport:\n"));
601 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
602 /*
603 * The host does not expect the adapter to be in promisc mode,
604 * unless it enabled the mode. Let's not disillusion it.
605 */
606 if ( pOidRequest->RequestType == NdisRequestQueryInformation
607 && pOidRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
608 vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
609 Log5(("vboxNetLwfWinOidRequest: reporting to the host the following packet filters:\n"));
610 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
611 vboxNetLwfWinCopyOidRequestResults(pClone, pOidRequest);
612 NdisFreeCloneOidRequest(pModuleCtx->hFilter, pClone);
613 }
614 /* In case of async completion we do the rest in vboxNetLwfWinOidRequestComplete() */
615 }
616 else
617 {
618 LogError(("vboxNetLwfWinOidRequest: NdisAllocateCloneOidRequest failed with 0x%x\n", Status));
619 }
620 LogFlow(("<==vboxNetLwfWinOidRequest: Status=0x%x\n", Status));
621 return Status;
622}
623
624VOID vboxNetLwfWinOidRequestComplete(IN NDIS_HANDLE hModuleCtx,
625 IN PNDIS_OID_REQUEST pRequest,
626 IN NDIS_STATUS Status)
627{
628 LogFlow(("==>vboxNetLwfWinOidRequestComplete: module=%p req=%p status=0x%x\n", hModuleCtx, pRequest, Status));
629 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
630 PNDIS_OID_REQUEST pOriginal = *((PNDIS_OID_REQUEST*)(pRequest->SourceReserved));
631 if (pOriginal)
632 {
633 /* NDIS is supposed to serialize requests */
634 PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
635 Assert(pPrev == pRequest);
636
637 Log5(("vboxNetLwfWinOidRequestComplete: completed rq type=%d oid=%x\n", pRequest->RequestType, pRequest->DATA.QUERY_INFORMATION.Oid));
638 vboxNetLwfWinCopyOidRequestResults(pRequest, pOriginal);
639 if ( pRequest->RequestType == NdisRequestQueryInformation
640 && pRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
641 {
642 Log5(("vboxNetLwfWinOidRequestComplete: underlying miniport reports its packet filters:\n"));
643 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
644 vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
645 Log5(("vboxNetLwfWinOidRequestComplete: reporting the following packet filters to upper protocol:\n"));
646 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
647 }
648 NdisFreeCloneOidRequest(pModuleCtx->hFilter, pRequest);
649 NdisFOidRequestComplete(pModuleCtx->hFilter, pOriginal, Status);
650 }
651 else
652 {
653 /* This is not a clone, we originated it */
654 Log(("vboxNetLwfWinOidRequestComplete: locally originated request (%p) completed, status=0x%x\n", pRequest, Status));
655 PVBOXNETLWF_OIDREQ pRqWrapper = RT_FROM_MEMBER(pRequest, VBOXNETLWF_OIDREQ, Request);
656 pRqWrapper->Status = Status;
657 NdisSetEvent(&pRqWrapper->Event);
658 }
659 LogFlow(("<==vboxNetLwfWinOidRequestComplete\n"));
660}
661
662
663static bool vboxNetLwfWinIsPromiscuous(PVBOXNETLWF_MODULE pModuleCtx)
664{
665 return ASMAtomicReadBool(&pModuleCtx->fHostPromisc);
666}
667
668#if 0
669static NDIS_STATUS vboxNetLwfWinGetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx)
670{
671 LogFlow(("==>vboxNetLwfWinGetPacketFilter: module=%p\n", pModuleCtx));
672 VBOXNETLWF_OIDREQ Rq;
673 vboxNetLwfWinInitOidRequest(&Rq);
674 Rq.Request.RequestType = NdisRequestQueryInformation;
675 Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
676 Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &pModuleCtx->uPacketFilter;
677 Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(pModuleCtx->uPacketFilter);
678 NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
679 if (Status != NDIS_STATUS_SUCCESS)
680 {
681 LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
682 return FALSE;
683 }
684 if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(pModuleCtx->uPacketFilter))
685 {
686 LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(pModuleCtx->uPacketFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
687 }
688
689 Log5(("vboxNetLwfWinGetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
690 vboxNetLwfWinDumpFilterTypes(pModuleCtx->uPacketFilter);
691
692 LogFlow(("<==vboxNetLwfWinGetPacketFilter: status=0x%x\n", Status));
693 return Status;
694}
695#endif
696
697static NDIS_STATUS vboxNetLwfWinSetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx, bool fPromisc)
698{
699 LogFlow(("==>vboxNetLwfWinSetPacketFilter: module=%p %s\n", pModuleCtx, fPromisc ? "promiscuous" : "normal"));
700 ULONG uFilter = 0;
701 VBOXNETLWF_OIDREQ Rq;
702 vboxNetLwfWinInitOidRequest(&Rq);
703 Rq.Request.RequestType = NdisRequestQueryInformation;
704 Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
705 Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &uFilter;
706 Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(uFilter);
707 NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
708 if (Status != NDIS_STATUS_SUCCESS)
709 {
710 LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
711 return Status;
712 }
713 if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(uFilter))
714 {
715 LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(uFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
716 return NDIS_STATUS_FAILURE;
717 }
718
719 Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
720 vboxNetLwfWinDumpFilterTypes(uFilter);
721
722 if (fPromisc)
723 {
724 /* If we about to go promiscuous, save the state before we change it. */
725 ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(uFilter & NDIS_PACKET_TYPE_PROMISCUOUS));
726 uFilter |= NDIS_PACKET_TYPE_PROMISCUOUS;
727 }
728 else
729 {
730 /* Reset promisc only if it was not enabled before we had changed it. */
731 if (!ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
732 uFilter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
733 }
734
735 Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER about to set the following filters:\n"));
736 vboxNetLwfWinDumpFilterTypes(uFilter);
737
738 NdisResetEvent(&Rq.Event); /* need to reset as it has been set by query op */
739 Rq.Request.RequestType = NdisRequestSetInformation;
740 Rq.Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
741 Rq.Request.DATA.SET_INFORMATION.InformationBuffer = &uFilter;
742 Rq.Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(uFilter);
743 Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
744 if (Status != NDIS_STATUS_SUCCESS)
745 {
746 LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(set, OID_GEN_CURRENT_PACKET_FILTER, vvv below vvv) failed with 0x%x\n", Status));
747 vboxNetLwfWinDumpFilterTypes(uFilter);
748 }
749 LogFlow(("<==vboxNetLwfWinSetPacketFilter: status=0x%x\n", Status));
750 return Status;
751}
752
753
754static NTSTATUS vboxNetLwfWinDevDispatch(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
755{
756 PIO_STACK_LOCATION pIrpSl = IoGetCurrentIrpStackLocation(pIrp);;
757 NTSTATUS Status = STATUS_SUCCESS;
758
759 switch (pIrpSl->MajorFunction)
760 {
761 case IRP_MJ_DEVICE_CONTROL:
762 Status = STATUS_NOT_SUPPORTED;
763 break;
764 case IRP_MJ_CREATE:
765 case IRP_MJ_CLEANUP:
766 case IRP_MJ_CLOSE:
767 break;
768 default:
769 Assert(0);
770 break;
771 }
772
773 pIrp->IoStatus.Status = Status;
774 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
775
776 return Status;
777}
778
779/** @todo So far we had no use for device, should we even bother to create it? */
780static NDIS_STATUS vboxNetLwfWinDevCreate(PVBOXNETLWFGLOBALS pGlobals)
781{
782 NDIS_STRING DevName, LinkName;
783 PDRIVER_DISPATCH aMajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
784 NdisInitUnicodeString(&DevName, VBOXNETLWF_NAME_DEVICE);
785 NdisInitUnicodeString(&LinkName, VBOXNETLWF_NAME_LINK);
786
787 Assert(!pGlobals->hDevice);
788 Assert(!pGlobals->pDevObj);
789 NdisZeroMemory(aMajorFunctions, sizeof (aMajorFunctions));
790 aMajorFunctions[IRP_MJ_CREATE] = vboxNetLwfWinDevDispatch;
791 aMajorFunctions[IRP_MJ_CLEANUP] = vboxNetLwfWinDevDispatch;
792 aMajorFunctions[IRP_MJ_CLOSE] = vboxNetLwfWinDevDispatch;
793 aMajorFunctions[IRP_MJ_DEVICE_CONTROL] = vboxNetLwfWinDevDispatch;
794
795 NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceAttributes;
796 NdisZeroMemory(&DeviceAttributes, sizeof(DeviceAttributes));
797 DeviceAttributes.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
798 DeviceAttributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
799 DeviceAttributes.Header.Size = sizeof(DeviceAttributes);
800 DeviceAttributes.DeviceName = &DevName;
801 DeviceAttributes.SymbolicName = &LinkName;
802 DeviceAttributes.MajorFunctions = aMajorFunctions;
803 //DeviceAttributes.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
804
805 NDIS_STATUS Status = NdisRegisterDeviceEx(pGlobals->hFilterDriver,
806 &DeviceAttributes,
807 &pGlobals->pDevObj,
808 &pGlobals->hDevice);
809 Log(("vboxNetLwfWinDevCreate: NdisRegisterDeviceEx returned 0x%x\n", Status));
810 Assert(Status == NDIS_STATUS_SUCCESS);
811#if 0
812 if (Status == NDIS_STATUS_SUCCESS)
813 {
814 PFILTER_DEVICE_EXTENSION pExtension;
815 pExtension = NdisGetDeviceReservedExtension(pGlobals->pDevObj);
816 pExtension->Signature = VBOXNETLWF_MEM_TAG;
817 pExtension->Handle = pGlobals->hFilterDriver;
818 }
819#endif
820 return Status;
821}
822
823static void vboxNetLwfWinDevDestroy(PVBOXNETLWFGLOBALS pGlobals)
824{
825 Assert(pGlobals->hDevice);
826 Assert(pGlobals->pDevObj);
827 NdisDeregisterDeviceEx(pGlobals->hDevice);
828 pGlobals->hDevice = NULL;
829 pGlobals->pDevObj = NULL;
830}
831
832static void vboxNetLwfWinUpdateSavedOffloadConfig(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
833{
834 pModuleCtx->SavedOffloadConfig = *pOffload;
835 pModuleCtx->fOffloadConfigValid = true;
836}
837
838static NDIS_STATUS vboxNetLwfWinAttach(IN NDIS_HANDLE hFilter, IN NDIS_HANDLE hDriverCtx,
839 IN PNDIS_FILTER_ATTACH_PARAMETERS pParameters)
840{
841 LogFlow(("==>vboxNetLwfWinAttach: filter=%p\n", hFilter));
842
843 PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)hDriverCtx;
844 if (!pGlobals)
845 {
846 vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 1);
847 return NDIS_STATUS_FAILURE;
848 }
849
850 ANSI_STRING strMiniportName;
851 /* We use the miniport name to associate this filter module with the netflt instance */
852 NTSTATUS rc = RtlUnicodeStringToAnsiString(&strMiniportName,
853 pParameters->BaseMiniportName,
854 TRUE);
855 if (rc != STATUS_SUCCESS)
856 {
857 LogError(("vboxNetLwfWinAttach: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
858 pParameters->BaseMiniportName, rc));
859 vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
860 return NDIS_STATUS_FAILURE;
861 }
862 DbgPrint("vboxNetLwfWinAttach: friendly name=%wZ\n", pParameters->BaseMiniportInstanceName);
863 DbgPrint("vboxNetLwfWinAttach: name=%Z\n", &strMiniportName);
864
865 UINT cbModuleWithNameExtra = sizeof(VBOXNETLWF_MODULE) + strMiniportName.Length;
866 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)NdisAllocateMemoryWithTagPriority(hFilter,
867 cbModuleWithNameExtra,
868 VBOXNETLWF_MEM_TAG,
869 LowPoolPriority);
870 if (!pModuleCtx)
871 {
872 LogError(("vboxNetLwfWinAttach: Failed to allocate module context for %ls\n", pParameters->BaseMiniportName));
873 RtlFreeAnsiString(&strMiniportName);
874 vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 3);
875 return NDIS_STATUS_RESOURCES;
876 }
877 Log4(("vboxNetLwfWinAttach: allocated module context 0x%p\n", pModuleCtx));
878
879 NdisZeroMemory(pModuleCtx, cbModuleWithNameExtra);
880 NdisMoveMemory(pModuleCtx->szMiniportName, strMiniportName.Buffer, strMiniportName.Length);
881 RtlFreeAnsiString(&strMiniportName);
882
883 pModuleCtx->hWorkItem = NdisAllocateIoWorkItem(g_VBoxNetLwfGlobals.hFilterDriver);
884 if (!pModuleCtx->hWorkItem)
885 {
886 LogError(("vboxNetLwfWinAttach: Failed to allocate work item for %ls\n",
887 pParameters->BaseMiniportName));
888 NdisFreeMemory(pModuleCtx, 0, 0);
889 vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 4);
890 return NDIS_STATUS_RESOURCES;
891 }
892
893 Assert(pParameters->MacAddressLength == sizeof(RTMAC));
894 NdisMoveMemory(&pModuleCtx->MacAddr, pParameters->CurrentMacAddress, RT_MIN(sizeof(RTMAC), pParameters->MacAddressLength));
895 if (pParameters->DefaultOffloadConfiguration)
896 vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, pParameters->DefaultOffloadConfiguration);
897
898 pModuleCtx->pGlobals = pGlobals;
899 pModuleCtx->hFilter = hFilter;
900 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Attaching);
901 /* Initialize transmission mutex and events */
902 NDIS_INIT_MUTEX(&pModuleCtx->InTransmit);
903#ifdef VBOXNETLWF_SYNC_SEND
904 KeInitializeEvent(&pModuleCtx->EventWire, SynchronizationEvent, FALSE);
905 KeInitializeEvent(&pModuleCtx->EventHost, SynchronizationEvent, FALSE);
906#else /* !VBOXNETLWF_SYNC_SEND */
907 NdisInitializeEvent(&pModuleCtx->EventSendComplete);
908 pModuleCtx->cPendingBuffers = 0;
909#endif /* !VBOXNETLWF_SYNC_SEND */
910
911 NDIS_FILTER_ATTRIBUTES Attributes;
912 NdisZeroMemory(&Attributes, sizeof(Attributes));
913 Attributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
914 Attributes.Header.Size = sizeof(Attributes);
915 Attributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
916 Attributes.Flags = 0;
917 NDIS_STATUS Status = NdisFSetAttributes(hFilter, pModuleCtx, &Attributes);
918 if (Status != NDIS_STATUS_SUCCESS)
919 {
920 LogError(("vboxNetLwfWinAttach: NdisFSetAttributes failed with 0x%x\n", Status));
921 NdisFreeNetBufferListPool(pModuleCtx->hPool);
922 Log4(("vboxNetLwfWinAttach: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool));
923 NdisFreeIoWorkItem(pModuleCtx->hWorkItem);
924 NdisFreeMemory(pModuleCtx, 0, 0);
925 vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_RESOURCES, 5);
926 return NDIS_STATUS_RESOURCES;
927 }
928 /* Insert into module chain */
929 NdisAcquireSpinLock(&pGlobals->Lock);
930 RTListPrepend(&pGlobals->listModules, &pModuleCtx->node);
931 NdisReleaseSpinLock(&pGlobals->Lock);
932
933 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused);
934
935 /// @todo Somehow the packet filter is 0 at this point: Status = vboxNetLwfWinGetPacketFilter(pModuleCtx);
936 /// @todo We actually update it later in status handler, perhaps we should not do anything here.
937
938 LogFlow(("<==vboxNetLwfWinAttach: Status = 0x%x\n", Status));
939 return Status;
940}
941
942static VOID vboxNetLwfWinDetach(IN NDIS_HANDLE hModuleCtx)
943{
944 LogFlow(("==>vboxNetLwfWinDetach: module=%p\n", hModuleCtx));
945 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
946 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Detached, LwfState_Paused);
947
948 /* Remove from module chain */
949 NdisAcquireSpinLock(&pModuleCtx->pGlobals->Lock);
950 RTListNodeRemove(&pModuleCtx->node);
951 NdisReleaseSpinLock(&pModuleCtx->pGlobals->Lock);
952
953 PVBOXNETFLTINS pNetFltIns = pModuleCtx->pNetFlt; /// @todo Atomic?
954 if (pNetFltIns && vboxNetFltTryRetainBusyNotDisconnected(pNetFltIns))
955 {
956 /*
957 * Set hModuleCtx to null now in order to prevent filter restart,
958 * OID requests and other stuff associated with NetFlt deactivation.
959 */
960 pNetFltIns->u.s.WinIf.hModuleCtx = NULL;
961 /* Notify NetFlt that we are going down */
962 pNetFltIns->pSwitchPort->pfnDisconnect(pNetFltIns->pSwitchPort, &pNetFltIns->MyPort, vboxNetFltPortReleaseBusy);
963 /* We do not 'release' netflt instance since it has been done by pfnDisconnect */
964 }
965 pModuleCtx->pNetFlt = NULL;
966
967 /*
968 * We have to make sure that all NET_BUFFER_LIST structures have been freed by now, but
969 * it does not require us to do anything here since it has already been taken care of
970 * by vboxNetLwfWinPause().
971 */
972 if (pModuleCtx->hPool)
973 {
974 NdisFreeNetBufferListPool(pModuleCtx->hPool);
975 Log4(("vboxNetLwfWinDetach: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool));
976 }
977 NdisFreeIoWorkItem(pModuleCtx->hWorkItem);
978 NdisFreeMemory(hModuleCtx, 0, 0);
979 Log4(("vboxNetLwfWinDetach: freed module context 0x%p\n", pModuleCtx));
980 LogFlow(("<==vboxNetLwfWinDetach\n"));
981}
982
983
984static NDIS_STATUS vboxNetLwfWinPause(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_PAUSE_PARAMETERS pParameters)
985{
986 LogFlow(("==>vboxNetLwfWinPause: module=%p\n", hModuleCtx));
987 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
988 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Pausing, LwfState_Running);
989 /* Wait for pending send/indication operations to complete. */
990 NDIS_WAIT_FOR_MUTEX(&pModuleCtx->InTransmit);
991#ifndef VBOXNETLWF_SYNC_SEND
992 NdisWaitEvent(&pModuleCtx->EventSendComplete, 1000 /* ms */);
993#endif /* !VBOXNETLWF_SYNC_SEND */
994 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused, LwfState_Pausing);
995 NDIS_RELEASE_MUTEX(&pModuleCtx->InTransmit);
996 LogFlow(("<==vboxNetLwfWinPause\n"));
997 return NDIS_STATUS_SUCCESS; /* Failure is not an option */
998}
999
1000
1001static void vboxNetLwfWinIndicateOffload(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
1002{
1003 Log5(("vboxNetLwfWinIndicateOffload: offload config changed to:\n"));
1004 vboxNetLwfWinDumpOffloadSettings(pOffload);
1005 NDIS_STATUS_INDICATION OffloadingIndication;
1006 NdisZeroMemory(&OffloadingIndication, sizeof(OffloadingIndication));
1007 OffloadingIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
1008 OffloadingIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
1009 OffloadingIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
1010 OffloadingIndication.SourceHandle = pModuleCtx->hFilter;
1011 OffloadingIndication.StatusCode = NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG;
1012 OffloadingIndication.StatusBuffer = pOffload;
1013 OffloadingIndication.StatusBufferSize = sizeof(NDIS_OFFLOAD);
1014 NdisFIndicateStatus(pModuleCtx->hFilter, &OffloadingIndication);
1015}
1016
1017
1018static NDIS_STATUS vboxNetLwfWinRestart(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_RESTART_PARAMETERS pParameters)
1019{
1020 LogFlow(("==>vboxNetLwfWinRestart: module=%p\n", hModuleCtx));
1021 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
1022 vboxNetLwfWinChangeState(pModuleCtx, LwfState_Restarting, LwfState_Paused);
1023
1024 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1025 ULONG uNewMtuSize = 1500; /* If we fail to find out MTU, we can always assume 1500. */
1026 PNDIS_RESTART_ATTRIBUTES pAttributes = pParameters->RestartAttributes;
1027 while (pAttributes && pAttributes->Oid != OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
1028 pAttributes = pAttributes->Next;
1029 if (pAttributes)
1030 {
1031 PNDIS_RESTART_GENERAL_ATTRIBUTES pGenAttrs = (PNDIS_RESTART_GENERAL_ATTRIBUTES)pAttributes->Data;
1032 uNewMtuSize = pGenAttrs->MtuSize;
1033 }
1034
1035 /* Let's see if MTU has changed. Re-allocate the pool if it has. */
1036 if (pModuleCtx->uMtuSize != uNewMtuSize)
1037 {
1038 pModuleCtx->uMtuSize = uNewMtuSize;
1039 if (pModuleCtx->hPool)
1040 {
1041 /*
1042 * Don't need to wait for pending sends to complete since we are already
1043 * in paused state. Just free the old pool.
1044 */
1045 NdisFreeNetBufferListPool(pModuleCtx->hPool);
1046 pModuleCtx->hPool = NULL;
1047 }
1048 }
1049 if (!pModuleCtx->hPool)
1050 {
1051 /* Allocate a new pool. */
1052 NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
1053 NdisZeroMemory(&PoolParams, sizeof(PoolParams));
1054 PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
1055 PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
1056 PoolParams.Header.Size = sizeof(PoolParams);
1057 PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
1058 PoolParams.fAllocateNetBuffer = TRUE;
1059 PoolParams.ContextSize = 0; /** @todo Do we need to consider underlying drivers? I think not. */
1060 PoolParams.PoolTag = VBOXNETLWF_MEM_TAG;
1061#ifndef VBOXNETLWF_SYNC_SEND
1062 PoolParams.DataSize = VBOXNETLWF_MAX_FRAME_SIZE(pModuleCtx->uMtuSize);
1063#endif /* !VBOXNETLWF_SYNC_SEND */
1064
1065 pModuleCtx->hPool = NdisAllocateNetBufferListPool(pModuleCtx->hFilter, &PoolParams);
1066 if (!pModuleCtx->hPool)
1067 {
1068 LogError(("vboxNetLwfWinRestart: NdisAllocateNetBufferListPool failed\n"));
1069 Status = NDIS_STATUS_RESOURCES;
1070 }
1071 else
1072 {
1073 Log4(("vboxNetLwfWinRestart: allocated NBL+NB pool 0x%p with MTU=%u\n",
1074 pModuleCtx->hPool, pModuleCtx->uMtuSize));
1075 }
1076 }
1077
1078 vboxNetLwfWinChangeState(pModuleCtx, Status == NDIS_STATUS_SUCCESS ? LwfState_Running : LwfState_Paused, LwfState_Restarting);
1079 LogFlow(("<==vboxNetLwfWinRestart: Status = 0x%x\n", Status));
1080 return Status;
1081}
1082
1083
1084static void vboxNetLwfWinDumpPackets(const char *pszMsg, PNET_BUFFER_LIST pBufLists)
1085{
1086 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
1087 {
1088 for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
1089 {
1090 Log(("%s packet: cb=%d\n", pszMsg, NET_BUFFER_DATA_LENGTH(pBuf)));
1091 }
1092 }
1093}
1094
1095DECLINLINE(const char *) vboxNetLwfWinEthTypeStr(uint16_t uType)
1096{
1097 switch (uType)
1098 {
1099 case RTNET_ETHERTYPE_IPV4: return "IP";
1100 case RTNET_ETHERTYPE_IPV6: return "IPv6";
1101 case RTNET_ETHERTYPE_ARP: return "ARP";
1102 }
1103 return "unknown";
1104}
1105
1106#define VBOXNETLWF_PKTDMPSIZE 0x50
1107
1108/**
1109 * Dump a packet to debug log.
1110 *
1111 * @param cpPacket The packet.
1112 * @param cb The size of the packet.
1113 * @param cszText A string denoting direction of packet transfer.
1114 */
1115DECLINLINE(void) vboxNetLwfWinDumpPacket(PCINTNETSG pSG, const char *cszText)
1116{
1117 uint8_t bPacket[VBOXNETLWF_PKTDMPSIZE];
1118
1119 uint32_t cb = pSG->cbTotal < VBOXNETLWF_PKTDMPSIZE ? pSG->cbTotal : VBOXNETLWF_PKTDMPSIZE;
1120 IntNetSgReadEx(pSG, 0, cb, bPacket);
1121
1122 AssertReturnVoid(cb >= 14);
1123
1124 uint8_t *pHdr = bPacket;
1125 uint8_t *pEnd = bPacket + cb;
1126 AssertReturnVoid(pEnd - pHdr >= 14);
1127 uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12));
1128 Log2(("NetLWF: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
1129 cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetLwfWinEthTypeStr(uEthType), uEthType));
1130 pHdr += sizeof(RTNETETHERHDR);
1131 if (uEthType == RTNET_ETHERTYPE_VLAN)
1132 {
1133 AssertReturnVoid(pEnd - pHdr >= 4);
1134 uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2));
1135 Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF,
1136 vboxNetLwfWinEthTypeStr(uEthType), uEthType));
1137 pHdr += 2 * sizeof(uint16_t);
1138 }
1139 uint8_t uProto = 0xFF;
1140 switch (uEthType)
1141 {
1142 case RTNET_ETHERTYPE_IPV6:
1143 AssertReturnVoid(pEnd - pHdr >= 40);
1144 uProto = pHdr[6];
1145 Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24));
1146 pHdr += 40;
1147 break;
1148 case RTNET_ETHERTYPE_IPV4:
1149 AssertReturnVoid(pEnd - pHdr >= 20);
1150 uProto = pHdr[9];
1151 Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16)));
1152 pHdr += (pHdr[0] & 0xF) * 4;
1153 break;
1154 case RTNET_ETHERTYPE_ARP:
1155 AssertReturnVoid(pEnd - pHdr >= 28);
1156 AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4);
1157 switch (RT_N2H_U16(*(uint16_t*)(pHdr+6)))
1158 {
1159 case 1: /* ARP request */
1160 Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n",
1161 *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14)));
1162 break;
1163 case 2: /* ARP reply */
1164 Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n",
1165 *(uint32_t*)(pHdr+14), pHdr+8));
1166 break;
1167 default:
1168 Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6))));
1169 break;
1170 }
1171 break;
1172 /* There is no default case as uProto is initialized with 0xFF */
1173 }
1174 while (uProto != 0xFF)
1175 {
1176 switch (uProto)
1177 {
1178 case 0: /* IPv6 Hop-by-Hop option*/
1179 case 60: /* IPv6 Destination option*/
1180 case 43: /* IPv6 Routing option */
1181 case 44: /* IPv6 Fragment option */
1182 Log2((" + IPv6 option (%d): <not implemented>\n", uProto));
1183 uProto = pHdr[0];
1184 pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */
1185 break;
1186 case 51: /* IPv6 IPsec AH */
1187 Log2((" + IPv6 IPsec AH: <not implemented>\n"));
1188 uProto = pHdr[0];
1189 pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */
1190 break;
1191 case 50: /* IPv6 IPsec ESP */
1192 /* Cannot decode IPsec, fall through */
1193 Log2((" + IPv6 IPsec ESP: <not implemented>\n"));
1194 uProto = 0xFF;
1195 break;
1196 case 59: /* No Next Header */
1197 Log2((" + IPv6 No Next Header\n"));
1198 uProto = 0xFF;
1199 break;
1200 case 58: /* IPv6-ICMP */
1201 switch (pHdr[0])
1202 {
1203 case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break;
1204 case 128: Log2((" + IPv6-ICMP: echo request\n")); break;
1205 case 129: Log2((" + IPv6-ICMP: echo reply\n")); break;
1206 default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
1207 }
1208 uProto = 0xFF;
1209 break;
1210 case 1: /* ICMP */
1211 switch (pHdr[0])
1212 {
1213 case 0: Log2((" + ICMP: echo reply\n")); break;
1214 case 8: Log2((" + ICMP: echo request\n")); break;
1215 case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break;
1216 default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
1217 }
1218 uProto = 0xFF;
1219 break;
1220 case 6: /* TCP */
1221 Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n",
1222 RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)),
1223 RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8))));
1224 uProto = 0xFF;
1225 break;
1226 case 17: /* UDP */
1227 Log2((" + UDP: src=%d dst=%d\n",
1228 RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2))));
1229 uProto = 0xFF;
1230 break;
1231 default:
1232 Log2((" + Unknown: proto=0x%x\n", uProto));
1233 uProto = 0xFF;
1234 break;
1235 }
1236 }
1237 Log3(("%.*Rhxd\n", cb, bPacket));
1238}
1239
1240static void vboxNetLwfWinDestroySG(PINTNETSG pSG)
1241{
1242 NdisFreeMemory(pSG, 0, 0);
1243 Log4(("vboxNetLwfWinDestroySG: freed SG 0x%p\n", pSG));
1244}
1245
1246DECLINLINE(ULONG) vboxNetLwfWinCalcSegments(PNET_BUFFER pNetBuf)
1247{
1248 ULONG cSegs = 0;
1249 for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf); pMdl; pMdl = NDIS_MDL_LINKAGE(pMdl))
1250 cSegs++;
1251 return cSegs;
1252}
1253
1254DECLINLINE(void) vboxNetLwfWinFreeMdlChain(PMDL pMdl)
1255{
1256#ifdef VBOXNETLWF_SYNC_SEND
1257 PMDL pMdlNext;
1258 while (pMdl)
1259 {
1260 pMdlNext = pMdl->Next;
1261 NdisFreeMdl(pMdl);
1262 Log4(("vboxNetLwfWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
1263 pMdl = pMdlNext;
1264 }
1265#endif /* VBOXNETLWF_SYNC_SEND */
1266}
1267
1268/** @todo
1269 * 1) Copy data from SG to MDL (if we decide to complete asynchronously).
1270 * 2) Provide context/backfill space. Nobody does it, should we?
1271 * 3) We always get a single segment from intnet. Simplify?
1272 */
1273static PNET_BUFFER_LIST vboxNetLwfWinSGtoNB(PVBOXNETLWF_MODULE pModule, PINTNETSG pSG)
1274{
1275 AssertReturn(pSG->cSegsUsed >= 1, NULL);
1276 LogFlow(("==>vboxNetLwfWinSGtoNB: segments=%d hPool=%p cb=%u max=%u\n", pSG->cSegsUsed,
1277 pModule->hPool, pSG->cbTotal, VBOXNETLWF_MAX_FRAME_SIZE(pModule->uMtuSize)));
1278 AssertReturn(pModule->hPool, NULL);
1279
1280#ifdef VBOXNETLWF_SYNC_SEND
1281 PINTNETSEG pSeg = pSG->aSegs;
1282 PMDL pMdl = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
1283 if (!pMdl)
1284 {
1285 LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
1286 LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
1287 return NULL;
1288 }
1289 Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdl));
1290 PMDL pMdlCurr = pMdl;
1291 for (int i = 1; i < pSG->cSegsUsed; i++)
1292 {
1293 pSeg = &pSG->aSegs[i];
1294 pMdlCurr->Next = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
1295 if (!pMdlCurr->Next)
1296 {
1297 LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
1298 /* Tear down all MDL we chained so far */
1299 vboxNetLwfWinFreeMdlChain(pMdl);
1300 return NULL;
1301 }
1302 pMdlCurr = pMdlCurr->Next;
1303 Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdlCurr));
1304 }
1305 PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferAndNetBufferList(pModule->hPool,
1306 0 /* ContextSize */,
1307 0 /* ContextBackFill */,
1308 pMdl,
1309 0 /* DataOffset */,
1310 pSG->cbTotal);
1311 if (pBufList)
1312 {
1313 Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
1314 pBufList->SourceHandle = pModule->hFilter;
1315 /** @todo Do we need to initialize anything else? */
1316 }
1317 else
1318 {
1319 LogError(("vboxNetLwfWinSGtoNB: failed to allocate an NBL+NB\n"));
1320 vboxNetLwfWinFreeMdlChain(pMdl);
1321 }
1322#else /* !VBOXNETLWF_SYNC_SEND */
1323 AssertReturn(pSG->cbTotal <= VBOXNETLWF_MAX_FRAME_SIZE(pModule->uMtuSize), NULL);
1324 PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferList(pModule->hPool,
1325 0 /** @todo ContextSize */,
1326 0 /** @todo ContextBackFill */);
1327 NET_BUFFER_LIST_NEXT_NBL(pBufList) = NULL; /** @todo Is it even needed? */
1328 NET_BUFFER *pBuffer = NET_BUFFER_LIST_FIRST_NB(pBufList);
1329 NDIS_STATUS Status = NdisRetreatNetBufferDataStart(pBuffer, pSG->cbTotal, 0 /** @todo DataBackfill */, NULL);
1330 if (Status == NDIS_STATUS_SUCCESS)
1331 {
1332 uint8_t *pDst = (uint8_t*)NdisGetDataBuffer(pBuffer, pSG->cbTotal, NULL, 1, 0);
1333 if (pDst)
1334 {
1335 for (int i = 0; i < pSG->cSegsUsed; i++)
1336 {
1337 NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
1338 pDst += pSG->aSegs[i].cb;
1339 }
1340 Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB+MDL+Data 0x%p\n", pBufList));
1341 pBufList->SourceHandle = pModule->hFilter;
1342 /** @todo Do we need to initialize anything else? */
1343 }
1344 else
1345 {
1346 LogError(("vboxNetLwfWinSGtoNB: failed to obtain the buffer pointer (size=%u)\n", pSG->cbTotal));
1347 NdisAdvanceNetBufferDataStart(pBuffer, pSG->cbTotal, false, NULL); /** @todo why bother? */
1348 NdisFreeNetBufferList(pBufList);
1349 pBufList = NULL;
1350 }
1351 }
1352 else
1353 {
1354 LogError(("vboxNetLwfWinSGtoNB: NdisRetreatNetBufferDataStart failed with 0x%x (size=%u)\n", Status, pSG->cbTotal));
1355 NdisFreeNetBufferList(pBufList);
1356 pBufList = NULL;
1357 }
1358#endif /* !VBOXNETLWF_SYNC_SEND */
1359 LogFlow(("<==vboxNetLwfWinSGtoNB: return %p\n", pBufList));
1360 return pBufList;
1361}
1362
1363static PINTNETSG vboxNetLwfWinNBtoSG(PVBOXNETLWF_MODULE pModule, PNET_BUFFER pNetBuf)
1364{
1365 ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
1366 UINT cSegs = vboxNetLwfWinCalcSegments(pNetBuf);
1367 /* Allocate and initialize SG */
1368 PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pModule->hFilter,
1369 RT_OFFSETOF(INTNETSG, aSegs[cSegs]),
1370 VBOXNETLWF_MEM_TAG,
1371 NormalPoolPriority);
1372 AssertReturn(pSG, pSG);
1373 Log4(("vboxNetLwfWinNBtoSG: allocated SG 0x%p\n", pSG));
1374 IntNetSgInitTempSegs(pSG, cbPacket /*cbTotal*/, cSegs, cSegs /*cSegsUsed*/);
1375
1376 int rc = NDIS_STATUS_SUCCESS;
1377 ULONG uOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuf);
1378 cSegs = 0;
1379 for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf);
1380 pMdl != NULL && cbPacket > 0;
1381 pMdl = NDIS_MDL_LINKAGE(pMdl))
1382 {
1383 PUCHAR pSrc = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPagePriority);
1384 if (!pSrc)
1385 {
1386 rc = NDIS_STATUS_RESOURCES;
1387 break;
1388 }
1389 ULONG cbSrc = MmGetMdlByteCount(pMdl);
1390 if (uOffset)
1391 {
1392 Assert(uOffset < cbSrc);
1393 pSrc += uOffset;
1394 cbSrc -= uOffset;
1395 uOffset = 0;
1396 }
1397
1398 if (cbSrc > cbPacket)
1399 cbSrc = cbPacket;
1400
1401 pSG->aSegs[cSegs].pv = pSrc;
1402 pSG->aSegs[cSegs].cb = cbSrc;
1403 pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
1404 cSegs++;
1405 cbPacket -= cbSrc;
1406 }
1407
1408 Assert(cSegs <= pSG->cSegsAlloc);
1409
1410 if (RT_FAILURE(rc))
1411 {
1412 vboxNetLwfWinDestroySG(pSG);
1413 pSG = NULL;
1414 }
1415 else
1416 {
1417 Assert(cbPacket == 0);
1418 Assert(pSG->cSegsUsed == cSegs);
1419 }
1420 return pSG;
1421}
1422
1423static void vboxNetLwfWinDisableOffloading(PNDIS_OFFLOAD pOffloadConfig)
1424{
1425 pOffloadConfig->Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
1426 pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1427 pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1428 pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
1429 pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
1430 pOffloadConfig->Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
1431 pOffloadConfig->Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
1432 pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1433 pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1434 pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
1435 pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
1436 pOffloadConfig->LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
1437 pOffloadConfig->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
1438 pOffloadConfig->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
1439 pOffloadConfig->LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
1440 pOffloadConfig->LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
1441 pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1442 pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
1443}
1444
1445VOID vboxNetLwfWinStatus(IN NDIS_HANDLE hModuleCtx, IN PNDIS_STATUS_INDICATION pIndication)
1446{
1447 LogFlow(("==>vboxNetLwfWinStatus: module=%p\n", hModuleCtx));
1448 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
1449 Log(("vboxNetLwfWinStatus: Got status indication: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
1450 switch (pIndication->StatusCode)
1451 {
1452 case NDIS_STATUS_PACKET_FILTER:
1453 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
1454 vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pIndication->StatusBuffer);
1455 Log(("vboxNetLwfWinStatus: Reporting status: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
1456 vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
1457 break;
1458 case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
1459 Log5(("vboxNetLwfWinStatus: offloading currently set to:\n"));
1460 vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
1461 vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, (PNDIS_OFFLOAD)pIndication->StatusBuffer);
1462 if (ASMAtomicReadBool(&pModuleCtx->fActive))
1463 vboxNetLwfWinDisableOffloading((PNDIS_OFFLOAD)pIndication->StatusBuffer);
1464 Log5(("vboxNetLwfWinStatus: reporting offloading up as:\n"));
1465 vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
1466 break;
1467 }
1468 NdisFIndicateStatus(pModuleCtx->hFilter, pIndication);
1469 LogFlow(("<==vboxNetLwfWinStatus\n"));
1470}
1471
1472static bool vboxNetLwfWinForwardToIntNet(PVBOXNETLWF_MODULE pModuleCtx, PNET_BUFFER_LIST pBufLists, uint32_t fSrc)
1473{
1474 /* We must not forward anything to the trunk unless it is ready to receive. */
1475 if (!ASMAtomicReadBool(&pModuleCtx->fActive))
1476 {
1477 Log(("vboxNetLwfWinForwardToIntNet: trunk is inactive, won't forward\n"));
1478 return false;
1479 }
1480
1481 AssertReturn(pModuleCtx->pNetFlt, false);
1482 AssertReturn(pModuleCtx->pNetFlt->pSwitchPort, false);
1483 AssertReturn(pModuleCtx->pNetFlt->pSwitchPort->pfnRecv, false);
1484 LogFlow(("==>vboxNetLwfWinForwardToIntNet: module=%p\n", pModuleCtx));
1485 Assert(pBufLists); /* The chain must contain at least one list */
1486 Assert(NET_BUFFER_LIST_NEXT_NBL(pBufLists) == NULL); /* The caller is supposed to unlink the list from the chain */
1487 /*
1488 * Even if NBL contains more than one buffer we are prepared to deal with it.
1489 * When any of buffers should not be dropped we keep the whole list. It is
1490 * better to leak some "unexpected" packets to the wire/host than to loose any.
1491 */
1492 bool fDropIt = false;
1493 bool fDontDrop = false;
1494 int nLists = 0;
1495 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
1496 {
1497 int nBuffers = 0;
1498 nLists++;
1499 for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
1500 {
1501 nBuffers++;
1502 PINTNETSG pSG = vboxNetLwfWinNBtoSG(pModuleCtx, pBuf);
1503 if (pSG)
1504 {
1505 vboxNetLwfWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
1506 /* A bit paranoid, but we do not use any locks, so... */
1507 if (ASMAtomicReadBool(&pModuleCtx->fActive))
1508 if (pModuleCtx->pNetFlt->pSwitchPort->pfnRecv(pModuleCtx->pNetFlt->pSwitchPort, NULL, pSG, fSrc))
1509 fDropIt = true;
1510 else
1511 fDontDrop = true;
1512 vboxNetLwfWinDestroySG(pSG);
1513 }
1514 }
1515 Log(("vboxNetLwfWinForwardToIntNet: list=%d buffers=%d\n", nLists, nBuffers));
1516 }
1517 Log(("vboxNetLwfWinForwardToIntNet: lists=%d drop=%s don't=%s\n", nLists, fDropIt ? "true":"false", fDontDrop ? "true":"false"));
1518 LogFlow(("<==vboxNetLwfWinForwardToIntNet: return '%s'\n",
1519 fDropIt ? (fDontDrop ? "do not drop (some)" : "drop it") : "do not drop (any)"));
1520 return fDropIt && !fDontDrop; /* Drop the list if ALL its buffers are being dropped! */
1521}
1522
1523DECLINLINE(bool) vboxNetLwfWinIsRunning(PVBOXNETLWF_MODULE pModule)
1524{
1525 Log(("vboxNetLwfWinIsRunning: state=%d\n", ASMAtomicReadU32(&pModule->enmState)));
1526 return ASMAtomicReadU32(&pModule->enmState) == LwfState_Running;
1527}
1528
1529VOID vboxNetLwfWinSendNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN NDIS_PORT_NUMBER nPort, IN ULONG fFlags)
1530{
1531 size_t cb = 0;
1532 LogFlow(("==>vboxNetLwfWinSendNetBufferLists: module=%p\n", hModuleCtx));
1533 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
1534
1535 if (!ASMAtomicReadBool(&pModule->fActive))
1536 {
1537 /*
1538 * The trunk is inactive, jusp pass along all packets to the next
1539 * underlying driver.
1540 */
1541 NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
1542 return;
1543 }
1544
1545 if (vboxNetLwfWinIsRunning(pModule))
1546 {
1547 PNET_BUFFER_LIST pNext = NULL;
1548 PNET_BUFFER_LIST pDropHead = NULL;
1549 PNET_BUFFER_LIST pDropTail = NULL;
1550 PNET_BUFFER_LIST pPassHead = NULL;
1551 PNET_BUFFER_LIST pPassTail = NULL;
1552 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
1553 {
1554 pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
1555 NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
1556 if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_HOST))
1557 {
1558 NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_SUCCESS;
1559 if (pDropHead)
1560 {
1561 NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
1562 pDropTail = pList;
1563 }
1564 else
1565 pDropHead = pDropTail = pList;
1566 }
1567 else
1568 {
1569 if (pPassHead)
1570 {
1571 NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
1572 pPassTail = pList;
1573 }
1574 else
1575 pPassHead = pPassTail = pList;
1576 }
1577 }
1578 Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
1579 if (pPassHead)
1580 {
1581 vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: passing down", pPassHead);
1582 NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
1583 }
1584 if (pDropHead)
1585 {
1586 vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pDropHead);
1587 NdisFSendNetBufferListsComplete(pModule->hFilter, pDropHead,
1588 fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
1589 }
1590 }
1591 else
1592 {
1593 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
1594 {
1595 NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_PAUSED;
1596 }
1597 vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pBufLists);
1598 NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists,
1599 fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
1600
1601 }
1602 LogFlow(("<==vboxNetLwfWinSendNetBufferLists\n"));
1603}
1604
1605VOID vboxNetLwfWinSendNetBufferListsComplete(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
1606{
1607 size_t cb = 0;
1608 LogFlow(("==>vboxNetLwfWinSendNetBufferListsComplete: module=%p\n", hModuleCtx));
1609 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
1610 PNET_BUFFER_LIST pList = pBufLists;
1611 PNET_BUFFER_LIST pNextList;
1612 PNET_BUFFER_LIST pPrevList = NULL;
1613 while (pList)
1614 {
1615 pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
1616 if (pList->SourceHandle == pModule->hFilter)
1617 {
1618 /* We allocated this NET_BUFFER_LIST, let's free it up */
1619 Assert(NET_BUFFER_LIST_FIRST_NB(pList));
1620 Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1621 /*
1622 * All our NBLs hold a single NB each, no need to iterate over a list.
1623 * There is no need to free an associated NB explicitly either, as it was
1624 * preallocated with NBL structure.
1625 */
1626 Assert(!NET_BUFFER_NEXT_NB(NET_BUFFER_LIST_FIRST_NB(pList)));
1627 vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1628 /* Unlink this list from the chain */
1629 if (pPrevList)
1630 NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
1631 else
1632 pBufLists = pNextList;
1633 Log(("vboxNetLwfWinSendNetBufferListsComplete: our list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
1634 NdisFreeNetBufferList(pList);
1635#ifdef VBOXNETLWF_SYNC_SEND
1636 Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB 0x%p\n", pList));
1637 KeSetEvent(&pModule->EventWire, 0, FALSE);
1638#else /* !VBOXNETLWF_SYNC_SEND */
1639 Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB+MDL+Data 0x%p\n", pList));
1640 Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
1641 if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
1642 NdisSetEvent(&pModule->EventSendComplete);
1643#endif /* !VBOXNETLWF_SYNC_SEND */
1644 }
1645 else
1646 {
1647 pPrevList = pList;
1648 Log(("vboxNetLwfWinSendNetBufferListsComplete: passing list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
1649 }
1650 pList = pNextList;
1651 }
1652 if (pBufLists)
1653 {
1654 /* There are still lists remaining in the chain, pass'em up */
1655 NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists, fFlags);
1656 }
1657 LogFlow(("<==vboxNetLwfWinSendNetBufferListsComplete\n"));
1658}
1659
1660VOID vboxNetLwfWinReceiveNetBufferLists(IN NDIS_HANDLE hModuleCtx,
1661 IN PNET_BUFFER_LIST pBufLists,
1662 IN NDIS_PORT_NUMBER nPort,
1663 IN ULONG nBufLists,
1664 IN ULONG fFlags)
1665{
1666 /// @todo Do we need loopback handling?
1667 LogFlow(("==>vboxNetLwfWinReceiveNetBufferLists: module=%p\n", hModuleCtx));
1668 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
1669
1670 if (!ASMAtomicReadBool(&pModule->fActive))
1671 {
1672 /*
1673 * The trunk is inactive, jusp pass along all packets to the next
1674 * overlying driver.
1675 */
1676 NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufLists, nPort, nBufLists, fFlags);
1677 LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists: inactive trunk\n"));
1678 return;
1679 }
1680
1681 if (vboxNetLwfWinIsRunning(pModule))
1682 {
1683 if (NDIS_TEST_RECEIVE_CANNOT_PEND(fFlags))
1684 {
1685 /* We do not own NBLs so we do not need to return them */
1686 /* First we need to scan through the list to see if some packets must be dropped */
1687 bool bDropIt = false;
1688 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
1689 {
1690 PNET_BUFFER_LIST pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
1691 NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink temporarily */
1692 if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
1693 bDropIt = true;
1694 NET_BUFFER_LIST_NEXT_NBL(pList) = pNext; /* Restore the link */
1695 }
1696 if (bDropIt)
1697 {
1698 /* Some NBLs must be dropped, indicate selectively one by one */
1699 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
1700 {
1701 PNET_BUFFER_LIST pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
1702 NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink temporarily */
1703 vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pList);
1704 NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pList, nPort, nBufLists, fFlags);
1705 NET_BUFFER_LIST_NEXT_NBL(pList) = pNext; /* Restore the link */
1706 }
1707 }
1708 else
1709 {
1710 /* All NBLs must be indicated, do it in bulk. */
1711 vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pBufLists);
1712 NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufLists, nPort, nBufLists, fFlags);
1713 }
1714 }
1715 else
1716 {
1717 /* We collect dropped NBLs in a separate list in order to "return" them. */
1718 PNET_BUFFER_LIST pNext = NULL;
1719 PNET_BUFFER_LIST pDropHead = NULL;
1720 PNET_BUFFER_LIST pDropTail = NULL;
1721 PNET_BUFFER_LIST pPassHead = NULL;
1722 PNET_BUFFER_LIST pPassTail = NULL;
1723 ULONG nDrop = 0, nPass = 0;
1724 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
1725 {
1726 pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
1727 NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
1728 if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
1729 {
1730 if (nDrop++)
1731 {
1732 NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
1733 pDropTail = pList;
1734 }
1735 else
1736 pDropHead = pDropTail = pList;
1737 }
1738 else
1739 {
1740 if (nPass++)
1741 {
1742 NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
1743 pPassTail = pList;
1744 }
1745 else
1746 pPassHead = pPassTail = pList;
1747 }
1748 }
1749 Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
1750 Assert(nDrop + nPass == nBufLists);
1751 if (pPassHead)
1752 {
1753 vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pPassHead);
1754 NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pPassHead, nPort, nPass, fFlags);
1755 }
1756 if (pDropHead)
1757 {
1758 vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pDropHead);
1759 NdisFReturnNetBufferLists(pModule->hFilter, pDropHead,
1760 fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
1761 }
1762 }
1763
1764 }
1765 else
1766 {
1767 vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pBufLists);
1768 if ((fFlags & NDIS_RECEIVE_FLAGS_RESOURCES) == 0)
1769 NdisFReturnNetBufferLists(pModule->hFilter, pBufLists,
1770 fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
1771 }
1772 LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists\n"));
1773}
1774
1775VOID vboxNetLwfWinReturnNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
1776{
1777 size_t cb = 0;
1778 LogFlow(("==>vboxNetLwfWinReturnNetBufferLists: module=%p\n", hModuleCtx));
1779 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
1780 PNET_BUFFER_LIST pList = pBufLists;
1781 PNET_BUFFER_LIST pNextList;
1782 PNET_BUFFER_LIST pPrevList = NULL;
1783 /** @todo Move common part into a separate function to be used by vboxNetLwfWinSendNetBufferListsComplete() as well */
1784 while (pList)
1785 {
1786 pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
1787 if (pList->SourceHandle == pModule->hFilter)
1788 {
1789 /* We allocated this NET_BUFFER_LIST, let's free it up */
1790 Assert(NET_BUFFER_LIST_FIRST_NB(pList));
1791 Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1792 /*
1793 * All our NBLs hold a single NB each, no need to iterate over a list.
1794 * There is no need to free an associated NB explicitly either, as it was
1795 * preallocated with NBL structure.
1796 */
1797 vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1798 /* Unlink this list from the chain */
1799 if (pPrevList)
1800 NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
1801 else
1802 pBufLists = pNextList;
1803 NdisFreeNetBufferList(pList);
1804#ifdef VBOXNETLWF_SYNC_SEND
1805 Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB 0x%p\n", pList));
1806 KeSetEvent(&pModule->EventHost, 0, FALSE);
1807#else /* !VBOXNETLWF_SYNC_SEND */
1808 Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
1809 Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
1810 if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
1811 NdisSetEvent(&pModule->EventSendComplete);
1812#endif /* !VBOXNETLWF_SYNC_SEND */
1813 }
1814 else
1815 pPrevList = pList;
1816 pList = pNextList;
1817 }
1818 if (pBufLists)
1819 {
1820 /* There are still lists remaining in the chain, pass'em up */
1821 NdisFReturnNetBufferLists(pModule->hFilter, pBufLists, fFlags);
1822 }
1823 LogFlow(("<==vboxNetLwfWinReturnNetBufferLists\n"));
1824}
1825
1826/**
1827 * register the filter driver
1828 */
1829DECLHIDDEN(NDIS_STATUS) vboxNetLwfWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
1830{
1831 NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
1832 NDIS_STRING FriendlyName;
1833 NDIS_STRING UniqueName;
1834 NDIS_STRING ServiceName;
1835
1836 NdisInitUnicodeString(&FriendlyName, VBOXNETLWF_NAME_FRIENDLY);
1837 NdisInitUnicodeString(&UniqueName, VBOXNETLWF_NAME_UNIQUE);
1838 NdisInitUnicodeString(&ServiceName, VBOXNETLWF_NAME_SERVICE);
1839
1840 NdisZeroMemory(&FChars, sizeof (FChars));
1841
1842 FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
1843 FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
1844 FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
1845
1846 FChars.MajorNdisVersion = VBOXNETLWF_VERSION_NDIS_MAJOR;
1847 FChars.MinorNdisVersion = VBOXNETLWF_VERSION_NDIS_MINOR;
1848
1849 FChars.FriendlyName = FriendlyName;
1850 FChars.UniqueName = UniqueName;
1851 FChars.ServiceName = ServiceName;
1852
1853 /* Mandatory functions */
1854 FChars.AttachHandler = vboxNetLwfWinAttach;
1855 FChars.DetachHandler = vboxNetLwfWinDetach;
1856 FChars.RestartHandler = vboxNetLwfWinRestart;
1857 FChars.PauseHandler = vboxNetLwfWinPause;
1858
1859 /* Optional functions, non changeble at run-time */
1860 FChars.OidRequestHandler = vboxNetLwfWinOidRequest;
1861 FChars.OidRequestCompleteHandler = vboxNetLwfWinOidRequestComplete;
1862 //FChars.CancelOidRequestHandler = vboxNetLwfWinCancelOidRequest;
1863 FChars.StatusHandler = vboxNetLwfWinStatus;
1864 //FChars.NetPnPEventHandler = vboxNetLwfWinPnPEvent;
1865
1866 /* Datapath functions */
1867 FChars.SendNetBufferListsHandler = vboxNetLwfWinSendNetBufferLists;
1868 FChars.SendNetBufferListsCompleteHandler = vboxNetLwfWinSendNetBufferListsComplete;
1869 FChars.ReceiveNetBufferListsHandler = vboxNetLwfWinReceiveNetBufferLists;
1870 FChars.ReturnNetBufferListsHandler = vboxNetLwfWinReturnNetBufferLists;
1871
1872 pDriverObject->DriverUnload = vboxNetLwfWinUnloadDriver;
1873
1874 NDIS_STATUS Status;
1875 g_VBoxNetLwfGlobals.hFilterDriver = NULL;
1876 Log(("vboxNetLwfWinRegister: registering filter driver...\n"));
1877 Status = NdisFRegisterFilterDriver(pDriverObject,
1878 (NDIS_HANDLE)&g_VBoxNetLwfGlobals,
1879 &FChars,
1880 &g_VBoxNetLwfGlobals.hFilterDriver);
1881 Assert(Status == STATUS_SUCCESS);
1882 if (Status == STATUS_SUCCESS)
1883 {
1884 Log(("vboxNetLwfWinRegister: successfully registered filter driver; registering device...\n"));
1885 Status = vboxNetLwfWinDevCreate(&g_VBoxNetLwfGlobals);
1886 Assert(Status == STATUS_SUCCESS);
1887 Log(("vboxNetLwfWinRegister: vboxNetLwfWinDevCreate() returned 0x%x\n", Status));
1888 }
1889 else
1890 {
1891 LogError(("vboxNetLwfWinRegister: failed to register filter driver, status=0x%x", Status));
1892 }
1893 return Status;
1894}
1895
1896static int vboxNetLwfWinStartInitIdcThread()
1897{
1898 int rc = VERR_INVALID_STATE;
1899
1900 if (ASMAtomicCmpXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Connecting, LwfIdcState_Disconnected))
1901 {
1902 Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
1903
1904 NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetLwfGlobals.hInitIdcThread,
1905 THREAD_ALL_ACCESS,
1906 NULL,
1907 NULL,
1908 NULL,
1909 vboxNetLwfWinInitIdcWorker,
1910 &g_VBoxNetLwfGlobals);
1911 Log(("vboxNetLwfWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
1912 if (Status != STATUS_SUCCESS)
1913 {
1914 LogError(("vboxNetLwfWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
1915 /*
1916 * We failed to init IDC and there will be no second chance.
1917 */
1918 Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
1919 ASMAtomicWriteU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Disconnected);
1920 }
1921 rc = RTErrConvertFromNtStatus(Status);
1922 }
1923 return rc;
1924}
1925
1926static void vboxNetLwfWinStopInitIdcThread()
1927{
1928}
1929
1930
1931RT_C_DECLS_BEGIN
1932
1933NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
1934
1935RT_C_DECLS_END
1936
1937NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
1938{
1939 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1940 int rc;
1941
1942 /* the idc registration is initiated via IOCTL since our driver
1943 * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
1944 rc = vboxNetLwfWinInitBase();
1945 AssertRC(rc);
1946 if (RT_SUCCESS(rc))
1947 {
1948 NdisZeroMemory(&g_VBoxNetLwfGlobals, sizeof (g_VBoxNetLwfGlobals));
1949 RTListInit(&g_VBoxNetLwfGlobals.listModules);
1950 NdisAllocateSpinLock(&g_VBoxNetLwfGlobals.Lock);
1951 /*
1952 * We choose to ignore IDC initialization errors here because if we fail to load
1953 * our filter the upper protocols won't bind to the associated adapter, causing
1954 * network failure at the host. Better to have non-working filter than broken
1955 * networking on the host.
1956 */
1957 rc = vboxNetLwfWinStartInitIdcThread();
1958 AssertRC(rc);
1959
1960 Status = vboxNetLwfWinRegister(pDriverObject, pRegistryPath);
1961 Assert(Status == STATUS_SUCCESS);
1962 if (Status == NDIS_STATUS_SUCCESS)
1963 {
1964 Log(("NETLWF: started successfully\n"));
1965 return STATUS_SUCCESS;
1966 }
1967 NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
1968 vboxNetLwfWinFini();
1969 }
1970 else
1971 {
1972 Status = NDIS_STATUS_FAILURE;
1973 }
1974
1975 return Status;
1976}
1977
1978
1979static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver)
1980{
1981 LogFlow(("==>vboxNetLwfWinUnloadDriver: driver=%p\n", pDriver));
1982 vboxNetLwfWinDevDestroy(&g_VBoxNetLwfGlobals);
1983 NdisFDeregisterFilterDriver(g_VBoxNetLwfGlobals.hFilterDriver);
1984 NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
1985 LogFlow(("<==vboxNetLwfWinUnloadDriver\n"));
1986 vboxNetLwfWinFini();
1987}
1988
1989static const char *vboxNetLwfWinIdcStateToText(uint32_t enmState)
1990{
1991 switch (enmState)
1992 {
1993 case LwfIdcState_Disconnected: return "Disconnected";
1994 case LwfIdcState_Connecting: return "Connecting";
1995 case LwfIdcState_Connected: return "Connected";
1996 case LwfIdcState_Stopping: return "Stopping";
1997 }
1998 return "Unknown";
1999}
2000
2001static VOID vboxNetLwfWinInitIdcWorker(PVOID pvContext)
2002{
2003 int rc;
2004 PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)pvContext;
2005
2006 while (ASMAtomicReadU32(&pGlobals->enmIdcState) == LwfIdcState_Connecting)
2007 {
2008 rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
2009 if (RT_SUCCESS(rc))
2010 {
2011 if (!ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, LwfIdcState_Connected, LwfIdcState_Connecting))
2012 {
2013 /* The state has been changed (the only valid transition is to "Stopping"), undo init */
2014 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2015 Log(("vboxNetLwfWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, deleted IDC, rc=0x%x\n",
2016 vboxNetLwfWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
2017 }
2018 else
2019 {
2020 Log(("vboxNetLwfWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
2021 }
2022 }
2023 else
2024 {
2025 LARGE_INTEGER WaitIn100nsUnits;
2026 WaitIn100nsUnits.QuadPart = -(LONGLONG)10000000; /* 1 sec */
2027 KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
2028 }
2029 }
2030 PsTerminateSystemThread(STATUS_SUCCESS);
2031}
2032
2033static int vboxNetLwfWinTryFiniIdc()
2034{
2035 int rc = VINF_SUCCESS;
2036 NTSTATUS Status;
2037 PKTHREAD pThread = NULL;
2038 uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Stopping);
2039
2040 Log(("vboxNetLwfWinTryFiniIdc: IDC state change %s -> Stopping\n", vboxNetLwfWinIdcStateToText(enmPrevState)));
2041
2042 switch (enmPrevState)
2043 {
2044 case LwfIdcState_Disconnected:
2045 /* Have not even attempted to connect -- nothing to do. */
2046 break;
2047 case LwfIdcState_Stopping:
2048 /* Impossible, but another thread is alreading doing FiniIdc, bail out */
2049 LogError(("vboxNetLwfWinTryFiniIdc: called in 'Stopping' state\n"));
2050 rc = VERR_INVALID_STATE;
2051 break;
2052 case LwfIdcState_Connecting:
2053 /* the worker thread is running, let's wait for it to stop */
2054 Status = ObReferenceObjectByHandle(g_VBoxNetLwfGlobals.hInitIdcThread,
2055 THREAD_ALL_ACCESS, NULL, KernelMode,
2056 (PVOID*)&pThread, NULL);
2057 if (Status == STATUS_SUCCESS)
2058 {
2059 KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
2060 ObDereferenceObject(pThread);
2061 }
2062 else
2063 {
2064 LogError(("vboxNetLwfWinTryFiniIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
2065 g_VBoxNetLwfGlobals.hInitIdcThread, Status));
2066 }
2067 rc = RTErrConvertFromNtStatus(Status);
2068 break;
2069 case LwfIdcState_Connected:
2070 /* the worker succeeded in IDC init and terminated */
2071 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2072 Log(("vboxNetLwfWinTryFiniIdc: deleted IDC, rc=0x%x\n", rc));
2073 break;
2074 }
2075 return rc;
2076}
2077
2078static void vboxNetLwfWinFiniBase()
2079{
2080 vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
2081
2082 /*
2083 * Undo the work done during start (in reverse order).
2084 */
2085 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2086
2087 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
2088 RTLogDestroy(RTLogSetDefaultInstance(NULL));
2089
2090 RTR0Term();
2091}
2092
2093static int vboxNetLwfWinInitBase()
2094{
2095 int rc = RTR0Init(0);
2096 if (!RT_SUCCESS(rc))
2097 return rc;
2098
2099 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2100 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
2101 if (!RT_SUCCESS(rc))
2102 RTR0Term();
2103
2104 return rc;
2105}
2106
2107static int vboxNetLwfWinFini()
2108{
2109 int rc = vboxNetLwfWinTryFiniIdc();
2110 if (RT_SUCCESS(rc))
2111 {
2112 vboxNetLwfWinFiniBase();
2113 }
2114 return rc;
2115}
2116
2117
2118/*
2119 *
2120 * The OS specific interface definition
2121 *
2122 */
2123
2124
2125bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
2126{
2127 LogFlow(("==>vboxNetFltOsMaybeRediscovered: instance=%p\n", pThis));
2128 LogFlow(("<==vboxNetFltOsMaybeRediscovered: return %RTbool\n", !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)));
2129 /* AttachToInterface true if disconnected */
2130 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
2131}
2132
2133int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
2134{
2135 int rc = VINF_SUCCESS;
2136
2137 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
2138 LogFlow(("==>vboxNetFltPortOsXmit: instance=%p module=%p\n", pThis, pModule));
2139 if (!pModule)
2140 {
2141 LogFlow(("<==vboxNetFltPortOsXmit: pModule is null, return %d\n", VERR_INTERNAL_ERROR));
2142 return VERR_INTERNAL_ERROR;
2143 }
2144 /* Prevent going into "paused" state until all transmissions have been completed. */
2145 NDIS_WAIT_FOR_MUTEX(&pModule->InTransmit);
2146 /* Ignore all sends if the stack is paused or being paused, etc... */
2147 if (!vboxNetLwfWinIsRunning(pModule))
2148 {
2149 NDIS_RELEASE_MUTEX(&pModule->InTransmit);
2150 return VINF_SUCCESS;
2151 }
2152
2153 const char *pszDir = (fDst & INTNETTRUNKDIR_WIRE) ?
2154 ( (fDst & INTNETTRUNKDIR_HOST) ? "intnet --> all" : "intnet --> wire" ) : "intnet --> host";
2155 vboxNetLwfWinDumpPacket(pSG, pszDir);
2156 /*
2157 * There are two possible strategies to deal with incoming SGs:
2158 * 1) make a copy of data and complete asynchronously;
2159 * 2) complete synchronously using the original data buffers.
2160 * Before we consider implementing (1) it is quite interesting to see
2161 * how well (2) performs. So we block until our requests are complete.
2162 * Actually there is third possibility -- to use SG retain/release
2163 * callbacks, but those seem not be fully implemented yet.
2164 * Note that ansynchronous completion will require different implementation
2165 * of vboxNetLwfWinPause(), not relying on InTransmit mutex.
2166 */
2167#ifdef VBOXNETLWF_SYNC_SEND
2168 PVOID aEvents[2]; /* To wire and to host */
2169 ULONG nEvents = 0;
2170 LARGE_INTEGER timeout;
2171 timeout.QuadPart = -(LONGLONG)10000000; /* 1 sec */
2172#endif /* VBOXNETLWF_SYNC_SEND */
2173 if (fDst & INTNETTRUNKDIR_WIRE)
2174 {
2175 PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
2176 if (pBufList)
2177 {
2178#ifdef VBOXNETLWF_SYNC_SEND
2179 aEvents[nEvents++] = &pModule->EventWire;
2180#else /* !VBOXNETLWF_SYNC_SEND */
2181 if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
2182 NdisResetEvent(&pModule->EventSendComplete);
2183#endif /* !VBOXNETLWF_SYNC_SEND */
2184 NdisFSendNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 0); /** @todo sendFlags! */
2185 }
2186 }
2187 if (fDst & INTNETTRUNKDIR_HOST)
2188 {
2189 PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
2190 if (pBufList)
2191 {
2192#ifdef VBOXNETLWF_SYNC_SEND
2193 aEvents[nEvents++] = &pModule->EventHost;
2194#else /* !VBOXNETLWF_SYNC_SEND */
2195 if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
2196 NdisResetEvent(&pModule->EventSendComplete);
2197#endif /* !VBOXNETLWF_SYNC_SEND */
2198 NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
2199 }
2200 }
2201#ifdef VBOXNETLWF_SYNC_SEND
2202 if (nEvents)
2203 {
2204 NTSTATUS Status = KeWaitForMultipleObjects(nEvents, aEvents, WaitAll, Executive, KernelMode, FALSE, &timeout, NULL);
2205 if (Status != STATUS_SUCCESS)
2206 {
2207 LogError(("vboxNetFltPortOsXmit: KeWaitForMultipleObjects() failed with 0x%x\n", Status));
2208 if (Status == STATUS_TIMEOUT)
2209 rc = VERR_TIMEOUT;
2210 else
2211 rc = RTErrConvertFromNtStatus(Status);
2212 }
2213 }
2214#endif /* VBOXNETLWF_SYNC_SEND */
2215 NDIS_RELEASE_MUTEX(&pModule->InTransmit);
2216
2217 LogFlow(("<==vboxNetFltPortOsXmit: return %d\n", rc));
2218 return rc;
2219}
2220
2221
2222NDIS_IO_WORKITEM_FUNCTION vboxNetLwfWinToggleOffloading;
2223
2224VOID vboxNetLwfWinToggleOffloading(PVOID WorkItemContext, NDIS_HANDLE NdisIoWorkItemHandle)
2225{
2226 /* WARNING! Call this with IRQL=Passive! */
2227 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)WorkItemContext;
2228
2229 if (ASMAtomicReadBool(&pModuleCtx->fActive))
2230 {
2231 /* Disable offloading temporarily by indicating offload config change. */
2232 /** @todo Be sure to revise this when implementing offloading support! */
2233 NDIS_OFFLOAD OffloadConfig;
2234 if (pModuleCtx->fOffloadConfigValid)
2235 {
2236 OffloadConfig = pModuleCtx->SavedOffloadConfig;
2237 vboxNetLwfWinDisableOffloading(&OffloadConfig);
2238 }
2239 else
2240 {
2241 DbgPrint("VBoxNetLwf: no saved offload config to modify for %s\n", pModuleCtx->szMiniportName);
2242 NdisZeroMemory(&OffloadConfig, sizeof(OffloadConfig));
2243 OffloadConfig.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
2244 OffloadConfig.Header.Revision = NDIS_OFFLOAD_REVISION_1;
2245 OffloadConfig.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
2246 }
2247 vboxNetLwfWinIndicateOffload(pModuleCtx, &OffloadConfig);
2248 Log(("vboxNetLwfWinToggleOffloading: set offloading off\n"));
2249 }
2250 else
2251 {
2252 /* The filter is inactive -- restore offloading configuration. */
2253 if (pModuleCtx->fOffloadConfigValid)
2254 {
2255 vboxNetLwfWinIndicateOffload(pModuleCtx, &pModuleCtx->SavedOffloadConfig);
2256 Log(("vboxNetLwfWinToggleOffloading: restored offloading config\n"));
2257 }
2258 else
2259 DbgPrint("VBoxNetLwf: no saved offload config to restore for %s\n", pModuleCtx->szMiniportName);
2260 }
2261}
2262
2263
2264void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
2265{
2266 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
2267 LogFlow(("==>vboxNetFltPortOsSetActive: instance=%p module=%p fActive=%RTbool\n", pThis, pModuleCtx, fActive));
2268 if (!pModuleCtx)
2269 {
2270 LogFlow(("<==vboxNetFltPortOsSetActive: pModuleCtx is null\n"));
2271 return;
2272 }
2273
2274 NDIS_STATUS Status = STATUS_SUCCESS;
2275 bool fOldActive = ASMAtomicXchgBool(&pModuleCtx->fActive, fActive);
2276 if (fOldActive != fActive)
2277 {
2278 NdisQueueIoWorkItem(pModuleCtx->hWorkItem, vboxNetLwfWinToggleOffloading, pModuleCtx);
2279 Status = vboxNetLwfWinSetPacketFilter(pModuleCtx, fActive);
2280 LogFlow(("<==vboxNetFltPortOsSetActive: vboxNetLwfWinSetPacketFilter() returned 0x%x\n", Status));
2281 }
2282 else
2283 LogFlow(("<==vboxNetFltPortOsSetActive: no change, remain %sactive\n", fActive ? "":"in"));
2284}
2285
2286int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
2287{
2288 LogFlow(("==>vboxNetFltOsDisconnectIt: instance=%p\n", pThis));
2289 LogFlow(("<==vboxNetFltOsDisconnectIt: return 0\n"));
2290 return VINF_SUCCESS;
2291}
2292
2293int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
2294{
2295 LogFlow(("==>vboxNetFltOsConnectIt: instance=%p\n", pThis));
2296 LogFlow(("<==vboxNetFltOsConnectIt: return 0\n"));
2297 return VINF_SUCCESS;
2298}
2299
2300/*
2301 * Uncommenting the following line produces debug log messages on IP address changes,
2302 * including wired interfaces. No actual calls to a switch port are made. This is for
2303 * debug purposes only!
2304 * #define VBOXNETLWFWIN_DEBUGIPADDRNOTIF 1
2305 */
2306static void vboxNetLwfWinIpAddrChangeCallback(IN PVOID pvCtx,
2307 IN PMIB_UNICASTIPADDRESS_ROW pRow,
2308 IN MIB_NOTIFICATION_TYPE enmNotifType)
2309{
2310 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvCtx;
2311 PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
2312
2313 /* We are only interested in add or remove notifications. */
2314 bool fAdded;
2315 if (enmNotifType == MibAddInstance)
2316 fAdded = true;
2317 else if (enmNotifType == MibDeleteInstance)
2318 fAdded = false;
2319 else
2320 return;
2321
2322 if ( pRow
2323#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
2324 && pThis->pSwitchPort->pfnNotifyHostAddress
2325#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
2326 )
2327 {
2328 switch (pRow->Address.si_family)
2329 {
2330 case AF_INET:
2331 if ( IN4_IS_ADDR_LINKLOCAL(&pRow->Address.Ipv4.sin_addr)
2332 || pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK)
2333 {
2334 Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring %s address (%RTnaipv4)\n",
2335 pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK ? "loopback" : "link-local",
2336 pRow->Address.Ipv4.sin_addr));
2337 break;
2338 }
2339 Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv4 addr=%RTnaipv4 on luid=(%u,%u)\n",
2340 fAdded ? "add" : "remove", pRow->Address.Ipv4.sin_addr,
2341 pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
2342#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
2343 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv4,
2344 &pRow->Address.Ipv4.sin_addr);
2345#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
2346 break;
2347 case AF_INET6:
2348 if (Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte) <= ScopeLevelLink)
2349 {
2350 Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring link-local address (%RTnaipv6)\n",
2351 &pRow->Address.Ipv6.sin6_addr));
2352 break;
2353 }
2354 Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv6 addr=%RTnaipv6 scope=%d luid=(%u,%u)\n",
2355 fAdded ? "add" : "remove", &pRow->Address.Ipv6.sin6_addr,
2356 Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte),
2357 pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
2358#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
2359 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv6,
2360 &pRow->Address.Ipv6.sin6_addr);
2361#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
2362 break;
2363 }
2364 }
2365 else
2366 Log(("vboxNetLwfWinIpAddrChangeCallback: pRow=%p pfnNotifyHostAddress=%p\n",
2367 pRow, pThis->pSwitchPort->pfnNotifyHostAddress));
2368}
2369
2370void vboxNetLwfWinRegisterIpAddrNotifier(PVBOXNETFLTINS pThis)
2371{
2372 LogFlow(("==>vboxNetLwfWinRegisterIpAddrNotifier: instance=%p\n", pThis));
2373 if ( pThis->pSwitchPort
2374#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
2375 && pThis->pSwitchPort->pfnNotifyHostAddress
2376#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
2377 )
2378 {
2379 NETIO_STATUS Status;
2380 /* First we need to go over all host IP addresses and add them via pfnNotifyHostAddress. */
2381 PMIB_UNICASTIPADDRESS_TABLE HostIpAddresses = NULL;
2382 Status = GetUnicastIpAddressTable(AF_UNSPEC, &HostIpAddresses);
2383 if (NETIO_SUCCESS(Status))
2384 {
2385 for (unsigned i = 0; i < HostIpAddresses->NumEntries; i++)
2386 vboxNetLwfWinIpAddrChangeCallback(pThis, &HostIpAddresses->Table[i], MibAddInstance);
2387 }
2388 else
2389 LogError(("vboxNetLwfWinRegisterIpAddrNotifier: GetUnicastIpAddressTable failed with %x\n", Status));
2390 /* Now we can register a callback function to keep track of address changes. */
2391 Status = NotifyUnicastIpAddressChange(AF_UNSPEC, vboxNetLwfWinIpAddrChangeCallback,
2392 pThis, false, &pThis->u.s.WinIf.hNotifier);
2393 if (NETIO_SUCCESS(Status))
2394 Log(("vboxNetLwfWinRegisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
2395 else
2396 LogError(("vboxNetLwfWinRegisterIpAddrNotifier: NotifyUnicastIpAddressChange failed with %x\n", Status));
2397 }
2398 else
2399 pThis->u.s.WinIf.hNotifier = NULL;
2400 LogFlow(("<==vboxNetLwfWinRegisterIpAddrNotifier\n"));
2401}
2402
2403void vboxNetLwfWinUnregisterIpAddrNotifier(PVBOXNETFLTINS pThis)
2404{
2405 Log(("vboxNetLwfWinUnregisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
2406 if (pThis->u.s.WinIf.hNotifier)
2407 CancelMibChangeNotify2(pThis->u.s.WinIf.hNotifier);
2408}
2409
2410void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
2411{
2412 PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
2413 LogFlow(("==>vboxNetFltOsDeleteInstance: instance=%p module=%p\n", pThis, pModuleCtx));
2414 /* Cancel IP address change notifications */
2415 vboxNetLwfWinUnregisterIpAddrNotifier(pThis);
2416 /* Technically it is possible that the module has already been gone by now. */
2417 if (pModuleCtx)
2418 {
2419 Assert(!pModuleCtx->fActive); /* Deactivation ensures bypass mode */
2420 pModuleCtx->pNetFlt = NULL;
2421 pThis->u.s.WinIf.hModuleCtx = NULL;
2422 }
2423 LogFlow(("<==vboxNetFltOsDeleteInstance\n"));
2424}
2425
2426static void vboxNetLwfWinReportCapabilities(PVBOXNETFLTINS pThis, PVBOXNETLWF_MODULE pModuleCtx)
2427{
2428 if (pThis->pSwitchPort
2429 && vboxNetFltTryRetainBusyNotDisconnected(pThis))
2430 {
2431 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pModuleCtx->MacAddr);
2432 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
2433 vboxNetLwfWinIsPromiscuous(pModuleCtx));
2434 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
2435 INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
2436 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
2437 vboxNetFltRelease(pThis, true /*fBusy*/);
2438 }
2439}
2440
2441int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
2442{
2443 LogFlow(("==>vboxNetFltOsInitInstance: instance=%p context=%p\n", pThis, pvContext));
2444 AssertReturn(pThis, VERR_INVALID_PARAMETER);
2445 Log(("vboxNetFltOsInitInstance: trunk name=%s\n", pThis->szName));
2446 PVBOXNETLWF_MODULE pModuleCtx = NULL;
2447 NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
2448 RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
2449 {
2450 DbgPrint("vboxNetFltOsInitInstance: evaluating module, name=%s\n", pModuleCtx->szMiniportName);
2451 if (!RTStrICmp(pThis->szName, pModuleCtx->szMiniportName))
2452 {
2453 NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
2454 Log(("vboxNetFltOsInitInstance: found matching module, name=%s\n", pThis->szName));
2455 pThis->u.s.WinIf.hModuleCtx = pModuleCtx;
2456 pModuleCtx->pNetFlt = pThis;
2457 vboxNetLwfWinReportCapabilities(pThis, pModuleCtx);
2458 vboxNetLwfWinRegisterIpAddrNotifier(pThis);
2459 LogFlow(("<==vboxNetFltOsInitInstance: return 0\n"));
2460 return VINF_SUCCESS;
2461 }
2462 }
2463 NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
2464 vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
2465 LogFlow(("<==vboxNetFltOsInitInstance: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
2466 return VERR_INTNET_FLT_IF_NOT_FOUND;
2467}
2468
2469int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
2470{
2471 LogFlow(("==>vboxNetFltOsPreInitInstance: instance=%p\n", pThis));
2472 pThis->u.s.WinIf.hModuleCtx = 0;
2473 pThis->u.s.WinIf.hNotifier = NULL;
2474 LogFlow(("<==vboxNetFltOsPreInitInstance: return 0\n"));
2475 return VINF_SUCCESS;
2476}
2477
2478void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
2479{
2480 LogFlow(("==>vboxNetFltPortOsNotifyMacAddress: instance=%p data=%p mac=%RTmac\n", pThis, pvIfData, pMac));
2481 LogFlow(("<==vboxNetFltPortOsNotifyMacAddress\n"));
2482}
2483
2484int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
2485{
2486 LogFlow(("==>vboxNetFltPortOsConnectInterface: instance=%p if=%p data=%p\n", pThis, pvIf, ppvIfData));
2487 LogFlow(("<==vboxNetFltPortOsConnectInterface: return 0\n"));
2488 /* Nothing to do */
2489 return VINF_SUCCESS;
2490}
2491
2492int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
2493{
2494 LogFlow(("==>vboxNetFltPortOsDisconnectInterface: instance=%p data=%p\n", pThis, pvIfData));
2495 LogFlow(("<==vboxNetFltPortOsDisconnectInterface: return 0\n"));
2496 /* Nothing to do */
2497 return VINF_SUCCESS;
2498}
2499
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette