VirtualBox

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

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

netflt-adp/win: additional bugfix

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