VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.c@ 24190

Last change on this file since 24190 was 24190, checked in by vboxsync, 15 years ago

netflt/win: fix packet loss caused by packet status not being reset

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 105.7 KB
Line 
1/* $Id: VBoxNetFlt-win.c 24190 2009-10-30 14:03:30Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Integration with IntNet/NetFlt
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21/*
22 * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
23 * Copyright (c) 1993-1999, Microsoft Corporation
24 */
25
26#include "VBoxNetFltCommon-win.h"
27#include <iprt/thread.h>
28
29/** represents the job element of the job queue
30 * see comments for JOB_QUEUE */
31typedef struct _JOB
32{
33 /** link in the job queue */
34 LIST_ENTRY ListEntry;
35 /** job function to be executed */
36 JOB_ROUTINE pRoutine;
37 /** parameter to be passed to the job function */
38 PVOID pContext;
39 /** event that will be fired on job completion */
40 KEVENT CompletionEvent;
41 /** true if the job manager should use the completion even for completion indication, false-otherwise*/
42 bool bUseCompletionEvent;
43} JOB, *PJOB;
44
45/**
46 * represents the queue of jobs processed by the worker thred
47 *
48 * we use the thread to process tasks which are required to be done at passive level
49 * our callbacks may be called at APC level by IntNet, there are some tasks that we can not create at APC,
50 * e.g. thread creation. This is why we schedule such jobs to the worker thread working at passive level
51 */
52typedef struct _JOB_QUEUE
53{
54 /* jobs */
55 LIST_ENTRY Jobs;
56 /* we are using ExInterlocked..List functions to access the jobs list */
57 KSPIN_LOCK Lock;
58 /** this event is used to initiate a job worker thread kill */
59 KEVENT KillEvent;
60 /** this event is used to notify a worker thread that jobs are added to the queue */
61 KEVENT NotifyEvent;
62 /** worker thread */
63 PKTHREAD pThread;
64} JOB_QUEUE, *PJOB_QUEUE;
65
66typedef struct _CREATE_INSTANCE_CONTEXT
67{
68#ifndef VBOXNETADP
69 PNDIS_STRING pOurName;
70 PNDIS_STRING pBindToName;
71#else
72 NDIS_HANDLE hMiniportAdapter;
73 NDIS_HANDLE hWrapperConfigurationContext;
74#endif
75 NDIS_STATUS Status;
76}CREATE_INSTANCE_CONTEXT, *PCREATE_INSTANCE_CONTEXT;
77
78/*contexts used for our jobs */
79/* Attach context */
80typedef struct _ATTACH_INFO
81{
82 PVBOXNETFLTINS pNetFltIf;
83 PCREATE_INSTANCE_CONTEXT pCreateContext;
84 bool fRediscovery;
85 int Status;
86}ATTACH_INFO, *PATTACH_INFO;
87
88/* general worker context */
89typedef struct _WORKER_INFO
90{
91 PVBOXNETFLTINS pNetFltIf;
92 int Status;
93}WORKER_INFO, *PWORKER_INFO;
94
95/* idc initialization */
96typedef struct _INIT_IDC_INFO
97{
98 JOB Job;
99 bool bInitialized;
100 volatile bool bStop;
101 volatile int rc;
102 KEVENT hCompletionEvent;
103}INIT_IDC_INFO, *PINIT_IDC_INFO;
104
105
106/** globals */
107
108/** global lock */
109NDIS_SPIN_LOCK g_GlobalLock;
110/** global job queue. some operations are required to be done at passive level, e.g. thread creation, adapter bind/unbind initiation,
111 * while IntNet typically calls us APC_LEVEL, so we just create a system thread in our DriverEntry and enqueue the jobs to that thread */
112static JOB_QUEUE g_JobQueue;
113/**
114 * The (common) global data.
115 */
116static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
117volatile static bool g_bIdcInitialized;
118INIT_IDC_INFO g_InitIdcInfo;
119
120#ifdef VBOX_LOOPBACK_USEFLAGS
121UINT g_fPacketDontLoopBack;
122UINT g_fPacketIsLoopedBack;
123#endif
124
125#define LIST_ENTRY_2_JOB(pListEntry) \
126 ( (PJOB)((uint8_t *)(pListEntry) - RT_OFFSETOF(JOB, ListEntry)) )
127
128static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery);
129static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis);
130static int vboxNetFltWinTryFiniIdc();
131static void vboxNetFltWinFiniNetFltBase();
132static int vboxNetFltWinInitNetFltBase();
133static int vboxNetFltWinFiniNetFlt();
134static int vboxNetFltWinStartInitIdcProbing();
135static int vboxNetFltWinStopInitIdcProbing();
136
137/** makes the current thread to sleep for the given number of miliseconds */
138DECLHIDDEN(void) vboxNetFltWinSleep(ULONG milis)
139{
140 RTThreadSleep(milis);
141}
142
143/** wait for the given device to be dereferenced */
144DECLHIDDEN(void) vboxNetFltWinWaitDereference(PADAPT_DEVICE pState)
145{
146#ifdef DEBUG
147 uint64_t StartNanoTS = RTTimeSystemNanoTS();
148 uint64_t CurNanoTS;
149#endif
150 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
151
152 while (ASMAtomicUoReadU32((volatile uint32_t *)&pState->cReferences))
153 {
154 vboxNetFltWinSleep(2);
155#ifdef DEBUG
156 CurNanoTS = RTTimeSystemNanoTS();
157 if(CurNanoTS - StartNanoTS > 20000000)
158 {
159 DBGPRINT(("device not idle"));
160 Assert(0);
161// break;
162 }
163#endif
164 }
165}
166
167/**
168 * mem functions
169 */
170/* allocates and zeroes the nonpaged memory of a given size */
171DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID* ppMemBuf, UINT cbLength)
172{
173 NDIS_STATUS fStatus = NdisAllocateMemoryWithTag(ppMemBuf, cbLength, MEM_TAG);
174 if(fStatus == NDIS_STATUS_SUCCESS)
175 {
176 NdisZeroMemory(*ppMemBuf, cbLength);
177 }
178 return fStatus;
179}
180
181/* frees memory allocated with vboxNetFltWinMemAlloc */
182DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pMemBuf)
183{
184 NdisFreeMemory(pMemBuf, 0, 0);
185}
186
187/* frees ndis buffers used on send/receive */
188static VOID vboxNetFltWinFiniBuffers(PADAPT pAdapt)
189{
190 /* NOTE: don't check for NULL since NULL is a valid handle */
191#ifndef VBOXNETADP
192 NdisFreeBufferPool(pAdapt->hSendBufferPoolHandle);
193#endif
194#ifndef VBOX_NETFLT_ONDEMAND_BIND
195 NdisFreeBufferPool(pAdapt->hRecvBufferPoolHandle);
196#endif
197}
198
199/* initializes ndis buffers used on send/receive */
200static NDIS_STATUS vboxNetFltWinInitBuffers(PADAPT pAdapt)
201{
202 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
203
204 do
205 {
206 /* NOTE: NULL is a valid handle !!! */
207#ifndef VBOXNETADP
208 NdisAllocateBufferPool(&Status,
209 &pAdapt->hSendBufferPoolHandle,
210 TX_BUFFER_POOL_SIZE);
211 Assert(Status == NDIS_STATUS_SUCCESS);
212 if (Status != NDIS_STATUS_SUCCESS)
213 {
214 break;
215 }
216#endif
217
218#ifndef VBOX_NETFLT_ONDEMAND_BIND
219 /* NOTE: NULL is a valid handle !!! */
220 NdisAllocateBufferPool(&Status,
221 &pAdapt->hRecvBufferPoolHandle,
222 RX_BUFFER_POOL_SIZE);
223 Assert(Status == NDIS_STATUS_SUCCESS);
224 if (Status != NDIS_STATUS_SUCCESS)
225 {
226#ifndef VBOXNETADP
227 NdisFreeBufferPool(pAdapt->hSendBufferPoolHandle);
228#endif
229 break;
230 }
231#endif
232 } while (FALSE);
233
234 return Status;
235}
236
237/* initializes packet info pool and allocates the cSize packet infos for the pool */
238static NDIS_STATUS vboxNetFltWinPpAllocatePacketInfoPool(PPACKET_INFO_POOL pPool, UINT cSize)
239{
240 UINT cbBufSize = sizeof(PACKET_INFO)*cSize;
241 PACKET_INFO * pPacketInfos;
242 NDIS_STATUS fStatus;
243 UINT i;
244
245 Assert(cSize > 0);
246
247 INIT_INTERLOCKED_PACKET_QUEUE(&pPool->Queue);
248
249 fStatus = vboxNetFltWinMemAlloc((PVOID*)&pPacketInfos, cbBufSize);
250
251 if(fStatus == NDIS_STATUS_SUCCESS)
252 {
253 PPACKET_INFO pInfo;
254 pPool->pBuffer = pPacketInfos;
255
256 for(i = 0; i < cSize; i++)
257 {
258 pInfo = &pPacketInfos[i];
259 vboxNetFltWinQuEnqueueTail(&pPool->Queue.Queue, pInfo);
260 pInfo->pPool = pPool;
261 }
262 }
263 else
264 {
265 Assert(0);
266 }
267
268 return fStatus;
269}
270
271/* frees the packet info pool */
272VOID vboxNetFltWinPpFreePacketInfoPool(PPACKET_INFO_POOL pPool)
273{
274 vboxNetFltWinMemFree(pPool->pBuffer);
275
276 FINI_INTERLOCKED_PACKET_QUEUE(&pPool->Queue)
277}
278
279/**
280 * copies one string to another. in case the destination string size is not enough to hold the complete source string
281 * does nothing and returns NDIS_STATUS_RESOURCES .
282 */
283DECLHIDDEN(NDIS_STATUS) vboxNetFltWinCopyString(PNDIS_STRING pDst, PNDIS_STRING pSrc)
284{
285 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
286
287 if(pDst != pSrc)
288 {
289 if(pDst->MaximumLength < pSrc->Length)
290 {
291 Assert(0);
292 Status = NDIS_STATUS_RESOURCES;
293 }
294 else
295 {
296 pDst->Length = pSrc->Length;
297
298 if(pDst->Buffer != pSrc->Buffer)
299 {
300 NdisMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length);
301 }
302 }
303 }
304 return Status;
305}
306
307/************************************************************************************
308 * PINTNETSG pSG manipulation functions
309 ************************************************************************************/
310static void vboxNetFltWinReinitSG(PINTNETSG pSG)
311{
312 pSG->pvOwnerData = NULL;
313 pSG->pvUserData = NULL;
314 pSG->pvUserData2 = NULL;
315 pSG->cUsers = 1;
316 pSG->fFlags = INTNETSG_FLAGS_TEMP;
317 pSG->cSegsUsed = 0;
318 pSG->cbTotal = 0;
319}
320
321static void vboxNetFltWinInitSG(PINTNETSG pSG, UINT cBufferCount)
322{
323 pSG->pvOwnerData = NULL;
324 pSG->pvUserData = NULL;
325 pSG->pvUserData2 = NULL;
326 pSG->cUsers = 1;
327 pSG->fFlags = INTNETSG_FLAGS_TEMP;
328 pSG->cSegsAlloc = cBufferCount;
329 pSG->cSegsUsed = 0;
330 pSG->cbTotal = 0;
331}
332
333/* moves the contents of the given NDIS_BUFFER and all other buffers chained to it to the PINTNETSG
334 * the PINTNETSG is expected to contain one segment whose bugger is large enough to maintain
335 * the contents of the given NDIS_BUFFER and all other buffers chained to it */
336static NDIS_STATUS vboxNetFltWinNdisBufferMoveToSG0(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
337{
338 UINT cbSeg = 0;
339 PINTNETSEG paSeg;
340 uint8_t * ptr;
341 PVOID pVirtualAddress;
342 UINT cbCurrentLength;
343 NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
344
345 Assert(pSG->cSegsAlloc == 1);
346
347 paSeg = pSG->aSegs;
348 ptr = (uint8_t*)paSeg->pv;
349 paSeg->cb = 0;
350 paSeg->Phys = NIL_RTHCPHYS;
351 pSG->cbTotal = 0;
352
353 Assert(paSeg->pv);
354
355 while(pBuffer)
356 {
357 NdisQueryBufferSafe(
358 pBuffer,
359 &pVirtualAddress,
360 &cbCurrentLength,
361 NormalPagePriority);
362
363 if(!pVirtualAddress)
364 {
365 fStatus = NDIS_STATUS_FAILURE;
366 break;
367 }
368
369 pSG->cbTotal += cbCurrentLength;
370 paSeg->cb += cbCurrentLength;
371 NdisMoveMemory(ptr, pVirtualAddress, cbCurrentLength);
372 ptr += cbCurrentLength;
373
374 NdisGetNextBuffer(
375 pBuffer,
376 &pBuffer);
377 }
378
379 if(fStatus == NDIS_STATUS_SUCCESS)
380 {
381 pSG->cSegsUsed = 1;
382 Assert(pSG->cbTotal == paSeg->cb);
383 }
384 return fStatus;
385}
386
387/* converts the PNDIS_BUFFER to PINTNETSG by making the PINTNETSG segments to point to the memory buffers the
388 * ndis buffer(s) point to (as opposed to vboxNetFltWinNdisBufferMoveToSG0 which copies the memory from ndis buffers(s) to PINTNETSG) */
389static NDIS_STATUS vboxNetFltWinNdisBuffersToSG(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
390{
391 UINT cbSeg = 0;
392 NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
393 PVOID pVirtualAddress;
394 UINT cbCurrentLength;
395
396 while(pBuffer)
397 {
398 NdisQueryBufferSafe(
399 pBuffer,
400 &pVirtualAddress,
401 &cbCurrentLength,
402 NormalPagePriority);
403
404 if(!pVirtualAddress) {
405 fStatus = NDIS_STATUS_FAILURE;
406 break;
407 }
408
409 pSG->cbTotal += cbCurrentLength;
410 pSG->aSegs[cbSeg].cb = cbCurrentLength;
411 pSG->aSegs[cbSeg].pv = pVirtualAddress;
412 pSG->aSegs[cbSeg].Phys = NIL_RTHCPHYS;
413 cbSeg++;
414
415 NdisGetNextBuffer(
416 pBuffer,
417 &pBuffer);
418 }
419
420 AssertFatal(cbSeg <= pSG->cSegsAlloc);
421
422 if(fStatus == NDIS_STATUS_SUCCESS)
423 {
424 pSG->cSegsUsed = cbSeg;
425 }
426
427 return fStatus;
428}
429
430static void vboxNetFltWinDeleteSG(PINTNETSG pSG)
431{
432 vboxNetFltWinMemFree(pSG);
433}
434
435static PINTNETSG vboxNetFltWinCreateSG(uint32_t cSize)
436{
437 PINTNETSG pSG;
438 NTSTATUS Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, RT_OFFSETOF(INTNETSG, aSegs[cSize]));
439 if(Status == STATUS_SUCCESS)
440 {
441 vboxNetFltWinInitSG(pSG, cSize);
442 return pSG;
443 }
444
445 return NULL;
446}
447
448/************************************************************************************
449 * packet queue functions
450 ************************************************************************************/
451
452#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
453static NDIS_STATUS vboxNetFltWinQuPostPacket(PADAPT pAdapt, PNDIS_PACKET pPacket, PINTNETSG pSG, uint32_t fFlags
454# ifdef DEBUG_NETFLT_PACKETS
455 , PNDIS_PACKET pTmpPacket
456# endif
457 )
458{
459 NDIS_STATUS fStatus;
460 PNDIS_PACKET pMyPacket;
461 bool bSrcHost = fFlags & PACKET_SRC_HOST;
462
463 LogFlow(("posting packet back to driver stack..\n"));
464
465 if(!pPacket)
466 {
467 /* INTNETSG was in the packet queue, create a new NdisPacket from INTNETSG*/
468 pMyPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, /* PADAPT */
469 pSG, /* PINTNETSG */
470 pSG, /* PVOID pBufToFree */
471 bSrcHost, /* bool bToWire */
472 false); /* bool bCopyMemory */
473
474 Assert(pMyPacket);
475
476 NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_SUCCESS);
477
478 DBG_CHECK_PACKET_AND_SG(pMyPacket, pSG);
479
480#ifdef DEBUG_NETFLT_PACKETS
481 Assert(pTmpPacket);
482
483 DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
484
485 DBG_CHECK_PACKETS(pTmpPacket, pMyPacket);
486#endif
487
488 LogFlow(("non-ndis packet info, packet created (%p)\n", pMyPacket));
489 }
490 else
491 {
492 /* NDIS_PACKET was in the packet queue */
493 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
494
495 if(!(fFlags & PACKET_MINE))
496 {
497 /* the packet is the one that was passed to us in send/receive callback
498 * According to the DDK, we can not post it further,
499 * instead we should allocate our own packet.
500 * So, allocate our own packet (pMyPacket) and copy the packet info there */
501 if(bSrcHost)
502 {
503 fStatus = vboxNetFltWinPrepareSendPacket(pAdapt, pPacket, &pMyPacket/*, true*/);
504 LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
505 }
506 else
507 {
508 fStatus = vboxNetFltWinPrepareRecvPacket(pAdapt, pPacket, &pMyPacket, false);
509 LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
510 }
511 }
512 else
513 {
514 /* the packet enqueued is ours, simply assign pMyPacket and zero pPacket */
515 pMyPacket = pPacket;
516 pPacket = NULL;
517 }
518 Assert(pMyPacket);
519 }
520
521 if (pMyPacket)
522 {
523 /* we have successfuly initialized our packet, post it to the host or to the wire */
524 if(bSrcHost)
525 {
526#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
527 vboxNetFltWinLbPutSendPacket(pAdapt, pMyPacket, false /* bFromIntNet */);
528#endif
529 NdisSend(&fStatus, pAdapt->hBindingHandle, pMyPacket);
530
531 if (fStatus != NDIS_STATUS_PENDING)
532 {
533#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
534 /* the status is NOT pending, complete the packet */
535 bool bTmp = vboxNetFltWinLbRemoveSendPacket(pAdapt, pMyPacket);
536 Assert(bTmp);
537#endif
538 if(pPacket)
539 {
540 LogFlow(("status is not pending, completing packet (%p)\n", pPacket));
541#ifndef WIN9X
542 NdisIMCopySendCompletePerPacketInfo (pPacket, pMyPacket);
543#endif
544 NdisFreePacket(pMyPacket);
545 }
546 else
547 {
548 /* should never be here since the PINTNETSG is stored only when the underlying miniport
549 * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
550 * the "from-host" packets */
551 Assert(0);
552 LogFlow(("status is not pending, freeing myPacket (%p)\n", pMyPacket));
553 vboxNetFltWinFreeSGNdisPacket(pMyPacket, false);
554 }
555 }
556 }
557 else
558 {
559 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pMyPacket, 1);
560
561 fStatus = NDIS_STATUS_PENDING;
562 /* the packet receive completion is always indicated via MiniportReturnPacket */
563 }
564 }
565 else
566 {
567 /*we failed to create our packet */
568 Assert(0);
569 fStatus = NDIS_STATUS_FAILURE;
570 }
571
572 return fStatus;
573}
574#endif
575
576static bool vboxNetFltWinQuProcessInfo(PVBOXNETFLTINS pNetFltIf, PPACKET_QUEUE_WORKER pWorker, PPACKET_INFO pInfo)
577{
578 PNDIS_PACKET pPacket = NULL;
579 PINTNETSG pSG = NULL;
580 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pNetFltIf);
581 UINT fFlags;
582 NDIS_STATUS Status;
583#ifndef VBOXNETADP
584 bool bSrcHost;
585 bool bPending;
586 bool bDropIt;
587#endif
588#ifdef DEBUG_NETFLT_PACKETS
589 /* packet used for matching */
590 PNDIS_PACKET pTmpPacket = NULL;
591#endif
592
593 fFlags = GET_FLAGS_FROM_INFO(pInfo);
594#ifndef VBOXNETADP
595 bSrcHost = (fFlags & PACKET_SRC_HOST) != 0;
596#endif
597
598 /* we first need to obtain the INTNETSG to be passed to intnet */
599
600 /* the queue may contain two "types" of packets:
601 * the NDIS_PACKET and the INTNETSG.
602 * I.e. on send/receive we typically enqueue the NDIS_PACKET passed to us by ndis,
603 * however in case our ProtocolReceive is called or the packet's status is set to NDIS_STSTUS_RESOURCES
604 * in ProtocolReceivePacket, we must return the packet immediately on ProtocolReceive*** exit
605 * In this case we allocate the INTNETSG, copy the ndis packet data there and enqueue it.
606 * In this case the packet info flags has the PACKET_SG fag set
607 *
608 * Besides that the NDIS_PACKET contained in the queue could be either the one passed to us in our send/receive callback
609 * or the one created by us. The latter is possible in case our ProtocolReceive callback is called and we call NdisTransferData
610 * in this case we need to allocate the packet the data to be transfered to.
611 * If the enqueued packet is the one allocated by us the PACKET_MINE flag is set
612 * */
613 if((fFlags & PACKET_SG) == 0)
614 {
615 /* we have NDIS_PACKET enqueued, we need to convert it to INTNETSG to be passed to intnet */
616 PNDIS_BUFFER pCurrentBuffer = NULL;
617 UINT cBufferCount;
618 UINT uBytesCopied = 0;
619 UINT cbPacketLength;
620
621 pPacket = (PNDIS_PACKET)GET_PACKET_FROM_INFO(pInfo);
622 LogFlow(("ndis packet info, packet (%p)\n", pPacket));
623
624 LogFlow(("preparing pSG"));
625 NdisQueryPacket(pPacket,
626 NULL,
627 &cBufferCount,
628 &pCurrentBuffer,
629 &cbPacketLength);
630
631
632 Assert(cBufferCount);
633
634 /* we can not allocate the INTNETSG on stack since in this case we may get stack overflow
635 * somewhere outside of our driver (3 pages of system thread stack does not seem to be enough)
636 *
637 * since we have a "serialized" packet processing, i.e. all packets are being processed and passed
638 * to intnet by this thread, we just use one previously allocated INTNETSG which is stored in PADAPT */
639 pSG = pWorker->pSG;
640
641 if(cBufferCount > pSG->cSegsAlloc)
642 {
643 pSG = vboxNetFltWinCreateSG(cBufferCount + 2);
644 if(pSG)
645 {
646 vboxNetFltWinDeleteSG(pWorker->pSG);
647 pWorker->pSG = pSG;
648 }
649 else
650 {
651 LogRel(("Failed to reallocate the pSG\n"));
652 }
653 }
654
655 if(pSG)
656 {
657 /* reinitialize */
658 vboxNetFltWinReinitSG(pSG);
659
660 /* convert the ndis buffers to INTNETSG */
661 Status = vboxNetFltWinNdisBuffersToSG(pCurrentBuffer, pSG);
662 if(Status != NDIS_STATUS_SUCCESS)
663 {
664 pSG = NULL;
665 }
666 else
667 {
668 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
669 }
670 }
671 }
672 else
673 {
674 /* we have the INTNETSG enqueued. (see the above comment explaining why/when this may happen)
675 * just use the INTNETSG to pass it to intnet */
676#ifndef VBOX_NETFLT_ONDEMAND_BIND
677 #ifndef VBOXNETADP
678 /* the PINTNETSG is stored only when the underlying miniport
679 * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
680 * the "from-host" packedts */
681 Assert(!bSrcHost);
682 #endif
683#else
684 /* we have both host and wire in ProtocolReceive */
685#endif
686 pSG = (PINTNETSG)GET_PACKET_FROM_INFO(pInfo);
687
688 LogFlow(("not ndis packet info, pSG (%p)\n", pSG));
689 }
690
691#ifdef DEBUG_NETFLT_PACKETS
692 if(!pPacket && !pTmpPacket)
693 {
694 /* create tmp packet that woud be used for matching */
695 pTmpPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, /* PADAPT */
696 pSG, /* PINTNETSG */
697 pSG, /* PVOID pBufToFree */
698 bSrcHost, /* bool bToWire */
699 true); /* bool bCopyMemory */
700
701 NDIS_SET_PACKET_STATUS(pTmpPacket, NDIS_STATUS_SUCCESS);
702
703 DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
704
705 Assert(pTmpPacket);
706 }
707#endif
708 do
709 {
710#ifndef VBOXNETADP
711 /* the pSG was successfully initialized, post it to the netFlt*/
712#ifndef VBOX_NETFLT_ONDEMAND_BIND
713 bDropIt =
714#endif
715 pSG ? pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, pSG,
716 bSrcHost ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE
717 )
718 : false;
719#else
720 if(pSG)
721 {
722 pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
723 STATISTIC_INCREASE(pAdapt->cTxSuccess);
724 }
725 else
726 {
727 STATISTIC_INCREASE(pAdapt->cTxError);
728 }
729#endif
730
731#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
732 if(!bDropIt)
733 {
734 Status = vboxNetFltWinQuPostPacket(pAdapt, pPacket, pSG, fFlags
735# ifdef DEBUG_NETFLT_PACKETS
736 , pTmpPacket
737# endif
738 );
739
740 if(Status == NDIS_STATUS_PENDING)
741 {
742 /* we will process packet completion in the completion routine */
743 bPending = true;
744 break;
745 }
746 }
747 else
748#endif
749 {
750 Status = NDIS_STATUS_SUCCESS;
751 }
752
753 /* drop it */
754 if(pPacket)
755 {
756 if(!(fFlags & PACKET_MINE))
757 {
758#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
759 /* complete the packets */
760 if(fFlags & PACKET_SRC_HOST)
761 {
762#endif
763#ifndef VBOX_NETFLT_ONDEMAND_BIND
764/* NDIS_SET_PACKET_STATUS(pPacket, Status); */
765 NdisMSendComplete(pAdapt->hMiniportHandle, pPacket, Status);
766#endif
767#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
768 }
769 else
770 {
771#endif
772#ifndef VBOXNETADP
773 NdisReturnPackets(&pPacket, 1);
774#endif
775#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
776 }
777#endif
778 }
779 else
780 {
781#ifndef VBOX_NETFLT_ONDEMAND_BIND
782 Assert(!(fFlags & PACKET_SRC_HOST));
783#endif
784 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
785 }
786 }
787 else
788 {
789 Assert(pSG);
790 vboxNetFltWinMemFree(pSG);
791 }
792#ifndef VBOXNETADP
793 bPending = false;
794#endif
795 } while(0);
796
797#ifdef DEBUG_NETFLT_PACKETS
798 if(pTmpPacket)
799 {
800 vboxNetFltWinFreeSGNdisPacket(pTmpPacket, true);
801 }
802#endif
803
804#ifndef VBOXNETADP
805 return bPending;
806#else
807 return false;
808#endif
809}
810/*
811 * thread start function for the thread which processes the packets enqueued in our send and receive callbacks called by ndis
812 *
813 * ndis calls us at DISPATCH_LEVEL, while IntNet is using kernel functions which require Irql<DISPATCH_LEVEL
814 * this is why we can not immediately post packets to IntNet from our sen/receive callbacks
815 * instead we put the incoming packets to the queue and maintain the system thread running at passive level
816 * which processes the queue and posts the packets to IntNet, and further to the host or to the wire.
817 */
818static VOID vboxNetFltWinQuPacketQueueWorkerThreadProc(PVBOXNETFLTINS pNetFltIf)
819{
820 bool fResume = true;
821 NTSTATUS fStatus;
822 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pNetFltIf);
823 PPACKET_QUEUE_WORKER pWorker = &pNetFltIf->u.s.PacketQueueWorker;
824
825 /* two events we're waiting is "kill" and "notify" events
826 * the former is used for the thread termination
827 * the latter gets fired each time the packet is added to the queue */
828 PVOID pEvents[] = {
829 (PVOID) &pWorker->KillEvent,
830 (PVOID) &pWorker->NotifyEvent,
831 };
832
833 while(fResume)
834 {
835 uint32_t cNumProcessed;
836 uint32_t cNumPostedToHostWire;
837
838 fStatus = KeWaitForMultipleObjects(2, pEvents, WaitAny, Executive, KernelMode, FALSE,
839 NULL, NULL);
840 if(!NT_SUCCESS(fStatus) || fStatus == STATUS_WAIT_0)
841 {
842 /* "kill" event was set
843 * will process queued packets and exit */
844 fResume = false;
845 }
846
847 LogFlow(("==> processing vboxNetFltWinQuPacketQueueWorkerThreadProc\n"));
848
849 cNumProcessed = 0;
850 cNumPostedToHostWire = 0;
851
852 do
853 {
854 PPACKET_INFO pInfo;
855
856#ifdef DEBUG_NETFLT_PACKETS
857 /* packet used for matching */
858 PNDIS_PACKET pTmpPacket = NULL;
859#endif
860
861 /*TODO: FIXME: !!! the better approach for performance would be to dequeue all packets at once
862 * and then go through all dequeued packets
863 * the same should be done for enqueue !!! */
864 pInfo = vboxNetFltWinQuInterlockedDequeueHead(&pWorker->PacketQueue);
865
866 if(!pInfo)
867 {
868 break;
869 }
870
871 LogFlow(("==> found info (%p)\n", pInfo));
872
873 if(vboxNetFltWinQuProcessInfo(pNetFltIf, pWorker, pInfo))
874 {
875 cNumPostedToHostWire++;
876 }
877
878 vboxNetFltWinPpFreePacketInfo(pInfo);
879
880 cNumProcessed++;
881 } while(TRUE);
882
883 if(cNumProcessed)
884 {
885 vboxNetFltWinDecReferenceNetFlt(pNetFltIf, cNumProcessed);
886
887 Assert(cNumProcessed >= cNumPostedToHostWire);
888
889 if(cNumProcessed != cNumPostedToHostWire)
890 {
891 vboxNetFltWinDecReferenceAdapt(pAdapt, cNumProcessed - cNumPostedToHostWire);
892 }
893 }
894 }
895
896 PsTerminateSystemThread(STATUS_SUCCESS);
897}
898
899/**
900 * thread start function for the job processing thread
901 *
902 * see comments for PJOB_QUEUE
903 */
904static VOID vboxNetFltWinJobWorkerThreadProc(PJOB_QUEUE pQueue)
905{
906 bool fResume = true;
907 NTSTATUS Status;
908
909 PVOID pEvents[] = {
910 (PVOID) &pQueue->KillEvent,
911 (PVOID) &pQueue->NotifyEvent,
912 };
913
914 do
915 {
916 Status = KeWaitForMultipleObjects(2, pEvents, WaitAny, Executive, KernelMode, FALSE,
917 NULL, NULL);
918 Assert(NT_SUCCESS(Status));
919 if(!NT_SUCCESS(Status) || Status == STATUS_WAIT_0)
920 {
921 /* will process queued jobs and exit */
922 Assert(Status == STATUS_WAIT_0);
923 fResume = false;
924 }
925
926 do
927 {
928 PLIST_ENTRY pJobEntry = ExInterlockedRemoveHeadList(&pQueue->Jobs, &pQueue->Lock);
929 PJOB pJob;
930
931 if(!pJobEntry)
932 break;
933
934 pJob = LIST_ENTRY_2_JOB(pJobEntry);
935
936 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
937 pJob->pRoutine(pJob->pContext);
938 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
939
940 if(pJob->bUseCompletionEvent)
941 {
942 KeSetEvent(&pJob->CompletionEvent, 1, FALSE);
943 }
944 } while(TRUE);
945 } while(fResume);
946
947 Assert(Status == STATUS_WAIT_0);
948
949 PsTerminateSystemThread(STATUS_SUCCESS);
950}
951
952/**
953 * enqueues the job to the job queue to be processed by the job worker thread
954 * see comments for PJOB_QUEUE
955 */
956static VOID vboxNetFltWinJobEnqueueJob(PJOB_QUEUE pQueue, PJOB pJob, bool bEnqueueHead)
957{
958 if(bEnqueueHead)
959 {
960 ExInterlockedInsertHeadList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
961 }
962 else
963 {
964 ExInterlockedInsertTailList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
965 }
966
967 KeSetEvent(&pQueue->NotifyEvent, 1, FALSE);
968}
969
970DECLINLINE(VOID) vboxNetFltWinJobInit(PJOB pJob, JOB_ROUTINE pRoutine, PVOID pContext, bool bUseEvent)
971{
972 pJob->pRoutine = pRoutine;
973 pJob->pContext = pContext;
974 pJob->bUseCompletionEvent = bUseEvent;
975 if(bUseEvent)
976 KeInitializeEvent(&pJob->CompletionEvent, NotificationEvent, FALSE);
977}
978
979/**
980 * enqueues the job to the job queue to be processed by the job worker thread and
981 * blocks until the job is done
982 * see comments for PJOB_QUEUE
983 */
984static VOID vboxNetFltWinJobSynchExec(PJOB_QUEUE pQueue, JOB_ROUTINE pRoutine, PVOID pContext)
985{
986 JOB Job;
987
988 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
989
990 vboxNetFltWinJobInit(&Job, pRoutine, pContext, true);
991
992 vboxNetFltWinJobEnqueueJob(pQueue, &Job, false);
993
994 KeWaitForSingleObject(&Job.CompletionEvent, Executive, KernelMode, FALSE, NULL);
995}
996
997/**
998 * enqueues the job to be processed by the job worker thread at passive level and
999 * blocks until the job is done
1000 */
1001DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(JOB_ROUTINE pRoutine, PVOID pContext)
1002{
1003 vboxNetFltWinJobSynchExec(&g_JobQueue, pRoutine, pContext);
1004}
1005
1006/**
1007 * helper function used for system thread creation
1008 */
1009static NTSTATUS vboxNetFltWinQuCreateSystemThread(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
1010{
1011 NTSTATUS fStatus;
1012 HANDLE hThread;
1013 OBJECT_ATTRIBUTES fObjectAttributes;
1014
1015 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1016
1017 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
1018 NULL, NULL);
1019
1020 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
1021 &fObjectAttributes, NULL, NULL,
1022 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
1023 if (!NT_SUCCESS(fStatus))
1024 return fStatus;
1025
1026 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
1027 KernelMode, (PVOID*) ppThread, NULL);
1028 ZwClose(hThread);
1029 return STATUS_SUCCESS;
1030}
1031
1032/**
1033 * initialize the job queue
1034 * see comments for PJOB_QUEUE
1035 */
1036static NTSTATUS vboxNetFltWinJobInitQueue(PJOB_QUEUE pQueue)
1037{
1038 NTSTATUS fStatus;
1039
1040 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1041
1042 NdisZeroMemory(pQueue, sizeof(JOB_QUEUE));
1043
1044 KeInitializeEvent(&pQueue->KillEvent, NotificationEvent, FALSE);
1045
1046 KeInitializeEvent(&pQueue->NotifyEvent, SynchronizationEvent, FALSE);
1047
1048 InitializeListHead(&pQueue->Jobs);
1049
1050 fStatus = vboxNetFltWinQuCreateSystemThread(&pQueue->pThread, (PKSTART_ROUTINE)vboxNetFltWinJobWorkerThreadProc, pQueue);
1051 if(fStatus != STATUS_SUCCESS)
1052 {
1053 pQueue->pThread = NULL;
1054 }
1055 else
1056 {
1057 Assert(pQueue->pThread);
1058 }
1059
1060 return fStatus;
1061}
1062
1063/**
1064 * deinitialize the job queue
1065 * see comments for PJOB_QUEUE
1066 */
1067static void vboxNetFltWinJobFiniQueue(PJOB_QUEUE pQueue)
1068{
1069 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1070
1071 if(pQueue->pThread)
1072 {
1073 KeSetEvent(&pQueue->KillEvent, 0, FALSE);
1074
1075 KeWaitForSingleObject(pQueue->pThread, Executive,
1076 KernelMode, FALSE, NULL);
1077 }
1078}
1079
1080/**
1081 * initializes the packet queue
1082 * */
1083DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance)
1084{
1085 NTSTATUS Status;
1086 PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
1087
1088 AssertFatal(!pWorker->pSG);
1089
1090 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1091
1092 KeInitializeEvent(&pWorker->KillEvent, NotificationEvent, FALSE);
1093
1094 KeInitializeEvent(&pWorker->NotifyEvent, SynchronizationEvent, FALSE);
1095
1096 INIT_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
1097
1098 do
1099 {
1100 Status = vboxNetFltWinPpAllocatePacketInfoPool(&pWorker->PacketInfoPool, PACKET_INFO_POOL_SIZE);
1101
1102 if(Status == NDIS_STATUS_SUCCESS)
1103 {
1104 pWorker->pSG = vboxNetFltWinCreateSG(PACKET_QUEUE_SG_SEGS_ALLOC);
1105 if(!pWorker->pSG)
1106 {
1107 Status = STATUS_INSUFFICIENT_RESOURCES;
1108 break;
1109 }
1110
1111 Status = vboxNetFltWinQuCreateSystemThread(&pWorker->pThread, (PKSTART_ROUTINE)vboxNetFltWinQuPacketQueueWorkerThreadProc, pInstance);
1112 if(Status != STATUS_SUCCESS)
1113 {
1114 vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
1115 vboxNetFltWinMemFree(pWorker->pSG);
1116 pWorker->pSG = NULL;
1117 break;
1118 }
1119 }
1120
1121 } while(0);
1122
1123 return Status;
1124}
1125
1126/*
1127 * deletes the packet queue
1128 */
1129DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance)
1130{
1131 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1132 PINTNETSG pSG;
1133 PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
1134 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1135
1136// Assert(pAdapt->pPacketQueueSG);
1137
1138 /* using the pPacketQueueSG as an indicator that the packet queue is initialized */
1139 RTSpinlockAcquire((pInstance)->hSpinlock, &Tmp);
1140 if(pWorker->pSG)
1141 {
1142 pSG = pWorker->pSG;
1143 pWorker->pSG = NULL;
1144 RTSpinlockRelease((pInstance)->hSpinlock, &Tmp);
1145 KeSetEvent(&pWorker->KillEvent, 0, FALSE);
1146
1147 KeWaitForSingleObject(pWorker->pThread, Executive,
1148 KernelMode, FALSE, NULL);
1149
1150 vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
1151
1152 vboxNetFltWinDeleteSG(pSG);
1153
1154 FINI_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
1155 }
1156 else
1157 {
1158 RTSpinlockRelease((pInstance)->hSpinlock, &Tmp);
1159 }
1160}
1161
1162/*
1163 * creates the INTNETSG containing one segment pointing to the buffer of size cbBufSize
1164 * the INTNETSG created should be cleaned with vboxNetFltWinMemFree
1165 */
1166DECLHIDDEN(NDIS_STATUS) vboxNetFltWinAllocSG(UINT cbBufSize, PINTNETSG *ppSG)
1167{
1168 UINT cbBufferOffset;
1169 UINT cbMemSize;
1170 NDIS_STATUS Status;
1171 PINTNETSG pSG;
1172
1173 /* allocation:
1174 * 1. SG_PACKET - with one aSegs pointing to
1175 * 2. buffer of cbPacketLength containing the entire packet */
1176 cbBufferOffset = sizeof(INTNETSG);
1177 /* make sure the buffer is aligned */
1178 if((cbBufferOffset & (sizeof(PVOID) - 1)) != 0)
1179 {
1180 cbBufferOffset += sizeof(PVOID);
1181 cbBufferOffset &= ~(sizeof(PVOID) - 1);
1182 }
1183
1184 cbMemSize = cbBufferOffset + cbBufSize;
1185 Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, cbMemSize);
1186 if(Status == NDIS_STATUS_SUCCESS)
1187 {
1188 vboxNetFltWinInitSG(pSG, 1);
1189 pSG->aSegs[0].pv = (uint8_t *)pSG + cbBufferOffset;
1190 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
1191 pSG->aSegs[0].cb = cbBufSize;
1192 pSG->cbTotal = cbBufSize;
1193 pSG->cSegsUsed = 1;
1194
1195 LogFlow(("pSG created (%p)\n", pSG));
1196
1197 *ppSG = pSG;
1198 }
1199 return Status;
1200}
1201
1202/**
1203 * put the packet info to the queue
1204 */
1205DECLINLINE(void) vboxNetFltWinQuEnqueueInfo(PPACKET_QUEUE_WORKER pWorker, PPACKET_INFO pInfo)
1206{
1207 vboxNetFltWinQuInterlockedEnqueueTail(&pWorker->PacketQueue, pInfo);
1208
1209 KeSetEvent(&pWorker->NotifyEvent, IO_NETWORK_INCREMENT, FALSE);
1210}
1211
1212
1213/**
1214 * puts the packet to the queue
1215 *
1216 * @return NDIST_STATUS_SUCCESS iff the packet was enqueued successfully
1217 * and error status otherwise.
1218 * NOTE: that the success status does NOT mean that the packet processing is completed, but only that it was enqueued successfully
1219 * the packet can be returned to the caller protocol/moniport only in case the bReleasePacket was set to true (in this case the copy of the packet was enqueued)
1220 * or if vboxNetFltWinQuEnqueuePacket failed, i.e. the packet was NOT enqueued
1221 */
1222DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags)
1223{
1224 PPACKET_INFO pInfo;
1225 PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
1226 NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
1227
1228 do
1229 {
1230 if(fPacketFlags & PACKET_COPY)
1231 {
1232 PNDIS_BUFFER pBuffer = NULL;
1233 UINT cBufferCount;
1234 UINT uBytesCopied = 0;
1235 UINT cbPacketLength;
1236 PINTNETSG pSG;
1237
1238 /* the packet is Ndis packet */
1239 Assert(!(fPacketFlags & PACKET_SG));
1240 Assert(!(fPacketFlags & PACKET_MINE));
1241
1242 NdisQueryPacket((PNDIS_PACKET)pPacket,
1243 NULL,
1244 &cBufferCount,
1245 &pBuffer,
1246 &cbPacketLength);
1247
1248
1249 Assert(cBufferCount);
1250
1251 fStatus = vboxNetFltWinAllocSG(cbPacketLength, &pSG);
1252 if(fStatus != NDIS_STATUS_SUCCESS)
1253 {
1254 Assert(0);
1255 break;
1256 }
1257
1258 pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
1259
1260 if(!pInfo)
1261 {
1262 Assert(0);
1263 /* TODO: what status to set? */
1264 fStatus = NDIS_STATUS_FAILURE;
1265 vboxNetFltWinMemFree(pSG);
1266 break;
1267 }
1268
1269 Assert(pInfo->pPool);
1270
1271 /* the packet we are queueing is SG, add PACKET_SG to flags */
1272 SET_FLAGS_TO_INFO(pInfo, fPacketFlags | PACKET_SG);
1273 SET_PACKET_TO_INFO(pInfo, pSG);
1274
1275 fStatus = vboxNetFltWinNdisBufferMoveToSG0(pBuffer, pSG);
1276 if(fStatus != NDIS_STATUS_SUCCESS)
1277 {
1278 Assert(0);
1279 vboxNetFltWinPpFreePacketInfo(pInfo);
1280 vboxNetFltWinMemFree(pSG);
1281 break;
1282 }
1283
1284 DBG_CHECK_PACKET_AND_SG((PNDIS_PACKET)pPacket, pSG);
1285 }
1286 else
1287 {
1288 pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
1289
1290 if(!pInfo)
1291 {
1292 Assert(0);
1293 /* TODO: what status to set? */
1294 fStatus = NDIS_STATUS_FAILURE;
1295 break;
1296 }
1297
1298 Assert(pInfo->pPool);
1299
1300 SET_FLAGS_TO_INFO(pInfo, fPacketFlags);
1301 SET_PACKET_TO_INFO(pInfo, pPacket);
1302 }
1303
1304 vboxNetFltWinQuEnqueueInfo(pWorker, pInfo);
1305
1306 } while(0);
1307
1308 return fStatus;
1309}
1310
1311#ifndef VBOX_NETFLT_ONDEMAND_BIND
1312/*
1313 * ioctl i/f
1314 */
1315static NTSTATUS
1316vboxNetFltWinPtDispatchIoctl(
1317 IN PDEVICE_OBJECT pDeviceObject,
1318 IN PIO_STACK_LOCATION pIrpStack)
1319{
1320#if 0
1321 ULONG CtlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
1322 NTSTATUS Status = STATUS_SUCCESS;
1323 int rc;
1324
1325 switch(CtlCode)
1326 {
1327
1328 case VBOXNETFLT_WIN_IOCTL_INIT:
1329 rc = vboxNetFltWinInitIdc();
1330 if(!RT_SUCCESS(rc))
1331 {
1332 Status = STATUS_UNSUCCESSFUL;
1333 }
1334 break;
1335 case VBOXNETFLT_WIN_IOCTL_FINI:
1336 /* we are finalizing during unload */
1337 /* TODO: FIXME: need to prevent driver unload that can occur in case IntNet is connected to us,
1338 * but we are not bound to any adapters */
1339/* rc = vboxNetFltWinTryFiniIdc();
1340 if(!RT_SUCCESS(rc))
1341 {
1342 Status = STATUS_UNSUCCESSFUL;
1343 }
1344 */
1345 break;
1346
1347 default:
1348 Status = STATUS_NOT_SUPPORTED;
1349 break;
1350 }
1351
1352 return Status;
1353#else
1354 return STATUS_NOT_SUPPORTED;
1355#endif
1356}
1357
1358/*
1359Routine Description:
1360
1361 Process IRPs sent to this device.
1362
1363Arguments:
1364
1365 DeviceObject - pointer to a device object
1366 Irp - pointer to an I/O Request Packet
1367
1368Return Value:
1369
1370 NTSTATUS - STATUS_SUCCESS always - change this when adding
1371 real code to handle ioctls.
1372
1373*/
1374DECLHIDDEN(NTSTATUS)
1375vboxNetFltWinPtDispatch(
1376 IN PDEVICE_OBJECT pDeviceObject,
1377 IN PIRP pIrp
1378 )
1379{
1380 PIO_STACK_LOCATION pIrpStack;
1381 NTSTATUS Status = STATUS_SUCCESS;
1382
1383 LogFlow(("==>Pt Dispatch\n"));
1384 pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
1385
1386
1387 switch (pIrpStack->MajorFunction)
1388 {
1389 case IRP_MJ_CREATE:
1390 break;
1391
1392 case IRP_MJ_CLEANUP:
1393 break;
1394
1395 case IRP_MJ_CLOSE:
1396 break;
1397
1398 case IRP_MJ_DEVICE_CONTROL:
1399 Status = vboxNetFltWinPtDispatchIoctl(pDeviceObject, pIrpStack);
1400 break;
1401 default:
1402 break;
1403 }
1404
1405 pIrp->IoStatus.Status = Status;
1406 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1407
1408 LogFlow(("<== Pt Dispatch\n"));
1409
1410 return Status;
1411
1412}
1413#endif
1414
1415/*
1416 * netflt
1417 */
1418#ifndef VBOXNETADP
1419/*
1420 * NOTE! the routine is NOT re-enterable for the given pAdapt
1421 * the serialization is not implemented for performance reasons
1422 * since we are assuming the caller serializes the requests as IntNet does
1423 */
1424static NDIS_STATUS vboxNetFltWinSynchNdisRequest(PADAPT pAdapt, PNDIS_REQUEST pRequest)
1425{
1426 int rc;
1427
1428 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1429
1430 /* 1. serialize */
1431 rc = RTSemFastMutexRequest(pAdapt->hSynchRequestMutex); AssertRC(rc);
1432 if(RT_SUCCESS(rc))
1433 {
1434 NDIS_STATUS fRequestStatus = NDIS_STATUS_SUCCESS;
1435
1436 /* 2. set pAdapt->pSynchRequest */
1437 Assert(!pAdapt->pSynchRequest);
1438 pAdapt->pSynchRequest = pRequest;
1439
1440 /* 3. call NdisRequest */
1441 NdisRequest(&fRequestStatus, pAdapt->hBindingHandle, pRequest);
1442
1443 if(fRequestStatus == NDIS_STATUS_PENDING)
1444 {
1445 /* 3.1 if pending wait and assign the resulting status */
1446 KeWaitForSingleObject(&pAdapt->hSynchCompletionEvent, Executive,
1447 KernelMode, FALSE, NULL);
1448
1449 fRequestStatus = pAdapt->fSynchCompletionStatus;
1450 }
1451
1452 /* 4. clear the pAdapt->pSynchRequest */
1453 pAdapt->pSynchRequest = NULL;
1454
1455 RTSemFastMutexRelease(pAdapt->hSynchRequestMutex); AssertRC(rc);
1456 return fRequestStatus;
1457 }
1458 return NDIS_STATUS_FAILURE;
1459}
1460
1461
1462DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PADAPT pAdapt, PRTMAC pMac)
1463{
1464 NDIS_REQUEST request;
1465 NDIS_STATUS status;
1466 request.RequestType = NdisRequestQueryInformation;
1467 request.DATA.QUERY_INFORMATION.InformationBuffer = pMac;
1468 request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(RTMAC);
1469 request.DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;
1470 status = vboxNetFltWinSynchNdisRequest(pAdapt, &request);
1471 if(status != NDIS_STATUS_SUCCESS)
1472 {
1473 /* TODO */
1474 Assert(0);
1475 }
1476
1477 return status;
1478
1479}
1480
1481DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PADAPT pAdapt, NDIS_PHYSICAL_MEDIUM * pMedium)
1482{
1483 NDIS_REQUEST Request;
1484 NDIS_STATUS Status;
1485 Request.RequestType = NdisRequestQueryInformation;
1486 Request.DATA.QUERY_INFORMATION.InformationBuffer = pMedium;
1487 Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_PHYSICAL_MEDIUM);
1488 Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_PHYSICAL_MEDIUM;
1489 Status = vboxNetFltWinSynchNdisRequest(pAdapt, &Request);
1490 if(Status != NDIS_STATUS_SUCCESS)
1491 {
1492 if(Status == NDIS_STATUS_NOT_SUPPORTED || Status == NDIS_STATUS_NOT_RECOGNIZED || Status == NDIS_STATUS_INVALID_OID)
1493 {
1494 Status = NDIS_STATUS_NOT_SUPPORTED;
1495 }
1496 else
1497 {
1498 LogRel(("OID_GEN_PHYSICAL_MEDIUM failed: Status (0x%x)", Status));
1499 Assert(0);
1500 }
1501 }
1502 return Status;
1503}
1504
1505DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PADAPT pAdapt)
1506{
1507 /** @todo r=bird: This is too slow and is probably returning the wrong
1508 * information. What we're interested in is whether someone besides us
1509 * has put the interface into promiscuous mode. */
1510 NDIS_REQUEST request;
1511 NDIS_STATUS status;
1512 ULONG filter;
1513 Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
1514 request.RequestType = NdisRequestQueryInformation;
1515 request.DATA.QUERY_INFORMATION.InformationBuffer = &filter;
1516 request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(filter);
1517 request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
1518 status = vboxNetFltWinSynchNdisRequest(pAdapt, &request);
1519 if(status != NDIS_STATUS_SUCCESS)
1520 {
1521 /* TODO */
1522 Assert(0);
1523 return false;
1524 }
1525 return (filter & NDIS_PACKET_TYPE_PROMISCUOUS) != 0;
1526}
1527
1528DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PADAPT pAdapt, bool bYes)
1529{
1530 Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
1531 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
1532 {
1533 NDIS_REQUEST Request;
1534 NDIS_STATUS fStatus;
1535 ULONG fFilter;
1536 ULONG fExpectedFilter;
1537 ULONG fOurFilter;
1538 Request.RequestType = NdisRequestQueryInformation;
1539 Request.DATA.QUERY_INFORMATION.InformationBuffer = &fFilter;
1540 Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(fFilter);
1541 Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
1542 fStatus = vboxNetFltWinSynchNdisRequest(pAdapt, &Request);
1543 if(fStatus != NDIS_STATUS_SUCCESS)
1544 {
1545 /* TODO: */
1546 Assert(0);
1547 return fStatus;
1548 }
1549
1550 if(!pAdapt->bUpperProtSetFilterInitialized)
1551 {
1552 /* the cache was not initialized yet, initiate it with the current filter value */
1553 pAdapt->fUpperProtocolSetFilter = fFilter;
1554 pAdapt->bUpperProtSetFilterInitialized = true;
1555 }
1556
1557
1558 if(bYes)
1559 {
1560 fExpectedFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
1561 fOurFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
1562 }
1563 else
1564 {
1565 fExpectedFilter = pAdapt->fUpperProtocolSetFilter;
1566 fOurFilter = 0;
1567 }
1568
1569 if(fExpectedFilter != fFilter)
1570 {
1571 Request.RequestType = NdisRequestSetInformation;
1572 Request.DATA.SET_INFORMATION.InformationBuffer = &fExpectedFilter;
1573 Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(fExpectedFilter);
1574 Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
1575 fStatus = vboxNetFltWinSynchNdisRequest(pAdapt, &Request);
1576 if(fStatus != NDIS_STATUS_SUCCESS)
1577 {
1578 /* TODO */
1579 Assert(0);
1580 return fStatus;
1581 }
1582 }
1583 pAdapt->fOurSetFilter = fOurFilter;
1584 return fStatus;
1585 }
1586 return NDIS_STATUS_NOT_SUPPORTED;
1587}
1588#else /* if defined VBOXNETADP */
1589
1590/**
1591 * Generates a new unique MAC address based on our vendor ID
1592 */
1593DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac)
1594{
1595 /* temporary use a time info */
1596 uint64_t NanoTS = RTTimeSystemNanoTS();
1597 pMac->au8[0] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 16) & 0xff);
1598 pMac->au8[1] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 8) & 0xff);
1599 pMac->au8[2] = (uint8_t)(VBOXNETADP_VENDOR_ID & 0xff);
1600 pMac->au8[3] = (uint8_t)(NanoTS & 0xff0000);
1601 pMac->au16[2] = (uint16_t)(NanoTS & 0xffff);
1602}
1603
1604DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
1605{
1606 static const char s_achDigits[17] = "0123456789abcdef";
1607 uint8_t u8;
1608 int i;
1609 PWSTR pString;
1610
1611 /* validate parameters */
1612 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
1613 AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
1614 AssertReturn(pNdisString->MaximumLength >= 13*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
1615
1616 pString = pNdisString->Buffer;
1617
1618 for( i = 0; i < 6; i++)
1619 {
1620 u8 = pMac->au8[i];
1621 pString[ 0] = s_achDigits[(u8 >> 4) & 0xf];
1622 pString[ 1] = s_achDigits[(u8/*>>0*/)& 0xf];
1623 pString += 2;
1624 }
1625
1626 pNdisString->Length = 12*sizeof(pNdisString->Buffer[0]);
1627
1628 *pString = L'\0';
1629
1630 return VINF_SUCCESS;
1631}
1632
1633static int vboxNetFltWinWchar2Int(WCHAR c, uint8_t * pv)
1634{
1635 if(c >= L'A' && c <= L'F')
1636 {
1637 *pv = (c - L'A') + 10;
1638 }
1639 else if(c >= L'a' && c <= L'f')
1640 {
1641 *pv = (c - L'a') + 10;
1642 }
1643 else if(c >= L'0' && c <= L'9')
1644 {
1645 *pv = (c - L'0');
1646 }
1647 else
1648 {
1649 return VERR_INVALID_PARAMETER;
1650 }
1651 return VINF_SUCCESS;
1652}
1653
1654DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
1655{
1656 int i, rc;
1657 PWSTR pString;
1658
1659 /* validate parameters */
1660 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
1661 AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
1662 AssertReturn(pNdisString->Length >= 12*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
1663
1664 pString = pNdisString->Buffer;
1665
1666 for(i = 0; i < 6; i++)
1667 {
1668 uint8_t v1, v2;
1669 rc = vboxNetFltWinWchar2Int(pString[0], &v1);
1670 if(RT_FAILURE(rc))
1671 {
1672 break;
1673 }
1674
1675 rc = vboxNetFltWinWchar2Int(pString[1], &v2);
1676 if(RT_FAILURE(rc))
1677 {
1678 break;
1679 }
1680
1681 pMac->au8[i] = (v1 << 4) | v2;
1682
1683 pString += 2;
1684 }
1685
1686 return rc;
1687}
1688
1689#endif
1690/**
1691 * creates a NDIS_PACKET from the PINTNETSG
1692 */
1693#ifdef VBOX_NETFLT_ONDEMAND_BIND
1694/* TODO: the bToWire parameter seems to be unneeded here, remove them*/
1695#endif
1696DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PADAPT pAdapt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
1697{
1698 NDIS_STATUS fStatus;
1699 PNDIS_PACKET pPacket;
1700
1701 Assert(pSG->cSegsUsed == 1);
1702 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
1703 Assert(pSG->aSegs[0].pv);
1704 Assert(pSG->cbTotal >= sizeof(ETH_HEADER_SIZE));
1705
1706#ifdef VBOX_NETFLT_ONDEMAND_BIND
1707 NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hSendPacketPoolHandle);
1708#elif defined(VBOXNETADP)
1709 NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hRecvPacketPoolHandle);
1710#else
1711 NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pAdapt->hSendPacketPoolHandle : pAdapt->hRecvPacketPoolHandle);
1712#endif
1713 if(fStatus == NDIS_STATUS_SUCCESS)
1714 {
1715 PNDIS_BUFFER pBuffer;
1716 PVOID pMemBuf;
1717
1718 /* @todo: generally we do not always need to zero-initialize the complete OOB data here, reinitialize only when/what we need,
1719 * however we DO need to reset the status for the packets we indicate via NdisMIndicateReceivePacket to avoid packet loss
1720 * in case the status contains NDIS_STATUS_RESOURCES */
1721 VBOXNETFLT_OOB_INIT(pPacket);
1722
1723 if(bCopyMemory)
1724 {
1725 fStatus = vboxNetFltWinMemAlloc(&pMemBuf, pSG->cbTotal);
1726 if(fStatus == NDIS_STATUS_SUCCESS)
1727 {
1728 NdisMoveMemory(pMemBuf, pSG->aSegs[0].pv, pSG->cbTotal);
1729 }
1730 else
1731 {
1732 Assert(0);
1733 NdisFreePacket(pPacket);
1734 pPacket = NULL;
1735 }
1736 }
1737 else
1738 {
1739 pMemBuf = pSG->aSegs[0].pv;
1740 }
1741 if(fStatus == NDIS_STATUS_SUCCESS)
1742 {
1743#ifdef VBOX_NETFLT_ONDEMAND_BIND
1744 NdisAllocateBuffer(&fStatus, &pBuffer,
1745 pAdapt->hSendBufferPoolHandle,
1746 pMemBuf,
1747 pSG->cbTotal);
1748#elif defined(VBOXNETADP)
1749 NdisAllocateBuffer(&fStatus, &pBuffer,
1750 pAdapt->hRecvBufferPoolHandle,
1751 pMemBuf,
1752 pSG->cbTotal);
1753#else
1754 NdisAllocateBuffer(&fStatus, &pBuffer,
1755 bToWire ? pAdapt->hSendBufferPoolHandle : pAdapt->hRecvBufferPoolHandle,
1756 pMemBuf,
1757 pSG->cbTotal);
1758#endif
1759
1760 if(fStatus == NDIS_STATUS_SUCCESS)
1761 {
1762 NdisChainBufferAtBack(pPacket, pBuffer);
1763
1764#ifndef VBOX_NETFLT_ONDEMAND_BIND
1765 if(bToWire)
1766#endif
1767 {
1768 PSEND_RSVD pSendRsvd;
1769 pSendRsvd = (PSEND_RSVD)(pPacket->ProtocolReserved);
1770 pSendRsvd->pOriginalPkt = NULL;
1771 pSendRsvd->pBufToFree = pBufToFree;
1772#ifdef VBOX_LOOPBACK_USEFLAGS
1773 /* set "don't loopback" flags */
1774 NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
1775#else
1776 NdisSetPacketFlags(pPacket, 0);
1777#endif
1778 }
1779#ifndef VBOX_NETFLT_ONDEMAND_BIND
1780 else
1781 {
1782 PRECV_RSVD pRecvRsvd;
1783 pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
1784 pRecvRsvd->pOriginalPkt = NULL;
1785 pRecvRsvd->pBufToFree = pBufToFree;
1786
1787 /* me must set the header size on receive */
1788 NDIS_SET_PACKET_HEADER_SIZE(pPacket, ETH_HEADER_SIZE);
1789 /* NdisAllocatePacket zero-initializes the OOB data,
1790 * but keeps the packet flags, clean them here */
1791 NdisSetPacketFlags(pPacket, 0);
1792 }
1793#endif
1794 /* TODO: set out of bound data */
1795 }
1796 else
1797 {
1798 Assert(0);
1799 if(bCopyMemory)
1800 {
1801 vboxNetFltWinMemFree(pMemBuf);
1802 }
1803 NdisFreePacket(pPacket);
1804 pPacket = NULL;
1805 }
1806 }
1807 else
1808 {
1809 Assert(0);
1810 NdisFreePacket(pPacket);
1811 pPacket = NULL;
1812 }
1813 }
1814 else
1815 {
1816 pPacket = NULL;
1817 }
1818
1819 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
1820
1821 return pPacket;
1822}
1823
1824/*
1825 * frees NDIS_PACKET creaed with vboxNetFltWinNdisPacketFromSG
1826 */
1827DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem)
1828{
1829 UINT cBufCount;
1830 PNDIS_BUFFER pFirstBuffer;
1831 UINT uTotalPacketLength;
1832 PNDIS_BUFFER pBuffer;
1833
1834 NdisQueryPacket(pPacket, NULL, &cBufCount, &pFirstBuffer, &uTotalPacketLength);
1835
1836 Assert(cBufCount == 1);
1837
1838 do
1839 {
1840 NdisUnchainBufferAtBack(pPacket, &pBuffer);
1841 if(pBuffer != NULL)
1842 {
1843 PVOID pMemBuf;
1844 UINT cbLength;
1845
1846 NdisQueryBufferSafe(pBuffer, &pMemBuf, &cbLength, NormalPagePriority);
1847 NdisFreeBuffer(pBuffer);
1848 if(bFreeMem)
1849 {
1850 vboxNetFltWinMemFree(pMemBuf);
1851 }
1852 }
1853 else
1854 {
1855 break;
1856 }
1857 } while(true);
1858
1859 NdisFreePacket(pPacket);
1860}
1861
1862/*
1863 * Free all packet pools on the specified adapter.
1864 * @param pAdapt - pointer to ADAPT structure
1865 */
1866static VOID
1867vboxNetFltWinPtFreeAllPacketPools(
1868 IN PADAPT pAdapt
1869 )
1870{
1871#ifndef VBOX_NETFLT_ONDEMAND_BIND
1872 if (pAdapt->hRecvPacketPoolHandle != NULL)
1873 {
1874 /*
1875 * Free the packet pool that is used to indicate receives
1876 */
1877 NdisFreePacketPool(pAdapt->hRecvPacketPoolHandle);
1878
1879 pAdapt->hRecvPacketPoolHandle = NULL;
1880 }
1881#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND*/
1882#ifndef VBOXNETADP
1883 if (pAdapt->hSendPacketPoolHandle != NULL)
1884 {
1885
1886 /*
1887 * Free the packet pool that is used to send packets below
1888 */
1889
1890 NdisFreePacketPool(pAdapt->hSendPacketPoolHandle);
1891
1892 pAdapt->hSendPacketPoolHandle = NULL;
1893
1894 }
1895#endif
1896}
1897#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
1898static void vboxNetFltWinAssociateMiniportProtocol()
1899{
1900 NdisIMAssociateMiniport(vboxNetFltWinMpGetHandle(), vboxNetFltWinPtGetHandle());
1901}
1902#endif
1903
1904/*
1905 * NetFlt driver unload function
1906 */
1907DECLHIDDEN(VOID)
1908vboxNetFltWinUnload(
1909 IN PDRIVER_OBJECT DriverObject
1910 )
1911{
1912 int rc;
1913 UNREFERENCED_PARAMETER(DriverObject);
1914
1915 LogFlow(("vboxNetFltWinUnload: entered\n"));
1916
1917 rc = vboxNetFltWinTryFiniIdc();
1918 if (RT_FAILURE(rc))
1919 {
1920 /* TODO: we can not prevent driver unload here */
1921 Assert(0);
1922
1923 Log(("vboxNetFltWinTryFiniIdc - failed, busy.\n"));
1924 }
1925
1926 vboxNetFltWinJobFiniQueue(&g_JobQueue);
1927#ifndef VBOXNETADP
1928 vboxNetFltWinPtDeregister();
1929#endif
1930#ifndef VBOX_NETFLT_ONDEMAND_BIND
1931 vboxNetFltWinMpDeregister();
1932#endif
1933
1934 vboxNetFltWinFiniNetFltBase();
1935 /* don't use logging or any RT after de-init */
1936
1937 NdisFreeSpinLock(&g_GlobalLock);
1938}
1939
1940RT_C_DECLS_BEGIN
1941
1942NTSTATUS
1943DriverEntry(
1944 IN PDRIVER_OBJECT DriverObject,
1945 IN PUNICODE_STRING RegistryPath
1946 );
1947
1948RT_C_DECLS_END
1949/*
1950 * First entry point to be called, when this driver is loaded.
1951 * Register with NDIS as an intermediate driver.
1952 * @return STATUS_SUCCESS if all initialization is successful, STATUS_XXX
1953 * error code if not.
1954 */
1955NTSTATUS
1956DriverEntry(
1957 IN PDRIVER_OBJECT DriverObject,
1958 IN PUNICODE_STRING RegistryPath
1959 )
1960{
1961 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1962 int rc;
1963
1964 NdisAllocateSpinLock(&g_GlobalLock);
1965
1966 do
1967 {
1968#ifdef VBOX_LOOPBACK_USEFLAGS
1969 ULONG MjVersion;
1970 ULONG MnVersion;
1971#endif
1972
1973#ifdef VBOX_NETFLT_ONDEMAND_BIND
1974 /* we are registering in the DriverEntry only when we are working as a protocol
1975 * since in this case our driver is loaded after the VBoxDrv*/
1976 rc = vboxNetFltWinInitNetFlt();
1977#else
1978 /* the idc registration is initiated via IOCTL since our driver
1979 * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
1980 rc = vboxNetFltWinInitNetFltBase();
1981#endif
1982 if(!RT_SUCCESS(rc))
1983 {
1984 Status = NDIS_STATUS_FAILURE;
1985 break;
1986 }
1987#ifdef VBOX_LOOPBACK_USEFLAGS
1988 PsGetVersion(&MjVersion, &MnVersion,
1989 NULL, /* PULONG BuildNumber OPTIONAL */
1990 NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
1991 );
1992
1993 g_fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
1994
1995 if(MjVersion == 5 && MnVersion == 0)
1996 {
1997 /* this is Win2k*/
1998 g_fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
1999 }
2000
2001 g_fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
2002#endif
2003
2004#ifndef VBOX_NETFLT_ONDEMAND_BIND
2005 Status = vboxNetFltWinMpRegister(DriverObject, RegistryPath);
2006 if (Status != NDIS_STATUS_SUCCESS)
2007 {
2008 vboxNetFltWinFiniNetFlt();
2009 break;
2010 }
2011#endif
2012#ifndef VBOXNETADP
2013 Status = vboxNetFltWinPtRegister(DriverObject, RegistryPath);
2014 if (Status != NDIS_STATUS_SUCCESS)
2015 {
2016#ifndef VBOX_NETFLT_ONDEMAND_BIND
2017 vboxNetFltWinMpDeregister();
2018#endif
2019 vboxNetFltWinFiniNetFlt();
2020 break;
2021 }
2022#endif
2023
2024 Status = vboxNetFltWinJobInitQueue(&g_JobQueue);
2025 if(Status != STATUS_SUCCESS)
2026 {
2027#ifndef VBOXNETADP
2028 vboxNetFltWinPtDeregister();
2029#endif
2030#ifndef VBOX_NETFLT_ONDEMAND_BIND
2031 vboxNetFltWinMpDeregister();
2032#endif
2033 vboxNetFltWinFiniNetFlt();
2034 break;
2035 }
2036
2037 /* note: we do it after we initialize the Job Queue */
2038 vboxNetFltWinStartInitIdcProbing();
2039
2040#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
2041 vboxNetFltWinAssociateMiniportProtocol();
2042#endif
2043 } while (FALSE);
2044
2045 return(Status);
2046}
2047
2048#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
2049/**
2050 * creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
2051 * according to DDK docs we must create our own packet rather than posting the one passed to us
2052 */
2053DECLHIDDEN(NDIS_STATUS)
2054vboxNetFltWinPrepareSendPacket(
2055 IN PADAPT pAdapt,
2056 IN PNDIS_PACKET pPacket,
2057 OUT PNDIS_PACKET *ppMyPacket
2058 /*, IN bool bNetFltActive */
2059 )
2060{
2061 NDIS_STATUS fStatus;
2062
2063 NdisAllocatePacket(&fStatus,
2064 ppMyPacket,
2065 pAdapt->hSendPacketPoolHandle);
2066
2067 if (fStatus == NDIS_STATUS_SUCCESS)
2068 {
2069 PSEND_RSVD pSendRsvd;
2070
2071 pSendRsvd = (PSEND_RSVD)((*ppMyPacket)->ProtocolReserved);
2072 pSendRsvd->pOriginalPkt = pPacket;
2073 pSendRsvd->pBufToFree = NULL;
2074
2075 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2076 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2077
2078 vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
2079
2080#ifdef VBOX_LOOPBACK_USEFLAGS
2081 NdisGetPacketFlags(*ppMyPacket) |= g_fPacketDontLoopBack;
2082#endif
2083 }
2084 else
2085 {
2086 *ppMyPacket = NULL;
2087 }
2088
2089 return fStatus;
2090}
2091
2092/**
2093 * creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
2094 * according to DDK docs we must create our own packet rather than posting the one passed to us
2095 */
2096DECLHIDDEN(NDIS_STATUS)
2097vboxNetFltWinPrepareRecvPacket(
2098 IN PADAPT pAdapt,
2099 IN PNDIS_PACKET pPacket,
2100 OUT PNDIS_PACKET *ppMyPacket,
2101 IN bool bDpr
2102 )
2103{
2104 NDIS_STATUS fStatus;
2105
2106 /*
2107 * Get a packet off the pool and indicate that up
2108 */
2109 if(bDpr)
2110 {
2111 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
2112
2113 NdisDprAllocatePacket(&fStatus,
2114 ppMyPacket,
2115 pAdapt->hRecvPacketPoolHandle);
2116 }
2117 else
2118 {
2119 NdisAllocatePacket(&fStatus,
2120 ppMyPacket,
2121 pAdapt->hRecvPacketPoolHandle);
2122 }
2123
2124 if (fStatus == NDIS_STATUS_SUCCESS)
2125 {
2126 PRECV_RSVD pRecvRsvd;
2127
2128 pRecvRsvd = (PRECV_RSVD)((*ppMyPacket)->MiniportReserved);
2129 pRecvRsvd->pOriginalPkt = pPacket;
2130 pRecvRsvd->pBufToFree = NULL;
2131
2132 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2133 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2134
2135 fStatus = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket);
2136 }
2137 else
2138 {
2139 *ppMyPacket = NULL;
2140 }
2141 return fStatus;
2142}
2143#endif
2144
2145/**
2146 * initializes the ADAPT (our context structure) and binds to the given adapter
2147 */
2148#if defined(VBOX_NETFLT_ONDEMAND_BIND)
2149DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT pAdapt)
2150#elif defined(VBOXNETADP)
2151DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
2152#else
2153DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
2154#endif
2155{
2156 NDIS_STATUS Status;
2157 do
2158 {
2159#ifndef VBOX_NETFLT_ONDEMAND_BIND
2160 ANSI_STRING AnsiString;
2161 int rc;
2162 PVBOXNETFLTINS pInstance;
2163 USHORT cbAnsiName = pBindToMiniportName->Length;/* the lenght is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
2164 CREATE_INSTANCE_CONTEXT Context;
2165 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2166
2167# ifndef VBOXNETADP
2168 Context.pOurName = pOurMiniportName;
2169 Context.pBindToName = pBindToMiniportName;
2170# else
2171 Context.hMiniportAdapter = hMiniportAdapter;
2172 Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
2173# endif
2174 Context.Status = NDIS_STATUS_SUCCESS;
2175
2176 AnsiString.Buffer = 0; /* will be allocated by RtlUnicodeStringToAnsiString */
2177 AnsiString.Length = 0;
2178 AnsiString.MaximumLength = cbAnsiName;
2179
2180 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2181
2182 Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, true);
2183
2184 if(Status != STATUS_SUCCESS)
2185 {
2186 break;
2187 }
2188
2189 rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, AnsiString.Buffer, &pInstance, &Context);
2190 RtlFreeAnsiString(&AnsiString);
2191 if(RT_FAILURE(rc))
2192 {
2193 Assert(0);
2194 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2195 break;
2196 }
2197
2198 Assert(pInstance);
2199
2200 if(rc == VINF_ALREADY_INITIALIZED)
2201 {
2202 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2203 /* the case when our adapter was unbound while IntNet was connected to it */
2204 /* the instance remains valid until intNet disconnects from it, we simply search and re-use it*/
2205
2206 /* re-initialize PADAPT */
2207 rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
2208 if(RT_FAILURE(rc))
2209 {
2210 Assert(0);
2211 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2212 /* release netflt */
2213 vboxNetFltRelease(pInstance, false);
2214
2215 break;
2216 }
2217 }
2218
2219 *ppAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2220#else
2221 Status = vboxNetFltWinPtAllocInitPADAPT(pAdapt);
2222 if (Status != NDIS_STATUS_SUCCESS)
2223 {
2224 break;
2225 }
2226
2227 Status = vboxNetFltWinPtDoBinding(pAdapt);
2228 if (Status != NDIS_STATUS_SUCCESS)
2229 {
2230 vboxNetFltWinPtFiniPADAPT(pAdapt);
2231 break;
2232 }
2233#endif
2234 }while(FALSE);
2235
2236 return Status;
2237}
2238
2239/**
2240 * initializes the ADAPT
2241 */
2242#ifdef VBOX_NETFLT_ONDEMAND_BIND
2243DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT pAdapt)
2244{
2245 NDIS_STATUS Status;
2246
2247 do
2248 {
2249 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
2250 if (Status != NDIS_STATUS_SUCCESS)
2251 {
2252 break;
2253 }
2254 Status = NDIS_STATUS_SUCCESS;
2255 } while(0);
2256
2257 return Status;
2258}
2259
2260/**
2261 * unbinds from the adapter we are bound to and deinitializes the ADAPT
2262 */
2263static NDIS_STATUS vboxNetFltWinPtFiniUnbind(PADAPT pAdapt)
2264{
2265 NDIS_STATUS Status;
2266
2267 LogFlow(("==> vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2268
2269 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2270
2271 do
2272 {
2273 Status = vboxNetFltWinPtDoUnbinding(pAdapt, true);
2274 if(Status != NDIS_STATUS_SUCCESS)
2275 {
2276 Assert(0);
2277 /* TODO: should we break ? */
2278 /* break; */
2279 }
2280
2281 vboxNetFltWinPtFiniPADAPT(pAdapt);
2282 } while(0);
2283 LogFlow(("<== vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2284
2285 return Status;
2286}
2287#endif
2288
2289/*
2290 * deinitializes the ADAPT
2291 */
2292DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt)
2293{
2294#ifndef VBOXNETADP
2295 int rc;
2296#endif
2297
2298 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2299
2300 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2301#ifndef VBOXNETADP
2302 if(pAdapt->DeviceName.Buffer)
2303 {
2304 vboxNetFltWinMemFree(pAdapt->DeviceName.Buffer);
2305 }
2306
2307
2308 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2309# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2310 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2311# endif
2312#endif
2313
2314#ifndef VBOX_NETFLT_ONDEMAND_BIND
2315 /* moved to vboxNetFltWinDetachFromInterfaceWorker */
2316#else
2317 vboxNetFltWinQuFiniPacketQueue(pAdapt);
2318#endif
2319
2320 vboxNetFltWinFiniBuffers(pAdapt);
2321
2322 /*
2323 * Free the memory here, if was not released earlier(by calling the HaltHandler)
2324 */
2325 vboxNetFltWinPtFreeAllPacketPools (pAdapt);
2326#ifndef VBOXNETADP
2327 rc = RTSemFastMutexDestroy(pAdapt->hSynchRequestMutex); AssertRC(rc);
2328#endif
2329
2330 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2331}
2332
2333DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
2334#ifndef VBOXNETADP
2335DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName)
2336#else
2337DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt)
2338#endif
2339{
2340 NDIS_STATUS Status;
2341#ifndef VBOXNETADP
2342 int rc;
2343#endif
2344 BOOLEAN bCallFiniOnFail = FALSE;
2345
2346 LogFlow(("==> vboxNetFltWinPtInitPADAPT : pAdapt %p\n", pAdapt));
2347
2348 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2349
2350 do
2351 {
2352 NdisZeroMemory(pAdapt, sizeof(ADAPT));
2353#ifndef VBOXNETADP
2354 NdisInitializeEvent(&pAdapt->hEvent);
2355
2356 KeInitializeEvent(&pAdapt->hSynchCompletionEvent, SynchronizationEvent, FALSE);
2357
2358 /*
2359 * Allocate a packet pool for sends. We need this to pass sends down.
2360 * We cannot use the same packet descriptor that came down to our send
2361 * handler (see also NDIS 5.1 packet stacking).
2362 */
2363 NdisAllocatePacketPoolEx(&Status,
2364 &pAdapt->hSendPacketPoolHandle,
2365 MIN_PACKET_POOL_SIZE,
2366 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2367 sizeof(PT_RSVD));
2368
2369 if (Status != NDIS_STATUS_SUCCESS)
2370 {
2371 pAdapt->hSendPacketPoolHandle = NULL;
2372 break;
2373 }
2374#else
2375#endif
2376
2377 Status = vboxNetFltWinInitBuffers(pAdapt);
2378 if (Status != NDIS_STATUS_SUCCESS)
2379 {
2380 break;
2381 }
2382
2383 bCallFiniOnFail = TRUE;
2384#ifndef VBOXNETADP
2385 rc = RTSemFastMutexCreate(&pAdapt->hSynchRequestMutex);
2386 if(RT_FAILURE(rc))
2387 {
2388 Status = NDIS_STATUS_FAILURE;
2389 break;
2390 }
2391#endif
2392
2393#ifndef VBOX_NETFLT_ONDEMAND_BIND
2394# ifndef VBOXNETADP
2395 Status = vboxNetFltWinMemAlloc((PVOID*)&pAdapt->DeviceName.Buffer, pOurDeviceName->Length);
2396 if(Status != NDIS_STATUS_SUCCESS)
2397 {
2398 Assert(0);
2399 pAdapt->DeviceName.Buffer = NULL;
2400 break;
2401 }
2402 pAdapt->DeviceName.MaximumLength = pOurDeviceName->Length;
2403 pAdapt->DeviceName.Length = 0;
2404 Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
2405 if(Status != NDIS_STATUS_SUCCESS)
2406 {
2407 Assert(0);
2408 break;
2409 }
2410# endif
2411
2412 /*
2413 * Allocate a packet pool for receives. We need this to indicate receives.
2414 * Same consideration as sends (see also NDIS 5.1 packet stacking).
2415 */
2416 NdisAllocatePacketPoolEx(&Status,
2417 &pAdapt->hRecvPacketPoolHandle,
2418 MIN_PACKET_POOL_SIZE,
2419 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2420 PROTOCOL_RESERVED_SIZE_IN_PACKET);
2421
2422 if (Status != NDIS_STATUS_SUCCESS)
2423 {
2424 pAdapt->hRecvPacketPoolHandle = NULL;
2425 break;
2426 }
2427#ifndef VBOXNETADP
2428 NdisInitializeEvent(&pAdapt->MiniportInitEvent);
2429#endif
2430#endif
2431#ifndef VBOXNETADP
2432 pAdapt->PTState.PowerState = NdisDeviceStateD3;
2433 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
2434
2435 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2436
2437# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2438 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2439# endif
2440#endif
2441 /* TODO: do we need it here ?? */
2442 pAdapt->MPState.PowerState = NdisDeviceStateD3;
2443 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
2444
2445#ifdef VBOX_NETFLT_ONDEMAND_BIND
2446 {
2447 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2448 rc = vboxNetFltWinConnectIt(pNetFlt);
2449 if(RT_FAILURE(rc))
2450 {
2451 Assert(0);
2452 Status = NDIS_STATUS_FAILURE;
2453 break;
2454 }
2455 }
2456#endif
2457
2458 /* moved to vboxNetFltOsInitInstance */
2459 } while(0);
2460
2461 if (Status != NDIS_STATUS_SUCCESS)
2462 {
2463 if(bCallFiniOnFail)
2464 {
2465 vboxNetFltWinPtFiniPADAPT(pAdapt);
2466 }
2467 }
2468
2469 LogFlow(("<== vboxNetFltWinPtInitPADAPT : pAdapt %p, Status %x\n", pAdapt, Status));
2470
2471 return Status;
2472}
2473
2474/**
2475 * match packets
2476 */
2477#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
2478#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
2479#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
2480#define LAST_LIST_ENTRY PREV_LIST_ENTRY
2481
2482#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
2483
2484#ifndef VBOXNETADP
2485
2486#ifdef DEBUG_misha
2487
2488RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2489RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
2490
2491DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
2492{
2493 UINT cBufCount1;
2494 PNDIS_BUFFER pBuffer1;
2495 UINT uTotalPacketLength1;
2496 RTNETETHERHDR* pEth;
2497 UINT cbLength1 = 0;
2498 UINT i = 0;
2499
2500 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2501
2502 Assert(pBuffer1);
2503 Assert(uTotalPacketLength1 >= ETH_HEADER_SIZE);
2504 if(uTotalPacketLength1 < ETH_HEADER_SIZE)
2505 return NULL;
2506
2507 NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
2508 Assert(cbLength1 >= ETH_HEADER_SIZE);
2509 if(cbLength1 < ETH_HEADER_SIZE)
2510 return NULL;
2511
2512 return pEth;
2513}
2514
2515DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
2516{
2517 Assert(pSG->cSegsUsed);
2518 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2519 Assert(pSG->aSegs[0].cb >= ETH_HEADER_SIZE);
2520
2521 if(!pSG->cSegsUsed)
2522 return NULL;
2523
2524 if(pSG->aSegs[0].cb < ETH_HEADER_SIZE)
2525 return NULL;
2526
2527 return (PRTNETETHERHDR)pSG->aSegs[0].pv;
2528}
2529
2530DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
2531{
2532 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
2533 Assert(pHdr);
2534
2535 if(!pHdr)
2536 return false;
2537
2538 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2539 return false;
2540
2541 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2542 return false;
2543
2544 return true;
2545}
2546
2547DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
2548{
2549 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
2550 Assert(pHdr);
2551
2552 if(!pHdr)
2553 return false;
2554
2555 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2556 return false;
2557
2558 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2559 return false;
2560
2561 return true;
2562}
2563#endif
2564
2565# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
2566/*
2567 * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
2568 * if cbMatch < 0 matches complete packets.
2569 */
2570DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
2571{
2572 UINT cBufCount1;
2573 PNDIS_BUFFER pBuffer1;
2574 UINT uTotalPacketLength1;
2575 uint8_t* pMemBuf1;
2576 UINT cbLength1 = 0;
2577
2578 UINT cBufCount2;
2579 PNDIS_BUFFER pBuffer2;
2580 UINT uTotalPacketLength2;
2581 uint8_t* pMemBuf2;
2582 UINT cbLength2 = 0;
2583 bool bMatch = true;
2584
2585#ifdef DEBUG_NETFLT_PACKETS
2586 bool bCompleteMatch = false;
2587#endif
2588
2589 NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2590 NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
2591
2592 Assert(pBuffer1);
2593 Assert(pBuffer2);
2594
2595 if(uTotalPacketLength1 != uTotalPacketLength2)
2596 {
2597 bMatch = false;
2598 }
2599 else
2600 {
2601 UINT ucbLength2Match = 0;
2602 UINT ucbMatch;
2603 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2604 {
2605 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2606 ucbMatch = uTotalPacketLength1;
2607#ifdef DEBUG_NETFLT_PACKETS
2608 bCompleteMatch = true;
2609#endif
2610 }
2611 else
2612 {
2613 ucbMatch = (UINT)cbMatch;
2614 }
2615
2616 for(;;)
2617 {
2618 if(!cbLength1)
2619 {
2620 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2621 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2622 }
2623 else
2624 {
2625 Assert(pMemBuf1);
2626 Assert(ucbLength2Match);
2627 pMemBuf1 += ucbLength2Match;
2628 }
2629
2630 if(!cbLength2)
2631 {
2632 NdisQueryBufferSafe(pBuffer2, &pMemBuf2, &cbLength2, NormalPagePriority);
2633 NdisGetNextBuffer(pBuffer2, &pBuffer2);
2634 }
2635 else
2636 {
2637 Assert(pMemBuf2);
2638 Assert(ucbLength2Match);
2639 pMemBuf2 += ucbLength2Match;
2640 }
2641
2642 ucbLength2Match = MIN(ucbMatch, cbLength1);
2643 ucbLength2Match = MIN(ucbMatch, cbLength2);
2644
2645 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2646 {
2647 bMatch = false;
2648 break;
2649 }
2650
2651 ucbMatch -= ucbLength2Match;
2652 if(!ucbMatch)
2653 break;
2654
2655 cbLength1 -= ucbLength2Match;
2656 cbLength2 -= ucbLength2Match;
2657 }
2658 }
2659
2660#ifdef DEBUG_NETFLT_PACKETS
2661 if(bMatch && !bCompleteMatch)
2662 {
2663 /* check that the packets fully match */
2664 DBG_CHECK_PACKETS(pPacket1, pPacket2);
2665 }
2666#endif
2667
2668 return bMatch;
2669}
2670
2671/*
2672 * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
2673 * if cbMatch < 0 matches complete packets.
2674 */
2675DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
2676{
2677 UINT cBufCount1;
2678 PNDIS_BUFFER pBuffer1;
2679 UINT uTotalPacketLength1;
2680 uint8_t* pMemBuf1;
2681 UINT cbLength1 = 0;
2682 UINT uTotalPacketLength2 = pSG->cbTotal;
2683 uint8_t* pMemBuf2;
2684 UINT cbLength2 = 0;
2685 bool bMatch = true;
2686 bool bCompleteMatch = false;
2687 UINT i = 0;
2688
2689 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2690
2691 Assert(pBuffer1);
2692 Assert(pSG->cSegsUsed);
2693 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2694
2695 if(uTotalPacketLength1 != uTotalPacketLength2)
2696 {
2697 Assert(0);
2698 bMatch = false;
2699 }
2700 else
2701 {
2702 UINT ucbLength2Match = 0;
2703 UINT ucbMatch;
2704
2705 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2706 {
2707 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2708 ucbMatch = uTotalPacketLength1;
2709 bCompleteMatch = true;
2710 }
2711 else
2712 {
2713 ucbMatch = (UINT)cbMatch;
2714 }
2715
2716 for(;;)
2717 {
2718 if(!cbLength1)
2719 {
2720 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2721 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2722 }
2723 else
2724 {
2725 Assert(pMemBuf1);
2726 Assert(ucbLength2Match);
2727 pMemBuf1 += ucbLength2Match;
2728 }
2729
2730 if(!cbLength2)
2731 {
2732 Assert(i < pSG->cSegsUsed);
2733 pMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
2734 cbLength2 = pSG->aSegs[i].cb;
2735 i++;
2736 }
2737 else
2738 {
2739 Assert(pMemBuf2);
2740 Assert(ucbLength2Match);
2741 pMemBuf2 += ucbLength2Match;
2742 }
2743
2744 ucbLength2Match = MIN(ucbMatch, cbLength1);
2745 ucbLength2Match = MIN(ucbMatch, cbLength2);
2746
2747 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2748 {
2749 bMatch = false;
2750 Assert(0);
2751 break;
2752 }
2753
2754 ucbMatch -= ucbLength2Match;
2755 if(!ucbMatch)
2756 break;
2757
2758 cbLength1 -= ucbLength2Match;
2759 cbLength2 -= ucbLength2Match;
2760 }
2761 }
2762
2763 if(bMatch && !bCompleteMatch)
2764 {
2765 /* check that the packets fully match */
2766 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
2767 }
2768 return bMatch;
2769}
2770
2771# if 0
2772/*
2773 * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
2774 * if cbMatch < 0 matches complete packets.
2775 */
2776static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
2777{
2778 UINT uTotalPacketLength1 = pSG1->cbTotal;
2779 PVOID pMemBuf1;
2780 UINT cbLength1 = 0;
2781 UINT i1 = 0;
2782 UINT uTotalPacketLength2 = pSG2->cbTotal;
2783 PVOID pMemBuf2;
2784 UINT cbLength2 = 0;
2785
2786 bool bMatch = true;
2787 bool bCompleteMatch = false;
2788 UINT i2 = 0;
2789
2790 Assert(pSG1->cSegsUsed);
2791 Assert(pSG2->cSegsUsed);
2792 Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
2793 Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
2794
2795 if(uTotalPacketLength1 != uTotalPacketLength2)
2796 {
2797 Assert(0);
2798 bMatch = false;
2799 }
2800 else
2801 {
2802 UINT ucbMatch;
2803 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2804 {
2805 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2806 ucbMatch = uTotalPacketLength1;
2807 bCompleteMatch = true;
2808 }
2809 else
2810 {
2811 ucbMatch = (UINT)cbMatch;
2812 }
2813
2814 do
2815 {
2816 UINT ucbLength2Match;
2817 if(!cbLength1)
2818 {
2819 Assert(i1 < pSG1->cSegsUsed);
2820 pMemBuf1 = pSG1->aSegs[i1].pv;
2821 cbLength1 = pSG1->aSegs[i1].cb;
2822 i1++;
2823 }
2824
2825 if(!cbLength2)
2826 {
2827 Assert(i2 < pSG2->cSegsUsed);
2828 pMemBuf2 = pSG2->aSegs[i2].pv;
2829 cbLength2 = pSG2->aSegs[i2].cb;
2830 i2++;
2831 }
2832
2833 ucbLength2Match = MIN(ucbMatch, cbLength1);
2834 ucbLength2Match = MIN(ucbMatch, cbLength2);
2835
2836 if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
2837 {
2838 bMatch = false;
2839 Assert(0);
2840 break;
2841 }
2842 ucbMatch -= ucbLength2Match;
2843 cbLength1 -= ucbLength2Match;
2844 cbLength2 -= ucbLength2Match;
2845 } while (ucbMatch);
2846 }
2847
2848 if(bMatch && !bCompleteMatch)
2849 {
2850 /* check that the packets fully match */
2851 DBG_CHECK_SGS(pSG1, pSG2);
2852 }
2853 return bMatch;
2854}
2855# endif
2856# endif
2857#endif
2858
2859static void vboxNetFltWinFiniNetFltBase()
2860{
2861 do
2862 {
2863 vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
2864
2865 /*
2866 * Undo the work done during start (in reverse order).
2867 */
2868 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2869
2870 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
2871 RTLogDestroy(RTLogSetDefaultInstance(NULL));
2872
2873 RTR0Term();
2874 } while (0);
2875}
2876
2877static int vboxNetFltWinTryFiniIdc()
2878{
2879 int rc;
2880
2881 vboxNetFltWinStopInitIdcProbing();
2882
2883 if(g_bIdcInitialized)
2884 {
2885 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2886 if(RT_SUCCESS(rc))
2887 {
2888 g_bIdcInitialized = false;
2889 }
2890 }
2891 else
2892 {
2893 rc = VINF_SUCCESS;
2894 }
2895 return rc;
2896
2897}
2898
2899static int vboxNetFltWinFiniNetFlt()
2900{
2901 int rc = vboxNetFltWinTryFiniIdc();
2902 if(RT_SUCCESS(rc))
2903 {
2904 vboxNetFltWinFiniNetFltBase();
2905 }
2906 return rc;
2907}
2908
2909/**
2910 * base netflt initialization
2911 */
2912static int vboxNetFltWinInitNetFltBase()
2913{
2914 int rc;
2915
2916 do
2917 {
2918 Assert(!g_bIdcInitialized);
2919
2920 rc = RTR0Init(0);
2921 if (!RT_SUCCESS(rc))
2922 {
2923 break;
2924 }
2925
2926 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2927 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
2928 if (!RT_SUCCESS(rc))
2929 {
2930 RTR0Term();
2931 break;
2932 }
2933 }while(0);
2934
2935 return rc;
2936}
2937
2938/**
2939 * initialize IDC
2940 */
2941static int vboxNetFltWinInitIdc()
2942{
2943 int rc;
2944
2945 do
2946 {
2947 if(g_bIdcInitialized)
2948 {
2949#ifdef VBOX_NETFLT_ONDEMAND_BIND
2950 Assert(0);
2951#endif
2952 rc = VINF_ALREADY_INITIALIZED;
2953 break;
2954 }
2955
2956 /*
2957 * connect to the support driver.
2958 *
2959 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
2960 * for establishing the connect to the support driver.
2961 */
2962 rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
2963 if (!RT_SUCCESS(rc))
2964 {
2965 break;
2966 }
2967
2968 g_bIdcInitialized = true;
2969 } while (0);
2970
2971 return rc;
2972}
2973
2974static void vboxNetFltWinInitIdcProbingWorker(PINIT_IDC_INFO pInitIdcInfo)
2975{
2976 int rc = vboxNetFltWinInitIdc();
2977 if(RT_FAILURE(rc))
2978 {
2979 bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2980 if(!bInterupted)
2981 {
2982 RTThreadSleep(1000); /* 1 s */
2983 bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2984 if(!bInterupted)
2985 {
2986 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &pInitIdcInfo->Job, false);
2987 return;
2988 }
2989 }
2990
2991 /* it's interupted */
2992 rc = VERR_INTERRUPTED;
2993 }
2994
2995 ASMAtomicUoWriteU32(&pInitIdcInfo->rc, rc);
2996 KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
2997}
2998
2999static int vboxNetFltWinStopInitIdcProbing()
3000{
3001 if(!g_InitIdcInfo.bInitialized)
3002 return VERR_INVALID_STATE;
3003
3004 ASMAtomicUoWriteBool(&g_InitIdcInfo.bStop, true);
3005 KeWaitForSingleObject(&g_InitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
3006
3007 return g_InitIdcInfo.rc;
3008}
3009
3010static int vboxNetFltWinStartInitIdcProbing()
3011{
3012 Assert(!g_bIdcInitialized);
3013 KeInitializeEvent(&g_InitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
3014 g_InitIdcInfo.bStop = false;
3015 g_InitIdcInfo.bInitialized = true;
3016 vboxNetFltWinJobInit(&g_InitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_InitIdcInfo, false);
3017 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &g_InitIdcInfo.Job, false);
3018 return VINF_SUCCESS;
3019}
3020
3021static int vboxNetFltWinInitNetFlt()
3022{
3023 int rc;
3024
3025 do
3026 {
3027 rc = vboxNetFltWinInitNetFltBase();
3028 if(RT_FAILURE(rc))
3029 {
3030 Assert(0);
3031 break;
3032 }
3033
3034 /*
3035 * connect to the support driver.
3036 *
3037 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
3038 * for establishing the connect to the support driver.
3039 */
3040 rc = vboxNetFltWinInitIdc();
3041 if (RT_FAILURE(rc))
3042 {
3043 Assert(0);
3044 vboxNetFltWinFiniNetFltBase();
3045 break;
3046 }
3047 } while (0);
3048
3049 return rc;
3050}
3051
3052/* detach*/
3053static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
3054{
3055 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3056 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3057 NDIS_STATUS Status;
3058 LogFlow(("vboxNetFltWinDeleteInstance: pThis=%p \n", pThis));
3059
3060 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3061 Assert(pAdapt);
3062 Assert(pThis);
3063 Assert(pThis->fDisconnectedFromHost);
3064 Assert(!pThis->fRediscoveryPending);
3065 Assert(!pThis->fActive);
3066#ifndef VBOXNETADP
3067 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
3068 Assert(!pAdapt->hBindingHandle);
3069#endif
3070 Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Deinitialized);
3071 Assert(!pThis->u.s.PacketQueueWorker.pSG);
3072// Assert(!pAdapt->hMiniportHandle);
3073
3074#ifndef VBOX_NETFLT_ONDEMAND_BIND
3075 Status = vboxNetFltWinMpDereferenceControlDevice();
3076 Assert(Status == NDIS_STATUS_SUCCESS);
3077#else
3078 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3079 if(Status != NDIS_STATUS_SUCCESS)
3080 {
3081 Assert(0);
3082 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3083 }
3084#endif
3085
3086 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3087
3088 return VINF_SUCCESS;
3089}
3090
3091static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
3092{
3093 vboxNetFltWinQuFiniPacketQueue(pInstance);
3094 return NDIS_STATUS_SUCCESS;
3095}
3096
3097/* detach*/
3098DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PADAPT pAdapt, bool bOnUnbind)
3099{
3100 PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
3101 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3102 NDIS_STATUS Status;
3103 int rc;
3104 LogFlow(("vboxNetFltWinDetachFromInterface: pThis=%p\n", pThis));
3105
3106 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3107 Assert(pAdapt);
3108 Assert(pThis);
3109/* Assert(!pThis->fActive); */
3110
3111 /* paranoya to ensyre the instance is not removed while we're waiting on the mutex
3112 * in case ndis does something unpredictable, e.g. calls our miniport halt independently
3113 * from protocol unbind and concurrently with it*/
3114 vboxNetFltRetain(pThis, false);
3115
3116 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3117 if(RT_SUCCESS(rc))
3118 {
3119#ifndef VBOX_NETFLT_ONDEMAND_BIND
3120 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected);
3121 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3122#ifndef VBOXNETADP
3123 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3124#endif
3125// if(
3126//#ifdef VBOXNETADP
3127// vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3128//#else
3129// vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized
3130//// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3131//#endif
3132// )
3133 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected)
3134 {
3135 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnecting);
3136#ifndef VBOXNETADP
3137 Status = vboxNetFltWinPtDoUnbinding(pAdapt, bOnUnbind);
3138#else
3139 Status = vboxNetFltWinMpDoDeinitialization(pAdapt);
3140#endif
3141 Assert(Status == NDIS_STATUS_SUCCESS);
3142
3143 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3144 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3145#ifndef VBOXNETADP
3146 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3147#endif
3148// /* paranoya */
3149// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3150//#ifndef VBOXNETADP
3151// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3152//#endif
3153
3154 vboxNetFltWinPtFiniPADAPT(pAdapt);
3155
3156 /* we're unbinding, make an unbind-related release */
3157 vboxNetFltRelease(pThis, false);
3158#else
3159 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3160 if(Status != NDIS_STATUS_SUCCESS)
3161 {
3162 Assert(0);
3163 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3164 }
3165#endif
3166 }
3167 else
3168 {
3169 AssertBreakpoint();
3170#ifndef VBOXNETADP
3171 pAdapt->Status = NDIS_STATUS_FAILURE;
3172#endif
3173 if(!bOnUnbind)
3174 {
3175 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3176 }
3177 Status = NDIS_STATUS_FAILURE;
3178 }
3179 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3180 }
3181 else
3182 {
3183 AssertBreakpoint();
3184 Status = NDIS_STATUS_FAILURE;
3185 }
3186
3187 /* release for the retain we made before waining on the mutex */
3188 vboxNetFltRelease(pThis, false);
3189
3190 return Status;
3191}
3192
3193/**
3194 * Worker for vboxNetFltWinAttachToInterface.
3195 *
3196 * @param pAttachInfo Structure for communicating with
3197 * vboxNetFltWinAttachToInterface.
3198 */
3199static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
3200{
3201 PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
3202 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3203 int rc;
3204 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3205
3206 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3207
3208 /* to ensure we're not removed while we're here */
3209 vboxNetFltRetain(pThis, false);
3210
3211 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3212 if(RT_SUCCESS(rc))
3213 {
3214 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3215 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected);
3216 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3217#ifndef VBOXNETADP
3218 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3219#endif
3220// if(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3221//#ifndef VBOXNETADP
3222// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3223//#endif
3224// )
3225 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected)
3226 {
3227
3228#ifndef VBOX_NETFLT_ONDEMAND_BIND
3229 if(pAttachInfo->fRediscovery)
3230 {
3231 /* rediscovery means adaptor bind is performed while intnet is already using it
3232 * i.e. adaptor was unbound while being used by intnet and now being bound back again */
3233 Assert(((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState)) == kVBoxNetFltInsState_Connected);
3234 }
3235#ifndef VBOXNETADP
3236 Status = vboxNetFltWinPtInitPADAPT(pAdapt, pAttachInfo->pCreateContext->pOurName);
3237#else
3238 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
3239#endif
3240 if(Status == NDIS_STATUS_SUCCESS)
3241 {
3242 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connecting);
3243
3244#ifndef VBOXNETADP
3245 Status = vboxNetFltWinPtDoBinding(pAdapt, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
3246#else
3247 Status = vboxNetFltWinMpDoInitialization(pAdapt, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
3248#endif
3249 if (Status == NDIS_STATUS_SUCCESS)
3250 {
3251 if(pAttachInfo->fRediscovery || (Status = vboxNetFltWinMpReferenceControlDevice()) == NDIS_STATUS_SUCCESS)
3252 {
3253#ifndef VBOXNETADP
3254 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
3255#endif
3256 {
3257 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connected);
3258// Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3259#ifndef VBOXNETADP
3260 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3261#endif
3262// /* paranoya */
3263//// vboxNetFltWinSetAdaptState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
3264//#ifndef VBOXNETADP
3265// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
3266//#endif
3267
3268 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
3269
3270 /* 4. mark as connected */
3271 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
3272
3273 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
3274
3275 pAttachInfo->Status = VINF_SUCCESS;
3276 pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
3277
3278 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3279
3280 vboxNetFltRelease(pThis, false);
3281
3282 return;
3283 }
3284 AssertBreakpoint();
3285
3286 if(!pAttachInfo->fRediscovery)
3287 {
3288 vboxNetFltWinMpDereferenceControlDevice();
3289 }
3290 }
3291 AssertBreakpoint();
3292#ifndef VBOXNETADP
3293 vboxNetFltWinPtDoUnbinding(pAdapt, true);
3294#else
3295 vboxNetFltWinMpDoDeinitialization(pAdapt);
3296#endif
3297 }
3298 AssertBreakpoint();
3299 vboxNetFltWinPtFiniPADAPT(pAdapt);
3300 }
3301 AssertBreakpoint();
3302 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3303 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3304#ifndef VBOXNETADP
3305 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3306#endif
3307// /* paranoya */
3308// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3309//#ifndef VBOXNETADP
3310// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3311//#endif
3312 }
3313 AssertBreakpoint();
3314
3315#else /* VBOX_NETFLT_ONDEMAND_BIND */
3316 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3317
3318 Status = vboxNetFltWinPtInitBind(pAdapt);
3319 if (Status != NDIS_STATUS_SUCCESS)
3320 {
3321 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3322 break;
3323 }
3324
3325 Status = vboxNetFltWinGetMacAddress(pAdapt, &pThis->u.s.Mac);
3326 if (Status != NDIS_STATUS_SUCCESS)
3327 {
3328 vboxNetFltWinPtFiniUnbind(pAdapt);
3329 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3330 break;
3331 }
3332#endif /* VBOX_NETFLT_ONDEMAND_BIND */
3333
3334
3335 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3336 pAttachInfo->pCreateContext->Status = Status;
3337 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3338 }
3339 else
3340 {
3341 AssertBreakpoint();
3342 pAttachInfo->Status = rc;
3343 }
3344
3345 vboxNetFltRelease(pThis, false);
3346
3347 return;
3348}
3349
3350/**
3351 * Common code for vboxNetFltOsInitInstance and
3352 * vboxNetFltOsMaybeRediscovered.
3353 *
3354 * @returns IPRT status code.
3355 * @param pThis The instance.
3356 * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
3357 * false if it's vboxNetFltOsInitInstance.
3358 */
3359static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
3360{
3361 ATTACH_INFO Info;
3362 Info.pNetFltIf = pThis;
3363 Info.fRediscovery = fRediscovery;
3364 Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
3365
3366
3367#ifdef VBOX_NETFLT_ONDEMAND_BIND
3368 /* packet queue worker thread gets created on attach interface, need to do it via job at passive level */
3369 vboxNetFltWinJobSynchExecAtPassive((JOB_ROUTINE)vboxNetFltWinAttachToInterfaceWorker, &Info);
3370#else
3371 vboxNetFltWinAttachToInterfaceWorker(&Info);
3372#endif
3373 return Info.Status;
3374}
3375
3376/*
3377 *
3378 * The OS specific interface definition
3379 *
3380 */
3381
3382
3383bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3384{
3385 /* AttachToInterface true if disconnected */
3386 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
3387}
3388
3389int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
3390{
3391 int rc = VINF_SUCCESS;
3392 uint32_t cRefs = 0;
3393 PADAPT pAdapt;
3394#if !defined(VBOXNETADP) && !defined(VBOX_NETFLT_ONDEMAND_BIND)
3395 if(fDst & INTNETTRUNKDIR_WIRE)
3396 {
3397 cRefs++;
3398 }
3399 if(fDst & INTNETTRUNKDIR_HOST)
3400 {
3401 cRefs++;
3402 }
3403#else
3404 if(fDst & INTNETTRUNKDIR_WIRE || fDst & INTNETTRUNKDIR_HOST)
3405 {
3406 cRefs = 1;
3407 }
3408#endif
3409
3410 AssertReturn(cRefs, VINF_SUCCESS);
3411
3412 pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3413
3414 if(!vboxNetFltWinIncReferenceAdapt(pAdapt, cRefs))
3415 {
3416 return VERR_GENERAL_FAILURE;
3417 }
3418#ifndef VBOXNETADP
3419 if ((fDst & INTNETTRUNKDIR_WIRE)
3420# ifdef VBOX_NETFLT_ONDEMAND_BIND
3421 || (fDst & INTNETTRUNKDIR_HOST)
3422# endif
3423 )
3424 {
3425 PNDIS_PACKET pPacket;
3426
3427 pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3428 true /*fToWire*/, true /*fCopyMemory*/);
3429
3430 if (pPacket)
3431 {
3432 NDIS_STATUS fStatus;
3433
3434#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3435 vboxNetFltWinLbPutSendPacket(pAdapt, pPacket, true /* bFromIntNet */);
3436#endif
3437 NdisSend(&fStatus, pAdapt->hBindingHandle, pPacket);
3438 if (fStatus != NDIS_STATUS_PENDING)
3439 {
3440#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3441 /* the status is NOT pending, complete the packet */
3442 bool bTmp = vboxNetFltWinLbRemoveSendPacket(pAdapt, pPacket);
3443 Assert(bTmp);
3444#endif
3445 if(!NT_SUCCESS(fStatus))
3446 {
3447 /* TODO: convert status to VERR_xxx */
3448 rc = VERR_GENERAL_FAILURE;
3449 }
3450
3451 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
3452 }
3453 else
3454 {
3455 /* pending, dereference on packet complete */
3456 cRefs--;
3457 }
3458 }
3459 else
3460 {
3461 Assert(0);
3462 rc = VERR_NO_MEMORY;
3463 }
3464 }
3465#endif
3466#ifndef VBOX_NETFLT_ONDEMAND_BIND
3467#ifndef VBOXNETADP
3468 if (fDst & INTNETTRUNKDIR_HOST)
3469#else
3470 if(cRefs)
3471#endif
3472 {
3473 PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3474 false /*fToWire*/, true /*fCopyMemory*/);
3475 if (pPacket)
3476 {
3477 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pPacket, 1);
3478 cRefs--;
3479#ifdef VBOXNETADP
3480 STATISTIC_INCREASE(pAdapt->cRxSuccess);
3481#endif
3482 }
3483 else
3484 {
3485 Assert(0);
3486#ifdef VBOXNETADP
3487 STATISTIC_INCREASE(pAdapt->cRxError);
3488#endif
3489 rc = VERR_NO_MEMORY;
3490 }
3491 }
3492
3493 Assert(cRefs <= 2);
3494
3495 if(cRefs)
3496 {
3497 vboxNetFltWinDecReferenceAdapt(pAdapt, cRefs);
3498 }
3499#endif
3500
3501 return rc;
3502}
3503
3504bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
3505{
3506#ifndef VBOXNETADP
3507 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3508 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3509 {
3510 bool bPromiscuous;
3511 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3512 return false;
3513
3514 bPromiscuous = (pAdapt->fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
3515 /*vboxNetFltWinIsPromiscuous(pAdapt);*/
3516
3517 vboxNetFltWinDereferenceAdapt(pAdapt);
3518 return bPromiscuous;
3519 }
3520 return false;
3521#else
3522 return true;
3523#endif
3524}
3525
3526void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
3527{
3528 *pMac = pThis->u.s.Mac;
3529}
3530
3531bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
3532{
3533 /* ASSUMES that the MAC address never changes. */
3534 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
3535 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
3536 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
3537}
3538
3539void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3540{
3541#ifndef VBOXNETADP
3542 NDIS_STATUS Status;
3543#endif
3544 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3545
3546 /* we first wait for all pending ops to complete
3547 * this might include all packets queued for processing */
3548 for(;;)
3549 {
3550 if(fActive)
3551 {
3552 if(!pThis->u.s.cModePassThruRefs)
3553 {
3554 break;
3555 }
3556 }
3557 else
3558 {
3559 if(!pThis->u.s.cModeNetFltRefs)
3560 {
3561 break;
3562 }
3563 }
3564 vboxNetFltWinSleep(2);
3565 }
3566
3567 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3568 return;
3569#ifndef VBOXNETADP
3570
3571 /* the packets put to ReceiveQueue Array are currently not holding the references,
3572 * simply need to flush them */
3573 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false /*fReturn*/);
3574
3575 if(fActive)
3576 {
3577#ifdef DEBUG_misha
3578 NDIS_PHYSICAL_MEDIUM PhMedium;
3579 bool bPromiscSupported;
3580
3581 Status = vboxNetFltWinQueryPhysicalMedium(pAdapt, &PhMedium);
3582 if(Status != NDIS_STATUS_SUCCESS)
3583 {
3584
3585 DBGPRINT(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3586 Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
3587 if(Status != NDIS_STATUS_NOT_SUPPORTED)
3588 {
3589 LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3590 }
3591 PhMedium = NdisPhysicalMediumUnspecified;
3592 }
3593 else
3594 {
3595 DBGPRINT(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
3596 }
3597
3598 bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
3599 || PhMedium == NdisPhysicalMediumWirelessLan
3600 || PhMedium == NdisPhysicalMediumNative802_11
3601 || PhMedium == NdisPhysicalMediumBluetooth
3602 /*|| PhMedium == NdisPhysicalMediumWiMax */
3603 ));
3604
3605 Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
3606#endif
3607 }
3608
3609 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3610 {
3611 Status = vboxNetFltWinSetPromiscuous(pAdapt, fActive);
3612 if(Status != NDIS_STATUS_SUCCESS)
3613 {
3614 DBGPRINT(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3615 Assert(0);
3616 LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3617 }
3618 }
3619#else
3620# ifdef VBOXNETADP_REPORT_DISCONNECTED
3621 if(fActive)
3622 {
3623 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3624 NDIS_STATUS_MEDIA_CONNECT,
3625 (PVOID)NULL,
3626 0);
3627 }
3628 else
3629 {
3630 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3631 NDIS_STATUS_MEDIA_DISCONNECT,
3632 (PVOID)NULL,
3633 0);
3634 }
3635#else
3636 if(fActive)
3637 {
3638 /* indicate status change to make the ip settings be re-picked for dhcp */
3639 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3640 NDIS_STATUS_MEDIA_DISCONNECT,
3641 (PVOID)NULL,
3642 0);
3643
3644 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3645 NDIS_STATUS_MEDIA_CONNECT,
3646 (PVOID)NULL,
3647 0);
3648 }
3649# endif
3650#endif
3651 vboxNetFltWinDereferenceAdapt(pAdapt);
3652
3653 return;
3654}
3655
3656int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3657{
3658 NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
3659 return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3660}
3661
3662static void vboxNetFltWinConnectItWorker(PWORKER_INFO pInfo)
3663{
3664 NDIS_STATUS Status;
3665 PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
3666 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
3667
3668 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3669
3670 /* this is not a rediscovery, initialize Mac cache */
3671 if(vboxNetFltWinReferenceAdapt(pAdapt))
3672 {
3673#ifndef VBOXNETADP
3674 Status = vboxNetFltWinGetMacAddress(pAdapt, &pInstance->u.s.Mac);
3675 if (Status == NDIS_STATUS_SUCCESS)
3676#endif
3677 {
3678 Status = vboxNetFltWinQuInitPacketQueue(pInstance);
3679 if(Status == NDIS_STATUS_SUCCESS)
3680 {
3681 pInfo->Status = VINF_SUCCESS;
3682 }
3683 else
3684 {
3685 pInfo->Status = VERR_GENERAL_FAILURE;
3686 }
3687 }
3688#ifndef VBOXNETADP
3689 else
3690 {
3691 pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
3692 }
3693#endif
3694
3695 vboxNetFltWinDereferenceAdapt(pAdapt);
3696 }
3697 else
3698 {
3699 pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
3700 }
3701}
3702
3703static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
3704{
3705 WORKER_INFO Info;
3706 Info.pNetFltIf = pThis;
3707
3708 vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
3709
3710 return Info.Status;
3711}
3712
3713int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3714{
3715 return vboxNetFltWinConnectIt(pThis);
3716}
3717
3718void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3719{
3720 vboxNetFltWinDeleteInstance(pThis);
3721}
3722
3723int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3724{
3725 int rc = RTSemMutexCreate(&pThis->u.s.hAdaptMutex);
3726 if (RT_SUCCESS(rc))
3727 {
3728 rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
3729 if (RT_SUCCESS(rc))
3730 {
3731 return rc;
3732 }
3733 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3734 }
3735 return rc;
3736}
3737
3738int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3739{
3740 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3741 pThis->u.s.cModeNetFltRefs = 0;
3742 pThis->u.s.cModePassThruRefs = 0;
3743 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3744 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3745#ifndef VBOXNETADP
3746 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3747#endif
3748 return VINF_SUCCESS;
3749}
3750
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