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