VirtualBox

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

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

NetLwf/Win: (bugref:7933) Fixed module structure corruption that was causing VERR_INTNET_FLT_IF_NOT_FOUND. Offload config buffers are allocated dynamically now.

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