VirtualBox

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

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

NetLwf/Win(bugref:8283): dynamic allocation of MDLs which fixes jumbo frame issue

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