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
13 /* Define this to bugcheck on double complete */
14 /* #define BREAK_ON_DOUBLE_COMPLETE */
16 UINT TransferDataCalled
= 0;
17 UINT TransferDataCompleteCalled
= 0;
18 UINT LanReceiveWorkerCalled
= 0;
19 BOOLEAN LanReceiveWorkerBusy
= FALSE
;
21 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
22 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
24 #define NGFP(_Packet) \
27 ULONG _ContigSize, _TotalSize; \
28 PNDIS_BUFFER _NdisBuffer; \
30 TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
31 NdisGetFirstBufferFromPacket(_Packet, \
36 TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
37 TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
38 TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
39 TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
42 typedef struct _LAN_WQ_ITEM
{
46 UINT BytesTransferred
;
47 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
49 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
50 BOOLEAN ProtocolRegistered
= FALSE
;
51 LIST_ENTRY AdapterListHead
;
52 KSPIN_LOCK AdapterListLock
;
54 /* Double complete protection */
55 KSPIN_LOCK LanSendCompleteLock
;
56 LIST_ENTRY LanSendCompleteList
;
58 VOID
LanChainCompletion( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
59 PLAN_WQ_ITEM PendingCompletion
=
60 ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
62 if( !PendingCompletion
) return;
64 PendingCompletion
->Packet
= NdisPacket
;
65 PendingCompletion
->Adapter
= Adapter
;
67 ExInterlockedInsertTailList( &LanSendCompleteList
,
68 &PendingCompletion
->ListEntry
,
69 &LanSendCompleteLock
);
72 BOOLEAN
LanShouldComplete( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
73 PLIST_ENTRY ListEntry
;
74 PLAN_WQ_ITEM CompleteEntry
;
77 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
78 for( ListEntry
= LanSendCompleteList
.Flink
;
79 ListEntry
!= &LanSendCompleteList
;
80 ListEntry
= ListEntry
->Flink
) {
81 CompleteEntry
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
83 if( CompleteEntry
->Adapter
== Adapter
&&
84 CompleteEntry
->Packet
== NdisPacket
) {
85 RemoveEntryList( ListEntry
);
86 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
87 ExFreePool( CompleteEntry
);
91 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
93 DbgPrint("NDIS completed the same send packet twice "
94 "(Adapter %x Packet %x)!!\n", Adapter
, NdisPacket
);
95 #ifdef BREAK_ON_DOUBLE_COMPLETE
102 NDIS_STATUS
NDISCall(
103 PLAN_ADAPTER Adapter
,
104 NDIS_REQUEST_TYPE Type
,
109 * FUNCTION: Send a request to NDIS
111 * Adapter = Pointer to a LAN_ADAPTER structure
112 * Type = Type of request (Set or Query)
113 * OID = Value to be set/queried for
114 * Buffer = Pointer to a buffer to use
115 * Length = Number of bytes in Buffer
117 * Status of operation
120 NDIS_REQUEST Request
;
121 NDIS_STATUS NdisStatus
;
123 Request
.RequestType
= Type
;
124 if (Type
== NdisRequestSetInformation
) {
125 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
126 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
127 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
129 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
130 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
131 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
134 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
135 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
137 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
140 /* Wait for NDIS to complete the request */
141 if (NdisStatus
== NDIS_STATUS_PENDING
) {
142 KeWaitForSingleObject(&Adapter
->Event
,
147 NdisStatus
= Adapter
->NdisStatus
;
155 PLAN_ADAPTER Adapter
)
157 * FUNCTION: Frees memory for a LAN_ADAPTER structure
159 * Adapter = Pointer to LAN_ADAPTER structure to free
166 NTSTATUS TcpipLanGetDwordOid
167 ( PIP_INTERFACE Interface
,
170 /* Get maximum frame size */
171 if( Interface
->Context
) {
172 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
173 NdisRequestQueryInformation
,
177 } else switch( Oid
) { /* Loopback Case */
178 case OID_GEN_HARDWARE_STATUS
:
179 *Result
= NdisHardwareStatusReady
;
180 return STATUS_SUCCESS
;
183 return STATUS_INVALID_PARAMETER
;
188 VOID STDCALL
ProtocolOpenAdapterComplete(
189 NDIS_HANDLE BindingContext
,
191 NDIS_STATUS OpenErrorStatus
)
193 * FUNCTION: Called by NDIS to complete opening of an adapter
195 * BindingContext = Pointer to a device context (LAN_ADAPTER)
196 * Status = Status of the operation
197 * OpenErrorStatus = Additional status information
200 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
202 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
204 Adapter
->NdisStatus
= Status
;
206 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
210 VOID STDCALL
ProtocolCloseAdapterComplete(
211 NDIS_HANDLE BindingContext
,
214 * FUNCTION: Called by NDIS to complete closing an adapter
216 * BindingContext = Pointer to a device context (LAN_ADAPTER)
217 * Status = Status of the operation
220 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
222 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
224 Adapter
->NdisStatus
= Status
;
226 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
230 VOID STDCALL
ProtocolResetComplete(
231 NDIS_HANDLE BindingContext
,
234 * FUNCTION: Called by NDIS to complete resetting an adapter
236 * BindingContext = Pointer to a device context (LAN_ADAPTER)
237 * Status = Status of the operation
240 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
242 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
244 Adapter
->NdisStatus
= Status
;
246 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
250 VOID STDCALL
ProtocolRequestComplete(
251 NDIS_HANDLE BindingContext
,
252 PNDIS_REQUEST NdisRequest
,
255 * FUNCTION: Called by NDIS to complete a request
257 * BindingContext = Pointer to a device context (LAN_ADAPTER)
258 * NdisRequest = Pointer to an object describing the request
259 * Status = Status of the operation
262 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
264 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
266 /* Save status of request and signal an event */
267 Adapter
->NdisStatus
= Status
;
269 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
273 VOID STDCALL
ProtocolSendComplete(
274 NDIS_HANDLE BindingContext
,
278 * FUNCTION: Called by NDIS to complete sending process
280 * BindingContext = Pointer to a device context (LAN_ADAPTER)
281 * Packet = Pointer to a packet descriptor
282 * Status = Status of the operation
285 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
286 if( LanShouldComplete( (PLAN_ADAPTER
)BindingContext
, Packet
) ) {
287 ASSERT_KM_POINTER(Packet
);
288 ASSERT_KM_POINTER(PC(Packet
));
289 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
290 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
291 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
295 VOID
LanReceiveWorker( PVOID Context
) {
297 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
299 PLAN_ADAPTER Adapter
;
300 UINT BytesTransferred
;
301 PNDIS_BUFFER NdisBuffer
;
304 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
306 Packet
= WorkItem
->Packet
;
307 Adapter
= WorkItem
->Adapter
;
308 BytesTransferred
= WorkItem
->BytesTransferred
;
310 IPPacket
.NdisPacket
= Packet
;
312 NdisGetFirstBufferFromPacket(Packet
,
315 &IPPacket
.ContigSize
,
316 &IPPacket
.TotalSize
);
318 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
319 /* Determine which upper layer protocol that should receive
320 this packet and pass it to the correct receive handler */
322 TI_DbgPrint(MID_TRACE
,
323 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
324 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
327 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
328 IPPacket
.Position
= 0;
332 ("Ether Type = %x ContigSize = %d Total = %d\n",
333 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
335 switch (PacketType
) {
338 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
339 IPReceive(Adapter
->Context
, &IPPacket
);
342 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
343 ARPReceive(Adapter
->Context
, &IPPacket
);
348 FreeNdisPacket( Packet
);
351 VOID
LanSubmitReceiveWork(
352 NDIS_HANDLE BindingContext
,
355 UINT BytesTransferred
) {
357 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
360 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
362 WQItem
.Packet
= Packet
;
363 WQItem
.Adapter
= Adapter
;
364 WQItem
.BytesTransferred
= BytesTransferred
;
367 ( &LanWorkItem
, sizeof(LAN_WQ_ITEM
), LanReceiveWorker
, &WQItem
) )
371 VOID STDCALL
ProtocolTransferDataComplete(
372 NDIS_HANDLE BindingContext
,
375 UINT BytesTransferred
)
377 * FUNCTION: Called by NDIS to complete reception of data
379 * BindingContext = Pointer to a device context (LAN_ADAPTER)
380 * Packet = Pointer to a packet descriptor
381 * Status = Status of the operation
382 * BytesTransferred = Number of bytes transferred
384 * If the packet was successfully received, determine the protocol
385 * type and pass it to the correct receive handler
388 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
390 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
392 TransferDataCompleteCalled
++;
393 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
395 if( Status
!= NDIS_STATUS_SUCCESS
) return;
397 LanSubmitReceiveWork( BindingContext
, Packet
, Status
, BytesTransferred
);
400 NDIS_STATUS STDCALL
ProtocolReceive(
401 NDIS_HANDLE BindingContext
,
402 NDIS_HANDLE MacReceiveContext
,
404 UINT HeaderBufferSize
,
405 PVOID LookaheadBuffer
,
406 UINT LookaheadBufferSize
,
409 * FUNCTION: Called by NDIS when a packet has been received on the physical link
411 * BindingContext = Pointer to a device context (LAN_ADAPTER)
412 * MacReceiveContext = Handle used by underlying NIC driver
413 * HeaderBuffer = Pointer to a buffer containing the packet header
414 * HeaderBufferSize = Number of bytes in HeaderBuffer
415 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
416 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
417 * PacketSize = Overall size of the packet (not including header)
419 * Status of operation
423 UINT PacketType
, BytesTransferred
;
427 NDIS_STATUS NdisStatus
;
428 PNDIS_PACKET NdisPacket
;
429 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
430 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
432 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
434 if (Adapter
->State
!= LAN_STATE_STARTED
) {
435 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
436 return NDIS_STATUS_NOT_ACCEPTED
;
439 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
440 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
441 return NDIS_STATUS_NOT_ACCEPTED
;
444 if (Adapter
->Media
== NdisMedium802_3
) {
445 /* Ethernet and IEEE 802.3 frames can be destinguished by
446 looking at the IEEE 802.3 length field. This field is
447 less than or equal to 1500 for a valid IEEE 802.3 frame
448 and larger than 1500 is it's a valid EtherType value.
449 See RFC 1122, section 2.3.3 for more information */
450 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
451 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
452 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
453 return NDIS_STATUS_NOT_ACCEPTED
;
455 /* We use EtherType constants to destinguish packet types */
458 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
459 /* FIXME: Support other medias */
460 return NDIS_STATUS_NOT_ACCEPTED
;
463 /* Get a transfer data packet */
465 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
466 Adapter
, Adapter
->MTU
));
468 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
469 PacketSize
+ HeaderBufferSize
);
470 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
471 return NDIS_STATUS_NOT_ACCEPTED
;
474 PC(NdisPacket
)->PacketType
= PacketType
;
476 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
478 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
480 IPPacket
.NdisPacket
= NdisPacket
;
481 IPPacket
.Position
= 0;
483 TransferDataCalled
++;
485 if (LookaheadBufferSize
== PacketSize
)
487 /* Optimized code path for packets that are fully contained in
488 * the lookahead buffer. */
489 NdisCopyLookaheadData(BufferData
,
492 Adapter
->MacOptions
);
496 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
497 MacReceiveContext
, 0, PacketSize
,
498 NdisPacket
, &BytesTransferred
);
500 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
502 if (NdisStatus
!= NDIS_STATUS_PENDING
)
503 ProtocolTransferDataComplete(BindingContext
,
508 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
510 return NDIS_STATUS_SUCCESS
;
514 VOID STDCALL
ProtocolReceiveComplete(
515 NDIS_HANDLE BindingContext
)
517 * FUNCTION: Called by NDIS when we're done receiving data
519 * BindingContext = Pointer to a device context (LAN_ADAPTER)
522 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
526 VOID STDCALL
ProtocolStatus(
527 NDIS_HANDLE BindingContext
,
528 NDIS_STATUS GeneralStatus
,
530 UINT StatusBufferSize
)
532 * FUNCTION: Called by NDIS when the underlying driver has changed state
534 * BindingContext = Pointer to a device context (LAN_ADAPTER)
535 * GeneralStatus = A general status code
536 * StatusBuffer = Pointer to a buffer with medium-specific data
537 * StatusBufferSize = Number of bytes in StatusBuffer
540 PLAN_ADAPTER Adapter
= BindingContext
;
542 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
544 switch(GeneralStatus
)
546 case NDIS_STATUS_MEDIA_CONNECT
:
547 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
550 case NDIS_STATUS_MEDIA_DISCONNECT
:
551 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
554 case NDIS_STATUS_RESET_START
:
555 Adapter
->State
= LAN_STATE_RESETTING
;
558 case NDIS_STATUS_RESET_END
:
559 Adapter
->State
= LAN_STATE_STARTED
;
563 DbgPrint("Unhandled status: %x", GeneralStatus
);
569 VOID STDCALL
ProtocolStatusComplete(
570 NDIS_HANDLE NdisBindingContext
)
572 * FUNCTION: Called by NDIS when a status-change has occurred
574 * BindingContext = Pointer to a device context (LAN_ADAPTER)
577 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
580 VOID STDCALL
ProtocolBindAdapter(
581 OUT PNDIS_STATUS Status
,
582 IN NDIS_HANDLE BindContext
,
583 IN PNDIS_STRING DeviceName
,
584 IN PVOID SystemSpecific1
,
585 IN PVOID SystemSpecific2
)
587 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
588 * bindings, and periodically thereafer as new adapters come online
590 * Status: Return value to NDIS
591 * BindContext: Handle provided by NDIS to track pending binding operations
592 * DeviceName: Name of the miniport device to bind to
593 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
594 * SystemSpecific2: Unused & must not be touched
597 /* XXX confirm that this is still true, or re-word the following comment */
598 /* we get to ignore BindContext because we will never pend an operation with NDIS */
599 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
600 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
606 PNDIS_PACKET NdisPacket
,
611 * FUNCTION: Transmits a packet
613 * Context = Pointer to context information (LAN_ADAPTER)
614 * NdisPacket = Pointer to NDIS packet to send
615 * Offset = Offset in packet where data starts
616 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
617 * Type = LAN protocol type (LAN_PROTO_*)
620 NDIS_STATUS NdisStatus
;
624 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
627 TI_DbgPrint(DEBUG_DATALINK
,
628 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
629 NdisPacket
, Offset
, Adapter
));
631 TI_DbgPrint(DEBUG_DATALINK
,
632 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
633 Adapter
->HWAddress
[0] & 0xff,
634 Adapter
->HWAddress
[1] & 0xff,
635 Adapter
->HWAddress
[2] & 0xff,
636 Adapter
->HWAddress
[3] & 0xff,
637 Adapter
->HWAddress
[4] & 0xff,
638 Adapter
->HWAddress
[5] & 0xff));
640 /* XXX arty -- Handled adjustment in a saner way than before ...
641 * not needed immediately */
642 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
644 LanChainCompletion( Adapter
, NdisPacket
);
646 if (Adapter
->State
== LAN_STATE_STARTED
) {
647 switch (Adapter
->Media
) {
648 case NdisMedium802_3
:
649 EHeader
= (PETH_HEADER
)Data
;
652 /* Unicast address */
653 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
655 /* Broadcast address */
656 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
659 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
663 EHeader
->EType
= ETYPE_IPv4
;
666 EHeader
->EType
= ETYPE_ARP
;
669 EHeader
->EType
= ETYPE_IPv6
;
673 /* Should not happen */
674 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
676 ProtocolSendComplete((NDIS_HANDLE
)Context
,
678 NDIS_STATUS_FAILURE
);
685 /* FIXME: Support other medias */
689 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
693 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
694 ((PCHAR
)LinkAddress
)[0] & 0xff,
695 ((PCHAR
)LinkAddress
)[1] & 0xff,
696 ((PCHAR
)LinkAddress
)[2] & 0xff,
697 ((PCHAR
)LinkAddress
)[3] & 0xff,
698 ((PCHAR
)LinkAddress
)[4] & 0xff,
699 ((PCHAR
)LinkAddress
)[5] & 0xff));
702 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
703 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
704 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
705 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
706 NdisStatus
== NDIS_STATUS_PENDING
?
707 "Pending" : "Complete"));
708 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
710 /* I had a talk with vizzini: these really ought to be here.
711 * we're supposed to see these completed by ndis *only* when
712 * status_pending is returned. Note that this is different from
713 * the situation with IRPs. */
714 if (NdisStatus
!= NDIS_STATUS_PENDING
)
715 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
717 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
722 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
723 OBJECT_ATTRIBUTES Attributes
;
726 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
727 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
731 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
732 PWCHAR RegistryValue
,
733 PUNICODE_STRING String
) {
734 UNICODE_STRING ValueName
;
735 UNICODE_STRING UnicodeString
;
739 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
741 RtlInitUnicodeString(&ValueName
, RegistryValue
);
743 ZwQueryValueKey(RegHandle
,
745 KeyValuePartialInformation
,
750 if (!NT_SUCCESS(Status
))
752 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
753 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
755 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
756 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
757 UnicodeString
.MaximumLength
= Information
->DataLength
;
760 (PWCHAR
)exAllocatePool( NonPagedPool
,
761 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
763 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
765 String
->MaximumLength
= UnicodeString
.MaximumLength
;
766 RtlCopyUnicodeString( String
, &UnicodeString
);
768 return STATUS_SUCCESS
;
772 * Utility to copy and append two unicode strings.
774 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
775 * IN PUNICODE_STRING Second -> Second string to append
776 * IN BOOL Deallocate -> TRUE: Deallocate First string before
782 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
783 PUNICODE_STRING Second
,
786 UNICODE_STRING Ustr
= *ResultFirst
;
787 PWSTR new_string
= ExAllocatePoolWithTag
789 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)), TAG_STRING
);
791 return STATUS_NO_MEMORY
;
793 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
794 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
795 Second
->Buffer
, Second
->Length
);
796 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
797 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
798 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
799 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
800 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
801 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
802 ExFreePool(new_string
);
806 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
807 PUNICODE_STRING TargetKeyName
,
808 PUNICODE_STRING Name
,
809 PUNICODE_STRING DeviceDesc
) {
810 UNICODE_STRING RootDevice
= { 0 }, LinkageKeyName
= { 0 };
811 UNICODE_STRING DescKeyName
= { 0 }, Linkage
= { 0 };
812 UNICODE_STRING BackSlash
= { 0 };
813 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
816 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
818 RtlInitUnicodeString(&BackSlash
, L
"\\");
819 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
821 RtlInitUnicodeString(&DescKeyName
, L
"");
822 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
823 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
824 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
826 RtlInitUnicodeString(&LinkageKeyName
, L
"");
827 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
828 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
830 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
831 if( !NT_SUCCESS(Status
) ) goto cleanup
;
833 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
834 if( !NT_SUCCESS(Status
) ) goto cleanup
;
836 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
837 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
838 if( !NT_SUCCESS(Status
) ) goto cleanup
;
840 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
841 if( !NT_SUCCESS(Status
) ) goto cleanup
;
843 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
844 } else Status
= STATUS_UNSUCCESSFUL
;
847 RtlFreeUnicodeString( &RootDevice
);
848 RtlFreeUnicodeString( &LinkageKeyName
);
849 RtlFreeUnicodeString( &DescKeyName
);
850 if( LinkageKey
) NtClose( LinkageKey
);
851 if( DescKey
) NtClose( DescKey
);
853 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
858 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
859 PUNICODE_STRING DeviceDesc
) {
860 UNICODE_STRING EnumKeyName
, TargetKeyName
;
864 KEY_BASIC_INFORMATION
*Kbio
=
865 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
866 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
868 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
871 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
873 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
875 if( !NT_SUCCESS(Status
) ) {
876 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
877 &EnumKeyName
, Status
));
882 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
883 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
884 Kbio
, KbioLength
, &ResultLength
);
886 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
888 KbioLength
= ResultLength
;
889 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
891 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
893 return STATUS_NO_MEMORY
;
896 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
897 Kbio
, KbioLength
, &ResultLength
);
899 if( !NT_SUCCESS(Status
) ) {
900 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
907 if( NT_SUCCESS(Status
) ) {
908 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
910 TargetKeyName
.Buffer
= Kbio
->Name
;
912 Status
= CheckForDeviceDesc
913 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
914 if( NT_SUCCESS(Status
) ) {
918 } else Status
= STATUS_SUCCESS
;
922 RtlInitUnicodeString( DeviceDesc
, L
"" );
923 AppendUnicodeString( DeviceDesc
, &TargetKeyName
, FALSE
);
926 return STATUS_UNSUCCESSFUL
;
929 VOID
GetName( PUNICODE_STRING RegistryKey
,
930 PUNICODE_STRING OutName
) {
932 UNICODE_STRING PartialRegistryKey
;
934 PartialRegistryKey
.Buffer
=
935 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
936 Ptr
= PartialRegistryKey
.Buffer
;
938 while( *Ptr
!= L
'\\' &&
939 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
942 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
943 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
945 RtlInitUnicodeString( OutName
, L
"" );
946 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
950 PLAN_ADAPTER Adapter
,
951 PNDIS_STRING RegistryPath
)
953 * FUNCTION: Binds a LAN adapter to IP layer
955 * Adapter = Pointer to LAN_ADAPTER structure
957 * We set the lookahead buffer size, set the packet filter and
958 * bind the adapter to IP layer
962 NDIS_STATUS NdisStatus
;
963 LLIP_BIND_INFO BindInfo
;
964 IP_ADDRESS DefaultMask
= { 0 };
965 ULONG Lookahead
= LOOKAHEAD_SIZE
;
967 HANDLE RegHandle
= 0;
969 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
971 Adapter
->State
= LAN_STATE_OPENING
;
973 NdisStatus
= NDISCall(Adapter
,
974 NdisRequestSetInformation
,
975 OID_GEN_CURRENT_LOOKAHEAD
,
978 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
979 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
983 /* Bind the adapter to IP layer */
984 BindInfo
.Context
= Adapter
;
985 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
986 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
987 BindInfo
.MTU
= Adapter
->MTU
;
988 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
989 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
990 BindInfo
.Transmit
= LANTransmit
;
992 IF
= IPCreateInterface(&BindInfo
);
995 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1000 * Query per-adapter configuration from the registry
1001 * In case anyone is curious: there *is* an Ndis configuration api
1002 * for this sort of thing, but it doesn't really support things like
1003 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1004 * protocol drivers developed for win2k and above just use the native
1005 * services (ZwOpenKey, etc).
1008 GetName( RegistryPath
, &IF
->Name
);
1010 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
1012 if(NT_SUCCESS(Status
)) {
1013 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
1014 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
1017 IPDestroyInterface( IF
);
1021 DefaultMask
.Type
= IP_ADDRESS_V4
;
1023 IF
->Unicast
= DefaultMask
;
1024 IF
->Netmask
= DefaultMask
;
1026 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
1027 IF
->Broadcast
.Address
.IPv4Address
=
1028 IF
->Unicast
.Address
.IPv4Address
|
1029 ~IF
->Netmask
.Address
.IPv4Address
;
1031 TI_DbgPrint(DEBUG_DATALINK
,("BCAST(IF) %s\n", A2S(&IF
->Broadcast
)));
1033 /* Get maximum link speed */
1034 NdisStatus
= NDISCall(Adapter
,
1035 NdisRequestQueryInformation
,
1040 if( !NT_SUCCESS(NdisStatus
) )
1041 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1043 /* Register interface with IP layer */
1044 IPRegisterInterface(IF
);
1046 /* Set packet filter so we can send and receive packets */
1047 NdisStatus
= NDISCall(Adapter
,
1048 NdisRequestSetInformation
,
1049 OID_GEN_CURRENT_PACKET_FILTER
,
1050 &Adapter
->PacketFilter
,
1053 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1054 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1055 IPDestroyInterface(IF
);
1059 Adapter
->Context
= IF
;
1060 Adapter
->State
= LAN_STATE_STARTED
;
1066 PLAN_ADAPTER Adapter
)
1068 * FUNCTION: Unbinds a LAN adapter from IP layer
1070 * Adapter = Pointer to LAN_ADAPTER structure
1073 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1075 if (Adapter
->State
== LAN_STATE_STARTED
) {
1076 PIP_INTERFACE IF
= Adapter
->Context
;
1078 IPUnregisterInterface(IF
);
1080 IPDestroyInterface(IF
);
1085 NDIS_STATUS
LANRegisterAdapter(
1086 PNDIS_STRING AdapterName
,
1087 PNDIS_STRING RegistryPath
)
1089 * FUNCTION: Registers protocol with an NDIS adapter
1091 * AdapterName = Pointer to string with name of adapter to register
1092 * Adapter = Address of pointer to a LAN_ADAPTER structure
1094 * Status of operation
1098 NDIS_STATUS NdisStatus
;
1099 NDIS_STATUS OpenStatus
;
1101 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1105 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1107 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
1109 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1110 return NDIS_STATUS_RESOURCES
;
1113 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1115 /* Put adapter in stopped state */
1116 IF
->State
= LAN_STATE_STOPPED
;
1118 /* Initialize protecting spin lock */
1119 KeInitializeSpinLock(&IF
->Lock
);
1121 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1123 /* Initialize array with media IDs we support */
1124 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1126 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1127 /* Open the adapter. */
1128 NdisOpenAdapter(&NdisStatus
,
1140 /* Wait until the adapter is opened */
1141 if (NdisStatus
== NDIS_STATUS_PENDING
)
1142 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1143 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1144 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1149 IF
->Media
= MediaArray
[MediaIndex
];
1151 /* Fill LAN_ADAPTER structure with some adapter specific information */
1152 switch (IF
->Media
) {
1153 case NdisMedium802_3
:
1154 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1155 IF
->BCastMask
= BCAST_ETH_MASK
;
1156 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1157 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1158 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1159 IF
->MinFrameSize
= 60;
1160 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1162 NDIS_PACKET_TYPE_BROADCAST
|
1163 NDIS_PACKET_TYPE_DIRECTED
|
1164 NDIS_PACKET_TYPE_MULTICAST
;
1168 /* Unsupported media */
1169 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1171 return NDIS_STATUS_NOT_SUPPORTED
;
1174 /* Get maximum frame size */
1175 NdisStatus
= NDISCall(IF
,
1176 NdisRequestQueryInformation
,
1177 OID_GEN_MAXIMUM_FRAME_SIZE
,
1180 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1181 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (NDISCall)\n", AdapterName
));
1186 /* Get maximum packet size */
1187 NdisStatus
= NDISCall(IF
,
1188 NdisRequestQueryInformation
,
1189 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1192 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1193 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1198 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1199 NdisStatus
= NDISCall(IF
,
1200 NdisRequestQueryInformation
,
1201 OID_GEN_MAXIMUM_SEND_PACKETS
,
1202 &IF
->MaxSendPackets
,
1204 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1205 /* Legacy NIC drivers may not support this query, if it fails we
1206 assume it can send at least one packet per call to NdisSend(Packets) */
1207 IF
->MaxSendPackets
= 1;
1209 /* Get current hardware address */
1210 NdisStatus
= NDISCall(IF
,
1211 NdisRequestQueryInformation
,
1214 IF
->HWAddressLength
);
1215 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1216 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1221 /* Get maximum link speed */
1222 NdisStatus
= NDISCall(IF
,
1223 NdisRequestQueryInformation
,
1227 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1228 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1233 /* Convert returned link speed to bps (it is in 100bps increments) */
1234 IF
->Speed
= Speed
* 100L;
1236 /* Bind adapter to IP layer */
1237 if( !BindAdapter(IF
, RegistryPath
) ) {
1238 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1240 return NDIS_STATUS_NOT_ACCEPTED
;
1243 /* Add adapter to the adapter list */
1244 ExInterlockedInsertTailList(&AdapterListHead
,
1248 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1250 return NDIS_STATUS_SUCCESS
;
1254 NDIS_STATUS
LANUnregisterAdapter(
1255 PLAN_ADAPTER Adapter
)
1257 * FUNCTION: Unregisters protocol with NDIS adapter
1259 * Adapter = Pointer to a LAN_ADAPTER structure
1261 * Status of operation
1265 NDIS_HANDLE NdisHandle
;
1266 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1268 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1270 /* Unlink the adapter from the list */
1271 RemoveEntryList(&Adapter
->ListEntry
);
1273 /* Unbind adapter from IP layer */
1274 UnbindAdapter(Adapter
);
1276 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1277 NdisHandle
= Adapter
->NdisHandle
;
1279 Adapter
->NdisHandle
= NULL
;
1280 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1282 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1283 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1284 TcpipWaitForSingleObject(&Adapter
->Event
,
1289 NdisStatus
= Adapter
->NdisStatus
;
1292 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1294 FreeAdapter(Adapter
);
1300 NTSTATUS
LANRegisterProtocol(
1303 * FUNCTION: Registers this protocol driver with NDIS
1305 * Name = Name of this protocol driver
1307 * Status of operation
1310 NDIS_STATUS NdisStatus
;
1311 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1313 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1315 InitializeListHead(&AdapterListHead
);
1316 KeInitializeSpinLock(&AdapterListLock
);
1318 /* Set up protocol characteristics */
1319 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1320 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1321 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1322 ProtChars
.Name
.Length
= Name
->Length
;
1323 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1324 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1325 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1326 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1327 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1328 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1329 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1330 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1331 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1332 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1333 ProtChars
.StatusHandler
= ProtocolStatus
;
1334 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1335 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1337 /* Try to register protocol */
1338 NdisRegisterProtocol(&NdisStatus
,
1339 &NdisProtocolHandle
,
1341 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1342 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1344 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1345 return (NTSTATUS
)NdisStatus
;
1348 ProtocolRegistered
= TRUE
;
1350 return STATUS_SUCCESS
;
1354 VOID
LANUnregisterProtocol(
1357 * FUNCTION: Unregisters this protocol driver with NDIS
1358 * NOTES: Does not care wether we are already registered
1361 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1363 if (ProtocolRegistered
) {
1364 NDIS_STATUS NdisStatus
;
1365 PLIST_ENTRY CurrentEntry
;
1366 PLIST_ENTRY NextEntry
;
1367 PLAN_ADAPTER Current
;
1370 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1372 /* Search the list and remove every adapter we find */
1373 CurrentEntry
= AdapterListHead
.Flink
;
1374 while (CurrentEntry
!= &AdapterListHead
) {
1375 NextEntry
= CurrentEntry
->Flink
;
1376 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1378 LANUnregisterAdapter(Current
);
1379 CurrentEntry
= NextEntry
;
1382 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1384 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1385 ProtocolRegistered
= FALSE
;
1390 InitializeListHead( &LanSendCompleteList
);
1391 KeInitializeSpinLock( &LanSendCompleteLock
);
1394 VOID
LANShutdown() {
1396 PLAN_WQ_ITEM WorkItem
;
1397 PLIST_ENTRY ListEntry
;
1399 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
1400 while( !IsListEmpty( &LanSendCompleteList
) ) {
1401 ListEntry
= RemoveHeadList( &LanSendCompleteList
);
1402 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1403 FreeNdisPacket( WorkItem
->Packet
);
1404 ExFreePool( WorkItem
);
1406 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);