VirtualBox

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

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

IntNet,VBoxNetFlt: Cleaned up the locking protocol between IntNet and NetFlt. Eleminated the out-bound trunk lock that IntNet always took when calling NetFlt.

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