VirtualBox

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

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

netflt/win: alternative loopback handling mechanism (disabled for now)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette