This repo is obsolete, please see git://git.code.sf.net/p/dummynet/code@master
[ipfw.git] / dummynet2 / miniport.c
1 /*++
2
3 Copyright (c) 1992-2000  Microsoft Corporation
4
5 Module Name:
6
7     miniport.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 #include "precomp.h"
24 #pragma hdrstop
25
26
27
28 NDIS_STATUS
29 MPInitialize(
30     OUT PNDIS_STATUS             OpenErrorStatus,
31     OUT PUINT                    SelectedMediumIndex,
32     IN  PNDIS_MEDIUM             MediumArray,
33     IN  UINT                     MediumArraySize,
34     IN  NDIS_HANDLE              MiniportAdapterHandle,
35     IN  NDIS_HANDLE              WrapperConfigurationContext
36     )
37 /*++
38
39 Routine Description:
40
41     This is the initialize handler which gets called as a result of
42     the BindAdapter handler calling NdisIMInitializeDeviceInstanceEx.
43     The context parameter which we pass there is the adapter structure
44     which we retrieve here.
45
46     Arguments:
47
48     OpenErrorStatus            Not used by us.
49     SelectedMediumIndex        Place-holder for what media we are using
50     MediumArray                Array of ndis media passed down to us to pick from
51     MediumArraySize            Size of the array
52     MiniportAdapterHandle    The handle NDIS uses to refer to us
53     WrapperConfigurationContext    For use by NdisOpenConfiguration
54
55 Return Value:
56
57     NDIS_STATUS_SUCCESS unless something goes wrong
58
59 --*/
60 {
61     UINT            i;
62     PADAPT          pAdapt;
63     NDIS_STATUS     Status = NDIS_STATUS_FAILURE;
64     NDIS_MEDIUM     Medium;
65
66     UNREFERENCED_PARAMETER(WrapperConfigurationContext);
67     
68     do
69     {
70         //
71         // Start off by retrieving our adapter context and storing
72         // the Miniport handle in it.
73         //
74         pAdapt = NdisIMGetDeviceContext(MiniportAdapterHandle);
75         pAdapt->MiniportIsHalted = FALSE;
76
77         DBGPRINT(("==> Miniport Initialize: Adapt %p\n", pAdapt));
78
79         //
80         // Usually we export the medium type of the adapter below as our
81         // virtual miniport's medium type. However if the adapter below us
82         // is a WAN device, then we claim to be of medium type 802.3.
83         //
84         Medium = pAdapt->Medium;
85
86         if (Medium == NdisMediumWan)
87         {
88             Medium = NdisMedium802_3;
89         }
90
91         for (i = 0; i < MediumArraySize; i++)
92         {
93             if (MediumArray[i] == Medium)
94             {
95                 *SelectedMediumIndex = i;
96                 break;
97             }
98         }
99
100         if (i == MediumArraySize)
101         {
102             Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
103             break;
104         }
105
106
107         //
108         // Set the attributes now. NDIS_ATTRIBUTE_DESERIALIZE enables us
109         // to make up-calls to NDIS without having to call NdisIMSwitchToMiniport
110         // or NdisIMQueueCallBack. This also forces us to protect our data using
111         // spinlocks where appropriate. Also in this case NDIS does not queue
112         // packets on our behalf. Since this is a very simple pass-thru
113         // miniport, we do not have a need to protect anything. However in
114         // a general case there will be a need to use per-adapter spin-locks
115         // for the packet queues at the very least.
116         //
117         NdisMSetAttributesEx(MiniportAdapterHandle,
118                              pAdapt,
119                              0,                                        // CheckForHangTimeInSeconds
120                              NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT    |
121                                 NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
122                                 NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
123                                 NDIS_ATTRIBUTE_DESERIALIZE |
124                                 NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
125                              0);
126
127         pAdapt->MiniportHandle = MiniportAdapterHandle;
128         //
129         // Initialize LastIndicatedStatus to be NDIS_STATUS_MEDIA_CONNECT
130         //
131         pAdapt->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
132         
133         //
134         // Initialize the power states for both the lower binding (PTDeviceState)
135         // and our miniport edge to Powered On.
136         //
137         pAdapt->MPDeviceState = NdisDeviceStateD0;
138         pAdapt->PTDeviceState = NdisDeviceStateD0;
139
140         //
141         // Add this adapter to the global pAdapt List
142         //
143         NdisAcquireSpinLock(&GlobalLock);
144
145         pAdapt->Next = pAdaptList;
146         pAdaptList = pAdapt;
147
148         NdisReleaseSpinLock(&GlobalLock);
149         
150         //
151         // Create an ioctl interface
152         //
153         (VOID)PtRegisterDevice();
154
155         Status = NDIS_STATUS_SUCCESS;
156     }
157     while (FALSE);
158
159     //
160     // If we had received an UnbindAdapter notification on the underlying
161     // adapter, we would have blocked that thread waiting for the IM Init
162     // process to complete. Wake up any such thread.
163     //
164     ASSERT(pAdapt->MiniportInitPending == TRUE);
165     pAdapt->MiniportInitPending = FALSE;
166     NdisSetEvent(&pAdapt->MiniportInitEvent);
167
168     if (Status == NDIS_STATUS_SUCCESS)
169     {
170         PtReferenceAdapt(pAdapt);
171     }
172
173     DBGPRINT(("<== Miniport Initialize: Adapt %p, Status %x\n", pAdapt, Status));
174
175     *OpenErrorStatus = Status;
176
177     
178     return Status;
179 }
180
181
182 NDIS_STATUS
183 MPSend(
184     IN NDIS_HANDLE             MiniportAdapterContext,
185     IN PNDIS_PACKET            Packet,
186     IN UINT                    Flags
187     )
188 /*++
189
190 Routine Description:
191
192     Send Packet handler. Either this or our SendPackets (array) handler is called
193     based on which one is enabled in our Miniport Characteristics.
194
195 Arguments:
196
197     MiniportAdapterContext    Pointer to the adapter
198     Packet                    Packet to send
199     Flags                     Unused, passed down below
200
201 Return Value:
202
203     Return code from NdisSend
204
205 --*/
206 {
207     PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
208     NDIS_STATUS         Status;
209     PNDIS_PACKET        MyPacket;
210     PVOID               MediaSpecificInfo = NULL;
211     ULONG               MediaSpecificInfoSize = 0;
212
213     //
214     // The driver should fail the send if the virtual miniport is in low 
215     // power state
216     //
217     if (pAdapt->MPDeviceState > NdisDeviceStateD0)
218     {
219          return NDIS_STATUS_FAILURE;
220     }
221
222 #ifdef NDIS51
223     //
224     // Use NDIS 5.1 packet stacking:
225     //
226     if (0)      // XXX IPFW - make sure we don't go in here
227     {
228         PNDIS_PACKET_STACK        pStack;
229         BOOLEAN                   Remaining;
230
231         //
232         // Packet stacks: Check if we can use the same packet for sending down.
233         //
234
235         pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
236         if (Remaining)
237         {
238             //
239             // We can reuse "Packet".
240             //
241             // NOTE: if we needed to keep per-packet information in packets
242             // sent down, we can use pStack->IMReserved[].
243             //
244             ASSERT(pStack);
245             //
246             // If the below miniport is going to low power state, stop sending down any packet.
247             //
248             NdisAcquireSpinLock(&pAdapt->Lock);
249             if (pAdapt->PTDeviceState > NdisDeviceStateD0)
250             {
251                 NdisReleaseSpinLock(&pAdapt->Lock);
252                 return NDIS_STATUS_FAILURE;
253             }
254             pAdapt->OutstandingSends++;
255             NdisReleaseSpinLock(&pAdapt->Lock);
256             NdisSend(&Status,
257                      pAdapt->BindingHandle,
258                      Packet);
259
260             if (Status != NDIS_STATUS_PENDING)
261             {
262                 ADAPT_DECR_PENDING_SENDS(pAdapt);
263             }
264
265             return(Status);
266         }
267     }
268 #endif // NDIS51
269
270     //
271     // We are either not using packet stacks, or there isn't stack space
272     // in the original packet passed down to us. Allocate a new packet
273     // to wrap the data with.
274     //
275     //
276     // If the below miniport is going to low power state, stop sending down any packet.
277     //
278     NdisAcquireSpinLock(&pAdapt->Lock);
279     if (pAdapt->PTDeviceState > NdisDeviceStateD0)
280     {
281         NdisReleaseSpinLock(&pAdapt->Lock);
282         return NDIS_STATUS_FAILURE;
283     
284     }
285     pAdapt->OutstandingSends++;
286     NdisReleaseSpinLock(&pAdapt->Lock);
287     
288     NdisAllocatePacket(&Status,
289                        &MyPacket,
290                        pAdapt->SendPacketPoolHandle);
291
292     if (Status == NDIS_STATUS_SUCCESS)
293     {
294         PSEND_RSVD            SendRsvd;
295
296         //
297         // Save a pointer to the original packet in our reserved
298         // area in the new packet. This is needed so that we can
299         // get back to the original packet when the new packet's send
300         // is completed.
301         //
302         SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
303         SendRsvd->OriginalPkt = Packet;
304
305         NdisGetPacketFlags(MyPacket) = Flags;
306
307         //
308         // Set up the new packet so that it describes the same
309         // data as the original packet.
310         //
311         NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
312         NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
313 #ifdef WIN9X
314         //
315         // Work around the fact that NDIS does not initialize this
316         // to FALSE on Win9x.
317         //
318         NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE;
319 #endif
320
321         //
322         // Copy the OOB Offset from the original packet to the new
323         // packet.
324         //
325         NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
326                        NDIS_OOB_DATA_FROM_PACKET(Packet),
327                        sizeof(NDIS_PACKET_OOB_DATA));
328
329 #ifndef WIN9X
330         //
331         // Copy the right parts of per packet info into the new packet.
332         // This API is not available on Win9x since task offload is
333         // not supported on that platform.
334         //
335         NdisIMCopySendPerPacketInfo(MyPacket, Packet);
336 #endif
337         
338         //
339         // Copy the Media specific information
340         //
341         NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
342                                             &MediaSpecificInfo,
343                                             &MediaSpecificInfoSize);
344
345         if (MediaSpecificInfo || MediaSpecificInfoSize)
346         {
347             NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
348                                                 MediaSpecificInfo,
349                                                 MediaSpecificInfoSize);
350                 }
351 #if 1   /* IPFW: query the firewall */
352         /* if dummynet keeps the packet, we mimic success.
353          * otherwise continue as usual.
354          */
355                 {
356                         int ret = ipfw2_qhandler_w32(MyPacket, OUTGOING,
357                                         MiniportAdapterContext);
358                         if (ret != PASS) {
359                                 if (ret == DROP)
360                                         return NDIS_STATUS_FAILURE;
361                                 else {  //dummynet kept the packet
362 #ifndef WIN9X
363                                         NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
364 #endif
365                                         return NDIS_STATUS_SUCCESS; //otherwise simply continue
366                                 }
367                         }
368                 }
369 #endif  /* end of IPFW code */
370
371         NdisSend(&Status,
372                  pAdapt->BindingHandle,
373                  MyPacket);
374
375
376         if (Status != NDIS_STATUS_PENDING)
377         {
378 #ifndef WIN9X
379             NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
380 #endif
381             NdisFreePacket(MyPacket);
382             ADAPT_DECR_PENDING_SENDS(pAdapt);
383         }
384     }
385     else
386     {
387         ADAPT_DECR_PENDING_SENDS(pAdapt);
388         //
389         // We are out of packets. Silently drop it. Alternatively we can deal with it:
390         //    - By keeping separate send and receive pools
391         //    - Dynamically allocate more pools as needed and free them when not needed
392         //
393     }
394
395     return(Status);
396 }
397
398
399 VOID
400 MPSendPackets(
401     IN NDIS_HANDLE             MiniportAdapterContext,
402     IN PPNDIS_PACKET           PacketArray,
403     IN UINT                    NumberOfPackets
404     )
405 /*++
406
407 Routine Description:
408
409     Send Packet Array handler. Either this or our SendPacket handler is called
410     based on which one is enabled in our Miniport Characteristics.
411
412 Arguments:
413
414     MiniportAdapterContext     Pointer to our adapter
415     PacketArray                Set of packets to send
416     NumberOfPackets            Self-explanatory
417
418 Return Value:
419
420     None
421
422 --*/
423 {
424     PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
425     NDIS_STATUS         Status;
426     UINT                i;
427     PVOID               MediaSpecificInfo = NULL;
428     UINT                MediaSpecificInfoSize = 0;
429     
430
431     for (i = 0; i < NumberOfPackets; i++)
432     {
433         PNDIS_PACKET    Packet, MyPacket;
434
435         Packet = PacketArray[i];
436         //
437         // The driver should fail the send if the virtual miniport is in low 
438         // power state
439         //
440         if (pAdapt->MPDeviceState > NdisDeviceStateD0)
441         {
442             NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
443                             Packet,
444                             NDIS_STATUS_FAILURE);
445             continue;
446         }
447
448 #ifdef NDIS51
449
450         //
451         // Use NDIS 5.1 packet stacking:
452         //
453         {
454             PNDIS_PACKET_STACK        pStack;
455             BOOLEAN                   Remaining;
456
457             //
458             // Packet stacks: Check if we can use the same packet for sending down.
459             //
460             pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
461             if (Remaining)
462             {
463                 //
464                 // We can reuse "Packet".
465                 //
466                 // NOTE: if we needed to keep per-packet information in packets
467                 // sent down, we can use pStack->IMReserved[].
468                 //
469                 ASSERT(pStack);
470                 //
471                 // If the below miniport is going to low power state, stop sending down any packet.
472                 //
473                 NdisAcquireSpinLock(&pAdapt->Lock);
474                 if (pAdapt->PTDeviceState > NdisDeviceStateD0)
475                 {
476                     NdisReleaseSpinLock(&pAdapt->Lock);
477                     NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
478                                         Packet,
479                                         NDIS_STATUS_FAILURE);
480                 }
481                 else
482                 {
483                     pAdapt->OutstandingSends++;
484                     NdisReleaseSpinLock(&pAdapt->Lock);
485                 
486                     NdisSend(&Status,
487                               pAdapt->BindingHandle,
488                               Packet);
489         
490                     if (Status != NDIS_STATUS_PENDING)
491                     {
492                         NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
493                                             Packet,
494                                             Status);
495                    
496                         ADAPT_DECR_PENDING_SENDS(pAdapt);
497                     }
498                 }
499                 continue;
500             }
501         }
502 #endif
503         do 
504         {
505             NdisAcquireSpinLock(&pAdapt->Lock);
506             //
507             // If the below miniport is going to low power state, stop sending down any packet.
508             //
509             if (pAdapt->PTDeviceState > NdisDeviceStateD0)
510             {
511                 NdisReleaseSpinLock(&pAdapt->Lock);
512                 Status = NDIS_STATUS_FAILURE;
513                 break;
514             }
515             pAdapt->OutstandingSends++;
516             NdisReleaseSpinLock(&pAdapt->Lock);
517             
518             NdisAllocatePacket(&Status,
519                                &MyPacket,
520                                pAdapt->SendPacketPoolHandle);
521
522             if (Status == NDIS_STATUS_SUCCESS)
523             {
524                 PSEND_RSVD        SendRsvd;
525
526                 SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
527                 SendRsvd->OriginalPkt = Packet;
528
529                 NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
530
531                 NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
532                 NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
533 #ifdef WIN9X
534                 //
535                 // Work around the fact that NDIS does not initialize this
536                 // to FALSE on Win9x.
537                 //
538                 NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE;
539 #endif // WIN9X
540
541                 //
542                 // Copy the OOB data from the original packet to the new
543                 // packet.
544                 //
545                 NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
546                             NDIS_OOB_DATA_FROM_PACKET(Packet),
547                             sizeof(NDIS_PACKET_OOB_DATA));
548                 //
549                 // Copy relevant parts of the per packet info into the new packet
550                 //
551 #ifndef WIN9X
552                 NdisIMCopySendPerPacketInfo(MyPacket, Packet);
553 #endif
554
555                 //
556                 // Copy the Media specific information
557                 //
558                 NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
559                                                     &MediaSpecificInfo,
560                                                     &MediaSpecificInfoSize);
561
562                 if (MediaSpecificInfo || MediaSpecificInfoSize)
563                 {
564                     NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
565                                                         MediaSpecificInfo,
566                                                         MediaSpecificInfoSize);
567                 }
568
569                 NdisSend(&Status,
570                          pAdapt->BindingHandle,
571                          MyPacket);
572
573                 if (Status != NDIS_STATUS_PENDING)
574                 {
575 #ifndef WIN9X
576                     NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
577 #endif
578                     NdisFreePacket(MyPacket);
579                     ADAPT_DECR_PENDING_SENDS(pAdapt);
580                 }
581             }
582             else
583             {
584                 //
585                 // The driver cannot allocate a packet.
586                 // 
587                 ADAPT_DECR_PENDING_SENDS(pAdapt);
588             }
589         }
590         while (FALSE);
591
592         if (Status != NDIS_STATUS_PENDING)
593         {
594             NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
595                               Packet,
596                               Status);
597         }
598     }
599 }
600
601
602 NDIS_STATUS
603 MPQueryInformation(
604     IN NDIS_HANDLE                MiniportAdapterContext,
605     IN NDIS_OID                   Oid,
606     IN PVOID                      InformationBuffer,
607     IN ULONG                      InformationBufferLength,
608     OUT PULONG                    BytesWritten,
609     OUT PULONG                    BytesNeeded
610     )
611 /*++
612
613 Routine Description:
614
615     Entry point called by NDIS to query for the value of the specified OID.
616     Typical processing is to forward the query down to the underlying miniport.
617
618     The following OIDs are filtered here:
619
620     OID_PNP_QUERY_POWER - return success right here
621
622     OID_GEN_SUPPORTED_GUIDS - do not forward, otherwise we will show up
623     multiple instances of private GUIDs supported by the underlying miniport.
624
625     OID_PNP_CAPABILITIES - we do send this down to the lower miniport, but
626     the values returned are postprocessed before we complete this request;
627     see PtRequestComplete.
628
629     NOTE on OID_TCP_TASK_OFFLOAD - if this IM driver modifies the contents
630     of data it passes through such that a lower miniport may not be able
631     to perform TCP task offload, then it should not forward this OID down,
632     but fail it here with the status NDIS_STATUS_NOT_SUPPORTED. This is to
633     avoid performing incorrect transformations on data.
634
635     If our miniport edge (upper edge) is at a low-power state, fail the request.
636
637     If our protocol edge (lower edge) has been notified of a low-power state,
638     we pend this request until the miniport below has been set to D0. Since
639     requests to miniports are serialized always, at most a single request will
640     be pended.
641
642 Arguments:
643
644     MiniportAdapterContext    Pointer to the adapter structure
645     Oid                       Oid for this query
646     InformationBuffer         Buffer for information
647     InformationBufferLength   Size of this buffer
648     BytesWritten              Specifies how much info is written
649     BytesNeeded               In case the buffer is smaller than what we need, tell them how much is needed
650
651
652 Return Value:
653
654     Return code from the NdisRequest below.
655
656 --*/
657 {
658     PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
659     NDIS_STATUS   Status = NDIS_STATUS_FAILURE;
660
661     do
662     {
663         if (Oid == OID_PNP_QUERY_POWER)
664         {
665             //
666             //  Do not forward this.
667             //
668             Status = NDIS_STATUS_SUCCESS;
669             break;
670         }
671
672         if (Oid == OID_GEN_SUPPORTED_GUIDS)
673         {
674             //
675             //  Do not forward this, otherwise we will end up with multiple
676             //  instances of private GUIDs that the underlying miniport
677             //  supports.
678             //
679             Status = NDIS_STATUS_NOT_SUPPORTED;
680             break;
681         }
682
683         if (Oid == OID_TCP_TASK_OFFLOAD)
684         {
685             //
686             // Fail this -if- this driver performs data transformations
687             // that can interfere with a lower driver's ability to offload
688             // TCP tasks.
689             //
690             // Status = NDIS_STATUS_NOT_SUPPORTED;
691             // break;
692             //
693         }
694         //
695         // If the miniport below is unbinding, just fail any request
696         //
697         NdisAcquireSpinLock(&pAdapt->Lock);
698         if (pAdapt->UnbindingInProcess == TRUE)
699         {
700             NdisReleaseSpinLock(&pAdapt->Lock);
701             Status = NDIS_STATUS_FAILURE;
702             break;
703         }
704         NdisReleaseSpinLock(&pAdapt->Lock);
705         //
706         // All other queries are failed, if the miniport is not at D0,
707         //
708         if (pAdapt->MPDeviceState > NdisDeviceStateD0) 
709         {
710             Status = NDIS_STATUS_FAILURE;
711             break;
712         }
713
714         pAdapt->Request.RequestType = NdisRequestQueryInformation;
715         pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid;
716         pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
717         pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
718         pAdapt->BytesNeeded = BytesNeeded;
719         pAdapt->BytesReadOrWritten = BytesWritten;
720
721         //
722         // If the miniport below is binding, fail the request
723         //
724         NdisAcquireSpinLock(&pAdapt->Lock);
725             
726         if (pAdapt->UnbindingInProcess == TRUE)
727         {
728             NdisReleaseSpinLock(&pAdapt->Lock);
729             Status = NDIS_STATUS_FAILURE;
730             break;
731         }
732         //
733         // If the Protocol device state is OFF, mark this request as being 
734         // pended. We queue this until the device state is back to D0. 
735         //
736         if ((pAdapt->PTDeviceState > NdisDeviceStateD0) 
737                 && (pAdapt->StandingBy == FALSE))
738         {
739             pAdapt->QueuedRequest = TRUE;
740             NdisReleaseSpinLock(&pAdapt->Lock);
741             Status = NDIS_STATUS_PENDING;
742             break;
743         }
744         //
745         // This is in the process of powering down the system, always fail the request
746         // 
747         if (pAdapt->StandingBy == TRUE)
748         {
749             NdisReleaseSpinLock(&pAdapt->Lock);
750             Status = NDIS_STATUS_FAILURE;
751             break;
752         }
753         pAdapt->OutstandingRequests = TRUE;
754         
755         NdisReleaseSpinLock(&pAdapt->Lock);
756
757         //
758         // default case, most requests will be passed to the miniport below
759         //
760         NdisRequest(&Status,
761                     pAdapt->BindingHandle,
762                     &pAdapt->Request);
763
764
765         if (Status != NDIS_STATUS_PENDING)
766         {
767             PtRequestComplete(pAdapt, &pAdapt->Request, Status);
768             Status = NDIS_STATUS_PENDING;
769         }
770
771     } while (FALSE);
772
773     return(Status);
774
775 }
776
777
778 VOID
779 MPQueryPNPCapabilities(
780     IN OUT PADAPT            pAdapt,
781     OUT PNDIS_STATUS         pStatus
782     )
783 /*++
784
785 Routine Description:
786
787     Postprocess a request for OID_PNP_CAPABILITIES that was forwarded
788     down to the underlying miniport, and has been completed by it.
789
790 Arguments:
791
792     pAdapt - Pointer to the adapter structure
793     pStatus - Place to return final status
794
795 Return Value:
796
797     None.
798
799 --*/
800
801 {
802     PNDIS_PNP_CAPABILITIES           pPNPCapabilities;
803     PNDIS_PM_WAKE_UP_CAPABILITIES    pPMstruct;
804
805     if (pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
806     {
807         pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)(pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer);
808
809         //
810         // The following fields must be overwritten by an IM driver.
811         //
812         pPMstruct= & pPNPCapabilities->WakeUpCapabilities;
813         pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
814         pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
815         pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
816         *pAdapt->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES);
817         *pAdapt->BytesNeeded = 0;
818
819
820         //
821         // Setting our internal flags
822         // Default, device is ON
823         //
824         pAdapt->MPDeviceState = NdisDeviceStateD0;
825         pAdapt->PTDeviceState = NdisDeviceStateD0;
826
827         *pStatus = NDIS_STATUS_SUCCESS;
828     }
829     else
830     {
831         *pAdapt->BytesNeeded= sizeof(NDIS_PNP_CAPABILITIES);
832         *pStatus = NDIS_STATUS_RESOURCES;
833     }
834 }
835
836
837 NDIS_STATUS
838 MPSetInformation(
839     IN NDIS_HANDLE                                  MiniportAdapterContext,
840     IN NDIS_OID                                     Oid,
841     __in_bcount(InformationBufferLength) IN PVOID   InformationBuffer,
842     IN ULONG                                        InformationBufferLength,
843     OUT PULONG                                      BytesRead,
844     OUT PULONG                                      BytesNeeded
845     )
846 /*++
847
848 Routine Description:
849
850     Miniport SetInfo handler.
851
852     In the case of OID_PNP_SET_POWER, record the power state and return the OID.    
853     Do not pass below
854     If the device is suspended, do not block the SET_POWER_OID 
855     as it is used to reactivate the Passthru miniport
856
857     
858     PM- If the MP is not ON (DeviceState > D0) return immediately  (except for 'query power' and 'set power')
859          If MP is ON, but the PT is not at D0, then queue the queue the request for later processing
860
861     Requests to miniports are always serialized
862
863
864 Arguments:
865
866     MiniportAdapterContext    Pointer to the adapter structure
867     Oid                       Oid for this query
868     InformationBuffer         Buffer for information
869     InformationBufferLength   Size of this buffer
870     BytesRead                 Specifies how much info is read
871     BytesNeeded               In case the buffer is smaller than what we need, tell them how much is needed
872
873 Return Value:
874
875     Return code from the NdisRequest below.
876
877 --*/
878 {
879     PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
880     NDIS_STATUS   Status;
881
882     Status = NDIS_STATUS_FAILURE;
883
884     do
885     {
886         //
887         // The Set Power should not be sent to the miniport below the Passthru, but is handled internally
888         //
889         if (Oid == OID_PNP_SET_POWER)
890         {
891             MPProcessSetPowerOid(&Status, 
892                                  pAdapt, 
893                                  InformationBuffer, 
894                                  InformationBufferLength, 
895                                  BytesRead, 
896                                  BytesNeeded);
897             break;
898
899         }
900
901         //
902         // If the miniport below is unbinding, fail the request
903         //
904         NdisAcquireSpinLock(&pAdapt->Lock);     
905         if (pAdapt->UnbindingInProcess == TRUE)
906         {
907             NdisReleaseSpinLock(&pAdapt->Lock);
908             Status = NDIS_STATUS_FAILURE;
909             break;
910         }
911         NdisReleaseSpinLock(&pAdapt->Lock);
912         //
913         // All other Set Information requests are failed, if the miniport is
914         // not at D0 or is transitioning to a device state greater than D0.
915         //
916         if (pAdapt->MPDeviceState > NdisDeviceStateD0)
917         {
918             Status = NDIS_STATUS_FAILURE;
919             break;
920         }
921
922         // Set up the Request and return the result
923         pAdapt->Request.RequestType = NdisRequestSetInformation;
924         pAdapt->Request.DATA.SET_INFORMATION.Oid = Oid;
925         pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
926         pAdapt->Request.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
927         pAdapt->BytesNeeded = BytesNeeded;
928         pAdapt->BytesReadOrWritten = BytesRead;
929
930         //
931         // If the miniport below is unbinding, fail the request
932         //
933         NdisAcquireSpinLock(&pAdapt->Lock);     
934         if (pAdapt->UnbindingInProcess == TRUE)
935         {
936             NdisReleaseSpinLock(&pAdapt->Lock);
937             Status = NDIS_STATUS_FAILURE;
938             break;
939         }
940             
941         //
942         // If the device below is at a low power state, we cannot send it the
943         // request now, and must pend it.
944         //
945         if ((pAdapt->PTDeviceState > NdisDeviceStateD0) 
946                 && (pAdapt->StandingBy == FALSE))
947         {
948             pAdapt->QueuedRequest = TRUE;
949             NdisReleaseSpinLock(&pAdapt->Lock);
950             Status = NDIS_STATUS_PENDING;
951             break;
952         }
953         //
954         // This is in the process of powering down the system, always fail the request
955         // 
956         if (pAdapt->StandingBy == TRUE)
957         {
958             NdisReleaseSpinLock(&pAdapt->Lock);
959             Status = NDIS_STATUS_FAILURE;
960             break;
961         }
962         pAdapt->OutstandingRequests = TRUE;
963         
964         NdisReleaseSpinLock(&pAdapt->Lock);
965         //
966         // Forward the request to the device below.
967         //
968         NdisRequest(&Status,
969                     pAdapt->BindingHandle,
970                     &pAdapt->Request);
971
972         if (Status != NDIS_STATUS_PENDING)
973         {
974             *BytesRead = pAdapt->Request.DATA.SET_INFORMATION.BytesRead;
975             *BytesNeeded = pAdapt->Request.DATA.SET_INFORMATION.BytesNeeded;
976             pAdapt->OutstandingRequests = FALSE;
977         }
978
979     } while (FALSE);
980
981     return(Status);
982 }
983
984
985 VOID
986 MPProcessSetPowerOid(
987     IN OUT PNDIS_STATUS                             pNdisStatus,
988     IN PADAPT                                       pAdapt,
989     __in_bcount(InformationBufferLength) IN PVOID   InformationBuffer,
990     IN ULONG                                        InformationBufferLength,
991     OUT PULONG                                      BytesRead,
992     OUT PULONG                                      BytesNeeded
993     )
994 /*++
995
996 Routine Description:
997     This routine does all the procssing for a request with a SetPower Oid
998     The miniport shoud accept  the Set Power and transition to the new state
999
1000     The Set Power should not be passed to the miniport below
1001
1002     If the IM miniport is going into a low power state, then there is no guarantee if it will ever
1003     be asked go back to D0, before getting halted. No requests should be pended or queued.
1004
1005     
1006 Arguments:
1007     pNdisStatus           - Status of the operation
1008     pAdapt                - The Adapter structure
1009     InformationBuffer     - The New DeviceState
1010     InformationBufferLength
1011     BytesRead             - No of bytes read
1012     BytesNeeded           -  No of bytes needed
1013
1014
1015 Return Value:
1016     Status  - NDIS_STATUS_SUCCESS if all the wait events succeed.
1017
1018 --*/
1019 {
1020
1021     
1022     NDIS_DEVICE_POWER_STATE NewDeviceState;
1023
1024     DBGPRINT(("==>MPProcessSetPowerOid: Adapt %p\n", pAdapt)); 
1025
1026     ASSERT (InformationBuffer != NULL);
1027
1028     *pNdisStatus = NDIS_STATUS_FAILURE;
1029
1030     do 
1031     {
1032         //
1033         // Check for invalid length
1034         //
1035         if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
1036         {
1037             *pNdisStatus = NDIS_STATUS_INVALID_LENGTH;
1038             break;
1039         }
1040
1041         NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE)InformationBuffer);
1042
1043         //
1044         // Check for invalid device state
1045         //
1046         if ((pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0))
1047         {
1048             //
1049             // If the miniport is in a non-D0 state, the miniport can only receive a Set Power to D0
1050             //
1051             ASSERT (!(pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0));
1052
1053             *pNdisStatus = NDIS_STATUS_FAILURE;
1054             break;
1055         }    
1056
1057         //
1058         // Is the miniport transitioning from an On (D0) state to an Low Power State (>D0)
1059         // If so, then set the StandingBy Flag - (Block all incoming requests)
1060         //
1061         if (pAdapt->MPDeviceState == NdisDeviceStateD0 && NewDeviceState > NdisDeviceStateD0)
1062         {
1063             pAdapt->StandingBy = TRUE;
1064         }
1065
1066         //
1067         // If the miniport is transitioning from a low power state to ON (D0), then clear the StandingBy flag
1068         // All incoming requests will be pended until the physical miniport turns ON.
1069         //
1070         if (pAdapt->MPDeviceState > NdisDeviceStateD0 &&  NewDeviceState == NdisDeviceStateD0)
1071         {
1072             pAdapt->StandingBy = FALSE;
1073         }
1074         
1075         //
1076         // Now update the state in the pAdapt structure;
1077         //
1078         pAdapt->MPDeviceState = NewDeviceState;
1079         
1080         *pNdisStatus = NDIS_STATUS_SUCCESS;
1081     
1082
1083     } while (FALSE);    
1084         
1085     if (*pNdisStatus == NDIS_STATUS_SUCCESS)
1086     {
1087         //
1088         // The miniport resume from low power state
1089         // 
1090         if (pAdapt->StandingBy == FALSE)
1091         {
1092             //
1093             // If we need to indicate the media connect state
1094             // 
1095             if (pAdapt->LastIndicatedStatus != pAdapt->LatestUnIndicateStatus)
1096             {
1097                if (pAdapt->MiniportHandle != NULL)
1098                {
1099                    NdisMIndicateStatus(pAdapt->MiniportHandle,
1100                                             pAdapt->LatestUnIndicateStatus,
1101                                             (PVOID)NULL,
1102                                             0);
1103                    NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
1104                    pAdapt->LastIndicatedStatus = pAdapt->LatestUnIndicateStatus;
1105                }
1106             }
1107         }
1108         else
1109         {
1110             //
1111             // Initialize LatestUnIndicatedStatus
1112             //
1113             pAdapt->LatestUnIndicateStatus = pAdapt->LastIndicatedStatus;
1114         }
1115         *BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
1116         *BytesNeeded = 0;
1117     }
1118     else
1119     {
1120         *BytesRead = 0;
1121         *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
1122     }
1123
1124     DBGPRINT(("<==MPProcessSetPowerOid: Adapt %p\n", pAdapt)); 
1125 }
1126
1127
1128 VOID
1129 MPReturnPacket(
1130     IN NDIS_HANDLE             MiniportAdapterContext,
1131     IN PNDIS_PACKET            Packet
1132     )
1133 /*++
1134
1135 Routine Description:
1136
1137     NDIS Miniport entry point called whenever protocols are done with
1138     a packet that we had indicated up and they had queued up for returning
1139     later.
1140
1141 Arguments:
1142
1143     MiniportAdapterContext    - pointer to ADAPT structure
1144     Packet    - packet being returned.
1145
1146 Return Value:
1147
1148     None.
1149
1150 --*/
1151 {
1152     PADAPT            pAdapt = (PADAPT)MiniportAdapterContext;
1153
1154 #ifdef NDIS51
1155     //
1156     // Packet stacking: Check if this packet belongs to us.
1157     //
1158     if (NdisGetPoolFromPacket(Packet) != pAdapt->RecvPacketPoolHandle)
1159     {
1160         //
1161         // We reused the original packet in a receive indication.
1162         // Simply return it to the miniport below us.
1163         //
1164         NdisReturnPackets(&Packet, 1);
1165     }
1166     else
1167 #endif // NDIS51
1168     {
1169         //
1170         // This is a packet allocated from this IM's receive packet pool.
1171         // Reclaim our packet, and return the original to the driver below.
1172         //
1173
1174         PNDIS_PACKET    MyPacket;
1175         PRECV_RSVD      RecvRsvd;
1176     
1177         RecvRsvd = (PRECV_RSVD)(Packet->MiniportReserved);
1178         MyPacket = RecvRsvd->OriginalPkt;
1179     
1180         NdisFreePacket(Packet);
1181         NdisReturnPackets(&MyPacket, 1);
1182     }
1183 }
1184
1185
1186 NDIS_STATUS
1187 MPTransferData(
1188     OUT PNDIS_PACKET            Packet,
1189     OUT PUINT                   BytesTransferred,
1190     IN NDIS_HANDLE              MiniportAdapterContext,
1191     IN NDIS_HANDLE              MiniportReceiveContext,
1192     IN UINT                     ByteOffset,
1193     IN UINT                     BytesToTransfer
1194     )
1195 /*++
1196
1197 Routine Description:
1198
1199     Miniport's transfer data handler.
1200
1201 Arguments:
1202
1203     Packet                    Destination packet
1204     BytesTransferred          Place-holder for how much data was copied
1205     MiniportAdapterContext    Pointer to the adapter structure
1206     MiniportReceiveContext    Context
1207     ByteOffset                Offset into the packet for copying data
1208     BytesToTransfer           How much to copy.
1209
1210 Return Value:
1211
1212     Status of transfer
1213
1214 --*/
1215 {
1216     PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
1217     NDIS_STATUS   Status;
1218
1219     //
1220     // Return, if the device is OFF
1221     //
1222
1223     if (IsIMDeviceStateOn(pAdapt) == FALSE)
1224     {
1225         return NDIS_STATUS_FAILURE;
1226     }
1227
1228     NdisTransferData(&Status,
1229                      pAdapt->BindingHandle,
1230                      MiniportReceiveContext,
1231                      ByteOffset,
1232                      BytesToTransfer,
1233                      Packet,
1234                      BytesTransferred);
1235
1236     return(Status);
1237 }
1238
1239 VOID
1240 MPHalt(
1241     IN NDIS_HANDLE                MiniportAdapterContext
1242     )
1243 /*++
1244
1245 Routine Description:
1246
1247     Halt handler. All the hard-work for clean-up is done here.
1248
1249 Arguments:
1250
1251     MiniportAdapterContext    Pointer to the Adapter
1252
1253 Return Value:
1254
1255     None.
1256
1257 --*/
1258 {
1259     PADAPT             pAdapt = (PADAPT)MiniportAdapterContext;
1260     NDIS_STATUS        Status;
1261     PADAPT            *ppCursor;
1262
1263     DBGPRINT(("==>MiniportHalt: Adapt %p\n", pAdapt));
1264
1265     pAdapt->MiniportHandle = NULL;
1266     pAdapt->MiniportIsHalted = TRUE;
1267
1268     //
1269     // Remove this adapter from the global list
1270     //
1271     NdisAcquireSpinLock(&GlobalLock);
1272
1273     for (ppCursor = &pAdaptList; *ppCursor != NULL; ppCursor = &(*ppCursor)->Next)
1274     {
1275         if (*ppCursor == pAdapt)
1276         {
1277             *ppCursor = pAdapt->Next;
1278             break;
1279         }
1280     }
1281
1282     NdisReleaseSpinLock(&GlobalLock);
1283
1284     //
1285     // Delete the ioctl interface that was created when the miniport
1286     // was created.
1287     //
1288     (VOID)PtDeregisterDevice();
1289
1290     //
1291     // If we have a valid bind, close the miniport below the protocol
1292     //
1293 #pragma prefast(suppress: __WARNING_DEREF_NULL_PTR, "pAdapt cannot be NULL")
1294     if (pAdapt->BindingHandle != NULL)
1295     {
1296         //
1297         // Close the binding below. and wait for it to complete
1298         //
1299         NdisResetEvent(&pAdapt->Event);
1300
1301         NdisCloseAdapter(&Status, pAdapt->BindingHandle);
1302
1303         if (Status == NDIS_STATUS_PENDING)
1304         {
1305             NdisWaitEvent(&pAdapt->Event, 0);
1306             Status = pAdapt->Status;
1307         }
1308
1309         ASSERT (Status == NDIS_STATUS_SUCCESS);
1310
1311         pAdapt->BindingHandle = NULL;
1312         
1313         PtDereferenceAdapt(pAdapt);
1314     }
1315
1316     if (PtDereferenceAdapt(pAdapt))
1317     {
1318         pAdapt = NULL;
1319     }
1320         
1321     
1322     DBGPRINT(("<== MiniportHalt: pAdapt %p\n", pAdapt));
1323 }
1324
1325
1326 #ifdef NDIS51_MINIPORT
1327
1328 VOID
1329 MPCancelSendPackets(
1330     IN NDIS_HANDLE            MiniportAdapterContext,
1331     IN PVOID                  CancelId
1332     )
1333 /*++
1334
1335 Routine Description:
1336
1337     The miniport entry point to handle cancellation of all send packets
1338     that match the given CancelId. If we have queued any packets that match
1339     this, then we should dequeue them and call NdisMSendComplete for all
1340     such packets, with a status of NDIS_STATUS_REQUEST_ABORTED.
1341
1342     We should also call NdisCancelSendPackets in turn, on each lower binding
1343     that this adapter corresponds to. This is to let miniports below cancel
1344     any matching packets.
1345
1346 Arguments:
1347
1348     MiniportAdapterContext    - pointer to ADAPT structure
1349     CancelId    - ID of packets to be cancelled.
1350
1351 Return Value:
1352
1353     None
1354
1355 --*/
1356 {
1357     PADAPT    pAdapt = (PADAPT)MiniportAdapterContext;
1358
1359     //
1360     // If we queue packets on our adapter structure, this would be 
1361     // the place to acquire a spinlock to it, unlink any packets whose
1362     // Id matches CancelId, release the spinlock and call NdisMSendComplete
1363     // with NDIS_STATUS_REQUEST_ABORTED for all unlinked packets.
1364     //
1365
1366     //
1367     // Next, pass this down so that we let the miniport(s) below cancel
1368     // any packets that they might have queued.
1369     //
1370     NdisCancelSendPackets(pAdapt->BindingHandle, CancelId);
1371
1372     return;
1373 }
1374
1375 VOID
1376 MPDevicePnPEvent(
1377     IN NDIS_HANDLE              MiniportAdapterContext,
1378     IN NDIS_DEVICE_PNP_EVENT    DevicePnPEvent,
1379     IN PVOID                    InformationBuffer,
1380     IN ULONG                    InformationBufferLength
1381     )
1382 /*++
1383
1384 Routine Description:
1385
1386     This handler is called to notify us of PnP events directed to
1387     our miniport device object.
1388
1389 Arguments:
1390
1391     MiniportAdapterContext    - pointer to ADAPT structure
1392     DevicePnPEvent - the event
1393     InformationBuffer - Points to additional event-specific information
1394     InformationBufferLength - length of above
1395
1396 Return Value:
1397
1398     None
1399 --*/
1400 {
1401     // TBD - add code/comments about processing this.
1402
1403     UNREFERENCED_PARAMETER(MiniportAdapterContext);
1404     UNREFERENCED_PARAMETER(DevicePnPEvent);
1405     UNREFERENCED_PARAMETER(InformationBuffer);
1406     UNREFERENCED_PARAMETER(InformationBufferLength);
1407     
1408     return;
1409 }
1410
1411 VOID
1412 MPAdapterShutdown(
1413     IN NDIS_HANDLE                MiniportAdapterContext
1414     )
1415 /*++
1416
1417 Routine Description:
1418
1419     This handler is called to notify us of an impending system shutdown.
1420
1421 Arguments:
1422
1423     MiniportAdapterContext    - pointer to ADAPT structure
1424
1425 Return Value:
1426
1427     None
1428 --*/
1429 {
1430     UNREFERENCED_PARAMETER(MiniportAdapterContext);
1431     
1432     return;
1433 }
1434
1435 #endif
1436
1437
1438 VOID
1439 MPFreeAllPacketPools(
1440     IN PADAPT                    pAdapt
1441     )
1442 /*++
1443
1444 Routine Description:
1445
1446     Free all packet pools on the specified adapter.
1447     
1448 Arguments:
1449
1450     pAdapt    - pointer to ADAPT structure
1451
1452 Return Value:
1453
1454     None
1455
1456 --*/
1457 {
1458     if (pAdapt->RecvPacketPoolHandle != NULL)
1459     {
1460         //
1461         // Free the packet pool that is used to indicate receives
1462         //
1463         NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
1464
1465         pAdapt->RecvPacketPoolHandle = NULL;
1466     }
1467
1468     if (pAdapt->SendPacketPoolHandle != NULL)
1469     {
1470
1471         //
1472         //  Free the packet pool that is used to send packets below
1473         //
1474
1475         NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
1476
1477         pAdapt->SendPacketPoolHandle = NULL;
1478
1479     }
1480 }
1481