VirtualBox

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

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

netflt/win: better driver initialization (do NdisIMAssociateMiniport right after Protocol & Miniport registration), netadp/win: don't report connection status on cunstruction (not needed), 2d accel: better 2D support test logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 105.8 KB
Line 
1/* $Id: VBoxNetFlt-win.c 24758 2009-11-18 12:57:48Z 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#ifdef VBOX_LOOPBACK_USEFLAGS
1964 ULONG MjVersion;
1965 ULONG MnVersion;
1966#endif
1967
1968 NdisAllocateSpinLock(&g_GlobalLock);
1969
1970#ifdef VBOX_NETFLT_ONDEMAND_BIND
1971 /* we are registering in the DriverEntry only when we are working as a protocol
1972 * since in this case our driver is loaded after the VBoxDrv*/
1973 rc = vboxNetFltWinInitNetFlt();
1974#else
1975 /* the idc registration is initiated via IOCTL since our driver
1976 * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
1977 rc = vboxNetFltWinInitNetFltBase();
1978#endif
1979 AssertRC(rc);
1980 if(RT_SUCCESS(rc))
1981 {
1982#ifdef VBOX_LOOPBACK_USEFLAGS
1983 PsGetVersion(&MjVersion, &MnVersion,
1984 NULL, /* PULONG BuildNumber OPTIONAL */
1985 NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
1986 );
1987
1988 g_fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
1989
1990 if(MjVersion == 5 && MnVersion == 0)
1991 {
1992 /* this is Win2k*/
1993 g_fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
1994 }
1995
1996 g_fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
1997#endif
1998
1999 Status = vboxNetFltWinJobInitQueue(&g_JobQueue);
2000 Assert(Status == STATUS_SUCCESS);
2001 if(Status == STATUS_SUCCESS)
2002 {
2003 /* note: we do it after we initialize the Job Queue */
2004 vboxNetFltWinStartInitIdcProbing();
2005
2006#ifndef VBOX_NETFLT_ONDEMAND_BIND
2007 Status = vboxNetFltWinMpRegister(DriverObject, RegistryPath);
2008 Assert(Status == STATUS_SUCCESS);
2009 if (Status == NDIS_STATUS_SUCCESS)
2010#endif
2011 {
2012#ifndef VBOXNETADP
2013 Status = vboxNetFltWinPtRegister(DriverObject, RegistryPath);
2014 Assert(Status == STATUS_SUCCESS);
2015 if (Status == NDIS_STATUS_SUCCESS)
2016#endif
2017 {
2018#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
2019 vboxNetFltWinAssociateMiniportProtocol();
2020#endif
2021 return STATUS_SUCCESS;
2022
2023//#ifndef VBOXNETADP
2024// vboxNetFltWinPtDeregister();
2025//#endif
2026 }
2027#ifndef VBOX_NETFLT_ONDEMAND_BIND
2028 vboxNetFltWinMpDeregister();
2029#endif
2030 }
2031 vboxNetFltWinJobFiniQueue(&g_JobQueue);
2032 }
2033 vboxNetFltWinFiniNetFlt();
2034 }
2035 else
2036 {
2037 Status = NDIS_STATUS_FAILURE;
2038 }
2039
2040 NdisFreeSpinLock(&g_GlobalLock);
2041
2042 return(Status);
2043}
2044
2045#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
2046/**
2047 * creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
2048 * according to DDK docs we must create our own packet rather than posting the one passed to us
2049 */
2050DECLHIDDEN(NDIS_STATUS)
2051vboxNetFltWinPrepareSendPacket(
2052 IN PADAPT pAdapt,
2053 IN PNDIS_PACKET pPacket,
2054 OUT PNDIS_PACKET *ppMyPacket
2055 /*, IN bool bNetFltActive */
2056 )
2057{
2058 NDIS_STATUS fStatus;
2059
2060 NdisAllocatePacket(&fStatus,
2061 ppMyPacket,
2062 pAdapt->hSendPacketPoolHandle);
2063
2064 if (fStatus == NDIS_STATUS_SUCCESS)
2065 {
2066 PSEND_RSVD pSendRsvd;
2067
2068 pSendRsvd = (PSEND_RSVD)((*ppMyPacket)->ProtocolReserved);
2069 pSendRsvd->pOriginalPkt = pPacket;
2070 pSendRsvd->pBufToFree = NULL;
2071
2072 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2073 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2074
2075 vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
2076
2077#ifdef VBOX_LOOPBACK_USEFLAGS
2078 NdisGetPacketFlags(*ppMyPacket) |= g_fPacketDontLoopBack;
2079#endif
2080 }
2081 else
2082 {
2083 *ppMyPacket = NULL;
2084 }
2085
2086 return fStatus;
2087}
2088
2089/**
2090 * creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
2091 * according to DDK docs we must create our own packet rather than posting the one passed to us
2092 */
2093DECLHIDDEN(NDIS_STATUS)
2094vboxNetFltWinPrepareRecvPacket(
2095 IN PADAPT pAdapt,
2096 IN PNDIS_PACKET pPacket,
2097 OUT PNDIS_PACKET *ppMyPacket,
2098 IN bool bDpr
2099 )
2100{
2101 NDIS_STATUS fStatus;
2102
2103 /*
2104 * Get a packet off the pool and indicate that up
2105 */
2106 if(bDpr)
2107 {
2108 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
2109
2110 NdisDprAllocatePacket(&fStatus,
2111 ppMyPacket,
2112 pAdapt->hRecvPacketPoolHandle);
2113 }
2114 else
2115 {
2116 NdisAllocatePacket(&fStatus,
2117 ppMyPacket,
2118 pAdapt->hRecvPacketPoolHandle);
2119 }
2120
2121 if (fStatus == NDIS_STATUS_SUCCESS)
2122 {
2123 PRECV_RSVD pRecvRsvd;
2124
2125 pRecvRsvd = (PRECV_RSVD)((*ppMyPacket)->MiniportReserved);
2126 pRecvRsvd->pOriginalPkt = pPacket;
2127 pRecvRsvd->pBufToFree = NULL;
2128
2129 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2130 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2131
2132 fStatus = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket);
2133 }
2134 else
2135 {
2136 *ppMyPacket = NULL;
2137 }
2138 return fStatus;
2139}
2140#endif
2141
2142/**
2143 * initializes the ADAPT (our context structure) and binds to the given adapter
2144 */
2145#if defined(VBOX_NETFLT_ONDEMAND_BIND)
2146DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT pAdapt)
2147#elif defined(VBOXNETADP)
2148DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
2149#else
2150DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
2151#endif
2152{
2153 NDIS_STATUS Status;
2154 do
2155 {
2156#ifndef VBOX_NETFLT_ONDEMAND_BIND
2157 ANSI_STRING AnsiString;
2158 int rc;
2159 PVBOXNETFLTINS pInstance;
2160 USHORT cbAnsiName = pBindToMiniportName->Length;/* the lenght is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
2161 CREATE_INSTANCE_CONTEXT Context;
2162 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2163
2164# ifndef VBOXNETADP
2165 Context.pOurName = pOurMiniportName;
2166 Context.pBindToName = pBindToMiniportName;
2167# else
2168 Context.hMiniportAdapter = hMiniportAdapter;
2169 Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
2170# endif
2171 Context.Status = NDIS_STATUS_SUCCESS;
2172
2173 AnsiString.Buffer = 0; /* will be allocated by RtlUnicodeStringToAnsiString */
2174 AnsiString.Length = 0;
2175 AnsiString.MaximumLength = cbAnsiName;
2176
2177 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2178
2179 Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, true);
2180
2181 if(Status != STATUS_SUCCESS)
2182 {
2183 break;
2184 }
2185
2186 rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, AnsiString.Buffer, &pInstance, &Context);
2187 RtlFreeAnsiString(&AnsiString);
2188 if(RT_FAILURE(rc))
2189 {
2190 Assert(0);
2191 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2192 break;
2193 }
2194
2195 Assert(pInstance);
2196
2197 if(rc == VINF_ALREADY_INITIALIZED)
2198 {
2199 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2200 /* the case when our adapter was unbound while IntNet was connected to it */
2201 /* the instance remains valid until intNet disconnects from it, we simply search and re-use it*/
2202
2203 /* re-initialize PADAPT */
2204 rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
2205 if(RT_FAILURE(rc))
2206 {
2207 Assert(0);
2208 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2209 /* release netflt */
2210 vboxNetFltRelease(pInstance, false);
2211
2212 break;
2213 }
2214 }
2215
2216 *ppAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2217#else
2218 Status = vboxNetFltWinPtAllocInitPADAPT(pAdapt);
2219 if (Status != NDIS_STATUS_SUCCESS)
2220 {
2221 break;
2222 }
2223
2224 Status = vboxNetFltWinPtDoBinding(pAdapt);
2225 if (Status != NDIS_STATUS_SUCCESS)
2226 {
2227 vboxNetFltWinPtFiniPADAPT(pAdapt);
2228 break;
2229 }
2230#endif
2231 }while(FALSE);
2232
2233 return Status;
2234}
2235
2236/**
2237 * initializes the ADAPT
2238 */
2239#ifdef VBOX_NETFLT_ONDEMAND_BIND
2240DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT pAdapt)
2241{
2242 NDIS_STATUS Status;
2243
2244 do
2245 {
2246 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
2247 if (Status != NDIS_STATUS_SUCCESS)
2248 {
2249 break;
2250 }
2251 Status = NDIS_STATUS_SUCCESS;
2252 } while(0);
2253
2254 return Status;
2255}
2256
2257/**
2258 * unbinds from the adapter we are bound to and deinitializes the ADAPT
2259 */
2260static NDIS_STATUS vboxNetFltWinPtFiniUnbind(PADAPT pAdapt)
2261{
2262 NDIS_STATUS Status;
2263
2264 LogFlow(("==> vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2265
2266 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2267
2268 do
2269 {
2270 Status = vboxNetFltWinPtDoUnbinding(pAdapt, true);
2271 if(Status != NDIS_STATUS_SUCCESS)
2272 {
2273 Assert(0);
2274 /* TODO: should we break ? */
2275 /* break; */
2276 }
2277
2278 vboxNetFltWinPtFiniPADAPT(pAdapt);
2279 } while(0);
2280 LogFlow(("<== vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2281
2282 return Status;
2283}
2284#endif
2285
2286/*
2287 * deinitializes the ADAPT
2288 */
2289DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt)
2290{
2291#ifndef VBOXNETADP
2292 int rc;
2293#endif
2294
2295 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2296
2297 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2298#ifndef VBOXNETADP
2299 if(pAdapt->DeviceName.Buffer)
2300 {
2301 vboxNetFltWinMemFree(pAdapt->DeviceName.Buffer);
2302 }
2303
2304
2305 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2306# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2307 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2308# endif
2309#endif
2310
2311#ifndef VBOX_NETFLT_ONDEMAND_BIND
2312 /* moved to vboxNetFltWinDetachFromInterfaceWorker */
2313#else
2314 vboxNetFltWinQuFiniPacketQueue(pAdapt);
2315#endif
2316
2317 vboxNetFltWinFiniBuffers(pAdapt);
2318
2319 /*
2320 * Free the memory here, if was not released earlier(by calling the HaltHandler)
2321 */
2322 vboxNetFltWinPtFreeAllPacketPools (pAdapt);
2323#ifndef VBOXNETADP
2324 rc = RTSemFastMutexDestroy(pAdapt->hSynchRequestMutex); AssertRC(rc);
2325#endif
2326
2327 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2328}
2329
2330DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
2331#ifndef VBOXNETADP
2332DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName)
2333#else
2334DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt)
2335#endif
2336{
2337 NDIS_STATUS Status;
2338#ifndef VBOXNETADP
2339 int rc;
2340#endif
2341 BOOLEAN bCallFiniOnFail = FALSE;
2342
2343 LogFlow(("==> vboxNetFltWinPtInitPADAPT : pAdapt %p\n", pAdapt));
2344
2345 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2346
2347 do
2348 {
2349 NdisZeroMemory(pAdapt, sizeof(ADAPT));
2350#ifndef VBOXNETADP
2351 NdisInitializeEvent(&pAdapt->hEvent);
2352
2353 KeInitializeEvent(&pAdapt->hSynchCompletionEvent, SynchronizationEvent, FALSE);
2354
2355 /*
2356 * Allocate a packet pool for sends. We need this to pass sends down.
2357 * We cannot use the same packet descriptor that came down to our send
2358 * handler (see also NDIS 5.1 packet stacking).
2359 */
2360 NdisAllocatePacketPoolEx(&Status,
2361 &pAdapt->hSendPacketPoolHandle,
2362 MIN_PACKET_POOL_SIZE,
2363 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2364 sizeof(SEND_RSVD));
2365
2366 if (Status != NDIS_STATUS_SUCCESS)
2367 {
2368 pAdapt->hSendPacketPoolHandle = NULL;
2369 break;
2370 }
2371#else
2372#endif
2373
2374 Status = vboxNetFltWinInitBuffers(pAdapt);
2375 if (Status != NDIS_STATUS_SUCCESS)
2376 {
2377 break;
2378 }
2379
2380 bCallFiniOnFail = TRUE;
2381#ifndef VBOXNETADP
2382 rc = RTSemFastMutexCreate(&pAdapt->hSynchRequestMutex);
2383 if(RT_FAILURE(rc))
2384 {
2385 Status = NDIS_STATUS_FAILURE;
2386 break;
2387 }
2388#endif
2389
2390#ifndef VBOX_NETFLT_ONDEMAND_BIND
2391# ifndef VBOXNETADP
2392 Status = vboxNetFltWinMemAlloc((PVOID*)&pAdapt->DeviceName.Buffer, pOurDeviceName->Length);
2393 if(Status != NDIS_STATUS_SUCCESS)
2394 {
2395 Assert(0);
2396 pAdapt->DeviceName.Buffer = NULL;
2397 break;
2398 }
2399 pAdapt->DeviceName.MaximumLength = pOurDeviceName->Length;
2400 pAdapt->DeviceName.Length = 0;
2401 Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
2402 if(Status != NDIS_STATUS_SUCCESS)
2403 {
2404 Assert(0);
2405 break;
2406 }
2407# endif
2408
2409 /*
2410 * Allocate a packet pool for receives. We need this to indicate receives.
2411 * Same consideration as sends (see also NDIS 5.1 packet stacking).
2412 */
2413 NdisAllocatePacketPoolEx(&Status,
2414 &pAdapt->hRecvPacketPoolHandle,
2415 MIN_PACKET_POOL_SIZE,
2416 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2417 PROTOCOL_RESERVED_SIZE_IN_PACKET);
2418
2419 if (Status != NDIS_STATUS_SUCCESS)
2420 {
2421 pAdapt->hRecvPacketPoolHandle = NULL;
2422 break;
2423 }
2424#ifndef VBOXNETADP
2425 NdisInitializeEvent(&pAdapt->MiniportInitEvent);
2426#endif
2427#endif
2428#ifndef VBOXNETADP
2429 pAdapt->PTState.PowerState = NdisDeviceStateD3;
2430 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
2431
2432 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2433
2434# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2435 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2436# endif
2437#endif
2438 /* TODO: do we need it here ?? */
2439 pAdapt->MPState.PowerState = NdisDeviceStateD3;
2440 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
2441
2442#ifdef VBOX_NETFLT_ONDEMAND_BIND
2443 {
2444 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2445 rc = vboxNetFltWinConnectIt(pNetFlt);
2446 if(RT_FAILURE(rc))
2447 {
2448 Assert(0);
2449 Status = NDIS_STATUS_FAILURE;
2450 break;
2451 }
2452 }
2453#endif
2454
2455 /* moved to vboxNetFltOsInitInstance */
2456 } while(0);
2457
2458 if (Status != NDIS_STATUS_SUCCESS)
2459 {
2460 if(bCallFiniOnFail)
2461 {
2462 vboxNetFltWinPtFiniPADAPT(pAdapt);
2463 }
2464 }
2465
2466 LogFlow(("<== vboxNetFltWinPtInitPADAPT : pAdapt %p, Status %x\n", pAdapt, Status));
2467
2468 return Status;
2469}
2470
2471/**
2472 * match packets
2473 */
2474#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
2475#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
2476#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
2477#define LAST_LIST_ENTRY PREV_LIST_ENTRY
2478
2479#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
2480
2481#ifndef VBOXNETADP
2482
2483#ifdef DEBUG_misha
2484
2485RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2486RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
2487
2488DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
2489{
2490 UINT cBufCount1;
2491 PNDIS_BUFFER pBuffer1;
2492 UINT uTotalPacketLength1;
2493 RTNETETHERHDR* pEth;
2494 UINT cbLength1 = 0;
2495 UINT i = 0;
2496
2497 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2498
2499 Assert(pBuffer1);
2500 Assert(uTotalPacketLength1 >= ETH_HEADER_SIZE);
2501 if(uTotalPacketLength1 < ETH_HEADER_SIZE)
2502 return NULL;
2503
2504 NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
2505 Assert(cbLength1 >= ETH_HEADER_SIZE);
2506 if(cbLength1 < ETH_HEADER_SIZE)
2507 return NULL;
2508
2509 return pEth;
2510}
2511
2512DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
2513{
2514 Assert(pSG->cSegsUsed);
2515 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2516 Assert(pSG->aSegs[0].cb >= ETH_HEADER_SIZE);
2517
2518 if(!pSG->cSegsUsed)
2519 return NULL;
2520
2521 if(pSG->aSegs[0].cb < ETH_HEADER_SIZE)
2522 return NULL;
2523
2524 return (PRTNETETHERHDR)pSG->aSegs[0].pv;
2525}
2526
2527DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
2528{
2529 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
2530 Assert(pHdr);
2531
2532 if(!pHdr)
2533 return false;
2534
2535 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2536 return false;
2537
2538 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2539 return false;
2540
2541 return true;
2542}
2543
2544DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
2545{
2546 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
2547 Assert(pHdr);
2548
2549 if(!pHdr)
2550 return false;
2551
2552 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2553 return false;
2554
2555 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2556 return false;
2557
2558 return true;
2559}
2560#endif
2561
2562# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
2563/*
2564 * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
2565 * if cbMatch < 0 matches complete packets.
2566 */
2567DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
2568{
2569 UINT cBufCount1;
2570 PNDIS_BUFFER pBuffer1;
2571 UINT uTotalPacketLength1;
2572 uint8_t* pMemBuf1;
2573 UINT cbLength1 = 0;
2574
2575 UINT cBufCount2;
2576 PNDIS_BUFFER pBuffer2;
2577 UINT uTotalPacketLength2;
2578 uint8_t* pMemBuf2;
2579 UINT cbLength2 = 0;
2580 bool bMatch = true;
2581
2582#ifdef DEBUG_NETFLT_PACKETS
2583 bool bCompleteMatch = false;
2584#endif
2585
2586 NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2587 NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
2588
2589 Assert(pBuffer1);
2590 Assert(pBuffer2);
2591
2592 if(uTotalPacketLength1 != uTotalPacketLength2)
2593 {
2594 bMatch = false;
2595 }
2596 else
2597 {
2598 UINT ucbLength2Match = 0;
2599 UINT ucbMatch;
2600 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2601 {
2602 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2603 ucbMatch = uTotalPacketLength1;
2604#ifdef DEBUG_NETFLT_PACKETS
2605 bCompleteMatch = true;
2606#endif
2607 }
2608 else
2609 {
2610 ucbMatch = (UINT)cbMatch;
2611 }
2612
2613 for(;;)
2614 {
2615 if(!cbLength1)
2616 {
2617 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2618 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2619 }
2620 else
2621 {
2622 Assert(pMemBuf1);
2623 Assert(ucbLength2Match);
2624 pMemBuf1 += ucbLength2Match;
2625 }
2626
2627 if(!cbLength2)
2628 {
2629 NdisQueryBufferSafe(pBuffer2, &pMemBuf2, &cbLength2, NormalPagePriority);
2630 NdisGetNextBuffer(pBuffer2, &pBuffer2);
2631 }
2632 else
2633 {
2634 Assert(pMemBuf2);
2635 Assert(ucbLength2Match);
2636 pMemBuf2 += ucbLength2Match;
2637 }
2638
2639 ucbLength2Match = MIN(ucbMatch, cbLength1);
2640 ucbLength2Match = MIN(ucbMatch, cbLength2);
2641
2642 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2643 {
2644 bMatch = false;
2645 break;
2646 }
2647
2648 ucbMatch -= ucbLength2Match;
2649 if(!ucbMatch)
2650 break;
2651
2652 cbLength1 -= ucbLength2Match;
2653 cbLength2 -= ucbLength2Match;
2654 }
2655 }
2656
2657#ifdef DEBUG_NETFLT_PACKETS
2658 if(bMatch && !bCompleteMatch)
2659 {
2660 /* check that the packets fully match */
2661 DBG_CHECK_PACKETS(pPacket1, pPacket2);
2662 }
2663#endif
2664
2665 return bMatch;
2666}
2667
2668/*
2669 * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
2670 * if cbMatch < 0 matches complete packets.
2671 */
2672DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
2673{
2674 UINT cBufCount1;
2675 PNDIS_BUFFER pBuffer1;
2676 UINT uTotalPacketLength1;
2677 uint8_t* pMemBuf1;
2678 UINT cbLength1 = 0;
2679 UINT uTotalPacketLength2 = pSG->cbTotal;
2680 uint8_t* pMemBuf2;
2681 UINT cbLength2 = 0;
2682 bool bMatch = true;
2683 bool bCompleteMatch = false;
2684 UINT i = 0;
2685
2686 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2687
2688 Assert(pBuffer1);
2689 Assert(pSG->cSegsUsed);
2690 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2691
2692 if(uTotalPacketLength1 != uTotalPacketLength2)
2693 {
2694 Assert(0);
2695 bMatch = false;
2696 }
2697 else
2698 {
2699 UINT ucbLength2Match = 0;
2700 UINT ucbMatch;
2701
2702 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2703 {
2704 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2705 ucbMatch = uTotalPacketLength1;
2706 bCompleteMatch = true;
2707 }
2708 else
2709 {
2710 ucbMatch = (UINT)cbMatch;
2711 }
2712
2713 for(;;)
2714 {
2715 if(!cbLength1)
2716 {
2717 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2718 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2719 }
2720 else
2721 {
2722 Assert(pMemBuf1);
2723 Assert(ucbLength2Match);
2724 pMemBuf1 += ucbLength2Match;
2725 }
2726
2727 if(!cbLength2)
2728 {
2729 Assert(i < pSG->cSegsUsed);
2730 pMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
2731 cbLength2 = pSG->aSegs[i].cb;
2732 i++;
2733 }
2734 else
2735 {
2736 Assert(pMemBuf2);
2737 Assert(ucbLength2Match);
2738 pMemBuf2 += ucbLength2Match;
2739 }
2740
2741 ucbLength2Match = MIN(ucbMatch, cbLength1);
2742 ucbLength2Match = MIN(ucbMatch, cbLength2);
2743
2744 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2745 {
2746 bMatch = false;
2747 Assert(0);
2748 break;
2749 }
2750
2751 ucbMatch -= ucbLength2Match;
2752 if(!ucbMatch)
2753 break;
2754
2755 cbLength1 -= ucbLength2Match;
2756 cbLength2 -= ucbLength2Match;
2757 }
2758 }
2759
2760 if(bMatch && !bCompleteMatch)
2761 {
2762 /* check that the packets fully match */
2763 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
2764 }
2765 return bMatch;
2766}
2767
2768# if 0
2769/*
2770 * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
2771 * if cbMatch < 0 matches complete packets.
2772 */
2773static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
2774{
2775 UINT uTotalPacketLength1 = pSG1->cbTotal;
2776 PVOID pMemBuf1;
2777 UINT cbLength1 = 0;
2778 UINT i1 = 0;
2779 UINT uTotalPacketLength2 = pSG2->cbTotal;
2780 PVOID pMemBuf2;
2781 UINT cbLength2 = 0;
2782
2783 bool bMatch = true;
2784 bool bCompleteMatch = false;
2785 UINT i2 = 0;
2786
2787 Assert(pSG1->cSegsUsed);
2788 Assert(pSG2->cSegsUsed);
2789 Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
2790 Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
2791
2792 if(uTotalPacketLength1 != uTotalPacketLength2)
2793 {
2794 Assert(0);
2795 bMatch = false;
2796 }
2797 else
2798 {
2799 UINT ucbMatch;
2800 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2801 {
2802 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2803 ucbMatch = uTotalPacketLength1;
2804 bCompleteMatch = true;
2805 }
2806 else
2807 {
2808 ucbMatch = (UINT)cbMatch;
2809 }
2810
2811 do
2812 {
2813 UINT ucbLength2Match;
2814 if(!cbLength1)
2815 {
2816 Assert(i1 < pSG1->cSegsUsed);
2817 pMemBuf1 = pSG1->aSegs[i1].pv;
2818 cbLength1 = pSG1->aSegs[i1].cb;
2819 i1++;
2820 }
2821
2822 if(!cbLength2)
2823 {
2824 Assert(i2 < pSG2->cSegsUsed);
2825 pMemBuf2 = pSG2->aSegs[i2].pv;
2826 cbLength2 = pSG2->aSegs[i2].cb;
2827 i2++;
2828 }
2829
2830 ucbLength2Match = MIN(ucbMatch, cbLength1);
2831 ucbLength2Match = MIN(ucbMatch, cbLength2);
2832
2833 if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
2834 {
2835 bMatch = false;
2836 Assert(0);
2837 break;
2838 }
2839 ucbMatch -= ucbLength2Match;
2840 cbLength1 -= ucbLength2Match;
2841 cbLength2 -= ucbLength2Match;
2842 } while (ucbMatch);
2843 }
2844
2845 if(bMatch && !bCompleteMatch)
2846 {
2847 /* check that the packets fully match */
2848 DBG_CHECK_SGS(pSG1, pSG2);
2849 }
2850 return bMatch;
2851}
2852# endif
2853# endif
2854#endif
2855
2856static void vboxNetFltWinFiniNetFltBase()
2857{
2858 do
2859 {
2860 vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
2861
2862 /*
2863 * Undo the work done during start (in reverse order).
2864 */
2865 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2866
2867 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
2868 RTLogDestroy(RTLogSetDefaultInstance(NULL));
2869
2870 RTR0Term();
2871 } while (0);
2872}
2873
2874static int vboxNetFltWinTryFiniIdc()
2875{
2876 int rc;
2877
2878 vboxNetFltWinStopInitIdcProbing();
2879
2880 if(g_bIdcInitialized)
2881 {
2882 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2883 if(RT_SUCCESS(rc))
2884 {
2885 g_bIdcInitialized = false;
2886 }
2887 }
2888 else
2889 {
2890 rc = VINF_SUCCESS;
2891 }
2892 return rc;
2893
2894}
2895
2896static int vboxNetFltWinFiniNetFlt()
2897{
2898 int rc = vboxNetFltWinTryFiniIdc();
2899 if(RT_SUCCESS(rc))
2900 {
2901 vboxNetFltWinFiniNetFltBase();
2902 }
2903 return rc;
2904}
2905
2906/**
2907 * base netflt initialization
2908 */
2909static int vboxNetFltWinInitNetFltBase()
2910{
2911 int rc;
2912
2913 do
2914 {
2915 Assert(!g_bIdcInitialized);
2916
2917 rc = RTR0Init(0);
2918 if (!RT_SUCCESS(rc))
2919 {
2920 break;
2921 }
2922
2923 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2924 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
2925 if (!RT_SUCCESS(rc))
2926 {
2927 RTR0Term();
2928 break;
2929 }
2930 }while(0);
2931
2932 return rc;
2933}
2934
2935/**
2936 * initialize IDC
2937 */
2938static int vboxNetFltWinInitIdc()
2939{
2940 int rc;
2941
2942 do
2943 {
2944 if(g_bIdcInitialized)
2945 {
2946#ifdef VBOX_NETFLT_ONDEMAND_BIND
2947 Assert(0);
2948#endif
2949 rc = VINF_ALREADY_INITIALIZED;
2950 break;
2951 }
2952
2953 /*
2954 * connect to the support driver.
2955 *
2956 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
2957 * for establishing the connect to the support driver.
2958 */
2959 rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
2960 if (!RT_SUCCESS(rc))
2961 {
2962 break;
2963 }
2964
2965 g_bIdcInitialized = true;
2966 } while (0);
2967
2968 return rc;
2969}
2970
2971static void vboxNetFltWinInitIdcProbingWorker(PINIT_IDC_INFO pInitIdcInfo)
2972{
2973 int rc = vboxNetFltWinInitIdc();
2974 if(RT_FAILURE(rc))
2975 {
2976 bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2977 if(!bInterupted)
2978 {
2979 RTThreadSleep(1000); /* 1 s */
2980 bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2981 if(!bInterupted)
2982 {
2983 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &pInitIdcInfo->Job, false);
2984 return;
2985 }
2986 }
2987
2988 /* it's interupted */
2989 rc = VERR_INTERRUPTED;
2990 }
2991
2992 ASMAtomicUoWriteU32(&pInitIdcInfo->rc, rc);
2993 KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
2994}
2995
2996static int vboxNetFltWinStopInitIdcProbing()
2997{
2998 if(!g_InitIdcInfo.bInitialized)
2999 return VERR_INVALID_STATE;
3000
3001 ASMAtomicUoWriteBool(&g_InitIdcInfo.bStop, true);
3002 KeWaitForSingleObject(&g_InitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
3003
3004 return g_InitIdcInfo.rc;
3005}
3006
3007static int vboxNetFltWinStartInitIdcProbing()
3008{
3009 Assert(!g_bIdcInitialized);
3010 KeInitializeEvent(&g_InitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
3011 g_InitIdcInfo.bStop = false;
3012 g_InitIdcInfo.bInitialized = true;
3013 vboxNetFltWinJobInit(&g_InitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_InitIdcInfo, false);
3014 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &g_InitIdcInfo.Job, false);
3015 return VINF_SUCCESS;
3016}
3017
3018static int vboxNetFltWinInitNetFlt()
3019{
3020 int rc;
3021
3022 do
3023 {
3024 rc = vboxNetFltWinInitNetFltBase();
3025 if(RT_FAILURE(rc))
3026 {
3027 Assert(0);
3028 break;
3029 }
3030
3031 /*
3032 * connect to the support driver.
3033 *
3034 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
3035 * for establishing the connect to the support driver.
3036 */
3037 rc = vboxNetFltWinInitIdc();
3038 if (RT_FAILURE(rc))
3039 {
3040 Assert(0);
3041 vboxNetFltWinFiniNetFltBase();
3042 break;
3043 }
3044 } while (0);
3045
3046 return rc;
3047}
3048
3049/* detach*/
3050static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
3051{
3052 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3053 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3054 NDIS_STATUS Status;
3055 LogFlow(("vboxNetFltWinDeleteInstance: pThis=%p \n", pThis));
3056
3057 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3058 Assert(pAdapt);
3059 Assert(pThis);
3060 Assert(pThis->fDisconnectedFromHost);
3061 Assert(!pThis->fRediscoveryPending);
3062 Assert(!pThis->fActive);
3063#ifndef VBOXNETADP
3064 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
3065 Assert(!pAdapt->hBindingHandle);
3066#endif
3067 Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Deinitialized);
3068 Assert(!pThis->u.s.PacketQueueWorker.pSG);
3069// Assert(!pAdapt->hMiniportHandle);
3070
3071#ifndef VBOX_NETFLT_ONDEMAND_BIND
3072 Status = vboxNetFltWinMpDereferenceControlDevice();
3073 Assert(Status == NDIS_STATUS_SUCCESS);
3074#else
3075 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3076 if(Status != NDIS_STATUS_SUCCESS)
3077 {
3078 Assert(0);
3079 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3080 }
3081#endif
3082
3083 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3084
3085 return VINF_SUCCESS;
3086}
3087
3088static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
3089{
3090 vboxNetFltWinQuFiniPacketQueue(pInstance);
3091 return NDIS_STATUS_SUCCESS;
3092}
3093
3094/* detach*/
3095DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PADAPT pAdapt, bool bOnUnbind)
3096{
3097 PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
3098 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3099 NDIS_STATUS Status;
3100 int rc;
3101 LogFlow(("vboxNetFltWinDetachFromInterface: pThis=%p\n", pThis));
3102
3103 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3104 Assert(pAdapt);
3105 Assert(pThis);
3106/* Assert(!pThis->fActive); */
3107
3108 /* paranoya to ensyre the instance is not removed while we're waiting on the mutex
3109 * in case ndis does something unpredictable, e.g. calls our miniport halt independently
3110 * from protocol unbind and concurrently with it*/
3111 vboxNetFltRetain(pThis, false);
3112
3113 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3114 if(RT_SUCCESS(rc))
3115 {
3116#ifndef VBOX_NETFLT_ONDEMAND_BIND
3117 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected);
3118 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3119#ifndef VBOXNETADP
3120 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3121#endif
3122// if(
3123//#ifdef VBOXNETADP
3124// vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3125//#else
3126// vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized
3127//// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3128//#endif
3129// )
3130 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected)
3131 {
3132 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnecting);
3133#ifndef VBOXNETADP
3134 Status = vboxNetFltWinPtDoUnbinding(pAdapt, bOnUnbind);
3135#else
3136 Status = vboxNetFltWinMpDoDeinitialization(pAdapt);
3137#endif
3138 Assert(Status == NDIS_STATUS_SUCCESS);
3139
3140 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3141 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3142#ifndef VBOXNETADP
3143 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3144#endif
3145// /* paranoya */
3146// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3147//#ifndef VBOXNETADP
3148// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3149//#endif
3150
3151 vboxNetFltWinPtFiniPADAPT(pAdapt);
3152
3153 /* we're unbinding, make an unbind-related release */
3154 vboxNetFltRelease(pThis, false);
3155#else
3156 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3157 if(Status != NDIS_STATUS_SUCCESS)
3158 {
3159 Assert(0);
3160 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3161 }
3162#endif
3163 }
3164 else
3165 {
3166 AssertBreakpoint();
3167#ifndef VBOXNETADP
3168 pAdapt->Status = NDIS_STATUS_FAILURE;
3169#endif
3170 if(!bOnUnbind)
3171 {
3172 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3173 }
3174 Status = NDIS_STATUS_FAILURE;
3175 }
3176 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3177 }
3178 else
3179 {
3180 AssertBreakpoint();
3181 Status = NDIS_STATUS_FAILURE;
3182 }
3183
3184 /* release for the retain we made before waining on the mutex */
3185 vboxNetFltRelease(pThis, false);
3186
3187 return Status;
3188}
3189
3190/**
3191 * Worker for vboxNetFltWinAttachToInterface.
3192 *
3193 * @param pAttachInfo Structure for communicating with
3194 * vboxNetFltWinAttachToInterface.
3195 */
3196static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
3197{
3198 PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
3199 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3200 int rc;
3201 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3202
3203 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3204
3205 /* to ensure we're not removed while we're here */
3206 vboxNetFltRetain(pThis, false);
3207
3208 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3209 if(RT_SUCCESS(rc))
3210 {
3211 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3212 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected);
3213 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3214#ifndef VBOXNETADP
3215 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3216#endif
3217// if(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3218//#ifndef VBOXNETADP
3219// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3220//#endif
3221// )
3222 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected)
3223 {
3224
3225#ifndef VBOX_NETFLT_ONDEMAND_BIND
3226 if(pAttachInfo->fRediscovery)
3227 {
3228 /* rediscovery means adaptor bind is performed while intnet is already using it
3229 * i.e. adaptor was unbound while being used by intnet and now being bound back again */
3230 Assert(((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState)) == kVBoxNetFltInsState_Connected);
3231 }
3232#ifndef VBOXNETADP
3233 Status = vboxNetFltWinPtInitPADAPT(pAdapt, pAttachInfo->pCreateContext->pOurName);
3234#else
3235 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
3236#endif
3237 if(Status == NDIS_STATUS_SUCCESS)
3238 {
3239 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connecting);
3240
3241#ifndef VBOXNETADP
3242 Status = vboxNetFltWinPtDoBinding(pAdapt, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
3243#else
3244 Status = vboxNetFltWinMpDoInitialization(pAdapt, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
3245#endif
3246 if (Status == NDIS_STATUS_SUCCESS)
3247 {
3248 if(pAttachInfo->fRediscovery || (Status = vboxNetFltWinMpReferenceControlDevice()) == NDIS_STATUS_SUCCESS)
3249 {
3250#ifndef VBOXNETADP
3251 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
3252#endif
3253 {
3254 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connected);
3255// Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3256#ifndef VBOXNETADP
3257 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3258#endif
3259// /* paranoya */
3260//// vboxNetFltWinSetAdaptState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
3261//#ifndef VBOXNETADP
3262// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
3263//#endif
3264
3265 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
3266
3267 /* 4. mark as connected */
3268 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
3269
3270 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
3271
3272 pAttachInfo->Status = VINF_SUCCESS;
3273 pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
3274
3275 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3276
3277 vboxNetFltRelease(pThis, false);
3278
3279 return;
3280 }
3281 AssertBreakpoint();
3282
3283 if(!pAttachInfo->fRediscovery)
3284 {
3285 vboxNetFltWinMpDereferenceControlDevice();
3286 }
3287 }
3288 AssertBreakpoint();
3289#ifndef VBOXNETADP
3290 vboxNetFltWinPtDoUnbinding(pAdapt, true);
3291#else
3292 vboxNetFltWinMpDoDeinitialization(pAdapt);
3293#endif
3294 }
3295 AssertBreakpoint();
3296 vboxNetFltWinPtFiniPADAPT(pAdapt);
3297 }
3298 AssertBreakpoint();
3299 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3300 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3301#ifndef VBOXNETADP
3302 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3303#endif
3304// /* paranoya */
3305// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3306//#ifndef VBOXNETADP
3307// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3308//#endif
3309 }
3310 AssertBreakpoint();
3311
3312#else /* VBOX_NETFLT_ONDEMAND_BIND */
3313 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3314
3315 Status = vboxNetFltWinPtInitBind(pAdapt);
3316 if (Status != NDIS_STATUS_SUCCESS)
3317 {
3318 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3319 break;
3320 }
3321
3322 Status = vboxNetFltWinGetMacAddress(pAdapt, &pThis->u.s.Mac);
3323 if (Status != NDIS_STATUS_SUCCESS)
3324 {
3325 vboxNetFltWinPtFiniUnbind(pAdapt);
3326 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3327 break;
3328 }
3329#endif /* VBOX_NETFLT_ONDEMAND_BIND */
3330
3331
3332 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3333 pAttachInfo->pCreateContext->Status = Status;
3334 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3335 }
3336 else
3337 {
3338 AssertBreakpoint();
3339 pAttachInfo->Status = rc;
3340 }
3341
3342 vboxNetFltRelease(pThis, false);
3343
3344 return;
3345}
3346
3347/**
3348 * Common code for vboxNetFltOsInitInstance and
3349 * vboxNetFltOsMaybeRediscovered.
3350 *
3351 * @returns IPRT status code.
3352 * @param pThis The instance.
3353 * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
3354 * false if it's vboxNetFltOsInitInstance.
3355 */
3356static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
3357{
3358 ATTACH_INFO Info;
3359 Info.pNetFltIf = pThis;
3360 Info.fRediscovery = fRediscovery;
3361 Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
3362
3363
3364#ifdef VBOX_NETFLT_ONDEMAND_BIND
3365 /* packet queue worker thread gets created on attach interface, need to do it via job at passive level */
3366 vboxNetFltWinJobSynchExecAtPassive((JOB_ROUTINE)vboxNetFltWinAttachToInterfaceWorker, &Info);
3367#else
3368 vboxNetFltWinAttachToInterfaceWorker(&Info);
3369#endif
3370 return Info.Status;
3371}
3372
3373/*
3374 *
3375 * The OS specific interface definition
3376 *
3377 */
3378
3379
3380bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3381{
3382 /* AttachToInterface true if disconnected */
3383 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
3384}
3385
3386int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
3387{
3388 int rc = VINF_SUCCESS;
3389 uint32_t cRefs = 0;
3390 PADAPT pAdapt;
3391#if !defined(VBOXNETADP) && !defined(VBOX_NETFLT_ONDEMAND_BIND)
3392 if(fDst & INTNETTRUNKDIR_WIRE)
3393 {
3394 cRefs++;
3395 }
3396 if(fDst & INTNETTRUNKDIR_HOST)
3397 {
3398 cRefs++;
3399 }
3400#else
3401 if(fDst & INTNETTRUNKDIR_WIRE || fDst & INTNETTRUNKDIR_HOST)
3402 {
3403 cRefs = 1;
3404 }
3405#endif
3406
3407 AssertReturn(cRefs, VINF_SUCCESS);
3408
3409 pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3410
3411 if(!vboxNetFltWinIncReferenceAdapt(pAdapt, cRefs))
3412 {
3413 return VERR_GENERAL_FAILURE;
3414 }
3415#ifndef VBOXNETADP
3416 if ((fDst & INTNETTRUNKDIR_WIRE)
3417# ifdef VBOX_NETFLT_ONDEMAND_BIND
3418 || (fDst & INTNETTRUNKDIR_HOST)
3419# endif
3420 )
3421 {
3422 PNDIS_PACKET pPacket;
3423
3424 pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3425 true /*fToWire*/, true /*fCopyMemory*/);
3426
3427 if (pPacket)
3428 {
3429 NDIS_STATUS fStatus;
3430
3431#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3432 vboxNetFltWinLbPutSendPacket(pAdapt, pPacket, true /* bFromIntNet */);
3433#endif
3434 NdisSend(&fStatus, pAdapt->hBindingHandle, pPacket);
3435 if (fStatus != NDIS_STATUS_PENDING)
3436 {
3437#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3438 /* the status is NOT pending, complete the packet */
3439 bool bTmp = vboxNetFltWinLbRemoveSendPacket(pAdapt, pPacket);
3440 Assert(bTmp);
3441#endif
3442 if(!NT_SUCCESS(fStatus))
3443 {
3444 /* TODO: convert status to VERR_xxx */
3445 rc = VERR_GENERAL_FAILURE;
3446 }
3447
3448 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
3449 }
3450 else
3451 {
3452 /* pending, dereference on packet complete */
3453 cRefs--;
3454 }
3455 }
3456 else
3457 {
3458 Assert(0);
3459 rc = VERR_NO_MEMORY;
3460 }
3461 }
3462#endif
3463#ifndef VBOX_NETFLT_ONDEMAND_BIND
3464#ifndef VBOXNETADP
3465 if (fDst & INTNETTRUNKDIR_HOST)
3466#else
3467 if(cRefs)
3468#endif
3469 {
3470 PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3471 false /*fToWire*/, true /*fCopyMemory*/);
3472 if (pPacket)
3473 {
3474 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pPacket, 1);
3475 cRefs--;
3476#ifdef VBOXNETADP
3477 STATISTIC_INCREASE(pAdapt->cRxSuccess);
3478#endif
3479 }
3480 else
3481 {
3482 Assert(0);
3483#ifdef VBOXNETADP
3484 STATISTIC_INCREASE(pAdapt->cRxError);
3485#endif
3486 rc = VERR_NO_MEMORY;
3487 }
3488 }
3489
3490 Assert(cRefs <= 2);
3491
3492 if(cRefs)
3493 {
3494 vboxNetFltWinDecReferenceAdapt(pAdapt, cRefs);
3495 }
3496#endif
3497
3498 return rc;
3499}
3500
3501bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
3502{
3503#ifndef VBOXNETADP
3504 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3505 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3506 {
3507 bool bPromiscuous;
3508 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3509 return false;
3510
3511 bPromiscuous = (pAdapt->fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
3512 /*vboxNetFltWinIsPromiscuous(pAdapt);*/
3513
3514 vboxNetFltWinDereferenceAdapt(pAdapt);
3515 return bPromiscuous;
3516 }
3517 return false;
3518#else
3519 return true;
3520#endif
3521}
3522
3523void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
3524{
3525 *pMac = pThis->u.s.Mac;
3526}
3527
3528bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
3529{
3530 /* ASSUMES that the MAC address never changes. */
3531 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
3532 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
3533 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
3534}
3535
3536void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3537{
3538#ifndef VBOXNETADP
3539 NDIS_STATUS Status;
3540#endif
3541 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3542
3543 /* we first wait for all pending ops to complete
3544 * this might include all packets queued for processing */
3545 for(;;)
3546 {
3547 if(fActive)
3548 {
3549 if(!pThis->u.s.cModePassThruRefs)
3550 {
3551 break;
3552 }
3553 }
3554 else
3555 {
3556 if(!pThis->u.s.cModeNetFltRefs)
3557 {
3558 break;
3559 }
3560 }
3561 vboxNetFltWinSleep(2);
3562 }
3563
3564 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3565 return;
3566#ifndef VBOXNETADP
3567
3568 /* the packets put to ReceiveQueue Array are currently not holding the references,
3569 * simply need to flush them */
3570 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false /*fReturn*/);
3571
3572 if(fActive)
3573 {
3574#ifdef DEBUG_misha
3575 NDIS_PHYSICAL_MEDIUM PhMedium;
3576 bool bPromiscSupported;
3577
3578 Status = vboxNetFltWinQueryPhysicalMedium(pAdapt, &PhMedium);
3579 if(Status != NDIS_STATUS_SUCCESS)
3580 {
3581
3582 DBGPRINT(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3583 Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
3584 if(Status != NDIS_STATUS_NOT_SUPPORTED)
3585 {
3586 LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3587 }
3588 PhMedium = NdisPhysicalMediumUnspecified;
3589 }
3590 else
3591 {
3592 DBGPRINT(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
3593 }
3594
3595 bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
3596 || PhMedium == NdisPhysicalMediumWirelessLan
3597 || PhMedium == NdisPhysicalMediumNative802_11
3598 || PhMedium == NdisPhysicalMediumBluetooth
3599 /*|| PhMedium == NdisPhysicalMediumWiMax */
3600 ));
3601
3602 Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
3603#endif
3604 }
3605
3606 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3607 {
3608 Status = vboxNetFltWinSetPromiscuous(pAdapt, fActive);
3609 if(Status != NDIS_STATUS_SUCCESS)
3610 {
3611 DBGPRINT(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3612 Assert(0);
3613 LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3614 }
3615 }
3616#else
3617# ifdef VBOXNETADP_REPORT_DISCONNECTED
3618 if(fActive)
3619 {
3620 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3621 NDIS_STATUS_MEDIA_CONNECT,
3622 (PVOID)NULL,
3623 0);
3624 }
3625 else
3626 {
3627 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3628 NDIS_STATUS_MEDIA_DISCONNECT,
3629 (PVOID)NULL,
3630 0);
3631 }
3632#else
3633 if(fActive)
3634 {
3635 /* indicate status change to make the ip settings be re-picked for dhcp */
3636 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3637 NDIS_STATUS_MEDIA_DISCONNECT,
3638 (PVOID)NULL,
3639 0);
3640
3641 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3642 NDIS_STATUS_MEDIA_CONNECT,
3643 (PVOID)NULL,
3644 0);
3645 }
3646# endif
3647#endif
3648 vboxNetFltWinDereferenceAdapt(pAdapt);
3649
3650 return;
3651}
3652
3653int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3654{
3655 NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
3656 return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3657}
3658
3659static void vboxNetFltWinConnectItWorker(PWORKER_INFO pInfo)
3660{
3661 NDIS_STATUS Status;
3662 PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
3663 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
3664
3665 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3666
3667 /* this is not a rediscovery, initialize Mac cache */
3668 if(vboxNetFltWinReferenceAdapt(pAdapt))
3669 {
3670#ifndef VBOXNETADP
3671 Status = vboxNetFltWinGetMacAddress(pAdapt, &pInstance->u.s.Mac);
3672 if (Status == NDIS_STATUS_SUCCESS)
3673#endif
3674 {
3675 Status = vboxNetFltWinQuInitPacketQueue(pInstance);
3676 if(Status == NDIS_STATUS_SUCCESS)
3677 {
3678 pInfo->Status = VINF_SUCCESS;
3679 }
3680 else
3681 {
3682 pInfo->Status = VERR_GENERAL_FAILURE;
3683 }
3684 }
3685#ifndef VBOXNETADP
3686 else
3687 {
3688 pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
3689 }
3690#endif
3691
3692 vboxNetFltWinDereferenceAdapt(pAdapt);
3693 }
3694 else
3695 {
3696 pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
3697 }
3698}
3699
3700static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
3701{
3702 WORKER_INFO Info;
3703 Info.pNetFltIf = pThis;
3704
3705 vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
3706
3707 return Info.Status;
3708}
3709
3710int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3711{
3712 return vboxNetFltWinConnectIt(pThis);
3713}
3714
3715void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3716{
3717 vboxNetFltWinDeleteInstance(pThis);
3718}
3719
3720int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3721{
3722 int rc = RTSemMutexCreate(&pThis->u.s.hAdaptMutex);
3723 if (RT_SUCCESS(rc))
3724 {
3725 rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
3726 if (RT_SUCCESS(rc))
3727 {
3728 return rc;
3729 }
3730 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3731 }
3732 return rc;
3733}
3734
3735int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3736{
3737 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3738 pThis->u.s.cModeNetFltRefs = 0;
3739 pThis->u.s.cModePassThruRefs = 0;
3740 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3741 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3742#ifndef VBOXNETADP
3743 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3744#endif
3745 return VINF_SUCCESS;
3746}
3747
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