VirtualBox

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

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

IntNet: added MAC address notification and connect/disconnect interface callbacks.

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