VirtualBox

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

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

IntNet: Added Interface, Interface private data passing for per-interface based VBoxNetFlt.

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