VirtualBox

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

Last change on this file since 62490 was 62490, checked in by vboxsync, 8 years ago

(C) 2016

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