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
->NdisMiniportBlock
.IndicatedPacket
[KeGetCurrentProcessorNumber()] = Packet
;
82 BufferedLength
= CopyPacketToBuffer(Adapter
->LookaheadBuffer
, Packet
, 0, Adapter
->NdisMiniportBlock
.CurrentLookahead
);
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
->NdisMiniportBlock
.IndicatedPacket
[KeGetCurrentProcessorNumber()] = 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
;
127 PNDIS_REQUEST_MAC_BLOCK MacBlock
= (PNDIS_REQUEST_MAC_BLOCK
)NdisRequest
->MacReserved
;
129 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
131 ASSERT(MacBindingHandle
);
132 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
134 ASSERT(AdapterBinding
->Adapter
);
135 Adapter
= AdapterBinding
->Adapter
;
137 MacBlock
->Binding
= &AdapterBinding
->NdisOpenBlock
;
140 * If the miniport is already busy, queue a workitem
142 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
143 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
145 if(Adapter
->MiniportBusy
)
146 QueueWorkItem
= TRUE
;
149 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
150 Adapter
->MiniportBusy
= TRUE
;
154 /* MiniQueueWorkItem must be called at IRQL >= DISPATCH_LEVEL */
157 MiniQueueWorkItem(Adapter
, NdisWorkItemRequest
, (PVOID
)NdisRequest
);
158 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
159 return NDIS_STATUS_PENDING
;
162 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
164 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
165 /* TODO (?): move the irql raise into MiniDoRequest */
166 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
168 NdisStatus
= MiniDoRequest(&Adapter
->NdisMiniportBlock
, NdisRequest
);
170 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
171 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
173 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
174 Adapter
->MiniportBusy
= FALSE
;
176 if (Adapter
->WorkQueueHead
)
177 KeInsertQueueDpc(&Adapter
->NdisMiniportBlock
.DeferredDpc
, NULL
, NULL
);
179 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
181 KeLowerIrql(OldIrql
);
189 IN NDIS_HANDLE MacBindingHandle
)
193 return NDIS_STATUS_FAILURE
;
199 IN NDIS_HANDLE MacBindingHandle
,
200 IN PNDIS_PACKET Packet
)
202 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
204 * MacBindingHandle = Adapter binding handle
205 * Packet = Pointer to NDIS packet descriptor
207 * NDIS_STATUS_SUCCESS always
210 * - Fix return values
211 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
212 * - Queue packets directly on the adapters when possible (i.e.
213 * when miniports not busy)
217 KIRQL RaiseOldIrql
, SpinOldIrql
;
218 BOOLEAN QueueWorkItem
= FALSE
;
219 NDIS_STATUS NdisStatus
;
220 PADAPTER_BINDING AdapterBinding
;
221 PLOGICAL_ADAPTER Adapter
;
223 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
225 ASSERT(MacBindingHandle
);
226 AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
228 ASSERT(AdapterBinding
);
229 Adapter
= AdapterBinding
->Adapter
;
233 /* if the following is not true, KeRaiseIrql() below will break */
234 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
236 /* XXX what is this crazy black magic? */
237 Packet
->Reserved
[0] = (ULONG_PTR
)MacBindingHandle
;
240 * Acquire this lock in order to see if the miniport is busy.
241 * If it is not busy, we mark it as busy and release the lock.
242 * Else we don't do anything because we have to queue a workitem
245 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
246 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
249 * if the miniport is marked as busy, we queue the packet as a work item,
250 * else we send the packet directly to the miniport. Sending to the miniport
253 if (Adapter
->MiniportBusy
)
254 QueueWorkItem
= TRUE
;
257 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to busy\n"));
258 Adapter
->MiniportBusy
= TRUE
;
261 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
264 * Test the packet to see if it is a MAC loopback.
266 * We may have to loop this packet if miniport cannot.
267 * If dest MAC address of packet == MAC address of adapter,
268 * this is a loopback frame.
270 if ((Adapter
->NdisMiniportBlock
.MacOptions
& NDIS_MAC_OPTION_NO_LOOPBACK
) &&
271 MiniAdapterHasAddress(Adapter
, Packet
))
273 NDIS_DbgPrint(MIN_TRACE
, ("Looping packet.\n"));
277 MiniQueueWorkItem(Adapter
, NdisWorkItemSendLoopback
, (PVOID
)Packet
);
278 return NDIS_STATUS_PENDING
;
281 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
284 * atm this *only* handles loopback packets - it calls MiniIndicateData to
285 * send back to the protocol. FIXME: this will need to be adjusted a bit.
286 * Also, I'm not sure you really have to be at dispatch level for this. It
287 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
289 NdisStatus
= ProIndicatePacket(Adapter
, Packet
);
291 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
292 KeAcquireSpinLockAtDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
294 NDIS_DbgPrint(MAX_TRACE
, ("Setting adapter 0x%x to free\n"));
295 Adapter
->MiniportBusy
= FALSE
;
297 if (Adapter
->WorkQueueHead
)
298 KeInsertQueueDpc(&Adapter
->NdisMiniportBlock
.DeferredDpc
, NULL
, NULL
);
300 NDIS_DbgPrint(MID_TRACE
,("Failed to insert packet into work queue\n"));
302 KeReleaseSpinLockFromDpcLevel(&Adapter
->NdisMiniportBlock
.Lock
);
304 KeLowerIrql(RaiseOldIrql
);
309 NDIS_DbgPrint(MID_TRACE
,("Not a loopback packet\n"));
311 /* This is a normal send packet, not a loopback packet. */
314 MiniQueueWorkItem(Adapter
, NdisWorkItemSend
, (PVOID
)Packet
);
315 NDIS_DbgPrint(MAX_TRACE
, ("Queued a work item and returning\n"));
316 return NDIS_STATUS_PENDING
;
319 ASSERT(Adapter
->NdisMiniportBlock
.DriverHandle
);
322 * Call the appropriate send handler
324 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
327 if(Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.SendPacketsHandler
)
329 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
331 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
332 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.SendPacketsHandler
)(
333 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
337 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
338 KeRaiseIrql(DISPATCH_LEVEL
, &RaiseOldIrql
);
340 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's SendPackets handler\n"));
341 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.SendPacketsHandler
)(
342 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, &Packet
, 1);
344 KeLowerIrql(RaiseOldIrql
);
347 /* SendPackets handlers return void - they always "succeed" */
348 NdisStatus
= NDIS_STATUS_SUCCESS
;
352 /* XXX FIXME THIS IS WRONG */
353 /* uh oh... forgot why i thought that... */
354 if(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_DESERIALIZE
)
356 NDIS_DbgPrint(MAX_TRACE
, ("Calling miniport's Send handler\n"));
357 NdisStatus
= (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.SendHandler
)(
358 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
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.SendHandler
)(
368 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
, Packet
, 0);
369 NDIS_DbgPrint(MAX_TRACE
, ("back from miniport's send handler\n"));
370 if( NdisStatus
!= NDIS_STATUS_PENDING
) {
371 Adapter
->MiniportBusy
= FALSE
;
373 KeLowerIrql(RaiseOldIrql
);
377 /* XXX why the hell do we do this? */
378 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
379 KeAcquireSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, &SpinOldIrql
);
381 if (Adapter
->WorkQueueHead
)
383 KeInsertQueueDpc(&Adapter
->NdisMiniportBlock
.DeferredDpc
, NULL
, NULL
);
384 NDIS_DbgPrint(MAX_TRACE
, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
387 KeReleaseSpinLock(&Adapter
->NdisMiniportBlock
.Lock
, SpinOldIrql
);
389 NDIS_DbgPrint(MAX_TRACE
, ("returning 0x%x\n", NdisStatus
));
396 IN NDIS_HANDLE NdisBindingHandle
,
397 IN PPNDIS_PACKET PacketArray
,
398 IN UINT NumberOfPackets
)
406 IN NDIS_HANDLE MacBindingHandle
,
407 IN NDIS_HANDLE MacReceiveContext
,
409 IN UINT BytesToTransfer
,
410 IN OUT PNDIS_PACKET Packet
,
411 OUT PUINT BytesTransferred
)
413 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
415 * MacBindingHandle = Adapter binding handle
416 * MacReceiveContext = MAC receive context
417 * ByteOffset = Offset in packet to place data
418 * BytesToTransfer = Number of bytes to copy into packet
419 * Packet = Pointer to NDIS packet descriptor
420 * BytesTransferred = Address of buffer to place number of bytes copied
423 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(MacBindingHandle
);
424 PLOGICAL_ADAPTER Adapter
= AdapterBinding
->Adapter
;
426 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
428 /* FIXME: Interrupts must be disabled for adapter */
429 /* XXX sd - why is that true? */
431 if (Packet
== Adapter
->NdisMiniportBlock
.IndicatedPacket
[KeGetCurrentProcessorNumber()]) {
432 NDIS_DbgPrint(MAX_TRACE
, ("LoopPacket\n"));
433 /* NDIS is responsible for looping this packet */
434 NdisCopyFromPacketToPacket(Packet
,
437 Adapter
->NdisMiniportBlock
.IndicatedPacket
[KeGetCurrentProcessorNumber()],
440 return NDIS_STATUS_SUCCESS
;
443 return (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.TransferDataHandler
)(
446 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
,
460 OUT PNDIS_STATUS Status
,
461 IN NDIS_HANDLE NdisBindingHandle
)
463 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
465 * Status = Address of buffer for status information
466 * NdisBindingHandle = Handle returned by NdisOpenAdapter
470 PADAPTER_BINDING AdapterBinding
= GET_ADAPTER_BINDING(NdisBindingHandle
);
472 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
474 /* Remove from protocol's bound adapters list */
475 KeAcquireSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, &OldIrql
);
476 RemoveEntryList(&AdapterBinding
->ProtocolListEntry
);
477 KeReleaseSpinLock(&AdapterBinding
->ProtocolBinding
->Lock
, OldIrql
);
479 /* Remove protocol from adapter's bound protocols list */
480 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
481 KeAcquireSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, &OldIrql
);
482 RemoveEntryList(&AdapterBinding
->AdapterListEntry
);
483 KeReleaseSpinLock(&AdapterBinding
->Adapter
->NdisMiniportBlock
.Lock
, OldIrql
);
485 ExFreePool(AdapterBinding
);
487 *Status
= NDIS_STATUS_SUCCESS
;
496 NdisDeregisterProtocol(
497 OUT PNDIS_STATUS Status
,
498 IN NDIS_HANDLE NdisProtocolHandle
)
500 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
502 * Status = Address of buffer for status information
503 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
507 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
509 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
511 /* FIXME: Make sure no adapter bindings exist */
513 /* Remove protocol from global list */
514 KeAcquireSpinLock(&ProtocolListLock
, &OldIrql
);
515 RemoveEntryList(&Protocol
->ListEntry
);
516 KeReleaseSpinLock(&ProtocolListLock
, OldIrql
);
518 ExFreePool(Protocol
);
520 *Status
= NDIS_STATUS_SUCCESS
;
530 OUT PNDIS_STATUS Status
,
531 OUT PNDIS_STATUS OpenErrorStatus
,
532 OUT PNDIS_HANDLE NdisBindingHandle
,
533 OUT PUINT SelectedMediumIndex
,
534 IN PNDIS_MEDIUM MediumArray
,
535 IN UINT MediumArraySize
,
536 IN NDIS_HANDLE NdisProtocolHandle
,
537 IN NDIS_HANDLE ProtocolBindingContext
,
538 IN PNDIS_STRING AdapterName
,
540 IN PSTRING AddressingInformation OPTIONAL
)
542 * FUNCTION: Opens an adapter for communication
544 * Status = Address of buffer for status information
545 * OpenErrorStatus = Address of buffer for secondary error code
546 * NdisBindingHandle = Address of buffer for adapter binding handle
547 * SelectedMediumIndex = Address of buffer for selected medium
548 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
549 * MediumArraySize = Number of elements in MediumArray
550 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
551 * ProtocolBindingContext = Pointer to caller suplied context area
552 * AdapterName = Pointer to buffer with name of adapter
553 * OpenOptions = Bitmask with flags passed to next-lower driver
554 * AddressingInformation = Optional pointer to buffer with NIC specific information
559 PLOGICAL_ADAPTER Adapter
;
560 PADAPTER_BINDING AdapterBinding
;
561 PPROTOCOL_BINDING Protocol
= GET_PROTOCOL_BINDING(NdisProtocolHandle
);
563 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
565 if(!NdisProtocolHandle
)
567 NDIS_DbgPrint(MAX_TRACE
, ("NdisProtocolHandle is NULL\n"));
568 *OpenErrorStatus
= *Status
= NDIS_STATUS_FAILURE
;
572 Adapter
= MiniLocateDevice(AdapterName
);
575 NDIS_DbgPrint(MIN_TRACE
, ("Adapter not found.\n"));
576 *Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
580 /* Find the media type in the list provided by the protocol driver */
582 for (i
= 0; i
< MediumArraySize
; i
++)
584 if (Adapter
->NdisMiniportBlock
.MediaType
== MediumArray
[i
])
586 *SelectedMediumIndex
= i
;
594 NDIS_DbgPrint(MIN_TRACE
, ("Medium is not supported.\n"));
595 *Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
599 /* Now that we have confirmed that the adapter can be opened, create a binding */
601 AdapterBinding
= ExAllocatePool(NonPagedPool
, sizeof(ADAPTER_BINDING
));
604 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
605 *Status
= NDIS_STATUS_RESOURCES
;
609 RtlZeroMemory(AdapterBinding
, sizeof(ADAPTER_BINDING
));
611 AdapterBinding
->ProtocolBinding
= Protocol
;
612 AdapterBinding
->Adapter
= Adapter
;
613 AdapterBinding
->NdisOpenBlock
.ProtocolBindingContext
= ProtocolBindingContext
;
615 /* Set fields required by some NDIS macros */
616 AdapterBinding
->NdisOpenBlock
.BindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
618 /* Set handlers (some NDIS macros require these) */
620 AdapterBinding
->NdisOpenBlock
.RequestHandler
= ProRequest
;
621 AdapterBinding
->NdisOpenBlock
.ResetHandler
= ProReset
;
622 AdapterBinding
->NdisOpenBlock
.SendHandler
= ProSend
;
623 AdapterBinding
->NdisOpenBlock
.SendPacketsHandler
= ProSendPackets
;
624 AdapterBinding
->NdisOpenBlock
.TransferDataHandler
= ProTransferData
;
626 AdapterBinding
->NdisOpenBlock
.RequestCompleteHandler
=
627 Protocol
->Chars
.RequestCompleteHandler
;
630 /* XXX this looks fishy */
631 /* OK, this really *is* fishy - it bugchecks */
632 /* Put on protocol's bound adapters list */
633 ExInterlockedInsertTailList(&Protocol
->AdapterListHead
, &AdapterBinding
->ProtocolListEntry
, &Protocol
->Lock
);
636 /* XXX so does this */
637 /* Put protocol on adapter's bound protocols list */
638 NDIS_DbgPrint(MAX_TRACE
, ("acquiring miniport block lock\n"));
639 ExInterlockedInsertTailList(&Adapter
->ProtocolListHead
, &AdapterBinding
->AdapterListEntry
, &Adapter
->NdisMiniportBlock
.Lock
);
641 *NdisBindingHandle
= (NDIS_HANDLE
)AdapterBinding
;
643 *Status
= NDIS_STATUS_SUCCESS
;
652 NdisRegisterProtocol(
653 OUT PNDIS_STATUS Status
,
654 OUT PNDIS_HANDLE NdisProtocolHandle
,
655 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics
,
656 IN UINT CharacteristicsLength
)
658 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
660 * Status = Address of buffer for status information
661 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
662 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
663 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
665 * - you *must* set NdisProtocolHandle before doing anything that could wind up
666 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
667 * - the above implies that the initialization of the protocol block must be complete
670 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
671 * - make this thing able to handle >1 protocol
674 PPROTOCOL_BINDING Protocol
;
677 HANDLE DriverKeyHandle
= NULL
;
678 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation
= NULL
;
681 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
683 /* first validate the PROTOCOL_CHARACTERISTICS */
684 switch (ProtocolCharacteristics
->MajorNdisVersion
)
687 /* we don't really want to support ndis3 drivers - so we complain for now */
688 NDIS_DbgPrint(MID_TRACE
, ("NDIS 3 protocol attempting to register\n"));
689 MinSize
= sizeof(NDIS30_PROTOCOL_CHARACTERISTICS
);
693 MinSize
= sizeof(NDIS40_PROTOCOL_CHARACTERISTICS
);
697 MinSize
= sizeof(NDIS50_PROTOCOL_CHARACTERISTICS
);
701 *Status
= NDIS_STATUS_BAD_VERSION
;
702 NDIS_DbgPrint(MIN_TRACE
, ("Incorrect characteristics size\n"));
706 if (CharacteristicsLength
< MinSize
)
708 NDIS_DbgPrint(DEBUG_PROTOCOL
, ("Bad protocol characteristics.\n"));
709 *Status
= NDIS_STATUS_BAD_CHARACTERISTICS
;
713 /* set up the protocol block */
714 Protocol
= ExAllocatePool(NonPagedPool
, sizeof(PROTOCOL_BINDING
));
717 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
718 *Status
= NDIS_STATUS_RESOURCES
;
722 RtlZeroMemory(Protocol
, sizeof(PROTOCOL_BINDING
));
723 RtlCopyMemory(&Protocol
->Chars
, ProtocolCharacteristics
, MinSize
);
725 NtStatus
= RtlUpcaseUnicodeString(&Protocol
->Chars
.Name
, &ProtocolCharacteristics
->Name
, TRUE
);
726 if (!NT_SUCCESS(NtStatus
))
728 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
729 ExFreePool(Protocol
);
730 *Status
= NDIS_STATUS_RESOURCES
;
734 KeInitializeSpinLock(&Protocol
->Lock
);
736 InitializeListHead(&Protocol
->AdapterListHead
);
739 * bind the protocol to all of its miniports
742 * get list of devices from Bind key
743 * call BindAdapterHandler for each
746 OBJECT_ATTRIBUTES ObjectAttributes
;
747 UNICODE_STRING RegistryPath
;
748 WCHAR
*RegistryPathStr
;
750 RegistryPathStr
= ExAllocatePoolWithTag(PagedPool
, sizeof(SERVICES_KEY
) + ProtocolCharacteristics
->Name
.Length
+ sizeof(LINKAGE_KEY
), NDIS_TAG
+ __LINE__
);
753 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
754 ExFreePool(Protocol
);
755 *Status
= NDIS_STATUS_RESOURCES
;
759 wcscpy(RegistryPathStr
, SERVICES_KEY
);
760 wcsncat(RegistryPathStr
, ((WCHAR
*)ProtocolCharacteristics
->Name
.Buffer
), ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
));
761 RegistryPathStr
[wcslen(SERVICES_KEY
)+ProtocolCharacteristics
->Name
.Length
/sizeof(WCHAR
)] = 0;
762 wcscat(RegistryPathStr
, LINKAGE_KEY
);
764 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
765 NDIS_DbgPrint(MAX_TRACE
, ("Opening configuration key: %wZ\n", &RegistryPath
));
767 InitializeObjectAttributes(&ObjectAttributes
, &RegistryPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
768 NtStatus
= ZwOpenKey(&DriverKeyHandle
, KEY_READ
, &ObjectAttributes
);
770 ExFreePool(RegistryPathStr
);
772 if(!NT_SUCCESS(NtStatus
))
774 NDIS_DbgPrint(MID_TRACE
, ("Unable to open protocol configuration\n"));
775 ExFreePool(Protocol
);
776 *Status
= NDIS_STATUS_FAILURE
;
781 NDIS_DbgPrint(MAX_TRACE
, ("Successfully opened the registry configuration\n"));
784 UNICODE_STRING ValueName
;
787 RtlInitUnicodeString(&ValueName
, L
"Bind");
789 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, NULL
, 0, &ResultLength
);
790 if(NtStatus
!= STATUS_BUFFER_OVERFLOW
&& NtStatus
!= STATUS_BUFFER_TOO_SMALL
)
792 NDIS_DbgPrint(MID_TRACE
, ("Unable to query the Bind value for size\n"));
793 ZwClose(DriverKeyHandle
);
794 ExFreePool(Protocol
);
795 *Status
= NDIS_STATUS_FAILURE
;
799 KeyInformation
= ExAllocatePoolWithTag(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, NDIS_TAG
+ __LINE__
);
802 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
803 ZwClose(DriverKeyHandle
);
804 ExFreePool(Protocol
);
805 *Status
= NDIS_STATUS_FAILURE
;
809 NtStatus
= ZwQueryValueKey(DriverKeyHandle
, &ValueName
, KeyValuePartialInformation
, KeyInformation
,
810 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + ResultLength
, &ResultLength
);
812 if(!NT_SUCCESS(NtStatus
))
814 NDIS_DbgPrint(MIN_TRACE
, ("Unable to query the Bind value\n"));
815 ZwClose(DriverKeyHandle
);
816 ExFreePool(KeyInformation
);
817 ExFreePool(Protocol
);
818 *Status
= NDIS_STATUS_FAILURE
;
823 for (DataPtr
= (WCHAR
*)KeyInformation
->Data
;
825 DataPtr
+= wcslen(DataPtr
) + 1)
827 /* BindContext is for tracking pending binding operations */
828 VOID
*BindContext
= 0;
829 NDIS_STRING DeviceName
;
830 NDIS_STRING RegistryPath
;
831 WCHAR
*RegistryPathStr
= NULL
;
832 ULONG PathLength
= 0;
834 RtlInitUnicodeString(&DeviceName
, DataPtr
); /* we know this is 0-term */
837 * RegistryPath should be:
838 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
840 * This is constructed as follows:
841 * SERVICES_KEY + extracted device name + Protocol name from characteristics
844 PathLength
= sizeof(SERVICES_KEY
) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
845 wcslen( DataPtr
+ 8 ) * sizeof(WCHAR
) + /* Adapter1 (extracted from \Device\Adapter1) */
846 sizeof(PARAMETERS_KEY
) + /* \Parameters\ */
847 ProtocolCharacteristics
->Name
.Length
+ sizeof(WCHAR
); /* Tcpip */
849 RegistryPathStr
= ExAllocatePool(PagedPool
, PathLength
);
852 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
853 ExFreePool(KeyInformation
);
854 ExFreePool(Protocol
);
855 *Status
= NDIS_STATUS_RESOURCES
;
859 wcscpy(RegistryPathStr
, SERVICES_KEY
);
860 wcscat(RegistryPathStr
, DataPtr
+ 8 );
861 wcscat(RegistryPathStr
, PARAMETERS_KEY
);
862 wcsncat(RegistryPathStr
, ProtocolCharacteristics
->Name
.Buffer
, ProtocolCharacteristics
->Name
.Length
/ sizeof(WCHAR
) );
864 RegistryPathStr
[PathLength
/sizeof(WCHAR
) - 1] = 0;
866 RtlInitUnicodeString(&RegistryPath
, RegistryPathStr
);
868 NDIS_DbgPrint(MAX_TRACE
, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
869 &DeviceName
, &RegistryPath
));
871 /* XXX SD must do something with bind context */
872 *NdisProtocolHandle
= Protocol
;
875 BIND_HANDLER BindHandler
= ProtocolCharacteristics
->BindAdapterHandler
;
877 BindHandler(Status
, BindContext
, &DeviceName
, &RegistryPath
, 0);
879 NDIS_DbgPrint(MID_TRACE
, ("No protocol bind handler specified\n"));
883 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
886 if(*Status
== NDIS_STATUS_SUCCESS
)
888 /* Put protocol binding struct on global list */
889 ExInterlockedInsertTailList(&ProtocolListHead
, &Protocol
->ListEntry
, &ProtocolListLock
);
893 else if(*Status != NDIS_STATUS_PENDING)
900 *Status
= NDIS_STATUS_SUCCESS
;
910 OUT PNDIS_STATUS Status
,
911 IN NDIS_HANDLE NdisBindingHandle
,
912 IN PNDIS_REQUEST NdisRequest
)
914 * FUNCTION: Forwards a request to an NDIS driver
916 * Status = Address of buffer for status information
917 * NdisBindingHandle = Adapter binding handle
918 * NdisRequest = Pointer to request to perform
921 *Status
= ProRequest(NdisBindingHandle
, NdisRequest
);
931 OUT PNDIS_STATUS Status
,
932 IN NDIS_HANDLE NdisBindingHandle
)
934 *Status
= ProReset(NdisBindingHandle
);
945 OUT PNDIS_STATUS Status
,
946 IN NDIS_HANDLE NdisBindingHandle
,
947 IN PNDIS_PACKET Packet
)
949 * FUNCTION: Forwards a request to send a packet
951 * Status = Address of buffer for status information
952 * NdisBindingHandle = Adapter binding handle
953 * Packet = Pointer to NDIS packet descriptor
956 *Status
= ProSend(NdisBindingHandle
, Packet
);
963 #undef NdisSendPackets
967 IN NDIS_HANDLE NdisBindingHandle
,
968 IN PPNDIS_PACKET PacketArray
,
969 IN UINT NumberOfPackets
)
971 ProSendPackets(NdisBindingHandle
, PacketArray
, NumberOfPackets
);
978 #undef NdisTransferData
982 OUT PNDIS_STATUS Status
,
983 IN NDIS_HANDLE NdisBindingHandle
,
984 IN NDIS_HANDLE MacReceiveContext
,
986 IN UINT BytesToTransfer
,
987 IN OUT PNDIS_PACKET Packet
,
988 OUT PUINT BytesTransferred
)
990 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
992 * Status = Address of buffer for status information
993 * NdisBindingHandle = Adapter binding handle
994 * MacReceiveContext = MAC receive context
995 * ByteOffset = Offset in packet to place data
996 * BytesToTransfer = Number of bytes to copy into packet
997 * Packet = Pointer to NDIS packet descriptor
998 * BytesTransferred = Address of buffer to place number of bytes copied
1001 *Status
= ProTransferData(NdisBindingHandle
,