VirtualBox

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

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

netflt/win: fix Protocol/Miniport reserved field usage

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