VirtualBox

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

Last change on this file since 56293 was 56293, checked in by vboxsync, 10 years ago

HostDrivers: Updated (C) year.

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