update for HEAD-2003091401
[reactos.git] / drivers / net / ndis / ndis / protocol.c
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  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 #include <ndissys.h>
11 #include <miniport.h>
12 #include <protocol.h>
13 #include <buffer.h>
14
15
16 LIST_ENTRY ProtocolListHead;
17 KSPIN_LOCK ProtocolListLock;
18
19 /*
20  * @implemented
21  */
22 VOID
23 EXPORT
24 NdisCompleteBindAdapter(
25     IN  NDIS_HANDLE BindAdapterContext,
26     IN  NDIS_STATUS Status,
27     IN  NDIS_STATUS OpenStatus)
28 /*
29  * FUNCTION: Indicates a packet to bound protocols
30  * ARGUMENTS:
31  *     Adapter = Pointer to logical adapter
32  *     Packet  = Pointer to packet to indicate
33  * RETURNS:
34  *     Status of operation
35  */
36 {
37     /* 
38           * XXX partially-implemented!
39           *
40           * need to handle error conditions, and i'm not sure this is even what this func should do.
41           * be sure to fix NdisRegisterProtocol before fixing this, though.
42           */
43
44     PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)BindAdapterContext;
45
46     /* Put protocol binding struct on global list */
47     ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
48 }
49
50
51 NDIS_STATUS
52 ProIndicatePacket(
53     PLOGICAL_ADAPTER Adapter,
54     PNDIS_PACKET Packet)
55 /*
56  * FUNCTION: Indicates a packet to bound protocols
57  * ARGUMENTS:
58  *     Adapter = Pointer to logical adapter
59  *     Packet  = Pointer to packet to indicate
60  * RETURNS:
61  *     Status of operation
62  */
63 {
64     KIRQL OldIrql;
65     UINT Length;
66     UINT Total;
67
68     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
69
70 #ifdef DBG
71     MiniDisplayPacket(Packet);
72 #endif
73
74     NdisQueryPacket(Packet, NULL, NULL, NULL, &Total);
75
76     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
77
78     Adapter->LoopPacket = Packet;
79
80     Length = CopyPacketToBuffer(
81         Adapter->LookaheadBuffer,
82         Packet,
83         0,
84         Adapter->CurLookaheadLength);
85
86     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
87
88     if (Length > Adapter->MediumHeaderSize) {
89         MiniIndicateData(Adapter,
90                          NULL,
91                          Adapter->LookaheadBuffer,
92                          Adapter->MediumHeaderSize,
93                          &Adapter->LookaheadBuffer[Adapter->MediumHeaderSize],
94                          Length - Adapter->MediumHeaderSize,
95                          Total - Adapter->MediumHeaderSize);
96     } else {
97         MiniIndicateData(Adapter,
98                          NULL,
99                          Adapter->LookaheadBuffer,
100                          Adapter->MediumHeaderSize,
101                          NULL,
102                          0,
103                          0);
104     }
105
106     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
107
108     Adapter->LoopPacket = NULL;
109
110     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
111
112     return STATUS_SUCCESS;
113 }
114
115
116 NDIS_STATUS
117 ProRequest(
118     IN  NDIS_HANDLE     MacBindingHandle,
119     IN  PNDIS_REQUEST   NdisRequest)
120 /*
121  * FUNCTION: Forwards a request to an NDIS miniport
122  * ARGUMENTS:
123  *     MacBindingHandle = Adapter binding handle
124  *     NdisRequest      = Pointer to request to perform
125  * RETURNS:
126  *     Status of operation
127  */
128 {
129     KIRQL OldIrql;
130     BOOLEAN Queue;
131     NDIS_STATUS NdisStatus;
132     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
133     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
134
135     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
136
137     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
138     Queue = Adapter->MiniportBusy;
139     if (Queue) {
140         MiniQueueWorkItem(Adapter,
141                           NdisWorkItemRequest,
142                           (PVOID)NdisRequest,
143                           (NDIS_HANDLE)AdapterBinding);
144     } else {
145         Adapter->MiniportBusy = TRUE;
146     }
147     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
148
149     if (!Queue) {
150         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
151         NdisStatus = MiniDoRequest(Adapter, NdisRequest);
152         KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
153         Adapter->MiniportBusy = FALSE;
154         if (Adapter->WorkQueueHead)
155             KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
156         KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
157         KeLowerIrql(OldIrql);
158     } else {
159         NdisStatus = NDIS_STATUS_PENDING;
160     }
161     return NdisStatus;
162 }
163
164
165 NDIS_STATUS
166 ProReset(
167     IN  NDIS_HANDLE MacBindingHandle)
168 {
169     UNIMPLEMENTED
170
171     return NDIS_STATUS_FAILURE;
172 }
173
174
175 NDIS_STATUS
176 ProSend(
177     IN  NDIS_HANDLE     MacBindingHandle,
178     IN  PNDIS_PACKET    Packet)
179 /*
180  * FUNCTION: Forwards a request to send a packet to an NDIS miniport
181  * ARGUMENTS:
182  *     MacBindingHandle = Adapter binding handle
183  *     Packet           = Pointer to NDIS packet descriptor
184  */
185 {
186     KIRQL OldIrql;
187     BOOLEAN Queue;
188     NDIS_STATUS NdisStatus;
189     PADAPTER_BINDING AdapterBinding  = GET_ADAPTER_BINDING(MacBindingHandle);
190     PLOGICAL_ADAPTER Adapter         = AdapterBinding->Adapter;
191
192     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
193
194     /* FIXME: Should queue packet if miniport returns NDIS_STATUS_RESOURCES */
195
196     Packet->Reserved[0] = (ULONG_PTR)MacBindingHandle;
197
198     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
199     Queue = Adapter->MiniportBusy;
200
201     /* We may have to loop this packet if miniport cannot */
202     if (Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) {
203         if (MiniAdapterHasAddress(Adapter, Packet)) {
204             /* Do software loopback because miniport does not support it */
205
206             NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
207
208             if (Queue) {
209
210                 /* FIXME: Packets should properbly be queued directly on the adapter instead */
211
212                 MiniQueueWorkItem(Adapter,
213                                   NdisWorkItemSendLoopback,
214                                   (PVOID)Packet,
215                                   (NDIS_HANDLE)AdapterBinding);
216             } else {
217                 Adapter->MiniportBusy = TRUE;
218             }
219             KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
220
221             if (!Queue) {
222                 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
223                 NdisStatus = ProIndicatePacket(Adapter, Packet);
224                 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
225                 Adapter->MiniportBusy = FALSE;
226                 if (Adapter->WorkQueueHead)
227                     KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
228                 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
229                 KeLowerIrql(OldIrql);
230                 return NdisStatus;
231             } else {
232                 return NDIS_STATUS_PENDING;
233             }
234         }
235     }
236
237     if (Queue) {
238
239         /* FIXME: Packets should properbly be queued directly on the adapter instead */
240
241         MiniQueueWorkItem(Adapter,
242                           NdisWorkItemSend,
243                           (PVOID)Packet,
244                           (NDIS_HANDLE)AdapterBinding);
245     } else {
246         Adapter->MiniportBusy = TRUE;
247     }
248     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
249
250     if (!Queue) {
251         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
252         NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(
253             Adapter->NdisMiniportBlock.MiniportAdapterContext,
254             Packet,
255             0);
256         KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
257         Adapter->MiniportBusy = FALSE;
258         if (Adapter->WorkQueueHead)
259             KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
260         KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
261         KeLowerIrql(OldIrql);
262     } else {
263         NdisStatus = NDIS_STATUS_PENDING;
264     }
265     return NdisStatus;
266 }
267
268
269 VOID
270 ProSendPackets(
271     IN  NDIS_HANDLE     NdisBindingHandle,
272     IN  PPNDIS_PACKET   PacketArray,
273     IN  UINT            NumberOfPackets)
274 {
275     UNIMPLEMENTED
276 }
277
278
279 NDIS_STATUS
280 ProTransferData(
281     IN  NDIS_HANDLE         MacBindingHandle,
282     IN  NDIS_HANDLE         MacReceiveContext,
283     IN  UINT                ByteOffset,
284     IN  UINT                BytesToTransfer,
285     IN  OUT     PNDIS_PACKET    Packet,
286     OUT PUINT               BytesTransferred)
287 /*
288  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
289  * ARGUMENTS:
290  *     MacBindingHandle  = Adapter binding handle
291  *     MacReceiveContext = MAC receive context
292  *     ByteOffset        = Offset in packet to place data
293  *     BytesToTransfer   = Number of bytes to copy into packet
294  *     Packet            = Pointer to NDIS packet descriptor
295  *     BytesTransferred  = Address of buffer to place number of bytes copied
296  */
297 {
298     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
299     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
300
301     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
302
303     /* FIXME: Interrupts must be disabled for adapter */
304
305     if (Packet == Adapter->LoopPacket) {
306         /* NDIS is responsible for looping this packet */
307         NdisCopyFromPacketToPacket(Packet,
308                                    ByteOffset,
309                                    BytesToTransfer,
310                                    Adapter->LoopPacket,
311                                    0,
312                                    BytesTransferred);
313         return NDIS_STATUS_SUCCESS;
314     }
315
316     return (*Adapter->Miniport->Chars.u2.TransferDataHandler)(
317         Packet,
318         BytesTransferred,
319         Adapter->NdisMiniportBlock.MiniportAdapterContext,
320         MacReceiveContext,
321         ByteOffset,
322         BytesToTransfer);
323 }
324
325
326
327 /*
328  * @implemented
329  */
330 VOID
331 EXPORT
332 NdisCloseAdapter(
333     OUT PNDIS_STATUS    Status,
334     IN  NDIS_HANDLE     NdisBindingHandle)
335 /*
336  * FUNCTION: Closes an adapter opened with NdisOpenAdapter
337  * ARGUMENTS:
338  *     Status            = Address of buffer for status information
339  *     NdisBindingHandle = Handle returned by NdisOpenAdapter
340  */
341 {
342     KIRQL OldIrql;
343     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
344
345     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
346
347     /* Remove from protocol's bound adapters list */
348     KeAcquireSpinLock(&AdapterBinding->ProtocolBinding->Lock, &OldIrql);
349     RemoveEntryList(&AdapterBinding->ProtocolListEntry);
350     KeReleaseSpinLock(&AdapterBinding->ProtocolBinding->Lock, OldIrql);
351
352     /* Remove protocol from adapter's bound protocols list */
353     KeAcquireSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, &OldIrql);
354     RemoveEntryList(&AdapterBinding->AdapterListEntry);
355     KeReleaseSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, OldIrql);
356
357     ExFreePool(AdapterBinding);
358
359     *Status = NDIS_STATUS_SUCCESS;
360 }
361
362
363 /*
364  * @implemented
365  */
366 VOID
367 EXPORT
368 NdisDeregisterProtocol(
369     OUT PNDIS_STATUS    Status,
370     IN NDIS_HANDLE      NdisProtocolHandle)
371 /*
372  * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
373  * ARGUMENTS:
374  *     Status             = Address of buffer for status information
375  *     NdisProtocolHandle = Handle returned by NdisRegisterProtocol
376  */
377 {
378     KIRQL OldIrql;
379     PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
380
381     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
382
383     /* FIXME: Make sure no adapter bindings exist */
384
385     /* Remove protocol from global list */
386     KeAcquireSpinLock(&ProtocolListLock, &OldIrql);
387     RemoveEntryList(&Protocol->ListEntry);
388     KeReleaseSpinLock(&ProtocolListLock, OldIrql);
389
390     ExFreePool(Protocol);
391
392     *Status = NDIS_STATUS_SUCCESS;
393 }
394
395
396 /*
397  * @implemented
398  */
399 VOID
400 EXPORT
401 NdisOpenAdapter(
402     OUT PNDIS_STATUS    Status,
403     OUT PNDIS_STATUS    OpenErrorStatus,
404     OUT PNDIS_HANDLE    NdisBindingHandle,
405     OUT PUINT           SelectedMediumIndex,
406     IN  PNDIS_MEDIUM    MediumArray,
407     IN  UINT            MediumArraySize,
408     IN  NDIS_HANDLE     NdisProtocolHandle,
409     IN  NDIS_HANDLE     ProtocolBindingContext,
410     IN  PNDIS_STRING    AdapterName,
411     IN  UINT            OpenOptions,
412     IN  PSTRING         AddressingInformation   OPTIONAL)
413 /*
414  * FUNCTION: Opens an adapter for communication
415  * ARGUMENTS:
416  *     Status                 = Address of buffer for status information
417  *     OpenErrorStatus        = Address of buffer for secondary error code
418  *     NdisBindingHandle      = Address of buffer for adapter binding handle
419  *     SelectedMediumIndex    = Address of buffer for selected medium
420  *     MediumArray            = Pointer to an array of NDIS_MEDIUMs called can support
421  *     MediumArraySize        = Number of elements in MediumArray
422  *     NdisProtocolHandle     = Handle returned by NdisRegisterProtocol
423  *     ProtocolBindingContext = Pointer to caller suplied context area
424  *     AdapterName            = Pointer to buffer with name of adapter
425  *     OpenOptions            = Bitmask with flags passed to next-lower driver
426  *     AddressingInformation  = Optional pointer to buffer with NIC specific information
427  */
428 {
429     UINT i;
430     BOOLEAN Found;
431     PLOGICAL_ADAPTER Adapter;
432     PADAPTER_BINDING AdapterBinding;
433     PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
434
435     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
436
437     Adapter = MiniLocateDevice(AdapterName);
438     if (!Adapter) {
439         NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
440         *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
441         return;
442     }
443
444     /* Find the media type in the list provided by the protocol driver */
445     Found = FALSE;
446     for (i = 0; i < MediumArraySize; i++) {
447         if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i]) {
448             *SelectedMediumIndex = i;
449             Found = TRUE;
450             break;
451         }
452     }
453
454     if (!Found) {
455         NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
456         *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
457         return;
458     }
459
460     AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
461     if (!AdapterBinding) {
462         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
463         *Status = NDIS_STATUS_RESOURCES;
464         return;
465     }
466
467     RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
468
469     AdapterBinding->ProtocolBinding        = Protocol;
470     AdapterBinding->Adapter                = Adapter;
471     AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
472
473     /* Set fields required by some NDIS macros */
474     AdapterBinding->NdisOpenBlock.MacBindingHandle = (NDIS_HANDLE)AdapterBinding;
475     
476     /* Set handlers (some NDIS macros require these) */
477
478     AdapterBinding->NdisOpenBlock.RequestHandler      = ProRequest;
479     AdapterBinding->NdisOpenBlock.ResetHandler        = ProReset;
480     AdapterBinding->NdisOpenBlock.u1.SendHandler      = ProSend;
481     AdapterBinding->NdisOpenBlock.SendPacketsHandler  = ProSendPackets;
482     AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
483
484 #if 0
485          /* XXX this looks fishy */
486          /* OK, this really *is* fishy - it bugchecks */
487     /* Put on protocol's bound adapters list */
488     ExInterlockedInsertTailList(&Protocol->AdapterListHead,
489                                 &AdapterBinding->ProtocolListEntry,
490                                 &Protocol->Lock);
491 #endif
492          /* XXX so does this */
493     /* Put protocol on adapter's bound protocols list */
494     ExInterlockedInsertTailList(&Adapter->ProtocolListHead,
495                                 &AdapterBinding->AdapterListEntry,
496                                 &Adapter->NdisMiniportBlock.Lock);
497
498     *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
499
500     *Status = NDIS_STATUS_SUCCESS;
501 }
502
503
504 /*
505  * @implemented
506  */
507 VOID
508 EXPORT
509 NdisRegisterProtocol(
510     OUT PNDIS_STATUS                    Status,
511     OUT PNDIS_HANDLE                    NdisProtocolHandle,
512     IN  PNDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,
513     IN  UINT                            CharacteristicsLength)
514 /*
515  * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
516  * ARGUMENTS:
517  *     Status                  = Address of buffer for status information
518  *     NdisProtocolHandle      = Address of buffer for handle used to identify the driver
519  *     ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
520  *     CharacteristicsLength   = Size of structure which ProtocolCharacteristics targets
521  * TODO:
522  *     break this function up
523  *     make this thing able to handle >1 protocol
524  */
525 {
526     PPROTOCOL_BINDING Protocol;
527     NTSTATUS NtStatus;
528     UINT MinSize;
529     HANDLE DriverKeyHandle = NULL;
530     PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
531          UINT DataOffset = 0;
532
533     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
534
535     switch (ProtocolCharacteristics->MajorNdisVersion) {
536     case 0x03:  /* we don't really want to support ndis3 drivers - so we complainf or now */
537                   NDIS_DbgPrint(MID_TRACE, ("Ndis 3 protocol attempting to register\n"));
538         MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S);
539         break;
540
541     case 0x04:
542         MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S);
543         break;
544
545     case 0x05:
546         MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S);
547         break;
548
549     default:
550         *Status = NDIS_STATUS_BAD_VERSION;
551                   NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
552         return;
553     }
554
555     if (CharacteristicsLength < MinSize) {
556         NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics.\n"));
557         *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
558         return;
559     }
560
561     Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
562     if (!Protocol) {
563         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
564         *Status = NDIS_STATUS_RESOURCES;
565         return;
566     }
567
568     RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
569     RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
570
571     NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name,
572                                       &ProtocolCharacteristics->Name,
573                                       TRUE);
574     if (!NT_SUCCESS(NtStatus)) {
575         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
576         ExFreePool(Protocol);
577         *Status = NDIS_STATUS_RESOURCES;
578         return;
579     }
580
581     KeInitializeSpinLock(&Protocol->Lock);
582
583     Protocol->RefCount = 1;
584
585     InitializeListHead(&Protocol->AdapterListHead);
586
587          /* 
588           * bind the adapter to all of its miniports 
589           *
590           * open registry path
591           * get list of devices from Bind key
592           * call BindAdapterHandler for each
593           */
594         {
595                 OBJECT_ATTRIBUTES ObjectAttributes;
596                 UNICODE_STRING RegistryPath;
597                 WCHAR *RegistryPathStr;
598
599 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
600 #define LINKAGE_KEY  L"\\Linkage"
601
602                 RegistryPathStr = ExAllocatePool(PagedPool, 
603                         sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY));
604                 if(!RegistryPathStr)
605                 {
606                         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
607                         ExFreePool(Protocol);
608                         *Status = NDIS_STATUS_RESOURCES;
609                         return;
610                 }
611
612                 wcscpy(RegistryPathStr, SERVICES_KEY);
613                 wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer),
614                                 ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
615                 RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
616                 wcscat(RegistryPathStr, LINKAGE_KEY);
617
618                 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
619                 NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
620
621                 InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
622                 NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
623
624                 ExFreePool(RegistryPathStr);
625
626                 if(!NT_SUCCESS(NtStatus))
627                 {
628                         NDIS_DbgPrint(MID_TRACE, ("Unable to open protocol configuration\n"));
629                         ExFreePool(Protocol);
630                         *Status = NDIS_STATUS_FAILURE;
631                         return;
632                 }
633         }
634
635         NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
636
637         {
638                 UNICODE_STRING ValueName;
639                 ULONG ResultLength;
640
641                 RtlInitUnicodeString(&ValueName, L"Bind");
642
643                 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
644                 if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL)
645                 {
646                         NDIS_DbgPrint(MID_TRACE, ("Unable to query the Bind value for size\n"));
647                         ZwClose(DriverKeyHandle);
648                         ExFreePool(Protocol);
649                         *Status = NDIS_STATUS_FAILURE;
650                         return;
651                 }
652
653                 KeyInformation = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength);
654                 if(!KeyInformation)
655                 {
656                         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
657                         ZwClose(DriverKeyHandle);
658                         ExFreePool(Protocol);
659                         *Status = NDIS_STATUS_FAILURE;
660                         return;
661                 }
662
663                 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
664                                 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
665
666                 if(!NT_SUCCESS(NtStatus))
667                 {
668                         NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
669                         ZwClose(DriverKeyHandle);
670                         ExFreePool(KeyInformation);
671                         ExFreePool(Protocol);
672                         *Status = NDIS_STATUS_FAILURE;
673                         return;
674                 }
675         }
676
677         DataOffset = 0;
678         while((KeyInformation->Data)[DataOffset])
679         {
680                 /* BindContext is for tracking pending binding operations */
681                 VOID *BindContext = 0;
682                 NDIS_STRING DeviceName;
683                 NDIS_STRING RegistryPath;
684                 WCHAR *RegistryPathStr = NULL;
685                 ULONG PathLength = 0;
686
687                 RtlInitUnicodeString(&DeviceName, (WCHAR *)KeyInformation->Data);       /* we know this is 0-term */
688
689                 /*
690                  * RegistryPath should be:
691                  *     \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
692                  *
693                  *  This is constructed as follows:
694                  *      SERVICES_KEY + extracted device name + Protocol name from characteristics 
695                  */
696 #define PARAMETERS_KEY L"\\Parameters\\"
697                 
698                 PathLength = sizeof(SERVICES_KEY) +                              /* \Registry\Machine\System\CurrentControlSet\Services\ */
699                         wcslen( ((WCHAR *)KeyInformation->Data)+8 ) * sizeof(WCHAR) + /* Adapter1  (extracted from \Device\Adapter1)          */
700                         sizeof(PARAMETERS_KEY) +                                      /* \Parameters\                                         */
701                         ProtocolCharacteristics->Name.Length;                         /* Tcpip                                                */
702
703                 RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
704                 if(!RegistryPathStr)
705                 {
706                         NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
707                         ExFreePool(KeyInformation);
708                         ExFreePool(Protocol);
709                         *Status = NDIS_STATUS_RESOURCES;
710                         return;
711                 }
712
713                 wcscpy(RegistryPathStr, SERVICES_KEY);
714                 wcscat(RegistryPathStr, (((WCHAR *)(KeyInformation->Data)) +8 ));
715                 wcscat(RegistryPathStr, PARAMETERS_KEY);
716                 wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
717
718                 RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
719
720                 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
721
722                 NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
723                                         &DeviceName, &RegistryPath));
724
725                 /* XXX SD must do something with bind context */
726                 {
727                         BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
728                         if(BindHandler)
729                                 BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
730                         else
731                                 NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
732                 }
733                 /*
734       (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
735                 */
736
737                 if(*Status == NDIS_STATUS_SUCCESS)
738                 {
739                          /* Put protocol binding struct on global list */
740                          ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
741                 }
742                 /*
743                 else if(*Status != NDIS_STATUS_PENDING)
744                 {
745                         // what to do here?
746                 }
747                 */
748
749                 DataOffset += wcslen((WCHAR *)KeyInformation->Data);
750         }
751
752     *NdisProtocolHandle = Protocol;
753     *Status             = NDIS_STATUS_SUCCESS;
754 }
755
756
757 /*
758  * @implemented
759  */
760 VOID
761 EXPORT
762 NdisRequest(
763     OUT PNDIS_STATUS    Status,
764     IN  NDIS_HANDLE     NdisBindingHandle,
765     IN  PNDIS_REQUEST   NdisRequest)
766 /*
767  * FUNCTION: Forwards a request to an NDIS driver
768  * ARGUMENTS:
769  *     Status            = Address of buffer for status information
770  *     NdisBindingHandle = Adapter binding handle
771  *     NdisRequest       = Pointer to request to perform
772  */
773 {
774     *Status = ProRequest(NdisBindingHandle, NdisRequest);
775 }
776
777
778 /*
779  * @implemented
780  */
781 VOID
782 EXPORT
783 NdisReset(
784     OUT PNDIS_STATUS    Status,
785     IN  NDIS_HANDLE     NdisBindingHandle)
786 {
787     *Status = ProReset(NdisBindingHandle);
788 }
789
790
791 /*
792  * @implemented
793  */
794 VOID
795 EXPORT
796 NdisSend(
797     OUT PNDIS_STATUS    Status,
798     IN  NDIS_HANDLE     NdisBindingHandle,
799     IN  PNDIS_PACKET    Packet)
800 /*
801  * FUNCTION: Forwards a request to send a packet
802  * ARGUMENTS:
803  *     Status             = Address of buffer for status information
804  *     NdisBindingHandle  = Adapter binding handle
805  *     Packet             = Pointer to NDIS packet descriptor
806  */
807 {
808     *Status = ProSend(NdisBindingHandle, Packet);
809 }
810
811
812 /*
813  * @implemented
814  */
815 VOID
816 EXPORT
817 NdisSendPackets(
818     IN  NDIS_HANDLE     NdisBindingHandle,
819     IN  PPNDIS_PACKET   PacketArray,
820     IN  UINT            NumberOfPackets)
821 {
822     ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
823 }
824
825
826 /*
827  * @implemented
828  */
829 VOID
830 EXPORT
831 NdisTransferData(
832     OUT     PNDIS_STATUS    Status,
833     IN      NDIS_HANDLE     NdisBindingHandle,
834     IN      NDIS_HANDLE     MacReceiveContext,
835     IN      UINT            ByteOffset,
836     IN      UINT            BytesToTransfer,
837     IN OUT      PNDIS_PACKET    Packet,
838     OUT     PUINT           BytesTransferred)
839 /*
840  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
841  * ARGUMENTS:
842  *     Status            = Address of buffer for status information
843  *     NdisBindingHandle = Adapter binding handle
844  *     MacReceiveContext = MAC receive context
845  *     ByteOffset        = Offset in packet to place data
846  *     BytesToTransfer   = Number of bytes to copy into packet
847  *     Packet            = Pointer to NDIS packet descriptor
848  *     BytesTransferred  = Address of buffer to place number of bytes copied
849  */
850 {
851     *Status = ProTransferData(NdisBindingHandle,
852                               MacReceiveContext,
853                               ByteOffset,
854                               BytesToTransfer,
855                               Packet,
856                               BytesTransferred);
857 }
858
859 /* EOF */