VirtualBox

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

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

netflt/win: fix for proper cleaning of rx packet array on power change

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