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
17 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
18 #define LINKAGE_KEY L"\\Linkage"
19 #define PARAMETERS_KEY L"\\Parameters\\"
21 LIST_ENTRY ProtocolListHead
;
22 KSPIN_LOCK ProtocolListLock
;
30 NdisCompleteBindAdapter(
31 IN NDIS_HANDLE BindAdapterContext
,
32 IN NDIS_STATUS Status
,
33 IN NDIS_STATUS OpenStatus
)
35 * FUNCTION: Indicates a packet to bound protocols
37 * Adapter = Pointer to logical adapter
38 * Packet = Pointer to packet to indicate
42 * - FIXME: partially-implemented
45 PROTOCOL_BINDING
*Protocol
= (PROTOCOL_BINDING
*)BindAdapterContext
;
47 /* Put protocol binding struct on global list */
48 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
54 PLOGICAL_ADAPTER Adapter
,
57 * FUNCTION: Indicates a packet to bound protocols
59 * Adapter = Pointer to logical adapter
60 * Packet = Pointer to packet to indicate
62 * STATUS_SUCCESS in all cases
64 * - XXX ATM, this only handles loopback packets - is that its designed function?
71 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
74 MiniDisplayPacket(Packet
);
77 NdisQueryPacket(Packet
, NULL
, NULL
, NULL
, &PacketLength
);
79 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
80 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
82 Adapter
->LoopPacket
= Packet
;
83 BufferedLength
= CopyPacketToBuffer(Adapter
->LookaheadBuffer
, Packet
, 0, Adapter
->CurLookaheadLength
);
85 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
87 if (BufferedLength
> Adapter
->MediumHeaderSize
)
89 /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
90 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
,
91 &Adapter
->LookaheadBuffer
[Adapter
->MediumHeaderSize
], BufferedLength
- Adapter
->MediumHeaderSize
,
92 PacketLength
- Adapter
->MediumHeaderSize
);
96 MiniIndicateData(Adapter
, NULL
, Adapter
->LookaheadBuffer
, Adapter
->MediumHeaderSize
, NULL
, 0, 0);
99 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
100 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
102 Adapter
->LoopPacket
= NULL
;
104 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
106 return STATUS_SUCCESS
;
112 IN NDIS_HANDLE MacBindingHandle
,
113 IN PNDIS_REQUEST NdisRequest
)
115 * FUNCTION: Forwards a request to an NDIS miniport
117 * MacBindingHandle = Adapter binding handle
118 * NdisRequest = Pointer to request to perform
120 * Status of operation
124 BOOLEAN QueueWorkItem
= FALSE
;
125 NDIS_STATUS NdisStatus
;
126 PADAPTER_BINDING AdapterBinding
;
127 PLOGICAL_ADAPTER Adapter
;
129 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
131 ASSERT(MacBindingHandle
);
132 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
134 ASSERT(AdapterBinding
->Adapter
);
135 Adapter
= AdapterBinding
->Adapter
;
138 * If the miniport is already busy, queue a workitem
140 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
141 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
143 if(Adapter
->MiniportBusy
)
144 QueueWorkItem
= TRUE
;
147 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
148 Adapter
->MiniportBusy
= TRUE
;
151 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
155 MiniQueueWorkItem(Adapter
, NdisWorkItemRequest
, (PVOID
)NdisRequest
, (NDIS_HANDLE
)AdapterBinding
);
156 return NDIS_STATUS_PENDING
;
159 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
160 /* TODO (?): move the irql raise into MiniDoRequest */
161 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
163 NdisStatus
= MiniDoRequest(Adapter
, NdisRequest
);
165 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
166 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
168 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
169 Adapter
->MiniportBusy
= FALSE
;
171 if (Adapter
->WorkQueueHead
)
172 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
174 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
176 KeLowerIrql(OldIrql
);
184 IN NDIS_HANDLE MacBindingHandle
)
188 return NDIS_STATUS_FAILURE
;
194 IN NDIS_HANDLE MacBindingHandle
,
195 IN PNDIS_PACKET Packet
)
197 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
199 * MacBindingHandle = Adapter binding handle
200 * Packet = Pointer to NDIS packet descriptor
202 * NDIS_STATUS_SUCCESS always
205 * - Fix return values
206 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
207 * - Queue packets directly on the adapters when possible (i.e.
208 * when miniports not busy)
212 KIRQL RaiseOldIrql
, SpinOldIrql
;
213 BOOLEAN QueueWorkItem
= FALSE
;
214 NDIS_STATUS NdisStatus
;
215 PADAPTER_BINDING AdapterBinding
;
216 PLOGICAL_ADAPTER Adapter
;
218 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
220 ASSERT(MacBindingHandle
);
221 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
223 ASSERT(AdapterBinding
);
224 Adapter
= AdapterBinding
->Adapter
;
228 /* if the following is not true, KeRaiseIrql() below will break */
229 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
231 /* XXX what is this crazy black magic? */
232 Packet
->Reserved
[0] = (ULONG_PTR
)MacBindingHandle
;
235 * Acquire this lock in order to see if the miniport is busy.
236 * If it is not busy, we mark it as busy and release the lock.
237 * Else we don't do anything because we have to queue a workitem
240 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
241 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
244 * if the miniport is marked as busy, we queue the packet as a work item,
245 * else we send the packet directly to the miniport. Sending to the miniport
248 if (Adapter
->MiniportBusy
)
249 QueueWorkItem
= TRUE
;
252 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
253 Adapter
->MiniportBusy
= TRUE
;
256 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
259 * Test the packet to see if it is a MAC loopback.
261 * We may have to loop this packet if miniport cannot.
262 * If dest MAC address of packet == MAC address of adapter,
263 * this is a loopback frame.
265 if ((Adapter
->NdisMiniportBlock
.MacOptions
& NDIS_MAC_OPTION_NO_LOOPBACK
) &&
266 MiniAdapterHasAddress(Adapter
, Packet
))
268 NDIS_DbgPrint(MIN_TRACE
, ("Looping packet.\n"));
272 MiniQueueWorkItem(Adapter
, NdisWorkItemSendLoopback
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
273 return NDIS_STATUS_PENDING
;
276 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
279 * atm this *only* handles loopback packets - it calls MiniIndicateData to
280 * send back to the protocol. FIXME: this will need to be adjusted a bit.
281 * Also, I'm not sure you really have to be at dispatch level for this. It
282 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
284 NdisStatus
= ProIndicatePacket(Adapter
, Packet
);
286 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
287 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
289 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
290 Adapter
->MiniportBusy
= FALSE
;
292 if (Adapter
->WorkQueueHead
)
293 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
295 NDIS_DbgPrint(MID_TRACE
,("Failed to insert packet into work queue\n"));
297 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
299 KeLowerIrql(RaiseOldIrql
);
304 NDIS_DbgPrint(MID_TRACE
,("Not a loopback packet\n"));
306 /* This is a normal send packet, not a loopback packet. */
309 MiniQueueWorkItem(Adapter
, NdisWorkItemSend
, (PVOID
)Packet
, (NDIS_HANDLE
)AdapterBinding
);
310 NDIS_DbgPrint(MAX_TRACE
, ("Queued a work item and returning\n"));
311 return NDIS_STATUS_PENDING
;
314 ASSERT(Adapter
->Miniport
);
317 * Call the appropriate send handler
319 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
322 if(Adapter
->Miniport
->Chars
.SendPacketsHandler
)
324 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
326 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
327 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
331 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
332 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
334 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
335 (*Adapter
->Miniport
->Chars
.SendPacketsHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
337 KeLowerIrql(RaiseOldIrql
);
340 /* SendPackets handlers return void - they always "succeed" */
341 NdisStatus
= NDIS_STATUS_SUCCESS
;
345 /* XXX FIXME THIS IS WRONG */
346 /* uh oh... forgot why i thought that... */
347 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
349 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
350 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
351 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
355 /* Send handlers always run at DISPATCH_LEVEL so we raise here */
356 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
358 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
359 NdisStatus
= (*Adapter
->Miniport
->Chars
.u1
.SendHandler
)(Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
360 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
362 KeLowerIrql(RaiseOldIrql
);
366 /* XXX why the hell do we do this? */
367 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
368 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
370 if (Adapter
->WorkQueueHead
)
372 KeInsertQueueDpc(&Adapter
->MiniportDpc
, NULL
, NULL
);
373 NDIS_DbgPrint(MAX_TRACE
, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
376 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
378 NDIS_DbgPrint(MAX_TRACE
, ("returning 0x%x\n", NdisStatus
));
385 IN NDIS_HANDLE NdisBindingHandle
,
386 IN PPNDIS_PACKET PacketArray
,
387 IN UINT NumberOfPackets
)
395 IN NDIS_HANDLE MacBindingHandle
,
396 IN NDIS_HANDLE MacReceiveContext
,
398 IN UINT BytesToTransfer
,
399 IN OUT PNDIS_PACKET Packet
,
400 OUT PUINT BytesTransferred
)
402 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
404 * MacBindingHandle = Adapter binding handle
405 * MacReceiveContext = MAC receive context
406 * ByteOffset = Offset in packet to place data
407 * BytesToTransfer = Number of bytes to copy into packet
408 * Packet = Pointer to NDIS packet descriptor
409 * BytesTransferred = Address of buffer to place number of bytes copied
412 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
413 PLOGICAL_ADAPTER Adapter
= AdapterBinding
->Adapter
;
415 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
417 /* FIXME: Interrupts must be disabled for adapter */
418 /* XXX sd - why is that true? */
420 if (Packet
== Adapter
->LoopPacket
) {
421 NDIS_DbgPrint(MAX_TRACE
, ("LoopPacket\n"));
422 /* NDIS is responsible for looping this packet */
423 NdisCopyFromPacketToPacket(Packet
,
429 return NDIS_STATUS_SUCCESS
;
432 return (*Adapter
->Miniport
->Chars
.u2
.TransferDataHandler
)(
435 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
,
449 OUT PNDIS_STATUS Status
,
450 IN NDIS_HANDLE NdisBindingHandle
)
452 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
454 * Status = Address of buffer for status information
455 * NdisBindingHandle = Handle returned by NdisOpenAdapter
459 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(NdisBindingHandle
);
461 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
463 /* Remove from protocol's bound adapters list */
464 KeAcquireSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, &OldIrql
);
465 RemoveEntryList(&AdapterBinding
->ProtocolListEntry
);
466 KeReleaseSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, OldIrql
);
468 /* Remove protocol from adapter's bound protocols list */
469 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
470 KeAcquireSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
471 RemoveEntryList(&AdapterBinding
->AdapterListEntry
);
472 KeReleaseSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
474 ExFreePool(AdapterBinding
);
476 *Status
= NDIS_STATUS_SUCCESS
;
485 NdisDeregisterProtocol(
486 OUT PNDIS_STATUS Status
,
487 IN NDIS_HANDLE NdisProtocolHandle
)
489 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
491 * Status = Address of buffer for status information
492 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
496 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
498 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
500 /* FIXME: Make sure no adapter bindings exist */
502 /* Remove protocol from global list */
503 KeAcquireSpinLock(&ProtocolListLock
, &OldIrql
);
504 RemoveEntryList(&Protocol
->ListEntry
);
505 KeReleaseSpinLock(&ProtocolListLock
, OldIrql
);
507 ExFreePool(Protocol
);
509 *Status
= NDIS_STATUS_SUCCESS
;
519 OUT PNDIS_STATUS Status
,
520 OUT PNDIS_STATUS OpenErrorStatus
,
521 OUT PNDIS_HANDLE NdisBindingHandle
,
522 OUT PUINT SelectedMediumIndex
,
523 IN PNDIS_MEDIUM MediumArray
,
524 IN UINT MediumArraySize
,
525 IN NDIS_HANDLE NdisProtocolHandle
,
526 IN NDIS_HANDLE ProtocolBindingContext
,
527 IN PNDIS_STRING AdapterName
,
529 IN PSTRING AddressingInformation OPTIONAL
)
531 * FUNCTION: Opens an adapter for communication
533 * Status = Address of buffer for status information
534 * OpenErrorStatus = Address of buffer for secondary error code
535 * NdisBindingHandle = Address of buffer for adapter binding handle
536 * SelectedMediumIndex = Address of buffer for selected medium
537 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
538 * MediumArraySize = Number of elements in MediumArray
539 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
540 * ProtocolBindingContext = Pointer to caller suplied context area
541 * AdapterName = Pointer to buffer with name of adapter
542 * OpenOptions = Bitmask with flags passed to next-lower driver
543 * AddressingInformation = Optional pointer to buffer with NIC specific information
548 PLOGICAL_ADAPTER Adapter
;
549 PADAPTER_BINDING AdapterBinding
;
550 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
552 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
554 if(!NdisProtocolHandle
)
556 NDIS_DbgPrint(MAX_TRACE
, ("NdisProtocolHandle is NULL\n"));
557 *OpenErrorStatus
= *Status
= NDIS_STATUS_FAILURE
;
561 Adapter
= MiniLocateDevice(AdapterName
);
564 NDIS_DbgPrint(MIN_TRACE
, ("Adapter not found.\n"));
565 *Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
569 /* Find the media type in the list provided by the protocol driver */
571 for (i
= 0; i
< MediumArraySize
; i
++)
573 if (Adapter
->NdisMiniportBlock
.MediaType
== MediumArray
[i
])
575 *SelectedMediumIndex
= i
;
583 NDIS_DbgPrint(MIN_TRACE
, ("Medium is not supported.\n"));
584 *Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
588 /* Now that we have confirmed that the adapter can be opened, create a binding */
590 AdapterBinding
= ExAllocatePool(NonPagedPool
, sizeof(ADAPTER_BINDING
));
593 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
594 *Status
= NDIS_STATUS_RESOURCES
;
598 RtlZeroMemory(AdapterBinding
, sizeof(ADAPTER_BINDING
));
600 AdapterBinding
->ProtocolBinding
= Protocol
;
601 AdapterBinding
->Adapter
= Adapter
;
602 AdapterBinding
->NdisOpenBlock
.ProtocolBindingContext
= ProtocolBindingContext
;
604 /* Set fields required by some NDIS macros */
605 AdapterBinding
->NdisOpenBlock
.MacBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
607 /* Set handlers (some NDIS macros require these) */
609 AdapterBinding
->NdisOpenBlock
.RequestHandler
= ProRequest
;
610 AdapterBinding
->NdisOpenBlock
.ResetHandler
= ProReset
;
611 AdapterBinding
->NdisOpenBlock
.u1
.SendHandler
= ProSend
;
612 AdapterBinding
->NdisOpenBlock
.SendPacketsHandler
= ProSendPackets
;
613 AdapterBinding
->NdisOpenBlock
.TransferDataHandler
= ProTransferData
;
616 /* XXX this looks fishy */
617 /* OK, this really *is* fishy - it bugchecks */
618 /* Put on protocol's bound adapters list */
619 ExInterlockedInsertTailList(&Protocol
->AdapterListHead
, &AdapterBinding
->ProtocolListEntry
, &Protocol
->Lock
);
622 /* XXX so does this */
623 /* Put protocol on adapter's bound protocols list */
624 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
625 ExInterlockedInsertTailList(&Adapter
->ProtocolListHead
, &AdapterBinding
->AdapterListEntry
, &Adapter
->NdisMiniportBlock
.Lock
);
627 *NdisBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
629 *Status
= NDIS_STATUS_SUCCESS
;
638 NdisRegisterProtocol(
639 OUT PNDIS_STATUS Status
,
640 OUT PNDIS_HANDLE NdisProtocolHandle
,
641 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics
,
642 IN UINT CharacteristicsLength
)
644 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
646 * Status = Address of buffer for status information
647 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
648 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
649 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
651 * - you *must* set NdisProtocolHandle before doing anything that could wind up
652 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
653 * - the above implies that the initialization of the protocol block must be complete
656 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
657 * - make this thing able to handle >1 protocol
660 PPROTOCOL_BINDING Protocol
;
663 HANDLE DriverKeyHandle
= NULL
;
664 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
= NULL
;
667 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
669 /* first validate the PROTOCOL_CHARACTERISTICS */
670 switch (ProtocolCharacteristics
->MajorNdisVersion
)
673 /* we don't really want to support ndis3 drivers - so we complain for now */
674 NDIS_DbgPrint(MID_TRACE
, ("NDIS 3 protocol attempting to register\n"));
675 MinSize
= sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S
);
679 MinSize
= sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S
);
683 MinSize
= sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S
);
687 *Status
= NDIS_STATUS_BAD_VERSION
;
688 NDIS_DbgPrint(MIN_TRACE
, ("Incorrect characteristics size\n"));
692 if (CharacteristicsLength
< MinSize
)
694 NDIS_DbgPrint(DEBUG_PROTOCOL
, ("Bad protocol characteristics.\n"));
695 *Status
= NDIS_STATUS_BAD_CHARACTERISTICS
;
699 /* set up the protocol block */
700 Protocol
= ExAllocatePool(NonPagedPool
, sizeof(PROTOCOL_BINDING
));
703 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
704 *Status
= NDIS_STATUS_RESOURCES
;
708 RtlZeroMemory(Protocol
, sizeof(PROTOCOL_BINDING
));
709 RtlCopyMemory(&Protocol
->Chars
, ProtocolCharacteristics
, MinSize
);
711 NtStatus
= RtlUpcaseUnicodeString(&Protocol
->Chars
.Name
, &ProtocolCharacteristics
->Name
, TRUE
);
712 if (!NT_SUCCESS(NtStatus
))
714 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
715 ExFreePool(Protocol
);
716 *Status
= NDIS_STATUS_RESOURCES
;
720 KeInitializeSpinLock(&Protocol
->Lock
);
722 Protocol
->RefCount
= 1;
724 InitializeListHead(&Protocol
->AdapterListHead
);
727 * bind the protocol to all of its miniports
730 * get list of devices from Bind key
731 * call BindAdapterHandler for each
734 OBJECT_ATTRIBUTES ObjectAttributes
;
735 UNICODE_STRING RegistryPath
;
736 WCHAR
*RegistryPathStr
;
738 RegistryPathStr
= ExAllocatePool(PagedPool
, sizeof(SERVICES_KEY
) + ProtocolCharacteristics
->Name
.Length
+ sizeof(LINKAGE_KEY
));
741 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
742 ExFreePool(Protocol
);
743 *Status
= NDIS_STATUS_RESOURCES
;
747 wcscpy(RegistryPathStr
, SERVICES_KEY
);
748 wcsncat(RegistryPathStr
, ((WCHAR
*)ProtocolCharacteristics
->Name
.Buffer
), ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
));
749 RegistryPathStr
[wcslen(SERVICES_KEY
)+ProtocolCharacteristics
->Name
.Length
/sizeof(WCHAR
)] = 0;
750 wcscat(RegistryPathStr
, LINKAGE_KEY
);
752 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
753 NDIS_DbgPrint(MAX_TRACE
, ("Opening configuration key: %wZ\n", &RegistryPath
));
755 InitializeObjectAttributes(&ObjectAttributes
, &RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
756 NtStatus
= ZwOpenKey(&DriverKeyHandle
, KEY_READ
, &ObjectAttributes
);
758 ExFreePool(RegistryPathStr
);
760 if(!NT_SUCCESS(NtStatus
))
762 NDIS_DbgPrint(MID_TRACE
, ("Unable to open protocol configuration\n"));
763 ExFreePool(Protocol
);
764 *Status
= NDIS_STATUS_FAILURE
;
769 NDIS_DbgPrint(MAX_TRACE
, ("Successfully opened the registry configuration\n"));
772 UNICODE_STRING ValueName
;
775 RtlInitUnicodeString(&ValueName
, L
"Bind");
777 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, NULL
, 0, &ResultLength
);
778 if(NtStatus
!= STATUS_BUFFER_OVERFLOW
&& NtStatus
!= STATUS_BUFFER_TOO_SMALL
)
780 NDIS_DbgPrint(MID_TRACE
, ("Unable to query the Bind value for size\n"));
781 ZwClose(DriverKeyHandle
);
782 ExFreePool(Protocol
);
783 *Status
= NDIS_STATUS_FAILURE
;
787 KeyInformation
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
);
790 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
791 ZwClose(DriverKeyHandle
);
792 ExFreePool(Protocol
);
793 *Status
= NDIS_STATUS_FAILURE
;
797 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, KeyInformation
,
798 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, &ResultLength
);
800 if(!NT_SUCCESS(NtStatus
))
802 NDIS_DbgPrint(MIN_TRACE
, ("Unable to query the Bind value\n"));
803 ZwClose(DriverKeyHandle
);
804 ExFreePool(KeyInformation
);
805 ExFreePool(Protocol
);
806 *Status
= NDIS_STATUS_FAILURE
;
812 while((KeyInformation
->Data
)[DataOffset
])
814 /* BindContext is for tracking pending binding operations */
815 VOID
*BindContext
= 0;
816 NDIS_STRING DeviceName
;
817 NDIS_STRING RegistryPath
;
818 WCHAR
*RegistryPathStr
= NULL
;
819 ULONG PathLength
= 0;
821 RtlInitUnicodeString(&DeviceName
, (WCHAR
*)KeyInformation
->Data
); /* we know this is 0-term */
824 * RegistryPath should be:
825 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
827 * This is constructed as follows:
828 * SERVICES_KEY + extracted device name + Protocol name from characteristics
831 PathLength
= sizeof(SERVICES_KEY
) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
832 wcslen( ((WCHAR
*)KeyInformation
->Data
)+8 ) * sizeof(WCHAR
) + /* Adapter1 (extracted from \Device\Adapter1) */
833 sizeof(PARAMETERS_KEY
) + /* \Parameters\ */
834 ProtocolCharacteristics
->Name
.Length
; /* Tcpip */
836 RegistryPathStr
= ExAllocatePool(PagedPool
, PathLength
);
839 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
840 ExFreePool(KeyInformation
);
841 ExFreePool(Protocol
);
842 *Status
= NDIS_STATUS_RESOURCES
;
846 wcscpy(RegistryPathStr
, SERVICES_KEY
);
847 wcscat(RegistryPathStr
, (((WCHAR
*)(KeyInformation
->Data
)) +8 ));
848 wcscat(RegistryPathStr
, PARAMETERS_KEY
);
849 wcsncat(RegistryPathStr
, ProtocolCharacteristics
->Name
.Buffer
, ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
) );
851 RegistryPathStr
[PathLength
/sizeof(WCHAR
) - 1] = 0;
853 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
855 NDIS_DbgPrint(MAX_TRACE
, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
856 &DeviceName
, &RegistryPath
));
858 /* XXX SD must do something with bind context */
859 *NdisProtocolHandle
= Protocol
;
862 BIND_HANDLER BindHandler
= ProtocolCharacteristics
->BindAdapterHandler
;
864 BindHandler(Status
, BindContext
, &DeviceName
, &RegistryPath
, 0);
866 NDIS_DbgPrint(MID_TRACE
, ("No protocol bind handler specified\n"));
870 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
873 if(*Status
== NDIS_STATUS_SUCCESS
)
875 /* Put protocol binding struct on global list */
876 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
880 else if(*Status != NDIS_STATUS_PENDING)
886 DataOffset
+= wcslen((WCHAR
*)KeyInformation
->Data
);
889 *Status
= NDIS_STATUS_SUCCESS
;
899 OUT PNDIS_STATUS Status
,
900 IN NDIS_HANDLE NdisBindingHandle
,
901 IN PNDIS_REQUEST NdisRequest
)
903 * FUNCTION: Forwards a request to an NDIS driver
905 * Status = Address of buffer for status information
906 * NdisBindingHandle = Adapter binding handle
907 * NdisRequest = Pointer to request to perform
910 *Status
= ProRequest(NdisBindingHandle
, NdisRequest
);
920 OUT PNDIS_STATUS Status
,
921 IN NDIS_HANDLE NdisBindingHandle
)
923 *Status
= ProReset(NdisBindingHandle
);
933 OUT PNDIS_STATUS Status
,
934 IN NDIS_HANDLE NdisBindingHandle
,
935 IN PNDIS_PACKET Packet
)
937 * FUNCTION: Forwards a request to send a packet
939 * Status = Address of buffer for status information
940 * NdisBindingHandle = Adapter binding handle
941 * Packet = Pointer to NDIS packet descriptor
944 *Status
= ProSend(NdisBindingHandle
, Packet
);
954 IN NDIS_HANDLE NdisBindingHandle
,
955 IN PPNDIS_PACKET PacketArray
,
956 IN UINT NumberOfPackets
)
958 ProSendPackets(NdisBindingHandle
, PacketArray
, NumberOfPackets
);
968 OUT PNDIS_STATUS Status
,
969 IN NDIS_HANDLE NdisBindingHandle
,
970 IN NDIS_HANDLE MacReceiveContext
,
972 IN UINT BytesToTransfer
,
973 IN OUT PNDIS_PACKET Packet
,
974 OUT PUINT BytesTransferred
)
976 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
978 * Status = Address of buffer for status information
979 * NdisBindingHandle = Adapter binding handle
980 * MacReceiveContext = MAC receive context
981 * ByteOffset = Offset in packet to place data
982 * BytesToTransfer = Number of bytes to copy into packet
983 * Packet = Pointer to NDIS packet descriptor
984 * BytesTransferred = Address of buffer to place number of bytes copied
987 *Status
= ProTransferData(NdisBindingHandle
,