VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/ndis6/VBoxNetLwf-win.cpp@ 53409

Last change on this file since 53409 was 52630, checked in by vboxsync, 11 years ago

fix svn properties

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette