VirtualBox

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

Last change on this file since 68500 was 68500, checked in by vboxsync, 7 years ago

NetLwf/Win: (bugref:8976) Align outgoing packets at word boundary.

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