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)
8 * CSH 01/08-2000 Created
16 LIST_ENTRY ProtocolListHead;
17 KSPIN_LOCK ProtocolListLock;
22 PLOGICAL_ADAPTER Adapter,
25 * FUNCTION: Indicates a packet to bound protocols
27 * Adapter = Pointer to logical adapter
28 * Packet = Pointer to packet to indicate
37 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
40 MiniDisplayPacket(Packet);
43 NdisQueryPacket(Packet, NULL, NULL, NULL, &Total);
45 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
47 Adapter->LoopPacket = Packet;
49 Length = CopyPacketToBuffer(
50 Adapter->LookaheadBuffer,
53 Adapter->CurLookaheadLength);
55 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
57 if (Length > Adapter->MediumHeaderSize) {
58 MiniIndicateData(Adapter,
60 Adapter->LookaheadBuffer,
61 Adapter->MediumHeaderSize,
62 &Adapter->LookaheadBuffer[Adapter->MediumHeaderSize],
63 Length - Adapter->MediumHeaderSize,
64 Total - Adapter->MediumHeaderSize);
66 MiniIndicateData(Adapter,
68 Adapter->LookaheadBuffer,
69 Adapter->MediumHeaderSize,
75 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
77 Adapter->LoopPacket = NULL;
79 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
81 return STATUS_SUCCESS;
87 IN NDIS_HANDLE MacBindingHandle,
88 IN PNDIS_REQUEST NdisRequest)
90 * FUNCTION: Forwards a request to an NDIS miniport
92 * MacBindingHandle = Adapter binding handle
93 * NdisRequest = Pointer to request to perform
100 NDIS_STATUS NdisStatus;
101 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
102 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
104 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
106 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
107 Queue = Adapter->MiniportBusy;
109 MiniQueueWorkItem(Adapter,
112 (NDIS_HANDLE)AdapterBinding);
114 Adapter->MiniportBusy = TRUE;
116 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
119 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
120 NdisStatus = MiniDoRequest(Adapter, NdisRequest);
121 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
122 Adapter->MiniportBusy = FALSE;
123 if (Adapter->WorkQueueHead)
124 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
125 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
126 KeLowerIrql(OldIrql);
128 NdisStatus = NDIS_STATUS_PENDING;
136 IN NDIS_HANDLE MacBindingHandle)
140 return NDIS_STATUS_FAILURE;
146 IN NDIS_HANDLE MacBindingHandle,
147 IN PNDIS_PACKET Packet)
149 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
151 * MacBindingHandle = Adapter binding handle
152 * Packet = Pointer to NDIS packet descriptor
157 NDIS_STATUS NdisStatus;
158 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
159 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
161 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
163 /* FIXME: Should queue packet if miniport returns NDIS_STATUS_RESOURCES */
165 Packet->Reserved[0] = (ULONG_PTR)MacBindingHandle;
167 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
168 Queue = Adapter->MiniportBusy;
170 /* We may have to loop this packet if miniport cannot */
171 if (Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) {
172 if (MiniAdapterHasAddress(Adapter, Packet)) {
173 /* Do software loopback because miniport does not support it */
175 NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
179 /* FIXME: Packets should properbly be queued directly on the adapter instead */
181 MiniQueueWorkItem(Adapter,
182 NdisWorkItemSendLoopback,
184 (NDIS_HANDLE)AdapterBinding);
186 Adapter->MiniportBusy = TRUE;
188 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
191 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
192 NdisStatus = ProIndicatePacket(Adapter, Packet);
193 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
194 Adapter->MiniportBusy = FALSE;
195 if (Adapter->WorkQueueHead)
196 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
197 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
198 KeLowerIrql(OldIrql);
201 return NDIS_STATUS_PENDING;
208 /* FIXME: Packets should properbly be queued directly on the adapter instead */
210 MiniQueueWorkItem(Adapter,
213 (NDIS_HANDLE)AdapterBinding);
215 Adapter->MiniportBusy = TRUE;
217 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
220 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
221 NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(
222 Adapter->NdisMiniportBlock.MiniportAdapterContext,
225 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
226 Adapter->MiniportBusy = FALSE;
227 if (Adapter->WorkQueueHead)
228 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
229 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
230 KeLowerIrql(OldIrql);
232 NdisStatus = NDIS_STATUS_PENDING;
240 IN NDIS_HANDLE NdisBindingHandle,
241 IN PPNDIS_PACKET PacketArray,
242 IN UINT NumberOfPackets)
250 IN NDIS_HANDLE MacBindingHandle,
251 IN NDIS_HANDLE MacReceiveContext,
253 IN UINT BytesToTransfer,
254 IN OUT PNDIS_PACKET Packet,
255 OUT PUINT BytesTransferred)
257 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
259 * MacBindingHandle = Adapter binding handle
260 * MacReceiveContext = MAC receive context
261 * ByteOffset = Offset in packet to place data
262 * BytesToTransfer = Number of bytes to copy into packet
263 * Packet = Pointer to NDIS packet descriptor
264 * BytesTransferred = Address of buffer to place number of bytes copied
267 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
268 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
270 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
272 /* FIXME: Interrupts must be disabled for adapter */
274 if (Packet == Adapter->LoopPacket) {
275 /* NDIS is responsible for looping this packet */
276 NdisCopyFromPacketToPacket(Packet,
282 return NDIS_STATUS_SUCCESS;
285 return (*Adapter->Miniport->Chars.u2.TransferDataHandler)(
288 Adapter->NdisMiniportBlock.MiniportAdapterContext,
299 OUT PNDIS_STATUS Status,
300 IN NDIS_HANDLE NdisBindingHandle)
302 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
304 * Status = Address of buffer for status information
305 * NdisBindingHandle = Handle returned by NdisOpenAdapter
309 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
311 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
313 /* Remove from protocol's bound adapters list */
314 KeAcquireSpinLock(&AdapterBinding->ProtocolBinding->Lock, &OldIrql);
315 RemoveEntryList(&AdapterBinding->ProtocolListEntry);
316 KeReleaseSpinLock(&AdapterBinding->ProtocolBinding->Lock, OldIrql);
318 /* Remove protocol from adapter's bound protocols list */
319 KeAcquireSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, &OldIrql);
320 RemoveEntryList(&AdapterBinding->AdapterListEntry);
321 KeReleaseSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, OldIrql);
323 ExFreePool(AdapterBinding);
325 *Status = NDIS_STATUS_SUCCESS;
331 NdisDeregisterProtocol(
332 OUT PNDIS_STATUS Status,
333 IN NDIS_HANDLE NdisProtocolHandle)
335 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
337 * Status = Address of buffer for status information
338 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
342 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
344 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
346 /* FIXME: Make sure no adapter bindings exist */
348 /* Remove protocol from global list */
349 KeAcquireSpinLock(&ProtocolListLock, &OldIrql);
350 RemoveEntryList(&Protocol->ListEntry);
351 KeReleaseSpinLock(&ProtocolListLock, OldIrql);
353 ExFreePool(Protocol);
355 *Status = NDIS_STATUS_SUCCESS;
362 OUT PNDIS_STATUS Status,
363 OUT PNDIS_STATUS OpenErrorStatus,
364 OUT PNDIS_HANDLE NdisBindingHandle,
365 OUT PUINT SelectedMediumIndex,
366 IN PNDIS_MEDIUM MediumArray,
367 IN UINT MediumArraySize,
368 IN NDIS_HANDLE NdisProtocolHandle,
369 IN NDIS_HANDLE ProtocolBindingContext,
370 IN PNDIS_STRING AdapterName,
372 IN PSTRING AddressingInformation OPTIONAL)
374 * FUNCTION: Opens an adapter for communication
376 * Status = Address of buffer for status information
377 * OpenErrorStatus = Address of buffer for secondary error code
378 * NdisBindingHandle = Address of buffer for adapter binding handle
379 * SelectedMediumIndex = Address of buffer for selected medium
380 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
381 * MediumArraySize = Number of elements in MediumArray
382 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
383 * ProtocolBindingContext = Pointer to caller suplied context area
384 * AdapterName = Pointer to buffer with name of adapter
385 * OpenOptions = Bitmask with flags passed to next-lower driver
386 * AddressingInformation = Optional pointer to buffer with NIC specific information
391 PLOGICAL_ADAPTER Adapter;
392 PADAPTER_BINDING AdapterBinding;
393 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
395 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
397 Adapter = MiniLocateDevice(AdapterName);
399 NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
400 *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
404 /* Find the media type in the list provided by the protocol driver */
406 for (i = 0; i < MediumArraySize; i++) {
407 if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i]) {
408 *SelectedMediumIndex = i;
415 NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
416 *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
420 AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
421 if (!AdapterBinding) {
422 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
423 *Status = NDIS_STATUS_RESOURCES;
427 RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
429 AdapterBinding->ProtocolBinding = Protocol;
430 AdapterBinding->Adapter = Adapter;
431 AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
433 /* Set fields required by some NDIS macros */
434 AdapterBinding->NdisOpenBlock.MacBindingHandle = (NDIS_HANDLE)AdapterBinding;
436 /* Set handlers (some NDIS macros require these) */
438 AdapterBinding->NdisOpenBlock.RequestHandler = ProRequest;
439 AdapterBinding->NdisOpenBlock.ResetHandler = ProReset;
440 AdapterBinding->NdisOpenBlock.u1.SendHandler = ProSend;
441 AdapterBinding->NdisOpenBlock.SendPacketsHandler = ProSendPackets;
442 AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
444 /* Put on protocol's bound adapters list */
445 ExInterlockedInsertTailList(&Protocol->AdapterListHead,
446 &AdapterBinding->ProtocolListEntry,
449 /* Put protocol on adapter's bound protocols list */
450 ExInterlockedInsertTailList(&Adapter->ProtocolListHead,
451 &AdapterBinding->AdapterListEntry,
452 &Adapter->NdisMiniportBlock.Lock);
454 *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
456 *Status = NDIS_STATUS_SUCCESS;
462 NdisRegisterProtocol(
463 OUT PNDIS_STATUS Status,
464 OUT PNDIS_HANDLE NdisProtocolHandle,
465 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
466 IN UINT CharacteristicsLength)
468 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
470 * Status = Address of buffer for status information
471 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
472 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
473 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
476 PPROTOCOL_BINDING Protocol;
480 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
482 switch (ProtocolCharacteristics->MajorNdisVersion) {
484 MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S);
488 MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S);
492 MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S);
496 *Status = NDIS_STATUS_BAD_VERSION;
500 if (CharacteristicsLength < MinSize) {
501 NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics.\n"));
502 *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
506 Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
508 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
509 *Status = NDIS_STATUS_RESOURCES;
513 RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
514 RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
516 NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name,
517 &ProtocolCharacteristics->Name,
519 if (!NT_SUCCESS(NtStatus)) {
520 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
521 ExFreePool(Protocol);
522 *Status = NDIS_STATUS_RESOURCES;
526 KeInitializeSpinLock(&Protocol->Lock);
528 Protocol->RefCount = 1;
530 InitializeListHead(&Protocol->AdapterListHead);
532 /* Put protocol binding on global list */
533 ExInterlockedInsertTailList(&ProtocolListHead,
534 &Protocol->ListEntry,
537 *NdisProtocolHandle = Protocol;
538 *Status = NDIS_STATUS_SUCCESS;
545 OUT PNDIS_STATUS Status,
546 IN NDIS_HANDLE NdisBindingHandle,
547 IN PNDIS_REQUEST NdisRequest)
549 * FUNCTION: Forwards a request to an NDIS driver
551 * Status = Address of buffer for status information
552 * NdisBindingHandle = Adapter binding handle
553 * NdisRequest = Pointer to request to perform
556 *Status = ProRequest(NdisBindingHandle, NdisRequest);
563 OUT PNDIS_STATUS Status,
564 IN NDIS_HANDLE NdisBindingHandle)
566 *Status = ProReset(NdisBindingHandle);
573 OUT PNDIS_STATUS Status,
574 IN NDIS_HANDLE NdisBindingHandle,
575 IN PNDIS_PACKET Packet)
577 * FUNCTION: Forwards a request to send a packet
579 * Status = Address of buffer for status information
580 * NdisBindingHandle = Adapter binding handle
581 * Packet = Pointer to NDIS packet descriptor
584 *Status = ProSend(NdisBindingHandle, Packet);
591 IN NDIS_HANDLE NdisBindingHandle,
592 IN PPNDIS_PACKET PacketArray,
593 IN UINT NumberOfPackets)
595 ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
602 OUT PNDIS_STATUS Status,
603 IN NDIS_HANDLE NdisBindingHandle,
604 IN NDIS_HANDLE MacReceiveContext,
606 IN UINT BytesToTransfer,
607 IN OUT PNDIS_PACKET Packet,
608 OUT PUINT BytesTransferred)
610 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
612 * Status = Address of buffer for status information
613 * NdisBindingHandle = Adapter binding handle
614 * MacReceiveContext = MAC receive context
615 * ByteOffset = Offset in packet to place data
616 * BytesToTransfer = Number of bytes to copy into packet
617 * Packet = Pointer to NDIS packet descriptor
618 * BytesTransferred = Address of buffer to place number of bytes copied
621 *Status = ProTransferData(NdisBindingHandle,