xref: /reactos/drivers/network/ndis/ndis/protocol.c (revision 68bcc2df)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS NDIS library
4  * FILE:        ndis/protocol.c
5  * PURPOSE:     Routines used by NDIS protocol drivers
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Vizzini (vizzini@plasmic.com)
8  * REVISIONS:
9  *   CSH 01/08-2000 Created
10  *   09-13-2003 Vizzini Updates for SendPackets support
11  */
12 
13 #include "ndissys.h"
14 
15 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
16 #define LINKAGE_KEY  L"\\Linkage"
17 #define PARAMETERS_KEY L"\\Parameters\\"
18 
19 LIST_ENTRY ProtocolListHead;
20 KSPIN_LOCK ProtocolListLock;
21 
22 #define WORKER_TEST 0
23 
24 typedef struct _DMA_CONTEXT {
25     PLOGICAL_ADAPTER Adapter;
26     PNDIS_PACKET Packet;
27 } DMA_CONTEXT, *PDMA_CONTEXT;
28 
29 PNET_PNP_EVENT
ProSetupPnPEvent(NET_PNP_EVENT_CODE EventCode,PVOID EventBuffer,ULONG EventBufferLength)30 ProSetupPnPEvent(
31     NET_PNP_EVENT_CODE EventCode,
32     PVOID              EventBuffer,
33     ULONG              EventBufferLength)
34 {
35     PNET_PNP_EVENT PnPEvent;
36 
37     PnPEvent = ExAllocatePool(PagedPool, sizeof(NET_PNP_EVENT));
38     if (!PnPEvent) {
39         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
40         return NULL;
41     }
42 
43     RtlZeroMemory(PnPEvent, sizeof(NET_PNP_EVENT));
44 
45     PnPEvent->NetEvent = EventCode;
46 
47     if (EventBuffer != NULL)
48     {
49         PnPEvent->Buffer = ExAllocatePool(PagedPool, EventBufferLength);
50         if (!PnPEvent->Buffer)
51         {
52             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
53             ExFreePool(PnPEvent);
54             return NULL;
55         }
56 
57         PnPEvent->BufferLength = EventBufferLength;
58 
59         RtlCopyMemory(PnPEvent->Buffer, EventBuffer, PnPEvent->BufferLength);
60     }
61 
62     return PnPEvent;
63 }
64 
65 NDIS_STATUS
ProSendAndFreePnPEvent(PLOGICAL_ADAPTER Adapter,PNET_PNP_EVENT PnPEvent,PIRP Irp)66 ProSendAndFreePnPEvent(
67    PLOGICAL_ADAPTER Adapter,
68    PNET_PNP_EVENT   PnPEvent,
69    PIRP             Irp)
70 {
71   PLIST_ENTRY CurrentEntry;
72   NDIS_STATUS Status;
73   PADAPTER_BINDING AdapterBinding;
74 
75   CurrentEntry = Adapter->ProtocolListHead.Flink;
76 
77   while (CurrentEntry != &Adapter->ProtocolListHead)
78   {
79      AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
80 
81      Status = (*AdapterBinding->ProtocolBinding->Chars.PnPEventHandler)(
82       AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
83       PnPEvent);
84 
85      if (Status == NDIS_STATUS_PENDING)
86      {
87          IoMarkIrpPending(Irp);
88          /* Yes, I know this is stupid */
89          PnPEvent->NdisReserved[0] = (ULONG_PTR)Irp;
90          PnPEvent->NdisReserved[1] = (ULONG_PTR)CurrentEntry->Flink;
91          return NDIS_STATUS_PENDING;
92      }
93      else if (Status != NDIS_STATUS_SUCCESS)
94      {
95          if (PnPEvent->Buffer) ExFreePool(PnPEvent->Buffer);
96          ExFreePool(PnPEvent);
97          return Status;
98      }
99 
100      CurrentEntry = CurrentEntry->Flink;
101   }
102 
103   if (PnPEvent->Buffer) ExFreePool(PnPEvent->Buffer);
104   ExFreePool(PnPEvent);
105 
106   return NDIS_STATUS_SUCCESS;
107 }
108 
109 NTSTATUS
110 NTAPI
NdisIPwrSetPower(IN PDEVICE_OBJECT DeviceObject,PIRP Irp)111 NdisIPwrSetPower(
112     IN PDEVICE_OBJECT DeviceObject,
113     PIRP Irp)
114 {
115   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
116   PNET_PNP_EVENT PnPEvent;
117   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
118 
119   ASSERT(Stack->Parameters.Power.Type == DevicePowerState);
120 
121   PnPEvent = ProSetupPnPEvent(NetEventSetPower, &Stack->Parameters.Power.State, sizeof(NDIS_DEVICE_POWER_STATE));
122   if (!PnPEvent) {
123       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
124       return NDIS_STATUS_RESOURCES;
125   }
126 
127   return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
128 }
129 
130 NTSTATUS
131 NTAPI
NdisIPwrQueryPower(IN PDEVICE_OBJECT DeviceObject,PIRP Irp)132 NdisIPwrQueryPower(
133     IN PDEVICE_OBJECT DeviceObject,
134     PIRP Irp)
135 {
136   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
137   PNET_PNP_EVENT PnPEvent;
138   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
139 
140   ASSERT(Stack->Parameters.Power.Type == DevicePowerState);
141 
142   PnPEvent = ProSetupPnPEvent(NetEventQueryPower, &Stack->Parameters.Power.State, sizeof(NDIS_DEVICE_POWER_STATE));
143   if (!PnPEvent) {
144       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
145       return NDIS_STATUS_RESOURCES;
146   }
147 
148   return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
149 }
150 
151 
152 NTSTATUS
153 NTAPI
NdisIPnPQueryStopDevice(IN PDEVICE_OBJECT DeviceObject,PIRP Irp)154 NdisIPnPQueryStopDevice(
155     IN PDEVICE_OBJECT DeviceObject,
156     PIRP Irp)
157 {
158   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
159   PNET_PNP_EVENT PnPEvent;
160 
161   PnPEvent = ProSetupPnPEvent(NetEventQueryRemoveDevice, NULL, 0);
162   if (!PnPEvent) {
163       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
164       return NDIS_STATUS_RESOURCES;
165   }
166 
167   return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
168 }
169 
170 NTSTATUS
171 NTAPI
NdisIPnPCancelStopDevice(IN PDEVICE_OBJECT DeviceObject,PIRP Irp)172 NdisIPnPCancelStopDevice(
173     IN PDEVICE_OBJECT DeviceObject,
174     PIRP Irp)
175 {
176   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
177   PNET_PNP_EVENT PnPEvent;
178 
179   PnPEvent = ProSetupPnPEvent(NetEventCancelRemoveDevice, NULL, 0);
180   if (!PnPEvent) {
181       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
182       return NDIS_STATUS_RESOURCES;
183   }
184 
185   return ProSendAndFreePnPEvent(Adapter, PnPEvent, Irp);
186 }
187 
188 /*
189  * @implemented
190  */
191 VOID
192 EXPORT
NdisCompleteBindAdapter(IN NDIS_HANDLE BindAdapterContext,IN NDIS_STATUS Status,IN NDIS_STATUS OpenStatus)193 NdisCompleteBindAdapter(
194     IN  NDIS_HANDLE BindAdapterContext,
195     IN  NDIS_STATUS Status,
196     IN  NDIS_STATUS OpenStatus)
197 /*
198  * FUNCTION: Indicates a packet to bound protocols
199  * ARGUMENTS:
200  *     Adapter = Pointer to logical adapter
201  *     Packet  = Pointer to packet to indicate
202  * RETURNS:
203  *     Status of operation
204  * NOTES:
205  *     - FIXME: partially-implemented
206  */
207 {
208   PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)BindAdapterContext;
209 
210   if (!NT_SUCCESS(Status)) {
211       NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", Status));
212       return;
213   }
214 
215   /* Put protocol binding struct on global list */
216   ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
217 }
218 
219 /*
220  * @implemented
221  */
222 VOID
223 EXPORT
NdisCompleteUnbindAdapter(IN NDIS_HANDLE UnbindAdapterContext,IN NDIS_STATUS Status)224 NdisCompleteUnbindAdapter(
225     IN  NDIS_HANDLE UnbindAdapterContext,
226     IN  NDIS_STATUS Status)
227 {
228   /* We probably need to do more here but for now we just do
229    * the opposite of what NdisCompleteBindAdapter does
230    */
231 
232   PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)UnbindAdapterContext;
233 
234   if (!NT_SUCCESS(Status)) {
235       NDIS_DbgPrint(MIN_TRACE, ("Unbinding failed (%x)\n", Status));
236       return;
237   }
238 
239   ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock);
240 }
241 
242 NDIS_STATUS
ProIndicatePacket(PLOGICAL_ADAPTER Adapter,PNDIS_PACKET Packet)243 ProIndicatePacket(
244     PLOGICAL_ADAPTER Adapter,
245     PNDIS_PACKET Packet)
246 /*
247  * FUNCTION: Indicates a packet to bound protocols
248  * ARGUMENTS:
249  *     Adapter = Pointer to logical adapter
250  *     Packet  = Pointer to packet to indicate
251  * RETURNS:
252  *     STATUS_SUCCESS in all cases
253  * NOTES:
254  *     - XXX ATM, this only handles loopback packets - is that its designed function?
255  */
256 {
257   UINT BufferedLength;
258   UINT PacketLength;
259   KIRQL OldIrql;
260   PUCHAR LookaheadBuffer;
261 
262   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
263 
264 #if DBG
265   MiniDisplayPacket(Packet, "INDICATE");
266 #endif
267 
268   NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
269 
270   LookaheadBuffer = ExAllocatePool(NonPagedPool, PacketLength);
271   if (!LookaheadBuffer) {
272       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
273       return NDIS_STATUS_RESOURCES;
274   }
275 
276   NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
277   KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
278     {
279       BufferedLength = CopyPacketToBuffer(LookaheadBuffer, Packet, 0, PacketLength);
280       Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = Packet;
281     }
282   KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
283 
284   if (BufferedLength > Adapter->MediumHeaderSize)
285     {
286       /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
287       MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize,
288           &LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize,
289           PacketLength - Adapter->MediumHeaderSize);
290     }
291   else
292     {
293       MiniIndicateData(Adapter, NULL, LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0);
294     }
295 
296   ExFreePool(LookaheadBuffer);
297 
298   KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
299     {
300       Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()] = NULL;
301     }
302   KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
303 
304   return NDIS_STATUS_SUCCESS;
305 }
306 
307 NDIS_STATUS NTAPI
ProRequest(IN NDIS_HANDLE MacBindingHandle,IN PNDIS_REQUEST NdisRequest)308 ProRequest(
309     IN  NDIS_HANDLE     MacBindingHandle,
310     IN  PNDIS_REQUEST   NdisRequest)
311 /*
312  * FUNCTION: Forwards a request to an NDIS miniport
313  * ARGUMENTS:
314  *     MacBindingHandle = Adapter binding handle
315  *     NdisRequest      = Pointer to request to perform
316  * RETURNS:
317  *     Status of operation
318  */
319 {
320   PADAPTER_BINDING AdapterBinding;
321   PLOGICAL_ADAPTER Adapter;
322   PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)NdisRequest->MacReserved;
323 
324   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
325 
326   ASSERT(MacBindingHandle);
327   AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
328 
329   ASSERT(AdapterBinding->Adapter);
330   Adapter = AdapterBinding->Adapter;
331 
332   MacBlock->Binding = &AdapterBinding->NdisOpenBlock;
333 
334 #if WORKER_TEST
335   MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE);
336   return NDIS_STATUS_PENDING;
337 #else
338   if (MiniIsBusy(Adapter, NdisWorkItemRequest)) {
339       MiniQueueWorkItem(Adapter, NdisWorkItemRequest, NdisRequest, FALSE);
340       return NDIS_STATUS_PENDING;
341   }
342 
343   return MiniDoRequest(Adapter, NdisRequest);
344 #endif
345 }
346 
347 
348 NDIS_STATUS NTAPI
ProReset(IN NDIS_HANDLE MacBindingHandle)349 ProReset(
350     IN  NDIS_HANDLE MacBindingHandle)
351 {
352     PADAPTER_BINDING AdapterBinding = MacBindingHandle;
353 
354     /* FIXME: Wait for all packets to be sent */
355 
356     return MiniReset(AdapterBinding->Adapter);
357 }
358 
359 VOID NTAPI
ScatterGatherSendPacket(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PSCATTER_GATHER_LIST ScatterGather,IN PVOID Context)360 ScatterGatherSendPacket(
361    IN PDEVICE_OBJECT DeviceObject,
362    IN PIRP Irp,
363    IN PSCATTER_GATHER_LIST ScatterGather,
364    IN PVOID Context)
365 {
366    PDMA_CONTEXT DmaContext = Context;
367    PLOGICAL_ADAPTER Adapter = DmaContext->Adapter;
368    PNDIS_PACKET Packet = DmaContext->Packet;
369    NDIS_STATUS Status;
370 
371    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
372 
373    NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
374                                     ScatterGatherListPacketInfo) = ScatterGather;
375 
376    Status = proSendPacketToMiniport(Adapter, Packet);
377 
378    if (Status != NDIS_STATUS_PENDING) {
379        NDIS_DbgPrint(MAX_TRACE, ("Completing packet.\n"));
380        MiniSendComplete(Adapter,
381                         Packet,
382                         Status);
383    }
384 
385    ExFreePool(DmaContext);
386 }
387 
388 NDIS_STATUS
proSendPacketToMiniport(PLOGICAL_ADAPTER Adapter,PNDIS_PACKET Packet)389 proSendPacketToMiniport(PLOGICAL_ADAPTER Adapter, PNDIS_PACKET Packet)
390 {
391 #if WORKER_TEST
392    MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE);
393    return NDIS_STATUS_PENDING;
394 #else
395    KIRQL RaiseOldIrql;
396    NDIS_STATUS NdisStatus;
397 
398    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
399 
400    if(MiniIsBusy(Adapter, NdisWorkItemSend)) {
401       NDIS_DbgPrint(MID_TRACE, ("Busy: NdisWorkItemSend.\n"));
402 
403       MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE);
404       return NDIS_STATUS_PENDING;
405    }
406 
407 #if DBG
408    MiniDisplayPacket(Packet, "SEND");
409 #endif
410 
411    if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
412    {
413         if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
414         {
415             NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
416             (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
417              Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
418              NdisStatus = NDIS_STATUS_PENDING;
419         } else {
420             /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
421             KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
422             {
423                NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
424                (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
425                 Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
426             }
427             KeLowerIrql(RaiseOldIrql);
428 
429             NdisStatus = NDIS_GET_PACKET_STATUS(Packet);
430             if (NdisStatus == NDIS_STATUS_RESOURCES) {
431                 MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
432                 NdisStatus = NDIS_STATUS_PENDING;
433             }
434         }
435 
436         if (NdisStatus != NDIS_STATUS_PENDING) {
437             MiniWorkItemComplete(Adapter, NdisWorkItemSend);
438         }
439 
440         return NdisStatus;
441    } else {
442         if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
443         {
444             NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
445             NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
446                           Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
447             NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
448         } else {
449             /* Send is called at DISPATCH_LEVEL for all serialized miniports */
450             KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
451             NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
452             NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
453                           Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
454             NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
455             KeLowerIrql(RaiseOldIrql);
456 
457             if (NdisStatus == NDIS_STATUS_RESOURCES) {
458                 MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
459                 NdisStatus = NDIS_STATUS_PENDING;
460             }
461         }
462 
463         if (NdisStatus != NDIS_STATUS_PENDING) {
464             MiniWorkItemComplete(Adapter, NdisWorkItemSend);
465         }
466 
467         return NdisStatus;
468    }
469 #endif
470 }
471 
472 NDIS_STATUS NTAPI
ProSend(IN NDIS_HANDLE MacBindingHandle,IN PNDIS_PACKET Packet)473 ProSend(
474     IN  NDIS_HANDLE     MacBindingHandle,
475     IN  PNDIS_PACKET    Packet)
476 /*
477  * FUNCTION: Forwards a request to send a packet to an NDIS miniport
478  * ARGUMENTS:
479  *     MacBindingHandle = Adapter binding handle
480  *     Packet           = Pointer to NDIS packet descriptor
481  * RETURNS:
482  *     NDIS_STATUS_SUCCESS if the packet was successfully sent
483  *     NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES
484  */
485 {
486   PADAPTER_BINDING AdapterBinding;
487   PLOGICAL_ADAPTER Adapter;
488   PNDIS_BUFFER NdisBuffer;
489   PDMA_CONTEXT Context;
490   NDIS_STATUS NdisStatus;
491   UINT PacketLength;
492   KIRQL OldIrql;
493 
494   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
495 
496   ASSERT(MacBindingHandle);
497   AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
498 
499   ASSERT(AdapterBinding);
500   Adapter = AdapterBinding->Adapter;
501 
502   ASSERT(Adapter);
503 
504   /* if the following is not true, KeRaiseIrql() below will break */
505   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
506 
507   /* XXX what is this crazy black magic? */
508   Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle;
509 
510   /*
511    * Test the packet to see if it is a MAC loopback.
512    *
513    * We may have to loop this packet if miniport cannot.
514    * If dest MAC address of packet == MAC address of adapter,
515    * this is a loopback frame.
516    */
517 
518   if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
519       MiniAdapterHasAddress(Adapter, Packet))
520     {
521 #if WORKER_TEST
522         MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE);
523         return NDIS_STATUS_PENDING;
524 #else
525         return ProIndicatePacket(Adapter, Packet);
526 #endif
527     } else {
528         if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0)
529         {
530             NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n"));
531 
532             NdisQueryPacket(Packet,
533                             NULL,
534                             NULL,
535                             &NdisBuffer,
536                             &PacketLength);
537 
538             Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT));
539             if (!Context) {
540                 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
541                 return NDIS_STATUS_RESOURCES;
542             }
543 
544             Context->Adapter = Adapter;
545             Context->Packet = Packet;
546 
547             KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
548 
549             KeFlushIoBuffers(NdisBuffer, FALSE, TRUE);
550 
551             NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList(
552                           Adapter->NdisMiniportBlock.SystemAdapterObject,
553                           Adapter->NdisMiniportBlock.PhysicalDeviceObject,
554                           NdisBuffer,
555                           MmGetMdlVirtualAddress(NdisBuffer),
556                           PacketLength,
557                           ScatterGatherSendPacket,
558                           Context,
559                           TRUE);
560 
561             KeLowerIrql(OldIrql);
562 
563             if (!NT_SUCCESS(NdisStatus)) {
564                 NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus));
565                 return NdisStatus;
566             }
567 
568             return NDIS_STATUS_PENDING;
569         }
570 
571 
572         return proSendPacketToMiniport(Adapter, Packet);
573     }
574 }
575 
576 VOID NTAPI
ProSendPackets(IN NDIS_HANDLE NdisBindingHandle,IN PPNDIS_PACKET PacketArray,IN UINT NumberOfPackets)577 ProSendPackets(
578     IN  NDIS_HANDLE     NdisBindingHandle,
579     IN  PPNDIS_PACKET   PacketArray,
580     IN  UINT            NumberOfPackets)
581 {
582     PADAPTER_BINDING AdapterBinding = NdisBindingHandle;
583     PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
584     KIRQL RaiseOldIrql;
585     NDIS_STATUS NdisStatus;
586     UINT i;
587 
588     if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
589     {
590        if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
591        {
592           (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
593            Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
594        }
595        else
596        {
597           /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
598           KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
599           (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
600            Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
601           KeLowerIrql(RaiseOldIrql);
602           for (i = 0; i < NumberOfPackets; i++)
603           {
604              NdisStatus = NDIS_GET_PACKET_STATUS(PacketArray[i]);
605              if (NdisStatus != NDIS_STATUS_PENDING)
606                  MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
607           }
608        }
609      }
610      else
611      {
612        if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
613        {
614           for (i = 0; i < NumberOfPackets; i++)
615           {
616              NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
617                            Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
618              if (NdisStatus != NDIS_STATUS_PENDING)
619                  MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
620           }
621        }
622        else
623        {
624          /* Send is called at DISPATCH_LEVEL for all serialized miniports */
625          KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
626          for (i = 0; i < NumberOfPackets; i++)
627          {
628             NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
629                            Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
630             if (NdisStatus != NDIS_STATUS_PENDING)
631                 MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
632          }
633          KeLowerIrql(RaiseOldIrql);
634        }
635      }
636 }
637 
638 NDIS_STATUS NTAPI
ProTransferData(IN NDIS_HANDLE MacBindingHandle,IN NDIS_HANDLE MacReceiveContext,IN UINT ByteOffset,IN UINT BytesToTransfer,IN OUT PNDIS_PACKET Packet,OUT PUINT BytesTransferred)639 ProTransferData(
640     IN  NDIS_HANDLE         MacBindingHandle,
641     IN  NDIS_HANDLE         MacReceiveContext,
642     IN  UINT                ByteOffset,
643     IN  UINT                BytesToTransfer,
644     IN  OUT PNDIS_PACKET    Packet,
645     OUT PUINT               BytesTransferred)
646 /*
647  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
648  * ARGUMENTS:
649  *     MacBindingHandle  = Adapter binding handle
650  *     MacReceiveContext = MAC receive context
651  *     ByteOffset        = Offset in packet to place data
652  *     BytesToTransfer   = Number of bytes to copy into packet
653  *     Packet            = Pointer to NDIS packet descriptor
654  *     BytesTransferred  = Address of buffer to place number of bytes copied
655  */
656 {
657     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
658     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
659     NDIS_STATUS Status;
660     KIRQL OldIrql;
661 
662     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
663 
664     /* FIXME: Interrupts must be disabled for adapter */
665     /* XXX sd - why is that true? */
666 
667     if (Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()]) {
668 	NDIS_DbgPrint(MAX_TRACE, ("LoopPacket\n"));
669         /* NDIS is responsible for looping this packet */
670         NdisCopyFromPacketToPacket(Packet,
671                                    ByteOffset + Adapter->MediumHeaderSize,
672                                    BytesToTransfer + Adapter->MediumHeaderSize,
673                                    Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()],
674                                    0,
675                                    BytesTransferred);
676         return NDIS_STATUS_SUCCESS;
677     }
678 
679     ASSERT(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler);
680 
681     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
682 
683     Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
684         Packet,
685         BytesTransferred,
686         Adapter->NdisMiniportBlock.MiniportAdapterContext,
687         MacReceiveContext,
688         ByteOffset,
689         BytesToTransfer);
690 
691     KeLowerIrql(OldIrql);
692 
693     return Status;
694 }
695 
696 
697 
698 /*
699  * @implemented
700  */
701 VOID
702 EXPORT
NdisCloseAdapter(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisBindingHandle)703 NdisCloseAdapter(
704     OUT PNDIS_STATUS    Status,
705     IN  NDIS_HANDLE     NdisBindingHandle)
706 /*
707  * FUNCTION: Closes an adapter opened with NdisOpenAdapter
708  * ARGUMENTS:
709  *     Status            = Address of buffer for status information
710  *     NdisBindingHandle = Handle returned by NdisOpenAdapter
711  */
712 {
713     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
714 
715     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
716 
717     /* Remove from protocol's bound adapters list */
718     ExInterlockedRemoveEntryList(&AdapterBinding->ProtocolListEntry, &AdapterBinding->ProtocolBinding->Lock);
719 
720     /* Remove protocol from adapter's bound protocols list */
721     ExInterlockedRemoveEntryList(&AdapterBinding->AdapterListEntry, &AdapterBinding->Adapter->NdisMiniportBlock.Lock);
722 
723     ExFreePool(AdapterBinding);
724 
725     *Status = NDIS_STATUS_SUCCESS;
726 }
727 
728 
729 /*
730  * @implemented
731  */
732 VOID
733 EXPORT
NdisDeregisterProtocol(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisProtocolHandle)734 NdisDeregisterProtocol(
735     OUT PNDIS_STATUS    Status,
736     IN NDIS_HANDLE      NdisProtocolHandle)
737 /*
738  * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
739  * ARGUMENTS:
740  *     Status             = Address of buffer for status information
741  *     NdisProtocolHandle = Handle returned by NdisRegisterProtocol
742  */
743 {
744     PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
745 
746     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
747 
748     /* FIXME: Make sure no adapter bindings exist */
749 
750     /* Remove protocol from global list */
751     ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock);
752 
753     ExFreePool(Protocol);
754 
755     *Status = NDIS_STATUS_SUCCESS;
756 }
757 
758 
759 /*
760  * @implemented
761  */
762 VOID
763 EXPORT
NdisOpenAdapter(OUT PNDIS_STATUS Status,OUT PNDIS_STATUS OpenErrorStatus,OUT PNDIS_HANDLE NdisBindingHandle,OUT PUINT SelectedMediumIndex,IN PNDIS_MEDIUM MediumArray,IN UINT MediumArraySize,IN NDIS_HANDLE NdisProtocolHandle,IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_STRING AdapterName,IN UINT OpenOptions,IN PSTRING AddressingInformation OPTIONAL)764 NdisOpenAdapter(
765     OUT PNDIS_STATUS    Status,
766     OUT PNDIS_STATUS    OpenErrorStatus,
767     OUT PNDIS_HANDLE    NdisBindingHandle,
768     OUT PUINT           SelectedMediumIndex,
769     IN  PNDIS_MEDIUM    MediumArray,
770     IN  UINT            MediumArraySize,
771     IN  NDIS_HANDLE     NdisProtocolHandle,
772     IN  NDIS_HANDLE     ProtocolBindingContext,
773     IN  PNDIS_STRING    AdapterName,
774     IN  UINT            OpenOptions,
775     IN  PSTRING         AddressingInformation   OPTIONAL)
776 /*
777  * FUNCTION: Opens an adapter for communication
778  * ARGUMENTS:
779  *     Status                 = Address of buffer for status information
780  *     OpenErrorStatus        = Address of buffer for secondary error code
781  *     NdisBindingHandle      = Address of buffer for adapter binding handle
782  *     SelectedMediumIndex    = Address of buffer for selected medium
783  *     MediumArray            = Pointer to an array of NDIS_MEDIUMs called can support
784  *     MediumArraySize        = Number of elements in MediumArray
785  *     NdisProtocolHandle     = Handle returned by NdisRegisterProtocol
786  *     ProtocolBindingContext = Pointer to caller supplied context area
787  *     AdapterName            = Pointer to buffer with name of adapter
788  *     OpenOptions            = Bitmask with flags passed to next-lower driver
789  *     AddressingInformation  = Optional pointer to buffer with NIC specific information
790  */
791 {
792   UINT i;
793   BOOLEAN Found;
794   PLOGICAL_ADAPTER Adapter;
795   PADAPTER_BINDING AdapterBinding;
796   PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
797 
798   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
799 
800   if(!NdisProtocolHandle)
801     {
802       NDIS_DbgPrint(MIN_TRACE, ("NdisProtocolHandle is NULL\n"));
803       *OpenErrorStatus = *Status = NDIS_STATUS_FAILURE;
804       return;
805     }
806 
807   Adapter = MiniLocateDevice(AdapterName);
808   if (!Adapter)
809     {
810       NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
811       *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
812       return;
813     }
814 
815   /* Find the media type in the list provided by the protocol driver */
816   Found = FALSE;
817   for (i = 0; i < MediumArraySize; i++)
818     {
819       if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i])
820         {
821           *SelectedMediumIndex = i;
822           Found = TRUE;
823           break;
824         }
825     }
826 
827   if (!Found)
828     {
829       NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
830       *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
831       return;
832     }
833 
834   /* Now that we have confirmed that the adapter can be opened, create a binding */
835 
836   AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
837   if (!AdapterBinding)
838     {
839       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
840       *Status = NDIS_STATUS_RESOURCES;
841       return;
842     }
843 
844   RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
845 
846   AdapterBinding->ProtocolBinding        = Protocol;
847   AdapterBinding->Adapter                = Adapter;
848   AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
849 
850   /* Set fields required by some NDIS macros */
851   AdapterBinding->NdisOpenBlock.BindingHandle = (NDIS_HANDLE)AdapterBinding;
852 
853   /* Set handlers (some NDIS macros require these) */
854 
855   AdapterBinding->NdisOpenBlock.RequestHandler      = ProRequest;
856   AdapterBinding->NdisOpenBlock.ResetHandler        = ProReset;
857   AdapterBinding->NdisOpenBlock.SendHandler         = ProSend;
858   AdapterBinding->NdisOpenBlock.SendPacketsHandler  = ProSendPackets;
859   AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
860 
861   AdapterBinding->NdisOpenBlock.RequestCompleteHandler =
862     Protocol->Chars.RequestCompleteHandler;
863 
864   /* Put on protocol's bound adapters list */
865   ExInterlockedInsertTailList(&Protocol->AdapterListHead, &AdapterBinding->ProtocolListEntry, &Protocol->Lock);
866 
867   /* Put protocol on adapter's bound protocols list */
868   NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
869   ExInterlockedInsertTailList(&Adapter->ProtocolListHead, &AdapterBinding->AdapterListEntry, &Adapter->NdisMiniportBlock.Lock);
870 
871   *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
872 
873   *Status = NDIS_STATUS_SUCCESS;
874 }
875 
876 PADAPTER_BINDING
877 NTAPI
LocateAdapterBindingByName(IN PPROTOCOL_BINDING ProtocolBinding,IN PNDIS_STRING AdapterName)878 LocateAdapterBindingByName(IN PPROTOCOL_BINDING ProtocolBinding, IN PNDIS_STRING AdapterName)
879 {
880     PLIST_ENTRY CurrentEntry;
881     PADAPTER_BINDING AdapterBinding;
882     KIRQL OldIrql;
883 
884     KeAcquireSpinLock(&ProtocolBinding->Lock, &OldIrql);
885 
886     CurrentEntry = ProtocolBinding->AdapterListHead.Flink;
887 
888     while (CurrentEntry != &ProtocolBinding->AdapterListHead)
889     {
890          AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, ProtocolListEntry);
891 
892          if (RtlCompareUnicodeString(AdapterName, &AdapterBinding->Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
893          {
894              KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
895              return AdapterBinding;
896          }
897 
898          CurrentEntry = CurrentEntry->Flink;
899     }
900 
901     KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
902 
903     return NULL;
904 }
905 
906 VOID
907 NTAPI
ndisBindMiniportsToProtocol(OUT PNDIS_STATUS Status,IN PPROTOCOL_BINDING Protocol)908 ndisBindMiniportsToProtocol(OUT PNDIS_STATUS Status, IN PPROTOCOL_BINDING Protocol)
909 {
910   /*
911    * bind the protocol to all of its miniports
912    *
913    * open registry path
914    * get list of devices from Bind key
915    * call BindAdapterHandler for each
916    */
917     OBJECT_ATTRIBUTES ObjectAttributes;
918     UNICODE_STRING RegistryPath;
919     WCHAR *RegistryPathStr, *DataPtr = NULL;
920     NTSTATUS NtStatus;
921     HANDLE DriverKeyHandle = NULL;
922     PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
923     PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics = &Protocol->Chars;
924     UNICODE_STRING ValueName;
925     ULONG ResultLength;
926     PLIST_ENTRY CurrentEntry = NULL;
927 
928     RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__);
929     if(!RegistryPathStr)
930     {
931         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
932         *Status = NDIS_STATUS_RESOURCES;
933         return;
934     }
935 
936     wcscpy(RegistryPathStr, SERVICES_KEY);
937     wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
938     RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
939     wcscat(RegistryPathStr, LINKAGE_KEY);
940 
941     RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
942     NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
943 
944     InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
945     NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
946 
947     ExFreePool(RegistryPathStr);
948 
949     if(NT_SUCCESS(NtStatus))
950     {
951         NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
952 
953         RtlInitUnicodeString(&ValueName, L"Bind");
954 
955         NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
956         if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL && NtStatus != STATUS_SUCCESS)
957         {
958             NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value for size\n"));
959             ZwClose(DriverKeyHandle);
960         }
961         else
962         {
963             KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__);
964             if(!KeyInformation)
965             {
966                 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
967                 ZwClose(DriverKeyHandle);
968                 NtStatus = STATUS_NO_MEMORY;
969             }
970             else
971             {
972                 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
973                                            sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
974 
975                 ZwClose(DriverKeyHandle);
976 
977                 if(!NT_SUCCESS(NtStatus))
978                 {
979                     NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
980                     ExFreePool(KeyInformation);
981                     KeyInformation = NULL;
982                 }
983             }
984         }
985     }
986 
987     if (!NT_SUCCESS(NtStatus))
988     {
989         NDIS_DbgPrint(MID_TRACE, ("Performing global bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
990         KeyInformation = NULL;
991 
992         CurrentEntry = AdapterListHead.Flink;
993     }
994     else
995     {
996         NDIS_DbgPrint(MID_TRACE, ("Performing standard bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
997 
998         DataPtr = (WCHAR*)KeyInformation->Data;
999     }
1000 
1001     /* Assume success for now */
1002     *Status = NDIS_STATUS_SUCCESS;
1003 
1004     while (TRUE)
1005     {
1006         /* BindContext is for tracking pending binding operations */
1007         VOID *BindContext = 0;
1008         NDIS_STRING DeviceName;
1009         NDIS_STRING RegistryPath;
1010         WCHAR *RegistryPathStr = NULL;
1011         ULONG PathLength = 0;
1012         PLOGICAL_ADAPTER Adapter;
1013 
1014         if (KeyInformation)
1015         {
1016             /* Parse the REG_MULTI_SZ entry for device names */
1017             if (!(*DataPtr))
1018                 break;
1019 
1020             RtlInitUnicodeString(&DeviceName, DataPtr);
1021         }
1022         else
1023         {
1024             /* Use the device name from the global adapter list */
1025             if (CurrentEntry == &AdapterListHead)
1026                 break;
1027 
1028             Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
1029 
1030             DeviceName = Adapter->NdisMiniportBlock.MiniportName;
1031         }
1032 
1033         /* Make sure the adapter has started */
1034         if (!MiniLocateDevice(&DeviceName))
1035         {
1036             /* It wasn't in the global miniport list, so skip the bind entry */
1037             goto next;
1038         }
1039 
1040         /* Make sure this device isn't already bound to this protocol */
1041         if (LocateAdapterBindingByName(Protocol, &DeviceName))
1042         {
1043             /* It was already in this protocol's bound adapter list, so skip the bind entry */
1044             goto next;
1045         }
1046 
1047         /*
1048          * RegistryPath should be:
1049          *     \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
1050          *
1051          *  This is constructed as follows:
1052          *      SERVICES_KEY + extracted device name + Protocol name from characteristics
1053          */
1054 
1055         PathLength = sizeof(SERVICES_KEY) +                               /* \Registry\Machine\System\CurrentControlSet\Services\ */
1056         wcslen( DeviceName.Buffer + 8 ) * sizeof(WCHAR) + /* Adapter1  (extracted from \Device\Adapter1)          */
1057         sizeof(PARAMETERS_KEY) +                                      /* \Parameters\                                         */
1058         ProtocolCharacteristics->Name.Length + sizeof(WCHAR);                         /* Tcpip                                                */
1059 
1060         RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
1061         if(!RegistryPathStr)
1062         {
1063             NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
1064             *Status = NDIS_STATUS_RESOURCES;
1065             break;
1066         }
1067 
1068         wcscpy(RegistryPathStr, SERVICES_KEY);
1069         wcscat(RegistryPathStr, DeviceName.Buffer + 8 );
1070         wcscat(RegistryPathStr, PARAMETERS_KEY);
1071         wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
1072 
1073         RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
1074 
1075         RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
1076 
1077         NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
1078                                   &DeviceName, &RegistryPath));
1079 
1080         {
1081             BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
1082             if(BindHandler)
1083             {
1084                 BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
1085                 NDIS_DbgPrint(MID_TRACE, ("%wZ's BindAdapter handler returned 0x%x for %wZ\n", &ProtocolCharacteristics->Name, *Status, &DeviceName));
1086             }
1087             else
1088                 NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
1089         }
1090 
1091     next:
1092         if (KeyInformation)
1093         {
1094             /* Advance to the next adapter in the REG_MULTI_SZ */
1095             DataPtr += (DeviceName.Length / sizeof(WCHAR)) + 1;
1096         }
1097         else
1098         {
1099             /* Advance to the next adapter in the global list */
1100             CurrentEntry = CurrentEntry->Flink;
1101         }
1102     }
1103 
1104     if (KeyInformation)
1105     {
1106         ExFreePool(KeyInformation);
1107     }
1108 }
1109 
1110 /*
1111  * @implemented
1112  */
1113 VOID
1114 EXPORT
NdisRegisterProtocol(OUT PNDIS_STATUS Status,OUT PNDIS_HANDLE NdisProtocolHandle,IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,IN UINT CharacteristicsLength)1115 NdisRegisterProtocol(
1116     OUT PNDIS_STATUS                    Status,
1117     OUT PNDIS_HANDLE                    NdisProtocolHandle,
1118     IN  PNDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,
1119     IN  UINT                            CharacteristicsLength)
1120 /*
1121  * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
1122  * ARGUMENTS:
1123  *     Status                  = Address of buffer for status information
1124  *     NdisProtocolHandle      = Address of buffer for handle used to identify the driver
1125  *     ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
1126  *     CharacteristicsLength   = Size of structure which ProtocolCharacteristics targets
1127  * NOTES:
1128  *     - you *must* set NdisProtocolHandle before doing anything that could wind up
1129  *       getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
1130  *     - the above implies that the initialization of the protocol block must be complete
1131  *       by then
1132  * TODO:
1133  *     - break this function up - probably do a 'ndisRefreshProtocolBindings' function
1134  *     - make this thing able to handle >1 protocol
1135  */
1136 {
1137   PPROTOCOL_BINDING Protocol;
1138   NTSTATUS NtStatus;
1139   UINT MinSize;
1140   PNET_PNP_EVENT PnPEvent;
1141 
1142   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1143 
1144   *NdisProtocolHandle = NULL;
1145 
1146   /* first validate the PROTOCOL_CHARACTERISTICS */
1147   switch (ProtocolCharacteristics->MajorNdisVersion)
1148     {
1149     case 0x03:
1150       /* we don't really want to support ndis3 drivers - so we complain for now */
1151       NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n"));
1152       MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
1153       break;
1154 
1155     case 0x04:
1156       MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
1157       break;
1158 
1159     case 0x05:
1160       MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
1161       break;
1162 
1163     default:
1164       *Status = NDIS_STATUS_BAD_VERSION;
1165       NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
1166       return;
1167     }
1168 
1169   if (CharacteristicsLength < MinSize)
1170     {
1171       NDIS_DbgPrint(MIN_TRACE, ("Bad protocol characteristics.\n"));
1172       *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
1173       return;
1174     }
1175 
1176   /* set up the protocol block */
1177   Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
1178   if (!Protocol)
1179     {
1180       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1181       *Status = NDIS_STATUS_RESOURCES;
1182       return;
1183     }
1184 
1185   RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
1186   RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
1187 
1188   NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);
1189   if (!NT_SUCCESS(NtStatus))
1190     {
1191       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1192       ExFreePool(Protocol);
1193       *Status = NDIS_STATUS_RESOURCES;
1194       return;
1195     }
1196 
1197   KeInitializeSpinLock(&Protocol->Lock);
1198 
1199   InitializeListHead(&Protocol->AdapterListHead);
1200 
1201   /* We must set this before the call to ndisBindMiniportsToProtocol because the protocol's
1202    * BindAdapter handler might need it */
1203 
1204   *NdisProtocolHandle = Protocol;
1205 
1206   ndisBindMiniportsToProtocol(Status, Protocol);
1207 
1208   /* Should we only send this if ndisBindMiniportsToProtocol succeeds? */
1209   PnPEvent = ProSetupPnPEvent(NetEventBindsComplete, NULL, 0);
1210   if (PnPEvent)
1211   {
1212       if (Protocol->Chars.PnPEventHandler)
1213       {
1214           /* We call this with a NULL binding context because it affects all bindings */
1215           NtStatus = (*Protocol->Chars.PnPEventHandler)(NULL,
1216                                                         PnPEvent);
1217 
1218           /* FIXME: We don't support this yet */
1219           ASSERT(NtStatus != NDIS_STATUS_PENDING);
1220       }
1221 
1222       ExFreePool(PnPEvent);
1223   }
1224 
1225   if (*Status == NDIS_STATUS_SUCCESS) {
1226       ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
1227   } else {
1228       NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", *Status));
1229       ExFreePool(Protocol);
1230       *NdisProtocolHandle = NULL;
1231   }
1232 }
1233 
1234 /*
1235  * @implemented
1236  */
1237 VOID
1238 EXPORT
NdisRequest(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisBindingHandle,IN PNDIS_REQUEST NdisRequest)1239 NdisRequest(
1240     OUT PNDIS_STATUS    Status,
1241     IN  NDIS_HANDLE     NdisBindingHandle,
1242     IN  PNDIS_REQUEST   NdisRequest)
1243 /*
1244  * FUNCTION: Forwards a request to an NDIS driver
1245  * ARGUMENTS:
1246  *     Status            = Address of buffer for status information
1247  *     NdisBindingHandle = Adapter binding handle
1248  *     NdisRequest       = Pointer to request to perform
1249  */
1250 {
1251     *Status = ProRequest(NdisBindingHandle, NdisRequest);
1252 }
1253 
1254 /*
1255  * @implemented
1256  */
1257 VOID
1258 EXPORT
NdisReset(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisBindingHandle)1259 NdisReset(
1260     OUT PNDIS_STATUS    Status,
1261     IN  NDIS_HANDLE     NdisBindingHandle)
1262 {
1263     *Status = ProReset(NdisBindingHandle);
1264 }
1265 
1266 /*
1267  * @implemented
1268  */
1269 #undef NdisSend
1270 VOID
1271 EXPORT
NdisSend(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisBindingHandle,IN PNDIS_PACKET Packet)1272 NdisSend(
1273     OUT PNDIS_STATUS    Status,
1274     IN  NDIS_HANDLE     NdisBindingHandle,
1275     IN  PNDIS_PACKET    Packet)
1276 /*
1277  * FUNCTION: Forwards a request to send a packet
1278  * ARGUMENTS:
1279  *     Status             = Address of buffer for status information
1280  *     NdisBindingHandle  = Adapter binding handle
1281  *     Packet             = Pointer to NDIS packet descriptor
1282  */
1283 {
1284     *Status = ProSend(NdisBindingHandle, Packet);
1285 }
1286 
1287 /*
1288  * @implemented
1289  */
1290 #undef NdisSendPackets
1291 VOID
1292 EXPORT
NdisSendPackets(IN NDIS_HANDLE NdisBindingHandle,IN PPNDIS_PACKET PacketArray,IN UINT NumberOfPackets)1293 NdisSendPackets(
1294     IN  NDIS_HANDLE     NdisBindingHandle,
1295     IN  PPNDIS_PACKET   PacketArray,
1296     IN  UINT            NumberOfPackets)
1297 {
1298     ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
1299 }
1300 
1301 /*
1302  * @implemented
1303  */
1304 #undef NdisTransferData
1305 VOID
1306 EXPORT
NdisTransferData(OUT PNDIS_STATUS Status,IN NDIS_HANDLE NdisBindingHandle,IN NDIS_HANDLE MacReceiveContext,IN UINT ByteOffset,IN UINT BytesToTransfer,IN OUT PNDIS_PACKET Packet,OUT PUINT BytesTransferred)1307 NdisTransferData(
1308     OUT     PNDIS_STATUS    Status,
1309     IN      NDIS_HANDLE     NdisBindingHandle,
1310     IN      NDIS_HANDLE     MacReceiveContext,
1311     IN      UINT            ByteOffset,
1312     IN      UINT            BytesToTransfer,
1313     IN OUT	PNDIS_PACKET    Packet,
1314     OUT     PUINT           BytesTransferred)
1315 /*
1316  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
1317  * ARGUMENTS:
1318  *     Status            = Address of buffer for status information
1319  *     NdisBindingHandle = Adapter binding handle
1320  *     MacReceiveContext = MAC receive context
1321  *     ByteOffset        = Offset in packet to place data
1322  *     BytesToTransfer   = Number of bytes to copy into packet
1323  *     Packet            = Pointer to NDIS packet descriptor
1324  *     BytesTransferred  = Address of buffer to place number of bytes copied
1325  */
1326 {
1327     *Status = ProTransferData(NdisBindingHandle,
1328                               MacReceiveContext,
1329                               ByteOffset,
1330                               BytesToTransfer,
1331                               Packet,
1332                               BytesTransferred);
1333 }
1334 
1335 /*
1336  * @implemented
1337  */
1338 VOID
1339 NTAPI
NdisReEnumerateProtocolBindings(IN NDIS_HANDLE NdisProtocolHandle)1340 NdisReEnumerateProtocolBindings(IN NDIS_HANDLE NdisProtocolHandle)
1341 {
1342     NDIS_STATUS NdisStatus;
1343 
1344     ndisBindMiniportsToProtocol(&NdisStatus, NdisProtocolHandle);
1345 }
1346 
1347 
1348 /*
1349  * @implemented
1350  */
1351 VOID
1352 EXPORT
NdisGetDriverHandle(IN PNDIS_HANDLE NdisBindingHandle,OUT PNDIS_HANDLE NdisDriverHandle)1353 NdisGetDriverHandle(
1354     IN  PNDIS_HANDLE    NdisBindingHandle,
1355     OUT PNDIS_HANDLE    NdisDriverHandle)
1356 /*
1357  * FUNCTION:
1358  * ARGUMENTS:
1359  * NOTES:
1360  *    NDIS 5.0
1361  */
1362 {
1363     PADAPTER_BINDING Binding = (PADAPTER_BINDING)NdisBindingHandle;
1364 
1365     if (!Binding)
1366     {
1367         NDIS_DbgPrint(MIN_TRACE, ("Bad binding handle\n"));
1368         *NdisDriverHandle = NULL;
1369         return;
1370     }
1371 
1372     *NdisDriverHandle = Binding->Adapter->NdisMiniportBlock.DriverHandle;
1373 }
1374 
1375 /* EOF */
1376