VirtualBox

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

Last change on this file since 34487 was 34102, checked in by vboxsync, 14 years ago

NetFlt/win: rx path fixs

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette