VirtualBox

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

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

IntNet/NetFlt: Added INTNETTRUNKSWPORT::pfnReportGsoCapabilities and enabled ring-0 transmission for linux hosts and wires.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 106.3 KB
Line 
1/* $Id: VBoxNetFlt-win.c 28723 2010-04-25 21:50:56Z 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/** @todo Need to report changes to the switch via:
1493 * pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, fPromisc);
1494 */
1495 Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
1496 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
1497 {
1498 NDIS_REQUEST Request;
1499 NDIS_STATUS fStatus;
1500 ULONG fFilter;
1501 ULONG fExpectedFilter;
1502 ULONG fOurFilter;
1503 Request.RequestType = NdisRequestQueryInformation;
1504 Request.DATA.QUERY_INFORMATION.InformationBuffer = &fFilter;
1505 Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(fFilter);
1506 Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
1507 fStatus = vboxNetFltWinSynchNdisRequest(pAdapt, &Request);
1508 if(fStatus != NDIS_STATUS_SUCCESS)
1509 {
1510 /* TODO: */
1511 AssertFailed();
1512 return fStatus;
1513 }
1514
1515 if(!pAdapt->bUpperProtSetFilterInitialized)
1516 {
1517 /* the cache was not initialized yet, initiate it with the current filter value */
1518 pAdapt->fUpperProtocolSetFilter = fFilter;
1519 pAdapt->bUpperProtSetFilterInitialized = true;
1520 }
1521
1522
1523 if(bYes)
1524 {
1525 fExpectedFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
1526 fOurFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
1527 }
1528 else
1529 {
1530 fExpectedFilter = pAdapt->fUpperProtocolSetFilter;
1531 fOurFilter = 0;
1532 }
1533
1534 if(fExpectedFilter != fFilter)
1535 {
1536 Request.RequestType = NdisRequestSetInformation;
1537 Request.DATA.SET_INFORMATION.InformationBuffer = &fExpectedFilter;
1538 Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(fExpectedFilter);
1539 Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
1540 fStatus = vboxNetFltWinSynchNdisRequest(pAdapt, &Request);
1541 if(fStatus != NDIS_STATUS_SUCCESS)
1542 {
1543 /* TODO */
1544 AssertFailed();
1545 return fStatus;
1546 }
1547 }
1548 pAdapt->fOurSetFilter = fOurFilter;
1549 return fStatus;
1550 }
1551 return NDIS_STATUS_NOT_SUPPORTED;
1552}
1553#else /* if defined VBOXNETADP */
1554
1555/**
1556 * Generates a new unique MAC address based on our vendor ID
1557 */
1558DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac)
1559{
1560 /* temporary use a time info */
1561 uint64_t NanoTS = RTTimeSystemNanoTS();
1562 pMac->au8[0] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 16) & 0xff);
1563 pMac->au8[1] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 8) & 0xff);
1564 pMac->au8[2] = (uint8_t)(VBOXNETADP_VENDOR_ID & 0xff);
1565 pMac->au8[3] = (uint8_t)(NanoTS & 0xff0000);
1566 pMac->au16[2] = (uint16_t)(NanoTS & 0xffff);
1567}
1568
1569DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
1570{
1571 static const char s_achDigits[17] = "0123456789abcdef";
1572 uint8_t u8;
1573 int i;
1574 PWSTR pString;
1575
1576 /* validate parameters */
1577 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
1578 AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
1579 AssertReturn(pNdisString->MaximumLength >= 13*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
1580
1581 pString = pNdisString->Buffer;
1582
1583 for( i = 0; i < 6; i++)
1584 {
1585 u8 = pMac->au8[i];
1586 pString[ 0] = s_achDigits[(u8 >> 4) & 0xf];
1587 pString[ 1] = s_achDigits[(u8/*>>0*/)& 0xf];
1588 pString += 2;
1589 }
1590
1591 pNdisString->Length = 12*sizeof(pNdisString->Buffer[0]);
1592
1593 *pString = L'\0';
1594
1595 return VINF_SUCCESS;
1596}
1597
1598static int vboxNetFltWinWchar2Int(WCHAR c, uint8_t * pv)
1599{
1600 if(c >= L'A' && c <= L'F')
1601 {
1602 *pv = (c - L'A') + 10;
1603 }
1604 else if(c >= L'a' && c <= L'f')
1605 {
1606 *pv = (c - L'a') + 10;
1607 }
1608 else if(c >= L'0' && c <= L'9')
1609 {
1610 *pv = (c - L'0');
1611 }
1612 else
1613 {
1614 return VERR_INVALID_PARAMETER;
1615 }
1616 return VINF_SUCCESS;
1617}
1618
1619DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
1620{
1621 int i, rc;
1622 PWSTR pString;
1623
1624 /* validate parameters */
1625 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
1626 AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
1627 AssertReturn(pNdisString->Length >= 12*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
1628
1629 pString = pNdisString->Buffer;
1630
1631 for(i = 0; i < 6; i++)
1632 {
1633 uint8_t v1, v2;
1634 rc = vboxNetFltWinWchar2Int(pString[0], &v1);
1635 if(RT_FAILURE(rc))
1636 {
1637 break;
1638 }
1639
1640 rc = vboxNetFltWinWchar2Int(pString[1], &v2);
1641 if(RT_FAILURE(rc))
1642 {
1643 break;
1644 }
1645
1646 pMac->au8[i] = (v1 << 4) | v2;
1647
1648 pString += 2;
1649 }
1650
1651 return rc;
1652}
1653
1654#endif
1655/**
1656 * creates a NDIS_PACKET from the PINTNETSG
1657 */
1658#ifdef VBOX_NETFLT_ONDEMAND_BIND
1659/* TODO: the bToWire parameter seems to be unneeded here, remove them*/
1660#endif
1661DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PADAPT pAdapt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
1662{
1663 NDIS_STATUS fStatus;
1664 PNDIS_PACKET pPacket;
1665
1666 Assert(pSG->aSegs[0].pv);
1667 Assert(pSG->cbTotal >= sizeof(ETH_HEADER_SIZE));
1668
1669/** @todo Hrmpf, how can we fix this assumption? I fear this'll cause data
1670 * corruption and maybe even BSODs ... */
1671 AssertReturn(pSG->cSegsUsed == 1 || bCopyMemory, NULL);
1672
1673#ifdef VBOX_NETFLT_ONDEMAND_BIND
1674 NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hSendPacketPoolHandle);
1675#elif defined(VBOXNETADP)
1676 NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hRecvPacketPoolHandle);
1677#else
1678 NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pAdapt->hSendPacketPoolHandle : pAdapt->hRecvPacketPoolHandle);
1679#endif
1680 if(fStatus == NDIS_STATUS_SUCCESS)
1681 {
1682 PNDIS_BUFFER pBuffer;
1683 PVOID pvMemBuf;
1684
1685 /* @todo: generally we do not always need to zero-initialize the complete OOB data here, reinitialize only when/what we need,
1686 * however we DO need to reset the status for the packets we indicate via NdisMIndicateReceivePacket to avoid packet loss
1687 * in case the status contains NDIS_STATUS_RESOURCES */
1688 VBOXNETFLT_OOB_INIT(pPacket);
1689
1690 if(bCopyMemory)
1691 {
1692 fStatus = vboxNetFltWinMemAlloc(&pvMemBuf, pSG->cbTotal);
1693 if(fStatus == NDIS_STATUS_SUCCESS)
1694 {
1695 IntNetSgRead(pSG, pvMemBuf);
1696 }
1697 else
1698 {
1699 AssertFailed();
1700 NdisFreePacket(pPacket);
1701 pPacket = NULL;
1702 }
1703 }
1704 else
1705 {
1706 pvMemBuf = pSG->aSegs[0].pv;
1707 }
1708 if(fStatus == NDIS_STATUS_SUCCESS)
1709 {
1710#ifdef VBOX_NETFLT_ONDEMAND_BIND
1711 NdisAllocateBuffer(&fStatus, &pBuffer,
1712 pAdapt->hSendBufferPoolHandle,
1713 pvMemBuf,
1714 pSG->cbTotal);
1715#elif defined(VBOXNETADP)
1716 NdisAllocateBuffer(&fStatus, &pBuffer,
1717 pAdapt->hRecvBufferPoolHandle,
1718 pvMemBuf,
1719 pSG->cbTotal);
1720#else
1721 NdisAllocateBuffer(&fStatus, &pBuffer,
1722 bToWire ? pAdapt->hSendBufferPoolHandle : pAdapt->hRecvBufferPoolHandle,
1723 pvMemBuf,
1724 pSG->cbTotal);
1725#endif
1726
1727 if(fStatus == NDIS_STATUS_SUCCESS)
1728 {
1729 NdisChainBufferAtBack(pPacket, pBuffer);
1730
1731#ifndef VBOX_NETFLT_ONDEMAND_BIND
1732 if(bToWire)
1733#endif
1734 {
1735 PSEND_RSVD pSendRsvd;
1736 pSendRsvd = (PSEND_RSVD)(pPacket->ProtocolReserved);
1737 pSendRsvd->pOriginalPkt = NULL;
1738 pSendRsvd->pBufToFree = pBufToFree;
1739#ifdef VBOX_LOOPBACK_USEFLAGS
1740 /* set "don't loopback" flags */
1741 NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
1742#else
1743 NdisSetPacketFlags(pPacket, 0);
1744#endif
1745 }
1746#ifndef VBOX_NETFLT_ONDEMAND_BIND
1747 else
1748 {
1749 PRECV_RSVD pRecvRsvd;
1750 pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
1751 pRecvRsvd->pOriginalPkt = NULL;
1752 pRecvRsvd->pBufToFree = pBufToFree;
1753
1754 /* me must set the header size on receive */
1755 NDIS_SET_PACKET_HEADER_SIZE(pPacket, ETH_HEADER_SIZE);
1756 /* NdisAllocatePacket zero-initializes the OOB data,
1757 * but keeps the packet flags, clean them here */
1758 NdisSetPacketFlags(pPacket, 0);
1759 }
1760#endif
1761 /* TODO: set out of bound data */
1762 }
1763 else
1764 {
1765 AssertFailed();
1766 if(bCopyMemory)
1767 {
1768 vboxNetFltWinMemFree(pvMemBuf);
1769 }
1770 NdisFreePacket(pPacket);
1771 pPacket = NULL;
1772 }
1773 }
1774 else
1775 {
1776 AssertFailed();
1777 NdisFreePacket(pPacket);
1778 pPacket = NULL;
1779 }
1780 }
1781 else
1782 {
1783 pPacket = NULL;
1784 }
1785
1786 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
1787
1788 return pPacket;
1789}
1790
1791/*
1792 * frees NDIS_PACKET creaed with vboxNetFltWinNdisPacketFromSG
1793 */
1794DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem)
1795{
1796 UINT cBufCount;
1797 PNDIS_BUFFER pFirstBuffer;
1798 UINT uTotalPacketLength;
1799 PNDIS_BUFFER pBuffer;
1800
1801 NdisQueryPacket(pPacket, NULL, &cBufCount, &pFirstBuffer, &uTotalPacketLength);
1802
1803 Assert(cBufCount == 1);
1804
1805 do
1806 {
1807 NdisUnchainBufferAtBack(pPacket, &pBuffer);
1808 if(pBuffer != NULL)
1809 {
1810 PVOID pvMemBuf;
1811 UINT cbLength;
1812
1813 NdisQueryBufferSafe(pBuffer, &pvMemBuf, &cbLength, NormalPagePriority);
1814 NdisFreeBuffer(pBuffer);
1815 if(bFreeMem)
1816 {
1817 vboxNetFltWinMemFree(pvMemBuf);
1818 }
1819 }
1820 else
1821 {
1822 break;
1823 }
1824 } while(true);
1825
1826 NdisFreePacket(pPacket);
1827}
1828
1829/*
1830 * Free all packet pools on the specified adapter.
1831 * @param pAdapt - pointer to ADAPT structure
1832 */
1833static VOID
1834vboxNetFltWinPtFreeAllPacketPools(
1835 IN PADAPT pAdapt
1836 )
1837{
1838#ifndef VBOX_NETFLT_ONDEMAND_BIND
1839 if (pAdapt->hRecvPacketPoolHandle != NULL)
1840 {
1841 /*
1842 * Free the packet pool that is used to indicate receives
1843 */
1844 NdisFreePacketPool(pAdapt->hRecvPacketPoolHandle);
1845
1846 pAdapt->hRecvPacketPoolHandle = NULL;
1847 }
1848#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND*/
1849#ifndef VBOXNETADP
1850 if (pAdapt->hSendPacketPoolHandle != NULL)
1851 {
1852
1853 /*
1854 * Free the packet pool that is used to send packets below
1855 */
1856
1857 NdisFreePacketPool(pAdapt->hSendPacketPoolHandle);
1858
1859 pAdapt->hSendPacketPoolHandle = NULL;
1860
1861 }
1862#endif
1863}
1864#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
1865static void vboxNetFltWinAssociateMiniportProtocol()
1866{
1867 NdisIMAssociateMiniport(vboxNetFltWinMpGetHandle(), vboxNetFltWinPtGetHandle());
1868}
1869#endif
1870
1871/*
1872 * NetFlt driver unload function
1873 */
1874DECLHIDDEN(VOID)
1875vboxNetFltWinUnload(
1876 IN PDRIVER_OBJECT DriverObject
1877 )
1878{
1879 int rc;
1880 UNREFERENCED_PARAMETER(DriverObject);
1881
1882 LogFlow(("vboxNetFltWinUnload: entered\n"));
1883
1884 rc = vboxNetFltWinTryFiniIdc();
1885 if (RT_FAILURE(rc))
1886 {
1887 /* TODO: we can not prevent driver unload here */
1888 AssertFailed();
1889
1890 Log(("vboxNetFltWinTryFiniIdc - failed, busy.\n"));
1891 }
1892
1893 vboxNetFltWinJobFiniQueue(&g_JobQueue);
1894#ifndef VBOXNETADP
1895 vboxNetFltWinPtDeregister();
1896#endif
1897#ifndef VBOX_NETFLT_ONDEMAND_BIND
1898 vboxNetFltWinMpDeregister();
1899#endif
1900
1901 vboxNetFltWinFiniNetFltBase();
1902 /* don't use logging or any RT after de-init */
1903
1904 NdisFreeSpinLock(&g_GlobalLock);
1905}
1906
1907RT_C_DECLS_BEGIN
1908
1909NTSTATUS
1910DriverEntry(
1911 IN PDRIVER_OBJECT DriverObject,
1912 IN PUNICODE_STRING RegistryPath
1913 );
1914
1915RT_C_DECLS_END
1916/*
1917 * First entry point to be called, when this driver is loaded.
1918 * Register with NDIS as an intermediate driver.
1919 * @return STATUS_SUCCESS if all initialization is successful, STATUS_XXX
1920 * error code if not.
1921 */
1922NTSTATUS
1923DriverEntry(
1924 IN PDRIVER_OBJECT DriverObject,
1925 IN PUNICODE_STRING RegistryPath
1926 )
1927{
1928 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1929 int rc;
1930#ifdef VBOX_LOOPBACK_USEFLAGS
1931 ULONG MjVersion;
1932 ULONG MnVersion;
1933#endif
1934
1935 NdisAllocateSpinLock(&g_GlobalLock);
1936
1937#ifdef VBOX_NETFLT_ONDEMAND_BIND
1938 /* we are registering in the DriverEntry only when we are working as a protocol
1939 * since in this case our driver is loaded after the VBoxDrv*/
1940 rc = vboxNetFltWinInitNetFlt();
1941#else
1942 /* the idc registration is initiated via IOCTL since our driver
1943 * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
1944 rc = vboxNetFltWinInitNetFltBase();
1945#endif
1946 AssertRC(rc);
1947 if(RT_SUCCESS(rc))
1948 {
1949#ifdef VBOX_LOOPBACK_USEFLAGS
1950 PsGetVersion(&MjVersion, &MnVersion,
1951 NULL, /* PULONG BuildNumber OPTIONAL */
1952 NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
1953 );
1954
1955 g_fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
1956
1957 if(MjVersion == 5 && MnVersion == 0)
1958 {
1959 /* this is Win2k*/
1960 g_fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
1961 }
1962
1963 g_fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
1964#endif
1965
1966 Status = vboxNetFltWinJobInitQueue(&g_JobQueue);
1967 Assert(Status == STATUS_SUCCESS);
1968 if(Status == STATUS_SUCCESS)
1969 {
1970 /* note: we do it after we initialize the Job Queue */
1971 vboxNetFltWinStartInitIdcProbing();
1972
1973#ifndef VBOX_NETFLT_ONDEMAND_BIND
1974 Status = vboxNetFltWinMpRegister(DriverObject, RegistryPath);
1975 Assert(Status == STATUS_SUCCESS);
1976 if (Status == NDIS_STATUS_SUCCESS)
1977#endif
1978 {
1979#ifndef VBOXNETADP
1980 Status = vboxNetFltWinPtRegister(DriverObject, RegistryPath);
1981 Assert(Status == STATUS_SUCCESS);
1982 if (Status == NDIS_STATUS_SUCCESS)
1983#endif
1984 {
1985#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
1986 vboxNetFltWinAssociateMiniportProtocol();
1987#endif
1988 return STATUS_SUCCESS;
1989
1990//#ifndef VBOXNETADP
1991// vboxNetFltWinPtDeregister();
1992//#endif
1993 }
1994#ifndef VBOX_NETFLT_ONDEMAND_BIND
1995 vboxNetFltWinMpDeregister();
1996#endif
1997 }
1998 vboxNetFltWinJobFiniQueue(&g_JobQueue);
1999 }
2000 vboxNetFltWinFiniNetFlt();
2001 }
2002 else
2003 {
2004 Status = NDIS_STATUS_FAILURE;
2005 }
2006
2007 NdisFreeSpinLock(&g_GlobalLock);
2008
2009 return(Status);
2010}
2011
2012#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
2013/**
2014 * creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
2015 * according to DDK docs we must create our own packet rather than posting the one passed to us
2016 */
2017DECLHIDDEN(NDIS_STATUS)
2018vboxNetFltWinPrepareSendPacket(
2019 IN PADAPT pAdapt,
2020 IN PNDIS_PACKET pPacket,
2021 OUT PNDIS_PACKET *ppMyPacket
2022 /*, IN bool bNetFltActive */
2023 )
2024{
2025 NDIS_STATUS fStatus;
2026
2027 NdisAllocatePacket(&fStatus,
2028 ppMyPacket,
2029 pAdapt->hSendPacketPoolHandle);
2030
2031 if (fStatus == NDIS_STATUS_SUCCESS)
2032 {
2033 PSEND_RSVD pSendRsvd;
2034
2035 pSendRsvd = (PSEND_RSVD)((*ppMyPacket)->ProtocolReserved);
2036 pSendRsvd->pOriginalPkt = pPacket;
2037 pSendRsvd->pBufToFree = NULL;
2038
2039 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2040 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2041
2042 vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
2043
2044#ifdef VBOX_LOOPBACK_USEFLAGS
2045 NdisGetPacketFlags(*ppMyPacket) |= g_fPacketDontLoopBack;
2046#endif
2047 }
2048 else
2049 {
2050 *ppMyPacket = NULL;
2051 }
2052
2053 return fStatus;
2054}
2055
2056/**
2057 * creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
2058 * according to DDK docs we must create our own packet rather than posting the one passed to us
2059 */
2060DECLHIDDEN(NDIS_STATUS)
2061vboxNetFltWinPrepareRecvPacket(
2062 IN PADAPT pAdapt,
2063 IN PNDIS_PACKET pPacket,
2064 OUT PNDIS_PACKET *ppMyPacket,
2065 IN bool bDpr
2066 )
2067{
2068 NDIS_STATUS fStatus;
2069
2070 /*
2071 * Get a packet off the pool and indicate that up
2072 */
2073 if(bDpr)
2074 {
2075 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
2076
2077 NdisDprAllocatePacket(&fStatus,
2078 ppMyPacket,
2079 pAdapt->hRecvPacketPoolHandle);
2080 }
2081 else
2082 {
2083 NdisAllocatePacket(&fStatus,
2084 ppMyPacket,
2085 pAdapt->hRecvPacketPoolHandle);
2086 }
2087
2088 if (fStatus == NDIS_STATUS_SUCCESS)
2089 {
2090 PRECV_RSVD pRecvRsvd;
2091
2092 pRecvRsvd = (PRECV_RSVD)((*ppMyPacket)->MiniportReserved);
2093 pRecvRsvd->pOriginalPkt = pPacket;
2094 pRecvRsvd->pBufToFree = NULL;
2095
2096 NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
2097 NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
2098
2099 fStatus = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket);
2100 }
2101 else
2102 {
2103 *ppMyPacket = NULL;
2104 }
2105 return fStatus;
2106}
2107#endif
2108
2109/**
2110 * initializes the ADAPT (our context structure) and binds to the given adapter
2111 */
2112#if defined(VBOX_NETFLT_ONDEMAND_BIND)
2113DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT pAdapt)
2114#elif defined(VBOXNETADP)
2115DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
2116#else
2117DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
2118#endif
2119{
2120 NDIS_STATUS Status;
2121 do
2122 {
2123#ifndef VBOX_NETFLT_ONDEMAND_BIND
2124 ANSI_STRING AnsiString;
2125 int rc;
2126 PVBOXNETFLTINS pInstance;
2127 USHORT cbAnsiName = pBindToMiniportName->Length;/* the lenght is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
2128 CREATE_INSTANCE_CONTEXT Context;
2129 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2130
2131# ifndef VBOXNETADP
2132 Context.pOurName = pOurMiniportName;
2133 Context.pBindToName = pBindToMiniportName;
2134# else
2135 Context.hMiniportAdapter = hMiniportAdapter;
2136 Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
2137# endif
2138 Context.Status = NDIS_STATUS_SUCCESS;
2139
2140 AnsiString.Buffer = 0; /* will be allocated by RtlUnicodeStringToAnsiString */
2141 AnsiString.Length = 0;
2142 AnsiString.MaximumLength = cbAnsiName;
2143
2144 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2145
2146 Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, true);
2147
2148 if(Status != STATUS_SUCCESS)
2149 {
2150 break;
2151 }
2152
2153 rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, AnsiString.Buffer, &pInstance, &Context);
2154 RtlFreeAnsiString(&AnsiString);
2155 if(RT_FAILURE(rc))
2156 {
2157 AssertFailed();
2158 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2159 break;
2160 }
2161
2162 Assert(pInstance);
2163
2164 if(rc == VINF_ALREADY_INITIALIZED)
2165 {
2166 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2167 /* the case when our adapter was unbound while IntNet was connected to it */
2168 /* the instance remains valid until intNet disconnects from it, we simply search and re-use it*/
2169
2170 /* re-initialize PADAPT */
2171 rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
2172 if(RT_FAILURE(rc))
2173 {
2174 AssertFailed();
2175 Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
2176 /* release netflt */
2177 vboxNetFltRelease(pInstance, false);
2178
2179 break;
2180 }
2181 }
2182
2183 *ppAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
2184#else
2185 Status = vboxNetFltWinPtAllocInitPADAPT(pAdapt);
2186 if (Status != NDIS_STATUS_SUCCESS)
2187 {
2188 break;
2189 }
2190
2191 Status = vboxNetFltWinPtDoBinding(pAdapt);
2192 if (Status != NDIS_STATUS_SUCCESS)
2193 {
2194 vboxNetFltWinPtFiniPADAPT(pAdapt);
2195 break;
2196 }
2197#endif
2198 }while(FALSE);
2199
2200 return Status;
2201}
2202
2203/**
2204 * initializes the ADAPT
2205 */
2206#ifdef VBOX_NETFLT_ONDEMAND_BIND
2207DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT pAdapt)
2208{
2209 NDIS_STATUS Status;
2210
2211 do
2212 {
2213 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
2214 if (Status != NDIS_STATUS_SUCCESS)
2215 {
2216 break;
2217 }
2218 Status = NDIS_STATUS_SUCCESS;
2219 } while(0);
2220
2221 return Status;
2222}
2223
2224/**
2225 * unbinds from the adapter we are bound to and deinitializes the ADAPT
2226 */
2227static NDIS_STATUS vboxNetFltWinPtFiniUnbind(PADAPT pAdapt)
2228{
2229 NDIS_STATUS Status;
2230
2231 LogFlow(("==> vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2232
2233 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2234
2235 do
2236 {
2237 Status = vboxNetFltWinPtDoUnbinding(pAdapt, true);
2238 if(Status != NDIS_STATUS_SUCCESS)
2239 {
2240 AssertFailed();
2241 /* TODO: should we break ? */
2242 /* break; */
2243 }
2244
2245 vboxNetFltWinPtFiniPADAPT(pAdapt);
2246 } while(0);
2247 LogFlow(("<== vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
2248
2249 return Status;
2250}
2251#endif
2252
2253/*
2254 * deinitializes the ADAPT
2255 */
2256DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt)
2257{
2258#ifndef VBOXNETADP
2259 int rc;
2260#endif
2261
2262 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2263
2264 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2265#ifndef VBOXNETADP
2266 if(pAdapt->DeviceName.Buffer)
2267 {
2268 vboxNetFltWinMemFree(pAdapt->DeviceName.Buffer);
2269 }
2270
2271
2272 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2273# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2274 FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2275# endif
2276#endif
2277
2278#ifndef VBOX_NETFLT_ONDEMAND_BIND
2279 /* moved to vboxNetFltWinDetachFromInterfaceWorker */
2280#else
2281 vboxNetFltWinQuFiniPacketQueue(pAdapt);
2282#endif
2283
2284 vboxNetFltWinFiniBuffers(pAdapt);
2285
2286 /*
2287 * Free the memory here, if was not released earlier(by calling the HaltHandler)
2288 */
2289 vboxNetFltWinPtFreeAllPacketPools (pAdapt);
2290#ifndef VBOXNETADP
2291 rc = RTSemFastMutexDestroy(pAdapt->hSynchRequestMutex); AssertRC(rc);
2292#endif
2293
2294 LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
2295}
2296
2297DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
2298#ifndef VBOXNETADP
2299DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName)
2300#else
2301DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN PADAPT pAdapt)
2302#endif
2303{
2304 NDIS_STATUS Status;
2305#ifndef VBOXNETADP
2306 int rc;
2307#endif
2308 BOOLEAN bCallFiniOnFail = FALSE;
2309
2310 LogFlow(("==> vboxNetFltWinPtInitPADAPT : pAdapt %p\n", pAdapt));
2311
2312 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
2313
2314 do
2315 {
2316 NdisZeroMemory(pAdapt, sizeof(ADAPT));
2317#ifndef VBOXNETADP
2318 NdisInitializeEvent(&pAdapt->hEvent);
2319
2320 KeInitializeEvent(&pAdapt->hSynchCompletionEvent, SynchronizationEvent, FALSE);
2321
2322 /*
2323 * Allocate a packet pool for sends. We need this to pass sends down.
2324 * We cannot use the same packet descriptor that came down to our send
2325 * handler (see also NDIS 5.1 packet stacking).
2326 */
2327 NdisAllocatePacketPoolEx(&Status,
2328 &pAdapt->hSendPacketPoolHandle,
2329 MIN_PACKET_POOL_SIZE,
2330 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2331 sizeof(SEND_RSVD));
2332
2333 if (Status != NDIS_STATUS_SUCCESS)
2334 {
2335 pAdapt->hSendPacketPoolHandle = NULL;
2336 break;
2337 }
2338#else
2339#endif
2340
2341 Status = vboxNetFltWinInitBuffers(pAdapt);
2342 if (Status != NDIS_STATUS_SUCCESS)
2343 {
2344 break;
2345 }
2346
2347 bCallFiniOnFail = TRUE;
2348#ifndef VBOXNETADP
2349 rc = RTSemFastMutexCreate(&pAdapt->hSynchRequestMutex);
2350 if(RT_FAILURE(rc))
2351 {
2352 Status = NDIS_STATUS_FAILURE;
2353 break;
2354 }
2355#endif
2356
2357#ifndef VBOX_NETFLT_ONDEMAND_BIND
2358# ifndef VBOXNETADP
2359 Status = vboxNetFltWinMemAlloc((PVOID*)&pAdapt->DeviceName.Buffer, pOurDeviceName->Length);
2360 if(Status != NDIS_STATUS_SUCCESS)
2361 {
2362 AssertFailed();
2363 pAdapt->DeviceName.Buffer = NULL;
2364 break;
2365 }
2366 pAdapt->DeviceName.MaximumLength = pOurDeviceName->Length;
2367 pAdapt->DeviceName.Length = 0;
2368 Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
2369 if(Status != NDIS_STATUS_SUCCESS)
2370 {
2371 AssertFailed();
2372 break;
2373 }
2374# endif
2375
2376 /*
2377 * Allocate a packet pool for receives. We need this to indicate receives.
2378 * Same consideration as sends (see also NDIS 5.1 packet stacking).
2379 */
2380 NdisAllocatePacketPoolEx(&Status,
2381 &pAdapt->hRecvPacketPoolHandle,
2382 MIN_PACKET_POOL_SIZE,
2383 MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
2384 PROTOCOL_RESERVED_SIZE_IN_PACKET);
2385
2386 if (Status != NDIS_STATUS_SUCCESS)
2387 {
2388 pAdapt->hRecvPacketPoolHandle = NULL;
2389 break;
2390 }
2391#ifndef VBOXNETADP
2392 NdisInitializeEvent(&pAdapt->MiniportInitEvent);
2393#endif
2394#endif
2395#ifndef VBOXNETADP
2396 pAdapt->PTState.PowerState = NdisDeviceStateD3;
2397 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
2398
2399 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
2400
2401# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
2402 INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->SendPacketQueue);
2403# endif
2404#endif
2405 /* TODO: do we need it here ?? */
2406 pAdapt->MPState.PowerState = NdisDeviceStateD3;
2407 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
2408
2409#ifdef VBOX_NETFLT_ONDEMAND_BIND
2410 {
2411 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2412 rc = vboxNetFltWinConnectIt(pNetFlt);
2413 if(RT_FAILURE(rc))
2414 {
2415 AssertFailed();
2416 Status = NDIS_STATUS_FAILURE;
2417 break;
2418 }
2419 }
2420#endif
2421
2422 /* moved to vboxNetFltOsInitInstance */
2423 } while(0);
2424
2425 if (Status != NDIS_STATUS_SUCCESS)
2426 {
2427 if(bCallFiniOnFail)
2428 {
2429 vboxNetFltWinPtFiniPADAPT(pAdapt);
2430 }
2431 }
2432
2433 LogFlow(("<== vboxNetFltWinPtInitPADAPT : pAdapt %p, Status %x\n", pAdapt, Status));
2434
2435 return Status;
2436}
2437
2438/**
2439 * match packets
2440 */
2441#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
2442#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
2443#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
2444#define LAST_LIST_ENTRY PREV_LIST_ENTRY
2445
2446#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
2447
2448#ifndef VBOXNETADP
2449
2450#ifdef DEBUG_misha
2451
2452RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2453RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
2454
2455DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
2456{
2457 UINT cBufCount1;
2458 PNDIS_BUFFER pBuffer1;
2459 UINT uTotalPacketLength1;
2460 RTNETETHERHDR* pEth;
2461 UINT cbLength1 = 0;
2462 UINT i = 0;
2463
2464 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2465
2466 Assert(pBuffer1);
2467 Assert(uTotalPacketLength1 >= ETH_HEADER_SIZE);
2468 if(uTotalPacketLength1 < ETH_HEADER_SIZE)
2469 return NULL;
2470
2471 NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
2472 Assert(cbLength1 >= ETH_HEADER_SIZE);
2473 if(cbLength1 < ETH_HEADER_SIZE)
2474 return NULL;
2475
2476 return pEth;
2477}
2478
2479DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
2480{
2481 Assert(pSG->cSegsUsed);
2482 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2483 Assert(pSG->aSegs[0].cb >= ETH_HEADER_SIZE);
2484
2485 if(!pSG->cSegsUsed)
2486 return NULL;
2487
2488 if(pSG->aSegs[0].cb < ETH_HEADER_SIZE)
2489 return NULL;
2490
2491 return (PRTNETETHERHDR)pSG->aSegs[0].pv;
2492}
2493
2494DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
2495{
2496 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
2497 Assert(pHdr);
2498
2499 if(!pHdr)
2500 return false;
2501
2502 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2503 return false;
2504
2505 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2506 return false;
2507
2508 return true;
2509}
2510
2511DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
2512{
2513 PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
2514 Assert(pHdr);
2515
2516 if(!pHdr)
2517 return false;
2518
2519 if(pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
2520 return false;
2521
2522 if(pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
2523 return false;
2524
2525 return true;
2526}
2527#endif
2528
2529# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
2530/*
2531 * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
2532 * if cbMatch < 0 matches complete packets.
2533 */
2534DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
2535{
2536 UINT cBufCount1;
2537 PNDIS_BUFFER pBuffer1;
2538 UINT uTotalPacketLength1;
2539 uint8_t* pMemBuf1;
2540 UINT cbLength1 = 0;
2541
2542 UINT cBufCount2;
2543 PNDIS_BUFFER pBuffer2;
2544 UINT uTotalPacketLength2;
2545 uint8_t* pMemBuf2;
2546 UINT cbLength2 = 0;
2547 bool bMatch = true;
2548
2549#ifdef DEBUG_NETFLT_PACKETS
2550 bool bCompleteMatch = false;
2551#endif
2552
2553 NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2554 NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
2555
2556 Assert(pBuffer1);
2557 Assert(pBuffer2);
2558
2559 if(uTotalPacketLength1 != uTotalPacketLength2)
2560 {
2561 bMatch = false;
2562 }
2563 else
2564 {
2565 UINT ucbLength2Match = 0;
2566 UINT ucbMatch;
2567 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2568 {
2569 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2570 ucbMatch = uTotalPacketLength1;
2571#ifdef DEBUG_NETFLT_PACKETS
2572 bCompleteMatch = true;
2573#endif
2574 }
2575 else
2576 {
2577 ucbMatch = (UINT)cbMatch;
2578 }
2579
2580 for(;;)
2581 {
2582 if(!cbLength1)
2583 {
2584 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2585 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2586 }
2587 else
2588 {
2589 Assert(pMemBuf1);
2590 Assert(ucbLength2Match);
2591 pMemBuf1 += ucbLength2Match;
2592 }
2593
2594 if(!cbLength2)
2595 {
2596 NdisQueryBufferSafe(pBuffer2, &pMemBuf2, &cbLength2, NormalPagePriority);
2597 NdisGetNextBuffer(pBuffer2, &pBuffer2);
2598 }
2599 else
2600 {
2601 Assert(pMemBuf2);
2602 Assert(ucbLength2Match);
2603 pMemBuf2 += ucbLength2Match;
2604 }
2605
2606 ucbLength2Match = MIN(ucbMatch, cbLength1);
2607 ucbLength2Match = MIN(ucbMatch, cbLength2);
2608
2609 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2610 {
2611 bMatch = false;
2612 break;
2613 }
2614
2615 ucbMatch -= ucbLength2Match;
2616 if(!ucbMatch)
2617 break;
2618
2619 cbLength1 -= ucbLength2Match;
2620 cbLength2 -= ucbLength2Match;
2621 }
2622 }
2623
2624#ifdef DEBUG_NETFLT_PACKETS
2625 if(bMatch && !bCompleteMatch)
2626 {
2627 /* check that the packets fully match */
2628 DBG_CHECK_PACKETS(pPacket1, pPacket2);
2629 }
2630#endif
2631
2632 return bMatch;
2633}
2634
2635/*
2636 * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
2637 * if cbMatch < 0 matches complete packets.
2638 */
2639DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
2640{
2641 UINT cBufCount1;
2642 PNDIS_BUFFER pBuffer1;
2643 UINT uTotalPacketLength1;
2644 uint8_t* pMemBuf1;
2645 UINT cbLength1 = 0;
2646 UINT uTotalPacketLength2 = pSG->cbTotal;
2647 uint8_t* pMemBuf2;
2648 UINT cbLength2 = 0;
2649 bool bMatch = true;
2650 bool bCompleteMatch = false;
2651 UINT i = 0;
2652
2653 NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
2654
2655 Assert(pBuffer1);
2656 Assert(pSG->cSegsUsed);
2657 Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
2658
2659 if(uTotalPacketLength1 != uTotalPacketLength2)
2660 {
2661 AssertFailed();
2662 bMatch = false;
2663 }
2664 else
2665 {
2666 UINT ucbLength2Match = 0;
2667 UINT ucbMatch;
2668
2669 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2670 {
2671 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2672 ucbMatch = uTotalPacketLength1;
2673 bCompleteMatch = true;
2674 }
2675 else
2676 {
2677 ucbMatch = (UINT)cbMatch;
2678 }
2679
2680 for(;;)
2681 {
2682 if(!cbLength1)
2683 {
2684 NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
2685 NdisGetNextBuffer(pBuffer1, &pBuffer1);
2686 }
2687 else
2688 {
2689 Assert(pMemBuf1);
2690 Assert(ucbLength2Match);
2691 pMemBuf1 += ucbLength2Match;
2692 }
2693
2694 if(!cbLength2)
2695 {
2696 Assert(i < pSG->cSegsUsed);
2697 pMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
2698 cbLength2 = pSG->aSegs[i].cb;
2699 i++;
2700 }
2701 else
2702 {
2703 Assert(pMemBuf2);
2704 Assert(ucbLength2Match);
2705 pMemBuf2 += ucbLength2Match;
2706 }
2707
2708 ucbLength2Match = MIN(ucbMatch, cbLength1);
2709 ucbLength2Match = MIN(ucbMatch, cbLength2);
2710
2711 if(memcmp((PVOID*)pMemBuf1, (PVOID*)pMemBuf2, ucbLength2Match))
2712 {
2713 bMatch = false;
2714 AssertFailed();
2715 break;
2716 }
2717
2718 ucbMatch -= ucbLength2Match;
2719 if(!ucbMatch)
2720 break;
2721
2722 cbLength1 -= ucbLength2Match;
2723 cbLength2 -= ucbLength2Match;
2724 }
2725 }
2726
2727 if(bMatch && !bCompleteMatch)
2728 {
2729 /* check that the packets fully match */
2730 DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
2731 }
2732 return bMatch;
2733}
2734
2735# if 0
2736/*
2737 * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
2738 * if cbMatch < 0 matches complete packets.
2739 */
2740static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
2741{
2742 UINT uTotalPacketLength1 = pSG1->cbTotal;
2743 PVOID pMemBuf1;
2744 UINT cbLength1 = 0;
2745 UINT i1 = 0;
2746 UINT uTotalPacketLength2 = pSG2->cbTotal;
2747 PVOID pMemBuf2;
2748 UINT cbLength2 = 0;
2749
2750 bool bMatch = true;
2751 bool bCompleteMatch = false;
2752 UINT i2 = 0;
2753
2754 Assert(pSG1->cSegsUsed);
2755 Assert(pSG2->cSegsUsed);
2756 Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
2757 Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
2758
2759 if(uTotalPacketLength1 != uTotalPacketLength2)
2760 {
2761 AssertFailed();
2762 bMatch = false;
2763 }
2764 else
2765 {
2766 UINT ucbMatch;
2767 if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
2768 {
2769 /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
2770 ucbMatch = uTotalPacketLength1;
2771 bCompleteMatch = true;
2772 }
2773 else
2774 {
2775 ucbMatch = (UINT)cbMatch;
2776 }
2777
2778 do
2779 {
2780 UINT ucbLength2Match;
2781 if(!cbLength1)
2782 {
2783 Assert(i1 < pSG1->cSegsUsed);
2784 pMemBuf1 = pSG1->aSegs[i1].pv;
2785 cbLength1 = pSG1->aSegs[i1].cb;
2786 i1++;
2787 }
2788
2789 if(!cbLength2)
2790 {
2791 Assert(i2 < pSG2->cSegsUsed);
2792 pMemBuf2 = pSG2->aSegs[i2].pv;
2793 cbLength2 = pSG2->aSegs[i2].cb;
2794 i2++;
2795 }
2796
2797 ucbLength2Match = MIN(ucbMatch, cbLength1);
2798 ucbLength2Match = MIN(ucbMatch, cbLength2);
2799
2800 if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
2801 {
2802 bMatch = false;
2803 AssertFailed();
2804 break;
2805 }
2806 ucbMatch -= ucbLength2Match;
2807 cbLength1 -= ucbLength2Match;
2808 cbLength2 -= ucbLength2Match;
2809 } while (ucbMatch);
2810 }
2811
2812 if(bMatch && !bCompleteMatch)
2813 {
2814 /* check that the packets fully match */
2815 DBG_CHECK_SGS(pSG1, pSG2);
2816 }
2817 return bMatch;
2818}
2819# endif
2820# endif
2821#endif
2822
2823static void vboxNetFltWinFiniNetFltBase()
2824{
2825 do
2826 {
2827 vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
2828
2829 /*
2830 * Undo the work done during start (in reverse order).
2831 */
2832 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2833
2834 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
2835 RTLogDestroy(RTLogSetDefaultInstance(NULL));
2836
2837 RTR0Term();
2838 } while (0);
2839}
2840
2841static int vboxNetFltWinTryFiniIdc()
2842{
2843 int rc;
2844
2845 vboxNetFltWinStopInitIdcProbing();
2846
2847 if(g_bIdcInitialized)
2848 {
2849 rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
2850 if(RT_SUCCESS(rc))
2851 {
2852 g_bIdcInitialized = false;
2853 }
2854 }
2855 else
2856 {
2857 rc = VINF_SUCCESS;
2858 }
2859 return rc;
2860
2861}
2862
2863static int vboxNetFltWinFiniNetFlt()
2864{
2865 int rc = vboxNetFltWinTryFiniIdc();
2866 if(RT_SUCCESS(rc))
2867 {
2868 vboxNetFltWinFiniNetFltBase();
2869 }
2870 return rc;
2871}
2872
2873/**
2874 * base netflt initialization
2875 */
2876static int vboxNetFltWinInitNetFltBase()
2877{
2878 int rc;
2879
2880 do
2881 {
2882 Assert(!g_bIdcInitialized);
2883
2884 rc = RTR0Init(0);
2885 if (!RT_SUCCESS(rc))
2886 {
2887 break;
2888 }
2889
2890 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
2891 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
2892 if (!RT_SUCCESS(rc))
2893 {
2894 RTR0Term();
2895 break;
2896 }
2897 }while(0);
2898
2899 return rc;
2900}
2901
2902/**
2903 * initialize IDC
2904 */
2905static int vboxNetFltWinInitIdc()
2906{
2907 int rc;
2908
2909 do
2910 {
2911 if(g_bIdcInitialized)
2912 {
2913#ifdef VBOX_NETFLT_ONDEMAND_BIND
2914 AssertFailed();
2915#endif
2916 rc = VINF_ALREADY_INITIALIZED;
2917 break;
2918 }
2919
2920 /*
2921 * connect to the support driver.
2922 *
2923 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
2924 * for establishing the connect to the support driver.
2925 */
2926 rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
2927 if (!RT_SUCCESS(rc))
2928 {
2929 break;
2930 }
2931
2932 g_bIdcInitialized = true;
2933 } while (0);
2934
2935 return rc;
2936}
2937
2938static void vboxNetFltWinInitIdcProbingWorker(PINIT_IDC_INFO pInitIdcInfo)
2939{
2940 int rc = vboxNetFltWinInitIdc();
2941 if(RT_FAILURE(rc))
2942 {
2943 bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2944 if(!bInterupted)
2945 {
2946 RTThreadSleep(1000); /* 1 s */
2947 bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
2948 if(!bInterupted)
2949 {
2950 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &pInitIdcInfo->Job, false);
2951 return;
2952 }
2953 }
2954
2955 /* it's interupted */
2956 rc = VERR_INTERRUPTED;
2957 }
2958
2959 ASMAtomicUoWriteU32(&pInitIdcInfo->rc, rc);
2960 KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
2961}
2962
2963static int vboxNetFltWinStopInitIdcProbing()
2964{
2965 if(!g_InitIdcInfo.bInitialized)
2966 return VERR_INVALID_STATE;
2967
2968 ASMAtomicUoWriteBool(&g_InitIdcInfo.bStop, true);
2969 KeWaitForSingleObject(&g_InitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
2970
2971 return g_InitIdcInfo.rc;
2972}
2973
2974static int vboxNetFltWinStartInitIdcProbing()
2975{
2976 Assert(!g_bIdcInitialized);
2977 KeInitializeEvent(&g_InitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
2978 g_InitIdcInfo.bStop = false;
2979 g_InitIdcInfo.bInitialized = true;
2980 vboxNetFltWinJobInit(&g_InitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_InitIdcInfo, false);
2981 vboxNetFltWinJobEnqueueJob(&g_JobQueue, &g_InitIdcInfo.Job, false);
2982 return VINF_SUCCESS;
2983}
2984
2985static int vboxNetFltWinInitNetFlt()
2986{
2987 int rc;
2988
2989 do
2990 {
2991 rc = vboxNetFltWinInitNetFltBase();
2992 if(RT_FAILURE(rc))
2993 {
2994 AssertFailed();
2995 break;
2996 }
2997
2998 /*
2999 * connect to the support driver.
3000 *
3001 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
3002 * for establishing the connect to the support driver.
3003 */
3004 rc = vboxNetFltWinInitIdc();
3005 if (RT_FAILURE(rc))
3006 {
3007 AssertFailed();
3008 vboxNetFltWinFiniNetFltBase();
3009 break;
3010 }
3011 } while (0);
3012
3013 return rc;
3014}
3015
3016/* detach*/
3017static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
3018{
3019 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3020 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3021 NDIS_STATUS Status;
3022 LogFlow(("vboxNetFltWinDeleteInstance: pThis=%p \n", pThis));
3023
3024 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3025 Assert(pAdapt);
3026 Assert(pThis);
3027 Assert(pThis->fDisconnectedFromHost);
3028 Assert(!pThis->fRediscoveryPending);
3029 Assert(!pThis->fActive);
3030#ifndef VBOXNETADP
3031 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
3032 Assert(!pAdapt->hBindingHandle);
3033#endif
3034 Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Deinitialized);
3035 Assert(!pThis->u.s.PacketQueueWorker.pSG);
3036// Assert(!pAdapt->hMiniportHandle);
3037
3038#ifndef VBOX_NETFLT_ONDEMAND_BIND
3039 Status = vboxNetFltWinMpDereferenceControlDevice();
3040 Assert(Status == NDIS_STATUS_SUCCESS);
3041#else
3042 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3043 if(Status != NDIS_STATUS_SUCCESS)
3044 {
3045 AssertFailed();
3046 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3047 }
3048#endif
3049
3050 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3051
3052 return VINF_SUCCESS;
3053}
3054
3055static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
3056{
3057 vboxNetFltWinQuFiniPacketQueue(pInstance);
3058 return NDIS_STATUS_SUCCESS;
3059}
3060
3061/* detach*/
3062DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PADAPT pAdapt, bool bOnUnbind)
3063{
3064 PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
3065 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3066 NDIS_STATUS Status;
3067 int rc;
3068 LogFlow(("vboxNetFltWinDetachFromInterface: pThis=%p\n", pThis));
3069
3070 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
3071 Assert(pAdapt);
3072 Assert(pThis);
3073/* Assert(!pThis->fActive); */
3074
3075 /* paranoya to ensyre the instance is not removed while we're waiting on the mutex
3076 * in case ndis does something unpredictable, e.g. calls our miniport halt independently
3077 * from protocol unbind and concurrently with it*/
3078 vboxNetFltRetain(pThis, false);
3079
3080 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3081 if(RT_SUCCESS(rc))
3082 {
3083#ifndef VBOX_NETFLT_ONDEMAND_BIND
3084 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected);
3085 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3086#ifndef VBOXNETADP
3087 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3088#endif
3089// if(
3090//#ifdef VBOXNETADP
3091// vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3092//#else
3093// vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized
3094//// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
3095//#endif
3096// )
3097 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected)
3098 {
3099 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnecting);
3100#ifndef VBOXNETADP
3101 Status = vboxNetFltWinPtDoUnbinding(pAdapt, bOnUnbind);
3102#else
3103 Status = vboxNetFltWinMpDoDeinitialization(pAdapt);
3104#endif
3105 Assert(Status == NDIS_STATUS_SUCCESS);
3106
3107 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3108 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3109#ifndef VBOXNETADP
3110 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3111#endif
3112// /* paranoya */
3113// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3114//#ifndef VBOXNETADP
3115// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3116//#endif
3117
3118 vboxNetFltWinPtFiniPADAPT(pAdapt);
3119
3120 /* we're unbinding, make an unbind-related release */
3121 vboxNetFltRelease(pThis, false);
3122#else
3123 Status = vboxNetFltWinPtFiniUnbind(pAdapt);
3124 if(Status != NDIS_STATUS_SUCCESS)
3125 {
3126 AssertFailed();
3127 /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
3128 }
3129#endif
3130 }
3131 else
3132 {
3133 AssertBreakpoint();
3134#ifndef VBOXNETADP
3135 pAdapt->Status = NDIS_STATUS_FAILURE;
3136#endif
3137 if(!bOnUnbind)
3138 {
3139 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3140 }
3141 Status = NDIS_STATUS_FAILURE;
3142 }
3143 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3144 }
3145 else
3146 {
3147 AssertBreakpoint();
3148 Status = NDIS_STATUS_FAILURE;
3149 }
3150
3151 /* release for the retain we made before waining on the mutex */
3152 vboxNetFltRelease(pThis, false);
3153
3154 return Status;
3155}
3156
3157
3158/**
3159 * Checks if the host (not us) has put the adapter in promiscuous mode.
3160 *
3161 * @returns true if promiscuous, false if not.
3162 * @param pThis The instance.
3163 */
3164static bool vboxNetFltWinIsPromiscuous2(PVBOXNETFLTINS pThis)
3165{
3166#ifndef VBOXNETADP
3167 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3168 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3169 {
3170 bool bPromiscuous;
3171 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3172 return false;
3173
3174 bPromiscuous = (pAdapt->fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
3175 /*vboxNetFltWinIsPromiscuous(pAdapt);*/
3176
3177 vboxNetFltWinDereferenceAdapt(pAdapt);
3178 return bPromiscuous;
3179 }
3180 return false;
3181#else
3182 return true;
3183#endif
3184}
3185
3186/**
3187 * Worker for vboxNetFltWinAttachToInterface.
3188 *
3189 * @param pAttachInfo Structure for communicating with
3190 * vboxNetFltWinAttachToInterface.
3191 */
3192static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
3193{
3194 PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
3195 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
3196 int rc;
3197 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3198
3199 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3200
3201 /* to ensure we're not removed while we're here */
3202 vboxNetFltRetain(pThis, false);
3203
3204 rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
3205 if(RT_SUCCESS(rc))
3206 {
3207 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
3208 Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected);
3209 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3210#ifndef VBOXNETADP
3211 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3212#endif
3213// if(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3214//#ifndef VBOXNETADP
3215// && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
3216//#endif
3217// )
3218 if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected)
3219 {
3220
3221#ifndef VBOX_NETFLT_ONDEMAND_BIND
3222 if(pAttachInfo->fRediscovery)
3223 {
3224 /* rediscovery means adaptor bind is performed while intnet is already using it
3225 * i.e. adaptor was unbound while being used by intnet and now being bound back again */
3226 Assert(((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState)) == kVBoxNetFltInsState_Connected);
3227 }
3228#ifndef VBOXNETADP
3229 Status = vboxNetFltWinPtInitPADAPT(pAdapt, pAttachInfo->pCreateContext->pOurName);
3230#else
3231 Status = vboxNetFltWinPtInitPADAPT(pAdapt);
3232#endif
3233 if(Status == NDIS_STATUS_SUCCESS)
3234 {
3235 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connecting);
3236
3237#ifndef VBOXNETADP
3238 Status = vboxNetFltWinPtDoBinding(pAdapt, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
3239#else
3240 Status = vboxNetFltWinMpDoInitialization(pAdapt, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
3241#endif
3242 if (Status == NDIS_STATUS_SUCCESS)
3243 {
3244 if(pAttachInfo->fRediscovery || (Status = vboxNetFltWinMpReferenceControlDevice()) == NDIS_STATUS_SUCCESS)
3245 {
3246#ifndef VBOXNETADP
3247 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
3248#endif
3249 {
3250 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connected);
3251// Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
3252#ifndef VBOXNETADP
3253 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
3254#endif
3255// /* paranoya */
3256//// vboxNetFltWinSetAdaptState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
3257//#ifndef VBOXNETADP
3258// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
3259//#endif
3260
3261 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
3262
3263 /* 4. mark as connected */
3264 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
3265
3266 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
3267
3268 pAttachInfo->Status = VINF_SUCCESS;
3269 pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
3270
3271 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3272
3273 vboxNetFltRelease(pThis, false);
3274
3275 /* 5. Report MAC address, promiscuousness and GSO capabilities. */
3276 /** @todo Keep these up to date, esp. the promiscuous mode bit. */
3277 if (pThis->pSwitchPort)
3278 {
3279 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
3280 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
3281 vboxNetFltWinIsPromiscuous2(pThis));
3282 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
3283 INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
3284 /** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */
3285 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
3286 }
3287 return;
3288 }
3289 AssertBreakpoint();
3290
3291 if(!pAttachInfo->fRediscovery)
3292 {
3293 vboxNetFltWinMpDereferenceControlDevice();
3294 }
3295 }
3296 AssertBreakpoint();
3297#ifndef VBOXNETADP
3298 vboxNetFltWinPtDoUnbinding(pAdapt, true);
3299#else
3300 vboxNetFltWinMpDoDeinitialization(pAdapt);
3301#endif
3302 }
3303 AssertBreakpoint();
3304 vboxNetFltWinPtFiniPADAPT(pAdapt);
3305 }
3306 AssertBreakpoint();
3307 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3308 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
3309#ifndef VBOXNETADP
3310 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
3311#endif
3312// /* paranoya */
3313// vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3314//#ifndef VBOXNETADP
3315// vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3316//#endif
3317 }
3318 AssertBreakpoint();
3319
3320#else /* VBOX_NETFLT_ONDEMAND_BIND */
3321 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3322
3323 Status = vboxNetFltWinPtInitBind(pAdapt);
3324 if (Status != NDIS_STATUS_SUCCESS)
3325 {
3326 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3327 break;
3328 }
3329
3330 Status = vboxNetFltWinGetMacAddress(pAdapt, &pThis->u.s.MacAddr);
3331 if (Status != NDIS_STATUS_SUCCESS)
3332 {
3333 vboxNetFltWinPtFiniUnbind(pAdapt);
3334 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3335 break;
3336 }
3337#endif /* VBOX_NETFLT_ONDEMAND_BIND */
3338
3339
3340 pAttachInfo->Status = VERR_GENERAL_FAILURE;
3341 pAttachInfo->pCreateContext->Status = Status;
3342 RTSemMutexRelease(pThis->u.s.hAdaptMutex);
3343 }
3344 else
3345 {
3346 AssertBreakpoint();
3347 pAttachInfo->Status = rc;
3348 }
3349
3350 vboxNetFltRelease(pThis, false);
3351
3352 return;
3353}
3354
3355/**
3356 * Common code for vboxNetFltOsInitInstance and
3357 * vboxNetFltOsMaybeRediscovered.
3358 *
3359 * @returns IPRT status code.
3360 * @param pThis The instance.
3361 * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
3362 * false if it's vboxNetFltOsInitInstance.
3363 */
3364static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
3365{
3366 ATTACH_INFO Info;
3367 Info.pNetFltIf = pThis;
3368 Info.fRediscovery = fRediscovery;
3369 Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
3370
3371
3372#ifdef VBOX_NETFLT_ONDEMAND_BIND
3373 /* packet queue worker thread gets created on attach interface, need to do it via job at passive level */
3374 vboxNetFltWinJobSynchExecAtPassive((JOB_ROUTINE)vboxNetFltWinAttachToInterfaceWorker, &Info);
3375#else
3376 vboxNetFltWinAttachToInterfaceWorker(&Info);
3377#endif
3378 return Info.Status;
3379}
3380
3381/*
3382 *
3383 * The OS specific interface definition
3384 *
3385 */
3386
3387
3388bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
3389{
3390 /* AttachToInterface true if disconnected */
3391 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
3392}
3393
3394int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
3395{
3396 int rc = VINF_SUCCESS;
3397 uint32_t cRefs = 0;
3398 PADAPT pAdapt;
3399#if !defined(VBOXNETADP) && !defined(VBOX_NETFLT_ONDEMAND_BIND)
3400 if(fDst & INTNETTRUNKDIR_WIRE)
3401 {
3402 cRefs++;
3403 }
3404 if(fDst & INTNETTRUNKDIR_HOST)
3405 {
3406 cRefs++;
3407 }
3408#else
3409 if(fDst & INTNETTRUNKDIR_WIRE || fDst & INTNETTRUNKDIR_HOST)
3410 {
3411 cRefs = 1;
3412 }
3413#endif
3414
3415 AssertReturn(cRefs, VINF_SUCCESS);
3416
3417 pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3418
3419 if(!vboxNetFltWinIncReferenceAdapt(pAdapt, cRefs))
3420 {
3421 return VERR_GENERAL_FAILURE;
3422 }
3423#ifndef VBOXNETADP
3424 if ((fDst & INTNETTRUNKDIR_WIRE)
3425# ifdef VBOX_NETFLT_ONDEMAND_BIND
3426 || (fDst & INTNETTRUNKDIR_HOST)
3427# endif
3428 )
3429 {
3430 PNDIS_PACKET pPacket;
3431
3432 pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3433 true /*fToWire*/, true /*fCopyMemory*/);
3434
3435 if (pPacket)
3436 {
3437 NDIS_STATUS fStatus;
3438
3439#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3440 vboxNetFltWinLbPutSendPacket(pAdapt, pPacket, true /* bFromIntNet */);
3441#endif
3442 NdisSend(&fStatus, pAdapt->hBindingHandle, pPacket);
3443 if (fStatus != NDIS_STATUS_PENDING)
3444 {
3445#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
3446 /* the status is NOT pending, complete the packet */
3447 bool bTmp = vboxNetFltWinLbRemoveSendPacket(pAdapt, pPacket);
3448 Assert(bTmp);
3449#endif
3450 if(!NT_SUCCESS(fStatus))
3451 {
3452 /* TODO: convert status to VERR_xxx */
3453 rc = VERR_GENERAL_FAILURE;
3454 }
3455
3456 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
3457 }
3458 else
3459 {
3460 /* pending, dereference on packet complete */
3461 cRefs--;
3462 }
3463 }
3464 else
3465 {
3466 AssertFailed();
3467 rc = VERR_NO_MEMORY;
3468 }
3469 }
3470#endif
3471#ifndef VBOX_NETFLT_ONDEMAND_BIND
3472#ifndef VBOXNETADP
3473 if (fDst & INTNETTRUNKDIR_HOST)
3474#else
3475 if(cRefs)
3476#endif
3477 {
3478 PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
3479 false /*fToWire*/, true /*fCopyMemory*/);
3480 if (pPacket)
3481 {
3482 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pPacket, 1);
3483 cRefs--;
3484#ifdef VBOXNETADP
3485 STATISTIC_INCREASE(pAdapt->cRxSuccess);
3486#endif
3487 }
3488 else
3489 {
3490 AssertFailed();
3491#ifdef VBOXNETADP
3492 STATISTIC_INCREASE(pAdapt->cRxError);
3493#endif
3494 rc = VERR_NO_MEMORY;
3495 }
3496 }
3497
3498 Assert(cRefs <= 2);
3499
3500 if(cRefs)
3501 {
3502 vboxNetFltWinDecReferenceAdapt(pAdapt, cRefs);
3503 }
3504#endif
3505
3506 return rc;
3507}
3508
3509void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
3510{
3511#ifndef VBOXNETADP
3512 NDIS_STATUS Status;
3513#endif
3514 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3515
3516 /* we first wait for all pending ops to complete
3517 * this might include all packets queued for processing */
3518 for(;;)
3519 {
3520 if(fActive)
3521 {
3522 if(!pThis->u.s.cModePassThruRefs)
3523 {
3524 break;
3525 }
3526 }
3527 else
3528 {
3529 if(!pThis->u.s.cModeNetFltRefs)
3530 {
3531 break;
3532 }
3533 }
3534 vboxNetFltWinSleep(2);
3535 }
3536
3537 if(!vboxNetFltWinReferenceAdapt(pAdapt))
3538 return;
3539#ifndef VBOXNETADP
3540
3541 /* the packets put to ReceiveQueue Array are currently not holding the references,
3542 * simply need to flush them */
3543 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false /*fReturn*/);
3544
3545 if(fActive)
3546 {
3547#ifdef DEBUG_misha
3548 NDIS_PHYSICAL_MEDIUM PhMedium;
3549 bool bPromiscSupported;
3550
3551 Status = vboxNetFltWinQueryPhysicalMedium(pAdapt, &PhMedium);
3552 if(Status != NDIS_STATUS_SUCCESS)
3553 {
3554
3555 DBGPRINT(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3556 Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
3557 if(Status != NDIS_STATUS_NOT_SUPPORTED)
3558 {
3559 LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
3560 }
3561 PhMedium = NdisPhysicalMediumUnspecified;
3562 }
3563 else
3564 {
3565 DBGPRINT(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
3566 }
3567
3568 bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
3569 || PhMedium == NdisPhysicalMediumWirelessLan
3570 || PhMedium == NdisPhysicalMediumNative802_11
3571 || PhMedium == NdisPhysicalMediumBluetooth
3572 /*|| PhMedium == NdisPhysicalMediumWiMax */
3573 ));
3574
3575 Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
3576#endif
3577 }
3578
3579 if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
3580 {
3581 Status = vboxNetFltWinSetPromiscuous(pAdapt, fActive);
3582 if(Status != NDIS_STATUS_SUCCESS)
3583 {
3584 DBGPRINT(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3585 AssertFailed();
3586 LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
3587 }
3588 }
3589#else
3590# ifdef VBOXNETADP_REPORT_DISCONNECTED
3591 if(fActive)
3592 {
3593 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3594 NDIS_STATUS_MEDIA_CONNECT,
3595 (PVOID)NULL,
3596 0);
3597 }
3598 else
3599 {
3600 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3601 NDIS_STATUS_MEDIA_DISCONNECT,
3602 (PVOID)NULL,
3603 0);
3604 }
3605#else
3606 if(fActive)
3607 {
3608 /* indicate status change to make the ip settings be re-picked for dhcp */
3609 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3610 NDIS_STATUS_MEDIA_DISCONNECT,
3611 (PVOID)NULL,
3612 0);
3613
3614 NdisMIndicateStatus(pAdapt->hMiniportHandle,
3615 NDIS_STATUS_MEDIA_CONNECT,
3616 (PVOID)NULL,
3617 0);
3618 }
3619# endif
3620#endif
3621 vboxNetFltWinDereferenceAdapt(pAdapt);
3622
3623 return;
3624}
3625
3626int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
3627{
3628 NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
3629 return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3630}
3631
3632static void vboxNetFltWinConnectItWorker(PWORKER_INFO pInfo)
3633{
3634 NDIS_STATUS Status;
3635 PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
3636 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
3637
3638 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
3639
3640 /* this is not a rediscovery, initialize Mac cache */
3641 if(vboxNetFltWinReferenceAdapt(pAdapt))
3642 {
3643#ifndef VBOXNETADP
3644 Status = vboxNetFltWinGetMacAddress(pAdapt, &pInstance->u.s.MacAddr);
3645 if (Status == NDIS_STATUS_SUCCESS)
3646#endif
3647 {
3648 Status = vboxNetFltWinQuInitPacketQueue(pInstance);
3649 if(Status == NDIS_STATUS_SUCCESS)
3650 {
3651 pInfo->Status = VINF_SUCCESS;
3652 }
3653 else
3654 {
3655 pInfo->Status = VERR_GENERAL_FAILURE;
3656 }
3657 }
3658#ifndef VBOXNETADP
3659 else
3660 {
3661 pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
3662 }
3663#endif
3664
3665 vboxNetFltWinDereferenceAdapt(pAdapt);
3666 }
3667 else
3668 {
3669 pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
3670 }
3671}
3672
3673static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
3674{
3675 WORKER_INFO Info;
3676 Info.pNetFltIf = pThis;
3677
3678 vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
3679
3680 return Info.Status;
3681}
3682
3683int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
3684{
3685 return vboxNetFltWinConnectIt(pThis);
3686}
3687
3688void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
3689{
3690 vboxNetFltWinDeleteInstance(pThis);
3691}
3692
3693int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
3694{
3695 int rc = RTSemMutexCreate(&pThis->u.s.hAdaptMutex);
3696 if (RT_SUCCESS(rc))
3697 {
3698 rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
3699 if (RT_SUCCESS(rc))
3700 {
3701 return rc;
3702 }
3703 RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
3704 }
3705 return rc;
3706}
3707
3708int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
3709{
3710 PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
3711 pThis->u.s.cModeNetFltRefs = 0;
3712 pThis->u.s.cModePassThruRefs = 0;
3713 vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
3714 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
3715#ifndef VBOXNETADP
3716 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
3717#endif
3718 return VINF_SUCCESS;
3719}
3720
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