VirtualBox

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

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

export vboxnetflt for Windows to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.2 KB
Line 
1/* $Id: VBoxNetFltPt-win.c 21343 2009-07-07 15:30:08Z 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 if(vboxNetFltWinGetPowerState(&pAdapt->PTState) != NdisDeviceStateD0
973 || vboxNetFltWinGetPowerState(&pAdapt->MPState) != NdisDeviceStateD0
974 || vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized
975 || vboxNetFltWinGetOpState(&pAdapt->MPState) > kVBoxNetDevOpState_Initialized)
976 {
977 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
978 bReturn = true;
979 break;
980 }
981
982 Assert(pAdapt->cReceivedPacketCount < MAX_RECEIVE_PACKET_ARRAY_SIZE);
983
984 /*
985 * pAdapt->ReceviePacketCount must be less than MAX_RECEIVE_PACKET_ARRAY_SIZE because
986 * the thread which held the pVElan->Lock before should already indicate the packet(s)
987 * up if pAdapt->ReceviePacketCount == MAX_RECEIVE_PACKET_ARRAY_SIZE.
988 */
989 pAdapt->aReceivedPackets[pAdapt->cReceivedPacketCount] = Packet;
990 pAdapt->cReceivedPacketCount++;
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)
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 DoIndicate = TRUE;
1009 }
1010 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1011 } while(0);
1012
1013 if(!bReturn)
1014 {
1015 if(DoIndicate)
1016 {
1017 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, PacketArray, NumberOfPackets);
1018 }
1019 }
1020 else
1021 {
1022 if (DoIndicate)
1023 {
1024 NumberOfPackets -= 1;
1025 }
1026 for (i = 0; i < NumberOfPackets; i++)
1027 {
1028 vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
1029 }
1030 }
1031}
1032
1033/**
1034 * This routine process the queued the packet, if anything is fine, indicate the packet
1035 * up, otherwise, return the packet to the underlying miniports.
1036 *
1037 * @param pAdapt - Pointer to the adpater structure.
1038 * @param bReturn - if true the packets should be returned without indication to the upper protocol
1039 * @return None. */
1040DECLHIDDEN(VOID)
1041vboxNetFltWinPtFlushReceiveQueue(
1042 IN PADAPT pAdapt,
1043 IN bool bReturn
1044 )
1045{
1046
1047 PNDIS_PACKET PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
1048 ULONG NumberOfPackets = 0, i;
1049 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1050 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1051
1052 do
1053 {
1054 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
1055
1056 if (pAdapt->cReceivedPacketCount > 0)
1057 {
1058 NdisMoveMemory(PacketArray,
1059 pAdapt->aReceivedPackets,
1060 pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
1061
1062 NumberOfPackets = pAdapt->cReceivedPacketCount;
1063 /*
1064 * So other thread can queue the received packets
1065 */
1066 pAdapt->cReceivedPacketCount = 0;
1067
1068 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1069
1070 if(!bReturn)
1071 {
1072 if(NumberOfPackets > 0)
1073 {
1074 Assert(pAdapt->hMiniportHandle);
1075
1076 /* we are here because the NetFlt is NOT active,
1077 * so no need for packet queueing here, simply indicate */
1078 NdisMIndicateReceivePacket(pAdapt->hMiniportHandle,
1079 PacketArray,
1080 NumberOfPackets);
1081 }
1082 break;
1083 }
1084 /*
1085 * We need return the packet here
1086 */
1087 for (i = 0; i < NumberOfPackets; i ++)
1088 {
1089 vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
1090 }
1091
1092 /* break to ensure we do not call RTSpinlockRelease extra time */
1093 break;
1094 }
1095
1096 /* we are here only in case pAdapt->cReceivedPacketCount == 0 */
1097 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1098 } while (FALSE);
1099}
1100
1101/**
1102 * ReceivePacket handler. Called by NDIS if the miniport below supports
1103 * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
1104 * and indicate the new packet to protocols above us. Any context for
1105 * packets indicated up must be kept in the MiniportReserved field.
1106 *
1107 * @param ProtocolBindingContext - Pointer to our adapter structure.
1108 * @param Packet - Pointer to the packet
1109 * @return INT == 0 -> We are done with the packet
1110 * != 0 -> We will keep the packet and call NdisReturnPackets() this
1111 * many times when done. */
1112static INT
1113vboxNetFltWinRecvPacketPassThru(
1114 IN PADAPT pAdapt,
1115 IN PNDIS_PACKET pPacket
1116 )
1117{
1118 NDIS_STATUS fStatus;
1119 PNDIS_PACKET pMyPacket;
1120
1121 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1122
1123 fStatus = vboxNetFltWinPrepareRecvPacket(pAdapt, pPacket, &pMyPacket, true);
1124
1125 Assert(pMyPacket);
1126
1127 if(pMyPacket != NULL)
1128 {
1129 if (fStatus == NDIS_STATUS_RESOURCES)
1130 {
1131 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
1132
1133 /*
1134 * Our ReturnPackets handler will not be called for this packet.
1135 * We should reclaim it right here.
1136 */
1137 NdisDprFreePacket(pMyPacket);
1138
1139 return 0;
1140 }
1141
1142 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, FALSE);
1143
1144 return 1;
1145 }
1146
1147 return 0;
1148}
1149
1150/**
1151 * process the packet receive in a "passthru" mode
1152 */
1153static NDIS_STATUS
1154vboxNetFltWinRecvPassThru(
1155 IN PADAPT pAdapt,
1156 IN PNDIS_PACKET pPacket)
1157{
1158
1159 NDIS_STATUS fStatus;
1160 PNDIS_PACKET pMyPacket;
1161 /*
1162 * The miniport below did indicate up a packet. Use information
1163 * from that packet to construct a new packet to indicate up.
1164 */
1165
1166 Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
1167
1168 /*
1169 * Get a packet off the pool and indicate that up
1170 */
1171 NdisDprAllocatePacket(&fStatus,
1172 &pMyPacket,
1173 pAdapt->hRecvPacketPoolHandle);
1174 Assert(fStatus == NDIS_STATUS_SUCCESS);
1175 if (fStatus == NDIS_STATUS_SUCCESS)
1176 {
1177 /*
1178 * Make our packet point to data from the original
1179 * packet. NOTE: this works only because we are
1180 * indicating a receive directly from the context of
1181 * our receive indication. If we need to queue this
1182 * packet and indicate it from another thread context,
1183 * we will also have to allocate a new buffer and copy
1184 * over the packet contents, OOB data and per-packet
1185 * information. This is because the packet data
1186 * is available only for the duration of this
1187 * receive indication call.
1188 */
1189 NDIS_PACKET_FIRST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
1190 NDIS_PACKET_LAST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
1191
1192 /*
1193 * Get the original packet (it could be the same packet as the
1194 * one received or a different one based on the number of layered
1195 * miniports below) and set it on the indicated packet so the OOB
1196 * data is visible correctly at protocols above.
1197 */
1198 NDIS_SET_ORIGINAL_PACKET(pMyPacket, NDIS_GET_ORIGINAL_PACKET(pPacket));
1199 NDIS_SET_PACKET_HEADER_SIZE(pMyPacket, NDIS_GET_PACKET_HEADER_SIZE(pPacket));
1200
1201 /*
1202 * Copy packet flags.
1203 */
1204 NdisGetPacketFlags(pMyPacket) = NdisGetPacketFlags(pPacket);
1205
1206 /*
1207 * Force protocols above to make a copy if they want to hang
1208 * on to data in this packet. This is because we are in our
1209 * Receive handler (not ReceivePacket) and we can't return a
1210 * ref count from here.
1211 */
1212 NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_RESOURCES);
1213
1214 /*
1215 * By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
1216 * this packet as soon as the call to NdisMIndicateReceivePacket
1217 * returns.
1218 *
1219 * NOTE: we queue the packet and indicate this packet immediately with
1220 * the already queued packets together. We have to the queue the packet
1221 * first because some versions of NDIS might call protocols'
1222 * ReceiveHandler(not ReceivePacketHandler) if the packet indicate status
1223 * is NDIS_STATUS_RESOURCES. If the miniport below indicates an array of
1224 * packets, some of them with status NDIS_STATUS_SUCCESS, some of them
1225 * with status NDIS_STATUS_RESOURCES, vboxNetFltWinPtReceive might be called, by
1226 * doing this way, we preserve the receive order of packets.
1227 */
1228 vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
1229 /*
1230 * Reclaim the indicated packet. Since we had set its status
1231 * to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
1232 * above are done with it.
1233 */
1234 NdisDprFreePacket(pMyPacket);
1235
1236 }
1237 return fStatus;
1238}
1239
1240#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
1241
1242
1243
1244
1245/**
1246 * process the ProtocolReceive in an "active" mode
1247 *
1248 * @return NDIS_STATUS_SUCCESS - the packet is processed
1249 * NDIS_STATUS_PENDING - the packet is being processed, we are waiting for the ProtocolTransferDataComplete to be called
1250 * NDIS_STATUS_NOT_ACCEPTED - the packet is not needed - typically this is because this is a loopback packet
1251 * NDIS_STATUS_FAILURE - packet processing failed
1252 */
1253static NDIS_STATUS
1254vboxNetFltWinPtReceiveActive(
1255 IN PADAPT pAdapt,
1256 IN NDIS_HANDLE MacReceiveContext,
1257 IN PVOID pHeaderBuffer,
1258 IN UINT cbHeaderBuffer,
1259 IN PVOID pLookaheadBuffer,
1260 IN UINT cbLookaheadBuffer,
1261 IN UINT cbPacket
1262 )
1263{
1264 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1265
1266 do
1267 {
1268 if (cbHeaderBuffer != ETH_HEADER_SIZE)
1269 {
1270 Status = NDIS_STATUS_NOT_ACCEPTED;
1271 break;
1272 }
1273
1274#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
1275 /* can check for loopback? check it*/
1276 if (cbPacket == cbLookaheadBuffer)
1277 {
1278 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1279 PINTNETSG pSG;
1280 PUCHAR pRcvData;
1281
1282#ifdef DEBUG_NETFLT_LOOPBACK
1283 /* TODO: can we check for loopback here ?
1284 * for now just get the complete SG and then decide if it is a loopback one */
1285 /* if loopback then quit */
1286#endif
1287 /* allocate SG buffer */
1288 Status = vboxNetFltWinAllocSG(cbPacket + cbHeaderBuffer, &pSG);
1289 if(Status != NDIS_STATUS_SUCCESS)
1290 {
1291 Assert(0);
1292 break;
1293 }
1294
1295 pRcvData = (PUCHAR)pSG->aSegs[0].pv;
1296
1297 NdisMoveMappedMemory(pRcvData, pHeaderBuffer, cbHeaderBuffer);
1298
1299 NdisCopyLookaheadData(pRcvData+cbHeaderBuffer,
1300 pLookaheadBuffer,
1301 cbLookaheadBuffer,
1302 pAdapt->fMacOptions);
1303#ifdef DEBUG_NETFLT_LOOPBACK
1304# error "implement (see comments in the sources below this #error:)"
1305 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1306 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1307 similar to that used in TrasferData handling should be used;
1308 */
1309
1310// /* check if it is a loopback */
1311//# ifdef VBOX_NETFLT_ONDEMAND_BIND
1312// if(vboxNetFltWinIsLoopedBackPacketSG(pAdapt, pSG))
1313//# else
1314// if(vboxNetFltWinIsLoopedBackPacketSG(pAdapt, pSG, true))
1315//# endif
1316// {
1317// Assert(0);
1318// vboxNetFltWinMemFree(pSG);
1319// Status = NDIS_STATUS_NOT_ACCEPTED;
1320// break;
1321// }
1322#endif
1323 /* enqueue SG */
1324#ifdef VBOX_NETFLT_ONDEMAND_BIND
1325 {
1326 uint32_t fFlags = MACS_EQUAL(((PRTNETETHERHDR)pRcvData)->SrcMac, pNetFlt->u.s.Mac) ?
1327 PACKET_SG | PACKET_MINE | PACKET_SRC_HOST : PACKET_SG | PACKET_MINE;
1328 Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, fFlags);
1329 }
1330#else
1331 Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, PACKET_SG | PACKET_MINE);
1332#endif
1333 if(Status != NDIS_STATUS_SUCCESS)
1334 {
1335 Assert(0);
1336 vboxNetFltWinMemFree(pSG);
1337 break;
1338 }
1339 }
1340 else
1341#endif /* #ifndef DEBUG_NETFLT_RECV_TRANSFERDATA */
1342 {
1343 PNDIS_PACKET pPacket;
1344 PNDIS_BUFFER pTransferBuffer;
1345 PNDIS_BUFFER pOrigBuffer;
1346 PUCHAR pMemBuf;
1347 UINT cbBuf = cbPacket + cbHeaderBuffer;
1348// PPACKET_INFO pInfo;
1349 UINT BytesTransferred;
1350 /* TODO: can check for loopback here ? */
1351 /* for now just get the complete complete packet and then decide if it is a looped back one */
1352 /* if loopback then quit with NDIS_STATUS_NOT_ACCEPTED
1353 * {
1354 * Status = NDIS_STATUS_NOT_ACCEPTED;
1355 * break;
1356 * }
1357 * */
1358
1359 /* allocate NDIS Packet buffer */
1360#ifdef VBOX_NETFLT_ONDEMAND_BIND
1361 /* use the Send packet pool for packet allocation */
1362 NdisAllocatePacket(&Status, &pPacket, pAdapt->hSendPacketPoolHandle);
1363#else
1364 NdisAllocatePacket(&Status, &pPacket, pAdapt->hRecvPacketPoolHandle);
1365#endif
1366 if(Status != NDIS_STATUS_SUCCESS)
1367 {
1368 Assert(0);
1369 break;
1370 }
1371
1372 /* set "don't loopback" flags */
1373 NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
1374
1375 Status = vboxNetFltWinMemAlloc(&pMemBuf, cbBuf);
1376 if(Status != NDIS_STATUS_SUCCESS)
1377 {
1378 Assert(0);
1379 NdisFreePacket(pPacket);
1380 break;
1381 }
1382#ifdef VBOX_NETFLT_ONDEMAND_BIND
1383 /* use the Send buffer pool for buffer allocation */
1384 NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
1385#else
1386 NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
1387#endif
1388 if(Status != NDIS_STATUS_SUCCESS)
1389 {
1390 Assert(0);
1391 Status = NDIS_STATUS_FAILURE;
1392 NdisFreePacket(pPacket);
1393 vboxNetFltWinMemFree(pMemBuf);
1394 break;
1395 }
1396
1397#ifdef VBOX_NETFLT_ONDEMAND_BIND
1398 /* use the Send buffer pool for buffer allocation */
1399 NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf, cbBuf);
1400#else
1401 NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf, cbBuf);
1402#endif
1403 if(Status != NDIS_STATUS_SUCCESS)
1404 {
1405 Assert(0);
1406 Status = NDIS_STATUS_FAILURE;
1407 NdisFreeBuffer(pTransferBuffer);
1408 NdisFreePacket(pPacket);
1409 vboxNetFltWinMemFree(pMemBuf);
1410 break;
1411 }
1412
1413 NdisChainBufferAtBack(pPacket, pTransferBuffer);
1414
1415 NdisMoveMappedMemory(pMemBuf, pHeaderBuffer, cbHeaderBuffer);
1416
1417#ifndef VBOX_NETFLT_ONDEMAND_BIND
1418 vboxNetFltWinPutPacketToList(&pAdapt->TransferDataList, pPacket, pOrigBuffer);
1419#endif
1420
1421#ifdef DEBUG_NETFLT_RECV_TRANSFERDATA
1422 if(cbPacket == cbLookaheadBuffer)
1423 {
1424 NdisCopyLookaheadData(pMemBuf+cbHeaderBuffer,
1425 pLookaheadBuffer,
1426 cbLookaheadBuffer,
1427 pAdapt->fMacOptions);
1428 }
1429 else
1430#endif
1431 {
1432 Assert(cbPacket > cbLookaheadBuffer);
1433
1434 NdisTransferData(
1435 &Status,
1436 pAdapt->hBindingHandle,
1437 MacReceiveContext,
1438 0, /* ByteOffset */
1439 cbPacket,
1440 pPacket,
1441 &BytesTransferred);
1442 }
1443 if(Status != NDIS_STATUS_PENDING)
1444 {
1445 vboxNetFltWinPtTransferDataComplete(pAdapt, pPacket, Status, BytesTransferred);
1446 }
1447 }
1448 } while(0);
1449
1450 return Status;
1451}
1452
1453
1454/**
1455 * Handle receive data indicated up by the miniport below. We pass
1456 * it along to the protocol above us.
1457 *
1458 * If the miniport below indicates packets, NDIS would more
1459 * likely call us at our ReceivePacket handler. However we
1460 * might be called here in certain situations even though
1461 * the miniport below has indicated a receive packet, e.g.
1462 * if the miniport had set packet status to NDIS_STATUS_RESOURCES.
1463 *
1464 * @param ProtocolBindingContext
1465 * @param MacReceiveContext
1466 * @param pHeaderBuffer
1467 * @param cbHeaderBuffer
1468 * @param pLookAheadBuffer
1469 * @param cbLookAheadBuffer
1470 * @param cbPacket
1471 * @return NDIS_STATUS_SUCCESS if we processed the receive successfully,
1472 * NDIS_STATUS_XXX error code if we discarded it. */
1473static NDIS_STATUS
1474vboxNetFltWinPtReceive(
1475 IN NDIS_HANDLE ProtocolBindingContext,
1476 IN NDIS_HANDLE MacReceiveContext,
1477 IN PVOID pHeaderBuffer,
1478 IN UINT cbHeaderBuffer,
1479 IN PVOID pLookAheadBuffer,
1480 IN UINT cbLookAheadBuffer,
1481 IN UINT cbPacket
1482 )
1483{
1484 PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
1485 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
1486 PVBOXNETFLTINS pNetFltIf;
1487#ifdef VBOX_NETFLT_ONDEMAND_BIND
1488#if 0
1489 uint32_t fFlags;
1490#endif
1491
1492 pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
1493 if(pNetFltIf)
1494 {
1495 do
1496 {
1497#if 0
1498 pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
1499 if(pPacket)
1500 {
1501# ifdef DEBUG_NETFLT_LOOPBACK
1502# error "implement (see comments in the sources below this #error:)"
1503 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1504 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1505 similar to that used in TrasferData handling should be used;
1506 */
1507
1508// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
1509# else
1510 if(vboxNetFltWinIsLoopedBackPacket(pPacket) || cbHeaderBuffer != ETH_HEADER_SIZE)
1511# endif
1512
1513 {
1514// Assert(0);
1515 /* nothing else to do here, just return the packet */
1516// NdisReturnPackets(&pPacket, 1);
1517// break;
1518 }
1519
1520 fFlags = MACS_EQUAL(((PRTNETETHERHDR)pHeaderBuffer)->SrcMac, pNetFltIf->u.s.Mac) ?
1521 PACKET_COPY | PACKET_SRC_HOST : PACKET_COPY;
1522 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, fFlags);
1523 if(Status == NDIS_STATUS_SUCCESS)
1524 {
1525 NdisReturnPackets(&pPacket, 1);
1526 pAdapt = NULL;
1527 pNetFltIf = NULL;
1528 break;
1529 }
1530 }
1531#endif
1532 Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
1533 pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
1534 if(NT_SUCCESS(Status))
1535 {
1536 if(Status != NDIS_STATUS_NOT_ACCEPTED)
1537 {
1538 pAdapt = NULL;
1539 pNetFltIf = NULL;
1540 }
1541 else
1542 {
1543 /* this is a looopback packet, nothing to do here */
1544 }
1545 break;
1546 }
1547 } while(0);
1548
1549 if(pNetFltIf)
1550 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1551 if(pAdapt)
1552 vboxNetFltWinDereferenceAdapt(pAdapt);
1553
1554
1555#if 0
1556 if(pPacket)
1557 {
1558 NdisReturnPackets(&pPacket, 1);
1559 }
1560#endif
1561 /* we are here because the vboxNetFltWinPtReceiveActive returned pending,
1562 * which means our ProtocolDataTransferComplete we will called,
1563 * so return SUCCESS instead of NOT_ACCEPTED ?? */
1564// return NDIS_STATUS_SUCCESS;
1565 }
1566 return NDIS_STATUS_NOT_ACCEPTED;
1567#else /* if NOT defined VBOX_NETFLT_ONDEMAND_BIND */
1568 PNDIS_PACKET pPacket = NULL;
1569 bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
1570 if(fAdaptActive)
1571 {
1572 do
1573 {
1574#ifndef DEBUG_NETFLT_RECV_NOPACKET
1575 /*
1576 * Get at the packet, if any, indicated up by the miniport below.
1577 */
1578 pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
1579 if (pPacket != NULL)
1580 {
1581 do
1582 {
1583#ifdef DEBUG_NETFLT_LOOPBACK
1584# error "implement (see comments in the sources below this #error:)"
1585 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1586 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1587 similar to that used in TrasferData handling should be used;
1588 */
1589
1590// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, true))
1591#else
1592 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1593#endif
1594
1595 {
1596 Assert(0);
1597 /* nothing else to do here, just return the packet */
1598 //NdisReturnPackets(&pPacket, 1);
1599 Status = NDIS_STATUS_NOT_ACCEPTED;
1600 break;
1601 }
1602
1603 if(pNetFltIf)
1604 {
1605 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_COPY);
1606 if(Status == NDIS_STATUS_SUCCESS)
1607 {
1608 //NdisReturnPackets(&pPacket, 1);
1609 fAdaptActive = false;
1610 pNetFltIf = NULL;
1611 break;
1612 }
1613 }
1614
1615 Status = vboxNetFltWinRecvPassThru(pAdapt, pPacket);
1616 /* we are done with packet processing, and we will
1617 * not receive packet return event for this packet,
1618 * fAdaptActive should be true to ensure we release adapt*/
1619 Assert(fAdaptActive);
1620 } while(FALSE);
1621
1622 if(Status == NDIS_STATUS_SUCCESS || Status == NDIS_STATUS_NOT_ACCEPTED)
1623 {
1624 break;
1625 }
1626 }
1627#endif /* todo: remove */
1628 if(pNetFltIf)
1629 {
1630 Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
1631 pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
1632 if(NT_SUCCESS(Status))
1633 {
1634 if(Status != NDIS_STATUS_NOT_ACCEPTED)
1635 {
1636 fAdaptActive = false;
1637 pNetFltIf = NULL;
1638 }
1639 else
1640 {
1641 /* this is a loopback packet, nothing to do here */
1642 }
1643 break;
1644 }
1645 }
1646
1647 /* Fall through if the miniport below us has either not
1648 * indicated a packet or we could not allocate one */
1649 if(pPacket != NULL)
1650 {
1651 /*
1652 * We are here because we failed to allocate packet
1653 */
1654 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
1655 }
1656
1657 /* we are done with packet processing, and we will
1658 * not receive packet return event for this packet,
1659 * fAdaptActive should be true to ensure we release adapt*/
1660 Assert(fAdaptActive);
1661
1662 pAdapt->bIndicateRcvComplete = TRUE;
1663 switch (pAdapt->Medium)
1664 {
1665 case NdisMedium802_3:
1666 case NdisMediumWan:
1667 NdisMEthIndicateReceive(pAdapt->hMiniportHandle,
1668 MacReceiveContext,
1669 (PCHAR)pHeaderBuffer,
1670 cbHeaderBuffer,
1671 pLookAheadBuffer,
1672 cbLookAheadBuffer,
1673 cbPacket);
1674 break;
1675 default:
1676 Assert(FALSE);
1677 break;
1678 }
1679 } while(0);
1680
1681 if(pNetFltIf)
1682 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1683 if(fAdaptActive)
1684 vboxNetFltWinDereferenceAdapt(pAdapt);
1685 }
1686 else
1687 {
1688 Status = NDIS_STATUS_FAILURE;
1689 }
1690
1691 return Status;
1692#endif
1693}
1694
1695/**
1696 * Called by the adapter below us when it is done indicating a batch of
1697 * received packets.
1698 *
1699 * @param ProtocolBindingContext Pointer to our adapter structure.
1700 * @return None */
1701static VOID
1702vboxNetFltWinPtReceiveComplete(
1703 IN NDIS_HANDLE ProtocolBindingContext
1704 )
1705{
1706#ifndef VBOX_NETFLT_ONDEMAND_BIND
1707 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
1708 ULONG NumberOfPackets = 0;
1709
1710 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
1711
1712 if ((pAdapt->hMiniportHandle != NULL)
1713 /* && (pAdapt->MPDeviceState == NdisDeviceStateD0) */
1714 && (pAdapt->bIndicateRcvComplete == TRUE))
1715 {
1716 switch (pAdapt->Medium)
1717 {
1718 case NdisMedium802_3:
1719 case NdisMediumWan:
1720 NdisMEthIndicateReceiveComplete(pAdapt->hMiniportHandle);
1721 break;
1722 default:
1723 Assert(FALSE);
1724 break;
1725 }
1726 }
1727
1728 pAdapt->bIndicateRcvComplete = FALSE;
1729#endif
1730}
1731
1732/**
1733 * ReceivePacket handler. Called by NDIS if the miniport below supports
1734 * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
1735 * and indicate the new packet to protocols above us. Any context for
1736 * packets indicated up must be kept in the MiniportReserved field.
1737 *
1738 * @param ProtocolBindingContext - Pointer to our adapter structure.
1739 * @param Packet - Pointer to the packet
1740 * @return == 0 -> We are done with the packet,
1741 * != 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
1742 */
1743static INT
1744vboxNetFltWinPtReceivePacket(
1745 IN NDIS_HANDLE ProtocolBindingContext,
1746 IN PNDIS_PACKET pPacket
1747 )
1748{
1749 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
1750 INT cRefCount = 0;
1751 PVBOXNETFLTINS pNetFltIf;
1752#ifdef VBOX_NETFLT_ONDEMAND_BIND
1753 PNDIS_BUFFER pBuffer;
1754 PVOID pVA;
1755 UINT cbLength;
1756 uint32_t fFlags;
1757
1758 pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
1759
1760 if(pNetFltIf)
1761 {
1762 NDIS_STATUS Status;
1763 bool bResources;
1764 do
1765 {
1766#ifdef DEBUG_NETFLT_LOOPBACK
1767# error "implement (see comments in the sources below this #error:)"
1768 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1769 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1770 similar to that used in TrasferData handling should be used;
1771 */
1772
1773// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
1774#else
1775 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1776#endif
1777
1778 {
1779 Assert(0);
1780 NdisReturnPackets(&pPacket, 1);
1781 break;
1782 }
1783 bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
1784
1785 NdisQueryPacket(pPacket, NULL, NULL, &pBuffer, NULL);
1786 if(!pBuffer)
1787 {
1788 Assert(0);
1789 NdisReturnPackets(&pPacket, 1);
1790 cRefCount = 0;
1791 break;
1792 }
1793
1794 NdisQueryBufferSafe(pBuffer, &pVA, &cbLength, NormalPagePriority);
1795 if(!pVA || !cbLength)
1796 {
1797 Assert(0);
1798 NdisReturnPackets(&pPacket, 1);
1799 cRefCount = 0;
1800 break;
1801 }
1802
1803 fFlags = MACS_EQUAL(((PRTNETETHERHDR)pVA)->SrcMac, pNetFltIf->u.s.Mac) ? PACKET_SRC_HOST : 0;
1804
1805 Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, bResources ? fFlags | PACKET_COPY : fFlags);
1806 if(Status == NDIS_STATUS_SUCCESS)
1807 {
1808 if(bResources)
1809 {
1810 cRefCount = 0;
1811 NdisReturnPackets(&pPacket, 1);
1812 }
1813 else
1814 {
1815 cRefCount = 1;
1816 }
1817 pNetFltIf = NULL;
1818 pAdapt = NULL;
1819 break;
1820 }
1821 else
1822 {
1823 Assert(0);
1824 NdisReturnPackets(&pPacket, 1);
1825 cRefCount = 0;
1826 break;
1827 }
1828 } while (0);
1829
1830 if(pNetFltIf)
1831 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1832 if(pAdapt)
1833 vboxNetFltWinDereferenceAdapt(pAdapt);
1834 return cRefCount;
1835 }
1836 /* we are here because we are inactive, simply return the packet */
1837 NdisReturnPackets(&pPacket, 1);
1838 return 0;
1839#else
1840 bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
1841 if(fAdaptActive)
1842 {
1843 do
1844 {
1845#ifdef DEBUG_NETFLT_LOOPBACK
1846# error "implement (see comments in the sources below this #error:)"
1847 /* @todo FIXME no need for the PPACKET_INFO mechanism here;
1848 instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
1849 similar to that used in TrasferData handling should be used;
1850 */
1851
1852// if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, true))
1853#else
1854 if(vboxNetFltWinIsLoopedBackPacket(pPacket))
1855#endif
1856
1857 {
1858 Assert(0);
1859 Log(("lb_rp"));
1860
1861 /* nothing else to do here, just return the packet */
1862 cRefCount = 0;
1863 //NdisReturnPackets(&pPacket, 1);
1864 break;
1865 }
1866
1867 if(pNetFltIf)
1868 {
1869 bool bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
1870 NDIS_STATUS fStatus;
1871
1872 /*TODO: remove this assert.
1873 * this is a temporary assert for debugging purposes:
1874 * we're probably doing something wrong with the packets if the miniport reports NDIS_STATUS_RESOURCES */
1875 Assert(!bResources);
1876
1877 fStatus = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, bResources ? PACKET_COPY : 0);
1878 if(fStatus == NDIS_STATUS_SUCCESS)
1879 {
1880 pNetFltIf = NULL;
1881 fAdaptActive = false;
1882 if(bResources)
1883 {
1884 cRefCount = 0;
1885 //NdisReturnPackets(&pPacket, 1);
1886 }
1887 else
1888 {
1889 cRefCount = 1;
1890 }
1891 break;
1892 }
1893 else
1894 {
1895 Assert(0);
1896 }
1897 }
1898
1899 cRefCount = vboxNetFltWinRecvPacketPassThru(pAdapt, pPacket);
1900 if(cRefCount)
1901 {
1902 Assert(cRefCount == 1);
1903 fAdaptActive = false;
1904 }
1905
1906 } while(FALSE);
1907
1908 if(pNetFltIf)
1909 vboxNetFltWinDereferenceNetFlt(pNetFltIf);
1910 if(fAdaptActive)
1911 vboxNetFltWinDereferenceAdapt(pAdapt);
1912 }
1913 else
1914 {
1915 cRefCount = 0;
1916 //NdisReturnPackets(&pPacket, 1);
1917 }
1918
1919 return cRefCount;
1920#endif
1921}
1922
1923/**
1924 * This routine is called from NDIS to notify our protocol edge of a
1925 * reconfiguration of parameters for either a specific binding (pAdapt
1926 * is not NULL), or global parameters if any (pAdapt is NULL).
1927 *
1928 * @param pAdapt - Pointer to our adapter structure.
1929 * @param pNetPnPEvent - the reconfigure event
1930 * @return NDIS_STATUS_SUCCESS */
1931static NDIS_STATUS
1932vboxNetFltWinPtPnPNetEventReconfigure(
1933 IN PADAPT pAdapt,
1934 IN PNET_PNP_EVENT pNetPnPEvent
1935 )
1936{
1937 NDIS_STATUS ReconfigStatus = NDIS_STATUS_SUCCESS;
1938 NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
1939
1940 do
1941 {
1942 /*
1943 * Is this is a global reconfiguration notification ?
1944 */
1945 if (pAdapt == NULL)
1946 {
1947 /*
1948 * An important event that causes this notification to us is if
1949 * one of our upper-edge miniport instances was enabled after being
1950 * disabled earlier, e.g. from Device Manager in Win2000. Note that
1951 * NDIS calls this because we had set up an association between our
1952 * miniport and protocol entities by calling NdisIMAssociateMiniport.
1953 *
1954 * Since we would have torn down the lower binding for that miniport,
1955 * we need NDIS' assistance to re-bind to the lower miniport. The
1956 * call to NdisReEnumerateProtocolBindings does exactly that.
1957 */
1958 NdisReEnumerateProtocolBindings (g_hProtHandle);
1959 break;
1960 }
1961
1962 ReconfigStatus = NDIS_STATUS_SUCCESS;
1963
1964 } while(FALSE);
1965
1966 LogFlow(("<==PtPNPNetEventReconfigure: pAdapt %p\n", pAdapt));
1967
1968 return ReconfigStatus;
1969}
1970
1971static NDIS_STATUS
1972vboxNetFltWinPtPnPNetEventBindsComplete(
1973 IN PADAPT pAdapt,
1974 IN PNET_PNP_EVENT pNetPnPEvent
1975 )
1976{
1977 return NDIS_STATUS_SUCCESS;
1978}
1979
1980DECLHIDDEN(bool) vboxNetFltWinPtCloseAdapter(PADAPT pAdapt, PNDIS_STATUS pStatus)
1981{
1982 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
1983 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1984
1985 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
1986
1987 if(pAdapt->bClosingAdapter)
1988 {
1989 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1990 Assert(0);
1991 return false;
1992 }
1993 if (pAdapt->hBindingHandle == NULL)
1994 {
1995 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
1996 Assert(0);
1997 return false;
1998 }
1999
2000 pAdapt->bClosingAdapter = true;
2001 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2002
2003 /*
2004 * Close the binding below. and wait for it to complete
2005 */
2006 NdisResetEvent(&pAdapt->hEvent);
2007
2008 NdisCloseAdapter(pStatus, pAdapt->hBindingHandle);
2009
2010 if (*pStatus == NDIS_STATUS_PENDING)
2011 {
2012 NdisWaitEvent(&pAdapt->hEvent, 0);
2013 *pStatus = pAdapt->Status;
2014 }
2015
2016 Assert (*pStatus == NDIS_STATUS_SUCCESS);
2017
2018 pAdapt->hBindingHandle = NULL;
2019
2020 return true;
2021}
2022
2023/**
2024 * This is a notification to our protocol edge of the power state
2025 * of the lower miniport. If it is going to a low-power state, we must
2026 * wait here for all outstanding sends and requests to complete.
2027 *
2028 * @param pAdapt - Pointer to the adpater structure
2029 * @param pNetPnPEvent - The Net Pnp Event. this contains the new device state
2030 * @return NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols.
2031 * */
2032static NDIS_STATUS
2033vboxNetFltWinPtPnPNetEventSetPower(
2034 IN PADAPT pAdapt,
2035 IN PNET_PNP_EVENT pNetPnPEvent
2036 )
2037{
2038 PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
2039 NDIS_DEVICE_POWER_STATE PrevDeviceState = vboxNetFltWinGetPowerState(&pAdapt->PTState);
2040 NDIS_STATUS ReturnStatus;
2041 PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
2042 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
2043
2044 ReturnStatus = NDIS_STATUS_SUCCESS;
2045
2046 /*
2047 * Set the Internal Device State, this blocks all new sends or receives
2048 */
2049 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
2050
2051 vboxNetFltWinSetPowerState(&pAdapt->PTState, *pDeviceState);
2052
2053 /*
2054 * Check if the miniport below is going to a low power state.
2055 */
2056 if (vboxNetFltWinGetPowerState(&pAdapt->PTState) > NdisDeviceStateD0)
2057 {
2058 /*
2059 * If the miniport below is going to standby, fail all incoming requests
2060 */
2061 if (PrevDeviceState == NdisDeviceStateD0)
2062 {
2063 pAdapt->bStandingBy = TRUE;
2064 }
2065 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2066#ifndef VBOX_NETFLT_ONDEMAND_BIND
2067
2068 vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
2069
2070 vboxNetFltWinWaitDereference(&pAdapt->MPState);
2071#endif
2072
2073 /*
2074 * Wait for outstanding sends and requests to complete.
2075 */
2076 vboxNetFltWinWaitDereference(&pAdapt->PTState);
2077
2078#ifndef VBOX_NETFLT_ONDEMAND_BIND
2079 while (ASMAtomicUoReadBool((volatile bool *)&pAdapt->bOutstandingRequests))
2080 {
2081 /*
2082 * sleep till outstanding requests complete
2083 */
2084 vboxNetFltWinSleep(2);
2085 }
2086
2087 /*
2088 * If the below miniport is going to low power state, complete the queued request
2089 */
2090 RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
2091 if (pAdapt->bQueuedRequest)
2092 {
2093 pAdapt->bQueuedRequest = FALSE;
2094 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2095 vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE);
2096 }
2097 else
2098 {
2099 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2100 }
2101#endif
2102
2103 Assert(NdisPacketPoolUsage(pAdapt->hSendPacketPoolHandle) == 0);
2104#ifndef VBOX_NETFLT_ONDEMAND_BIND
2105 Assert(NdisPacketPoolUsage(pAdapt->hRecvPacketPoolHandle) == 0);
2106 Assert(pAdapt->bOutstandingRequests == FALSE);
2107#endif
2108 }
2109 else
2110 {
2111 /*
2112 * If the physical miniport is powering up (from Low power state to D0),
2113 * clear the flag
2114 */
2115 if (PrevDeviceState > NdisDeviceStateD0)
2116 {
2117 pAdapt->bStandingBy = FALSE;
2118 }
2119
2120#ifdef VBOX_NETFLT_ONDEMAND_BIND
2121 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2122#else
2123 /*
2124 * The device below is being turned on. If we had a request
2125 * pending, send it down now.
2126 */
2127 if (pAdapt->bQueuedRequest == TRUE)
2128 {
2129 NDIS_STATUS Status;
2130
2131 pAdapt->bQueuedRequest = FALSE;
2132
2133 pAdapt->bOutstandingRequests = TRUE;
2134 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2135
2136 NdisRequest(&Status,
2137 pAdapt->hBindingHandle,
2138 &pAdapt->Request);
2139
2140 if (Status != NDIS_STATUS_PENDING)
2141 {
2142 vboxNetFltWinPtRequestComplete(pAdapt,
2143 &pAdapt->Request,
2144 Status);
2145
2146 }
2147 }
2148 else
2149 {
2150 RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
2151 }
2152
2153#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
2154
2155 }
2156
2157 return ReturnStatus;
2158}
2159
2160/**
2161 * This is called by NDIS to notify us of a PNP event related to a lower
2162 * binding. Based on the event, this dispatches to other helper routines.
2163 *
2164 * @param ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
2165 * for "global" notifications
2166 * @param pNetPnPEvent - Pointer to the PNP event to be processed.
2167 * @return NDIS_STATUS code indicating status of event processing.
2168 * */
2169static NDIS_STATUS
2170vboxNetFltWinPtPnPHandler(
2171 IN NDIS_HANDLE ProtocolBindingContext,
2172 IN PNET_PNP_EVENT pNetPnPEvent
2173 )
2174{
2175 PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
2176 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
2177
2178 LogFlow(("vboxNetFltWinPtPnPHandler: Adapt %p, Event %d\n", pAdapt, pNetPnPEvent->NetEvent));
2179
2180 switch (pNetPnPEvent->NetEvent)
2181 {
2182 case NetEventSetPower:
2183 Status = vboxNetFltWinPtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
2184 break;
2185
2186 case NetEventReconfigure:
2187 DBGPRINT(("NetEventReconfigure, pAdapt(%p)", pAdapt));
2188 Status = vboxNetFltWinPtPnPNetEventReconfigure(pAdapt, pNetPnPEvent);
2189 break;
2190 case NetEventBindsComplete:
2191 DBGPRINT(("NetEventBindsComplete"));
2192 Status = vboxNetFltWinPtPnPNetEventBindsComplete(pAdapt, pNetPnPEvent);
2193 break;
2194 default:
2195 Status = NDIS_STATUS_SUCCESS;
2196 break;
2197 }
2198
2199 return Status;
2200}
2201#ifdef __cplusplus
2202# define PTCHARS_40(_p) ((_p).Ndis40Chars)
2203#else
2204# define PTCHARS_40(_p) (_p)
2205#endif
2206
2207/**
2208 * register the protocol edge
2209 */
2210DECLHIDDEN(NDIS_STATUS)
2211vboxNetFltWinPtRegister(
2212 IN PDRIVER_OBJECT DriverObject,
2213 IN PUNICODE_STRING RegistryPath
2214 )
2215{
2216 NDIS_STATUS Status;
2217 NDIS_PROTOCOL_CHARACTERISTICS PChars;
2218 NDIS_STRING Name;
2219
2220 /*
2221 * Now register the protocol.
2222 */
2223 NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
2224 PTCHARS_40(PChars).MajorNdisVersion = VBOXNETFLT_PROT_MAJOR_NDIS_VERSION;
2225 PTCHARS_40(PChars).MinorNdisVersion = VBOXNETFLT_PROT_MINOR_NDIS_VERSION;
2226
2227 /*
2228 * Make sure the protocol-name matches the service-name
2229 * (from the INF) under which this protocol is installed.
2230 * This is needed to ensure that NDIS can correctly determine
2231 * the binding and call us to bind to miniports below.
2232 */
2233 NdisInitUnicodeString(&Name, VBOXNETFLT_PROTOCOL_NAME); /* Protocol name */
2234 PTCHARS_40(PChars).Name = Name;
2235 PTCHARS_40(PChars).OpenAdapterCompleteHandler = vboxNetFltWinPtOpenAdapterComplete;
2236 PTCHARS_40(PChars).CloseAdapterCompleteHandler = vboxNetFltWinPtCloseAdapterComplete;
2237 PTCHARS_40(PChars).SendCompleteHandler = vboxNetFltWinPtSendComplete;
2238 PTCHARS_40(PChars).TransferDataCompleteHandler = vboxNetFltWinPtTransferDataComplete;
2239
2240 PTCHARS_40(PChars).ResetCompleteHandler = vboxNetFltWinPtResetComplete;
2241 PTCHARS_40(PChars).RequestCompleteHandler = vboxNetFltWinPtRequestComplete;
2242 PTCHARS_40(PChars).ReceiveHandler = vboxNetFltWinPtReceive;
2243 PTCHARS_40(PChars).ReceiveCompleteHandler = vboxNetFltWinPtReceiveComplete;
2244 PTCHARS_40(PChars).StatusHandler = vboxNetFltWinPtStatus;
2245 PTCHARS_40(PChars).StatusCompleteHandler = vboxNetFltWinPtStatusComplete;
2246 PTCHARS_40(PChars).BindAdapterHandler = vboxNetFltWinPtBindAdapter;
2247 PTCHARS_40(PChars).UnbindAdapterHandler = vboxNetFltWinPtUnbindAdapter;
2248 PTCHARS_40(PChars).UnloadHandler = vboxNetFltWinPtUnloadProtocol;
2249#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(DEBUG_NETFLT_RECV)
2250 PTCHARS_40(PChars).ReceivePacketHandler = vboxNetFltWinPtReceivePacket;
2251#else
2252 PTCHARS_40(PChars).ReceivePacketHandler = NULL;
2253#endif
2254 PTCHARS_40(PChars).PnPEventHandler= vboxNetFltWinPtPnPHandler;
2255
2256 NdisRegisterProtocol(&Status,
2257 &g_hProtHandle,
2258 &PChars,
2259 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
2260
2261 return Status;
2262}
2263
2264/**
2265 * deregister the protocol edge
2266 */
2267DECLHIDDEN(NDIS_STATUS)
2268vboxNetFltWinPtDeregister()
2269{
2270 NDIS_STATUS Status;
2271
2272 if (g_hProtHandle != NULL)
2273 {
2274 NdisDeregisterProtocol(&Status, g_hProtHandle);
2275 g_hProtHandle = NULL;
2276 }
2277
2278 return Status;
2279}
2280
2281#ifndef VBOX_NETFLT_ONDEMAND_BIND
2282/**
2283 * returns the protocol handle
2284 */
2285DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinPtGetHandle()
2286{
2287 return g_hProtHandle;
2288}
2289#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