VirtualBox

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

Last change on this file since 48435 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

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