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