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)
9 * CSH 01/08-2000 Created
10 * 09-13-2003 Vizzini Updates for SendPackets support
19 IN NDIS_HANDLE MiniportAdapterHandle
,
20 IN PNDIS_PACKET Packet
,
21 IN NDIS_STATUS Status
);
23 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
24 #define LINKAGE_KEY L"\\Linkage"
25 #define PARAMETERS_KEY L"\\Parameters\\"
27 LIST_ENTRY ProtocolListHead
;
28 KSPIN_LOCK ProtocolListLock
;
36 NdisCompleteBindAdapter(
37 IN NDIS_HANDLE BindAdapterContext
,
38 IN NDIS_STATUS Status
,
39 IN NDIS_STATUS OpenStatus
)
41 * FUNCTION: Indicates a packet to bound protocols
43 * Adapter = Pointer to logical adapter
44 * Packet = Pointer to packet to indicate
48 * - FIXME: partially-implemented
51 PROTOCOL_BINDING
*Protocol
= (PROTOCOL_BINDING
*)BindAdapterContext
;
53 /* Put protocol binding struct on global list */
54 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
60 PLOGICAL_ADAPTER Adapter
,
63 * FUNCTION: Indicates a packet to bound protocols
65 * Adapter = Pointer to logical adapter
66 * Packet = Pointer to packet to indicate
68 * STATUS_SUCCESS in all cases
70 * - XXX ATM, this only handles loopback packets - is that its designed function?
77 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
80 MiniDisplayPacket(Packet
);
83 NdisQueryPacket(Packet
, NULL
, NULL
, NULL
, &PacketLength
);
85 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
86 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
88 Adapter
->LoopPacket
= Packet
;
89 BufferedLength
= CopyPacketToBuffer(Adapter
->LookaheadBuffer
, Packet
, 0, Adapter
->NdisMiniportBlock
.CurrentLookahead
);
91 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
93 if (BufferedLength
> Adapter
->MediumHeaderSize
)
95 /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
96 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
,
97 &Adapter
->LookaheadBuffer
[Adapter
->MediumHeaderSize
], BufferedLength
- Adapter
->MediumHeaderSize
,
98 PacketLength
- Adapter
->MediumHeaderSize
);
102 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
, NULL
, 0, 0);
105 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
106 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
108 Adapter
->LoopPacket
= NULL
;
110 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
112 return STATUS_SUCCESS
;
118 IN NDIS_HANDLE MacBindingHandle
,
119 IN PNDIS_REQUEST NdisRequest
)
121 * FUNCTION: Forwards a request to an NDIS miniport
123 * MacBindingHandle = Adapter binding handle
124 * NdisRequest = Pointer to request to perform
126 * Status of operation
130 BOOLEAN QueueWorkItem
= FALSE
;
131 NDIS_STATUS NdisStatus
;
132 PADAPTER_BINDING AdapterBinding
;
133 PLOGICAL_ADAPTER Adapter
;
135 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
137 ASSERT(MacBindingHandle
);
138 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
140 ASSERT(AdapterBinding
->Adapter
);
141 Adapter
= AdapterBinding
->Adapter
;
144 * If the miniport is already busy, queue a workitem
146 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
147 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
149 if(Adapter
->MiniportBusy
)
150 QueueWorkItem
= TRUE
;
153 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
154 Adapter
->MiniportBusy
= TRUE
;
158 /* MiniQueueWorkItem must be called at IRQL >= DISPATCH_LEVEL */
161 MiniQueueWorkItem(Adapter
, NdisWorkItemRequest
, (PVOID
)NdisRequest
);
162 return NDIS_STATUS_PENDING
;
165 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
167 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
168 /* TODO (?): move the irql raise into MiniDoRequest */
169 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
171 NdisStatus
= MiniDoRequest(Adapter
, NdisRequest
);
173 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
174 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
176 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
177 Adapter
->MiniportBusy
= FALSE
;
179 if (Adapter
->WorkQueueHead
)
180 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
182 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
184 KeLowerIrql(OldIrql
);
192 IN NDIS_HANDLE MacBindingHandle
)
196 return NDIS_STATUS_FAILURE
;
202 IN NDIS_HANDLE MacBindingHandle
,
203 IN PNDIS_PACKET Packet
)
205 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
207 * MacBindingHandle = Adapter binding handle
208 * Packet = Pointer to NDIS packet descriptor
210 * NDIS_STATUS_SUCCESS always
213 * - Fix return values
214 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
215 * - Queue packets directly on the adapters when possible (i.e.
216 * when miniports not busy)
220 KIRQL RaiseOldIrql
, SpinOldIrql
;
221 BOOLEAN QueueWorkItem
= FALSE
;
222 NDIS_STATUS NdisStatus
;
223 PADAPTER_BINDING AdapterBinding
;
224 PLOGICAL_ADAPTER Adapter
;
226 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
228 ASSERT(MacBindingHandle
);
229 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
231 ASSERT(AdapterBinding
);
232 Adapter
= AdapterBinding
->Adapter
;
236 /* if the following is not true, KeRaiseIrql() below will break */
237 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
239 /* XXX what is this crazy black magic? */
240 Packet
->Reserved
[0] = (ULONG_PTR
)MacBindingHandle
;
243 * Acquire this lock in order to see if the miniport is busy.
244 * If it is not busy, we mark it as busy and release the lock.
245 * Else we don't do anything because we have to queue a workitem
248 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
249 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
252 * if the miniport is marked as busy, we queue the packet as a work item,
253 * else we send the packet directly to the miniport. Sending to the miniport
256 if (Adapter
->MiniportBusy
)
257 QueueWorkItem
= TRUE
;
260 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
261 Adapter
->MiniportBusy
= TRUE
;
264 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
267 * Test the packet to see if it is a MAC loopback.
269 * We may have to loop this packet if miniport cannot.
270 * If dest MAC address of packet == MAC address of adapter,
271 * this is a loopback frame.
273 if ((Adapter
->NdisMiniportBlock
.MacOptions
& NDIS_MAC_OPTION_NO_LOOPBACK
) &&
274 MiniAdapterHasAddress(Adapter
, Packet
))
276 NDIS_DbgPrint(MIN_TRACE
, ("Looping packet.\n"));
280 MiniQueueWorkItem(Adapter
, NdisWorkItemSendLoopback
, (PVOID
)Packet
);
281 return NDIS_STATUS_PENDING
;
284 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
287 * atm this *only* handles loopback packets - it calls MiniIndicateData to
288 * send back to the protocol. FIXME: this will need to be adjusted a bit.
289 * Also, I'm not sure you really have to be at dispatch level for this. It
290 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
292 NdisStatus
= ProIndicatePacket(Adapter
, Packet
);
294 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
295 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
297 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
298 Adapter
->MiniportBusy
= FALSE
;
300 if (Adapter
->WorkQueueHead
)
301 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
303 NDIS_DbgPrint(MID_TRACE
,("Failed to insert packet into work queue\n"));
305 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
307 KeLowerIrql(RaiseOldIrql
);
312 NDIS_DbgPrint(MID_TRACE
,("Not a loopback packet\n"));
314 /* This is a normal send packet, not a loopback packet. */
317 MiniQueueWorkItem(Adapter
, NdisWorkItemSend
, (PVOID
)Packet
);
318 NDIS_DbgPrint(MAX_TRACE
, ("Queued a work item and returning\n"));
319 return NDIS_STATUS_PENDING
;
322 ASSERT(Adapter
->Miniport
);
325 * Call the appropriate send handler
327 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
330 if(Adapter
->Miniport
->Chars
.SendPacketsHandler
)
332 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
334 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
335 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
339 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
340 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
342 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
343 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
345 KeLowerIrql(RaiseOldIrql
);
348 /* SendPackets handlers return void - they always "succeed" */
349 NdisStatus
= NDIS_STATUS_SUCCESS
;
353 /* XXX FIXME THIS IS WRONG */
354 /* uh oh... forgot why i thought that... */
355 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
357 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
358 NdisStatus
= (*Adapter
->Miniport
->Chars
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
359 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
363 /* Send handlers always run at DISPATCH_LEVEL so we raise here */
364 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
366 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
367 NdisStatus
= (*Adapter
->Miniport
->Chars
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
368 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
369 if( NdisStatus
!= NDIS_STATUS_PENDING
) {
370 Adapter
->MiniportBusy
= FALSE
;
372 KeLowerIrql(RaiseOldIrql
);
376 /* XXX why the hell do we do this? */
377 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
378 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
380 if (Adapter
->WorkQueueHead
)
382 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
383 NDIS_DbgPrint(MAX_TRACE
, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
386 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
388 NDIS_DbgPrint(MAX_TRACE
, ("returning 0x%x\n", NdisStatus
));
395 IN NDIS_HANDLE NdisBindingHandle
,
396 IN PPNDIS_PACKET PacketArray
,
397 IN UINT NumberOfPackets
)
405 IN NDIS_HANDLE MacBindingHandle
,
406 IN NDIS_HANDLE MacReceiveContext
,
408 IN UINT BytesToTransfer
,
409 IN OUT PNDIS_PACKET Packet
,
410 OUT PUINT BytesTransferred
)
412 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
414 * MacBindingHandle = Adapter binding handle
415 * MacReceiveContext = MAC receive context
416 * ByteOffset = Offset in packet to place data
417 * BytesToTransfer = Number of bytes to copy into packet
418 * Packet = Pointer to NDIS packet descriptor
419 * BytesTransferred = Address of buffer to place number of bytes copied
422 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
423 PLOGICAL_ADAPTER Adapter
= AdapterBinding
->Adapter
;
425 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
427 /* FIXME: Interrupts must be disabled for adapter */
428 /* XXX sd - why is that true? */
430 if (Packet
== Adapter
->LoopPacket
) {
431 NDIS_DbgPrint(MAX_TRACE
, ("LoopPacket\n"));
432 /* NDIS is responsible for looping this packet */
433 NdisCopyFromPacketToPacket(Packet
,
439 return NDIS_STATUS_SUCCESS
;
442 return (*Adapter
->Miniport
->Chars
.TransferDataHandler
)(
445 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
,
459 OUT PNDIS_STATUS Status
,
460 IN NDIS_HANDLE NdisBindingHandle
)
462 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
464 * Status = Address of buffer for status information
465 * NdisBindingHandle = Handle returned by NdisOpenAdapter
469 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(NdisBindingHandle
);
471 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
473 /* Remove from protocol's bound adapters list */
474 KeAcquireSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, &OldIrql
);
475 RemoveEntryList(&AdapterBinding
->ProtocolListEntry
);
476 KeReleaseSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, OldIrql
);
478 /* Remove protocol from adapter's bound protocols list */
479 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
480 KeAcquireSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
481 RemoveEntryList(&AdapterBinding
->AdapterListEntry
);
482 KeReleaseSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
484 ExFreePool(AdapterBinding
);
486 *Status
= NDIS_STATUS_SUCCESS
;
495 NdisDeregisterProtocol(
496 OUT PNDIS_STATUS Status
,
497 IN NDIS_HANDLE NdisProtocolHandle
)
499 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
501 * Status = Address of buffer for status information
502 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
506 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
508 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
510 /* FIXME: Make sure no adapter bindings exist */
512 /* Remove protocol from global list */
513 KeAcquireSpinLock(&ProtocolListLock
, &OldIrql
);
514 RemoveEntryList(&Protocol
->ListEntry
);
515 KeReleaseSpinLock(&ProtocolListLock
, OldIrql
);
517 ExFreePool(Protocol
);
519 *Status
= NDIS_STATUS_SUCCESS
;
529 OUT PNDIS_STATUS Status
,
530 OUT PNDIS_STATUS OpenErrorStatus
,
531 OUT PNDIS_HANDLE NdisBindingHandle
,
532 OUT PUINT SelectedMediumIndex
,
533 IN PNDIS_MEDIUM MediumArray
,
534 IN UINT MediumArraySize
,
535 IN NDIS_HANDLE NdisProtocolHandle
,
536 IN NDIS_HANDLE ProtocolBindingContext
,
537 IN PNDIS_STRING AdapterName
,
539 IN PSTRING AddressingInformation OPTIONAL
)
541 * FUNCTION: Opens an adapter for communication
543 * Status = Address of buffer for status information
544 * OpenErrorStatus = Address of buffer for secondary error code
545 * NdisBindingHandle = Address of buffer for adapter binding handle
546 * SelectedMediumIndex = Address of buffer for selected medium
547 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
548 * MediumArraySize = Number of elements in MediumArray
549 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
550 * ProtocolBindingContext = Pointer to caller suplied context area
551 * AdapterName = Pointer to buffer with name of adapter
552 * OpenOptions = Bitmask with flags passed to next-lower driver
553 * AddressingInformation = Optional pointer to buffer with NIC specific information
558 PLOGICAL_ADAPTER Adapter
;
559 PADAPTER_BINDING AdapterBinding
;
560 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
562 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
564 if(!NdisProtocolHandle
)
566 NDIS_DbgPrint(MAX_TRACE
, ("NdisProtocolHandle is NULL\n"));
567 *OpenErrorStatus
= *Status
= NDIS_STATUS_FAILURE
;
571 Adapter
= MiniLocateDevice(AdapterName
);
574 NDIS_DbgPrint(MIN_TRACE
, ("Adapter not found.\n"));
575 *Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
579 /* Find the media type in the list provided by the protocol driver */
581 for (i
= 0; i
< MediumArraySize
; i
++)
583 if (Adapter
->NdisMiniportBlock
.MediaType
== MediumArray
[i
])
585 *SelectedMediumIndex
= i
;
593 NDIS_DbgPrint(MIN_TRACE
, ("Medium is not supported.\n"));
594 *Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
598 /* Now that we have confirmed that the adapter can be opened, create a binding */
600 AdapterBinding
= ExAllocatePool(NonPagedPool
, sizeof(ADAPTER_BINDING
));
603 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
604 *Status
= NDIS_STATUS_RESOURCES
;
608 RtlZeroMemory(AdapterBinding
, sizeof(ADAPTER_BINDING
));
610 AdapterBinding
->ProtocolBinding
= Protocol
;
611 AdapterBinding
->Adapter
= Adapter
;
612 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.ProtocolBindingContext
= ProtocolBindingContext
;
614 /* Set fields required by some NDIS macros */
615 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.BindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
617 /* Set handlers (some NDIS macros require these) */
619 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.RequestHandler
= ProRequest
;
620 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.ResetHandler
= ProReset
;
621 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.SendHandler
= ProSend
;
622 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.SendPacketsHandler
= ProSendPackets
;
623 AdapterBinding
->NdisOpenBlock
.NdisCommonOpenBlock
.TransferDataHandler
= ProTransferData
;
626 /* XXX this looks fishy */
627 /* OK, this really *is* fishy - it bugchecks */
628 /* Put on protocol's bound adapters list */
629 ExInterlockedInsertTailList(&Protocol
->AdapterListHead
, &AdapterBinding
->ProtocolListEntry
, &Protocol
->Lock
);
632 /* XXX so does this */
633 /* Put protocol on adapter's bound protocols list */
634 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
635 ExInterlockedInsertTailList(&Adapter
->ProtocolListHead
, &AdapterBinding
->AdapterListEntry
, &Adapter
->NdisMiniportBlock
.Lock
);
637 *NdisBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
639 *Status
= NDIS_STATUS_SUCCESS
;
648 NdisRegisterProtocol(
649 OUT PNDIS_STATUS Status
,
650 OUT PNDIS_HANDLE NdisProtocolHandle
,
651 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics
,
652 IN UINT CharacteristicsLength
)
654 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
656 * Status = Address of buffer for status information
657 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
658 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
659 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
661 * - you *must* set NdisProtocolHandle before doing anything that could wind up
662 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
663 * - the above implies that the initialization of the protocol block must be complete
666 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
667 * - make this thing able to handle >1 protocol
670 PPROTOCOL_BINDING Protocol
;
673 HANDLE DriverKeyHandle
= NULL
;
674 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
= NULL
;
677 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
679 /* first validate the PROTOCOL_CHARACTERISTICS */
680 switch (ProtocolCharacteristics
->MajorNdisVersion
)
683 /* we don't really want to support ndis3 drivers - so we complain for now */
684 NDIS_DbgPrint(MID_TRACE
, ("NDIS 3 protocol attempting to register\n"));
685 MinSize
= sizeof(NDIS30_PROTOCOL_CHARACTERISTICS
);
689 MinSize
= sizeof(NDIS40_PROTOCOL_CHARACTERISTICS
);
693 MinSize
= sizeof(NDIS50_PROTOCOL_CHARACTERISTICS
);
697 *Status
= NDIS_STATUS_BAD_VERSION
;
698 NDIS_DbgPrint(MIN_TRACE
, ("Incorrect characteristics size\n"));
702 if (CharacteristicsLength
< MinSize
)
704 NDIS_DbgPrint(DEBUG_PROTOCOL
, ("Bad protocol characteristics.\n"));
705 *Status
= NDIS_STATUS_BAD_CHARACTERISTICS
;
709 /* set up the protocol block */
710 Protocol
= ExAllocatePool(NonPagedPool
, sizeof(PROTOCOL_BINDING
));
713 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
714 *Status
= NDIS_STATUS_RESOURCES
;
718 RtlZeroMemory(Protocol
, sizeof(PROTOCOL_BINDING
));
719 RtlCopyMemory(&Protocol
->Chars
, ProtocolCharacteristics
, MinSize
);
721 NtStatus
= RtlUpcaseUnicodeString(&Protocol
->Chars
.Name
, &ProtocolCharacteristics
->Name
, TRUE
);
722 if (!NT_SUCCESS(NtStatus
))
724 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
725 ExFreePool(Protocol
);
726 *Status
= NDIS_STATUS_RESOURCES
;
730 KeInitializeSpinLock(&Protocol
->Lock
);
732 Protocol
->RefCount
= 1;
734 InitializeListHead(&Protocol
->AdapterListHead
);
737 * bind the protocol to all of its miniports
740 * get list of devices from Bind key
741 * call BindAdapterHandler for each
744 OBJECT_ATTRIBUTES ObjectAttributes
;
745 UNICODE_STRING RegistryPath
;
746 WCHAR
*RegistryPathStr
;
748 RegistryPathStr
= ExAllocatePoolWithTag(PagedPool
, sizeof(SERVICES_KEY
) + ProtocolCharacteristics
->Name
.Length
+ sizeof(LINKAGE_KEY
), NDIS_TAG
+ __LINE__
);
751 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
752 ExFreePool(Protocol
);
753 *Status
= NDIS_STATUS_RESOURCES
;
757 wcscpy(RegistryPathStr
, SERVICES_KEY
);
758 wcsncat(RegistryPathStr
, ((WCHAR
*)ProtocolCharacteristics
->Name
.Buffer
), ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
));
759 RegistryPathStr
[wcslen(SERVICES_KEY
)+ProtocolCharacteristics
->Name
.Length
/sizeof(WCHAR
)] = 0;
760 wcscat(RegistryPathStr
, LINKAGE_KEY
);
762 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
763 NDIS_DbgPrint(MAX_TRACE
, ("Opening configuration key: %wZ\n", &RegistryPath
));
765 InitializeObjectAttributes(&ObjectAttributes
, &RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
766 NtStatus
= ZwOpenKey(&DriverKeyHandle
, KEY_READ
, &ObjectAttributes
);
768 ExFreePool(RegistryPathStr
);
770 if(!NT_SUCCESS(NtStatus
))
772 NDIS_DbgPrint(MID_TRACE
, ("Unable to open protocol configuration\n"));
773 ExFreePool(Protocol
);
774 *Status
= NDIS_STATUS_FAILURE
;
779 NDIS_DbgPrint(MAX_TRACE
, ("Successfully opened the registry configuration\n"));
782 UNICODE_STRING ValueName
;
785 RtlInitUnicodeString(&ValueName
, L
"Bind");
787 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, NULL
, 0, &ResultLength
);
788 if(NtStatus
!= STATUS_BUFFER_OVERFLOW
&& NtStatus
!= STATUS_BUFFER_TOO_SMALL
)
790 NDIS_DbgPrint(MID_TRACE
, ("Unable to query the Bind value for size\n"));
791 ZwClose(DriverKeyHandle
);
792 ExFreePool(Protocol
);
793 *Status
= NDIS_STATUS_FAILURE
;
797 KeyInformation
= ExAllocatePoolWithTag(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, NDIS_TAG
+ __LINE__
);
800 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
801 ZwClose(DriverKeyHandle
);
802 ExFreePool(Protocol
);
803 *Status
= NDIS_STATUS_FAILURE
;
807 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, KeyInformation
,
808 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, &ResultLength
);
810 if(!NT_SUCCESS(NtStatus
))
812 NDIS_DbgPrint(MIN_TRACE
, ("Unable to query the Bind value\n"));
813 ZwClose(DriverKeyHandle
);
814 ExFreePool(KeyInformation
);
815 ExFreePool(Protocol
);
816 *Status
= NDIS_STATUS_FAILURE
;
821 for (DataPtr
= (WCHAR
*)KeyInformation
->Data
;
823 DataPtr
+= wcslen(DataPtr
) + 1)
825 /* BindContext is for tracking pending binding operations */
826 VOID
*BindContext
= 0;
827 NDIS_STRING DeviceName
;
828 NDIS_STRING RegistryPath
;
829 WCHAR
*RegistryPathStr
= NULL
;
830 ULONG PathLength
= 0;
832 RtlInitUnicodeString(&DeviceName
, DataPtr
); /* we know this is 0-term */
835 * RegistryPath should be:
836 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
838 * This is constructed as follows:
839 * SERVICES_KEY + extracted device name + Protocol name from characteristics
842 PathLength
= sizeof(SERVICES_KEY
) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
843 wcslen( DataPtr
+ 8 ) * sizeof(WCHAR
) + /* Adapter1 (extracted from \Device\Adapter1) */
844 sizeof(PARAMETERS_KEY
) + /* \Parameters\ */
845 ProtocolCharacteristics
->Name
.Length
+ sizeof(WCHAR
); /* Tcpip */
847 RegistryPathStr
= ExAllocatePool(PagedPool
, PathLength
);
850 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
851 ExFreePool(KeyInformation
);
852 ExFreePool(Protocol
);
853 *Status
= NDIS_STATUS_RESOURCES
;
857 wcscpy(RegistryPathStr
, SERVICES_KEY
);
858 wcscat(RegistryPathStr
, DataPtr
+ 8 );
859 wcscat(RegistryPathStr
, PARAMETERS_KEY
);
860 wcsncat(RegistryPathStr
, ProtocolCharacteristics
->Name
.Buffer
, ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
) );
862 RegistryPathStr
[PathLength
/sizeof(WCHAR
) - 1] = 0;
864 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
866 NDIS_DbgPrint(MAX_TRACE
, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
867 &DeviceName
, &RegistryPath
));
869 /* XXX SD must do something with bind context */
870 *NdisProtocolHandle
= Protocol
;
873 BIND_HANDLER BindHandler
= ProtocolCharacteristics
->BindAdapterHandler
;
875 BindHandler(Status
, BindContext
, &DeviceName
, &RegistryPath
, 0);
877 NDIS_DbgPrint(MID_TRACE
, ("No protocol bind handler specified\n"));
881 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
884 if(*Status
== NDIS_STATUS_SUCCESS
)
886 /* Put protocol binding struct on global list */
887 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
891 else if(*Status != NDIS_STATUS_PENDING)
898 *Status
= NDIS_STATUS_SUCCESS
;
908 OUT PNDIS_STATUS Status
,
909 IN NDIS_HANDLE NdisBindingHandle
,
910 IN PNDIS_REQUEST NdisRequest
)
912 * FUNCTION: Forwards a request to an NDIS driver
914 * Status = Address of buffer for status information
915 * NdisBindingHandle = Adapter binding handle
916 * NdisRequest = Pointer to request to perform
919 *Status
= ProRequest(NdisBindingHandle
, NdisRequest
);
929 OUT PNDIS_STATUS Status
,
930 IN NDIS_HANDLE NdisBindingHandle
)
932 *Status
= ProReset(NdisBindingHandle
);
942 OUT PNDIS_STATUS Status
,
943 IN NDIS_HANDLE NdisBindingHandle
,
944 IN PNDIS_PACKET Packet
)
946 * FUNCTION: Forwards a request to send a packet
948 * Status = Address of buffer for status information
949 * NdisBindingHandle = Adapter binding handle
950 * Packet = Pointer to NDIS packet descriptor
953 *Status
= ProSend(NdisBindingHandle
, Packet
);
963 IN NDIS_HANDLE NdisBindingHandle
,
964 IN PPNDIS_PACKET PacketArray
,
965 IN UINT NumberOfPackets
)
967 ProSendPackets(NdisBindingHandle
, PacketArray
, NumberOfPackets
);
977 OUT PNDIS_STATUS Status
,
978 IN NDIS_HANDLE NdisBindingHandle
,
979 IN NDIS_HANDLE MacReceiveContext
,
981 IN UINT BytesToTransfer
,
982 IN OUT PNDIS_PACKET Packet
,
983 OUT PUINT BytesTransferred
)
985 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
987 * Status = Address of buffer for status information
988 * NdisBindingHandle = Adapter binding handle
989 * MacReceiveContext = MAC receive context
990 * ByteOffset = Offset in packet to place data
991 * BytesToTransfer = Number of bytes to copy into packet
992 * Packet = Pointer to NDIS packet descriptor
993 * BytesTransferred = Address of buffer to place number of bytes copied
996 *Status
= ProTransferData(NdisBindingHandle
,