VirtualBox

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

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

export vboxnetflt for Windows to OSE

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

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