VirtualBox

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

Last change on this file since 24026 was 23927, checked in by vboxsync, 16 years ago

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.6 KB
Line 
1/* $Id: VBoxNetFltPt-win.c 23927 2009-10-21 09:18:34Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Protocol edge of ndis filter driver
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
28#ifdef VBOXNETADP
29# error "No protocol edge"
30#endif
31
32/** protocol handle */
33static NDIS_HANDLE g_hProtHandle = NULL;
34/** medium array used while opening underlying adaprot
35 * we are actually binding to NdisMedium802_3 and NdisMediumWan
36 * as specified in VBoxNetFlt.inf:
37 * HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet, wan" */
38static NDIS_MEDIUM g_aMediumArray[] =
39 {
40 /* Ethernet */
41 NdisMedium802_3,
42 /* Wan */
43 NdisMediumWan
44 };
45
46/**
47 * performs binding to the given adapter
48 */
49#ifdef VBOX_NETFLT_ONDEMAND_BIND
50DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt)
51#else
52DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName, IN PNDIS_STRING pBindToDeviceName)
53#endif
54{
55 UINT MediumIndex;
56 NDIS_STATUS Status, Sts;
57
58 Assert(pAdapt->PTState.PowerState == NdisDeviceStateD3);
59 Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
60 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
61
62 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initializing);
63
64 do
65 {
66// NDIS_STATUS TmpStatus;
67 /* copy the bind to dev name to our buffer */
68#ifdef VBOX_NETFLT_ONDEMAND_BIND
69 NDIS_STRING BindToDeviceName;
70 PNDIS_STRING pBindToDeviceName;
71 PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
72 PWSTR pUnicode;
73 ULONG cbUnicode;
74 ANSI_STRING AnsiStr;
75
76 /* most Rtlxx functions we are using here require this */
77 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
78
79 RtlInitAnsiString(&AnsiStr, pThis->szName);
80 cbUnicode = RtlAnsiStringToUnicodeSize(&AnsiStr);
81
82 pUnicode = alloca(cbUnicode);
83 BindToDeviceName.Buffer = pUnicode;
84 BindToDeviceName.MaximumLength = (USHORT)cbUnicode;
85
86 Status = RtlAnsiStringToUnicodeString(&BindToDeviceName, &AnsiStr, FALSE);
87 if(!NT_SUCCESS(Status))
88 {
89 Assert(0);
90 break;
91 }
92
93 pBindToDeviceName = &BindToDeviceName;
94#else
95 Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
96 if(Status != NDIS_STATUS_SUCCESS)
97 {
98 Assert(0);
99 break;
100 }
101#endif
102
103 vboxNetFltWinSetPowerState(&pAdapt->PTState, NdisDeviceStateD0);
104 pAdapt->Status = NDIS_STATUS_SUCCESS;
105
106 NdisResetEvent(&pAdapt->hEvent);
107
108 /*
109 * Now open the adapter below and complete the initialization
110 */
111 NdisOpenAdapter(&Status,
112 &Sts,
113 &pAdapt->hBindingHandle,
114 &MediumIndex,
115 g_aMediumArray,
116 sizeof(g_aMediumArray)/sizeof(NDIS_MEDIUM),
117 g_hProtHandle,
118 pAdapt,
119 pBindToDeviceName,
120 0,
121 NULL);
122
123 if (Status == NDIS_STATUS_PENDING)
124 {
125 NdisWaitEvent(&pAdapt->hEvent, 0);
126 Status = pAdapt->Status;
127 }
128
129 Assert(Status == NDIS_STATUS_SUCCESS);
130 if(Status != NDIS_STATUS_SUCCESS)
131 {
132 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
133 pAdapt->hBindingHandle = NULL;
134 LogRel(("NdisOpenAdapter failed, Status (0c%x)", Status));
135 break;
136 }
137
138 Assert(pAdapt->hBindingHandle);
139
140 pAdapt->Medium = g_aMediumArray[MediumIndex];
141 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
142
143#ifndef VBOX_NETFLT_ONDEMAND_BIND
144 Status = vboxNetFltWinMpInitializeDevideInstance(pAdapt);
145 if (Status != NDIS_STATUS_SUCCESS)
146 {
147 Log(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n",
148 pAdapt, Status));
149
150 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitializing);
151 vboxNetFltWinPtCloseAdapter(pAdapt, &Sts);
152 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
153 break;
154 }
155#endif
156 } while(0);
157
158 return Status;
159}
160
161/**
162 * Called by NDIS to bind to a miniport below.
163 * @param Status - Return status of bind here.
164 * @param BindContext - Can be passed to NdisCompleteBindAdapter if this call is pended.
165 * @param DeviceName - Device name to bind to. This is passed to NdisOpenAdapter.
166 * @param SystemSpecific1 - Can be passed to NdisOpenProtocolConfiguration to read per-binding information
167 * @paran SystemSpecific2 - Unused
168 * @return NDIS_STATUS_PENDING if this call is pended. In this case call NdisCompleteBindAdapter to complete.
169 * Anything else Completes this call synchronously */
170static VOID
171vboxNetFltWinPtBindAdapter(
172 OUT PNDIS_STATUS pStatus,
173 IN NDIS_HANDLE BindContext,
174 IN PNDIS_STRING pDeviceName,
175 IN PVOID SystemSpecific1,
176 IN PVOID SystemSpecific2
177 )
178{
179#ifdef VBOX_NETFLT_ONDEMAND_BIND
180 /* we initiate the binding ourselves by calling NdisOpenAdapter */
181 LogFlow(("==> Protocol BindAdapter\n"));
182 Assert(0);
183 *pStatus = NDIS_STATUS_OPEN_FAILED;
184 LogFlow(("<== Protocol BindAdapter\n"));
185 return;
186#else
187 NDIS_HANDLE ConfigHandle = NULL;
188 PNDIS_CONFIGURATION_PARAMETER Param;
189 NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
190 PADAPT pAdapt = NULL;
191
192 UNREFERENCED_PARAMETER(BindContext);
193 UNREFERENCED_PARAMETER(SystemSpecific2);
194
195 LogFlow(("==> Protocol BindAdapter\n"));
196
197 do
198 {
199 /* Access the configuration section for our binding-specific
200 * parameters. */
201
202 NdisOpenProtocolConfiguration(pStatus,
203 &ConfigHandle,
204 (PNDIS_STRING)SystemSpecific1);
205
206 if (*pStatus != NDIS_STATUS_SUCCESS)
207 {
208 break;
209 }
210
211 /* Read the "UpperBindings" reserved key that contains a list
212 * of device names representing our miniport instances corresponding
213 * to this lower binding. Since this is a 1:1 IM driver, this key
214 * contains exactly one name.
215 *
216 * If we want to implement a N:1 mux driver (N adapter instances
217 * over a single lower binding), then UpperBindings will be a
218 * MULTI_SZ containing a list of device names - we would loop through
219 * this list, calling NdisIMInitializeDeviceInstanceEx once for
220 * each name in it. */
221
222 NdisReadConfiguration(pStatus,
223 &Param,
224 ConfigHandle,
225 &DeviceStr,
226 NdisParameterString);
227 if (*pStatus != NDIS_STATUS_SUCCESS)
228 {
229 break;
230 }
231
232 *pStatus = vboxNetFltWinPtInitBind(&pAdapt, &Param->ParameterData.StringData, pDeviceName);
233 if (*pStatus != NDIS_STATUS_SUCCESS)
234 {
235 break;
236 }
237 } while(FALSE);
238
239 /*
240 * Close the configuration handle now - see comments above with
241 * the call to NdisIMInitializeDeviceInstanceEx.
242 */
243 if (ConfigHandle != NULL)
244 {
245 NdisCloseConfiguration(ConfigHandle);
246 }
247
248 LogFlow(("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *pStatus));
249#endif
250}
251
252/**
253 * Completion routine for NdisOpenAdapter issued from within the vboxNetFltWinPtBindAdapter. Simply
254 * unblock the caller.
255 *
256 * @param ProtocolBindingContext Pointer to the adapter
257 * @param Status Status of the NdisOpenAdapter call
258 * @param OpenErrorStatus Secondary status(ignored by us).
259 * @return None
260 * */
261static VOID
262vboxNetFltWinPtOpenAdapterComplete(
263 IN NDIS_HANDLE ProtocolBindingContext,
264 IN NDIS_STATUS Status,
265 IN NDIS_STATUS OpenErrorStatus
266 )
267{
268 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
269
270 UNREFERENCED_PARAMETER(OpenErrorStatus);
271
272 LogFlow(("==> vboxNetFltWinPtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
273 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
274 {
275 pAdapt->Status = Status;
276 }
277 NdisSetEvent(&pAdapt->hEvent);
278}
279
280DECLHIDDEN(NDIS_STATUS)
281vboxNetFltWinPtDoUnbinding(PADAPT pAdapt, bool bOnUnbind)
282{
283 NDIS_STATUS Status;
284#ifndef VBOX_NETFLT_ONDEMAND_BIND
285 PNDIS_PACKET PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
286 ULONG NumberOfPackets = 0, i;
287 BOOLEAN CompleteRequest = FALSE;
288 BOOLEAN ReturnPackets = FALSE;
289 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
290 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
291 uint64_t NanoTS = RTTimeSystemNanoTS();
292#endif
293
294 LogFlow(("==> vboxNetFltWinPtDoUnbinding: Adapt %p\n", pAdapt));
295
296 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
297
298#ifndef VBOX_NETFLT_ONDEMAND_BIND
299 Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
300 /*
301 * Set the flag that the miniport below is unbinding, so the request handlers will
302 * fail any request comming later
303 */
304 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
305
306 ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
307 ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
308 ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
309
310// pAdapt->PTState.DeviceState = NdisDeviceStateD3;
311// pAdapt->MPState.DeviceState = NdisDeviceStateD3;
312 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitializing);
313 if(!bOnUnbind)
314 {
315 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing);
316 }
317
318 if (pAdapt->bQueuedRequest == TRUE)
319 {
320 pAdapt->bQueuedRequest = FALSE;
321 CompleteRequest = TRUE;
322 }
323 if (pAdapt->cReceivedPacketCount > 0)
324 {
325
326 NdisMoveMemory(PacketArray,
327 pAdapt->aReceivedPackets,
328 pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
329
330 NumberOfPackets = pAdapt->cReceivedPacketCount;
331
332 pAdapt->cReceivedPacketCount = 0;
333 ReturnPackets = TRUE;
334 }
335
336
337 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
338
339 if (CompleteRequest == TRUE)
340 {
341 vboxNetFltWinPtRequestComplete(pAdapt,
342 &pAdapt->Request,
343 NDIS_STATUS_FAILURE );
344
345 }
346 if (ReturnPackets == TRUE)
347 {
348 for (i = 0; i < NumberOfPackets; i++)
349 {
350 vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
351 }
352 }
353
354 vboxNetFltWinWaitDereference(&pAdapt->MPState);
355
356 vboxNetFltWinWaitDereference(&pAdapt->PTState);
357
358 while (ASMAtomicUoReadBool((volatile bool *)&pAdapt->bOutstandingRequests))
359 {
360 /*
361 * sleep till outstanding requests complete
362 */
363 vboxNetFltWinSleep(2);
364 }
365
366 if(!bOnUnbind || !vboxNetFltWinMpDeInitializeDevideInstance(pAdapt, &Status))
367#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
368 {
369 /*
370 * We need to do some work here.
371 * Close the binding below us
372 * and release the memory allocated.
373 */
374 vboxNetFltWinPtCloseAdapter(pAdapt, &Status);
375 vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
376
377 if(!bOnUnbind)
378 {
379 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitializing);
380 vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
381 }
382 else
383 {
384 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
385 }
386 }
387 else
388 {
389 Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
390 }
391
392 LogFlow(("<== vboxNetFltWinPtDoUnbinding: Adapt %p\n", pAdapt));
393
394 return Status;
395}
396
397/**
398 * Called by NDIS when we are required to unbind to the adapter below.
399 * This functions shares functionality with the miniport's HaltHandler.
400 * The code should ensure that NdisCloseAdapter and NdisFreeMemory is called
401 * only once between the two functions
402 *
403 * @param Status Placeholder for return status
404 * @param ProtocolBindingContext Pointer to the adapter structure
405 * @param UnbindContext Context for NdisUnbindComplete() if this pends
406 * @return NONE */
407static VOID
408vboxNetFltWinPtUnbindAdapter(
409 OUT PNDIS_STATUS pStatus,
410 IN NDIS_HANDLE ProtocolBindingContext,
411 IN NDIS_HANDLE UnbindContext
412 )
413{
414 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
415 PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
416
417 LogFlow(("==> vboxNetFltWinPtUnbindAdapter: Adapt %p\n", pAdapt));
418
419 *pStatus = vboxNetFltWinDetachFromInterface(pAdapt, true);
420 Assert(*pStatus == NDIS_STATUS_SUCCESS);
421
422 LogFlow(("<== vboxNetFltWinPtUnbindAdapter: Adapt %p\n", pAdapt));
423}
424
425/**
426 * protocol unload handler
427 */
428static VOID
429vboxNetFltWinPtUnloadProtocol(
430 VOID
431)
432{
433 vboxNetFltWinPtDeregister();
434 LogFlow(("vboxNetFltWinPtUnloadProtocol: done!\n"));
435}
436
437
438/**
439 * Completion for the CloseAdapter call.
440 *
441 * @param ProtocolBindingContext Pointer to the adapter structure
442 * @param Status Completion status
443 * @return None */
444static VOID
445vboxNetFltWinPtCloseAdapterComplete(
446 IN NDIS_HANDLE ProtocolBindingContext,
447 IN NDIS_STATUS Status
448 )
449{
450 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
451
452 LogFlow(("CloseAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
453 if(pAdapt->Status == NDIS_STATUS_SUCCESS)
454 {
455 pAdapt->Status = Status;
456 }
457 NdisSetEvent(&pAdapt->hEvent);
458}
459
460
461/**
462 * Completion for the reset.
463 *
464 * @param ProtocolBindingContext Pointer to the adapter structure
465 * @param Status Completion status
466 * @return None */
467static VOID
468vboxNetFltWinPtResetComplete(
469 IN NDIS_HANDLE ProtocolBindingContext,
470 IN NDIS_STATUS Status
471 )
472{
473
474 UNREFERENCED_PARAMETER(ProtocolBindingContext);
475 UNREFERENCED_PARAMETER(Status);
476 /*
477 * We never issue a reset, so we should not be here.
478 */
479 Assert(0);
480}
481
482/**
483 * Completion handler for the previously posted request. All OIDS
484 * are completed by and sent to the same miniport that they were requested for.
485 * If Oid == OID_PNP_QUERY_POWER then the data structure needs to returned with all entries =
486 * NdisDeviceStateUnspecified
487 * @param ProtocolBindingContext Pointer to the adapter structure
488 * @param NdisRequest The posted request
489 * @param Status Completion status
490 * @return None
491 *
492 */
493DECLHIDDEN(VOID)
494vboxNetFltWinPtRequestComplete(
495 IN NDIS_HANDLE ProtocolBindingContext,
496 IN PNDIS_REQUEST NdisRequest,
497 IN NDIS_STATUS Status
498 )
499{
500 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
501 PNDIS_REQUEST pSynchRequest = pAdapt->pSynchRequest;
502#ifndef VBOX_NETFLT_ONDEMAND_BIND
503 NDIS_OID Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;
504#endif
505
506 if(pSynchRequest == NdisRequest)
507 {
508 /* assynchronous completion of our synch request */
509
510 /*1.set the status */
511 pAdapt->fSynchCompletionStatus = Status;
512
513 /* 2. set event */
514 KeSetEvent(&pAdapt->hSynchCompletionEvent, 0, FALSE);
515
516 /* 3. return; */
517 return;
518 }
519#ifdef VBOX_NETFLT_ONDEMAND_BIND
520 Assert(0);
521 return;
522#else
523
524 /*
525 * Since our request is not outstanding anymore
526 */
527 Assert(pAdapt->bOutstandingRequests == TRUE);
528
529 pAdapt->bOutstandingRequests = FALSE;
530
531 /*
532 * Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
533 */
534 switch (NdisRequest->RequestType)
535 {
536 case NdisRequestQueryInformation:
537
538 /*
539 * We never pass OID_PNP_QUERY_POWER down.
540 */
541 Assert(Oid != OID_PNP_QUERY_POWER);
542
543 if ((Oid == OID_PNP_CAPABILITIES) && (Status == NDIS_STATUS_SUCCESS))
544 {
545 vboxNetFltWinMpQueryPNPCapabilities(pAdapt, &Status);
546 }
547 *pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
548 *pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
549
550 if ((Oid == OID_GEN_MAC_OPTIONS) && (Status == NDIS_STATUS_SUCCESS))
551 {
552 /* save mac options for adaptor below us to use it with the NdisCopyLookaheadData when our ProtocolReceive is called */
553 pAdapt->fMacOptions = *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
554#ifndef VBOX_LOOPBACK_USEFLAGS
555 /*
556 * Remove the no-loopback bit from mac-options. In essence we are
557 * telling NDIS that we can handle loopback. We don't, but the
558 * interface below us does. If we do not do this, then loopback
559 * processing happens both below us and above us. This is wasteful
560 * at best and if Netmon is running, it will see multiple copies
561 * of loopback packets when sniffing above us.
562 *
563 * Only the lowest miniport is a stack of layered miniports should
564 * ever report this bit set to NDIS.
565 */
566 *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
567#else
568 /* we have to catch loopbacks from the underlying driver, so no duplications will occur,
569 * just indicate NDIS to handle loopbacks for the packets coming from the protocol */
570 *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer |= NDIS_MAC_OPTION_NO_LOOPBACK;
571#endif
572 }
573 if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
574 {
575 /* we're here _ONLY_ in the passthru mode */
576 Assert(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_PASSTHRU);
577 if(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_PASSTHRU)
578 {
579 PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
580 Assert(!pNetFltIf->fActive);
581 vboxNetFltWinDereferenceModePassThru(pNetFltIf);
582 vboxNetFltWinDereferenceAdapt(pAdapt);
583 }
584
585 if(Status == NDIS_STATUS_SUCCESS)
586 {
587 /* the filter request is issued below only in case netflt is not active,
588 * simply update the cache here */
589 /* cache the filter used by upper protocols */
590 pAdapt->fUpperProtocolSetFilter = *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
591 pAdapt->bUpperProtSetFilterInitialized = true;
592 }
593 }
594
595
596 NdisMQueryInformationComplete(pAdapt->hMiniportHandle,
597 Status);
598 break;
599
600 case NdisRequestSetInformation:
601
602 Assert( Oid != OID_PNP_SET_POWER);
603
604 if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
605 {
606 PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
607 Assert(Status == NDIS_STATUS_SUCCESS);
608 if(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_NETFLT)
609 {
610 Assert(pNetFltIf->fActive);
611 if(Status == NDIS_STATUS_SUCCESS)
612 {
613 pAdapt->fOurSetFilter = *((PULONG)pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer);
614 Assert(pAdapt->fOurSetFilter == NDIS_PACKET_TYPE_PROMISCUOUS);
615 }
616 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
617 vboxNetFltWinDereferenceAdapt(pAdapt);
618 pAdapt->fProcessingPacketFilter = 0;
619 }
620 else if(pAdapt->fProcessingPacketFilter == VBOXNETFLT_PFP_PASSTHRU)
621 {
622 Assert(!pNetFltIf->fActive);
623
624 if(Status == NDIS_STATUS_SUCCESS)
625 {
626 /* the request was issued when the netflt was not active, simply update the cache here */
627 pAdapt->fUpperProtocolSetFilter = *((PULONG)pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer);
628 pAdapt->bUpperProtSetFilterInitialized = true;
629 }
630 vboxNetFltWinDereferenceModePassThru(pNetFltIf);
631 vboxNetFltWinDereferenceAdapt(pAdapt);
632 pAdapt->fProcessingPacketFilter = 0;
633 }
634 }
635
636
637 *pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
638 *pAdapt->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
639 NdisMSetInformationComplete(pAdapt->hMiniportHandle,
640 Status);
641 break;
642
643 default:
644 Assert(0);
645 break;
646 }
647#endif
648}
649
650/**
651 * Status handler for the lower-edge(protocol).
652 *
653 * @param ProtocolBindingContext Pointer to the adapter structure
654 * @param GeneralStatus Status code
655 * @param StatusBuffer Status buffer
656 * @param StatusBufferSize Size of the status buffer
657 * @return None
658 */
659static VOID
660vboxNetFltWinPtStatus(
661 IN NDIS_HANDLE ProtocolBindingContext,
662 IN NDIS_STATUS GeneralStatus,
663 IN PVOID StatusBuffer,
664 IN UINT StatusBufferSize
665 )
666{
667#ifndef VBOX_NETFLT_ONDEMAND_BIND
668 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
669
670 /*
671 * Pass up this indication only if the upper edge miniport is initialized
672 * and powered on. Also ignore indications that might be sent by the lower
673 * miniport when it isn't at D0.
674 */
675 if (vboxNetFltWinReferenceAdapt(pAdapt))
676 {
677 Assert(pAdapt->hMiniportHandle);
678
679 if ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
680 (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT))
681 {
682
683 pAdapt->LastIndicatedStatus = GeneralStatus;
684 }
685 NdisMIndicateStatus(pAdapt->hMiniportHandle,
686 GeneralStatus,
687 StatusBuffer,
688 StatusBufferSize);
689
690 vboxNetFltWinDereferenceAdapt(pAdapt);
691 }
692 /*
693 * Save the last indicated media status
694 */
695 else
696 {
697 if ((pAdapt->hMiniportHandle != NULL) &&
698 ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
699 (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT)))
700 {
701 pAdapt->LatestUnIndicateStatus = GeneralStatus;
702 }
703 }
704#endif
705}
706
707/**
708 * status complete handler
709 */
710static VOID
711vboxNetFltWinPtStatusComplete(
712 IN NDIS_HANDLE ProtocolBindingContext
713 )
714{
715#ifndef VBOX_NETFLT_ONDEMAND_BIND
716 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
717
718 /*
719 * Pass up this indication only if the upper edge miniport is initialized
720 * and powered on. Also ignore indications that might be sent by the lower
721 * miniport when it isn't at D0.
722 */
723 if (vboxNetFltWinReferenceAdapt(pAdapt))
724 {
725 NdisMIndicateStatusComplete(pAdapt->hMiniportHandle);
726
727 vboxNetFltWinDereferenceAdapt(pAdapt);
728 }
729#endif
730}
731
732/**
733 * Called by NDIS when the miniport below had completed a send. We should
734 * complete the corresponding upper-edge send this represents.
735 *
736 * @param ProtocolBindingContext - Points to ADAPT structure
737 * @param Packet - Low level packet being completed
738 * @param Status - status of send
739 * @return None
740 */
741static VOID
742vboxNetFltWinPtSendComplete(
743 IN NDIS_HANDLE ProtocolBindingContext,
744 IN PNDIS_PACKET Packet,
745 IN NDIS_STATUS Status
746 )
747{
748 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
749 PNDIS_PACKET Pkt;
750
751 {
752 PSEND_RSVD SendRsvd;
753
754#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
755 /* @todo: for optimization we could check only for netflt-mode packets
756 * do it for all for now */
757 vboxNetFltWinLbRemoveSendPacket(pAdapt, Packet);
758#endif
759// Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
760
761 SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
762 Pkt = SendRsvd->pOriginalPkt;
763
764#ifndef VBOX_NETFLT_ONDEMAND_BIND
765 if(Pkt)
766 {
767#ifndef WIN9X
768 NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
769#endif
770 NdisFreePacket(Packet);
771
772 /* the ptk was posted from the upperlying protocol */
773 NdisMSendComplete(pAdapt->hMiniportHandle,
774 Pkt,
775 Status);
776 }
777 else
778#else
779 /* TODO: should change the PSEND_RSVD structure as we no nolnger need to handle original packets
780 * because all packets are originated by us */
781 Assert(!Pkt);
782#endif
783 {
784 /* if the ptk is zerro - the ptk was originated by netFlt send/receive
785 * need to free packet buffers */
786 PVOID pBufToFree = SendRsvd->pBufToFree;
787
788 vboxNetFltWinFreeSGNdisPacket(Packet, !pBufToFree);
789 if(pBufToFree)
790 {
791 vboxNetFltWinMemFree(pBufToFree);
792 }
793 }
794 }
795
796 vboxNetFltWinDereferenceAdapt(pAdapt);
797}
798
799#ifndef VBOX_NETFLT_ONDEMAND_BIND
800
801/**
802 * removes searches for the packet in the list and removes it if found
803 * @return true if the packet was found and removed, false - otherwise
804 */
805static bool vboxNetFltWinRemovePacketFromList(PINTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket)
806{
807 PTRANSFERDATA_RSVD pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->u.TransferDataRsvd;
808 return vboxNetFltWinInterlockedSearchListEntry(pList, &pTDR->ListEntry,
809 true /* remove*/);
810}
811
812/**
813 * puts the packet to the tail of the list
814 */
815static void vboxNetFltWinPutPacketToList(PINTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket, PNDIS_BUFFER pOrigBuffer)
816{
817 PTRANSFERDATA_RSVD pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->u.TransferDataRsvd;
818 pTDR->pOriginalBuffer = pOrigBuffer;
819 vboxNetFltWinInterlockedPutTail(pList, &pTDR->ListEntry);
820}
821
822/**
823 * This is to queue the received packets and indicates them up if the given Packet
824 * status is NDIS_STATUS_RESOURCES, or the array is full.
825 *
826 * @param pAdapt - Pointer to the adpater structure.
827 * @param Packet - Pointer to the indicated packet.
828 * @param Indicate - Do the indication now.
829 * @return NONE
830 */
831static VOID
832vboxNetFltWinPtQueueReceivedPacket(
833 IN PADAPT pAdapt,
834 IN PNDIS_PACKET Packet,
835 IN BOOLEAN DoIndicate
836 )
837{
838 PNDIS_PACKET PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
839 ULONG NumberOfPackets = 0, i;
840 bool bReturn = false;
841 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
842 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
843
844 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
845 do{
846 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
847
848 Assert(pAdapt->cReceivedPacketCount < MAX_RECEIVE_PACKET_ARRAY_SIZE);
849
850 /*
851 * pAdapt->ReceviePacketCount must be less than MAX_RECEIVE_PACKET_ARRAY_SIZE because
852 * the thread which held the pVElan->Lock before should already indicate the packet(s)
853 * up if pAdapt->ReceviePacketCount == MAX_RECEIVE_PACKET_ARRAY_SIZE.
854 */
855 pAdapt->aReceivedPackets[pAdapt->cReceivedPacketCount] = Packet;
856 pAdapt->cReceivedPacketCount++;
857
858 /* check the device state */
859 if(vboxNetFltWinGetPowerState(&pAdapt->PTState) != NdisDeviceStateD0
860 || vboxNetFltWinGetPowerState(&pAdapt->MPState) != NdisDeviceStateD0
861 || vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized
862 || vboxNetFltWinGetOpState(&pAdapt->MPState) > kVBoxNetDevOpState_Initialized)
863 {
864 /* we need to return all packets */
865 bReturn = true;
866 }
867
868 /*
869 * If our receive packet array is full, or the miniport below indicated the packets
870 * with resources, do the indicatin now.
871 */
872
873 if ((pAdapt->cReceivedPacketCount == MAX_RECEIVE_PACKET_ARRAY_SIZE) || DoIndicate || bReturn)
874 {
875 NdisMoveMemory(PacketArray,
876 pAdapt->aReceivedPackets,
877 pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
878
879 NumberOfPackets = pAdapt->cReceivedPacketCount;
880 /*
881 * So other thread can queue the received packets
882 */
883 pAdapt->cReceivedPacketCount = 0;
884
885 if(!bReturn)
886 {
887 DoIndicate = TRUE;
888 }
889 }
890 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
891 } while(0);
892
893 if(!bReturn)
894 {
895 if(DoIndicate)
896 {
897 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, PacketArray, NumberOfPackets);
898 }
899 }
900 else
901 {
902 if (DoIndicate)
903 {
904 NumberOfPackets -= 1;
905 }
906 for (i = 0; i < NumberOfPackets; i++)
907 {
908 vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
909 }
910 }
911}
912
913#endif
914
915static bool vboxNetFltWinPtTransferDataCompleteActive(IN PADAPT pAdapt,
916 IN PNDIS_PACKET pPacket,
917 IN NDIS_STATUS Status)
918{
919 PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
920 PNDIS_BUFFER pBuffer;
921 PTRANSFERDATA_RSVD pTDR;
922
923 if(!vboxNetFltWinRemovePacketFromList(&pAdapt->TransferDataList, pPacket))
924 return false;
925
926 pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->u.TransferDataRsvd;
927 Assert(pTDR);
928 Assert(pTDR->pOriginalBuffer);
929
930 do
931 {
932 NdisUnchainBufferAtFront(pPacket, &pBuffer);
933
934 Assert(pBuffer);
935
936 NdisFreeBuffer(pBuffer);
937
938 pBuffer = pTDR->pOriginalBuffer;
939
940 NdisChainBufferAtBack(pPacket, pBuffer);
941
942 /* data transfer was initiated when the netFlt was active
943 * the netFlt is still retained by us
944 * 1. check if loopback
945 * 2. enqueue packet
946 * 3. release netFlt */
947
948 if(Status == NDIS_STATUS_SUCCESS)
949 {
950
951#ifdef VBOX_LOOPBACK_USEFLAGS
952 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
953 {
954 /* should not be here */
955 Assert(0);
956 }
957#else
958 PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pAdapt, pPacket, false);
959 if(pLb)
960 {
961 /* should not be here */
962 Assert(0);
963 if(!vboxNetFltWinLbIsFromIntNet(pLb))
964 {
965 /* the packet is not from int net, need to pass it up to the host */
966 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pPacket, true);
967 /* dereference NetFlt, pAdapt will be dereferenced on Packet return */
968 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
969 break;
970 }
971 }
972#endif
973 else
974 {
975 PRECV_RSVD pRecvRsvd;
976 /* 2. enqueue */
977 /* use the same packet info to put the packet in the processing packet queue */
978#ifdef VBOX_NETFLT_ONDEMAND_BIND
979 PNDIS_BUFFER pBuffer;
980 PVOID pVA;
981 UINT cbLength;
982 uint32_t fFlags;
983
984 NdisQueryPacket(pPacket, NULL, NULL, &pBuffer, NULL);
985 NdisQueryBufferSafe(pBuffer, &pVA, &cbLength, NormalPagePriority);
986
987 fFlags = MACS_EQUAL(((PRTNETETHERHDR)pVA)->SrcMac, pNetFltIf->u.s.Mac) ?
988 PACKET_MINE | PACKET_SRC_HOST : PACKET_MINE;
989 SET_FLAGS_TO_INFO(pInfo, fFlags);
990
991 pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
992 pRecvRsvd->pOriginalPkt = NULL;
993 pRecvRsvd->pBufToFree = NULL;
994
995 NdisSetPacketFlags(pPacket, 0);
996
997 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, fFlags);
998#else
999 VBOXNETFLT_LBVERIFY(pNetFltIf, pPacket);
1000
1001 pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
1002 pRecvRsvd->pOriginalPkt = NULL;
1003 pRecvRsvd->pBufToFree = NULL;
1004
1005 NdisSetPacketFlags(pPacket, 0);
1006
1007 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_MINE);
1008#endif
1009 if(Status == NDIS_STATUS_SUCCESS)
1010 {
1011 break;
1012 }
1013 Assert(0);
1014 }
1015 }
1016 else
1017 {
1018 Assert(0);
1019 }
1020 /* we are here because of error either in data transfer or in enqueueing the packet */
1021 vboxNetFltWinFreeSGNdisPacket(pPacket, true);
1022 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1023 vboxNetFltWinDereferenceAdapt(pAdapt);
1024 } while(0);
1025
1026 return true;
1027}
1028
1029/**
1030 * Entry point called by NDIS to indicate completion of a call by us
1031 * to NdisTransferData.
1032 *
1033 * See notes under SendComplete.
1034 */
1035static VOID
1036vboxNetFltWinPtTransferDataComplete(
1037 IN NDIS_HANDLE ProtocolBindingContext,
1038 IN PNDIS_PACKET pPacket,
1039 IN NDIS_STATUS Status,
1040 IN UINT BytesTransferred
1041 )
1042{
1043 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
1044 if(!vboxNetFltWinPtTransferDataCompleteActive(pAdapt, pPacket, Status))
1045 {
1046#ifndef VBOX_NETFLT_ONDEMAND_BIND
1047 if(pAdapt->hMiniportHandle)
1048 {
1049 NdisMTransferDataComplete(pAdapt->hMiniportHandle,
1050 pPacket,
1051 Status,
1052 BytesTransferred);
1053 }
1054
1055 vboxNetFltWinDereferenceAdapt(pAdapt);
1056#else
1057 /* we are here because we've failed to allocate packet info */
1058 Assert(0);
1059#endif
1060 }
1061}
1062#ifndef VBOX_NETFLT_ONDEMAND_BIND
1063/**
1064 * This routine process the queued the packet, if anything is fine, indicate the packet
1065 * up, otherwise, return the packet to the underlying miniports.
1066 *
1067 * @param pAdapt - Pointer to the adpater structure.
1068 * @param bReturn - if true the packets should be returned without indication to the upper protocol
1069 * @return None. */
1070DECLHIDDEN(VOID)
1071vboxNetFltWinPtFlushReceiveQueue(
1072 IN PADAPT pAdapt,
1073 IN bool bReturn
1074 )
1075{
1076
1077 PNDIS_PACKET PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
1078 ULONG NumberOfPackets = 0, i;
1079 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1080 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1081
1082 do
1083 {
1084 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
1085
1086 if (pAdapt->cReceivedPacketCount > 0)
1087 {
1088 NdisMoveMemory(PacketArray,
1089 pAdapt->aReceivedPackets,
1090 pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
1091
1092 NumberOfPackets = pAdapt->cReceivedPacketCount;
1093 /*
1094 * So other thread can queue the received packets
1095 */
1096 pAdapt->cReceivedPacketCount = 0;
1097
1098 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1099
1100 if(!bReturn)
1101 {
1102 if(NumberOfPackets > 0)
1103 {
1104 Assert(pAdapt->hMiniportHandle);
1105
1106 /* we are here because the NetFlt is NOT active,
1107 * so no need for packet queueing here, simply indicate */
1108 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle,
1109 PacketArray,
1110 NumberOfPackets);
1111 }
1112 break;
1113 }
1114 /*
1115 * We need return the packet here
1116 */
1117 for (i = 0; i < NumberOfPackets; i ++)
1118 {
1119 vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
1120 }
1121
1122 /* break to ensure we do not call RTSpinlockRelease extra time */
1123 break;
1124 }
1125
1126 /* we are here only in case pAdapt->cReceivedPacketCount == 0 */
1127 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1128 } while (FALSE);
1129}
1130
1131/**
1132 * ReceivePacket handler. Called by NDIS if the miniport below supports
1133 * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
1134 * and indicate the new packet to protocols above us. Any context for
1135 * packets indicated up must be kept in the MiniportReserved field.
1136 *
1137 * @param ProtocolBindingContext - Pointer to our adapter structure.
1138 * @param Packet - Pointer to the packet
1139 * @return INT == 0 -> We are done with the packet
1140 * != 0 -> We will keep the packet and call NdisReturnPackets() this
1141 * many times when done. */
1142static INT
1143vboxNetFltWinRecvPacketPassThru(
1144 IN PADAPT pAdapt,
1145 IN PNDIS_PACKET pPacket
1146 )
1147{
1148 NDIS_STATUS fStatus;
1149 PNDIS_PACKET pMyPacket;
1150
1151 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1152
1153 fStatus = vboxNetFltWinPrepareRecvPacket(pAdapt, pPacket, &pMyPacket, true);
1154
1155 Assert(pMyPacket);
1156
1157 if(pMyPacket != NULL)
1158 {
1159 if (fStatus == NDIS_STATUS_RESOURCES)
1160 {
1161 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
1162
1163 /*
1164 * Our ReturnPackets handler will not be called for this packet.
1165 * We should reclaim it right here.
1166 */
1167 NdisDprFreePacket(pMyPacket);
1168
1169 return 0;
1170 }
1171
1172 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, FALSE);
1173
1174 return 1;
1175 }
1176
1177 return 0;
1178}
1179
1180/**
1181 * process the packet receive in a "passthru" mode
1182 */
1183static NDIS_STATUS
1184vboxNetFltWinRecvPassThru(
1185 IN PADAPT pAdapt,
1186 IN PNDIS_PACKET pPacket)
1187{
1188
1189 NDIS_STATUS fStatus;
1190 PNDIS_PACKET pMyPacket;
1191 /*
1192 * The miniport below did indicate up a packet. Use information
1193 * from that packet to construct a new packet to indicate up.
1194 */
1195
1196 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1197
1198 /*
1199 * Get a packet off the pool and indicate that up
1200 */
1201 NdisDprAllocatePacket(&fStatus,
1202 &pMyPacket,
1203 pAdapt->hRecvPacketPoolHandle);
1204 Assert(fStatus == NDIS_STATUS_SUCCESS);
1205 if (fStatus == NDIS_STATUS_SUCCESS)
1206 {
1207 /*
1208 * Make our packet point to data from the original
1209 * packet. NOTE: this works only because we are
1210 * indicating a receive directly from the context of
1211 * our receive indication. If we need to queue this
1212 * packet and indicate it from another thread context,
1213 * we will also have to allocate a new buffer and copy
1214 * over the packet contents, OOB data and per-packet
1215 * information. This is because the packet data
1216 * is available only for the duration of this
1217 * receive indication call.
1218 */
1219 NDIS_PACKET_FIRST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
1220 NDIS_PACKET_LAST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
1221
1222 /*
1223 * Get the original packet (it could be the same packet as the
1224 * one received or a different one based on the number of layered
1225 * miniports below) and set it on the indicated packet so the OOB
1226 * data is visible correctly at protocols above.
1227 */
1228 NDIS_SET_ORIGINAL_PACKET(pMyPacket, NDIS_GET_ORIGINAL_PACKET(pPacket));
1229 NDIS_SET_PACKET_HEADER_SIZE(pMyPacket, NDIS_GET_PACKET_HEADER_SIZE(pPacket));
1230
1231 /*
1232 * Copy packet flags.
1233 */
1234 NdisGetPacketFlags(pMyPacket) = NdisGetPacketFlags(pPacket);
1235
1236 /*
1237 * Force protocols above to make a copy if they want to hang
1238 * on to data in this packet. This is because we are in our
1239 * Receive handler (not ReceivePacket) and we can't return a
1240 * ref count from here.
1241 */
1242 NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_RESOURCES);
1243
1244 /*
1245 * By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
1246 * this packet as soon as the call to NdisMIndicateReceivePacket
1247 * returns.
1248 *
1249 * NOTE: we queue the packet and indicate this packet immediately with
1250 * the already queued packets together. We have to the queue the packet
1251 * first because some versions of NDIS might call protocols'
1252 * ReceiveHandler(not ReceivePacketHandler) if the packet indicate status
1253 * is NDIS_STATUS_RESOURCES. If the miniport below indicates an array of
1254 * packets, some of them with status NDIS_STATUS_SUCCESS, some of them
1255 * with status NDIS_STATUS_RESOURCES, vboxNetFltWinPtReceive might be called, by
1256 * doing this way, we preserve the receive order of packets.
1257 */
1258 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
1259 /*
1260 * Reclaim the indicated packet. Since we had set its status
1261 * to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
1262 * above are done with it.
1263 */
1264 NdisDprFreePacket(pMyPacket);
1265
1266 }
1267 return fStatus;
1268}
1269
1270#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
1271
1272
1273
1274
1275/**
1276 * process the ProtocolReceive in an "active" mode
1277 *
1278 * @return NDIS_STATUS_SUCCESS - the packet is processed
1279 * NDIS_STATUS_PENDING - the packet is being processed, we are waiting for the ProtocolTransferDataComplete to be called
1280 * NDIS_STATUS_NOT_ACCEPTED - the packet is not needed - typically this is because this is a loopback packet
1281 * NDIS_STATUS_FAILURE - packet processing failed
1282 */
1283static NDIS_STATUS
1284vboxNetFltWinPtReceiveActive(
1285 IN PADAPT pAdapt,
1286 IN NDIS_HANDLE MacReceiveContext,
1287 IN PVOID pHeaderBuffer,
1288 IN UINT cbHeaderBuffer,
1289 IN PVOID pLookaheadBuffer,
1290 IN UINT cbLookaheadBuffer,
1291 IN UINT cbPacket
1292 )
1293{
1294 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1295
1296 do
1297 {
1298 if (cbHeaderBuffer != ETH_HEADER_SIZE)
1299 {
1300 Status = NDIS_STATUS_NOT_ACCEPTED;
1301 break;
1302 }
1303
1304#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
1305 if (cbPacket == cbLookaheadBuffer)
1306 {
1307 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1308 PINTNETSG pSG;
1309 PUCHAR pRcvData;
1310#ifndef VBOX_LOOPBACK_USEFLAGS
1311 PNDIS_PACKET pLb;
1312#endif
1313
1314 /* allocate SG buffer */
1315 Status = vboxNetFltWinAllocSG(cbPacket + cbHeaderBuffer, &pSG);
1316 if(Status != NDIS_STATUS_SUCCESS)
1317 {
1318 Assert(0);
1319 break;
1320 }
1321
1322 pRcvData = (PUCHAR)pSG->aSegs[0].pv;
1323
1324 NdisMoveMappedMemory(pRcvData, pHeaderBuffer, cbHeaderBuffer);
1325
1326 NdisCopyLookaheadData(pRcvData+cbHeaderBuffer,
1327 pLookaheadBuffer,
1328 cbLookaheadBuffer,
1329 pAdapt->fMacOptions);
1330#ifndef VBOX_LOOPBACK_USEFLAGS
1331 pLb = vboxNetFltWinLbSearchLoopBackBySG(pAdapt, pSG, false);
1332 if(pLb)
1333 {
1334 /* should not be here */
1335 Assert(0);
1336
1337 if(!vboxNetFltWinLbIsFromIntNet(pLb))
1338 {
1339 PNDIS_PACKET pMyPacket;
1340 pMyPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, /* PADAPT */
1341 pSG, /* PINTNETSG */
1342 pSG, /* PVOID pBufToFree */
1343 false, /* bool bToWire */
1344 false); /* bool bCopyMemory */
1345 if(pMyPacket)
1346 {
1347 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, true);
1348 /* dereference the NetFlt here & indicate SUCCESS, which would mean the caller would not do a dereference
1349 * the pAdapt dereference will be done on packet return */
1350 vboxNetFltWinDereferenceNetFlt(pNetFlt);
1351 Status = NDIS_STATUS_SUCCESS;
1352 }
1353 else
1354 {
1355 vboxNetFltWinMemFree(pSG);
1356 Status = NDIS_STATUS_FAILURE;
1357 }
1358 }
1359 else
1360 {
1361 vboxNetFltWinMemFree(pSG);
1362 Status = NDIS_STATUS_NOT_ACCEPTED;
1363 }
1364 break;
1365 }
1366#endif
1367 VBOXNETFLT_LBVERIFYSG(pNetFlt, pSG);
1368
1369 /* enqueue SG */
1370#ifdef VBOX_NETFLT_ONDEMAND_BIND
1371 {
1372 uint32_t fFlags = MACS_EQUAL(((PRTNETETHERHDR)pRcvData)->SrcMac, pNetFlt->u.s.Mac) ?
1373 PACKET_SG | PACKET_MINE | PACKET_SRC_HOST : PACKET_SG | PACKET_MINE;
1374 Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, fFlags);
1375 }
1376#else
1377 Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, PACKET_SG | PACKET_MINE);
1378#endif
1379 if(Status != NDIS_STATUS_SUCCESS)
1380 {
1381 Assert(0);
1382 vboxNetFltWinMemFree(pSG);
1383 break;
1384 }
1385 }
1386 else
1387#endif /* #ifndef DEBUG_NETFLT_RECV_TRANSFERDATA */
1388 {
1389 PNDIS_PACKET pPacket;
1390 PNDIS_BUFFER pTransferBuffer;
1391 PNDIS_BUFFER pOrigBuffer;
1392 PUCHAR pMemBuf;
1393 UINT cbBuf = cbPacket + cbHeaderBuffer;
1394 UINT BytesTransferred;
1395
1396 /* allocate NDIS Packet buffer */
1397#ifdef VBOX_NETFLT_ONDEMAND_BIND
1398 /* use the Send packet pool for packet allocation */
1399 NdisAllocatePacket(&Status, &pPacket, pAdapt->hSendPacketPoolHandle);
1400#else
1401 NdisAllocatePacket(&Status, &pPacket, pAdapt->hRecvPacketPoolHandle);
1402#endif
1403 if(Status != NDIS_STATUS_SUCCESS)
1404 {
1405 Assert(0);
1406 break;
1407 }
1408
1409#ifdef VBOX_LOOPBACK_USEFLAGS
1410 /* set "don't loopback" flags */
1411 NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
1412#endif
1413
1414 Status = vboxNetFltWinMemAlloc(&pMemBuf, cbBuf);
1415 if(Status != NDIS_STATUS_SUCCESS)
1416 {
1417 Assert(0);
1418 NdisFreePacket(pPacket);
1419 break;
1420 }
1421#ifdef VBOX_NETFLT_ONDEMAND_BIND
1422 /* use the Send buffer pool for buffer allocation */
1423 NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
1424#else
1425 NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
1426#endif
1427 if(Status != NDIS_STATUS_SUCCESS)
1428 {
1429 Assert(0);
1430 Status = NDIS_STATUS_FAILURE;
1431 NdisFreePacket(pPacket);
1432 vboxNetFltWinMemFree(pMemBuf);
1433 break;
1434 }
1435
1436#ifdef VBOX_NETFLT_ONDEMAND_BIND
1437 /* use the Send buffer pool for buffer allocation */
1438 NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf, cbBuf);
1439#else
1440 NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf, cbBuf);
1441#endif
1442 if(Status != NDIS_STATUS_SUCCESS)
1443 {
1444 Assert(0);
1445 Status = NDIS_STATUS_FAILURE;
1446 NdisFreeBuffer(pTransferBuffer);
1447 NdisFreePacket(pPacket);
1448 vboxNetFltWinMemFree(pMemBuf);
1449 break;
1450 }
1451
1452 NdisChainBufferAtBack(pPacket, pTransferBuffer);
1453
1454 NdisMoveMappedMemory(pMemBuf, pHeaderBuffer, cbHeaderBuffer);
1455
1456#ifndef VBOX_NETFLT_ONDEMAND_BIND
1457 vboxNetFltWinPutPacketToList(&pAdapt->TransferDataList, pPacket, pOrigBuffer);
1458#endif
1459
1460#ifdef DEBUG_NETFLT_RECV_TRANSFERDATA
1461 if(cbPacket == cbLookaheadBuffer)
1462 {
1463 NdisCopyLookaheadData(pMemBuf+cbHeaderBuffer,
1464 pLookaheadBuffer,
1465 cbLookaheadBuffer,
1466 pAdapt->fMacOptions);
1467 }
1468 else
1469#endif
1470 {
1471 Assert(cbPacket > cbLookaheadBuffer);
1472
1473 NdisTransferData(
1474 &Status,
1475 pAdapt->hBindingHandle,
1476 MacReceiveContext,
1477 0, /* ByteOffset */
1478 cbPacket,
1479 pPacket,
1480 &BytesTransferred);
1481 }
1482 if(Status != NDIS_STATUS_PENDING)
1483 {
1484 vboxNetFltWinPtTransferDataComplete(pAdapt, pPacket, Status, BytesTransferred);
1485 }
1486 }
1487 } while(0);
1488
1489 return Status;
1490}
1491
1492
1493/**
1494 * Handle receive data indicated up by the miniport below. We pass
1495 * it along to the protocol above us.
1496 *
1497 * If the miniport below indicates packets, NDIS would more
1498 * likely call us at our ReceivePacket handler. However we
1499 * might be called here in certain situations even though
1500 * the miniport below has indicated a receive packet, e.g.
1501 * if the miniport had set packet status to NDIS_STATUS_RESOURCES.
1502 *
1503 * @param ProtocolBindingContext
1504 * @param MacReceiveContext
1505 * @param pHeaderBuffer
1506 * @param cbHeaderBuffer
1507 * @param pLookAheadBuffer
1508 * @param cbLookAheadBuffer
1509 * @param cbPacket
1510 * @return NDIS_STATUS_SUCCESS if we processed the receive successfully,
1511 * NDIS_STATUS_XXX error code if we discarded it. */
1512static NDIS_STATUS
1513vboxNetFltWinPtReceive(
1514 IN NDIS_HANDLE ProtocolBindingContext,
1515 IN NDIS_HANDLE MacReceiveContext,
1516 IN PVOID pHeaderBuffer,
1517 IN UINT cbHeaderBuffer,
1518 IN PVOID pLookAheadBuffer,
1519 IN UINT cbLookAheadBuffer,
1520 IN UINT cbPacket
1521 )
1522{
1523 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
1524 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1525 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1526#ifdef VBOX_NETFLT_ONDEMAND_BIND
1527#if 0
1528 uint32_t fFlags;
1529#endif
1530
1531 pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
1532 if(pNetFltIf)
1533 {
1534 do
1535 {
1536#if 0
1537 pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
1538 if(pPacket)
1539 {
1540# ifdef DEBUG_NETFLT_LOOPBACK
1541# error "implement (see comments in the sources below this #error:)"
1542 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1543 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1544 similar to that used in TrasferData handling should be used;
1545 */
1546
1547// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
1548# else
1549 if(vboxNetFltWinIsLoopedBackPacket(pPacket) || cbHeaderBuffer != ETH_HEADER_SIZE)
1550# endif
1551
1552 {
1553// Assert(0);
1554 /* nothing else to do here, just return the packet */
1555// NdisReturnPackets(&pPacket, 1);
1556// break;
1557 }
1558
1559 fFlags = MACS_EQUAL(((PRTNETETHERHDR)pHeaderBuffer)->SrcMac, pNetFltIf->u.s.Mac) ?
1560 PACKET_COPY | PACKET_SRC_HOST : PACKET_COPY;
1561 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, fFlags);
1562 if(Status == NDIS_STATUS_SUCCESS)
1563 {
1564 NdisReturnPackets(&pPacket, 1);
1565 pAdapt = NULL;
1566 pNetFltIf = NULL;
1567 break;
1568 }
1569 }
1570#endif
1571 Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
1572 pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
1573 if(NT_SUCCESS(Status))
1574 {
1575 if(Status != NDIS_STATUS_NOT_ACCEPTED)
1576 {
1577 pAdapt = NULL;
1578 pNetFltIf = NULL;
1579 }
1580 else
1581 {
1582 /* this is a looopback packet, nothing to do here */
1583 }
1584 break;
1585 }
1586 } while(0);
1587
1588 if(pNetFltIf)
1589 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1590 if(pAdapt)
1591 vboxNetFltWinDereferenceAdapt(pAdapt);
1592
1593
1594#if 0
1595 if(pPacket)
1596 {
1597 NdisReturnPackets(&pPacket, 1);
1598 }
1599#endif
1600 /* we are here because the vboxNetFltWinPtReceiveActive returned pending,
1601 * which means our ProtocolDataTransferComplete we will called,
1602 * so return SUCCESS instead of NOT_ACCEPTED ?? */
1603// return NDIS_STATUS_SUCCESS;
1604 }
1605 return NDIS_STATUS_NOT_ACCEPTED;
1606#else /* if NOT defined VBOX_NETFLT_ONDEMAND_BIND */
1607 PNDIS_PACKET pPacket = NULL;
1608 bool bNetFltActive;
1609 bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFlt(pNetFlt, pAdapt, &bNetFltActive);
1610 const bool bPassThruActive = !bNetFltActive;
1611 if(fAdaptActive)
1612 {
1613 do
1614 {
1615#ifndef DEBUG_NETFLT_RECV_NOPACKET
1616 /*
1617 * Get at the packet, if any, indicated up by the miniport below.
1618 */
1619 pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
1620 if (pPacket != NULL)
1621 {
1622 do
1623 {
1624#ifdef VBOX_LOOPBACK_USEFLAGS
1625 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1626 {
1627 Assert(0);
1628 /* nothing else to do here, just return the packet */
1629 //NdisReturnPackets(&pPacket, 1);
1630 Status = NDIS_STATUS_NOT_ACCEPTED;
1631 break;
1632 }
1633
1634 VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
1635#else
1636 PNDIS_PACKET pLb = NULL;
1637#endif
1638 if(bNetFltActive)
1639 {
1640#ifndef VBOX_LOOPBACK_USEFLAGS
1641 pLb = vboxNetFltWinLbSearchLoopBack(pAdapt, pPacket, true /* ??? no need to keep it, so remove */);
1642 if(!pLb)
1643#endif
1644 {
1645 VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
1646
1647 Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, PACKET_COPY);
1648 Assert(Status == NDIS_STATUS_SUCCESS);
1649 if(Status == NDIS_STATUS_SUCCESS)
1650 {
1651 //NdisReturnPackets(&pPacket, 1);
1652 fAdaptActive = false;
1653 bNetFltActive = false;
1654 break;
1655 }
1656 }
1657#ifndef VBOX_LOOPBACK_USEFLAGS
1658 else if(vboxNetFltWinLbIsFromIntNet(pLb))
1659 {
1660 /* nothing else to do here, just return the packet */
1661 //NdisReturnPackets(&pPacket, 1);
1662 Status = NDIS_STATUS_NOT_ACCEPTED;
1663 break;
1664 }
1665 /* we are here because this is a looped back packet set not from intnet
1666 * we will post it to the upper protocol */
1667#endif
1668 }
1669
1670#ifndef VBOX_LOOPBACK_USEFLAGS
1671 Assert(pLb && !vboxNetFltWinLbIsFromIntNet(pLb));
1672#endif
1673 Status = vboxNetFltWinRecvPassThru(pAdapt, pPacket);
1674 /* we are done with packet processing, and we will
1675 * not receive packet return event for this packet,
1676 * fAdaptActive should be true to ensure we release adapt*/
1677 Assert(fAdaptActive);
1678 } while(FALSE);
1679
1680 if(Status == NDIS_STATUS_SUCCESS || Status == NDIS_STATUS_NOT_ACCEPTED
1681#ifndef VBOX_LOOPBACK_USEFLAGS
1682 || pLb
1683#endif
1684 )
1685 {
1686 break;
1687 }
1688 }
1689#endif
1690 if(bNetFltActive)
1691 {
1692 Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
1693 pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
1694 if(NT_SUCCESS(Status))
1695 {
1696 if(Status != NDIS_STATUS_NOT_ACCEPTED)
1697 {
1698 fAdaptActive = false;
1699 bNetFltActive = false;
1700 }
1701 else
1702 {
1703#ifndef VBOX_LOOPBACK_USEFLAGS
1704 /* this is a loopback packet, nothing to do here */
1705#else
1706 Assert(0);
1707 /* should not be here */
1708#endif
1709 }
1710 break;
1711 }
1712 }
1713
1714 /* Fall through if the miniport below us has either not
1715 * indicated a packet or we could not allocate one */
1716 if(pPacket != NULL)
1717 {
1718 /*
1719 * We are here because we failed to allocate packet
1720 */
1721 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
1722 }
1723
1724 /* we are done with packet processing, and we will
1725 * not receive packet return event for this packet,
1726 * fAdaptActive should be true to ensure we release adapt*/
1727 Assert(fAdaptActive);
1728
1729 pAdapt->bIndicateRcvComplete = TRUE;
1730 switch (pAdapt->Medium)
1731 {
1732 case NdisMedium802_3:
1733 case NdisMediumWan:
1734 NdisMEthIndicateReceive(pAdapt->hMiniportHandle,
1735 MacReceiveContext,
1736 (PCHAR)pHeaderBuffer,
1737 cbHeaderBuffer,
1738 pLookAheadBuffer,
1739 cbLookAheadBuffer,
1740 cbPacket);
1741 break;
1742 default:
1743 Assert(FALSE);
1744 break;
1745 }
1746 } while(0);
1747
1748 if(bNetFltActive)
1749 {
1750 vboxNetFltWinDereferenceNetFlt(pNetFlt);
1751 }
1752 else if(bPassThruActive)
1753 {
1754 vboxNetFltWinDereferenceModePassThru(pNetFlt);
1755 }
1756 if(fAdaptActive)
1757 {
1758 vboxNetFltWinDereferenceAdapt(pAdapt);
1759 }
1760 }
1761 else
1762 {
1763 Status = NDIS_STATUS_FAILURE;
1764 }
1765
1766 return Status;
1767#endif
1768}
1769
1770/**
1771 * Called by the adapter below us when it is done indicating a batch of
1772 * received packets.
1773 *
1774 * @param ProtocolBindingContext Pointer to our adapter structure.
1775 * @return None */
1776static VOID
1777vboxNetFltWinPtReceiveComplete(
1778 IN NDIS_HANDLE ProtocolBindingContext
1779 )
1780{
1781#ifndef VBOX_NETFLT_ONDEMAND_BIND
1782 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
1783 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1784 ULONG NumberOfPackets = 0;
1785 /* since the receive array queued packets do not hold the reference we need to
1786 * reference the PassThru/NetFlt mode here to avoid packet reordering caused by
1787 * concurrently running vboxNetFltWinPtReceiveComplete and vboxNetFltPortOsSetActive
1788 * on netflt activation/deactivation */
1789 bool bNetFltActive;
1790 bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFlt(pNetFlt, pAdapt, &bNetFltActive);
1791
1792 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
1793
1794 if ((pAdapt->hMiniportHandle != NULL)
1795 /* && (pAdapt->MPDeviceState == NdisDeviceStateD0) */
1796 && (pAdapt->bIndicateRcvComplete == TRUE))
1797 {
1798 switch (pAdapt->Medium)
1799 {
1800 case NdisMedium802_3:
1801 case NdisMediumWan:
1802 NdisMEthIndicateReceiveComplete(pAdapt->hMiniportHandle);
1803 break;
1804 default:
1805 Assert(FALSE);
1806 break;
1807 }
1808 }
1809
1810 pAdapt->bIndicateRcvComplete = FALSE;
1811
1812 if(fAdaptActive)
1813 {
1814 if(bNetFltActive)
1815 {
1816 vboxNetFltWinDereferenceNetFlt(pNetFlt);
1817 }
1818 else
1819 {
1820 vboxNetFltWinDereferenceModePassThru(pNetFlt);
1821 }
1822 vboxNetFltWinDereferenceAdapt(pAdapt);
1823 }
1824#endif
1825}
1826
1827/**
1828 * ReceivePacket handler. Called by NDIS if the miniport below supports
1829 * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
1830 * and indicate the new packet to protocols above us. Any context for
1831 * packets indicated up must be kept in the MiniportReserved field.
1832 *
1833 * @param ProtocolBindingContext - Pointer to our adapter structure.
1834 * @param Packet - Pointer to the packet
1835 * @return == 0 -> We are done with the packet,
1836 * != 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
1837 */
1838static INT
1839vboxNetFltWinPtReceivePacket(
1840 IN NDIS_HANDLE ProtocolBindingContext,
1841 IN PNDIS_PACKET pPacket
1842 )
1843{
1844 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
1845 INT cRefCount = 0;
1846 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1847#ifdef VBOX_NETFLT_ONDEMAND_BIND
1848 PNDIS_BUFFER pBuffer;
1849 PVOID pVA;
1850 UINT cbLength;
1851 uint32_t fFlags;
1852
1853 pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
1854
1855 if(pNetFltIf)
1856 {
1857 NDIS_STATUS Status;
1858 bool bResources;
1859 do
1860 {
1861#ifdef DEBUG_NETFLT_LOOPBACK
1862# error "implement (see comments in the sources below this #error:)"
1863 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1864 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1865 similar to that used in TrasferData handling should be used;
1866 */
1867
1868// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
1869#else
1870 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1871#endif
1872
1873 {
1874 Assert(0);
1875 NdisReturnPackets(&pPacket, 1);
1876 break;
1877 }
1878 bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
1879
1880 NdisQueryPacket(pPacket, NULL, NULL, &pBuffer, NULL);
1881 if(!pBuffer)
1882 {
1883 Assert(0);
1884 NdisReturnPackets(&pPacket, 1);
1885 cRefCount = 0;
1886 break;
1887 }
1888
1889 NdisQueryBufferSafe(pBuffer, &pVA, &cbLength, NormalPagePriority);
1890 if(!pVA || !cbLength)
1891 {
1892 Assert(0);
1893 NdisReturnPackets(&pPacket, 1);
1894 cRefCount = 0;
1895 break;
1896 }
1897
1898 fFlags = MACS_EQUAL(((PRTNETETHERHDR)pVA)->SrcMac, pNetFltIf->u.s.Mac) ? PACKET_SRC_HOST : 0;
1899
1900 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, bResources ? fFlags | PACKET_COPY : fFlags);
1901 if(Status == NDIS_STATUS_SUCCESS)
1902 {
1903 if(bResources)
1904 {
1905 cRefCount = 0;
1906 NdisReturnPackets(&pPacket, 1);
1907 }
1908 else
1909 {
1910 cRefCount = 1;
1911 }
1912 pNetFltIf = NULL;
1913 pAdapt = NULL;
1914 break;
1915 }
1916 else
1917 {
1918 Assert(0);
1919 NdisReturnPackets(&pPacket, 1);
1920 cRefCount = 0;
1921 break;
1922 }
1923 } while (0);
1924
1925 if(pNetFltIf)
1926 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1927 if(pAdapt)
1928 vboxNetFltWinDereferenceAdapt(pAdapt);
1929 return cRefCount;
1930 }
1931 /* we are here because we are inactive, simply return the packet */
1932 NdisReturnPackets(&pPacket, 1);
1933 return 0;
1934#else
1935 bool bNetFltActive;
1936 bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFlt(pNetFlt, pAdapt, &bNetFltActive);
1937 const bool bPassThruActive = !bNetFltActive;
1938 if(fAdaptActive)
1939 {
1940 do
1941 {
1942#ifdef VBOX_LOOPBACK_USEFLAGS
1943 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1944 {
1945 Assert(0);
1946 Log(("lb_rp"));
1947
1948 /* nothing else to do here, just return the packet */
1949 cRefCount = 0;
1950 //NdisReturnPackets(&pPacket, 1);
1951 break;
1952 }
1953
1954 VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
1955#endif
1956
1957 if(bNetFltActive)
1958 {
1959#ifndef VBOX_LOOPBACK_USEFLAGS
1960 PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pAdapt, pPacket, true /* ??? no need to keep it, so remove */);
1961 if(!pLb)
1962#endif
1963 {
1964 NDIS_STATUS fStatus;
1965 bool bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
1966
1967 VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
1968
1969 /*TODO: remove this assert.
1970 * this is a temporary assert for debugging purposes:
1971 * we're probably doing something wrong with the packets if the miniport reports NDIS_STATUS_RESOURCES */
1972 Assert(!bResources);
1973
1974 fStatus = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, bResources ? PACKET_COPY : 0);
1975 if(fStatus == NDIS_STATUS_SUCCESS)
1976 {
1977 bNetFltActive = false;
1978 fAdaptActive = false;
1979 if(bResources)
1980 {
1981 cRefCount = 0;
1982 //NdisReturnPackets(&pPacket, 1);
1983 }
1984 else
1985 {
1986 cRefCount = 1;
1987 }
1988 break;
1989 }
1990 else
1991 {
1992 Assert(0);
1993 }
1994 }
1995#ifndef VBOX_LOOPBACK_USEFLAGS
1996 else if(vboxNetFltWinLbIsFromIntNet(pLb))
1997 {
1998 /* the packet is from intnet, it has already been set to the host,
1999 * no need for loopng it back to the host again */
2000 /* nothing else to do here, just return the packet */
2001 cRefCount = 0;
2002 //NdisReturnPackets(&pPacket, 1);
2003 break;
2004 }
2005#endif
2006 }
2007
2008 cRefCount = vboxNetFltWinRecvPacketPassThru(pAdapt, pPacket);
2009 if(cRefCount)
2010 {
2011 Assert(cRefCount == 1);
2012 fAdaptActive = false;
2013 }
2014
2015 } while(FALSE);
2016
2017 if(bNetFltActive)
2018 {
2019 vboxNetFltWinDereferenceNetFlt(pNetFlt);
2020 }
2021 else if(bPassThruActive)
2022 {
2023 vboxNetFltWinDereferenceModePassThru(pNetFlt);
2024 }
2025 if(fAdaptActive)
2026 {
2027 vboxNetFltWinDereferenceAdapt(pAdapt);
2028 }
2029 }
2030 else
2031 {
2032 cRefCount = 0;
2033 //NdisReturnPackets(&pPacket, 1);
2034 }
2035
2036 return cRefCount;
2037#endif
2038}
2039
2040/**
2041 * This routine is called from NDIS to notify our protocol edge of a
2042 * reconfiguration of parameters for either a specific binding (pAdapt
2043 * is not NULL), or global parameters if any (pAdapt is NULL).
2044 *
2045 * @param pAdapt - Pointer to our adapter structure.
2046 * @param pNetPnPEvent - the reconfigure event
2047 * @return NDIS_STATUS_SUCCESS */
2048static NDIS_STATUS
2049vboxNetFltWinPtPnPNetEventReconfigure(
2050 IN PADAPT pAdapt,
2051 IN PNET_PNP_EVENT pNetPnPEvent
2052 )
2053{
2054 NDIS_STATUS ReconfigStatus = NDIS_STATUS_SUCCESS;
2055 NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
2056
2057 do
2058 {
2059 /*
2060 * Is this is a global reconfiguration notification ?
2061 */
2062 if (pAdapt == NULL)
2063 {
2064 /*
2065 * An important event that causes this notification to us is if
2066 * one of our upper-edge miniport instances was enabled after being
2067 * disabled earlier, e.g. from Device Manager in Win2000. Note that
2068 * NDIS calls this because we had set up an association between our
2069 * miniport and protocol entities by calling NdisIMAssociateMiniport.
2070 *
2071 * Since we would have torn down the lower binding for that miniport,
2072 * we need NDIS' assistance to re-bind to the lower miniport. The
2073 * call to NdisReEnumerateProtocolBindings does exactly that.
2074 */
2075 NdisReEnumerateProtocolBindings (g_hProtHandle);
2076 break;
2077 }
2078
2079 ReconfigStatus = NDIS_STATUS_SUCCESS;
2080
2081 } while(FALSE);
2082
2083 LogFlow(("<==PtPNPNetEventReconfigure: pAdapt %p\n", pAdapt));
2084
2085 return ReconfigStatus;
2086}
2087
2088static NDIS_STATUS
2089vboxNetFltWinPtPnPNetEventBindsComplete(
2090 IN PADAPT pAdapt,
2091 IN PNET_PNP_EVENT pNetPnPEvent
2092 )
2093{
2094 return NDIS_STATUS_SUCCESS;
2095}
2096
2097DECLHIDDEN(bool) vboxNetFltWinPtCloseAdapter(PADAPT pAdapt, PNDIS_STATUS pStatus)
2098{
2099 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2100 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2101
2102 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
2103
2104 if(pAdapt->bClosingAdapter)
2105 {
2106 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2107 Assert(0);
2108 return false;
2109 }
2110 if (pAdapt->hBindingHandle == NULL)
2111 {
2112 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2113 Assert(0);
2114 return false;
2115 }
2116
2117 pAdapt->bClosingAdapter = true;
2118 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2119
2120 /*
2121 * Close the binding below. and wait for it to complete
2122 */
2123 NdisResetEvent(&pAdapt->hEvent);
2124
2125 NdisCloseAdapter(pStatus, pAdapt->hBindingHandle);
2126
2127 if (*pStatus == NDIS_STATUS_PENDING)
2128 {
2129 NdisWaitEvent(&pAdapt->hEvent, 0);
2130 *pStatus = pAdapt->Status;
2131 }
2132
2133 Assert (*pStatus == NDIS_STATUS_SUCCESS);
2134
2135 pAdapt->hBindingHandle = NULL;
2136
2137 return true;
2138}
2139
2140/**
2141 * This is a notification to our protocol edge of the power state
2142 * of the lower miniport. If it is going to a low-power state, we must
2143 * wait here for all outstanding sends and requests to complete.
2144 *
2145 * @param pAdapt - Pointer to the adpater structure
2146 * @param pNetPnPEvent - The Net Pnp Event. this contains the new device state
2147 * @return NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols.
2148 * */
2149static NDIS_STATUS
2150vboxNetFltWinPtPnPNetEventSetPower(
2151 IN PADAPT pAdapt,
2152 IN PNET_PNP_EVENT pNetPnPEvent
2153 )
2154{
2155 PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
2156 NDIS_DEVICE_POWER_STATE PrevDeviceState = vboxNetFltWinGetPowerState(&pAdapt->PTState);
2157 NDIS_STATUS ReturnStatus;
2158 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2159 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2160
2161 ReturnStatus = NDIS_STATUS_SUCCESS;
2162
2163 /*
2164 * Set the Internal Device State, this blocks all new sends or receives
2165 */
2166 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
2167
2168 vboxNetFltWinSetPowerState(&pAdapt->PTState, *pDeviceState);
2169
2170 /*
2171 * Check if the miniport below is going to a low power state.
2172 */
2173 if (vboxNetFltWinGetPowerState(&pAdapt->PTState) > NdisDeviceStateD0)
2174 {
2175 /*
2176 * If the miniport below is going to standby, fail all incoming requests
2177 */
2178 if (PrevDeviceState == NdisDeviceStateD0)
2179 {
2180 pAdapt->bStandingBy = TRUE;
2181 }
2182 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2183#ifndef VBOX_NETFLT_ONDEMAND_BIND
2184
2185 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
2186
2187 vboxNetFltWinWaitDereference(&pAdapt->MPState);
2188#endif
2189
2190 /*
2191 * Wait for outstanding sends and requests to complete.
2192 */
2193 vboxNetFltWinWaitDereference(&pAdapt->PTState);
2194
2195#ifndef VBOX_NETFLT_ONDEMAND_BIND
2196 while (ASMAtomicUoReadBool((volatile bool *)&pAdapt->bOutstandingRequests))
2197 {
2198 /*
2199 * sleep till outstanding requests complete
2200 */
2201 vboxNetFltWinSleep(2);
2202 }
2203
2204 /*
2205 * If the below miniport is going to low power state, complete the queued request
2206 */
2207 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
2208 if (pAdapt->bQueuedRequest)
2209 {
2210 pAdapt->bQueuedRequest = FALSE;
2211 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2212 vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE);
2213 }
2214 else
2215 {
2216 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2217 }
2218#endif
2219
2220 Assert(NdisPacketPoolUsage(pAdapt->hSendPacketPoolHandle) == 0);
2221#ifndef VBOX_NETFLT_ONDEMAND_BIND
2222 Assert(NdisPacketPoolUsage(pAdapt->hRecvPacketPoolHandle) == 0);
2223 Assert(pAdapt->bOutstandingRequests == FALSE);
2224#endif
2225 }
2226 else
2227 {
2228 /*
2229 * If the physical miniport is powering up (from Low power state to D0),
2230 * clear the flag
2231 */
2232 if (PrevDeviceState > NdisDeviceStateD0)
2233 {
2234 pAdapt->bStandingBy = FALSE;
2235 }
2236
2237#ifdef VBOX_NETFLT_ONDEMAND_BIND
2238 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2239#else
2240 /*
2241 * The device below is being turned on. If we had a request
2242 * pending, send it down now.
2243 */
2244 if (pAdapt->bQueuedRequest == TRUE)
2245 {
2246 NDIS_STATUS Status;
2247
2248 pAdapt->bQueuedRequest = FALSE;
2249
2250 pAdapt->bOutstandingRequests = TRUE;
2251 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2252
2253 NdisRequest(&Status,
2254 pAdapt->hBindingHandle,
2255 &pAdapt->Request);
2256
2257 if (Status != NDIS_STATUS_PENDING)
2258 {
2259 vboxNetFltWinPtRequestComplete(pAdapt,
2260 &pAdapt->Request,
2261 Status);
2262
2263 }
2264 }
2265 else
2266 {
2267 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2268 }
2269
2270#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
2271
2272 }
2273
2274 return ReturnStatus;
2275}
2276
2277/**
2278 * This is called by NDIS to notify us of a PNP event related to a lower
2279 * binding. Based on the event, this dispatches to other helper routines.
2280 *
2281 * @param ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
2282 * for "global" notifications
2283 * @param pNetPnPEvent - Pointer to the PNP event to be processed.
2284 * @return NDIS_STATUS code indicating status of event processing.
2285 * */
2286static NDIS_STATUS
2287vboxNetFltWinPtPnPHandler(
2288 IN NDIS_HANDLE ProtocolBindingContext,
2289 IN PNET_PNP_EVENT pNetPnPEvent
2290 )
2291{
2292 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
2293 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
2294
2295 LogFlow(("vboxNetFltWinPtPnPHandler: Adapt %p, Event %d\n", pAdapt, pNetPnPEvent->NetEvent));
2296
2297 switch (pNetPnPEvent->NetEvent)
2298 {
2299 case NetEventSetPower:
2300 Status = vboxNetFltWinPtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
2301 break;
2302
2303 case NetEventReconfigure:
2304 DBGPRINT(("NetEventReconfigure, pAdapt(%p)", pAdapt));
2305 Status = vboxNetFltWinPtPnPNetEventReconfigure(pAdapt, pNetPnPEvent);
2306 break;
2307 case NetEventBindsComplete:
2308 DBGPRINT(("NetEventBindsComplete"));
2309 Status = vboxNetFltWinPtPnPNetEventBindsComplete(pAdapt, pNetPnPEvent);
2310 break;
2311 default:
2312 Status = NDIS_STATUS_SUCCESS;
2313 break;
2314 }
2315
2316 return Status;
2317}
2318#ifdef __cplusplus
2319# define PTCHARS_40(_p) ((_p).Ndis40Chars)
2320#else
2321# define PTCHARS_40(_p) (_p)
2322#endif
2323
2324/**
2325 * register the protocol edge
2326 */
2327DECLHIDDEN(NDIS_STATUS)
2328vboxNetFltWinPtRegister(
2329 IN PDRIVER_OBJECT DriverObject,
2330 IN PUNICODE_STRING RegistryPath
2331 )
2332{
2333 NDIS_STATUS Status;
2334 NDIS_PROTOCOL_CHARACTERISTICS PChars;
2335 NDIS_STRING Name;
2336
2337 /*
2338 * Now register the protocol.
2339 */
2340 NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
2341 PTCHARS_40(PChars).MajorNdisVersion = VBOXNETFLT_PROT_MAJOR_NDIS_VERSION;
2342 PTCHARS_40(PChars).MinorNdisVersion = VBOXNETFLT_PROT_MINOR_NDIS_VERSION;
2343
2344 /*
2345 * Make sure the protocol-name matches the service-name
2346 * (from the INF) under which this protocol is installed.
2347 * This is needed to ensure that NDIS can correctly determine
2348 * the binding and call us to bind to miniports below.
2349 */
2350 NdisInitUnicodeString(&Name, VBOXNETFLT_PROTOCOL_NAME); /* Protocol name */
2351 PTCHARS_40(PChars).Name = Name;
2352 PTCHARS_40(PChars).OpenAdapterCompleteHandler = vboxNetFltWinPtOpenAdapterComplete;
2353 PTCHARS_40(PChars).CloseAdapterCompleteHandler = vboxNetFltWinPtCloseAdapterComplete;
2354 PTCHARS_40(PChars).SendCompleteHandler = vboxNetFltWinPtSendComplete;
2355 PTCHARS_40(PChars).TransferDataCompleteHandler = vboxNetFltWinPtTransferDataComplete;
2356
2357 PTCHARS_40(PChars).ResetCompleteHandler = vboxNetFltWinPtResetComplete;
2358 PTCHARS_40(PChars).RequestCompleteHandler = vboxNetFltWinPtRequestComplete;
2359 PTCHARS_40(PChars).ReceiveHandler = vboxNetFltWinPtReceive;
2360 PTCHARS_40(PChars).ReceiveCompleteHandler = vboxNetFltWinPtReceiveComplete;
2361 PTCHARS_40(PChars).StatusHandler = vboxNetFltWinPtStatus;
2362 PTCHARS_40(PChars).StatusCompleteHandler = vboxNetFltWinPtStatusComplete;
2363 PTCHARS_40(PChars).BindAdapterHandler = vboxNetFltWinPtBindAdapter;
2364 PTCHARS_40(PChars).UnbindAdapterHandler = vboxNetFltWinPtUnbindAdapter;
2365 PTCHARS_40(PChars).UnloadHandler = vboxNetFltWinPtUnloadProtocol;
2366#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(DEBUG_NETFLT_RECV)
2367 PTCHARS_40(PChars).ReceivePacketHandler = vboxNetFltWinPtReceivePacket;
2368#else
2369 PTCHARS_40(PChars).ReceivePacketHandler = NULL;
2370#endif
2371 PTCHARS_40(PChars).PnPEventHandler= vboxNetFltWinPtPnPHandler;
2372
2373 NdisRegisterProtocol(&Status,
2374 &g_hProtHandle,
2375 &PChars,
2376 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
2377
2378 return Status;
2379}
2380
2381/**
2382 * deregister the protocol edge
2383 */
2384DECLHIDDEN(NDIS_STATUS)
2385vboxNetFltWinPtDeregister()
2386{
2387 NDIS_STATUS Status;
2388
2389 if (g_hProtHandle != NULL)
2390 {
2391 NdisDeregisterProtocol(&Status, g_hProtHandle);
2392 g_hProtHandle = NULL;
2393 }
2394
2395 return Status;
2396}
2397
2398#ifndef VBOX_NETFLT_ONDEMAND_BIND
2399/**
2400 * returns the protocol handle
2401 */
2402DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinPtGetHandle()
2403{
2404 return g_hProtHandle;
2405}
2406#endif
Note: See TracBrowser for help on using the repository browser.

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