VirtualBox

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

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

netadp/win: fix r61826 regression caused by parameter switch

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 108.3 KB
Line 
1/* $Id: VBoxNetFlt-win.c 30007 2010-06-03 11:13:10Z 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 thred
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 successfuly 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 transfered 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 creaed 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 lenght 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
2304 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2305# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2306 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2307# endif
2308#endif
2309
2310#ifndef VBOX_NETFLT_ONDEMAND_BIND
2311 /* moved to vboxNetFltWinDetachFromInterfaceWorker */
2312#else
2313# ifndef VBOXNETFLT_NO_PACKET_QUEUE
2314 vboxNetFltWinQuFiniPacketQueue(pAdapt);
2315# endif
2316#endif
2317
2318 vboxNetFltWinFiniBuffers(pAdapt);
2319
2320 /*
2321 * Free the memory here, if was not released earlier(by calling the HaltHandler)
2322 */
2323 vboxNetFltWinPtFreeAllPacketPools (pAdapt);
2324#ifndef VBOXNETADP
2325 rc = RTSemFastMutexDestroy(pAdapt->hSynchRequestMutex); AssertRC(rc);
2326#endif
2327
2328 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2329}
2330
2331DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
2332#ifndef VBOXNETADP
2333DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName)
2334#else
2335DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt)
2336#endif
2337{
2338 NDIS_STATUS Status;
2339#ifndef VBOXNETADP
2340 int rc;
2341#endif
2342 BOOLEAN bCallFiniOnFail = FALSE;
2343
2344 LogFlow(("==> vboxNetFltWinPtInitPADAPT : pAdapt %p\n", pAdapt));
2345
2346 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2347
2348 do
2349 {
2350 NdisZeroMemory(pAdapt, sizeof(ADAPT));
2351#ifndef VBOXNETADP
2352 NdisInitializeEvent(&pAdapt->hEvent);
2353
2354 KeInitializeEvent(&pAdapt->hSynchCompletionEvent, SynchronizationEvent, FALSE);
2355
2356 /*
2357 * Allocate a packet pool for sends. We need this to pass sends down.
2358 * We cannot use the same packet descriptor that came down to our send
2359 * handler (see also NDIS 5.1 packet stacking).
2360 */
2361 NdisAllocatePacketPoolEx(&Status,
2362 &pAdapt->hSendPacketPoolHandle,
2363 MIN_PACKET_POOL_SIZE,
2364 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2365 sizeof(SEND_RSVD));
2366
2367 if (Status != NDIS_STATUS_SUCCESS)
2368 {
2369 pAdapt->hSendPacketPoolHandle = NULL;
2370 break;
2371 }
2372#else
2373#endif
2374
2375 Status = vboxNetFltWinInitBuffers(pAdapt);
2376 if (Status != NDIS_STATUS_SUCCESS)
2377 {
2378 break;
2379 }
2380
2381 bCallFiniOnFail = TRUE;
2382#ifndef VBOXNETADP
2383 rc = RTSemFastMutexCreate(&pAdapt->hSynchRequestMutex);
2384 if(RT_FAILURE(rc))
2385 {
2386 Status = NDIS_STATUS_FAILURE;
2387 break;
2388 }
2389#endif
2390
2391#ifndef VBOX_NETFLT_ONDEMAND_BIND
2392# ifndef VBOXNETADP
2393 Status = vboxNetFltWinMemAlloc((PVOID*)&pAdapt->DeviceName.Buffer, pOurDeviceName->Length);
2394 if(Status != NDIS_STATUS_SUCCESS)
2395 {
2396 AssertFailed();
2397 pAdapt->DeviceName.Buffer = NULL;
2398 break;
2399 }
2400 pAdapt->DeviceName.MaximumLength = pOurDeviceName->Length;
2401 pAdapt->DeviceName.Length = 0;
2402 Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
2403 if(Status != NDIS_STATUS_SUCCESS)
2404 {
2405 AssertFailed();
2406 break;
2407 }
2408# endif
2409
2410 /*
2411 * Allocate a packet pool for receives. We need this to indicate receives.
2412 * Same consideration as sends (see also NDIS 5.1 packet stacking).
2413 */
2414 NdisAllocatePacketPoolEx(&Status,
2415 &pAdapt->hRecvPacketPoolHandle,
2416 MIN_PACKET_POOL_SIZE,
2417 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2418 PROTOCOL_RESERVED_SIZE_IN_PACKET);
2419
2420 if (Status != NDIS_STATUS_SUCCESS)
2421 {
2422 pAdapt->hRecvPacketPoolHandle = NULL;
2423 break;
2424 }
2425#ifndef VBOXNETADP
2426 NdisInitializeEvent(&pAdapt->MiniportInitEvent);
2427#endif
2428#endif
2429#ifndef VBOXNETADP
2430 pAdapt->PTState.PowerState = NdisDeviceStateD3;
2431 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
2432
2433 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2434
2435# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2436 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2437# endif
2438#endif
2439 /* TODO: do we need it here ?? */
2440 pAdapt->MPState.PowerState = NdisDeviceStateD3;
2441 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
2442
2443#ifdef VBOX_NETFLT_ONDEMAND_BIND
2444 {
2445 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2446 rc = vboxNetFltWinConnectIt(pNetFlt);
2447 if(RT_FAILURE(rc))
2448 {
2449 AssertFailed();
2450 Status = NDIS_STATUS_FAILURE;
2451 break;
2452 }
2453 }
2454#endif
2455
2456 /* moved to vboxNetFltOsInitInstance */
2457 } while(0);
2458
2459 if (Status != NDIS_STATUS_SUCCESS)
2460 {
2461 if(bCallFiniOnFail)
2462 {
2463 vboxNetFltWinPtFiniPADAPT(pAdapt);
2464 }
2465 }
2466
2467 LogFlow(("<== vboxNetFltWinPtInitPADAPT : pAdapt %p, Status %x\n", pAdapt, Status));
2468
2469 return Status;
2470}
2471
2472/**
2473 * match packets
2474 */
2475#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
2476#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
2477#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
2478#define LAST_LIST_ENTRY PREV_LIST_ENTRY
2479
2480#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
2481
2482#ifndef VBOXNETADP
2483
2484#ifdef DEBUG_misha
2485
2486RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2487RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
2488
2489DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
2490{
2491 UINT cBufCount1;
2492 PNDIS_BUFFER pBuffer1;
2493 UINT uTotalPacketLength1;
2494 RTNETETHERHDR* pEth;
2495 UINT cbLength1 = 0;
2496 UINT i = 0;
2497
2498 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2499
2500 Assert(pBuffer1);
2501 Assert(uTotalPacketLength1 >= ETH_HEADER_SIZE);
2502 if(uTotalPacketLength1 < ETH_HEADER_SIZE)
2503 return NULL;
2504
2505 NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
2506 Assert(cbLength1 >= ETH_HEADER_SIZE);
2507 if(cbLength1 < ETH_HEADER_SIZE)
2508 return NULL;
2509
2510 return pEth;
2511}
2512
2513DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
2514{
2515 Assert(pSG->cSegsUsed);
2516 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2517 Assert(pSG->aSegs[0].cb >= ETH_HEADER_SIZE);
2518
2519 if(!pSG->cSegsUsed)
2520 return NULL;
2521
2522 if(pSG->aSegs[0].cb < ETH_HEADER_SIZE)
2523 return NULL;
2524
2525 return (PRTNETETHERHDR)pSG->aSegs[0].pv;
2526}
2527
2528DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
2529{
2530 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
2531 Assert(pHdr);
2532
2533 if(!pHdr)
2534 return false;
2535
2536 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2537 return false;
2538
2539 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2540 return false;
2541
2542 return true;
2543}
2544
2545DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
2546{
2547 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
2548 Assert(pHdr);
2549
2550 if(!pHdr)
2551 return false;
2552
2553 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2554 return false;
2555
2556 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2557 return false;
2558
2559 return true;
2560}
2561#endif
2562
2563# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
2564/*
2565 * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
2566 * if cbMatch < 0 matches complete packets.
2567 */
2568DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
2569{
2570 UINT cBufCount1;
2571 PNDIS_BUFFER pBuffer1;
2572 UINT uTotalPacketLength1;
2573 uint8_t* pMemBuf1;
2574 UINT cbLength1 = 0;
2575
2576 UINT cBufCount2;
2577 PNDIS_BUFFER pBuffer2;
2578 UINT uTotalPacketLength2;
2579 uint8_t* pMemBuf2;
2580 UINT cbLength2 = 0;
2581 bool bMatch = true;
2582
2583#ifdef DEBUG_NETFLT_PACKETS
2584 bool bCompleteMatch = false;
2585#endif
2586
2587 NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2588 NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
2589
2590 Assert(pBuffer1);
2591 Assert(pBuffer2);
2592
2593 if(uTotalPacketLength1 != uTotalPacketLength2)
2594 {
2595 bMatch = false;
2596 }
2597 else
2598 {
2599 UINT ucbLength2Match = 0;
2600 UINT ucbMatch;
2601 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2602 {
2603 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2604 ucbMatch = uTotalPacketLength1;
2605#ifdef DEBUG_NETFLT_PACKETS
2606 bCompleteMatch = true;
2607#endif
2608 }
2609 else
2610 {
2611 ucbMatch = (UINT)cbMatch;
2612 }
2613
2614 for(;;)
2615 {
2616 if(!cbLength1)
2617 {
2618 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2619 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2620 }
2621 else
2622 {
2623 Assert(pMemBuf1);
2624 Assert(ucbLength2Match);
2625 pMemBuf1 += ucbLength2Match;
2626 }
2627
2628 if(!cbLength2)
2629 {
2630 NdisQueryBufferSafe(pBuffer2, &pMemBuf2, &cbLength2, NormalPagePriority);
2631 NdisGetNextBuffer(pBuffer2, &pBuffer2);
2632 }
2633 else
2634 {
2635 Assert(pMemBuf2);
2636 Assert(ucbLength2Match);
2637 pMemBuf2 += ucbLength2Match;
2638 }
2639
2640 ucbLength2Match = MIN(ucbMatch, cbLength1);
2641 ucbLength2Match = MIN(ucbLength2Match, cbLength2);
2642
2643 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2644 {
2645 bMatch = false;
2646 break;
2647 }
2648
2649 ucbMatch -= ucbLength2Match;
2650 if(!ucbMatch)
2651 break;
2652
2653 cbLength1 -= ucbLength2Match;
2654 cbLength2 -= ucbLength2Match;
2655 }
2656 }
2657
2658#ifdef DEBUG_NETFLT_PACKETS
2659 if(bMatch && !bCompleteMatch)
2660 {
2661 /* check that the packets fully match */
2662 DBG_CHECK_PACKETS(pPacket1, pPacket2);
2663 }
2664#endif
2665
2666 return bMatch;
2667}
2668
2669/*
2670 * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
2671 * if cbMatch < 0 matches complete packets.
2672 */
2673DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
2674{
2675 UINT cBufCount1;
2676 PNDIS_BUFFER pBuffer1;
2677 UINT uTotalPacketLength1;
2678 uint8_t* pMemBuf1;
2679 UINT cbLength1 = 0;
2680 UINT uTotalPacketLength2 = pSG->cbTotal;
2681 uint8_t* pMemBuf2;
2682 UINT cbLength2 = 0;
2683 bool bMatch = true;
2684 bool bCompleteMatch = false;
2685 UINT i = 0;
2686
2687 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2688
2689 Assert(pBuffer1);
2690 Assert(pSG->cSegsUsed);
2691 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2692
2693 if(uTotalPacketLength1 != uTotalPacketLength2)
2694 {
2695 AssertFailed();
2696 bMatch = false;
2697 }
2698 else
2699 {
2700 UINT ucbLength2Match = 0;
2701 UINT ucbMatch;
2702
2703 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2704 {
2705 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2706 ucbMatch = uTotalPacketLength1;
2707 bCompleteMatch = true;
2708 }
2709 else
2710 {
2711 ucbMatch = (UINT)cbMatch;
2712 }
2713
2714 for(;;)
2715 {
2716 if(!cbLength1)
2717 {
2718 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2719 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2720 }
2721 else
2722 {
2723 Assert(pMemBuf1);
2724 Assert(ucbLength2Match);
2725 pMemBuf1 += ucbLength2Match;
2726 }
2727
2728 if(!cbLength2)
2729 {
2730 Assert(i < pSG->cSegsUsed);
2731 pMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
2732 cbLength2 = pSG->aSegs[i].cb;
2733 i++;
2734 }
2735 else
2736 {
2737 Assert(pMemBuf2);
2738 Assert(ucbLength2Match);
2739 pMemBuf2 += ucbLength2Match;
2740 }
2741
2742 ucbLength2Match = MIN(ucbMatch, cbLength1);
2743 ucbLength2Match = MIN(ucbLength2Match, cbLength2);
2744
2745 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2746 {
2747 bMatch = false;
2748 AssertFailed();
2749 break;
2750 }
2751
2752 ucbMatch -= ucbLength2Match;
2753 if(!ucbMatch)
2754 break;
2755
2756 cbLength1 -= ucbLength2Match;
2757 cbLength2 -= ucbLength2Match;
2758 }
2759 }
2760
2761 if(bMatch && !bCompleteMatch)
2762 {
2763 /* check that the packets fully match */
2764 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
2765 }
2766 return bMatch;
2767}
2768
2769# if 0
2770/*
2771 * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
2772 * if cbMatch < 0 matches complete packets.
2773 */
2774static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
2775{
2776 UINT uTotalPacketLength1 = pSG1->cbTotal;
2777 PVOID pMemBuf1;
2778 UINT cbLength1 = 0;
2779 UINT i1 = 0;
2780 UINT uTotalPacketLength2 = pSG2->cbTotal;
2781 PVOID pMemBuf2;
2782 UINT cbLength2 = 0;
2783
2784 bool bMatch = true;
2785 bool bCompleteMatch = false;
2786 UINT i2 = 0;
2787
2788 Assert(pSG1->cSegsUsed);
2789 Assert(pSG2->cSegsUsed);
2790 Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
2791 Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
2792
2793 if(uTotalPacketLength1 != uTotalPacketLength2)
2794 {
2795 AssertFailed();
2796 bMatch = false;
2797 }
2798 else
2799 {
2800 UINT ucbMatch;
2801 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2802 {
2803 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2804 ucbMatch = uTotalPacketLength1;
2805 bCompleteMatch = true;
2806 }
2807 else
2808 {
2809 ucbMatch = (UINT)cbMatch;
2810 }
2811
2812 do
2813 {
2814 UINT ucbLength2Match;
2815 if(!cbLength1)
2816 {
2817 Assert(i1 < pSG1->cSegsUsed);
2818 pMemBuf1 = pSG1->aSegs[i1].pv;
2819 cbLength1 = pSG1->aSegs[i1].cb;
2820 i1++;
2821 }
2822
2823 if(!cbLength2)
2824 {
2825 Assert(i2 < pSG2->cSegsUsed);
2826 pMemBuf2 = pSG2->aSegs[i2].pv;
2827 cbLength2 = pSG2->aSegs[i2].cb;
2828 i2++;
2829 }
2830
2831 ucbLength2Match = MIN(ucbMatch, cbLength1);
2832 ucbLength2Match = MIN(ucbLength2Match, cbLength2);
2833
2834 if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
2835 {
2836 bMatch = false;
2837 AssertFailed();
2838 break;
2839 }
2840 ucbMatch -= ucbLength2Match;
2841 cbLength1 -= ucbLength2Match;
2842 cbLength2 -= ucbLength2Match;
2843 } while (ucbMatch);
2844 }
2845
2846 if(bMatch && !bCompleteMatch)
2847 {
2848 /* check that the packets fully match */
2849 DBG_CHECK_SGS(pSG1, pSG2);
2850 }
2851 return bMatch;
2852}
2853# endif
2854# endif
2855#endif
2856
2857static void vboxNetFltWinFiniNetFltBase()
2858{
2859 do
2860 {
2861 vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
2862
2863 /*
2864 * Undo the work done during start (in reverse order).
2865 */
2866 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2867
2868 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
2869 RTLogDestroy(RTLogSetDefaultInstance(NULL));
2870
2871 RTR0Term();
2872 } while (0);
2873}
2874
2875static int vboxNetFltWinTryFiniIdc()
2876{
2877 int rc;
2878
2879 vboxNetFltWinStopInitIdcProbing();
2880
2881 if(g_bIdcInitialized)
2882 {
2883 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2884 if(RT_SUCCESS(rc))
2885 {
2886 g_bIdcInitialized = false;
2887 }
2888 }
2889 else
2890 {
2891 rc = VINF_SUCCESS;
2892 }
2893 return rc;
2894
2895}
2896
2897static int vboxNetFltWinFiniNetFlt()
2898{
2899 int rc = vboxNetFltWinTryFiniIdc();
2900 if(RT_SUCCESS(rc))
2901 {
2902 vboxNetFltWinFiniNetFltBase();
2903 }
2904 return rc;
2905}
2906
2907/**
2908 * base netflt initialization
2909 */
2910static int vboxNetFltWinInitNetFltBase()
2911{
2912 int rc;
2913
2914 do
2915 {
2916 Assert(!g_bIdcInitialized);
2917
2918 rc = RTR0Init(0);
2919 if (!RT_SUCCESS(rc))
2920 {
2921 break;
2922 }
2923
2924 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2925 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
2926 if (!RT_SUCCESS(rc))
2927 {
2928 RTR0Term();
2929 break;
2930 }
2931 }while(0);
2932
2933 return rc;
2934}
2935
2936/**
2937 * initialize IDC
2938 */
2939static int vboxNetFltWinInitIdc()
2940{
2941 int rc;
2942
2943 do
2944 {
2945 if(g_bIdcInitialized)
2946 {
2947#ifdef VBOX_NETFLT_ONDEMAND_BIND
2948 AssertFailed();
2949#endif
2950 rc = VINF_ALREADY_INITIALIZED;
2951 break;
2952 }
2953
2954 /*
2955 * connect to the support driver.
2956 *
2957 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
2958 * for establishing the connect to the support driver.
2959 */
2960 rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
2961 if (!RT_SUCCESS(rc))
2962 {
2963 break;
2964 }
2965
2966 g_bIdcInitialized = true;
2967 } while (0);
2968
2969 return rc;
2970}
2971
2972static void vboxNetFltWinInitIdcProbingWorker(PINIT_IDC_INFO pInitIdcInfo)
2973{
2974 int rc = vboxNetFltWinInitIdc();
2975 if(RT_FAILURE(rc))
2976 {
2977 bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2978 if(!bInterupted)
2979 {
2980 RTThreadSleep(1000); /* 1 s */
2981 bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2982 if(!bInterupted)
2983 {
2984 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &pInitIdcInfo->Job, false);
2985 return;
2986 }
2987 }
2988
2989 /* it's interupted */
2990 rc = VERR_INTERRUPTED;
2991 }
2992
2993 ASMAtomicUoWriteU32(&pInitIdcInfo->rc, rc);
2994 KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
2995}
2996
2997static int vboxNetFltWinStopInitIdcProbing()
2998{
2999 if(!g_InitIdcInfo.bInitialized)
3000 return VERR_INVALID_STATE;
3001
3002 ASMAtomicUoWriteBool(&g_InitIdcInfo.bStop, true);
3003 KeWaitForSingleObject(&g_InitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
3004
3005 return g_InitIdcInfo.rc;
3006}
3007
3008static int vboxNetFltWinStartInitIdcProbing()
3009{
3010 Assert(!g_bIdcInitialized);
3011 KeInitializeEvent(&g_InitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
3012 g_InitIdcInfo.bStop = false;
3013 g_InitIdcInfo.bInitialized = true;
3014 vboxNetFltWinJobInit(&g_InitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_InitIdcInfo, false);
3015 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &g_InitIdcInfo.Job, false);
3016 return VINF_SUCCESS;
3017}
3018
3019static int vboxNetFltWinInitNetFlt()
3020{
3021 int rc;
3022
3023 do
3024 {
3025 rc = vboxNetFltWinInitNetFltBase();
3026 if(RT_FAILURE(rc))
3027 {
3028 AssertFailed();
3029 break;
3030 }
3031
3032 /*
3033 * connect to the support driver.
3034 *
3035 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
3036 * for establishing the connect to the support driver.
3037 */
3038 rc = vboxNetFltWinInitIdc();
3039 if (RT_FAILURE(rc))
3040 {
3041 AssertFailed();
3042 vboxNetFltWinFiniNetFltBase();
3043 break;
3044 }
3045 } while (0);
3046
3047 return rc;
3048}
3049
3050/* detach*/
3051static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
3052{
3053 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3054 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3055 NDIS_STATUS Status;
3056 LogFlow(("vboxNetFltWinDeleteInstance: pThis=%p \n", pThis));
3057
3058 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3059 Assert(pAdapt);
3060 Assert(pThis);
3061 Assert(pThis->fDisconnectedFromHost);
3062 Assert(!pThis->fRediscoveryPending);
3063 Assert(pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
3064#ifndef VBOXNETADP
3065 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
3066 Assert(!pAdapt->hBindingHandle);
3067#endif
3068 Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Deinitialized);
3069#ifndef VBOXNETFLT_NO_PACKET_QUEUE
3070 Assert(!pThis->u.s.PacketQueueWorker.pSG);
3071#endif
3072// Assert(!pAdapt->hMiniportHandle);
3073
3074#ifndef VBOX_NETFLT_ONDEMAND_BIND
3075 Status = vboxNetFltWinMpDereferenceControlDevice();
3076 Assert(Status == NDIS_STATUS_SUCCESS);
3077#else
3078 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3079 if(Status != NDIS_STATUS_SUCCESS)
3080 {
3081 AssertFailed();
3082 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3083 }
3084#endif
3085
3086 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3087
3088 return VINF_SUCCESS;
3089}
3090
3091static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
3092{
3093#ifndef VBOXNETFLT_NO_PACKET_QUEUE
3094 vboxNetFltWinQuFiniPacketQueue(pInstance);
3095#endif
3096 return NDIS_STATUS_SUCCESS;
3097}
3098
3099/* detach*/
3100DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PADAPT pAdapt, bool bOnUnbind)
3101{
3102 PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
3103 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3104 NDIS_STATUS Status;
3105 int rc;
3106 LogFlow(("vboxNetFltWinDetachFromInterface: pThis=%p\n", pThis));
3107
3108 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3109 Assert(pAdapt);
3110 Assert(pThis);
3111/* Assert(!pThis->fActive); */
3112
3113 /* paranoya to ensyre the instance is not removed while we're waiting on the mutex
3114 * in case ndis does something unpredictable, e.g. calls our miniport halt independently
3115 * from protocol unbind and concurrently with it*/
3116 vboxNetFltRetain(pThis, false);
3117
3118 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3119 if(RT_SUCCESS(rc))
3120 {
3121#ifndef VBOX_NETFLT_ONDEMAND_BIND
3122 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected);
3123 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3124#ifndef VBOXNETADP
3125 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3126#endif
3127// if(
3128//#ifdef VBOXNETADP
3129// vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3130//#else
3131// vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized
3132//// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3133//#endif
3134// )
3135 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected)
3136 {
3137 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnecting);
3138#ifndef VBOXNETADP
3139 Status = vboxNetFltWinPtDoUnbinding(pAdapt, bOnUnbind);
3140#else
3141 Status = vboxNetFltWinMpDoDeinitialization(pAdapt);
3142#endif
3143 Assert(Status == NDIS_STATUS_SUCCESS);
3144
3145 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3146 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3147#ifndef VBOXNETADP
3148 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3149#endif
3150// /* paranoya */
3151// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3152//#ifndef VBOXNETADP
3153// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3154//#endif
3155
3156 vboxNetFltWinPtFiniPADAPT(pAdapt);
3157
3158 /* we're unbinding, make an unbind-related release */
3159 vboxNetFltRelease(pThis, false);
3160#else
3161 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3162 if(Status != NDIS_STATUS_SUCCESS)
3163 {
3164 AssertFailed();
3165 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3166 }
3167#endif
3168 }
3169 else
3170 {
3171 AssertBreakpoint();
3172#ifndef VBOXNETADP
3173 pAdapt->Status = NDIS_STATUS_FAILURE;
3174#endif
3175 if(!bOnUnbind)
3176 {
3177 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3178 }
3179 Status = NDIS_STATUS_FAILURE;
3180 }
3181 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3182 }
3183 else
3184 {
3185 AssertBreakpoint();
3186 Status = NDIS_STATUS_FAILURE;
3187 }
3188
3189 /* release for the retain we made before waining on the mutex */
3190 vboxNetFltRelease(pThis, false);
3191
3192 return Status;
3193}
3194
3195
3196/**
3197 * Checks if the host (not us) has put the adapter in promiscuous mode.
3198 *
3199 * @returns true if promiscuous, false if not.
3200 * @param pThis The instance.
3201 */
3202static bool vboxNetFltWinIsPromiscuous2(PVBOXNETFLTINS pThis)
3203{
3204#ifndef VBOXNETADP
3205 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3206 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3207 {
3208 bool bPromiscuous;
3209 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3210 return false;
3211
3212 bPromiscuous = (pAdapt->fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
3213 /*vboxNetFltWinIsPromiscuous(pAdapt);*/
3214
3215 vboxNetFltWinDereferenceAdapt(pAdapt);
3216 return bPromiscuous;
3217 }
3218 return false;
3219#else
3220 return true;
3221#endif
3222}
3223
3224
3225/**
3226 * Report the MAC address, promiscuous mode setting, GSO capabilities and
3227 * no-preempt destinations to the internal network.
3228 *
3229 * Does nothing if we're not currently connected to an internal network.
3230 *
3231 * @param pThis The instance data.
3232 */
3233static void vboxNetFltWinReportStuff(PVBOXNETFLTINS pThis)
3234{
3235 /** @todo Keep these up to date, esp. the promiscuous mode bit. */
3236 if ( pThis->pSwitchPort
3237 && vboxNetFltTryRetainBusyNotDisconnected(pThis))
3238 {
3239 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
3240 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
3241 vboxNetFltWinIsPromiscuous2(pThis));
3242 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
3243 INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
3244 /** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */
3245 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
3246 vboxNetFltRelease(pThis, true /*fBusy*/);
3247 }
3248}
3249
3250/**
3251 * Worker for vboxNetFltWinAttachToInterface.
3252 *
3253 * @param pAttachInfo Structure for communicating with
3254 * vboxNetFltWinAttachToInterface.
3255 */
3256static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
3257{
3258 PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
3259 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3260 int rc;
3261 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3262
3263 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3264
3265 /* to ensure we're not removed while we're here */
3266 vboxNetFltRetain(pThis, false);
3267
3268 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3269 if(RT_SUCCESS(rc))
3270 {
3271 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3272 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected);
3273 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3274#ifndef VBOXNETADP
3275 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3276#endif
3277// if(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3278//#ifndef VBOXNETADP
3279// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3280//#endif
3281// )
3282 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected)
3283 {
3284
3285#ifndef VBOX_NETFLT_ONDEMAND_BIND
3286 if(pAttachInfo->fRediscovery)
3287 {
3288 /* rediscovery means adaptor bind is performed while intnet is already using it
3289 * i.e. adaptor was unbound while being used by intnet and now being bound back again */
3290 Assert(((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState)) == kVBoxNetFltInsState_Connected);
3291 }
3292#ifndef VBOXNETADP
3293 Status = vboxNetFltWinPtInitPADAPT(pAdapt, pAttachInfo->pCreateContext->pOurName);
3294#else
3295 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
3296#endif
3297 if(Status == NDIS_STATUS_SUCCESS)
3298 {
3299 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connecting);
3300
3301#ifndef VBOXNETADP
3302 Status = vboxNetFltWinPtDoBinding(pAdapt, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
3303#else
3304 Status = vboxNetFltWinMpDoInitialization(pAdapt, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
3305#endif
3306 if (Status == NDIS_STATUS_SUCCESS)
3307 {
3308 if(pAttachInfo->fRediscovery || (Status = vboxNetFltWinMpReferenceControlDevice()) == NDIS_STATUS_SUCCESS)
3309 {
3310#ifndef VBOXNETADP
3311 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
3312#endif
3313 {
3314 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connected);
3315// Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3316#ifndef VBOXNETADP
3317 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3318#endif
3319// /* paranoya */
3320//// vboxNetFltWinSetAdaptState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
3321//#ifndef VBOXNETADP
3322// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
3323//#endif
3324
3325
3326 /* 4. mark as connected */
3327 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
3328 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
3329 RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
3330
3331 pAttachInfo->Status = VINF_SUCCESS;
3332 pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
3333
3334 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3335
3336 vboxNetFltRelease(pThis, false);
3337
3338 /* 5. Report MAC address, promiscuousness and GSO capabilities. */
3339 vboxNetFltWinReportStuff(pThis);
3340
3341 return;
3342 }
3343 AssertBreakpoint();
3344
3345 if(!pAttachInfo->fRediscovery)
3346 {
3347 vboxNetFltWinMpDereferenceControlDevice();
3348 }
3349 }
3350 AssertBreakpoint();
3351#ifndef VBOXNETADP
3352 vboxNetFltWinPtDoUnbinding(pAdapt, true);
3353#else
3354 vboxNetFltWinMpDoDeinitialization(pAdapt);
3355#endif
3356 }
3357 AssertBreakpoint();
3358 vboxNetFltWinPtFiniPADAPT(pAdapt);
3359 }
3360 AssertBreakpoint();
3361 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3362 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3363#ifndef VBOXNETADP
3364 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3365#endif
3366// /* paranoya */
3367// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3368//#ifndef VBOXNETADP
3369// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3370//#endif
3371 }
3372 AssertBreakpoint();
3373
3374#else /* VBOX_NETFLT_ONDEMAND_BIND */
3375 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3376
3377 Status = vboxNetFltWinPtInitBind(pAdapt);
3378 if (Status != NDIS_STATUS_SUCCESS)
3379 {
3380 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3381 break;
3382 }
3383
3384 Status = vboxNetFltWinGetMacAddress(pAdapt, &pThis->u.s.MacAddr);
3385 if (Status != NDIS_STATUS_SUCCESS)
3386 {
3387 vboxNetFltWinPtFiniUnbind(pAdapt);
3388 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3389 break;
3390 }
3391#endif /* VBOX_NETFLT_ONDEMAND_BIND */
3392
3393
3394 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3395 pAttachInfo->pCreateContext->Status = Status;
3396 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3397 }
3398 else
3399 {
3400 AssertBreakpoint();
3401 pAttachInfo->Status = rc;
3402 }
3403
3404 vboxNetFltRelease(pThis, false);
3405
3406 return;
3407}
3408
3409/**
3410 * Common code for vboxNetFltOsInitInstance and
3411 * vboxNetFltOsMaybeRediscovered.
3412 *
3413 * @returns IPRT status code.
3414 * @param pThis The instance.
3415 * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
3416 * false if it's vboxNetFltOsInitInstance.
3417 */
3418static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
3419{
3420 ATTACH_INFO Info;
3421 Info.pNetFltIf = pThis;
3422 Info.fRediscovery = fRediscovery;
3423 Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
3424
3425
3426#ifdef VBOX_NETFLT_ONDEMAND_BIND
3427 /* packet queue worker thread gets created on attach interface, need to do it via job at passive level */
3428 vboxNetFltWinJobSynchExecAtPassive((JOB_ROUTINE)vboxNetFltWinAttachToInterfaceWorker, &Info);
3429#else
3430 vboxNetFltWinAttachToInterfaceWorker(&Info);
3431#endif
3432 return Info.Status;
3433}
3434
3435/*
3436 *
3437 * The OS specific interface definition
3438 *
3439 */
3440
3441
3442bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3443{
3444 /* AttachToInterface true if disconnected */
3445 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
3446}
3447
3448int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
3449{
3450 int rc = VINF_SUCCESS;
3451 uint32_t cRefs = 0;
3452 PADAPT pAdapt;
3453#if !defined(VBOXNETADP) && !defined(VBOX_NETFLT_ONDEMAND_BIND)
3454 if(fDst & INTNETTRUNKDIR_WIRE)
3455 {
3456 cRefs++;
3457 }
3458 if(fDst & INTNETTRUNKDIR_HOST)
3459 {
3460 cRefs++;
3461 }
3462#else
3463 if(fDst & INTNETTRUNKDIR_WIRE || fDst & INTNETTRUNKDIR_HOST)
3464 {
3465 cRefs = 1;
3466 }
3467#endif
3468
3469 AssertReturn(cRefs, VINF_SUCCESS);
3470
3471 pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3472
3473 if(!vboxNetFltWinIncReferenceAdapt(pAdapt, cRefs))
3474 {
3475 return VERR_GENERAL_FAILURE;
3476 }
3477#ifndef VBOXNETADP
3478 if ((fDst & INTNETTRUNKDIR_WIRE)
3479# ifdef VBOX_NETFLT_ONDEMAND_BIND
3480 || (fDst & INTNETTRUNKDIR_HOST)
3481# endif
3482 )
3483 {
3484 PNDIS_PACKET pPacket;
3485
3486 pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3487 true /*fToWire*/, true /*fCopyMemory*/);
3488
3489 if (pPacket)
3490 {
3491 NDIS_STATUS fStatus;
3492
3493#ifndef VBOX_LOOPBACK_USEFLAGS
3494 /* force "don't loopback" flags to prevent loopback branch invocation in any case
3495 * to avoid ndis misbehave */
3496 NdisGetPacketFlags(pPacket) |= g_fPacketDontLoopBack;
3497#else
3498 /* this is done by default in vboxNetFltWinNdisPacketFromSG */
3499#endif
3500
3501#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3502 vboxNetFltWinLbPutSendPacket(pAdapt, pPacket, true /* bFromIntNet */);
3503#endif
3504 NdisSend(&fStatus, pAdapt->hBindingHandle, pPacket);
3505 if (fStatus != NDIS_STATUS_PENDING)
3506 {
3507#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3508 /* the status is NOT pending, complete the packet */
3509 bool bTmp = vboxNetFltWinLbRemoveSendPacket(pAdapt, pPacket);
3510 Assert(bTmp);
3511#endif
3512 if(!NT_SUCCESS(fStatus))
3513 {
3514 /* TODO: convert status to VERR_xxx */
3515 rc = VERR_GENERAL_FAILURE;
3516 }
3517
3518 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
3519 }
3520 else
3521 {
3522 /* pending, dereference on packet complete */
3523 cRefs--;
3524 }
3525 }
3526 else
3527 {
3528 AssertFailed();
3529 rc = VERR_NO_MEMORY;
3530 }
3531 }
3532#endif
3533#ifndef VBOX_NETFLT_ONDEMAND_BIND
3534#ifndef VBOXNETADP
3535 if (fDst & INTNETTRUNKDIR_HOST)
3536#else
3537 if(cRefs)
3538#endif
3539 {
3540 PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3541 false /*fToWire*/, true /*fCopyMemory*/);
3542 if (pPacket)
3543 {
3544 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pPacket, 1);
3545 cRefs--;
3546#ifdef VBOXNETADP
3547 STATISTIC_INCREASE(pAdapt->cRxSuccess);
3548#endif
3549 }
3550 else
3551 {
3552 AssertFailed();
3553#ifdef VBOXNETADP
3554 STATISTIC_INCREASE(pAdapt->cRxError);
3555#endif
3556 rc = VERR_NO_MEMORY;
3557 }
3558 }
3559
3560 Assert(cRefs <= 2);
3561
3562 if(cRefs)
3563 {
3564 vboxNetFltWinDecReferenceAdapt(pAdapt, cRefs);
3565 }
3566#endif
3567
3568 return rc;
3569}
3570
3571void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3572{
3573#ifndef VBOXNETADP
3574 NDIS_STATUS Status;
3575#endif
3576 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3577
3578 /* we first wait for all pending ops to complete
3579 * this might include all packets queued for processing */
3580 for(;;)
3581 {
3582 if(fActive)
3583 {
3584 if(!pThis->u.s.cModePassThruRefs)
3585 {
3586 break;
3587 }
3588 }
3589 else
3590 {
3591 if(!pThis->u.s.cModeNetFltRefs)
3592 {
3593 break;
3594 }
3595 }
3596 vboxNetFltWinSleep(2);
3597 }
3598
3599 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3600 return;
3601#ifndef VBOXNETADP
3602
3603 /* the packets put to ReceiveQueue Array are currently not holding the references,
3604 * simply need to flush them */
3605 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false /*fReturn*/);
3606
3607 if(fActive)
3608 {
3609#ifdef DEBUG_misha
3610 NDIS_PHYSICAL_MEDIUM PhMedium;
3611 bool bPromiscSupported;
3612
3613 Status = vboxNetFltWinQueryPhysicalMedium(pAdapt, &PhMedium);
3614 if(Status != NDIS_STATUS_SUCCESS)
3615 {
3616
3617 DBGPRINT(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3618 Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
3619 if(Status != NDIS_STATUS_NOT_SUPPORTED)
3620 {
3621 LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3622 }
3623 PhMedium = NdisPhysicalMediumUnspecified;
3624 }
3625 else
3626 {
3627 DBGPRINT(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
3628 }
3629
3630 bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
3631 || PhMedium == NdisPhysicalMediumWirelessLan
3632 || PhMedium == NdisPhysicalMediumNative802_11
3633 || PhMedium == NdisPhysicalMediumBluetooth
3634 /*|| PhMedium == NdisPhysicalMediumWiMax */
3635 ));
3636
3637 Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
3638#endif
3639 }
3640
3641 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3642 {
3643 Status = vboxNetFltWinSetPromiscuous(pAdapt, fActive);
3644 if(Status != NDIS_STATUS_SUCCESS)
3645 {
3646 DBGPRINT(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3647 AssertFailed();
3648 LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3649 }
3650 }
3651#else
3652# ifdef VBOXNETADP_REPORT_DISCONNECTED
3653 if(fActive)
3654 {
3655 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3656 NDIS_STATUS_MEDIA_CONNECT,
3657 (PVOID)NULL,
3658 0);
3659 }
3660 else
3661 {
3662 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3663 NDIS_STATUS_MEDIA_DISCONNECT,
3664 (PVOID)NULL,
3665 0);
3666 }
3667#else
3668 if(fActive)
3669 {
3670 /* indicate status change to make the ip settings be re-picked for dhcp */
3671 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3672 NDIS_STATUS_MEDIA_DISCONNECT,
3673 (PVOID)NULL,
3674 0);
3675
3676 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3677 NDIS_STATUS_MEDIA_CONNECT,
3678 (PVOID)NULL,
3679 0);
3680 }
3681# endif
3682#endif
3683 vboxNetFltWinDereferenceAdapt(pAdapt);
3684
3685 return;
3686}
3687
3688int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3689{
3690 NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
3691 return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3692}
3693
3694static void vboxNetFltWinConnectItWorker(PWORKER_INFO pInfo)
3695{
3696#if !defined(VBOXNETADP) || !defined(VBOXNETFLT_NO_PACKET_QUEUE)
3697 NDIS_STATUS Status;
3698#endif
3699 PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
3700 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
3701
3702 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3703
3704 /* this is not a rediscovery, initialize Mac cache */
3705 if(vboxNetFltWinReferenceAdapt(pAdapt))
3706 {
3707#ifndef VBOXNETADP
3708 Status = vboxNetFltWinGetMacAddress(pAdapt, &pInstance->u.s.MacAddr);
3709 if (Status == NDIS_STATUS_SUCCESS)
3710#endif
3711 {
3712#ifdef VBOXNETFLT_NO_PACKET_QUEUE
3713 pInfo->Status = VINF_SUCCESS;
3714#else
3715 Status = vboxNetFltWinQuInitPacketQueue(pInstance);
3716 if(Status == NDIS_STATUS_SUCCESS)
3717 {
3718 pInfo->Status = VINF_SUCCESS;
3719 }
3720 else
3721 {
3722 pInfo->Status = VERR_GENERAL_FAILURE;
3723 }
3724#endif
3725 }
3726#ifndef VBOXNETADP
3727 else
3728 {
3729 pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
3730 }
3731#endif
3732
3733 vboxNetFltWinDereferenceAdapt(pAdapt);
3734 }
3735 else
3736 {
3737 pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
3738 }
3739}
3740
3741static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
3742{
3743 WORKER_INFO Info;
3744 Info.pNetFltIf = pThis;
3745
3746 vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
3747
3748 if (RT_SUCCESS(Info.Status))
3749 vboxNetFltWinReportStuff(pThis);
3750
3751 return Info.Status;
3752}
3753
3754int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3755{
3756 return vboxNetFltWinConnectIt(pThis);
3757}
3758
3759void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3760{
3761 vboxNetFltWinDeleteInstance(pThis);
3762}
3763
3764int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3765{
3766 int rc = RTSemMutexCreate(&pThis->u.s.hAdaptMutex);
3767 if (RT_SUCCESS(rc))
3768 {
3769 rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
3770 if (RT_SUCCESS(rc))
3771 {
3772 return rc;
3773 }
3774 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3775 }
3776 return rc;
3777}
3778
3779int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3780{
3781 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3782 pThis->u.s.cModeNetFltRefs = 0;
3783 pThis->u.s.cModePassThruRefs = 0;
3784 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3785 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3786#ifndef VBOXNETADP
3787 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3788#endif
3789 return VINF_SUCCESS;
3790}
3791
3792void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
3793{
3794}
3795
3796int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
3797{
3798 /* Nothing to do */
3799 return VINF_SUCCESS;
3800}
3801
3802int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
3803{
3804 /* Nothing to do */
3805 return VINF_SUCCESS;
3806}
3807
Note: See TracBrowser for help on using the repository browser.

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