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
16 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
17 #define LINKAGE_KEY L"\\Linkage"
18 #define PARAMETERS_KEY L"\\Parameters\\"
20 LIST_ENTRY ProtocolListHead
;
21 KSPIN_LOCK ProtocolListLock
;
29 NdisCompleteBindAdapter(
30 IN NDIS_HANDLE BindAdapterContext
,
31 IN NDIS_STATUS Status
,
32 IN NDIS_STATUS OpenStatus
)
34 * FUNCTION: Indicates a packet to bound protocols
36 * Adapter = Pointer to logical adapter
37 * Packet = Pointer to packet to indicate
41 * - FIXME: partially-implemented
44 PROTOCOL_BINDING
*Protocol
= (PROTOCOL_BINDING
*)BindAdapterContext
;
46 /* Put protocol binding struct on global list */
47 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
53 PLOGICAL_ADAPTER Adapter
,
56 * FUNCTION: Indicates a packet to bound protocols
58 * Adapter = Pointer to logical adapter
59 * Packet = Pointer to packet to indicate
61 * STATUS_SUCCESS in all cases
63 * - XXX ATM, this only handles loopback packets - is that its designed function?
70 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
73 MiniDisplayPacket(Packet
);
76 NdisQueryPacket(Packet
, NULL
, NULL
, NULL
, &PacketLength
);
78 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
79 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
81 Adapter
->LoopPacket
= Packet
;
82 BufferedLength
= CopyPacketToBuffer(Adapter
->LookaheadBuffer
, Packet
, 0, Adapter
->CurLookaheadLength
);
84 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
86 if (BufferedLength
> Adapter
->MediumHeaderSize
)
88 /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
89 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
,
90 &Adapter
->LookaheadBuffer
[Adapter
->MediumHeaderSize
], BufferedLength
- Adapter
->MediumHeaderSize
,
91 PacketLength
- Adapter
->MediumHeaderSize
);
95 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
, NULL
, 0, 0);
98 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
99 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
101 Adapter
->LoopPacket
= NULL
;
103 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
105 return STATUS_SUCCESS
;
111 IN NDIS_HANDLE MacBindingHandle
,
112 IN PNDIS_REQUEST NdisRequest
)
114 * FUNCTION: Forwards a request to an NDIS miniport
116 * MacBindingHandle = Adapter binding handle
117 * NdisRequest = Pointer to request to perform
119 * Status of operation
123 BOOLEAN QueueWorkItem
= FALSE
;
124 NDIS_STATUS NdisStatus
;
125 PADAPTER_BINDING AdapterBinding
;
126 PLOGICAL_ADAPTER Adapter
;
128 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
130 ASSERT(MacBindingHandle
);
131 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
133 ASSERT(AdapterBinding
->Adapter
);
134 Adapter
= AdapterBinding
->Adapter
;
137 * If the miniport is already busy, queue a workitem
139 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
140 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
142 if(Adapter
->MiniportBusy
)
143 QueueWorkItem
= TRUE
;
146 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
147 Adapter
->MiniportBusy
= TRUE
;
150 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
154 MiniQueueWorkItem(Adapter
, NdisWorkItemRequest
, (PVOID
)NdisRequest
, (NDIS_HANDLE
)AdapterBinding
);
155 return NDIS_STATUS_PENDING
;
158 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
159 /* TODO (?): move the irql raise into MiniDoRequest */
160 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
162 NdisStatus
= MiniDoRequest(Adapter
, NdisRequest
);
164 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
165 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
167 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
168 Adapter
->MiniportBusy
= FALSE
;
170 if (Adapter
->WorkQueueHead
)
171 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
173 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
175 KeLowerIrql(OldIrql
);
183 IN NDIS_HANDLE MacBindingHandle
)
187 return NDIS_STATUS_FAILURE
;
193 IN NDIS_HANDLE MacBindingHandle
,
194 IN PNDIS_PACKET Packet
)
196 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
198 * MacBindingHandle = Adapter binding handle
199 * Packet = Pointer to NDIS packet descriptor
201 * NDIS_STATUS_SUCCESS always
204 * - Fix return values
205 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
206 * - Queue packets directly on the adapters when possible (i.e.
207 * when miniports not busy)
211 KIRQL RaiseOldIrql
, SpinOldIrql
;
212 BOOLEAN QueueWorkItem
= FALSE
;
213 NDIS_STATUS NdisStatus
;
214 PADAPTER_BINDING AdapterBinding
;
215 PLOGICAL_ADAPTER Adapter
;
217 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
219 ASSERT(MacBindingHandle
);
220 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
222 ASSERT(AdapterBinding
);
223 Adapter
= AdapterBinding
->Adapter
;
227 /* if the following is not true, KeRaiseIrql() below will break */
228 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
230 /* XXX what is this crazy black magic? */
231 Packet
->Reserved
[0] = (ULONG_PTR
)MacBindingHandle
;
234 * Acquire this lock in order to see if the miniport is busy.
235 * If it is not busy, we mark it as busy and release the lock.
236 * Else we don't do anything because we have to queue a workitem
239 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
240 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
243 * if the miniport is marked as busy, we queue the packet as a work item,
244 * else we send the packet directly to the miniport. Sending to the miniport
247 if (Adapter
->MiniportBusy
)
248 QueueWorkItem
= TRUE
;
251 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
252 Adapter
->MiniportBusy
= TRUE
;
255 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
258 * Test the packet to see if it is a MAC loopback.
260 * We may have to loop this packet if miniport cannot.
261 * If dest MAC address of packet == MAC address of adapter,
262 * this is a loopback frame.
264 if ((Adapter
->NdisMiniportBlock
.MacOptions
& NDIS_MAC_OPTION_NO_LOOPBACK
) &&
265 MiniAdapterHasAddress(Adapter
, Packet
))
267 NDIS_DbgPrint(MIN_TRACE
, ("Looping packet.\n"));
271 MiniQueueWorkItem(Adapter
, NdisWorkItemSendLoopback
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
272 return NDIS_STATUS_PENDING
;
275 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
278 * atm this *only* handles loopback packets - it calls MiniIndicateData to
279 * send back to the protocol. FIXME: this will need to be adjusted a bit.
280 * Also, I'm not sure you really have to be at dispatch level for this. It
281 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
283 NdisStatus
= ProIndicatePacket(Adapter
, Packet
);
285 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
286 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
288 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
289 Adapter
->MiniportBusy
= FALSE
;
291 if (Adapter
->WorkQueueHead
)
292 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
294 NDIS_DbgPrint(MID_TRACE
,("Failed to insert packet into work queue\n"));
296 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
298 KeLowerIrql(RaiseOldIrql
);
303 NDIS_DbgPrint(MID_TRACE
,("Not a loopback packet\n"));
305 /* This is a normal send packet, not a loopback packet. */
308 MiniQueueWorkItem(Adapter
, NdisWorkItemSend
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
309 NDIS_DbgPrint(MAX_TRACE
, ("Queued a work item and returning\n"));
310 return NDIS_STATUS_PENDING
;
313 ASSERT(Adapter
->Miniport
);
316 * Call the appropriate send handler
318 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
321 if(Adapter
->Miniport
->Chars
.SendPacketsHandler
)
323 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
325 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
326 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
330 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
331 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
333 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
334 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
336 KeLowerIrql(RaiseOldIrql
);
339 /* SendPackets handlers return void - they always "succeed" */
340 NdisStatus
= NDIS_STATUS_SUCCESS
;
344 /* XXX FIXME THIS IS WRONG */
345 /* uh oh... forgot why i thought that... */
346 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
348 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
349 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
350 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
354 /* Send handlers always run at DISPATCH_LEVEL so we raise here */
355 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
357 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
358 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
359 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
361 KeLowerIrql(RaiseOldIrql
);
365 /* XXX why the hell do we do this? */
366 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
367 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
369 if (Adapter
->WorkQueueHead
)
371 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
372 NDIS_DbgPrint(MAX_TRACE
, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
375 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
377 NDIS_DbgPrint(MAX_TRACE
, ("returning 0x%x\n", NdisStatus
));
384 IN NDIS_HANDLE NdisBindingHandle
,
385 IN PPNDIS_PACKET PacketArray
,
386 IN UINT NumberOfPackets
)
394 IN NDIS_HANDLE MacBindingHandle
,
395 IN NDIS_HANDLE MacReceiveContext
,
397 IN UINT BytesToTransfer
,
398 IN OUT PNDIS_PACKET Packet
,
399 OUT PUINT BytesTransferred
)
401 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
403 * MacBindingHandle = Adapter binding handle
404 * MacReceiveContext = MAC receive context
405 * ByteOffset = Offset in packet to place data
406 * BytesToTransfer = Number of bytes to copy into packet
407 * Packet = Pointer to NDIS packet descriptor
408 * BytesTransferred = Address of buffer to place number of bytes copied
411 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
412 PLOGICAL_ADAPTER Adapter
= AdapterBinding
->Adapter
;
414 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
416 /* FIXME: Interrupts must be disabled for adapter */
417 /* XXX sd - why is that true? */
419 if (Packet
== Adapter
->LoopPacket
) {
420 NDIS_DbgPrint(MAX_TRACE
, ("LoopPacket\n"));
421 /* NDIS is responsible for looping this packet */
422 NdisCopyFromPacketToPacket(Packet
,
428 return NDIS_STATUS_SUCCESS
;
431 return (*Adapter
->Miniport
->Chars
.u2
.TransferDataHandler
)(
434 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
,
448 OUT PNDIS_STATUS Status
,
449 IN NDIS_HANDLE NdisBindingHandle
)
451 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
453 * Status = Address of buffer for status information
454 * NdisBindingHandle = Handle returned by NdisOpenAdapter
458 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(NdisBindingHandle
);
460 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
462 /* Remove from protocol's bound adapters list */
463 KeAcquireSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, &OldIrql
);
464 RemoveEntryList(&AdapterBinding
->ProtocolListEntry
);
465 KeReleaseSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, OldIrql
);
467 /* Remove protocol from adapter's bound protocols list */
468 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
469 KeAcquireSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
470 RemoveEntryList(&AdapterBinding
->AdapterListEntry
);
471 KeReleaseSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
473 ExFreePool(AdapterBinding
);
475 *Status
= NDIS_STATUS_SUCCESS
;
484 NdisDeregisterProtocol(
485 OUT PNDIS_STATUS Status
,
486 IN NDIS_HANDLE NdisProtocolHandle
)
488 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
490 * Status = Address of buffer for status information
491 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
495 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
497 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
499 /* FIXME: Make sure no adapter bindings exist */
501 /* Remove protocol from global list */
502 KeAcquireSpinLock(&ProtocolListLock
, &OldIrql
);
503 RemoveEntryList(&Protocol
->ListEntry
);
504 KeReleaseSpinLock(&ProtocolListLock
, OldIrql
);
506 ExFreePool(Protocol
);
508 *Status
= NDIS_STATUS_SUCCESS
;
518 OUT PNDIS_STATUS Status
,
519 OUT PNDIS_STATUS OpenErrorStatus
,
520 OUT PNDIS_HANDLE NdisBindingHandle
,
521 OUT PUINT SelectedMediumIndex
,
522 IN PNDIS_MEDIUM MediumArray
,
523 IN UINT MediumArraySize
,
524 IN NDIS_HANDLE NdisProtocolHandle
,
525 IN NDIS_HANDLE ProtocolBindingContext
,
526 IN PNDIS_STRING AdapterName
,
528 IN PSTRING AddressingInformation OPTIONAL
)
530 * FUNCTION: Opens an adapter for communication
532 * Status = Address of buffer for status information
533 * OpenErrorStatus = Address of buffer for secondary error code
534 * NdisBindingHandle = Address of buffer for adapter binding handle
535 * SelectedMediumIndex = Address of buffer for selected medium
536 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
537 * MediumArraySize = Number of elements in MediumArray
538 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
539 * ProtocolBindingContext = Pointer to caller suplied context area
540 * AdapterName = Pointer to buffer with name of adapter
541 * OpenOptions = Bitmask with flags passed to next-lower driver
542 * AddressingInformation = Optional pointer to buffer with NIC specific information
547 PLOGICAL_ADAPTER Adapter
;
548 PADAPTER_BINDING AdapterBinding
;
549 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
551 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
553 if(!NdisProtocolHandle
)
555 NDIS_DbgPrint(MAX_TRACE
, ("NdisProtocolHandle is NULL\n"));
556 *OpenErrorStatus
= *Status
= NDIS_STATUS_FAILURE
;
560 Adapter
= MiniLocateDevice(AdapterName
);
563 NDIS_DbgPrint(MIN_TRACE
, ("Adapter not found.\n"));
564 *Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
568 /* Find the media type in the list provided by the protocol driver */
570 for (i
= 0; i
< MediumArraySize
; i
++)
572 if (Adapter
->NdisMiniportBlock
.MediaType
== MediumArray
[i
])
574 *SelectedMediumIndex
= i
;
582 NDIS_DbgPrint(MIN_TRACE
, ("Medium is not supported.\n"));
583 *Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
587 /* Now that we have confirmed that the adapter can be opened, create a binding */
589 AdapterBinding
= ExAllocatePool(NonPagedPool
, sizeof(ADAPTER_BINDING
));
592 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
593 *Status
= NDIS_STATUS_RESOURCES
;
597 RtlZeroMemory(AdapterBinding
, sizeof(ADAPTER_BINDING
));
599 AdapterBinding
->ProtocolBinding
= Protocol
;
600 AdapterBinding
->Adapter
= Adapter
;
601 AdapterBinding
->NdisOpenBlock
.ProtocolBindingContext
= ProtocolBindingContext
;
603 /* Set fields required by some NDIS macros */
604 AdapterBinding
->NdisOpenBlock
.MacBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
606 /* Set handlers (some NDIS macros require these) */
608 AdapterBinding
->NdisOpenBlock
.RequestHandler
= ProRequest
;
609 AdapterBinding
->NdisOpenBlock
.ResetHandler
= ProReset
;
610 AdapterBinding
->NdisOpenBlock
.u1
.SendHandler
= ProSend
;
611 AdapterBinding
->NdisOpenBlock
.SendPacketsHandler
= ProSendPackets
;
612 AdapterBinding
->NdisOpenBlock
.TransferDataHandler
= ProTransferData
;
615 /* XXX this looks fishy */
616 /* OK, this really *is* fishy - it bugchecks */
617 /* Put on protocol's bound adapters list */
618 ExInterlockedInsertTailList(&Protocol
->AdapterListHead
, &AdapterBinding
->ProtocolListEntry
, &Protocol
->Lock
);
621 /* XXX so does this */
622 /* Put protocol on adapter's bound protocols list */
623 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
624 ExInterlockedInsertTailList(&Adapter
->ProtocolListHead
, &AdapterBinding
->AdapterListEntry
, &Adapter
->NdisMiniportBlock
.Lock
);
626 *NdisBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
628 *Status
= NDIS_STATUS_SUCCESS
;
637 NdisRegisterProtocol(
638 OUT PNDIS_STATUS Status
,
639 OUT PNDIS_HANDLE NdisProtocolHandle
,
640 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics
,
641 IN UINT CharacteristicsLength
)
643 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
645 * Status = Address of buffer for status information
646 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
647 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
648 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
650 * - you *must* set NdisProtocolHandle before doing anything that could wind up
651 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
652 * - the above implies that the initialization of the protocol block must be complete
655 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
656 * - make this thing able to handle >1 protocol
659 PPROTOCOL_BINDING Protocol
;
662 HANDLE DriverKeyHandle
= NULL
;
663 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
= NULL
;
666 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
668 /* first validate the PROTOCOL_CHARACTERISTICS */
669 switch (ProtocolCharacteristics
->MajorNdisVersion
)
672 /* we don't really want to support ndis3 drivers - so we complain for now */
673 NDIS_DbgPrint(MID_TRACE
, ("NDIS 3 protocol attempting to register\n"));
674 MinSize
= sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S
);
678 MinSize
= sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S
);
682 MinSize
= sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S
);
686 *Status
= NDIS_STATUS_BAD_VERSION
;
687 NDIS_DbgPrint(MIN_TRACE
, ("Incorrect characteristics size\n"));
691 if (CharacteristicsLength
< MinSize
)
693 NDIS_DbgPrint(DEBUG_PROTOCOL
, ("Bad protocol characteristics.\n"));
694 *Status
= NDIS_STATUS_BAD_CHARACTERISTICS
;
698 /* set up the protocol block */
699 Protocol
= ExAllocatePool(NonPagedPool
, sizeof(PROTOCOL_BINDING
));
702 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
703 *Status
= NDIS_STATUS_RESOURCES
;
707 RtlZeroMemory(Protocol
, sizeof(PROTOCOL_BINDING
));
708 RtlCopyMemory(&Protocol
->Chars
, ProtocolCharacteristics
, MinSize
);
710 NtStatus
= RtlUpcaseUnicodeString(&Protocol
->Chars
.Name
, &ProtocolCharacteristics
->Name
, TRUE
);
711 if (!NT_SUCCESS(NtStatus
))
713 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
714 ExFreePool(Protocol
);
715 *Status
= NDIS_STATUS_RESOURCES
;
719 KeInitializeSpinLock(&Protocol
->Lock
);
721 Protocol
->RefCount
= 1;
723 InitializeListHead(&Protocol
->AdapterListHead
);
726 * bind the protocol to all of its miniports
729 * get list of devices from Bind key
730 * call BindAdapterHandler for each
733 OBJECT_ATTRIBUTES ObjectAttributes
;
734 UNICODE_STRING RegistryPath
;
735 WCHAR
*RegistryPathStr
;
737 RegistryPathStr
= ExAllocatePool(PagedPool
, sizeof(SERVICES_KEY
) + ProtocolCharacteristics
->Name
.Length
+ sizeof(LINKAGE_KEY
));
740 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
741 ExFreePool(Protocol
);
742 *Status
= NDIS_STATUS_RESOURCES
;
746 wcscpy(RegistryPathStr
, SERVICES_KEY
);
747 wcsncat(RegistryPathStr
, ((WCHAR
*)ProtocolCharacteristics
->Name
.Buffer
), ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
));
748 RegistryPathStr
[wcslen(SERVICES_KEY
)+ProtocolCharacteristics
->Name
.Length
/sizeof(WCHAR
)] = 0;
749 wcscat(RegistryPathStr
, LINKAGE_KEY
);
751 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
752 NDIS_DbgPrint(MAX_TRACE
, ("Opening configuration key: %wZ\n", &RegistryPath
));
754 InitializeObjectAttributes(&ObjectAttributes
, &RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
755 NtStatus
= ZwOpenKey(&DriverKeyHandle
, KEY_READ
, &ObjectAttributes
);
757 ExFreePool(RegistryPathStr
);
759 if(!NT_SUCCESS(NtStatus
))
761 NDIS_DbgPrint(MID_TRACE
, ("Unable to open protocol configuration\n"));
762 ExFreePool(Protocol
);
763 *Status
= NDIS_STATUS_FAILURE
;
768 NDIS_DbgPrint(MAX_TRACE
, ("Successfully opened the registry configuration\n"));
771 UNICODE_STRING ValueName
;
774 RtlInitUnicodeString(&ValueName
, L
"Bind");
776 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, NULL
, 0, &ResultLength
);
777 if(NtStatus
!= STATUS_BUFFER_OVERFLOW
&& NtStatus
!= STATUS_BUFFER_TOO_SMALL
)
779 NDIS_DbgPrint(MID_TRACE
, ("Unable to query the Bind value for size\n"));
780 ZwClose(DriverKeyHandle
);
781 ExFreePool(Protocol
);
782 *Status
= NDIS_STATUS_FAILURE
;
786 KeyInformation
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
);
789 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
790 ZwClose(DriverKeyHandle
);
791 ExFreePool(Protocol
);
792 *Status
= NDIS_STATUS_FAILURE
;
796 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, KeyInformation
,
797 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, &ResultLength
);
799 if(!NT_SUCCESS(NtStatus
))
801 NDIS_DbgPrint(MIN_TRACE
, ("Unable to query the Bind value\n"));
802 ZwClose(DriverKeyHandle
);
803 ExFreePool(KeyInformation
);
804 ExFreePool(Protocol
);
805 *Status
= NDIS_STATUS_FAILURE
;
810 for(CurrentStr
= (WCHAR
*)&KeyInformation
->Data
[0]; *CurrentStr
!= '\0'; CurrentStr
+= wcslen(CurrentStr
) + 1)
812 /* BindContext is for tracking pending binding operations */
813 VOID
*BindContext
= 0;
814 NDIS_STRING DeviceName
;
815 NDIS_STRING RegistryPath
;
816 WCHAR
*RegistryPathStr
= NULL
;
817 ULONG PathLength
= 0;
819 RtlInitUnicodeString(&DeviceName
, CurrentStr
); /* we know this is 0-term */
822 * RegistryPath should be:
823 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
825 * This is constructed as follows:
826 * SERVICES_KEY + extracted device name + Protocol name from characteristics
829 PathLength
= sizeof(SERVICES_KEY
) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
830 wcslen( CurrentStr
+8 ) * sizeof(WCHAR
) + /* Adapter1 (extracted from \Device\Adapter1) */
831 sizeof(PARAMETERS_KEY
) + /* \Parameters\ */
832 ProtocolCharacteristics
->Name
.Length
; /* Tcpip */
834 RegistryPathStr
= ExAllocatePool(PagedPool
, PathLength
);
837 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
838 ExFreePool(KeyInformation
);
839 ExFreePool(Protocol
);
840 *Status
= NDIS_STATUS_RESOURCES
;
844 wcscpy(RegistryPathStr
, SERVICES_KEY
);
845 wcscat(RegistryPathStr
, CurrentStr
+8 );
846 wcscat(RegistryPathStr
, PARAMETERS_KEY
);
847 wcsncat(RegistryPathStr
, ProtocolCharacteristics
->Name
.Buffer
, ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
) );
849 RegistryPathStr
[PathLength
/sizeof(WCHAR
) - 1] = 0;
851 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
853 NDIS_DbgPrint(MAX_TRACE
, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
854 &DeviceName
, &RegistryPath
));
856 /* XXX SD must do something with bind context */
857 *NdisProtocolHandle
= Protocol
;
860 BIND_HANDLER BindHandler
= ProtocolCharacteristics
->BindAdapterHandler
;
862 BindHandler(Status
, BindContext
, &DeviceName
, &RegistryPath
, 0);
864 NDIS_DbgPrint(MID_TRACE
, ("No protocol bind handler specified\n"));
868 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
871 if(*Status
== NDIS_STATUS_SUCCESS
)
873 /* Put protocol binding struct on global list */
874 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
875 NDIS_DbgPrint(MAX_TRACE
, ("Added to global list.\n"));
879 else if(*Status != NDIS_STATUS_PENDING)
885 NDIS_DbgPrint(MAX_TRACE
, ("Leaving..\n"));
886 *Status
= NDIS_STATUS_SUCCESS
;
896 OUT PNDIS_STATUS Status
,
897 IN NDIS_HANDLE NdisBindingHandle
,
898 IN PNDIS_REQUEST NdisRequest
)
900 * FUNCTION: Forwards a request to an NDIS driver
902 * Status = Address of buffer for status information
903 * NdisBindingHandle = Adapter binding handle
904 * NdisRequest = Pointer to request to perform
907 *Status
= ProRequest(NdisBindingHandle
, NdisRequest
);
917 OUT PNDIS_STATUS Status
,
918 IN NDIS_HANDLE NdisBindingHandle
)
920 *Status
= ProReset(NdisBindingHandle
);
930 OUT PNDIS_STATUS Status
,
931 IN NDIS_HANDLE NdisBindingHandle
,
932 IN PNDIS_PACKET Packet
)
934 * FUNCTION: Forwards a request to send a packet
936 * Status = Address of buffer for status information
937 * NdisBindingHandle = Adapter binding handle
938 * Packet = Pointer to NDIS packet descriptor
941 *Status
= ProSend(NdisBindingHandle
, Packet
);
951 IN NDIS_HANDLE NdisBindingHandle
,
952 IN PPNDIS_PACKET PacketArray
,
953 IN UINT NumberOfPackets
)
955 ProSendPackets(NdisBindingHandle
, PacketArray
, NumberOfPackets
);
965 OUT PNDIS_STATUS Status
,
966 IN NDIS_HANDLE NdisBindingHandle
,
967 IN NDIS_HANDLE MacReceiveContext
,
969 IN UINT BytesToTransfer
,
970 IN OUT PNDIS_PACKET Packet
,
971 OUT PUINT BytesTransferred
)
973 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
975 * Status = Address of buffer for status information
976 * NdisBindingHandle = Adapter binding handle
977 * MacReceiveContext = MAC receive context
978 * ByteOffset = Offset in packet to place data
979 * BytesToTransfer = Number of bytes to copy into packet
980 * Packet = Pointer to NDIS packet descriptor
981 * BytesTransferred = Address of buffer to place number of bytes copied
984 *Status
= ProTransferData(NdisBindingHandle
,