VirtualBox

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

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

HostDrivers: scm updates

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