VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp@ 63549

Last change on this file since 63549 was 63549, checked in by vboxsync, 8 years ago

scm cleanups

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