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
18 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
19 #define LINKAGE_KEY L"\\Linkage"
20 #define PARAMETERS_KEY L"\\Parameters\\"
22 LIST_ENTRY ProtocolListHead
;
23 KSPIN_LOCK ProtocolListLock
;
31 NdisCompleteBindAdapter(
32 IN NDIS_HANDLE BindAdapterContext
,
33 IN NDIS_STATUS Status
,
34 IN NDIS_STATUS OpenStatus
)
36 * FUNCTION: Indicates a packet to bound protocols
38 * Adapter = Pointer to logical adapter
39 * Packet = Pointer to packet to indicate
43 * - FIXME: partially-implemented
46 PROTOCOL_BINDING
*Protocol
= (PROTOCOL_BINDING
*)BindAdapterContext
;
48 /* Put protocol binding struct on global list */
49 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
55 PLOGICAL_ADAPTER Adapter
,
58 * FUNCTION: Indicates a packet to bound protocols
60 * Adapter = Pointer to logical adapter
61 * Packet = Pointer to packet to indicate
63 * STATUS_SUCCESS in all cases
65 * - XXX ATM, this only handles loopback packets - is that its designed function?
72 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
75 MiniDisplayPacket(Packet
);
78 NdisQueryPacket(Packet
, NULL
, NULL
, NULL
, &PacketLength
);
80 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
81 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
83 Adapter
->LoopPacket
= Packet
;
84 BufferedLength
= CopyPacketToBuffer(Adapter
->LookaheadBuffer
, Packet
, 0, Adapter
->CurLookaheadLength
);
86 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
88 if (BufferedLength
> Adapter
->MediumHeaderSize
)
90 /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
91 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
,
92 &Adapter
->LookaheadBuffer
[Adapter
->MediumHeaderSize
], BufferedLength
- Adapter
->MediumHeaderSize
,
93 PacketLength
- Adapter
->MediumHeaderSize
);
97 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
, NULL
, 0, 0);
100 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
101 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
103 Adapter
->LoopPacket
= NULL
;
105 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
107 return STATUS_SUCCESS
;
113 IN NDIS_HANDLE MacBindingHandle
,
114 IN PNDIS_REQUEST NdisRequest
)
116 * FUNCTION: Forwards a request to an NDIS miniport
118 * MacBindingHandle = Adapter binding handle
119 * NdisRequest = Pointer to request to perform
121 * Status of operation
125 BOOLEAN QueueWorkItem
= FALSE
;
126 NDIS_STATUS NdisStatus
;
127 PADAPTER_BINDING AdapterBinding
;
128 PLOGICAL_ADAPTER Adapter
;
130 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
132 ASSERT(MacBindingHandle
);
133 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
135 ASSERT(AdapterBinding
->Adapter
);
136 Adapter
= AdapterBinding
->Adapter
;
139 * If the miniport is already busy, queue a workitem
141 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
142 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
144 if(Adapter
->MiniportBusy
)
145 QueueWorkItem
= TRUE
;
148 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
149 Adapter
->MiniportBusy
= TRUE
;
152 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
156 MiniQueueWorkItem(Adapter
, NdisWorkItemRequest
, (PVOID
)NdisRequest
, (NDIS_HANDLE
)AdapterBinding
);
157 return NDIS_STATUS_PENDING
;
160 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
161 /* TODO (?): move the irql raise into MiniDoRequest */
162 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
164 NdisStatus
= MiniDoRequest(Adapter
, NdisRequest
);
166 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
167 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
169 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
170 Adapter
->MiniportBusy
= FALSE
;
172 if (Adapter
->WorkQueueHead
)
173 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
175 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
177 KeLowerIrql(OldIrql
);
185 IN NDIS_HANDLE MacBindingHandle
)
189 return NDIS_STATUS_FAILURE
;
195 IN NDIS_HANDLE MacBindingHandle
,
196 IN PNDIS_PACKET Packet
)
198 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
200 * MacBindingHandle = Adapter binding handle
201 * Packet = Pointer to NDIS packet descriptor
203 * NDIS_STATUS_SUCCESS always
206 * - Fix return values
207 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
208 * - Queue packets directly on the adapters when possible (i.e.
209 * when miniports not busy)
213 KIRQL RaiseOldIrql
, SpinOldIrql
;
214 BOOLEAN QueueWorkItem
= FALSE
;
215 NDIS_STATUS NdisStatus
;
216 PADAPTER_BINDING AdapterBinding
;
217 PLOGICAL_ADAPTER Adapter
;
219 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
221 ASSERT(MacBindingHandle
);
222 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
224 ASSERT(AdapterBinding
);
225 Adapter
= AdapterBinding
->Adapter
;
229 /* if the following is not true, KeRaiseIrql() below will break */
230 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
232 /* XXX what is this crazy black magic? */
233 Packet
->Reserved
[0] = (ULONG_PTR
)MacBindingHandle
;
236 * Acquire this lock in order to see if the miniport is busy.
237 * If it is not busy, we mark it as busy and release the lock.
238 * Else we don't do anything because we have to queue a workitem
241 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
242 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
245 * if the miniport is marked as busy, we queue the packet as a work item,
246 * else we send the packet directly to the miniport. Sending to the miniport
249 if (Adapter
->MiniportBusy
)
250 QueueWorkItem
= TRUE
;
253 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
254 Adapter
->MiniportBusy
= TRUE
;
257 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
260 * Test the packet to see if it is a MAC loopback.
262 * We may have to loop this packet if miniport cannot.
263 * If dest MAC address of packet == MAC address of adapter,
264 * this is a loopback frame.
266 if ((Adapter
->NdisMiniportBlock
.MacOptions
& NDIS_MAC_OPTION_NO_LOOPBACK
) &&
267 MiniAdapterHasAddress(Adapter
, Packet
))
269 NDIS_DbgPrint(MIN_TRACE
, ("Looping packet.\n"));
273 MiniQueueWorkItem(Adapter
, NdisWorkItemSendLoopback
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
274 return NDIS_STATUS_PENDING
;
277 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
280 * atm this *only* handles loopback packets - it calls MiniIndicateData to
281 * send back to the protocol. FIXME: this will need to be adjusted a bit.
282 * Also, I'm not sure you really have to be at dispatch level for this. It
283 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
285 NdisStatus
= ProIndicatePacket(Adapter
, Packet
);
287 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
288 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
290 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
291 Adapter
->MiniportBusy
= FALSE
;
293 if (Adapter
->WorkQueueHead
)
294 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
296 NDIS_DbgPrint(MID_TRACE
,("Failed to insert packet into work queue\n"));
298 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
300 KeLowerIrql(RaiseOldIrql
);
305 NDIS_DbgPrint(MID_TRACE
,("Not a loopback packet\n"));
307 /* This is a normal send packet, not a loopback packet. */
310 MiniQueueWorkItem(Adapter
, NdisWorkItemSend
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
311 NDIS_DbgPrint(MAX_TRACE
, ("Queued a work item and returning\n"));
312 return NDIS_STATUS_PENDING
;
315 ASSERT(Adapter
->Miniport
);
318 * Call the appropriate send handler
320 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
323 if(Adapter
->Miniport
->Chars
.SendPacketsHandler
)
325 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
327 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
328 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
332 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
333 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
335 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
336 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
338 KeLowerIrql(RaiseOldIrql
);
341 /* SendPackets handlers return void - they always "succeed" */
342 NdisStatus
= NDIS_STATUS_SUCCESS
;
346 /* XXX FIXME THIS IS WRONG */
347 /* uh oh... forgot why i thought that... */
348 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
350 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
351 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
352 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
356 /* Send handlers always run at DISPATCH_LEVEL so we raise here */
357 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
359 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
360 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
361 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
363 KeLowerIrql(RaiseOldIrql
);
367 /* XXX why the hell do we do this? */
368 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
369 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
371 if (Adapter
->WorkQueueHead
)
373 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
374 NDIS_DbgPrint(MAX_TRACE
, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
377 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
379 NDIS_DbgPrint(MAX_TRACE
, ("returning 0x%x\n", NdisStatus
));
386 IN NDIS_HANDLE NdisBindingHandle
,
387 IN PPNDIS_PACKET PacketArray
,
388 IN UINT NumberOfPackets
)
396 IN NDIS_HANDLE MacBindingHandle
,
397 IN NDIS_HANDLE MacReceiveContext
,
399 IN UINT BytesToTransfer
,
400 IN OUT PNDIS_PACKET Packet
,
401 OUT PUINT BytesTransferred
)
403 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
405 * MacBindingHandle = Adapter binding handle
406 * MacReceiveContext = MAC receive context
407 * ByteOffset = Offset in packet to place data
408 * BytesToTransfer = Number of bytes to copy into packet
409 * Packet = Pointer to NDIS packet descriptor
410 * BytesTransferred = Address of buffer to place number of bytes copied
413 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
414 PLOGICAL_ADAPTER Adapter
= AdapterBinding
->Adapter
;
416 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
418 /* FIXME: Interrupts must be disabled for adapter */
419 /* XXX sd - why is that true? */
421 if (Packet
== Adapter
->LoopPacket
) {
422 NDIS_DbgPrint(MAX_TRACE
, ("LoopPacket\n"));
423 /* NDIS is responsible for looping this packet */
424 NdisCopyFromPacketToPacket(Packet
,
430 return NDIS_STATUS_SUCCESS
;
433 return (*Adapter
->Miniport
->Chars
.u2
.TransferDataHandler
)(
436 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
,
450 OUT PNDIS_STATUS Status
,
451 IN NDIS_HANDLE NdisBindingHandle
)
453 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
455 * Status = Address of buffer for status information
456 * NdisBindingHandle = Handle returned by NdisOpenAdapter
460 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(NdisBindingHandle
);
462 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
464 /* Remove from protocol's bound adapters list */
465 KeAcquireSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, &OldIrql
);
466 RemoveEntryList(&AdapterBinding
->ProtocolListEntry
);
467 KeReleaseSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, OldIrql
);
469 /* Remove protocol from adapter's bound protocols list */
470 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
471 KeAcquireSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
472 RemoveEntryList(&AdapterBinding
->AdapterListEntry
);
473 KeReleaseSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
475 ExFreePool(AdapterBinding
);
477 *Status
= NDIS_STATUS_SUCCESS
;
486 NdisDeregisterProtocol(
487 OUT PNDIS_STATUS Status
,
488 IN NDIS_HANDLE NdisProtocolHandle
)
490 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
492 * Status = Address of buffer for status information
493 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
497 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
499 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
501 /* FIXME: Make sure no adapter bindings exist */
503 /* Remove protocol from global list */
504 KeAcquireSpinLock(&ProtocolListLock
, &OldIrql
);
505 RemoveEntryList(&Protocol
->ListEntry
);
506 KeReleaseSpinLock(&ProtocolListLock
, OldIrql
);
508 ExFreePool(Protocol
);
510 *Status
= NDIS_STATUS_SUCCESS
;
520 OUT PNDIS_STATUS Status
,
521 OUT PNDIS_STATUS OpenErrorStatus
,
522 OUT PNDIS_HANDLE NdisBindingHandle
,
523 OUT PUINT SelectedMediumIndex
,
524 IN PNDIS_MEDIUM MediumArray
,
525 IN UINT MediumArraySize
,
526 IN NDIS_HANDLE NdisProtocolHandle
,
527 IN NDIS_HANDLE ProtocolBindingContext
,
528 IN PNDIS_STRING AdapterName
,
530 IN PSTRING AddressingInformation OPTIONAL
)
532 * FUNCTION: Opens an adapter for communication
534 * Status = Address of buffer for status information
535 * OpenErrorStatus = Address of buffer for secondary error code
536 * NdisBindingHandle = Address of buffer for adapter binding handle
537 * SelectedMediumIndex = Address of buffer for selected medium
538 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
539 * MediumArraySize = Number of elements in MediumArray
540 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
541 * ProtocolBindingContext = Pointer to caller suplied context area
542 * AdapterName = Pointer to buffer with name of adapter
543 * OpenOptions = Bitmask with flags passed to next-lower driver
544 * AddressingInformation = Optional pointer to buffer with NIC specific information
549 PLOGICAL_ADAPTER Adapter
;
550 PADAPTER_BINDING AdapterBinding
;
551 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
553 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
555 if(!NdisProtocolHandle
)
557 NDIS_DbgPrint(MAX_TRACE
, ("NdisProtocolHandle is NULL\n"));
558 *OpenErrorStatus
= *Status
= NDIS_STATUS_FAILURE
;
562 Adapter
= MiniLocateDevice(AdapterName
);
565 NDIS_DbgPrint(MIN_TRACE
, ("Adapter not found.\n"));
566 *Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
570 /* Find the media type in the list provided by the protocol driver */
572 for (i
= 0; i
< MediumArraySize
; i
++)
574 if (Adapter
->NdisMiniportBlock
.MediaType
== MediumArray
[i
])
576 *SelectedMediumIndex
= i
;
584 NDIS_DbgPrint(MIN_TRACE
, ("Medium is not supported.\n"));
585 *Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
589 /* Now that we have confirmed that the adapter can be opened, create a binding */
591 AdapterBinding
= ExAllocatePool(NonPagedPool
, sizeof(ADAPTER_BINDING
));
594 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
595 *Status
= NDIS_STATUS_RESOURCES
;
599 RtlZeroMemory(AdapterBinding
, sizeof(ADAPTER_BINDING
));
601 AdapterBinding
->ProtocolBinding
= Protocol
;
602 AdapterBinding
->Adapter
= Adapter
;
603 AdapterBinding
->NdisOpenBlock
.ProtocolBindingContext
= ProtocolBindingContext
;
605 /* Set fields required by some NDIS macros */
606 AdapterBinding
->NdisOpenBlock
.MacBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
608 /* Set handlers (some NDIS macros require these) */
610 AdapterBinding
->NdisOpenBlock
.RequestHandler
= ProRequest
;
611 AdapterBinding
->NdisOpenBlock
.ResetHandler
= ProReset
;
612 AdapterBinding
->NdisOpenBlock
.u1
.SendHandler
= ProSend
;
613 AdapterBinding
->NdisOpenBlock
.SendPacketsHandler
= ProSendPackets
;
614 AdapterBinding
->NdisOpenBlock
.TransferDataHandler
= ProTransferData
;
617 /* XXX this looks fishy */
618 /* OK, this really *is* fishy - it bugchecks */
619 /* Put on protocol's bound adapters list */
620 ExInterlockedInsertTailList(&Protocol
->AdapterListHead
, &AdapterBinding
->ProtocolListEntry
, &Protocol
->Lock
);
623 /* XXX so does this */
624 /* Put protocol on adapter's bound protocols list */
625 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
626 ExInterlockedInsertTailList(&Adapter
->ProtocolListHead
, &AdapterBinding
->AdapterListEntry
, &Adapter
->NdisMiniportBlock
.Lock
);
628 *NdisBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
630 *Status
= NDIS_STATUS_SUCCESS
;
639 NdisRegisterProtocol(
640 OUT PNDIS_STATUS Status
,
641 OUT PNDIS_HANDLE NdisProtocolHandle
,
642 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics
,
643 IN UINT CharacteristicsLength
)
645 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
647 * Status = Address of buffer for status information
648 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
649 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
650 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
652 * - you *must* set NdisProtocolHandle before doing anything that could wind up
653 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
654 * - the above implies that the initialization of the protocol block must be complete
657 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
658 * - make this thing able to handle >1 protocol
661 PPROTOCOL_BINDING Protocol
;
664 HANDLE DriverKeyHandle
= NULL
;
665 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
= NULL
;
668 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
670 /* first validate the PROTOCOL_CHARACTERISTICS */
671 switch (ProtocolCharacteristics
->MajorNdisVersion
)
674 /* we don't really want to support ndis3 drivers - so we complain for now */
675 NDIS_DbgPrint(MID_TRACE
, ("NDIS 3 protocol attempting to register\n"));
676 MinSize
= sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S
);
680 MinSize
= sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S
);
684 MinSize
= sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S
);
688 *Status
= NDIS_STATUS_BAD_VERSION
;
689 NDIS_DbgPrint(MIN_TRACE
, ("Incorrect characteristics size\n"));
693 if (CharacteristicsLength
< MinSize
)
695 NDIS_DbgPrint(DEBUG_PROTOCOL
, ("Bad protocol characteristics.\n"));
696 *Status
= NDIS_STATUS_BAD_CHARACTERISTICS
;
700 /* set up the protocol block */
701 Protocol
= ExAllocatePool(NonPagedPool
, sizeof(PROTOCOL_BINDING
));
704 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
705 *Status
= NDIS_STATUS_RESOURCES
;
709 RtlZeroMemory(Protocol
, sizeof(PROTOCOL_BINDING
));
710 RtlCopyMemory(&Protocol
->Chars
, ProtocolCharacteristics
, MinSize
);
712 NtStatus
= RtlUpcaseUnicodeString(&Protocol
->Chars
.Name
, &ProtocolCharacteristics
->Name
, TRUE
);
713 if (!NT_SUCCESS(NtStatus
))
715 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
716 ExFreePool(Protocol
);
717 *Status
= NDIS_STATUS_RESOURCES
;
721 KeInitializeSpinLock(&Protocol
->Lock
);
723 Protocol
->RefCount
= 1;
725 InitializeListHead(&Protocol
->AdapterListHead
);
728 * bind the protocol to all of its miniports
731 * get list of devices from Bind key
732 * call BindAdapterHandler for each
735 OBJECT_ATTRIBUTES ObjectAttributes
;
736 UNICODE_STRING RegistryPath
;
737 WCHAR
*RegistryPathStr
;
739 RegistryPathStr
= ExAllocatePool(PagedPool
, sizeof(SERVICES_KEY
) + ProtocolCharacteristics
->Name
.Length
+ sizeof(LINKAGE_KEY
));
742 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
743 ExFreePool(Protocol
);
744 *Status
= NDIS_STATUS_RESOURCES
;
748 wcscpy(RegistryPathStr
, SERVICES_KEY
);
749 wcsncat(RegistryPathStr
, ((WCHAR
*)ProtocolCharacteristics
->Name
.Buffer
), ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
));
750 RegistryPathStr
[wcslen(SERVICES_KEY
)+ProtocolCharacteristics
->Name
.Length
/sizeof(WCHAR
)] = 0;
751 wcscat(RegistryPathStr
, LINKAGE_KEY
);
753 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
754 NDIS_DbgPrint(MAX_TRACE
, ("Opening configuration key: %wZ\n", &RegistryPath
));
756 InitializeObjectAttributes(&ObjectAttributes
, &RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
757 NtStatus
= ZwOpenKey(&DriverKeyHandle
, KEY_READ
, &ObjectAttributes
);
759 ExFreePool(RegistryPathStr
);
761 if(!NT_SUCCESS(NtStatus
))
763 NDIS_DbgPrint(MID_TRACE
, ("Unable to open protocol configuration\n"));
764 ExFreePool(Protocol
);
765 *Status
= NDIS_STATUS_FAILURE
;
770 NDIS_DbgPrint(MAX_TRACE
, ("Successfully opened the registry configuration\n"));
773 UNICODE_STRING ValueName
;
776 RtlInitUnicodeString(&ValueName
, L
"Bind");
778 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, NULL
, 0, &ResultLength
);
779 if(NtStatus
!= STATUS_BUFFER_OVERFLOW
&& NtStatus
!= STATUS_BUFFER_TOO_SMALL
)
781 NDIS_DbgPrint(MID_TRACE
, ("Unable to query the Bind value for size\n"));
782 ZwClose(DriverKeyHandle
);
783 ExFreePool(Protocol
);
784 *Status
= NDIS_STATUS_FAILURE
;
788 KeyInformation
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
);
791 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
792 ZwClose(DriverKeyHandle
);
793 ExFreePool(Protocol
);
794 *Status
= NDIS_STATUS_FAILURE
;
798 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, KeyInformation
,
799 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, &ResultLength
);
801 if(!NT_SUCCESS(NtStatus
))
803 NDIS_DbgPrint(MIN_TRACE
, ("Unable to query the Bind value\n"));
804 ZwClose(DriverKeyHandle
);
805 ExFreePool(KeyInformation
);
806 ExFreePool(Protocol
);
807 *Status
= NDIS_STATUS_FAILURE
;
813 while((KeyInformation
->Data
)[DataOffset
])
815 /* BindContext is for tracking pending binding operations */
816 VOID
*BindContext
= 0;
817 NDIS_STRING DeviceName
;
818 NDIS_STRING RegistryPath
;
819 WCHAR
*RegistryPathStr
= NULL
;
820 ULONG PathLength
= 0;
822 RtlInitUnicodeString(&DeviceName
, (WCHAR
*)KeyInformation
->Data
); /* we know this is 0-term */
825 * RegistryPath should be:
826 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
828 * This is constructed as follows:
829 * SERVICES_KEY + extracted device name + Protocol name from characteristics
832 PathLength
= sizeof(SERVICES_KEY
) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
833 wcslen( ((WCHAR
*)KeyInformation
->Data
)+8 ) * sizeof(WCHAR
) + /* Adapter1 (extracted from \Device\Adapter1) */
834 sizeof(PARAMETERS_KEY
) + /* \Parameters\ */
835 ProtocolCharacteristics
->Name
.Length
; /* Tcpip */
837 RegistryPathStr
= ExAllocatePool(PagedPool
, PathLength
);
840 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
841 ExFreePool(KeyInformation
);
842 ExFreePool(Protocol
);
843 *Status
= NDIS_STATUS_RESOURCES
;
847 wcscpy(RegistryPathStr
, SERVICES_KEY
);
848 wcscat(RegistryPathStr
, (((WCHAR
*)(KeyInformation
->Data
)) +8 ));
849 wcscat(RegistryPathStr
, PARAMETERS_KEY
);
850 wcsncat(RegistryPathStr
, ProtocolCharacteristics
->Name
.Buffer
, ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
) );
852 RegistryPathStr
[PathLength
/sizeof(WCHAR
) - 1] = 0;
854 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
856 NDIS_DbgPrint(MAX_TRACE
, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
857 &DeviceName
, &RegistryPath
));
859 /* XXX SD must do something with bind context */
860 *NdisProtocolHandle
= Protocol
;
863 BIND_HANDLER BindHandler
= ProtocolCharacteristics
->BindAdapterHandler
;
865 BindHandler(Status
, BindContext
, &DeviceName
, &RegistryPath
, 0);
867 NDIS_DbgPrint(MID_TRACE
, ("No protocol bind handler specified\n"));
871 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
874 if(*Status
== NDIS_STATUS_SUCCESS
)
876 /* Put protocol binding struct on global list */
877 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
881 else if(*Status != NDIS_STATUS_PENDING)
887 DataOffset
+= wcslen((WCHAR
*)KeyInformation
->Data
);
890 *Status
= NDIS_STATUS_SUCCESS
;
900 OUT PNDIS_STATUS Status
,
901 IN NDIS_HANDLE NdisBindingHandle
,
902 IN PNDIS_REQUEST NdisRequest
)
904 * FUNCTION: Forwards a request to an NDIS driver
906 * Status = Address of buffer for status information
907 * NdisBindingHandle = Adapter binding handle
908 * NdisRequest = Pointer to request to perform
911 *Status
= ProRequest(NdisBindingHandle
, NdisRequest
);
921 OUT PNDIS_STATUS Status
,
922 IN NDIS_HANDLE NdisBindingHandle
)
924 *Status
= ProReset(NdisBindingHandle
);
934 OUT PNDIS_STATUS Status
,
935 IN NDIS_HANDLE NdisBindingHandle
,
936 IN PNDIS_PACKET Packet
)
938 * FUNCTION: Forwards a request to send a packet
940 * Status = Address of buffer for status information
941 * NdisBindingHandle = Adapter binding handle
942 * Packet = Pointer to NDIS packet descriptor
945 *Status
= ProSend(NdisBindingHandle
, Packet
);
955 IN NDIS_HANDLE NdisBindingHandle
,
956 IN PPNDIS_PACKET PacketArray
,
957 IN UINT NumberOfPackets
)
959 ProSendPackets(NdisBindingHandle
, PacketArray
, NumberOfPackets
);
969 OUT PNDIS_STATUS Status
,
970 IN NDIS_HANDLE NdisBindingHandle
,
971 IN NDIS_HANDLE MacReceiveContext
,
973 IN UINT BytesToTransfer
,
974 IN OUT PNDIS_PACKET Packet
,
975 OUT PUINT BytesTransferred
)
977 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
979 * Status = Address of buffer for status information
980 * NdisBindingHandle = Adapter binding handle
981 * MacReceiveContext = MAC receive context
982 * ByteOffset = Offset in packet to place data
983 * BytesToTransfer = Number of bytes to copy into packet
984 * Packet = Pointer to NDIS packet descriptor
985 * BytesTransferred = Address of buffer to place number of bytes copied
988 *Status
= ProTransferData(NdisBindingHandle
,