VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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