VirtualBox

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

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

NDIS6/NetLwf: re-worked promiscuous mode handling (#7231)

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