VirtualBox

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

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

NetLwf/Win(bugref:8283): test build with 2K frame limit and dynamic re-allocation of frame pool

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