VirtualBox

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

Last change on this file since 73097 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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