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