cygwin on 64 bit defines __CYGWIN__ and not __CYGWIN32__
[ipfw-google.git] / modified_passthru / protocol.c
1 /*++
2
3 Copyright(c) 1992-2000  Microsoft Corporation
4
5 Module Name:
6
7     protocol.c
8
9 Abstract:
10
11     Ndis Intermediate Miniport driver sample. This is a passthru driver.
12
13 Author:
14
15 Environment:
16
17
18 Revision History:
19
20
21 --*/
22
23
24 #include "precomp.h"
25 #pragma hdrstop
26
27 #define MAX_PACKET_POOL_SIZE 0x0000FFFF
28 #define MIN_PACKET_POOL_SIZE 0x000000FF
29
30 //
31 // NDIS version as 0xMMMMmmmm, where M=Major/m=minor (0x00050001 = 5.1); 
32 // initially unknown (0)
33 // 
34 ULONG       NdisDotSysVersion =  0x0;
35
36
37 #define NDIS_SYS_VERSION_51       0x00050001
38
39
40 VOID
41 PtBindAdapter(
42     OUT PNDIS_STATUS            Status,
43     IN  NDIS_HANDLE             BindContext,
44     IN  PNDIS_STRING            DeviceName,
45     IN  PVOID                   SystemSpecific1,
46     IN  PVOID                   SystemSpecific2
47     )
48 /*++
49
50 Routine Description:
51
52     Called by NDIS to bind to a miniport below.
53
54 Arguments:
55
56     Status            - Return status of bind here.
57     BindContext        - Can be passed to NdisCompleteBindAdapter if this call is pended.
58     DeviceName         - Device name to bind to. This is passed to NdisOpenAdapter.
59     SystemSpecific1    - Can be passed to NdisOpenProtocolConfiguration to read per-binding information
60     SystemSpecific2    - Unused
61
62 Return Value:
63
64     NDIS_STATUS_PENDING    if this call is pended. In this case call NdisCompleteBindAdapter
65     to complete.
66     Anything else          Completes this call synchronously
67
68 --*/
69 {
70     NDIS_HANDLE                     ConfigHandle = NULL;
71     PNDIS_CONFIGURATION_PARAMETER   Param;
72     NDIS_STRING                     DeviceStr = NDIS_STRING_CONST("UpperBindings");
73     NDIS_STRING                     NdisVersionStr = NDIS_STRING_CONST("NdisVersion");
74     PADAPT                          pAdapt = NULL;
75     NDIS_STATUS                     Sts;
76     UINT                            MediumIndex;
77     ULONG                           TotalSize;
78     BOOLEAN                         NoCleanUpNeeded = FALSE;
79
80
81     UNREFERENCED_PARAMETER(BindContext);
82     UNREFERENCED_PARAMETER(SystemSpecific2);
83     
84     DBGPRINT(("==> Protocol BindAdapter\n"));
85
86     do
87     {
88         //
89         // Access the configuration section for our binding-specific
90         // parameters.
91         //
92         NdisOpenProtocolConfiguration(Status,
93                                        &ConfigHandle,
94                                        SystemSpecific1);
95
96         if (*Status != NDIS_STATUS_SUCCESS)
97         {
98             break;
99         }
100         if (NdisDotSysVersion == 0)
101         {
102             NdisReadConfiguration(Status,
103                                   &Param,
104                                   ConfigHandle,
105                                   &NdisVersionStr,        // "NdisVersion"
106                                   NdisParameterInteger);
107             if (*Status != NDIS_STATUS_SUCCESS)
108             {
109                 break;
110             }
111             
112             NdisDotSysVersion = Param->ParameterData.IntegerData;
113         }
114                         
115
116         //
117         // Read the "UpperBindings" reserved key that contains a list
118         // of device names representing our miniport instances corresponding
119         // to this lower binding. Since this is a 1:1 IM driver, this key
120         // contains exactly one name.
121         //
122         // If we want to implement a N:1 mux driver (N adapter instances
123         // over a single lower binding), then UpperBindings will be a
124         // MULTI_SZ containing a list of device names - we would loop through
125         // this list, calling NdisIMInitializeDeviceInstanceEx once for
126         // each name in it.
127         //
128         NdisReadConfiguration(Status,
129                               &Param,
130                               ConfigHandle,
131                               &DeviceStr,
132                               NdisParameterString);
133         if (*Status != NDIS_STATUS_SUCCESS)
134         {
135             break;
136         }
137
138         //
139         // Allocate memory for the Adapter structure. This represents both the
140         // protocol context as well as the adapter structure when the miniport
141         // is initialized.
142         //
143         // In addition to the base structure, allocate space for the device
144         // instance string.
145         //
146         TotalSize = sizeof(ADAPT) + Param->ParameterData.StringData.MaximumLength;
147
148         NdisAllocateMemoryWithTag(&pAdapt, TotalSize, TAG);
149
150         if (pAdapt == NULL)
151         {
152             *Status = NDIS_STATUS_RESOURCES;
153             break;
154         }
155
156         //
157         // Initialize the adapter structure. We copy in the IM device
158         // name as well, because we may need to use it in a call to
159         // NdisIMCancelInitializeDeviceInstance. The string returned
160         // by NdisReadConfiguration is active (i.e. available) only
161         // for the duration of this call to our BindAdapter handler.
162         //
163         NdisZeroMemory(pAdapt, TotalSize);
164         pAdapt->DeviceName.MaximumLength = Param->ParameterData.StringData.MaximumLength;
165         pAdapt->DeviceName.Length = Param->ParameterData.StringData.Length;
166         pAdapt->DeviceName.Buffer = (PWCHAR)((ULONG_PTR)pAdapt + sizeof(ADAPT));
167         NdisMoveMemory(pAdapt->DeviceName.Buffer,
168                        Param->ParameterData.StringData.Buffer,
169                        Param->ParameterData.StringData.MaximumLength);
170
171
172
173         NdisInitializeEvent(&pAdapt->Event);
174         NdisAllocateSpinLock(&pAdapt->Lock);
175
176         //
177         // Allocate a packet pool for sends. We need this to pass sends down.
178         // We cannot use the same packet descriptor that came down to our send
179         // handler (see also NDIS 5.1 packet stacking).
180         //
181         NdisAllocatePacketPoolEx(Status,
182                                    &pAdapt->SendPacketPoolHandle,
183                                    MIN_PACKET_POOL_SIZE,
184                                    MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
185                                    sizeof(SEND_RSVD));
186
187         if (*Status != NDIS_STATUS_SUCCESS)
188         {
189             break;
190         }
191
192         //
193         // Allocate a packet pool for receives. We need this to indicate receives.
194         // Same consideration as sends (see also NDIS 5.1 packet stacking).
195         //
196         NdisAllocatePacketPoolEx(Status,
197                                    &pAdapt->RecvPacketPoolHandle,
198                                    MIN_PACKET_POOL_SIZE,
199                                    MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
200                                    PROTOCOL_RESERVED_SIZE_IN_PACKET);
201
202         if (*Status != NDIS_STATUS_SUCCESS)
203         {
204             break;
205         }
206
207         //
208         // Now open the adapter below and complete the initialization
209         //
210         NdisOpenAdapter(Status,
211                           &Sts,
212                           &pAdapt->BindingHandle,
213                           &MediumIndex,
214                           MediumArray,
215                           sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
216                           ProtHandle,
217                           pAdapt,
218                           DeviceName,
219                           0,
220                           NULL);
221
222         if (*Status == NDIS_STATUS_PENDING)
223         {
224             NdisWaitEvent(&pAdapt->Event, 0);
225             *Status = pAdapt->Status;
226         }
227
228         if (*Status != NDIS_STATUS_SUCCESS)
229         {
230             break;
231         }
232         PtReferenceAdapt(pAdapt);
233
234 #pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "Ndis guarantees MediumIndex to be within bounds");
235         pAdapt->Medium = MediumArray[MediumIndex];
236
237         //
238         // Now ask NDIS to initialize our miniport (upper) edge.
239         // Set the flag below to synchronize with a possible call
240         // to our protocol Unbind handler that may come in before
241         // our miniport initialization happens.
242         //
243         pAdapt->MiniportInitPending = TRUE;
244         NdisInitializeEvent(&pAdapt->MiniportInitEvent);
245
246         PtReferenceAdapt(pAdapt);
247
248         *Status = NdisIMInitializeDeviceInstanceEx(DriverHandle,
249                                            &pAdapt->DeviceName,
250                                            pAdapt);
251
252         if (*Status != NDIS_STATUS_SUCCESS)
253         {
254             if (pAdapt->MiniportIsHalted == TRUE)
255             {
256                 NoCleanUpNeeded = TRUE;
257             }
258             
259             DBGPRINT(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n",
260                 pAdapt, *Status));
261             
262             if (PtDereferenceAdapt(pAdapt))
263             {
264                 pAdapt = NULL;
265             }
266             
267             break;
268         }
269         
270         PtDereferenceAdapt(pAdapt);
271
272     } while(FALSE);
273
274     //
275     // Close the configuration handle now - see comments above with
276     // the call to NdisIMInitializeDeviceInstanceEx.
277     //
278     if (ConfigHandle != NULL)
279     {
280         NdisCloseConfiguration(ConfigHandle);
281     }
282
283     if ((*Status != NDIS_STATUS_SUCCESS) && (NoCleanUpNeeded == FALSE))
284     {
285         if (pAdapt != NULL)
286         {
287             if (pAdapt->BindingHandle != NULL)
288             {
289                 NDIS_STATUS    LocalStatus;
290
291                 //
292                 // Close the binding we opened above.
293                 //
294
295                 NdisResetEvent(&pAdapt->Event);
296                 
297                 NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
298                 pAdapt->BindingHandle = NULL;
299
300                 if (LocalStatus == NDIS_STATUS_PENDING)
301                 {
302                      NdisWaitEvent(&pAdapt->Event, 0);
303                      LocalStatus = pAdapt->Status;
304
305                      
306                 }
307                 if (PtDereferenceAdapt(pAdapt))
308                 {
309                      pAdapt = NULL;
310                 }
311             }
312         }
313     }
314
315
316     DBGPRINT(("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *Status));
317 }
318
319
320 VOID
321 PtOpenAdapterComplete(
322     IN  NDIS_HANDLE             ProtocolBindingContext,
323     IN  NDIS_STATUS             Status,
324     IN  NDIS_STATUS             OpenErrorStatus
325     )
326 /*++
327
328 Routine Description:
329
330     Completion routine for NdisOpenAdapter issued from within the PtBindAdapter. Simply
331     unblock the caller.
332
333 Arguments:
334
335     ProtocolBindingContext    Pointer to the adapter
336     Status                    Status of the NdisOpenAdapter call
337     OpenErrorStatus            Secondary status(ignored by us).
338
339 Return Value:
340
341     None
342
343 --*/
344 {
345     PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
346     
347     UNREFERENCED_PARAMETER(OpenErrorStatus);
348     
349     DBGPRINT(("==> PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
350     pAdapt->Status = Status;
351     NdisSetEvent(&pAdapt->Event);
352 }
353
354
355 VOID
356 PtUnbindAdapter(
357     OUT PNDIS_STATUS           Status,
358     IN  NDIS_HANDLE            ProtocolBindingContext,
359     IN  NDIS_HANDLE            UnbindContext
360     )
361 /*++
362
363 Routine Description:
364
365     Called by NDIS when we are required to unbind to the adapter below.
366     This functions shares functionality with the miniport's HaltHandler.
367     The code should ensure that NdisCloseAdapter and NdisFreeMemory is called
368     only once between the two functions
369
370 Arguments:
371
372     Status                    Placeholder for return status
373     ProtocolBindingContext    Pointer to the adapter structure
374     UnbindContext            Context for NdisUnbindComplete() if this pends
375
376 Return Value:
377
378     Status for NdisIMDeinitializeDeviceContext
379
380 --*/
381 {
382     PADAPT         pAdapt =(PADAPT)ProtocolBindingContext;
383     NDIS_STATUS    LocalStatus;
384
385     UNREFERENCED_PARAMETER(UnbindContext);
386     
387     DBGPRINT(("==> PtUnbindAdapter: Adapt %p\n", pAdapt));
388
389     //
390     // Set the flag that the miniport below is unbinding, so the request handlers will
391     // fail any request comming later
392     // 
393     NdisAcquireSpinLock(&pAdapt->Lock);
394     pAdapt->UnbindingInProcess = TRUE;
395     if (pAdapt->QueuedRequest == TRUE)
396     {
397         pAdapt->QueuedRequest = FALSE;
398         NdisReleaseSpinLock(&pAdapt->Lock);
399
400         PtRequestComplete(pAdapt,
401                          &pAdapt->Request,
402                          NDIS_STATUS_FAILURE );
403
404     }
405     else
406     {
407         NdisReleaseSpinLock(&pAdapt->Lock);
408     }
409 #ifndef WIN9X
410     //
411     // Check if we had called NdisIMInitializeDeviceInstanceEx and
412     // we are awaiting a call to MiniportInitialize.
413     //
414     if (pAdapt->MiniportInitPending == TRUE)
415     {
416         //
417         // Try to cancel the pending IMInit process.
418         //
419         LocalStatus = NdisIMCancelInitializeDeviceInstance(
420                         DriverHandle,
421                         &pAdapt->DeviceName);
422
423         if (LocalStatus == NDIS_STATUS_SUCCESS)
424         {
425             //
426             // Successfully cancelled IM Initialization; our
427             // Miniport Initialize routine will not be called
428             // for this device.
429             //
430             pAdapt->MiniportInitPending = FALSE;
431             ASSERT(pAdapt->MiniportHandle == NULL);
432         }
433         else
434         {
435             //
436             // Our Miniport Initialize routine will be called
437             // (may be running on another thread at this time).
438             // Wait for it to finish.
439             //
440             NdisWaitEvent(&pAdapt->MiniportInitEvent, 0);
441             ASSERT(pAdapt->MiniportInitPending == FALSE);
442         }
443
444     }
445 #endif // !WIN9X
446
447     //
448     // Call NDIS to remove our device-instance. We do most of the work
449     // inside the HaltHandler.
450     //
451     // The Handle will be NULL if our miniport Halt Handler has been called or
452     // if the IM device was never initialized
453     //
454     
455     if (pAdapt->MiniportHandle != NULL)
456     {
457         *Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle);
458
459         if (*Status != NDIS_STATUS_SUCCESS)
460         {
461             *Status = NDIS_STATUS_FAILURE;
462         }
463     }
464     else
465     {
466         //
467         // We need to do some work here. 
468         // Close the binding below us 
469         // and release the memory allocated.
470         //
471         
472         if(pAdapt->BindingHandle != NULL)
473         {
474             NdisResetEvent(&pAdapt->Event);
475
476             NdisCloseAdapter(Status, pAdapt->BindingHandle);
477
478             //
479             // Wait for it to complete
480             //
481             if(*Status == NDIS_STATUS_PENDING)
482             {
483                  NdisWaitEvent(&pAdapt->Event, 0);
484                  *Status = pAdapt->Status;
485             }
486             pAdapt->BindingHandle = NULL;
487         }
488         else
489         {
490             //
491             // Both Our MiniportHandle and Binding Handle  should not be NULL.
492             //
493             *Status = NDIS_STATUS_FAILURE;
494             ASSERT(0);
495         }
496
497         //
498         //    Free the memory here, if was not released earlier(by calling the HaltHandler)
499         //
500         MPFreeAllPacketPools(pAdapt);
501         NdisFreeSpinLock(&pAdapt->Lock);
502         NdisFreeMemory(pAdapt, 0, 0);
503     }
504
505     DBGPRINT(("<== PtUnbindAdapter: Adapt %p\n", pAdapt));
506 }
507
508 VOID
509 PtUnloadProtocol(
510     VOID
511 )
512 {
513     NDIS_STATUS Status;
514
515     if (ProtHandle != NULL)
516     {
517         NdisDeregisterProtocol(&Status, ProtHandle);
518         ProtHandle = NULL;
519     }
520
521     DBGPRINT(("PtUnloadProtocol: done!\n"));
522 }
523
524
525
526 VOID
527 PtCloseAdapterComplete(
528     IN    NDIS_HANDLE            ProtocolBindingContext,
529     IN    NDIS_STATUS            Status
530     )
531 /*++
532
533 Routine Description:
534
535     Completion for the CloseAdapter call.
536
537 Arguments:
538
539     ProtocolBindingContext    Pointer to the adapter structure
540     Status                    Completion status
541
542 Return Value:
543
544     None.
545
546 --*/
547 {
548     PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
549
550     DBGPRINT(("CloseAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
551     pAdapt->Status = Status;
552     NdisSetEvent(&pAdapt->Event);
553 }
554
555
556 VOID
557 PtResetComplete(
558     IN  NDIS_HANDLE            ProtocolBindingContext,
559     IN  NDIS_STATUS            Status
560     )
561 /*++
562
563 Routine Description:
564
565     Completion for the reset.
566
567 Arguments:
568
569     ProtocolBindingContext    Pointer to the adapter structure
570     Status                    Completion status
571
572 Return Value:
573
574     None.
575
576 --*/
577 {
578
579     UNREFERENCED_PARAMETER(ProtocolBindingContext);
580     UNREFERENCED_PARAMETER(Status);
581     //
582     // We never issue a reset, so we should not be here.
583     //
584     ASSERT(0);
585 }
586
587
588 VOID
589 PtRequestComplete(
590     IN  NDIS_HANDLE            ProtocolBindingContext,
591     IN  PNDIS_REQUEST          NdisRequest,
592     IN  NDIS_STATUS            Status
593     )
594 /*++
595
596 Routine Description:
597
598     Completion handler for the previously posted request. All OIDS
599     are completed by and sent to the same miniport that they were requested for.
600     If Oid == OID_PNP_QUERY_POWER then the data structure needs to returned with all entries =
601     NdisDeviceStateUnspecified
602
603 Arguments:
604
605     ProtocolBindingContext    Pointer to the adapter structure
606     NdisRequest                The posted request
607     Status                    Completion status
608
609 Return Value:
610
611     None
612
613 --*/
614 {
615     PADAPT        pAdapt = (PADAPT)ProtocolBindingContext;
616     NDIS_OID      Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;
617
618     //
619     // Since our request is not outstanding anymore
620     //
621     ASSERT(pAdapt->OutstandingRequests == TRUE);
622
623     pAdapt->OutstandingRequests = FALSE;
624
625     //
626     // Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
627     //
628     switch (NdisRequest->RequestType)
629     {
630       case NdisRequestQueryInformation:
631
632         //
633         // We never pass OID_PNP_QUERY_POWER down.
634         //
635         ASSERT(Oid != OID_PNP_QUERY_POWER);
636
637         if ((Oid == OID_PNP_CAPABILITIES) && (Status == NDIS_STATUS_SUCCESS))
638         {
639             MPQueryPNPCapabilities(pAdapt, &Status);
640         }
641         *pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
642         *pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
643
644         if (((Oid == OID_GEN_MAC_OPTIONS) 
645               && (Status == NDIS_STATUS_SUCCESS))
646               && (NdisDotSysVersion >= NDIS_SYS_VERSION_51))
647         {
648             //
649             // Only do this on Windows XP or greater (NDIS.SYS v 5.1); 
650             // do not do in Windows 2000 (NDIS.SYS v 5.0))
651             //
652                 
653             //
654             // Remove the no-loopback bit from mac-options. In essence we are
655             // telling NDIS that we can handle loopback. We don't, but the
656             // interface below us does. If we do not do this, then loopback
657             // processing happens both below us and above us. This is wasteful
658             // at best and if Netmon is running, it will see multiple copies
659             // of loopback packets when sniffing above us.
660             //
661             // Only the lowest miniport is a stack of layered miniports should
662             // ever report this bit set to NDIS.
663             //
664             *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
665         }
666
667         NdisMQueryInformationComplete(pAdapt->MiniportHandle,
668                                       Status);
669         break;
670
671       case NdisRequestSetInformation:
672
673         ASSERT( Oid != OID_PNP_SET_POWER);
674
675         *pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
676         *pAdapt->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
677         NdisMSetInformationComplete(pAdapt->MiniportHandle,
678                                     Status);
679         break;
680
681       default:
682         ASSERT(0);
683         break;
684     }
685     
686 }
687
688
689 VOID
690 PtStatus(
691     IN  NDIS_HANDLE         ProtocolBindingContext,
692     IN  NDIS_STATUS         GeneralStatus,
693     IN  PVOID               StatusBuffer,
694     IN  UINT                StatusBufferSize
695     )
696 /*++
697
698 Routine Description:
699
700     Status handler for the lower-edge(protocol).
701
702 Arguments:
703
704     ProtocolBindingContext    Pointer to the adapter structure
705     GeneralStatus             Status code
706     StatusBuffer              Status buffer
707     StatusBufferSize          Size of the status buffer
708
709 Return Value:
710
711     None
712
713 --*/
714 {
715     PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
716
717     //
718     // Pass up this indication only if the upper edge miniport is initialized
719     // and powered on. Also ignore indications that might be sent by the lower
720     // miniport when it isn't at D0.
721     //
722     if ((pAdapt->MiniportHandle != NULL)  &&
723         (pAdapt->MPDeviceState == NdisDeviceStateD0) &&
724         (pAdapt->PTDeviceState == NdisDeviceStateD0))    
725     {
726         if ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) || 
727             (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT))
728         {
729             
730             pAdapt->LastIndicatedStatus = GeneralStatus;
731         }
732         NdisMIndicateStatus(pAdapt->MiniportHandle,
733                             GeneralStatus,
734                             StatusBuffer,
735                             StatusBufferSize);
736     }
737     //
738     // Save the last indicated media status 
739     //
740     else
741     {
742         if ((pAdapt->MiniportHandle != NULL) && 
743         ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) || 
744             (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT)))
745         {
746             pAdapt->LatestUnIndicateStatus = GeneralStatus;
747         }
748     }
749     
750 }
751
752
753 VOID
754 PtStatusComplete(
755     IN NDIS_HANDLE            ProtocolBindingContext
756     )
757 /*++
758
759 Routine Description:
760
761
762 Arguments:
763
764
765 Return Value:
766
767
768 --*/
769 {
770     PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
771
772     //
773     // Pass up this indication only if the upper edge miniport is initialized
774     // and powered on. Also ignore indications that might be sent by the lower
775     // miniport when it isn't at D0.
776     //
777     if ((pAdapt->MiniportHandle != NULL)  &&
778         (pAdapt->MPDeviceState == NdisDeviceStateD0) &&
779         (pAdapt->PTDeviceState == NdisDeviceStateD0))    
780     {
781         NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
782     }
783 }
784
785
786 VOID
787 PtSendComplete(
788     IN  NDIS_HANDLE            ProtocolBindingContext,
789     IN  PNDIS_PACKET           Packet,
790     IN  NDIS_STATUS            Status
791     )
792 /*++
793
794 Routine Description:
795
796     Called by NDIS when the miniport below had completed a send. We should
797     complete the corresponding upper-edge send this represents.
798
799 Arguments:
800
801     ProtocolBindingContext - Points to ADAPT structure
802     Packet - Low level packet being completed
803     Status - status of send
804
805 Return Value:
806
807     None
808
809 --*/
810 {
811     PADAPT            pAdapt = (PADAPT)ProtocolBindingContext;
812     PNDIS_PACKET      Pkt; 
813     NDIS_HANDLE       PoolHandle;
814
815 #ifdef NDIS51
816     //
817     // Packet stacking:
818     //
819     // Determine if the packet we are completing is the one we allocated. If so, then
820     // get the original packet from the reserved area and completed it and free the
821     // allocated packet. If this is the packet that was sent down to us, then just
822     // complete it
823     //
824     PoolHandle = NdisGetPoolFromPacket(Packet);
825     if (PoolHandle != pAdapt->SendPacketPoolHandle)
826     {
827         //
828         // We had passed down a packet belonging to the protocol above us.
829         //
830         // DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));
831
832         NdisMSendComplete(pAdapt->MiniportHandle,
833                           Packet,
834                           Status);
835     }
836     else
837 #endif // NDIS51
838     {
839         PSEND_RSVD        SendRsvd;
840
841         SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
842         Pkt = SendRsvd->OriginalPkt;
843
844 #if 1   // IPFW - new code
845         //DbgPrint("SendComplete: packet %p pkt %p\n", Packet, Pkt);
846         if (Pkt == NULL) { //this is a reinjected packet, with no 'father'
847                 CleanupReinjected(Packet, SendRsvd->pMbuf, pAdapt);
848                 return;
849         }
850 #endif /* IPFW */
851     
852 #ifndef WIN9X
853         NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
854 #endif
855     
856         NdisDprFreePacket(Packet);
857
858         NdisMSendComplete(pAdapt->MiniportHandle,
859                                  Pkt,
860                                  Status);
861     }
862     //
863     // Decrease the outstanding send count
864     //
865     ADAPT_DECR_PENDING_SENDS(pAdapt);
866 }       
867
868
869 VOID
870 PtTransferDataComplete(
871     IN  NDIS_HANDLE         ProtocolBindingContext,
872     IN  PNDIS_PACKET        Packet,
873     IN  NDIS_STATUS         Status,
874     IN  UINT                BytesTransferred
875     )
876 /*++
877
878 Routine Description:
879
880     Entry point called by NDIS to indicate completion of a call by us
881     to NdisTransferData.
882
883     See notes under SendComplete.
884
885 Arguments:
886
887 Return Value:
888
889 --*/
890 {
891     PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
892
893     if(pAdapt->MiniportHandle)
894     {
895         NdisMTransferDataComplete(pAdapt->MiniportHandle,
896                                   Packet,
897                                   Status,
898                                   BytesTransferred);
899     }
900 }
901
902
903 NDIS_STATUS
904 PtReceive(
905     IN  NDIS_HANDLE         ProtocolBindingContext,
906     IN  NDIS_HANDLE         MacReceiveContext,
907     IN  PVOID               HeaderBuffer,
908     IN  UINT                HeaderBufferSize,
909     IN  PVOID               LookAheadBuffer,
910     IN  UINT                LookAheadBufferSize,
911     IN  UINT                PacketSize
912     )
913 /*++
914
915 Routine Description:
916
917     Handle receive data indicated up by the miniport below. We pass
918     it along to the protocol above us.
919
920     If the miniport below indicates packets, NDIS would more
921     likely call us at our ReceivePacket handler. However we
922     might be called here in certain situations even though
923     the miniport below has indicated a receive packet, e.g.
924     if the miniport had set packet status to NDIS_STATUS_RESOURCES.
925         
926 Arguments:
927
928     <see DDK ref page for ProtocolReceive>
929
930 Return Value:
931
932     NDIS_STATUS_SUCCESS if we processed the receive successfully,
933     NDIS_STATUS_XXX error code if we discarded it.
934
935 --*/
936 {
937     PADAPT            pAdapt = (PADAPT)ProtocolBindingContext;
938     PNDIS_PACKET      MyPacket, Packet = NULL;
939     NDIS_STATUS       Status = NDIS_STATUS_SUCCESS;
940     ULONG             Proc = KeGetCurrentProcessorNumber();      
941     
942     if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState > NdisDeviceStateD0))
943     {
944         Status = NDIS_STATUS_FAILURE;
945     }
946     else do
947     {
948         //
949         // Get at the packet, if any, indicated up by the miniport below.
950         //
951         Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
952         if (Packet != NULL)
953         {               
954             //
955             // The miniport below did indicate up a packet. Use information
956             // from that packet to construct a new packet to indicate up.
957             //
958
959 #ifdef NDIS51
960             //
961             // NDIS 5.1 NOTE: Do not reuse the original packet in indicating
962             // up a receive, even if there is sufficient packet stack space.
963             // If we had to do so, we would have had to overwrite the
964             // status field in the original packet to NDIS_STATUS_RESOURCES,
965             // and it is not allowed for protocols to overwrite this field
966             // in received packets.
967             //
968 #endif // NDIS51
969
970             //
971             // Get a packet off the pool and indicate that up
972             //
973             NdisDprAllocatePacket(&Status,
974                                 &MyPacket,
975                                 pAdapt->RecvPacketPoolHandle);
976
977             if (Status == NDIS_STATUS_SUCCESS)
978             {
979                 //
980                 // Make our packet point to data from the original
981                 // packet. NOTE: this works only because we are
982                 // indicating a receive directly from the context of
983                 // our receive indication. If we need to queue this
984                 // packet and indicate it from another thread context,
985                 // we will also have to allocate a new buffer and copy
986                 // over the packet contents, OOB data and per-packet
987                 // information. This is because the packet data
988                 // is available only for the duration of this
989                 // receive indication call.
990                 //
991                 NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
992                 NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
993
994                 //
995                 // Get the original packet (it could be the same packet as the
996                 // one received or a different one based on the number of layered
997                 // miniports below) and set it on the indicated packet so the OOB
998                 // data is visible correctly at protocols above.  If the IM driver 
999                 // modifies the packet in any way it should not set the new packet's
1000                 // original packet equal to the original packet of the packet that 
1001                 // was indicated to it from the underlying driver, in this case, the 
1002                 // IM driver should also ensure that the related per packet info should
1003                 // be copied to the new packet.
1004                 // we can set the original packet to the original packet of the packet
1005                 // indicated from the underlying driver because the driver doesn't modify
1006                 // the data content in the packet.
1007                 //
1008                 NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
1009                 NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
1010
1011                 //
1012                 // Copy packet flags.
1013                 //
1014                 NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
1015
1016                 //
1017                 // Force protocols above to make a copy if they want to hang
1018                 // on to data in this packet. This is because we are in our
1019                 // Receive handler (not ReceivePacket) and we can't return a
1020                 // ref count from here.
1021                 //
1022                 NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
1023
1024                 //
1025                 // By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
1026                 // this packet as soon as the call to NdisMIndicateReceivePacket
1027                 // returns.
1028                 //
1029
1030                 if (pAdapt->MiniportHandle != NULL)
1031                 {
1032 #if 1   /* IPFW: query the firewall */
1033                                         int     ret;
1034                                         ret = ipfw2_qhandler_w32(MyPacket, INCOMING,
1035                                                 ProtocolBindingContext);
1036                                         if (ret != PASS)
1037                                         return 0; //otherwise simply continue
1038 #endif /* end of IPFW code */
1039                     NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
1040                 }
1041
1042                 //
1043                 // Reclaim the indicated packet. Since we had set its status
1044                 // to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
1045                 // above are done with it.
1046                 //
1047                 NdisDprFreePacket(MyPacket);
1048
1049                 break;
1050             }
1051         }
1052         else
1053         {
1054             //
1055             // The miniport below us uses the old-style (not packet)
1056             // receive indication. Fall through.
1057             //
1058         }
1059
1060         //
1061         // Fall through if the miniport below us has either not
1062         // indicated a packet or we could not allocate one
1063         //
1064         pAdapt->ReceivedIndicationFlags[Proc] = TRUE;
1065         if (pAdapt->MiniportHandle == NULL)
1066         {
1067             break;
1068         }
1069         switch (pAdapt->Medium)
1070         {
1071             case NdisMedium802_3:
1072             case NdisMediumWan:
1073                                 //DbgPrint("EthIndicateReceive context %p, header at %p len %u, lookahead at %p len %u, packetsize %u\n",ProtocolBindingContext,HeaderBuffer,HeaderBufferSize,LookAheadBuffer,LookAheadBufferSize,PacketSize);
1074                                 //hexdump(HeaderBuffer,HeaderBufferSize+LookAheadBufferSize,"EthIndicateReceive");
1075                         {
1076                                 int ret = ipfw2_qhandler_w32_oldstyle(INCOMING, ProtocolBindingContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize);
1077                                 if (ret != PASS)
1078                                         return NDIS_STATUS_SUCCESS;
1079                         }
1080                 NdisMEthIndicateReceive(pAdapt->MiniportHandle,
1081                                              MacReceiveContext,
1082                                              HeaderBuffer,
1083                                              HeaderBufferSize,
1084                                              LookAheadBuffer,
1085                                              LookAheadBufferSize,
1086                                              PacketSize);
1087                 break;
1088
1089             case NdisMedium802_5:
1090                 NdisMTrIndicateReceive(pAdapt->MiniportHandle,
1091                                             MacReceiveContext,
1092                                             HeaderBuffer,
1093                                             HeaderBufferSize,
1094                                             LookAheadBuffer,
1095                                             LookAheadBufferSize,
1096                                             PacketSize);
1097                 break;
1098
1099 #if FDDI
1100                   case NdisMediumFddi:
1101                          NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
1102                                                                                           MacReceiveContext,
1103                                                                                           HeaderBuffer,
1104                                                                                           HeaderBufferSize,
1105                                                                                           LookAheadBuffer,
1106                                                                                           LookAheadBufferSize,
1107                                                                                           PacketSize);
1108                          break;
1109 #endif
1110                   default:
1111                          ASSERT(FALSE);
1112                          break;
1113                 }
1114
1115     } while(FALSE);
1116
1117     return Status;
1118 }
1119
1120
1121 VOID
1122 PtReceiveComplete(
1123     IN NDIS_HANDLE        ProtocolBindingContext
1124     )
1125 /*++
1126
1127 Routine Description:
1128
1129     Called by the adapter below us when it is done indicating a batch of
1130     received packets.
1131
1132 Arguments:
1133
1134     ProtocolBindingContext    Pointer to our adapter structure.
1135
1136 Return Value:
1137
1138     None
1139
1140 --*/
1141 {
1142     PADAPT        pAdapt =(PADAPT)ProtocolBindingContext;
1143     ULONG         Proc = KeGetCurrentProcessorNumber();      
1144         
1145         /* Warning: this is a poor implementation of the PtReceiveComplete
1146          * made by MS, and it's a well known (but never fixed) issue.
1147          * Since the ProcessorNumber here can be different from the one
1148          * that processed the PtReceive, sometimes NdisMEthIndicateReceiveComplete
1149          * will not be called, causing poor performance in the incoming traffic.
1150          * In our driver, PtReceive is called for IP packets ONLY by particulary 
1151          * old NIC drivers, and the poor performance can be seen even 
1152          * in traffic not handled by ipfw or dummynet.
1153          * Fortunately, this is quite rare, all the incoming IP packets
1154          * will arrive through PtReceivePacket, and this callback will never
1155          * be called. For reinjected traffic, a workaround is done
1156          * commuting the ReceivedIndicationFlag and calling
1157          * NdisMEthIndicateReceiveComplete manually for each packet.
1158          */
1159
1160     if (((pAdapt->MiniportHandle != NULL)
1161                 && (pAdapt->MPDeviceState == NdisDeviceStateD0))
1162                 && (pAdapt->ReceivedIndicationFlags[Proc]))
1163     {
1164         switch (pAdapt->Medium)
1165         {
1166             case NdisMedium802_3:
1167             case NdisMediumWan:
1168                 NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
1169                 break;
1170
1171                   case NdisMedium802_5:
1172                         NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
1173                         break;
1174 #if FDDI
1175                   case NdisMediumFddi:
1176                         NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
1177                         break;
1178 #endif
1179                   default:
1180                         ASSERT(FALSE);
1181                         break;
1182                 }
1183         }
1184
1185     pAdapt->ReceivedIndicationFlags[Proc] = FALSE;
1186 }
1187
1188
1189 INT
1190 PtReceivePacket(
1191     IN NDIS_HANDLE            ProtocolBindingContext,
1192     IN PNDIS_PACKET           Packet
1193     )
1194 /*++
1195
1196 Routine Description:
1197
1198     ReceivePacket handler. Called by NDIS if the miniport below supports
1199     NDIS 4.0 style receives. Re-package the buffer chain in a new packet
1200     and indicate the new packet to protocols above us. Any context for
1201     packets indicated up must be kept in the MiniportReserved field.
1202
1203     NDIS 5.1 - packet stacking - if there is sufficient "stack space" in
1204     the packet passed to us, we can use the same packet in a receive
1205     indication.
1206
1207 Arguments:
1208
1209     ProtocolBindingContext - Pointer to our adapter structure.
1210     Packet - Pointer to the packet
1211
1212 Return Value:
1213
1214     == 0 -> We are done with the packet
1215     != 0 -> We will keep the packet and call NdisReturnPackets() this
1216             many times when done.
1217 --*/
1218 {
1219     PADAPT              pAdapt =(PADAPT)ProtocolBindingContext;
1220     NDIS_STATUS         Status;
1221     PNDIS_PACKET        MyPacket;
1222     BOOLEAN             Remaining;
1223
1224     //
1225     // Drop the packet silently if the upper miniport edge isn't initialized or
1226     // the miniport edge is in low power state
1227     //
1228     if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState > NdisDeviceStateD0))
1229     {
1230           return 0;
1231     }
1232
1233 #ifdef NDIS51
1234     //
1235     // Check if we can reuse the same packet for indicating up.
1236     // See also: PtReceive(). 
1237     //
1238     (VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);
1239     if (0 && Remaining)
1240     {
1241         //
1242         // We can reuse "Packet". Indicate it up and be done with it.
1243         //
1244         Status = NDIS_GET_PACKET_STATUS(Packet);
1245         NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet, 1);
1246         return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
1247     }
1248 #endif // NDIS51
1249
1250     //
1251     // Get a packet off the pool and indicate that up
1252     //
1253     NdisDprAllocatePacket(&Status,
1254                            &MyPacket,
1255                            pAdapt->RecvPacketPoolHandle);
1256
1257     if (Status == NDIS_STATUS_SUCCESS)
1258     {
1259         PRECV_RSVD            RecvRsvd;
1260
1261         RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
1262         RecvRsvd->OriginalPkt = Packet;
1263
1264         NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
1265         NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
1266
1267         //
1268         // Get the original packet (it could be the same packet as the one
1269         // received or a different one based on the number of layered miniports
1270         // below) and set it on the indicated packet so the OOB data is visible
1271         // correctly to protocols above us.
1272         //
1273         NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
1274
1275         //
1276         // Set Packet Flags
1277         //
1278         NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
1279
1280         Status = NDIS_GET_PACKET_STATUS(Packet);
1281
1282         NDIS_SET_PACKET_STATUS(MyPacket, Status);
1283         NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
1284
1285         if (pAdapt->MiniportHandle != NULL)
1286         {
1287 #if 1   /* IPFW: query the firewall */
1288             int ret;
1289             ret = ipfw2_qhandler_w32(MyPacket, INCOMING,
1290                         ProtocolBindingContext);
1291             if (ret != PASS)
1292                         return 0; //otherwise simply continue
1293 #endif /* end of IPFW code */
1294             NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
1295         }
1296
1297         //
1298         // Check if we had indicated up the packet with NDIS_STATUS_RESOURCES
1299         // NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket) for this since
1300         // it might have changed! Use the value saved in the local variable.
1301         //
1302         if (Status == NDIS_STATUS_RESOURCES)
1303         {
1304             //
1305             // Our ReturnPackets handler will not be called for this packet.
1306             // We should reclaim it right here.
1307             //
1308             NdisDprFreePacket(MyPacket);
1309         }
1310
1311         return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
1312     }
1313     else
1314     {
1315         //
1316         // We are out of packets. Silently drop it.
1317         //
1318         return(0);
1319     }
1320 }
1321
1322
1323 NDIS_STATUS
1324 PtPNPHandler(
1325     IN NDIS_HANDLE        ProtocolBindingContext,
1326     IN PNET_PNP_EVENT     pNetPnPEvent
1327     )
1328
1329 /*++
1330 Routine Description:
1331
1332     This is called by NDIS to notify us of a PNP event related to a lower
1333     binding. Based on the event, this dispatches to other helper routines.
1334
1335     NDIS 5.1: forward this event to the upper protocol(s) by calling
1336     NdisIMNotifyPnPEvent.
1337
1338 Arguments:
1339
1340     ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
1341                 for "global" notifications
1342
1343     pNetPnPEvent - Pointer to the PNP event to be processed.
1344
1345 Return Value:
1346
1347     NDIS_STATUS code indicating status of event processing.
1348
1349 --*/
1350 {
1351     PADAPT            pAdapt  =(PADAPT)ProtocolBindingContext;
1352     NDIS_STATUS       Status  = NDIS_STATUS_SUCCESS;
1353
1354     DBGPRINT(("PtPnPHandler: Adapt %p, Event %d\n", pAdapt, pNetPnPEvent->NetEvent));
1355
1356     switch (pNetPnPEvent->NetEvent)
1357     {
1358         case NetEventSetPower:
1359             Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
1360             break;
1361
1362          case NetEventReconfigure:
1363             Status = PtPnPNetEventReconfigure(pAdapt, pNetPnPEvent);
1364             break;
1365
1366          default:
1367 #ifdef NDIS51
1368             //
1369             // Pass on this notification to protocol(s) above, before
1370             // doing anything else with it.
1371             //
1372             if (pAdapt && pAdapt->MiniportHandle)
1373             {
1374                 Status = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
1375             }
1376 #else
1377             Status = NDIS_STATUS_SUCCESS;
1378
1379 #endif // NDIS51
1380
1381             break;
1382     }
1383
1384     return Status;
1385 }
1386
1387
1388 NDIS_STATUS
1389 PtPnPNetEventReconfigure(
1390     IN PADAPT            pAdapt,
1391     IN PNET_PNP_EVENT    pNetPnPEvent
1392     )
1393 /*++
1394 Routine Description:
1395
1396     This routine is called from NDIS to notify our protocol edge of a
1397     reconfiguration of parameters for either a specific binding (pAdapt
1398     is not NULL), or global parameters if any (pAdapt is NULL).
1399
1400 Arguments:
1401
1402     pAdapt - Pointer to our adapter structure.
1403     pNetPnPEvent - the reconfigure event
1404
1405 Return Value:
1406
1407     NDIS_STATUS_SUCCESS
1408
1409 --*/
1410 {
1411     NDIS_STATUS    ReconfigStatus = NDIS_STATUS_SUCCESS;
1412     NDIS_STATUS    ReturnStatus = NDIS_STATUS_SUCCESS;
1413
1414     do
1415     {
1416         //
1417         // Is this is a global reconfiguration notification ?
1418         //
1419         if (pAdapt == NULL)
1420         {
1421             //
1422             // An important event that causes this notification to us is if
1423             // one of our upper-edge miniport instances was enabled after being
1424             // disabled earlier, e.g. from Device Manager in Win2000. Note that
1425             // NDIS calls this because we had set up an association between our
1426             // miniport and protocol entities by calling NdisIMAssociateMiniport.
1427             //
1428             // Since we would have torn down the lower binding for that miniport,
1429             // we need NDIS' assistance to re-bind to the lower miniport. The
1430             // call to NdisReEnumerateProtocolBindings does exactly that.
1431             //
1432             NdisReEnumerateProtocolBindings (ProtHandle);        
1433             
1434             break;
1435         }
1436
1437 #ifdef NDIS51
1438         //
1439         // Pass on this notification to protocol(s) above before doing anything
1440         // with it.
1441         //
1442         if (pAdapt->MiniportHandle)
1443         {
1444             ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
1445         }
1446 #endif // NDIS51
1447
1448         ReconfigStatus = NDIS_STATUS_SUCCESS;
1449
1450     } while(FALSE);
1451
1452     DBGPRINT(("<==PtPNPNetEventReconfigure: pAdapt %p\n", pAdapt));
1453
1454 #ifdef NDIS51
1455     //
1456     // Overwrite status with what upper-layer protocol(s) returned.
1457     //
1458     ReconfigStatus = ReturnStatus;
1459 #endif
1460
1461     return ReconfigStatus;
1462 }
1463
1464
1465 NDIS_STATUS
1466 PtPnPNetEventSetPower(
1467     IN PADAPT            pAdapt,
1468     IN PNET_PNP_EVENT    pNetPnPEvent
1469     )
1470 /*++
1471 Routine Description:
1472
1473     This is a notification to our protocol edge of the power state
1474     of the lower miniport. If it is going to a low-power state, we must
1475     wait here for all outstanding sends and requests to complete.
1476
1477     NDIS 5.1:  Since we use packet stacking, it is not sufficient to
1478     check usage of our local send packet pool to detect whether or not
1479     all outstanding sends have completed. For this, use the new API
1480     NdisQueryPendingIOCount.
1481
1482     NDIS 5.1: Use the 5.1 API NdisIMNotifyPnPEvent to pass on PnP
1483     notifications to upper protocol(s).
1484
1485 Arguments:
1486
1487     pAdapt            -    Pointer to the adpater structure
1488     pNetPnPEvent    -    The Net Pnp Event. this contains the new device state
1489
1490 Return Value:
1491
1492     NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols.
1493
1494 --*/
1495 {
1496     PNDIS_DEVICE_POWER_STATE       pDeviceState  =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
1497     NDIS_DEVICE_POWER_STATE        PrevDeviceState = pAdapt->PTDeviceState;  
1498     NDIS_STATUS                    Status;
1499     NDIS_STATUS                    ReturnStatus;
1500
1501     ReturnStatus = NDIS_STATUS_SUCCESS;
1502
1503     //
1504     // Set the Internal Device State, this blocks all new sends or receives
1505     //
1506     NdisAcquireSpinLock(&pAdapt->Lock);
1507     pAdapt->PTDeviceState = *pDeviceState;
1508
1509     //
1510     // Check if the miniport below is going to a low power state.
1511     //
1512     if (pAdapt->PTDeviceState > NdisDeviceStateD0)
1513     {
1514         //
1515         // If the miniport below is going to standby, fail all incoming requests
1516         //
1517         if (PrevDeviceState == NdisDeviceStateD0)
1518         {
1519             pAdapt->StandingBy = TRUE;
1520         }
1521
1522         NdisReleaseSpinLock(&pAdapt->Lock);
1523
1524 #ifdef NDIS51
1525         //
1526         // Notify upper layer protocol(s) first.
1527         //
1528         if (pAdapt->MiniportHandle != NULL)
1529         {
1530             ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
1531         }
1532 #endif // NDIS51
1533
1534         //
1535         // Wait for outstanding sends and requests to complete.
1536         //
1537         while (pAdapt->OutstandingSends != 0)
1538         {
1539             NdisMSleep(2);
1540         }
1541
1542         while (pAdapt->OutstandingRequests == TRUE)
1543         {
1544             //
1545             // sleep till outstanding requests complete
1546             //
1547             NdisMSleep(2);
1548         }
1549
1550         //
1551         // If the below miniport is going to low power state, complete the queued request
1552         //
1553         NdisAcquireSpinLock(&pAdapt->Lock);
1554         if (pAdapt->QueuedRequest)
1555         {
1556             pAdapt->QueuedRequest = FALSE;
1557             NdisReleaseSpinLock(&pAdapt->Lock);
1558             PtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE);
1559         }
1560         else
1561         {
1562             NdisReleaseSpinLock(&pAdapt->Lock);
1563         }
1564             
1565
1566         ASSERT(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) == 0);
1567         ASSERT(pAdapt->OutstandingRequests == FALSE);
1568     }
1569     else
1570     {
1571         //
1572         // If the physical miniport is powering up (from Low power state to D0), 
1573         // clear the flag
1574         //
1575         if (PrevDeviceState > NdisDeviceStateD0)
1576         {
1577             pAdapt->StandingBy = FALSE;
1578         }
1579         //
1580         // The device below is being turned on. If we had a request
1581         // pending, send it down now.
1582         //
1583         if (pAdapt->QueuedRequest == TRUE)
1584         {
1585             pAdapt->QueuedRequest = FALSE;
1586         
1587             pAdapt->OutstandingRequests = TRUE;
1588             NdisReleaseSpinLock(&pAdapt->Lock);
1589
1590             NdisRequest(&Status,
1591                         pAdapt->BindingHandle,
1592                         &pAdapt->Request);
1593
1594             if (Status != NDIS_STATUS_PENDING)
1595             {
1596                 PtRequestComplete(pAdapt,
1597                                   &pAdapt->Request,
1598                                   Status);
1599                 
1600             }
1601         }
1602         else
1603         {
1604             NdisReleaseSpinLock(&pAdapt->Lock);
1605         }
1606
1607
1608 #ifdef NDIS51
1609         //
1610         // Pass on this notification to protocol(s) above
1611         //
1612         if (pAdapt->MiniportHandle)
1613         {
1614             ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
1615         }
1616 #endif // NDIS51
1617
1618     }
1619
1620     return ReturnStatus;
1621 }
1622
1623 VOID
1624 PtReferenceAdapt(
1625     IN PADAPT     pAdapt
1626     )
1627 {
1628     NdisAcquireSpinLock(&pAdapt->Lock);
1629     
1630     ASSERT(pAdapt->RefCount >= 0);
1631
1632     pAdapt->RefCount ++;
1633     NdisReleaseSpinLock(&pAdapt->Lock);
1634 }
1635
1636
1637 BOOLEAN
1638 PtDereferenceAdapt(
1639     IN PADAPT     pAdapt
1640     )
1641 {
1642     NdisAcquireSpinLock(&pAdapt->Lock);
1643
1644     ASSERT(pAdapt->RefCount > 0);
1645
1646     pAdapt->RefCount--;
1647
1648     if (pAdapt->RefCount == 0)
1649     {
1650         NdisReleaseSpinLock(&pAdapt->Lock);
1651         
1652         //
1653         // Free all resources on this adapter structure.
1654         //
1655         MPFreeAllPacketPools (pAdapt);;
1656         NdisFreeSpinLock(&pAdapt->Lock);
1657         NdisFreeMemory(pAdapt, 0 , 0);
1658         
1659         return TRUE;
1660         
1661     }
1662     else
1663     {
1664         NdisReleaseSpinLock(&pAdapt->Lock);
1665
1666         return FALSE;
1667     }
1668 }
1669
1670