2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Local Area Network media routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
19 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
20 BOOLEAN ProtocolRegistered = FALSE;
21 LIST_ENTRY AdapterListHead;
22 KSPIN_LOCK AdapterListLock;
27 NDIS_REQUEST_TYPE Type,
32 * FUNCTION: Send a request to NDIS
34 * Adapter = Pointer to a LAN_ADAPTER structure
35 * Type = Type of request (Set or Query)
36 * OID = Value to be set/queried for
37 * Buffer = Pointer to a buffer to use
38 * Length = Number of bytes in Buffer
44 NDIS_STATUS NdisStatus;
46 Request.RequestType = Type;
47 if (Type == NdisRequestSetInformation) {
48 Request.DATA.SET_INFORMATION.Oid = OID;
49 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
50 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
52 Request.DATA.QUERY_INFORMATION.Oid = OID;
53 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
54 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
57 if (Adapter->State != LAN_STATE_RESETTING) {
58 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
60 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
63 /* Wait for NDIS to complete the request */
64 if (NdisStatus == NDIS_STATUS_PENDING) {
65 KeWaitForSingleObject(&Adapter->Event,
70 NdisStatus = Adapter->NdisStatus;
77 PNDIS_PACKET AllocateTDPacket(
80 * FUNCTION: Allocates an NDIS packet for NdisTransferData
82 * Adapter = Pointer to LAN_ADAPTER structure
84 * Pointer to NDIS packet or NULL if there was not enough free
88 NDIS_STATUS NdisStatus;
89 PNDIS_PACKET NdisPacket;
93 NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
94 if (NdisStatus != NDIS_STATUS_SUCCESS)
97 Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
99 NdisFreePacket(NdisPacket);
103 NdisAllocateBuffer(&NdisStatus,
108 if (NdisStatus != NDIS_STATUS_SUCCESS) {
109 NdisFreePacket(NdisPacket);
114 NdisChainBufferAtFront(NdisPacket, Buffer);
116 PC(NdisPacket)->Context = NULL; /* End of list */
123 PLAN_ADAPTER Adapter)
125 * FUNCTION: Frees transfer data packets
127 * Adapter = Pointer to LAN_ADAPTER structure
130 PNDIS_PACKET NdisPacket, Next;
132 /* Release transfer data packets */
133 NdisPacket = Adapter->TDPackets;
135 Next = PC(NdisPacket)->Context;
136 FreeNdisPacket(NdisPacket);
139 Adapter->TDPackets = NULL;
144 PLAN_ADAPTER Adapter)
146 * FUNCTION: Frees memory for a LAN_ADAPTER structure
148 * Adapter = Pointer to LAN_ADAPTER structure to free
151 FreeTDPackets(Adapter);
156 VOID ProtocolOpenAdapterComplete(
157 NDIS_HANDLE BindingContext,
159 NDIS_STATUS OpenErrorStatus)
161 * FUNCTION: Called by NDIS to complete opening of an adapter
163 * BindingContext = Pointer to a device context (LAN_ADAPTER)
164 * Status = Status of the operation
165 * OpenErrorStatus = Additional status information
168 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
170 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
172 KeSetEvent(&Adapter->Event, 0, FALSE);
176 VOID ProtocolCloseAdapterComplete(
177 NDIS_HANDLE BindingContext,
180 * FUNCTION: Called by NDIS to complete closing an adapter
182 * BindingContext = Pointer to a device context (LAN_ADAPTER)
183 * Status = Status of the operation
186 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
188 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
190 Adapter->NdisStatus = Status;
192 KeSetEvent(&Adapter->Event, 0, FALSE);
196 VOID ProtocolResetComplete(
197 NDIS_HANDLE BindingContext,
200 * FUNCTION: Called by NDIS to complete resetting an adapter
202 * BindingContext = Pointer to a device context (LAN_ADAPTER)
203 * Status = Status of the operation
206 TI_DbgPrint(MID_TRACE, ("Called.\n"));
210 VOID ProtocolRequestComplete(
211 NDIS_HANDLE BindingContext,
212 PNDIS_REQUEST NdisRequest,
215 * FUNCTION: Called by NDIS to complete a request
217 * BindingContext = Pointer to a device context (LAN_ADAPTER)
218 * NdisRequest = Pointer to an object describing the request
219 * Status = Status of the operation
222 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
224 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
226 /* Save status of request and signal an event */
227 Adapter->NdisStatus = Status;
229 KeSetEvent(&Adapter->Event, 0, FALSE);
233 VOID ProtocolSendComplete(
234 NDIS_HANDLE BindingContext,
238 * FUNCTION: Called by NDIS to complete sending process
240 * BindingContext = Pointer to a device context (LAN_ADAPTER)
241 * Packet = Pointer to a packet descriptor
242 * Status = Status of the operation
245 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
247 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
249 AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
251 (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
255 VOID ProtocolTransferDataComplete(
256 NDIS_HANDLE BindingContext,
259 UINT BytesTransferred)
261 * FUNCTION: Called by NDIS to complete reception of data
263 * BindingContext = Pointer to a device context (LAN_ADAPTER)
264 * Packet = Pointer to a packet descriptor
265 * Status = Status of the operation
266 * BytesTransferred = Number of bytes transferred
268 * If the packet was successfully received, determine the protocol
269 * type and pass it to the correct receive handler
273 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
275 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
277 if (Status == NDIS_STATUS_SUCCESS) {
278 PNDIS_BUFFER NdisBuffer;
281 IPPacket.NdisPacket = Packet;
283 NdisGetFirstBufferFromPacket(Packet,
286 &IPPacket.ContigSize,
287 &IPPacket.TotalSize);
289 /* Determine which upper layer protocol that should receive
290 this packet and pass it to the correct receive handler */
291 PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
292 switch (PacketType) {
295 IPReceive(Adapter->Context, &IPPacket);
298 ARPReceive(Adapter->Context, &IPPacket);
304 /* Release the packet descriptor */
305 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
307 PC(Packet)->Context = Adapter->TDPackets;
308 Adapter->TDPackets = Packet;
310 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
314 NDIS_STATUS ProtocolReceive(
315 NDIS_HANDLE BindingContext,
316 NDIS_HANDLE MacReceiveContext,
318 UINT HeaderBufferSize,
319 PVOID LookaheadBuffer,
320 UINT LookaheadBufferSize,
323 * FUNCTION: Called by NDIS when a packet has been received on the physical link
325 * BindingContext = Pointer to a device context (LAN_ADAPTER)
326 * MacReceiveContext = Handle used by underlying NIC driver
327 * HeaderBuffer = Pointer to a buffer containing the packet header
328 * HeaderBufferSize = Number of bytes in HeaderBuffer
329 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
330 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
331 * PacketSize = Overall size of the packet (not including header)
333 * Status of operation
339 PNDIS_PACKET NdisPacket;
340 PNDIS_BUFFER NdisBuffer;
341 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
342 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
344 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
346 if (Adapter->State != LAN_STATE_STARTED) {
347 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
348 return NDIS_STATUS_NOT_ACCEPTED;
351 if (HeaderBufferSize < Adapter->HeaderSize) {
352 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
353 return NDIS_STATUS_NOT_ACCEPTED;
356 if (Adapter->Media == NdisMedium802_3) {
357 /* Ethernet and IEEE 802.3 frames can be destinguished by
358 looking at the IEEE 802.3 length field. This field is
359 less than or equal to 1500 for a valid IEEE 802.3 frame
360 and larger than 1500 is it's a valid EtherType value.
361 See RFC 1122, section 2.3.3 for more information */
362 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
363 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
364 TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
365 return NDIS_STATUS_NOT_ACCEPTED;
367 /* We use EtherType constants to destinguish packet types */
370 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
371 /* FIXME: Support other medias */
372 return NDIS_STATUS_NOT_ACCEPTED;
375 /* Get a transfer data packet */
377 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
379 NdisPacket = Adapter->TDPackets;
380 if (NdisPacket == (PNDIS_PACKET)NULL) {
381 TI_DbgPrint(DEBUG_DATALINK, ("No available packet descriptors.\n"));
382 /* We don't have a free packet descriptor. Drop the packet */
383 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
384 return NDIS_STATUS_SUCCESS;
386 Adapter->TDPackets = PC(NdisPacket)->Context;
388 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
390 if (LookaheadBufferSize < PacketSize) {
391 NDIS_STATUS NdisStatus;
392 UINT BytesTransferred;
395 NdisTransferData(&NdisStatus,
402 if (NdisStatus != NDIS_STATUS_PENDING)
403 ProtocolTransferDataComplete(BindingContext,
408 return NDIS_STATUS_SUCCESS;
411 /* We got all the data in the lookahead buffer */
413 IPPacket.NdisPacket = NdisPacket;
415 NdisGetFirstBufferFromPacket(NdisPacket,
418 &IPPacket.ContigSize,
419 &IPPacket.TotalSize);
421 RtlCopyMemory(IPPacket.Header, LookaheadBuffer, PacketSize);
423 switch (PacketType) {
426 IPReceive(Adapter->Context, &IPPacket);
429 ARPReceive(Adapter->Context, &IPPacket);
435 /* Release the packet descriptor */
436 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
438 PC(NdisPacket)->Context = Adapter->TDPackets;
439 Adapter->TDPackets = NdisPacket;
441 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
443 return NDIS_STATUS_SUCCESS;
447 VOID ProtocolReceiveComplete(
448 NDIS_HANDLE BindingContext)
450 * FUNCTION: Called by NDIS when we're done receiving data
452 * BindingContext = Pointer to a device context (LAN_ADAPTER)
455 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
460 NDIS_HANDLE BindingContext,
461 NDIS_STATUS GenerelStatus,
463 UINT StatusBufferSize)
465 * FUNCTION: Called by NDIS when the underlying driver has changed state
467 * BindingContext = Pointer to a device context (LAN_ADAPTER)
468 * GenerelStatus = A generel status code
469 * StatusBuffer = Pointer to a buffer with medium-specific data
470 * StatusBufferSize = Number of bytes in StatusBuffer
473 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
477 VOID ProtocolStatusComplete(
478 NDIS_HANDLE NdisBindingContext)
480 * FUNCTION: Called by NDIS when a status-change has occurred
482 * BindingContext = Pointer to a device context (LAN_ADAPTER)
485 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
491 PNDIS_PACKET NdisPacket,
496 * FUNCTION: Transmits a packet
498 * Context = Pointer to context information (LAN_ADAPTER)
499 * NdisPacket = Pointer to NDIS packet to send
500 * Offset = Offset in packet where data starts
501 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
502 * Type = LAN protocol type (LAN_PROTO_*)
505 NDIS_STATUS NdisStatus;
508 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
510 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
512 /* NDIS send routines don't have an offset argument so we
513 must offset the data in upper layers and adjust the
514 packet here. We save the offset in the packet context
515 area so it can be undone before we release the packet */
516 Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
517 PC(NdisPacket)->DLOffset = Offset;
519 if (Adapter->State == LAN_STATE_STARTED) {
520 switch (Adapter->Media) {
521 case NdisMedium802_3:
522 EHeader = (PETH_HEADER)Data;
525 /* Unicast address */
526 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
528 /* Broadcast address */
529 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
532 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
536 EHeader->EType = ETYPE_IPv4;
539 EHeader->EType = ETYPE_ARP;
542 EHeader->EType = ETYPE_IPv6;
546 /* Should not happen */
547 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
549 ProtocolSendComplete((NDIS_HANDLE)Context,
551 NDIS_STATUS_FAILURE);
558 /* FIXME: Support other medias */
562 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
563 if (NdisStatus != NDIS_STATUS_PENDING)
564 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
566 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
572 PLAN_ADAPTER Adapter)
574 * FUNCTION: Binds a LAN adapter to IP layer
576 * Adapter = Pointer to LAN_ADAPTER structure
578 * We set the lookahead buffer size, set the packet filter and
579 * bind the adapter to IP layer
586 NDIS_STATUS NdisStatus;
587 LLIP_BIND_INFO BindInfo;
588 ULONG Lookahead = LOOKAHEAD_SIZE;
590 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
592 Adapter->State = LAN_STATE_OPENING;
594 NdisStatus = NDISCall(Adapter,
595 NdisRequestSetInformation,
596 OID_GEN_CURRENT_LOOKAHEAD,
599 if (NdisStatus != NDIS_STATUS_SUCCESS) {
600 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
604 /* Allocate packets for NdisTransferData */
605 /* FIXME: How many should we allocate? */
606 Adapter->TDPackets = NULL;
607 for (i = 0; i < 2; i++) {
608 Packet = AllocateTDPacket(Adapter);
609 PC(Packet)->Context = Adapter->TDPackets;
610 Adapter->TDPackets = Packet;
612 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
613 FreeTDPackets(Adapter);
618 /* Bind the adapter to IP layer */
619 BindInfo.Context = Adapter;
620 BindInfo.HeaderSize = Adapter->HeaderSize;
621 BindInfo.MinFrameSize = Adapter->MinFrameSize;
622 BindInfo.MTU = Adapter->MTU;
623 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
624 BindInfo.AddressLength = Adapter->HWAddressLength;
625 BindInfo.Transmit = LANTransmit;
627 IF = IPCreateInterface(&BindInfo);
629 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
630 FreeTDPackets(Adapter);
634 /* FIXME: Get address from registry.
635 For now just use a private address, eg. 10.0.0.100 */
636 Address = AddrBuildIPv4(0x6400000A);
638 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
639 FreeTDPackets(Adapter);
640 IPDestroyInterface(Adapter->Context);
643 /* Create a net table entry for this interface */
644 if (!IPCreateNTE(IF, Address, 8)) {
645 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
646 FreeTDPackets(Adapter);
647 IPDestroyInterface(IF);
651 /* Reference the interface for the NTE. The reference
652 for the address is just passed on to the NTE */
655 /* Register interface with IP layer */
656 IPRegisterInterface(IF);
658 /* Set packet filter so we can send and receive packets */
659 NdisStatus = NDISCall(Adapter,
660 NdisRequestSetInformation,
661 OID_GEN_CURRENT_PACKET_FILTER,
662 &Adapter->PacketFilter,
664 if (NdisStatus != NDIS_STATUS_SUCCESS) {
665 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
666 FreeTDPackets(Adapter);
667 IPDestroyInterface(IF);
671 Adapter->Context = IF;
673 Adapter->State = LAN_STATE_STARTED;
678 PLAN_ADAPTER Adapter)
680 * FUNCTION: Unbinds a LAN adapter from IP layer
682 * Adapter = Pointer to LAN_ADAPTER structure
685 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
687 if (Adapter->State == LAN_STATE_STARTED) {
688 PIP_INTERFACE IF = Adapter->Context;
690 IPUnregisterInterface(IF);
692 IPDestroyInterface(IF);
694 /* Free transfer data packets */
695 FreeTDPackets(Adapter);
700 NDIS_STATUS LANRegisterAdapter(
701 PNDIS_STRING AdapterName,
702 PLAN_ADAPTER *Adapter)
704 * FUNCTION: Registers protocol with an NDIS adapter
706 * AdapterName = Pointer to string with name of adapter to register
707 * Adapter = Address of pointer to a LAN_ADAPTER structure
709 * Status of operation
713 NDIS_STATUS NdisStatus;
714 NDIS_STATUS OpenStatus;
716 NDIS_MEDIUM MediaArray[MAX_MEDIA];
720 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
722 IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
724 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
725 return NDIS_STATUS_RESOURCES;
728 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
730 /* Put adapter in stopped state */
731 IF->State = LAN_STATE_STOPPED;
733 /* Initialize protecting spin lock */
734 KeInitializeSpinLock(&IF->Lock);
736 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
738 /* Initialize array with media IDs we support */
739 MediaArray[MEDIA_ETH] = NdisMedium802_3;
741 /* Open the adapter. */
742 NdisOpenAdapter(&NdisStatus,
754 /* Wait until the adapter is opened */
755 if (NdisStatus == NDIS_STATUS_PENDING)
756 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
757 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
762 IF->Media = MediaArray[MediaIndex];
764 /* Fill LAN_ADAPTER structure with some adapter specific information */
766 case NdisMedium802_3:
767 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
768 IF->BCastMask = BCAST_ETH_MASK;
769 IF->BCastCheck = BCAST_ETH_CHECK;
770 IF->BCastOffset = BCAST_ETH_OFFSET;
771 IF->HeaderSize = sizeof(ETH_HEADER);
772 IF->MinFrameSize = 60;
773 AddressOID = OID_802_3_CURRENT_ADDRESS;
775 NDIS_PACKET_TYPE_BROADCAST |
776 NDIS_PACKET_TYPE_DIRECTED |
777 NDIS_PACKET_TYPE_MULTICAST;
781 /* Unsupported media */
782 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
784 return NDIS_STATUS_NOT_SUPPORTED;
787 /* Get maximum frame size */
788 NdisStatus = NDISCall(IF,
789 NdisRequestQueryInformation,
790 OID_GEN_MAXIMUM_FRAME_SIZE,
793 if (NdisStatus != NDIS_STATUS_SUCCESS) {
798 /* Get maximum packet size */
799 NdisStatus = NDISCall(IF,
800 NdisRequestQueryInformation,
801 OID_GEN_MAXIMUM_TOTAL_SIZE,
804 if (NdisStatus != NDIS_STATUS_SUCCESS) {
805 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
810 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
811 NdisStatus = NDISCall(IF,
812 NdisRequestQueryInformation,
813 OID_GEN_MAXIMUM_SEND_PACKETS,
816 if (NdisStatus != NDIS_STATUS_SUCCESS)
817 /* Legacy NIC drivers may not support this query, if it fails we
818 assume it can send at least one packet per call to NdisSend(Packets) */
819 IF->MaxSendPackets = 1;
821 /* Get current hardware address */
822 NdisStatus = NDISCall(IF,
823 NdisRequestQueryInformation,
826 IF->HWAddressLength);
827 if (NdisStatus != NDIS_STATUS_SUCCESS) {
828 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
833 /* Get maximum link speed */
834 NdisStatus = NDISCall(IF,
835 NdisRequestQueryInformation,
839 if (NdisStatus != NDIS_STATUS_SUCCESS) {
840 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
845 /* Convert returned link speed to bps (it is in 100bps increments) */
846 IF->Speed = Speed * 100L;
850 /* Add adapter to the adapter list */
851 ExInterlockedInsertTailList(&AdapterListHead,
855 /* Bind adapter to IP layer */
858 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
860 return NDIS_STATUS_SUCCESS;
864 NDIS_STATUS LANUnregisterAdapter(
865 PLAN_ADAPTER Adapter)
867 * FUNCTION: Unregisters protocol with NDIS adapter
869 * Adapter = Pointer to a LAN_ADAPTER structure
871 * Status of operation
875 NDIS_HANDLE NdisHandle;
876 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
878 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
880 /* Unlink the adapter from the list */
881 RemoveEntryList(&Adapter->ListEntry);
883 /* Unbind adapter from IP layer */
884 UnbindAdapter(Adapter);
886 KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
887 NdisHandle = Adapter->NdisHandle;
889 Adapter->NdisHandle = NULL;
890 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
892 NdisCloseAdapter(&NdisStatus, NdisHandle);
893 if (NdisStatus == NDIS_STATUS_PENDING) {
894 KeWaitForSingleObject(&Adapter->Event,
899 NdisStatus = Adapter->NdisStatus;
902 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
904 FreeAdapter(Adapter);
906 return NDIS_STATUS_SUCCESS;
910 NTSTATUS LANRegisterProtocol(
913 * FUNCTION: Registers this protocol driver with NDIS
915 * Name = Name of this protocol driver
917 * Status of operation
920 NDIS_STATUS NdisStatus;
921 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
923 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
925 InitializeListHead(&AdapterListHead);
926 KeInitializeSpinLock(&AdapterListLock);
928 /* Set up protocol characteristics */
929 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
930 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
931 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
932 ProtChars.Name.Length = Name->Length;
933 ProtChars.Name.Buffer = (PVOID)Name->Buffer;
934 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
935 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
936 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
937 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
938 ProtChars.u2.SendCompleteHandler = ProtocolSendComplete;
939 ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete;
940 ProtChars.u4.ReceiveHandler = ProtocolReceive;
941 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
942 ProtChars.StatusHandler = ProtocolStatus;
943 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
945 /* Try to register protocol */
946 NdisRegisterProtocol(&NdisStatus,
949 sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);
950 if (NdisStatus != NDIS_STATUS_SUCCESS)
951 return (NTSTATUS)NdisStatus;
953 ProtocolRegistered = TRUE;
955 return STATUS_SUCCESS;
959 VOID LANUnregisterProtocol(
962 * FUNCTION: Unregisters this protocol driver with NDIS
963 * NOTES: Does not care wether we are already registered
966 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
968 if (ProtocolRegistered) {
969 NDIS_STATUS NdisStatus;
970 PLIST_ENTRY CurrentEntry;
971 PLIST_ENTRY NextEntry;
972 PLAN_ADAPTER Current;
975 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
977 /* Search the list and remove every adapter we find */
978 CurrentEntry = AdapterListHead.Flink;
979 while (CurrentEntry != &AdapterListHead) {
980 NextEntry = CurrentEntry->Flink;
981 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
983 LANUnregisterAdapter(Current);
984 CurrentEntry = NextEntry;
987 KeReleaseSpinLock(&AdapterListLock, OldIrql);
989 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
990 ProtocolRegistered = FALSE;