VirtualBox

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

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

VBoxNetFlt: Deal with multi segment SG buffers. TODO: One weird windows code path.

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