VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.0 KB
Line 
1/* $Id: VBoxNetAdp-win.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxNetAdp-win.cpp - NDIS6 Host-only Networking Driver, Windows-specific code.
4 */
5/*
6 * Copyright (C) 2014-2022 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
27
28#include <VBox/log.h>
29#include <VBox/version.h>
30#include <VBox/err.h>
31#include <VBox/sup.h>
32#include <VBox/intnet.h>
33#include <VBox/intnetinline.h>
34#include <iprt/assert.h>
35#include <iprt/initterm.h>
36#include <iprt/list.h>
37#include <iprt/net.h>
38#include <iprt/semaphore.h>
39#include <iprt/string.h>
40#include <iprt/uuid.h>
41
42#include <iprt/nt/ntddk.h>
43#include <iprt/nt/ndis.h>
44
45#include "VBoxNetAdp-win.h"
46#include "VBox/VBoxNetCmn-win.h"
47
48#define VBOXNETADP_MEM_TAG 'OHBV'
49
50/*
51 * By default the link speed reported to be 1Gbps. We may wish to lower
52 * it to 100Mbps to work around issues with multi-cast traffic on the host.
53 * See @bugref{6379}.
54 */
55#define VBOXNETADPWIN_LINK_SPEED 1000000000ULL
56
57#define LogError LogRel
58
59/* Forward declarations */
60MINIPORT_INITIALIZE vboxNetAdpWinInitializeEx;
61MINIPORT_HALT vboxNetAdpWinHaltEx;
62MINIPORT_UNLOAD vboxNetAdpWinUnload;
63MINIPORT_PAUSE vboxNetAdpWinPause;
64MINIPORT_RESTART vboxNetAdpWinRestart;
65MINIPORT_OID_REQUEST vboxNetAdpWinOidRequest;
66MINIPORT_SEND_NET_BUFFER_LISTS vboxNetAdpWinSendNetBufferLists;
67MINIPORT_RETURN_NET_BUFFER_LISTS vboxNetAdpWinReturnNetBufferLists;
68MINIPORT_CANCEL_SEND vboxNetAdpWinCancelSend;
69MINIPORT_CHECK_FOR_HANG vboxNetAdpWinCheckForHangEx;
70MINIPORT_RESET vboxNetAdpWinResetEx;
71MINIPORT_DEVICE_PNP_EVENT_NOTIFY vboxNetAdpWinDevicePnPEventNotify;
72MINIPORT_SHUTDOWN vboxNetAdpWinShutdownEx;
73MINIPORT_CANCEL_OID_REQUEST vboxNetAdpWinCancelOidRequest;
74
75
76/* Packet types by destination address; used in statistics. */
77typedef enum {
78 kVBoxNetAdpWinPacketType_Unicast,
79 kVBoxNetAdpWinPacketType_Multicast,
80 kVBoxNetAdpWinPacketType_Broadcast,
81 kVBoxNetAdpWinPacketType_ArraySize /* Must be the last one */
82} VBOXNETADPWIN_PACKET_TYPE;
83
84
85/* Miniport states as defined by NDIS. */
86typedef enum {
87 kVBoxNetAdpWinState_Initializing,
88 kVBoxNetAdpWinState_Paused,
89 kVBoxNetAdpWinState_Restarting,
90 kVBoxNetAdpWinState_Running,
91 kVBoxNetAdpWinState_Pausing,
92 kVBoxNetAdpWinState_32BitHack = 0x7fffffff
93} VBOXNETADPWIN_ADAPTER_STATE;
94
95
96/*
97 * Valid state transitions are:
98 * 1) Disconnected -> Connecting : start the worker thread, attempting to init IDC;
99 * 2) Connecting -> Disconnected : failed to start IDC init worker thread;
100 * 3) Connecting -> Connected : IDC init successful, terminate the worker;
101 * 4) Connecting -> Stopping : IDC init incomplete, but the driver is being unloaded, terminate the worker;
102 * 5) Connected -> Stopping : IDC init was successful, no worker, the driver is being unloaded;
103 *
104 * Driver terminates in either in Disconnected or in Stopping state.
105 */
106typedef enum {
107 kVBoxNetAdpWinIdcState_Disconnected = 0, /* Initial state */
108 kVBoxNetAdpWinIdcState_Connecting, /* Attemping to init IDC, worker thread running */
109 kVBoxNetAdpWinIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
110 kVBoxNetAdpWinIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
111} VBOXNETADPWIN_IDC_STATE;
112
113typedef struct _VBOXNETADPGLOBALS
114{
115 /** Miniport driver handle. */
116 NDIS_HANDLE hMiniportDriver;
117 /** Power management capabilities, shared by all instances, do not change after init. */
118 NDIS_PNP_CAPABILITIES PMCaps;
119 /** The INTNET trunk network interface factory. */
120 INTNETTRUNKFACTORY TrunkFactory;
121 /** The SUPDRV component factory registration. */
122 SUPDRVFACTORY SupDrvFactory;
123 /** The SUPDRV IDC handle (opaque struct). */
124 SUPDRVIDCHANDLE SupDrvIDC;
125 /** IDC init thread handle. */
126 HANDLE hInitIdcThread;
127 /** Lock protecting the following members. */
128 NDIS_SPIN_LOCK Lock;
129 /** Lock-protected: the head of module list. */
130 RTLISTANCHOR ListOfAdapters;
131 /** Lock-protected: The number of current factory references. */
132 int32_t volatile cFactoryRefs;
133 /** Lock-protected: IDC initialization state. */
134 volatile uint32_t enmIdcState;
135 /** Lock-protected: event signaled when trunk factory is not in use. */
136 NDIS_EVENT EventUnloadAllowed;
137} VBOXNETADPGLOBALS, *PVBOXNETADPGLOBALS;
138
139/* win-specific global data */
140VBOXNETADPGLOBALS g_VBoxNetAdpGlobals;
141
142
143typedef struct _VBOXNETADP_ADAPTER {
144 /** Auxiliary member to link adapters into a list. */
145 RTLISTNODE node;
146 /** Adapter handle for NDIS. */
147 NDIS_HANDLE hAdapter;
148 /** Memory pool network buffers are allocated from. */
149 NDIS_HANDLE hPool;
150 /** Our RJ-45 port.
151 * This is what the internal network plugs into. */
152 INTNETTRUNKIFPORT MyPort;
153 /** The RJ-45 port on the INTNET "switch".
154 * This is what we're connected to. */
155 PINTNETTRUNKSWPORT pSwitchPort;
156 /** Pointer to global data */
157 PVBOXNETADPGLOBALS pGlobals;
158 /** Adapter state in NDIS, used for assertions only */
159 VBOXNETADPWIN_ADAPTER_STATE volatile enmAdapterState; /// @todo do we need it really?
160 /** The trunk state. */
161 INTNETTRUNKIFSTATE volatile enmTrunkState;
162 /** Number of pending operations, when it reaches zero we signal EventIdle. */
163 int32_t volatile cBusy;
164 /** The event that is signaled when we go idle and that pfnWaitForIdle blocks on. */
165 NDIS_EVENT EventIdle;
166 /** MAC address of adapter. */
167 RTMAC MacAddr;
168 /** Statistics: bytes received from internal network. */
169 uint64_t au64StatsInOctets[kVBoxNetAdpWinPacketType_ArraySize];
170 /** Statistics: packets received from internal network. */
171 uint64_t au64StatsInPackets[kVBoxNetAdpWinPacketType_ArraySize];
172 /** Statistics: bytes sent to internal network. */
173 uint64_t au64StatsOutOctets[kVBoxNetAdpWinPacketType_ArraySize];
174 /** Statistics: packets sent to internal network. */
175 uint64_t au64StatsOutPackets[kVBoxNetAdpWinPacketType_ArraySize];
176 /** Adapter friendly name. */
177 char szName[1];
178} VBOXNETADP_ADAPTER;
179typedef VBOXNETADP_ADAPTER *PVBOXNETADP_ADAPTER;
180
181
182/* Port */
183
184#define IFPORT_2_VBOXNETADP_ADAPTER(pIfPort) \
185 ( (PVBOXNETADP_ADAPTER)((uint8_t *)(pIfPort) - RT_UOFFSETOF(VBOXNETADP_ADAPTER, MyPort)) )
186
187DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinGetState(PVBOXNETADP_ADAPTER pThis)
188{
189 return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmAdapterState);
190}
191
192DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState)
193{
194 return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState);
195}
196
197DECLINLINE(bool) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState,
198 VBOXNETADPWIN_ADAPTER_STATE enmOldState)
199{
200 return ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState, enmOldState);
201}
202
203#ifdef DEBUG
204
205DECLHIDDEN(void) vboxNetAdpWinDumpPackets(const char *pszMsg, PNET_BUFFER_LIST pBufLists)
206{
207 for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
208 {
209 for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
210 {
211 Log6(("%s packet: cb=%d offset=%d", pszMsg, NET_BUFFER_DATA_LENGTH(pBuf), NET_BUFFER_DATA_OFFSET(pBuf)));
212 for (PMDL pMdl = NET_BUFFER_FIRST_MDL(pBuf);
213 pMdl != NULL;
214 pMdl = NDIS_MDL_LINKAGE(pMdl))
215 {
216 Log6((" MDL: cb=%d", MmGetMdlByteCount(pMdl)));
217 }
218 Log6(("\n"));
219 }
220 }
221}
222
223DECLINLINE(const char *) vboxNetAdpWinEthTypeStr(uint16_t uType)
224{
225 switch (uType)
226 {
227 case RTNET_ETHERTYPE_IPV4: return "IP";
228 case RTNET_ETHERTYPE_IPV6: return "IPv6";
229 case RTNET_ETHERTYPE_ARP: return "ARP";
230 }
231 return "unknown";
232}
233
234#define VBOXNETADP_PKTDMPSIZE 0x50
235
236/**
237 * Dump a packet to debug log.
238 *
239 * @param cpPacket The packet.
240 * @param cb The size of the packet.
241 * @param cszText A string denoting direction of packet transfer.
242 */
243DECLINLINE(void) vboxNetAdpWinDumpPacket(PCINTNETSG pSG, const char *cszText)
244{
245 uint8_t bPacket[VBOXNETADP_PKTDMPSIZE];
246
247 uint32_t cb = pSG->cbTotal < VBOXNETADP_PKTDMPSIZE ? pSG->cbTotal : VBOXNETADP_PKTDMPSIZE;
248 IntNetSgReadEx(pSG, 0, cb, bPacket);
249
250 AssertReturnVoid(cb >= 14);
251
252 uint8_t *pHdr = bPacket;
253 uint8_t *pEnd = bPacket + cb;
254 AssertReturnVoid(pEnd - pHdr >= 14);
255 uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12));
256 Log2(("NetADP: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
257 cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetAdpWinEthTypeStr(uEthType), uEthType));
258 pHdr += sizeof(RTNETETHERHDR);
259 if (uEthType == RTNET_ETHERTYPE_VLAN)
260 {
261 AssertReturnVoid(pEnd - pHdr >= 4);
262 uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2));
263 Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF,
264 vboxNetAdpWinEthTypeStr(uEthType), uEthType));
265 pHdr += 2 * sizeof(uint16_t);
266 }
267 uint8_t uProto = 0xFF;
268 switch (uEthType)
269 {
270 case RTNET_ETHERTYPE_IPV6:
271 AssertReturnVoid(pEnd - pHdr >= 40);
272 uProto = pHdr[6];
273 Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24));
274 pHdr += 40;
275 break;
276 case RTNET_ETHERTYPE_IPV4:
277 AssertReturnVoid(pEnd - pHdr >= 20);
278 uProto = pHdr[9];
279 Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16)));
280 pHdr += (pHdr[0] & 0xF) * 4;
281 break;
282 case RTNET_ETHERTYPE_ARP:
283 AssertReturnVoid(pEnd - pHdr >= 28);
284 AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4);
285 switch (RT_N2H_U16(*(uint16_t*)(pHdr+6)))
286 {
287 case 1: /* ARP request */
288 Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n",
289 *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14)));
290 break;
291 case 2: /* ARP reply */
292 Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n",
293 *(uint32_t*)(pHdr+14), pHdr+8));
294 break;
295 default:
296 Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6))));
297 break;
298 }
299 break;
300 /* There is no default case as uProto is initialized with 0xFF */
301 }
302 while (uProto != 0xFF)
303 {
304 switch (uProto)
305 {
306 case 0: /* IPv6 Hop-by-Hop option*/
307 case 60: /* IPv6 Destination option*/
308 case 43: /* IPv6 Routing option */
309 case 44: /* IPv6 Fragment option */
310 Log2((" + IPv6 option (%d): <not implemented>\n", uProto));
311 uProto = pHdr[0];
312 pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */
313 break;
314 case 51: /* IPv6 IPsec AH */
315 Log2((" + IPv6 IPsec AH: <not implemented>\n"));
316 uProto = pHdr[0];
317 pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */
318 break;
319 case 50: /* IPv6 IPsec ESP */
320 /* Cannot decode IPsec, fall through */
321 Log2((" + IPv6 IPsec ESP: <not implemented>\n"));
322 uProto = 0xFF;
323 break;
324 case 59: /* No Next Header */
325 Log2((" + IPv6 No Next Header\n"));
326 uProto = 0xFF;
327 break;
328 case 58: /* IPv6-ICMP */
329 switch (pHdr[0])
330 {
331 case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break;
332 case 128: Log2((" + IPv6-ICMP: echo request\n")); break;
333 case 129: Log2((" + IPv6-ICMP: echo reply\n")); break;
334 default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
335 }
336 uProto = 0xFF;
337 break;
338 case 1: /* ICMP */
339 switch (pHdr[0])
340 {
341 case 0: Log2((" + ICMP: echo reply\n")); break;
342 case 8: Log2((" + ICMP: echo request\n")); break;
343 case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break;
344 default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
345 }
346 uProto = 0xFF;
347 break;
348 case 6: /* TCP */
349 Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n",
350 RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)),
351 RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8))));
352 uProto = 0xFF;
353 break;
354 case 17: /* UDP */
355 Log2((" + UDP: src=%d dst=%d\n",
356 RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2))));
357 uProto = 0xFF;
358 break;
359 default:
360 Log2((" + Unknown: proto=0x%x\n", uProto));
361 uProto = 0xFF;
362 break;
363 }
364 }
365 Log3(("%.*Rhxd\n", cb, bPacket));
366}
367
368#else /* !DEBUG */
369//# define vboxNetAdpWinDumpFilterTypes(uFlags) do { } while (0)
370//# define vboxNetAdpWinDumpOffloadSettings(p) do { } while (0)
371//# define vboxNetAdpWinDumpSetOffloadSettings(p) do { } while (0)
372# define vboxNetAdpWinDumpPackets(m,l) do { } while (0)
373# define vboxNetAdpWinDumpPacket(p,t) do { } while (0)
374#endif /* !DEBUG */
375
376
377DECLHIDDEN(VBOXNETADPWIN_PACKET_TYPE) vboxNetAdpWinPacketType(PINTNETSG pSG)
378{
379 static const uint8_t g_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
380 AssertReturn(pSG->cbTotal >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
381 AssertReturn(pSG->cSegsUsed > 0, kVBoxNetAdpWinPacketType_Unicast);
382 AssertReturn(pSG->aSegs[0].cb >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
383 if (!memcmp(pSG->aSegs[0].pv, g_abBcastAddr, sizeof(g_abBcastAddr)))
384 return kVBoxNetAdpWinPacketType_Broadcast;
385 if ((*(uint8_t*)pSG->aSegs[0].pv) & 1)
386 return kVBoxNetAdpWinPacketType_Multicast;
387 return kVBoxNetAdpWinPacketType_Unicast;
388}
389
390DECLINLINE(void) vboxNetAdpWinUpdateStats(uint64_t *pPacketStats, uint64_t *pOctetStats, PINTNETSG pSG)
391{
392 VBOXNETADPWIN_PACKET_TYPE enmPktType = vboxNetAdpWinPacketType(pSG);
393 ASMAtomicIncU64(&pPacketStats[enmPktType]);
394 ASMAtomicAddU64(&pOctetStats[enmPktType], pSG->cbTotal);
395}
396
397DECLINLINE(void) vboxNetAdpWinFreeMdlChain(PMDL pMdl)
398{
399 PMDL pMdlNext;
400 while (pMdl)
401 {
402 pMdlNext = pMdl->Next;
403 PUCHAR pDataBuf;
404 ULONG cb = 0;
405 NdisQueryMdl(pMdl, &pDataBuf, &cb, NormalPagePriority);
406 NdisFreeMdl(pMdl);
407 Log4(("vboxNetAdpWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
408 NdisFreeMemory(pDataBuf, 0, 0);
409 Log4(("vboxNetAdpWinFreeMdlChain: freed data buffer 0x%p\n", pDataBuf));
410 pMdl = pMdlNext;
411 }
412}
413
414DECLHIDDEN(PNET_BUFFER_LIST) vboxNetAdpWinSGtoNB(PVBOXNETADP_ADAPTER pThis, PINTNETSG pSG)
415{
416 AssertReturn(pSG->cSegsUsed >= 1, NULL);
417 LogFlow(("==>vboxNetAdpWinSGtoNB: segments=%d hPool=%p cb=%u\n", pSG->cSegsUsed,
418 pThis->hPool, pSG->cbTotal));
419 AssertReturn(pThis->hPool, NULL);
420
421
422 PNET_BUFFER_LIST pBufList = NULL;
423 ULONG cbMdl = pSG->cbTotal;
424 ULONG uDataOffset = cbMdl - pSG->cbTotal;
425 PUCHAR pDataBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pThis->hAdapter, cbMdl,
426 VBOXNETADP_MEM_TAG, NormalPoolPriority);
427 if (pDataBuf)
428 {
429 Log4(("vboxNetAdpWinSGtoNB: allocated data buffer (cb=%u) 0x%p\n", cbMdl, pDataBuf));
430 PMDL pMdl = NdisAllocateMdl(pThis->hAdapter, pDataBuf, cbMdl);
431 if (!pMdl)
432 {
433 NdisFreeMemory(pDataBuf, 0, 0);
434 Log4(("vboxNetAdpWinSGtoNB: freed data buffer 0x%p\n", pDataBuf));
435 LogError(("vboxNetAdpWinSGtoNB: failed to allocate an MDL (cb=%u)\n", cbMdl));
436 LogFlow(("<==vboxNetAdpWinSGtoNB: return NULL\n"));
437 return NULL;
438 }
439 PUCHAR pDst = pDataBuf + uDataOffset;
440 for (int i = 0; i < pSG->cSegsUsed; i++)
441 {
442 NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
443 pDst += pSG->aSegs[i].cb;
444 }
445 pBufList = NdisAllocateNetBufferAndNetBufferList(pThis->hPool,
446 0 /* ContextSize */,
447 0 /* ContextBackFill */,
448 pMdl,
449 uDataOffset,
450 pSG->cbTotal);
451 if (pBufList)
452 {
453 Log4(("vboxNetAdpWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
454 pBufList->SourceHandle = pThis->hAdapter;
455 /** @todo Do we need to initialize anything else? */
456 }
457 else
458 {
459 LogError(("vboxNetAdpWinSGtoNB: failed to allocate an NBL+NB\n"));
460 vboxNetAdpWinFreeMdlChain(pMdl);
461 }
462 }
463 else
464 {
465 LogError(("vboxNetAdpWinSGtoNB: failed to allocate data buffer (size=%u)\n", cbMdl));
466 }
467
468 LogFlow(("<==vboxNetAdpWinSGtoNB: return %p\n", pBufList));
469 return pBufList;
470}
471
472DECLINLINE(void) vboxNetAdpWinDestroySG(PINTNETSG pSG)
473{
474 NdisFreeMemory(pSG, 0, 0);
475 Log4(("vboxNetAdpWinDestroySG: freed SG 0x%p\n", pSG));
476}
477
478/**
479 * Worker for vboxNetAdpWinNBtoSG() that gets the max segment count needed.
480 * @note vboxNetAdpWinNBtoSG may use fewer depending on cbPacket and offset!
481 * @note vboxNetLwfWinCalcSegments() is a copy of this code.
482 */
483DECLINLINE(ULONG) vboxNetAdpWinCalcSegments(PNET_BUFFER pNetBuf)
484{
485 ULONG cSegs = 0;
486 for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf); pMdl; pMdl = NDIS_MDL_LINKAGE(pMdl))
487 {
488 /* Skip empty MDLs (see @bugref{9233}) */
489 if (MmGetMdlByteCount(pMdl))
490 cSegs++;
491 }
492 return cSegs;
493}
494
495/**
496 * @note vboxNetLwfWinNBtoSG() is a copy of this code.
497 */
498DECLHIDDEN(PINTNETSG) vboxNetAdpWinNBtoSG(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER pNetBuf)
499{
500 ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
501 ULONG cSegs = vboxNetAdpWinCalcSegments(pNetBuf);
502 /* Allocate and initialize SG */
503 PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pThis->hAdapter,
504 RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]),
505 VBOXNETADP_MEM_TAG,
506 NormalPoolPriority);
507 AssertReturn(pSG, pSG);
508 Log4(("vboxNetAdpWinNBtoSG: allocated SG 0x%p\n", pSG));
509 IntNetSgInitTempSegs(pSG, cbPacket /*cbTotal*/, cSegs, cSegs /*cSegsUsed*/);
510
511 ULONG uOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuf);
512 cSegs = 0;
513 for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf);
514 pMdl != NULL && cbPacket > 0;
515 pMdl = NDIS_MDL_LINKAGE(pMdl))
516 {
517 ULONG cbSrc = MmGetMdlByteCount(pMdl);
518 if (cbSrc == 0)
519 continue; /* Skip empty MDLs (see @bugref{9233}) */
520
521 PUCHAR pSrc = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPagePriority);
522 if (!pSrc)
523 {
524 vboxNetAdpWinDestroySG(pSG);
525 return NULL;
526 }
527
528 /* Handle the offset in the current (which is the first for us) MDL */
529 if (uOffset)
530 {
531 if (uOffset < cbSrc)
532 {
533 pSrc += uOffset;
534 cbSrc -= uOffset;
535 uOffset = 0;
536 }
537 else
538 {
539 /* This is an invalid MDL chain */
540 vboxNetAdpWinDestroySG(pSG);
541 return NULL;
542 }
543 }
544
545 /* Do not read the last MDL beyond packet's end */
546 if (cbSrc > cbPacket)
547 cbSrc = cbPacket;
548
549 Assert(cSegs < pSG->cSegsAlloc);
550 pSG->aSegs[cSegs].pv = pSrc;
551 pSG->aSegs[cSegs].cb = cbSrc;
552 pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
553 cSegs++;
554 cbPacket -= cbSrc;
555 }
556
557 Assert(cbPacket == 0);
558 Assert(cSegs <= pSG->cSegsUsed);
559
560 /* Update actual segment count in case we used fewer than anticipated. */
561 pSG->cSegsUsed = (uint16_t)cSegs;
562
563 return pSG;
564}
565
566DECLINLINE(bool) vboxNetAdpWinIsActive(PVBOXNETADP_ADAPTER pThis)
567{
568 if (vboxNetAdpWinGetState(pThis) != kVBoxNetAdpWinState_Running)
569 return false;
570 if (pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
571 return false;
572 AssertPtrReturn(pThis->pSwitchPort, false);
573 return true;
574}
575
576DECLHIDDEN(bool) vboxNetAdpWinForwardToIntNet(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER_LIST pList, uint32_t fSrc)
577{
578 if (!vboxNetAdpWinIsActive(pThis))
579 {
580 LogFlow(("vboxNetAdpWinForwardToIntNet: not active\n"));
581 return false;
582 }
583 AssertReturn(pThis->pSwitchPort, false);
584 AssertReturn(pThis->pSwitchPort->pfnRecv, false);
585 LogFlow(("==>vboxNetAdpWinForwardToIntNet\n"));
586
587 if (ASMAtomicIncS32(&pThis->cBusy) == 1)
588 NdisResetEvent(&pThis->EventIdle);
589 for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
590 {
591 PINTNETSG pSG = vboxNetAdpWinNBtoSG(pThis, pBuf);
592 if (pSG)
593 {
594 vboxNetAdpWinUpdateStats(pThis->au64StatsOutPackets, pThis->au64StatsOutOctets, pSG);
595 vboxNetAdpWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
596 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
597 vboxNetAdpWinDestroySG(pSG);
598 }
599 }
600 if (ASMAtomicDecS32(&pThis->cBusy) == 0)
601 NdisSetEvent(&pThis->EventIdle);
602
603 return true;
604}
605
606
607/**
608 * @copydoc INTNETTRUNKIFPORT::pfnRetain
609 */
610static DECLCALLBACK(void) vboxNetAdpWinPortRetain(PINTNETTRUNKIFPORT pIfPort)
611{
612 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
613 RT_NOREF1(pThis);
614 LogFlow(("vboxNetAdpWinPortRetain: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
615}
616
617/**
618 * @copydoc INTNETTRUNKIFPORT::pfnRelease
619 */
620static DECLCALLBACK(void) vboxNetAdpWinPortRelease(PINTNETTRUNKIFPORT pIfPort)
621{
622 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
623 RT_NOREF1(pThis);
624 LogFlow(("vboxNetAdpWinPortRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
625}
626
627/**
628 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
629 */
630static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
631{
632 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
633
634 LogFlow(("vboxNetAdpWinPortDisconnectAndRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
635 /*
636 * Serious paranoia.
637 */
638 AssertPtr(pThis);
639 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
640 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
641 AssertPtr(pThis->pGlobals);
642 Assert(pThis->szName[0]);
643
644 AssertPtr(pThis->pSwitchPort);
645 Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
646
647 pThis->pSwitchPort = NULL;
648}
649
650/**
651 * @copydoc INTNETTRUNKIFPORT::pfnSetState
652 */
653static DECLCALLBACK(INTNETTRUNKIFSTATE) vboxNetAdpWinPortSetState(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)
654{
655 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
656 INTNETTRUNKIFSTATE enmOldTrunkState;
657
658 LogFlow(("vboxNetAdpWinPortSetState: pThis=%p, pIfPort=%p, enmState=%d\n", pThis, pIfPort, enmState));
659 /*
660 * Input validation.
661 */
662 AssertPtr(pThis);
663 AssertPtr(pThis->pGlobals);
664 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
665 AssertPtrReturn(pThis->pSwitchPort, INTNETTRUNKIFSTATE_INVALID);
666 AssertReturn(enmState > INTNETTRUNKIFSTATE_INVALID && enmState < INTNETTRUNKIFSTATE_END,
667 INTNETTRUNKIFSTATE_INVALID);
668
669 enmOldTrunkState = pThis->enmTrunkState;
670 if (enmOldTrunkState != enmState)
671 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmTrunkState, enmState);
672
673 return enmOldTrunkState;
674}
675
676/**
677 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
678 */
679static DECLCALLBACK(int) vboxNetAdpWinPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
680{
681 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
682 int rc;
683
684 LogFlow(("vboxNetAdpWinPortWaitForIdle: pThis=%p, pIfPort=%p, cMillies=%u\n", pThis, pIfPort, cMillies));
685 /*
686 * Input validation.
687 */
688 AssertPtr(pThis);
689 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
690 AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
691 AssertReturn(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING, VERR_INVALID_STATE);
692
693 rc = NdisWaitEvent(&pThis->EventIdle, cMillies) ? VINF_SUCCESS : VERR_TIMEOUT;
694
695 return rc;
696}
697
698/**
699 * @copydoc INTNETTRUNKIFPORT::pfnXmit
700 */
701static DECLCALLBACK(int) vboxNetAdpWinPortXmit(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
702{
703 RT_NOREF1(fDst);
704 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
705 int rc = VINF_SUCCESS;
706
707 LogFlow(("vboxNetAdpWinPortXmit: pThis=%p, pIfPort=%p, pvIfData=%p, pSG=%p, fDst=0x%x\n", pThis, pIfPort, pvIfData, pSG, fDst));
708 RT_NOREF1(pvIfData);
709 /*
710 * Input validation.
711 */
712 AssertPtr(pThis);
713 AssertPtr(pSG);
714 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
715 AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
716
717 vboxNetAdpWinDumpPacket(pSG, "intnet --> host");
718
719 /*
720 * First of all, indicate we are busy. It is possible the trunk or the adapter
721 * will get paused or even disconnected, so we need to check the state after
722 * we have marked ourselves busy.
723 * Later, when NDIS returns all buffers, we will mark ourselves idle.
724 */
725 if (ASMAtomicIncS32(&pThis->cBusy) == 1)
726 NdisResetEvent(&pThis->EventIdle);
727
728 if (vboxNetAdpWinIsActive(pThis))
729 {
730 PNET_BUFFER_LIST pBufList = vboxNetAdpWinSGtoNB(pThis, pSG);
731 if (pBufList)
732 {
733 NdisMIndicateReceiveNetBufferLists(pThis->hAdapter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
734 vboxNetAdpWinUpdateStats(pThis->au64StatsInPackets, pThis->au64StatsInOctets, pSG);
735 }
736 }
737
738 return rc;
739}
740
741/**
742 * @copydoc INTNETTRUNKIFPORT::pfnNotifyMacAddress
743 */
744static DECLCALLBACK(void) vboxNetAdpWinPortNotifyMacAddress(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PCRTMAC pMac)
745{
746 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
747
748 LogFlow(("vboxNetAdpWinPortNotifyMacAddress: pThis=%p, pIfPort=%p, pvIfData=%p, pMac=%p\n", pThis, pIfPort, pvIfData, pMac));
749 RT_NOREF3(pThis, pvIfData, pMac);
750 /*
751 * Input validation.
752 */
753 AssertPtr(pThis);
754 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
755
756 /// @todo Do we really need to handle this?
757}
758
759
760/**
761 * @copydoc INTNETTRUNKIFPORT::pfnConnectInterface
762 */
763static DECLCALLBACK(int) vboxNetAdpWinPortConnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIf, void **ppvIfData)
764{
765 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
766 int rc;
767
768 LogFlow(("vboxNetAdpWinPortConnectInterface: pThis=%p, pIfPort=%p, pvIf=%p, ppvIfData=%p\n", pThis, pIfPort, pvIf, ppvIfData));
769 RT_NOREF3(pThis, pvIf, ppvIfData);
770 /*
771 * Input validation.
772 */
773 AssertPtr(pThis);
774 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
775
776 rc = VINF_SUCCESS;
777
778 return rc;
779}
780
781
782/**
783 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectInterface
784 */
785static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIfData)
786{
787 PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
788 int rc;
789
790 LogFlow(("vboxNetAdpWinPortDisconnectInterface: pThis=%p, pIfPort=%p, pvIfData=%p\n", pThis, pIfPort, pvIfData));
791 RT_NOREF2(pThis, pvIfData);
792 /*
793 * Input validation.
794 */
795 AssertPtr(pThis);
796 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
797
798 rc = VINF_SUCCESS;
799 AssertRC(rc);
800}
801
802
803
804/**
805 * Implements the SUPDRV component factor interface query method.
806 *
807 * @returns Pointer to an interface. NULL if not supported.
808 *
809 * @param pSupDrvFactory Pointer to the component factory registration structure.
810 * @param pSession The session - unused.
811 * @param pszInterfaceUuid The factory interface id.
812 */
813static DECLCALLBACK(void *) vboxNetAdpWinQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession,
814 const char *pszInterfaceUuid)
815{
816 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
817
818 /*
819 * Convert the UUID strings and compare them.
820 */
821 RTUUID UuidReq;
822 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
823 if (RT_SUCCESS(rc))
824 {
825 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
826 {
827 NdisAcquireSpinLock(&pGlobals->Lock);
828 if (pGlobals->enmIdcState == kVBoxNetAdpWinIdcState_Connected)
829 {
830 pGlobals->cFactoryRefs++;
831 NdisResetEvent(&pGlobals->EventUnloadAllowed);
832 }
833 NdisReleaseSpinLock(&pGlobals->Lock);
834 return &pGlobals->TrunkFactory;
835 }
836#ifdef LOG_ENABLED
837 else
838 Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
839#endif
840 }
841 else
842 Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
843
844 RT_NOREF1(pSession);
845 return NULL;
846}
847
848
849DECLHIDDEN(void) vboxNetAdpWinReportCapabilities(PVBOXNETADP_ADAPTER pThis)
850{
851 if (pThis->pSwitchPort)
852 {
853 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->MacAddr);
854 /* Promiscuous mode makes no sense for host-only adapters, does it? */
855 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
856 INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
857 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
858 }
859}
860
861/**
862 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
863 */
864static DECLCALLBACK(int) vboxNetAdpWinFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
865 PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
866 PINTNETTRUNKIFPORT *ppIfPort)
867{
868 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
869
870 LogFlow(("==>vboxNetAdpWinFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
871 Assert(pGlobals->cFactoryRefs > 0);
872 AssertMsgReturn(!(fFlags & ~(INTNETTRUNKFACTORY_FLAG_NO_PROMISC)),
873 ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
874
875 DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: looking for %s...\n", pszName);
876 PVBOXNETADP_ADAPTER pAdapter = NULL;
877 NdisAcquireSpinLock(&pGlobals->Lock);
878 RTListForEach(&g_VBoxNetAdpGlobals.ListOfAdapters, pAdapter, VBOXNETADP_ADAPTER, node)
879 {
880 Log(("vboxNetAdpWinFactoryCreateAndConnect: evaluating adapter=%s\n", pAdapter->szName));
881 DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: evaluating %s...\n", pAdapter->szName);
882 if (!RTStrICmp(pszName, pAdapter->szName))
883 {
884 pAdapter->pSwitchPort = pSwitchPort;
885 *ppIfPort = &pAdapter->MyPort;
886 NdisReleaseSpinLock(&g_VBoxNetAdpGlobals.Lock); /// @todo too early? adp should have been connected by the time we do this
887 Log(("vboxNetAdpWinFactoryCreateAndConnect: found matching adapter, name=%s\n", pszName));
888 vboxNetAdpWinReportCapabilities(pAdapter);
889 /// @todo I guess there is no need in vboxNetAdpWinRegisterIpAddrNotifier(pThis);
890 LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VINF_SUCCESS\n"));
891 return VINF_SUCCESS;
892 }
893 }
894 NdisReleaseSpinLock(&pGlobals->Lock);
895 /// @todo vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
896 DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: could not find %s\n", pszName);
897 LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
898 return VERR_INTNET_FLT_IF_NOT_FOUND;
899}
900
901
902/**
903 * @copydoc INTNETTRUNKFACTORY::pfnRelease
904 */
905static DECLCALLBACK(void) vboxNetAdpWinFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
906{
907 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
908
909 NdisAcquireSpinLock(&pGlobals->Lock);
910 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
911 if (cRefs == 0)
912 NdisSetEvent(&pGlobals->EventUnloadAllowed);
913 NdisReleaseSpinLock(&pGlobals->Lock);
914 Assert(cRefs >= 0); NOREF(cRefs);
915 LogFlow(("vboxNetAdpWinFactoryRelease: cRefs=%d (new)\n", cRefs));
916}
917
918
919
920/* IDC */
921
922DECLINLINE(const char *) vboxNetAdpWinIdcStateToText(uint32_t enmState)
923{
924 switch (enmState)
925 {
926 case kVBoxNetAdpWinIdcState_Disconnected: return "Disconnected";
927 case kVBoxNetAdpWinIdcState_Connecting: return "Connecting";
928 case kVBoxNetAdpWinIdcState_Connected: return "Connected";
929 case kVBoxNetAdpWinIdcState_Stopping: return "Stopping";
930 }
931 return "Unknown";
932}
933
934static VOID vboxNetAdpWinInitIdcWorker(PVOID pvContext)
935{
936 int rc;
937 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)pvContext;
938
939 /*
940 * Note that we break the rules here and access IDC state wihout acquiring
941 * the lock. This is ok because vboxNetAdpWinUnload will wait for this
942 * thread to terminate itself and we always use atomic access to IDC state.
943 * We check the state (while holding the lock) further when we have succeeded
944 * to connect. We cannot take the lock here and release it later as we will
945 * be holding it for too long.
946 */
947 while (ASMAtomicReadU32(&pGlobals->enmIdcState) == kVBoxNetAdpWinIdcState_Connecting)
948 {
949 /*
950 * Establish a connection to SUPDRV and register our component factory.
951 */
952 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
953 if (RT_SUCCESS(rc))
954 {
955 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
956 if (RT_SUCCESS(rc))
957 {
958 /*
959 * At this point we should take the lock to access IDC state as
960 * we technically may now race with factory methods.
961 */
962 NdisAcquireSpinLock(&pGlobals->Lock);
963 bool fSuccess = ASMAtomicCmpXchgU32(&pGlobals->enmIdcState,
964 kVBoxNetAdpWinIdcState_Connected,
965 kVBoxNetAdpWinIdcState_Connecting);
966 NdisReleaseSpinLock(&pGlobals->Lock);
967 if (!fSuccess)
968 {
969 /* The state has been changed (the only valid transition is to "Stopping"), undo init */
970 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
971 AssertRC(rc);
972 SUPR0IdcClose(&pGlobals->SupDrvIDC);
973 Log(("vboxNetAdpWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, closed IDC, rc=0x%x\n",
974 vboxNetAdpWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
975 }
976 else
977 {
978 Log(("vboxNetAdpWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
979 }
980 }
981 }
982 else
983 {
984 LARGE_INTEGER WaitIn100nsUnits;
985 WaitIn100nsUnits.QuadPart = -(LONGLONG)5000000; /* 0.5 sec */
986 KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
987 }
988 }
989 PsTerminateSystemThread(STATUS_SUCCESS);
990}
991
992
993DECLHIDDEN(int) vboxNetAdpWinStartInitIdcThread(PVBOXNETADPGLOBALS pGlobals)
994{
995 int rc = VERR_INVALID_STATE;
996
997 /* No locking needed yet */
998 if (ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, kVBoxNetAdpWinIdcState_Connecting, kVBoxNetAdpWinIdcState_Disconnected))
999 {
1000 Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
1001
1002 NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetAdpGlobals.hInitIdcThread,
1003 THREAD_ALL_ACCESS,
1004 NULL,
1005 NULL,
1006 NULL,
1007 vboxNetAdpWinInitIdcWorker,
1008 &g_VBoxNetAdpGlobals);
1009 Log(("vboxNetAdpWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
1010 if (Status != STATUS_SUCCESS)
1011 {
1012 LogError(("vboxNetAdpWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
1013 /*
1014 * We failed to init IDC and there will be no second chance.
1015 */
1016 Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
1017 ASMAtomicWriteU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Disconnected);
1018 }
1019 rc = RTErrConvertFromNtStatus(Status);
1020 }
1021 return rc;
1022}
1023
1024
1025
1026/* === !!!! */
1027
1028
1029NDIS_OID g_SupportedOids[] =
1030{
1031 OID_GEN_CURRENT_LOOKAHEAD,
1032 OID_GEN_CURRENT_PACKET_FILTER,
1033 OID_GEN_INTERRUPT_MODERATION,
1034 OID_GEN_LINK_PARAMETERS,
1035 OID_GEN_MAXIMUM_TOTAL_SIZE,
1036 OID_GEN_RCV_OK,
1037 OID_GEN_RECEIVE_BLOCK_SIZE,
1038 OID_GEN_RECEIVE_BUFFER_SPACE,
1039 OID_GEN_STATISTICS,
1040 OID_GEN_TRANSMIT_BLOCK_SIZE,
1041 OID_GEN_TRANSMIT_BUFFER_SPACE,
1042 OID_GEN_VENDOR_DESCRIPTION,
1043 OID_GEN_VENDOR_DRIVER_VERSION,
1044 OID_GEN_VENDOR_ID,
1045 OID_GEN_XMIT_OK,
1046 OID_802_3_PERMANENT_ADDRESS,
1047 OID_802_3_CURRENT_ADDRESS,
1048 OID_802_3_MULTICAST_LIST,
1049 OID_802_3_MAXIMUM_LIST_SIZE,
1050 OID_PNP_CAPABILITIES,
1051 OID_PNP_QUERY_POWER,
1052 OID_PNP_SET_POWER
1053};
1054
1055DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinAllocAdapter(NDIS_HANDLE hAdapter, PVBOXNETADP_ADAPTER *ppAdapter, ULONG uIfIndex)
1056{
1057 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1058 PVBOXNETADP_ADAPTER pAdapter = NULL;
1059 PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
1060
1061 LogFlow(("==>vboxNetAdpWinAllocAdapter: adapter handle=%p\n", hAdapter));
1062
1063 /* Get the name */
1064 UNICODE_STRING strUnicodeName;
1065 Status = NdisMQueryAdapterInstanceName(&strUnicodeName, hAdapter);
1066 if (Status != NDIS_STATUS_SUCCESS)
1067 {
1068 LogError(("vboxNetAdpWinAllocAdapter: NdisMQueryAdapterInstanceName failed with 0x%x\n", Status));
1069 return Status;
1070 }
1071
1072 ANSI_STRING strAnsiName;
1073 /* We use the miniport name to associate this filter module with the netflt instance */
1074 NTSTATUS rc = RtlUnicodeStringToAnsiString(&strAnsiName,
1075 &strUnicodeName,
1076 TRUE);
1077 if (rc != STATUS_SUCCESS)
1078 {
1079 LogError(("vboxNetAdpWinAllocAdapter: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
1080 strUnicodeName, rc));
1081 //vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
1082 NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
1083 return NDIS_STATUS_FAILURE;
1084 }
1085 NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
1086 DbgPrint("vboxNetAdpWinAllocAdapter: name=%Z\n", &strAnsiName);
1087
1088 *ppAdapter = NULL;
1089
1090 UINT cbAdapterWithNameExtra = sizeof(VBOXNETADP_ADAPTER) + strAnsiName.Length;
1091 pAdapter = (PVBOXNETADP_ADAPTER)NdisAllocateMemoryWithTagPriority(pGlobals->hMiniportDriver,
1092 cbAdapterWithNameExtra,
1093 VBOXNETADPWIN_TAG,
1094 NormalPoolPriority);
1095 if (!pAdapter)
1096 {
1097 RtlFreeAnsiString(&strAnsiName);
1098 Status = NDIS_STATUS_RESOURCES;
1099 Log(("vboxNetAdpWinAllocAdapter: Out of memory while allocating adapter context (size=%d)\n", sizeof(VBOXNETADP_ADAPTER)));
1100 }
1101 else
1102 {
1103 NdisZeroMemory(pAdapter, cbAdapterWithNameExtra);
1104 NdisMoveMemory(pAdapter->szName, strAnsiName.Buffer, strAnsiName.Length);
1105 RtlFreeAnsiString(&strAnsiName);
1106
1107 /* Allocate buffer pool */
1108 NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
1109 NdisZeroMemory(&PoolParams, sizeof(PoolParams));
1110 PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
1111 PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
1112 PoolParams.Header.Size = sizeof(PoolParams);
1113 PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
1114 PoolParams.fAllocateNetBuffer = TRUE;
1115 PoolParams.ContextSize = 0;
1116 PoolParams.PoolTag = VBOXNETADP_MEM_TAG;
1117 pAdapter->hPool = NdisAllocateNetBufferListPool(hAdapter, &PoolParams);
1118 if (!pAdapter->hPool)
1119 {
1120 LogError(("vboxNetAdpWinAllocAdapter: NdisAllocateNetBufferListPool failed\n"));
1121 NdisFreeMemory(pAdapter, 0, 0);
1122 return NDIS_STATUS_RESOURCES;
1123 }
1124 Log4(("vboxNetAdpWinAllocAdapter: allocated NBL+NB pool 0x%p\n", pAdapter->hPool));
1125
1126 pAdapter->hAdapter = hAdapter;
1127 pAdapter->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
1128 pAdapter->MyPort.pfnRetain = vboxNetAdpWinPortRetain;
1129 pAdapter->MyPort.pfnRelease = vboxNetAdpWinPortRelease;
1130 pAdapter->MyPort.pfnDisconnectAndRelease = vboxNetAdpWinPortDisconnectAndRelease;
1131 pAdapter->MyPort.pfnSetState = vboxNetAdpWinPortSetState;
1132 pAdapter->MyPort.pfnWaitForIdle = vboxNetAdpWinPortWaitForIdle;
1133 pAdapter->MyPort.pfnXmit = vboxNetAdpWinPortXmit;
1134 pAdapter->MyPort.pfnNotifyMacAddress = vboxNetAdpWinPortNotifyMacAddress;
1135 pAdapter->MyPort.pfnConnectInterface = vboxNetAdpWinPortConnectInterface;
1136 pAdapter->MyPort.pfnDisconnectInterface = vboxNetAdpWinPortDisconnectInterface;
1137 pAdapter->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
1138 pAdapter->pGlobals = pGlobals;
1139 pAdapter->enmAdapterState = kVBoxNetAdpWinState_Initializing;
1140 pAdapter->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE;
1141 pAdapter->cBusy = 0;
1142 NdisInitializeEvent(&pAdapter->EventIdle);
1143 NdisSetEvent(&pAdapter->EventIdle); /* We are idle initially */
1144
1145 /* Use a locally administered version of the OUI we use for the guest NICs. */
1146 pAdapter->MacAddr.au8[0] = 0x08 | 2;
1147 pAdapter->MacAddr.au8[1] = 0x00;
1148 pAdapter->MacAddr.au8[2] = 0x27;
1149
1150 pAdapter->MacAddr.au8[3] = (uIfIndex >> 16) & 0xFF;
1151 pAdapter->MacAddr.au8[4] = (uIfIndex >> 8) & 0xFF;
1152 pAdapter->MacAddr.au8[5] = uIfIndex & 0xFF;
1153
1154 NdisAcquireSpinLock(&pGlobals->Lock);
1155 RTListPrepend(&pGlobals->ListOfAdapters, &pAdapter->node);
1156 NdisReleaseSpinLock(&pGlobals->Lock);
1157
1158 *ppAdapter = pAdapter;
1159 }
1160 LogFlow(("<==vboxNetAdpWinAllocAdapter: status=0x%x\n", Status));
1161 return Status;
1162}
1163
1164DECLHIDDEN(void) vboxNetAdpWinFreeAdapter(PVBOXNETADP_ADAPTER pAdapter)
1165{
1166 /* Remove from adapter chain */
1167 NdisAcquireSpinLock(&pAdapter->pGlobals->Lock);
1168 RTListNodeRemove(&pAdapter->node);
1169 NdisReleaseSpinLock(&pAdapter->pGlobals->Lock);
1170
1171 NdisFreeMemory(pAdapter, 0, 0);
1172}
1173
1174DECLINLINE(NDIS_MEDIA_CONNECT_STATE) vboxNetAdpWinGetConnectState(PVBOXNETADP_ADAPTER pAdapter)
1175{
1176 RT_NOREF1(pAdapter);
1177 return MediaConnectStateConnected;
1178}
1179
1180
1181DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinInitializeEx(IN NDIS_HANDLE NdisMiniportHandle,
1182 IN NDIS_HANDLE MiniportDriverContext,
1183 IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
1184{
1185 RT_NOREF1(MiniportDriverContext);
1186 PVBOXNETADP_ADAPTER pAdapter = NULL;
1187 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1188
1189 LogFlow(("==>vboxNetAdpWinInitializeEx: miniport=0x%x\n", NdisMiniportHandle));
1190
1191 do
1192 {
1193 NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RAttrs = {0};
1194 NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GAttrs = {0};
1195
1196 Status = vboxNetAdpWinAllocAdapter(NdisMiniportHandle, &pAdapter, MiniportInitParameters->IfIndex);
1197 if (Status != NDIS_STATUS_SUCCESS)
1198 {
1199 Log(("vboxNetAdpWinInitializeEx: Failed to allocate the adapter context with 0x%x\n", Status));
1200 break;
1201 }
1202
1203 RAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
1204 RAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
1205 RAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
1206 RAttrs.MiniportAdapterContext = pAdapter;
1207 RAttrs.AttributeFlags = VBOXNETADPWIN_ATTR_FLAGS; // NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM
1208 RAttrs.CheckForHangTimeInSeconds = VBOXNETADPWIN_HANG_CHECK_TIME;
1209 RAttrs.InterfaceType = NdisInterfaceInternal;
1210
1211 Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
1212 (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&RAttrs);
1213 if (Status != NDIS_STATUS_SUCCESS)
1214 {
1215 Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(registration) failed with 0x%x\n", Status));
1216 break;
1217 }
1218
1219 /// @todo Registry?
1220
1221 /// @todo WDM stack?
1222
1223 /// @todo DPC?
1224
1225 GAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
1226 GAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
1227 GAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
1228
1229 GAttrs.MediaType = NdisMedium802_3;
1230 GAttrs.PhysicalMediumType = NdisPhysicalMediumUnspecified;
1231 GAttrs.MtuSize = 1500; /// @todo
1232 GAttrs.MaxXmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
1233 GAttrs.XmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
1234 GAttrs.MaxRcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
1235 GAttrs.RcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
1236 GAttrs.MediaConnectState = vboxNetAdpWinGetConnectState(pAdapter);
1237 GAttrs.MediaDuplexState = MediaDuplexStateFull;
1238 GAttrs.LookaheadSize = 1500; /// @todo
1239 GAttrs.MacOptions = VBOXNETADP_MAC_OPTIONS;
1240 GAttrs.SupportedPacketFilters = VBOXNETADP_SUPPORTED_FILTERS;
1241 GAttrs.MaxMulticastListSize = 32; /// @todo
1242
1243 GAttrs.MacAddressLength = ETH_LENGTH_OF_ADDRESS;
1244 Assert(GAttrs.MacAddressLength == sizeof(pAdapter->MacAddr));
1245 memcpy(GAttrs.PermanentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
1246 memcpy(GAttrs.CurrentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
1247
1248 GAttrs.RecvScaleCapabilities = NULL;
1249 GAttrs.AccessType = NET_IF_ACCESS_BROADCAST;
1250 GAttrs.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
1251 GAttrs.ConnectionType = NET_IF_CONNECTION_DEDICATED;
1252 GAttrs.IfType = IF_TYPE_ETHERNET_CSMACD;
1253 GAttrs.IfConnectorPresent = false;
1254 GAttrs.SupportedStatistics = VBOXNETADPWIN_SUPPORTED_STATISTICS;
1255 GAttrs.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
1256 GAttrs.DataBackFillSize = 0;
1257 GAttrs.ContextBackFillSize = 0;
1258 GAttrs.SupportedOidList = g_SupportedOids;
1259 GAttrs.SupportedOidListLength = sizeof(g_SupportedOids);
1260 GAttrs.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
1261 GAttrs.PowerManagementCapabilities = &g_VBoxNetAdpGlobals.PMCaps;
1262
1263 Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
1264 (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&GAttrs);
1265 if (Status != NDIS_STATUS_SUCCESS)
1266 {
1267 Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(general) failed with 0x%x\n", Status));
1268 break;
1269 }
1270
1271 VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pAdapter, kVBoxNetAdpWinState_Paused);
1272 RT_NOREF1(enmPrevState);
1273 Assert(enmPrevState == kVBoxNetAdpWinState_Initializing);
1274 } while (false);
1275
1276 if (Status != NDIS_STATUS_SUCCESS)
1277 {
1278 if (pAdapter)
1279 vboxNetAdpWinFreeAdapter(pAdapter);
1280 }
1281
1282 LogFlow(("<==vboxNetAdpWinInitializeEx: status=0x%x\n", Status));
1283 return Status;
1284}
1285
1286DECLHIDDEN(VOID) vboxNetAdpWinHaltEx(IN NDIS_HANDLE MiniportAdapterContext,
1287 IN NDIS_HALT_ACTION HaltAction)
1288{
1289 RT_NOREF1(HaltAction);
1290 PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1291 LogFlow(("==>vboxNetAdpWinHaltEx\n"));
1292 AssertPtr(pThis);
1293 Assert(vboxNetAdpWinGetState(pThis) == kVBoxNetAdpWinState_Paused);
1294 /*
1295 * Check if the trunk is active which means the adapter gets disabled
1296 * while it is used by VM(s) and we need to disconnect the trunk.
1297 */
1298 if (pThis->pSwitchPort && pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
1299 pThis->pSwitchPort->pfnDisconnect(pThis->pSwitchPort, &pThis->MyPort, NULL);
1300 /*
1301 * Since we are already in the paused state and we have disconnected
1302 * the trunk, we can safely destroy this adapter.
1303 */
1304 vboxNetAdpWinFreeAdapter(pThis);
1305 LogFlow(("<==vboxNetAdpWinHaltEx\n"));
1306}
1307
1308DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinPause(IN NDIS_HANDLE MiniportAdapterContext,
1309 IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
1310{
1311 RT_NOREF1(MiniportPauseParameters);
1312 PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1313 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1314 LogFlow(("==>vboxNetAdpWinPause\n"));
1315 VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Pausing);
1316 Assert(enmPrevState == kVBoxNetAdpWinState_Running);
1317 if (!NdisWaitEvent(&pThis->EventIdle, 1000 /* ms */))
1318 {
1319 LogError(("vboxNetAdpWinPause: timed out while pausing the adapter\n"));
1320 /// @todo implement NDIS_STATUS_PENDING case? probably not.
1321 }
1322 enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Paused);
1323 Assert(enmPrevState == kVBoxNetAdpWinState_Pausing);
1324 LogFlow(("<==vboxNetAdpWinPause: status=0x%x\n", Status));
1325 return Status;
1326}
1327
1328DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRestart(IN NDIS_HANDLE MiniportAdapterContext,
1329 IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
1330{
1331 RT_NOREF1(MiniportRestartParameters);
1332 PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1333 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1334 LogFlow(("==>vboxNetAdpWinRestart\n"));
1335 VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Restarting);
1336 Assert(enmPrevState == kVBoxNetAdpWinState_Paused);
1337 /// @todo anything?
1338 enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Running);
1339 Assert(enmPrevState == kVBoxNetAdpWinState_Restarting);
1340 LogFlow(("<==vboxNetAdpWinRestart: status=0x%x\n", Status));
1341 return Status;
1342}
1343
1344DECLINLINE(uint64_t) vboxNetAdpWinStatsTotals(uint64_t *pStats)
1345{
1346 return pStats[kVBoxNetAdpWinPacketType_Unicast]
1347 + pStats[kVBoxNetAdpWinPacketType_Multicast]
1348 + pStats[kVBoxNetAdpWinPacketType_Broadcast];
1349}
1350
1351DECLINLINE(PVOID) vboxNetAdpWinStatsU64(uint64_t *pTmp, ULONG *pcbTmp, uint64_t u64Stat)
1352{
1353 *pcbTmp = sizeof(*pTmp);
1354 *pTmp = u64Stat;
1355 return pTmp;
1356}
1357
1358DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqQuery(PVBOXNETADP_ADAPTER pThis,
1359 PNDIS_OID_REQUEST pRequest)
1360{
1361 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1362 struct _NDIS_OID_REQUEST::_REQUEST_DATA::_QUERY *pQuery = &pRequest->DATA.QUERY_INFORMATION;
1363
1364 LogFlow(("==>vboxNetAdpWinOidRqQuery\n"));
1365
1366 uint64_t u64Tmp = 0;
1367 ULONG ulTmp = 0;
1368 PVOID pInfo = &ulTmp;
1369 ULONG cbInfo = sizeof(ulTmp);
1370
1371 switch (pQuery->Oid)
1372 {
1373 case OID_GEN_INTERRUPT_MODERATION:
1374 {
1375 PNDIS_INTERRUPT_MODERATION_PARAMETERS pParams =
1376 (PNDIS_INTERRUPT_MODERATION_PARAMETERS)pQuery->InformationBuffer;
1377 cbInfo = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
1378 if (cbInfo > pQuery->InformationBufferLength)
1379 break;
1380 pParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
1381 pParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
1382 pParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
1383 pParams->Flags = 0;
1384 pParams->InterruptModeration = NdisInterruptModerationNotSupported;
1385 pInfo = NULL; /* Do not copy */
1386 break;
1387 }
1388 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1389 case OID_GEN_RECEIVE_BLOCK_SIZE:
1390 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1391 ulTmp = VBOXNETADP_MAX_FRAME_SIZE;
1392 break;
1393 case OID_GEN_RECEIVE_BUFFER_SPACE:
1394 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1395 /// @todo Make configurable
1396 ulTmp = VBOXNETADP_MAX_FRAME_SIZE * 40;
1397 break;
1398 case OID_GEN_RCV_OK:
1399 pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsInPackets));
1400 break;
1401 case OID_GEN_XMIT_OK:
1402 pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsOutPackets));
1403 break;
1404 case OID_GEN_STATISTICS:
1405 {
1406 PNDIS_STATISTICS_INFO pStats =
1407 (PNDIS_STATISTICS_INFO)pQuery->InformationBuffer;
1408 cbInfo = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
1409 if (cbInfo > pQuery->InformationBufferLength)
1410 break;
1411 pInfo = NULL; /* Do not copy */
1412 memset(pStats, 0, cbInfo);
1413 pStats->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
1414 pStats->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
1415 pStats->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
1416 pStats->SupportedStatistics =
1417 NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV
1418 | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV
1419 | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV
1420 | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV
1421 | NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS
1422 | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR
1423 | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT
1424 | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT
1425 | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT
1426 | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT
1427 | NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR
1428 | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS
1429 | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV
1430 | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV
1431 | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV
1432 | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT
1433 | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT
1434 | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
1435
1436 pStats->ifHCInOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsInOctets);
1437 pStats->ifHCInUcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Unicast]);
1438 pStats->ifHCInMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Multicast]);
1439 pStats->ifHCInBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Broadcast]);
1440 pStats->ifHCOutOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsOutOctets);;
1441 pStats->ifHCOutUcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Unicast]);
1442 pStats->ifHCOutMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Multicast]);
1443 pStats->ifHCOutBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Broadcast]);
1444 pStats->ifHCInUcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Unicast]);
1445 pStats->ifHCInMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Multicast]);
1446 pStats->ifHCInBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Broadcast]);
1447 pStats->ifHCOutUcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Unicast]);
1448 pStats->ifHCOutMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Multicast]);
1449 pStats->ifHCOutBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Broadcast]);
1450 break;
1451 }
1452 case OID_GEN_VENDOR_DESCRIPTION:
1453 pInfo = VBOXNETADP_VENDOR_NAME;
1454 cbInfo = sizeof(VBOXNETADP_VENDOR_NAME);
1455 break;
1456 case OID_GEN_VENDOR_DRIVER_VERSION:
1457 ulTmp = (VBOXNETADP_VERSION_NDIS_MAJOR << 16) | VBOXNETADP_VERSION_NDIS_MINOR;
1458 break;
1459 case OID_GEN_VENDOR_ID:
1460 ulTmp = VBOXNETADP_VENDOR_ID;
1461 break;
1462 case OID_802_3_PERMANENT_ADDRESS:
1463 case OID_802_3_CURRENT_ADDRESS:
1464 pInfo = &pThis->MacAddr;
1465 cbInfo = sizeof(pThis->MacAddr);
1466 break;
1467 //case OID_802_3_MULTICAST_LIST:
1468 case OID_802_3_MAXIMUM_LIST_SIZE:
1469 ulTmp = VBOXNETADP_MCAST_LIST_SIZE;
1470 break;
1471 case OID_PNP_CAPABILITIES:
1472 pInfo = &pThis->pGlobals->PMCaps;
1473 cbInfo = sizeof(pThis->pGlobals->PMCaps);
1474 break;
1475 case OID_PNP_QUERY_POWER:
1476 pInfo = NULL; /* Do not copy */
1477 cbInfo = 0;
1478 break;
1479 default:
1480 Status = NDIS_STATUS_NOT_SUPPORTED;
1481 break;
1482 }
1483
1484 if (Status == NDIS_STATUS_SUCCESS)
1485 {
1486 if (cbInfo > pQuery->InformationBufferLength)
1487 {
1488 pQuery->BytesNeeded = cbInfo;
1489 Status = NDIS_STATUS_BUFFER_TOO_SHORT;
1490 }
1491 else
1492 {
1493 if (pInfo)
1494 NdisMoveMemory(pQuery->InformationBuffer, pInfo, cbInfo);
1495 pQuery->BytesWritten = cbInfo;
1496 }
1497 }
1498
1499 LogFlow(("<==vboxNetAdpWinOidRqQuery: status=0x%x\n", Status));
1500 return Status;
1501}
1502
1503DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqSet(PVBOXNETADP_ADAPTER pAdapter,
1504 PNDIS_OID_REQUEST pRequest)
1505{
1506 RT_NOREF1(pAdapter);
1507 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1508 struct _NDIS_OID_REQUEST::_REQUEST_DATA::_SET *pSet = &pRequest->DATA.SET_INFORMATION;
1509
1510 LogFlow(("==>vboxNetAdpWinOidRqSet\n"));
1511
1512 switch (pSet->Oid)
1513 {
1514 case OID_GEN_CURRENT_LOOKAHEAD:
1515 if (pSet->InformationBufferLength != sizeof(ULONG))
1516 {
1517 pSet->BytesNeeded = sizeof(ULONG);
1518 Status = NDIS_STATUS_INVALID_LENGTH;
1519 break;
1520 }
1521 /// @todo For the time being we simply ignore lookahead settings.
1522 pSet->BytesRead = sizeof(ULONG);
1523 Status = NDIS_STATUS_SUCCESS;
1524 break;
1525
1526 case OID_GEN_CURRENT_PACKET_FILTER:
1527 if (pSet->InformationBufferLength != sizeof(ULONG))
1528 {
1529 pSet->BytesNeeded = sizeof(ULONG);
1530 Status = NDIS_STATUS_INVALID_LENGTH;
1531 break;
1532 }
1533 /// @todo For the time being we simply ignore packet filter settings.
1534 pSet->BytesRead = pSet->InformationBufferLength;
1535 Status = NDIS_STATUS_SUCCESS;
1536 break;
1537
1538 case OID_GEN_INTERRUPT_MODERATION:
1539 pSet->BytesNeeded = 0;
1540 pSet->BytesRead = 0;
1541 Status = NDIS_STATUS_INVALID_DATA;
1542 break;
1543
1544 case OID_PNP_SET_POWER:
1545 if (pSet->InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
1546 {
1547 Status = NDIS_STATUS_INVALID_LENGTH;
1548 break;
1549 }
1550 pSet->BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
1551 Status = NDIS_STATUS_SUCCESS;
1552 break;
1553
1554 default:
1555 Status = NDIS_STATUS_NOT_SUPPORTED;
1556 break;
1557 }
1558
1559 LogFlow(("<==vboxNetAdpWinOidRqSet: status=0x%x\n", Status));
1560 return Status;
1561}
1562
1563DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
1564 IN PNDIS_OID_REQUEST NdisRequest)
1565{
1566 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1567 PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1568 LogFlow(("==>vboxNetAdpWinOidRequest\n"));
1569 vboxNetCmnWinDumpOidRequest(__FUNCTION__, NdisRequest);
1570
1571 switch (NdisRequest->RequestType)
1572 {
1573#if 0
1574 case NdisRequestMethod:
1575 Status = vboxNetAdpWinOidRqMethod(pAdapter, NdisRequest);
1576 break;
1577#endif
1578
1579 case NdisRequestSetInformation:
1580 Status = vboxNetAdpWinOidRqSet(pAdapter, NdisRequest);
1581 break;
1582
1583 case NdisRequestQueryInformation:
1584 case NdisRequestQueryStatistics:
1585 Status = vboxNetAdpWinOidRqQuery(pAdapter, NdisRequest);
1586 break;
1587
1588 default:
1589 Status = NDIS_STATUS_NOT_SUPPORTED;
1590 break;
1591 }
1592 LogFlow(("<==vboxNetAdpWinOidRequest: status=0x%x\n", Status));
1593 return Status;
1594}
1595
1596DECLHIDDEN(VOID) vboxNetAdpWinSendNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
1597 IN PNET_BUFFER_LIST NetBufferLists,
1598 IN NDIS_PORT_NUMBER PortNumber,
1599 IN ULONG SendFlags)
1600{
1601 RT_NOREF1(PortNumber);
1602 PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1603 LogFlow(("==>vboxNetAdpWinSendNetBufferLists\n"));
1604 PNET_BUFFER_LIST pNbl = NetBufferLists;
1605 vboxNetAdpWinDumpPackets("vboxNetAdpWinSendNetBufferLists: got", pNbl);
1606
1607 /* We alwast complete all send requests. */
1608 for (pNbl = NetBufferLists; pNbl; pNbl = NET_BUFFER_LIST_NEXT_NBL(pNbl))
1609 {
1610 vboxNetAdpWinForwardToIntNet(pAdapter, pNbl, INTNETTRUNKDIR_HOST);
1611 NET_BUFFER_LIST_STATUS(pNbl) = NDIS_STATUS_SUCCESS;
1612 }
1613 NdisMSendNetBufferListsComplete(pAdapter->hAdapter, NetBufferLists,
1614 (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ?
1615 NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
1616 LogFlow(("<==vboxNetAdpWinSendNetBufferLists\n"));
1617}
1618
1619DECLHIDDEN(VOID) vboxNetAdpWinReturnNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
1620 IN PNET_BUFFER_LIST NetBufferLists,
1621 IN ULONG ReturnFlags)
1622{
1623 LogFlow(("==>vboxNetAdpWinReturnNetBufferLists\n"));
1624 RT_NOREF1(ReturnFlags);
1625 PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
1626 PNET_BUFFER_LIST pList = NetBufferLists;
1627 while (pList)
1628 {
1629 Assert(pList->SourceHandle == pThis->hAdapter);
1630 Assert(NET_BUFFER_LIST_FIRST_NB(pList));
1631 Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1632
1633 PNET_BUFFER_LIST pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
1634
1635 vboxNetAdpWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
1636 NdisFreeNetBufferList(pList);
1637 Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
1638 Assert(ASMAtomicReadS32(&pThis->cBusy) > 0);
1639 if (ASMAtomicDecS32(&pThis->cBusy) == 0)
1640 NdisSetEvent(&pThis->EventIdle);
1641
1642 pList = pNextList;
1643 }
1644 LogFlow(("<==vboxNetAdpWinReturnNetBufferLists\n"));
1645}
1646
1647DECLHIDDEN(VOID) vboxNetAdpWinCancelSend(IN NDIS_HANDLE MiniportAdapterContext,
1648 IN PVOID CancelId)
1649{
1650 RT_NOREF2(MiniportAdapterContext, CancelId);
1651 LogFlow(("==>vboxNetAdpWinCancelSend\n"));
1652 Log(("vboxNetAdpWinCancelSend: We should not be here!\n"));
1653 LogFlow(("<==vboxNetAdpWinCancelSend\n"));
1654}
1655
1656
1657DECLHIDDEN(BOOLEAN) vboxNetAdpWinCheckForHangEx(IN NDIS_HANDLE MiniportAdapterContext)
1658{
1659 RT_NOREF1(MiniportAdapterContext);
1660 LogFlow(("==>vboxNetAdpWinCheckForHangEx\n"));
1661 LogFlow(("<==vboxNetAdpWinCheckForHangEx return false\n"));
1662 return FALSE;
1663}
1664
1665DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinResetEx(IN NDIS_HANDLE MiniportAdapterContext,
1666 OUT PBOOLEAN AddressingReset)
1667{
1668 RT_NOREF2(MiniportAdapterContext, AddressingReset);
1669 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1670 LogFlow(("==>vboxNetAdpWinResetEx\n"));
1671 LogFlow(("<==vboxNetAdpWinResetEx: status=0x%x\n", Status));
1672 return Status;
1673}
1674
1675DECLHIDDEN(VOID) vboxNetAdpWinDevicePnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
1676 IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
1677{
1678 RT_NOREF2(MiniportAdapterContext, NetDevicePnPEvent);
1679 LogFlow(("==>vboxNetAdpWinDevicePnPEventNotify\n"));
1680 Log(("vboxNetAdpWinDevicePnPEventNotify: PnP event=%d\n", NetDevicePnPEvent->DevicePnPEvent));
1681 LogFlow(("<==vboxNetAdpWinDevicePnPEventNotify\n"));
1682}
1683
1684
1685DECLHIDDEN(VOID) vboxNetAdpWinShutdownEx(IN NDIS_HANDLE MiniportAdapterContext,
1686 IN NDIS_SHUTDOWN_ACTION ShutdownAction)
1687{
1688 RT_NOREF2(MiniportAdapterContext, ShutdownAction);
1689 LogFlow(("==>vboxNetAdpWinShutdownEx\n"));
1690 Log(("vboxNetAdpWinShutdownEx: action=%d\n", ShutdownAction));
1691 LogFlow(("<==vboxNetAdpWinShutdownEx\n"));
1692}
1693
1694DECLHIDDEN(VOID) vboxNetAdpWinCancelOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
1695 IN PVOID RequestId)
1696{
1697 RT_NOREF2(MiniportAdapterContext, RequestId);
1698 LogFlow(("==>vboxNetAdpWinCancelOidRequest\n"));
1699 Log(("vboxNetAdpWinCancelOidRequest: req id=%p\n", RequestId));
1700 LogFlow(("<==vboxNetAdpWinCancelOidRequest\n"));
1701}
1702
1703
1704
1705DECLHIDDEN(VOID) vboxNetAdpWinUnload(IN PDRIVER_OBJECT DriverObject)
1706{
1707 RT_NOREF1(DriverObject);
1708 LogFlow(("==>vboxNetAdpWinUnload\n"));
1709 PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
1710 int rc;
1711 NDIS_STATUS Status;
1712 PKTHREAD pThread = NULL;
1713
1714 /* We are about to disconnect IDC, let's make it clear so the factories will know */
1715 NdisAcquireSpinLock(&pGlobals->Lock);
1716 uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Stopping);
1717 NdisReleaseSpinLock(&pGlobals->Lock);
1718 Log(("vboxNetAdpWinUnload: IDC state change %s -> Stopping\n", vboxNetAdpWinIdcStateToText(enmPrevState)));
1719
1720 switch (enmPrevState)
1721 {
1722 case kVBoxNetAdpWinIdcState_Disconnected:
1723 /* Have not even attempted to connect -- nothing to do. */
1724 break;
1725 case kVBoxNetAdpWinIdcState_Stopping:
1726 /* Impossible, but another thread is alreading doing StopIdc, bail out */
1727 LogError(("vboxNetAdpWinUnload: called in 'Stopping' state\n"));
1728 break;
1729 case kVBoxNetAdpWinIdcState_Connecting:
1730 /* the worker thread is running, let's wait for it to stop */
1731 Status = ObReferenceObjectByHandle(g_VBoxNetAdpGlobals.hInitIdcThread,
1732 THREAD_ALL_ACCESS, NULL, KernelMode,
1733 (PVOID*)&pThread, NULL);
1734 if (Status == STATUS_SUCCESS)
1735 {
1736 KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
1737 ObDereferenceObject(pThread);
1738 }
1739 else
1740 {
1741 LogError(("vboxNetAdpWinStopIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
1742 g_VBoxNetAdpGlobals.hInitIdcThread, Status));
1743 }
1744 break;
1745 case kVBoxNetAdpWinIdcState_Connected:
1746 /* the worker succeeded in IDC init and terminated */
1747 /* Make sure nobody uses the trunk factory. Wait half a second if needed. */
1748 if (!NdisWaitEvent(&pGlobals->EventUnloadAllowed, 500))
1749 LogRel(("VBoxNetAdp: unloading driver while trunk factory is in use!\n"));
1750 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1751 AssertRC(rc);
1752 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1753 Log(("vboxNetAdpWinUnload: closed IDC, rc=0x%x\n", rc));
1754 break;
1755 }
1756 if (pGlobals->hMiniportDriver)
1757 NdisMDeregisterMiniportDriver(pGlobals->hMiniportDriver);
1758 NdisFreeSpinLock(&pGlobals->Lock);
1759 LogFlow(("<==vboxNetAdpWinUnload\n"));
1760 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
1761 RTLogDestroy(RTLogSetDefaultInstance(NULL));
1762 RTR0Term();
1763}
1764
1765
1766/**
1767 * register the miniport driver
1768 */
1769DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
1770{
1771 NDIS_MINIPORT_DRIVER_CHARACTERISTICS MChars;
1772
1773 NdisZeroMemory(&MChars, sizeof (MChars));
1774
1775 MChars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
1776 MChars.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS);
1777 MChars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
1778
1779 MChars.MajorNdisVersion = VBOXNETADP_VERSION_NDIS_MAJOR;
1780 MChars.MinorNdisVersion = VBOXNETADP_VERSION_NDIS_MINOR;
1781
1782 MChars.MajorDriverVersion = VBOXNETADP_VERSION_MAJOR;
1783 MChars.MinorDriverVersion = VBOXNETADP_VERSION_MINOR;
1784
1785 MChars.InitializeHandlerEx = vboxNetAdpWinInitializeEx;
1786 MChars.HaltHandlerEx = vboxNetAdpWinHaltEx;
1787 MChars.UnloadHandler = vboxNetAdpWinUnload;
1788 MChars.PauseHandler = vboxNetAdpWinPause;
1789 MChars.RestartHandler = vboxNetAdpWinRestart;
1790 MChars.OidRequestHandler = vboxNetAdpWinOidRequest;
1791 MChars.SendNetBufferListsHandler = vboxNetAdpWinSendNetBufferLists;
1792 MChars.ReturnNetBufferListsHandler = vboxNetAdpWinReturnNetBufferLists;
1793 MChars.CancelSendHandler = vboxNetAdpWinCancelSend;
1794 MChars.CheckForHangHandlerEx = vboxNetAdpWinCheckForHangEx;
1795 MChars.ResetHandlerEx = vboxNetAdpWinResetEx;
1796 MChars.DevicePnPEventNotifyHandler = vboxNetAdpWinDevicePnPEventNotify;
1797 MChars.ShutdownHandlerEx = vboxNetAdpWinShutdownEx;
1798 MChars.CancelOidRequestHandler = vboxNetAdpWinCancelOidRequest;
1799
1800 NDIS_STATUS Status;
1801 g_VBoxNetAdpGlobals.hMiniportDriver = NULL;
1802 Log(("vboxNetAdpWinRegister: registering miniport driver...\n"));
1803 Status = NdisMRegisterMiniportDriver(pDriverObject,
1804 pRegistryPathStr,
1805 (NDIS_HANDLE)&g_VBoxNetAdpGlobals,
1806 &MChars,
1807 &g_VBoxNetAdpGlobals.hMiniportDriver);
1808 Assert(Status == STATUS_SUCCESS);
1809 if (Status == STATUS_SUCCESS)
1810 {
1811 Log(("vboxNetAdpWinRegister: successfully registered miniport driver; registering device...\n"));
1812 }
1813 else
1814 {
1815 Log(("ERROR! vboxNetAdpWinRegister: failed to register miniport driver, status=0x%x", Status));
1816 }
1817 return Status;
1818}
1819
1820
1821RT_C_DECLS_BEGIN
1822
1823NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
1824
1825RT_C_DECLS_END
1826
1827NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
1828{
1829 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1830 int rc;
1831
1832
1833 rc = RTR0Init(0);
1834 AssertRC(rc);
1835 if (RT_SUCCESS(rc))
1836 {
1837 NdisZeroMemory(&g_VBoxNetAdpGlobals, sizeof (g_VBoxNetAdpGlobals));
1838 RTListInit(&g_VBoxNetAdpGlobals.ListOfAdapters);
1839 NdisAllocateSpinLock(&g_VBoxNetAdpGlobals.Lock);
1840 NdisInitializeEvent(&g_VBoxNetAdpGlobals.EventUnloadAllowed);
1841 //g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
1842 g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
1843 g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
1844
1845 /* Initialize SupDrv interface */
1846 g_VBoxNetAdpGlobals.SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpWinQueryFactoryInterface;
1847 memcpy(g_VBoxNetAdpGlobals.SupDrvFactory.szName, "VBoxNetAdp", sizeof("VBoxNetAdp"));
1848 /* Initialize trunk factory interface */
1849 g_VBoxNetAdpGlobals.TrunkFactory.pfnRelease = vboxNetAdpWinFactoryRelease;
1850 g_VBoxNetAdpGlobals.TrunkFactory.pfnCreateAndConnect = vboxNetAdpWinFactoryCreateAndConnect;
1851
1852 rc = vboxNetAdpWinStartInitIdcThread(&g_VBoxNetAdpGlobals);
1853 if (RT_SUCCESS(rc))
1854 {
1855 Status = vboxNetAdpWinRegister(pDriverObject, pRegistryPath);
1856 Assert(Status == STATUS_SUCCESS);
1857 if (Status == NDIS_STATUS_SUCCESS)
1858 {
1859 Log(("NETADP: started successfully\n"));
1860 return STATUS_SUCCESS;
1861 }
1862 }
1863 else
1864 Status = NDIS_STATUS_FAILURE;
1865 NdisFreeSpinLock(&g_VBoxNetAdpGlobals.Lock);
1866 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
1867 RTLogDestroy(RTLogSetDefaultInstance(NULL));
1868
1869 RTR0Term();
1870 }
1871 else
1872 {
1873 Status = NDIS_STATUS_FAILURE;
1874 }
1875
1876 return Status;
1877}
1878
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