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 /* Work around being called back into afd at Dpc level */
55 KSPIN_LOCK LanWorkLock
;
56 LIST_ENTRY LanWorkList
;
57 WORK_QUEUE_ITEM LanWorkItem
;
59 /* Double complete protection */
60 KSPIN_LOCK LanSendCompleteLock
;
61 LIST_ENTRY LanSendCompleteList
;
63 VOID
LanChainCompletion( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
64 PLAN_WQ_ITEM PendingCompletion
=
65 ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
67 if( !PendingCompletion
) return;
69 PendingCompletion
->Packet
= NdisPacket
;
70 PendingCompletion
->Adapter
= Adapter
;
72 ExInterlockedInsertTailList( &LanSendCompleteList
,
73 &PendingCompletion
->ListEntry
,
74 &LanSendCompleteLock
);
77 BOOLEAN
LanShouldComplete( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
78 PLIST_ENTRY ListEntry
;
79 PLAN_WQ_ITEM CompleteEntry
;
82 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
83 for( ListEntry
= LanSendCompleteList
.Flink
;
84 ListEntry
!= &LanSendCompleteList
;
85 ListEntry
= ListEntry
->Flink
) {
86 CompleteEntry
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
88 if( CompleteEntry
->Adapter
== Adapter
&&
89 CompleteEntry
->Packet
== NdisPacket
) {
90 RemoveEntryList( ListEntry
);
91 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
92 ExFreePool( CompleteEntry
);
96 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
98 DbgPrint("NDIS completed the same send packet twice "
99 "(Adapter %x Packet %x)!!\n", Adapter
, NdisPacket
);
100 #ifdef BREAK_ON_DOUBLE_COMPLETE
107 NDIS_STATUS
NDISCall(
108 PLAN_ADAPTER Adapter
,
109 NDIS_REQUEST_TYPE Type
,
114 * FUNCTION: Send a request to NDIS
116 * Adapter = Pointer to a LAN_ADAPTER structure
117 * Type = Type of request (Set or Query)
118 * OID = Value to be set/queried for
119 * Buffer = Pointer to a buffer to use
120 * Length = Number of bytes in Buffer
122 * Status of operation
125 NDIS_REQUEST Request
;
126 NDIS_STATUS NdisStatus
;
128 Request
.RequestType
= Type
;
129 if (Type
== NdisRequestSetInformation
) {
130 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
131 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
132 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
134 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
135 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
136 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
139 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
140 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
142 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
145 /* Wait for NDIS to complete the request */
146 if (NdisStatus
== NDIS_STATUS_PENDING
) {
147 KeWaitForSingleObject(&Adapter
->Event
,
152 NdisStatus
= Adapter
->NdisStatus
;
160 PLAN_ADAPTER Adapter
)
162 * FUNCTION: Frees memory for a LAN_ADAPTER structure
164 * Adapter = Pointer to LAN_ADAPTER structure to free
171 NTSTATUS TcpipLanGetDwordOid
172 ( PIP_INTERFACE Interface
,
175 /* Get maximum frame size */
176 if( Interface
->Context
) {
177 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
178 NdisRequestQueryInformation
,
182 } else switch( Oid
) { /* Loopback Case */
183 case OID_GEN_HARDWARE_STATUS
:
184 *Result
= NdisHardwareStatusReady
;
185 return STATUS_SUCCESS
;
188 return STATUS_INVALID_PARAMETER
;
193 VOID STDCALL
ProtocolOpenAdapterComplete(
194 NDIS_HANDLE BindingContext
,
196 NDIS_STATUS OpenErrorStatus
)
198 * FUNCTION: Called by NDIS to complete opening of an adapter
200 * BindingContext = Pointer to a device context (LAN_ADAPTER)
201 * Status = Status of the operation
202 * OpenErrorStatus = Additional status information
205 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
207 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
209 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
213 VOID STDCALL
ProtocolCloseAdapterComplete(
214 NDIS_HANDLE BindingContext
,
217 * FUNCTION: Called by NDIS to complete closing an adapter
219 * BindingContext = Pointer to a device context (LAN_ADAPTER)
220 * Status = Status of the operation
223 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
225 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
227 Adapter
->NdisStatus
= Status
;
229 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
233 VOID STDCALL
ProtocolResetComplete(
234 NDIS_HANDLE BindingContext
,
237 * FUNCTION: Called by NDIS to complete resetting an adapter
239 * BindingContext = Pointer to a device context (LAN_ADAPTER)
240 * Status = Status of the operation
243 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
247 VOID STDCALL
ProtocolRequestComplete(
248 NDIS_HANDLE BindingContext
,
249 PNDIS_REQUEST NdisRequest
,
252 * FUNCTION: Called by NDIS to complete a request
254 * BindingContext = Pointer to a device context (LAN_ADAPTER)
255 * NdisRequest = Pointer to an object describing the request
256 * Status = Status of the operation
259 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
261 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
263 /* Save status of request and signal an event */
264 Adapter
->NdisStatus
= Status
;
266 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
270 VOID STDCALL
ProtocolSendComplete(
271 NDIS_HANDLE BindingContext
,
275 * FUNCTION: Called by NDIS to complete sending process
277 * BindingContext = Pointer to a device context (LAN_ADAPTER)
278 * Packet = Pointer to a packet descriptor
279 * Status = Status of the operation
282 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
283 if( LanShouldComplete( (PLAN_ADAPTER
)BindingContext
, Packet
) ) {
284 ASSERT_KM_POINTER(Packet
);
285 ASSERT_KM_POINTER(PC(Packet
));
286 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
287 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
288 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
292 VOID STDCALL
LanReceiveWorker( PVOID Context
) {
294 PLIST_ENTRY ListEntry
;
295 PLAN_WQ_ITEM WorkItem
;
297 PLAN_ADAPTER Adapter
;
298 UINT BytesTransferred
;
299 PNDIS_BUFFER NdisBuffer
;
302 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
305 ExInterlockedRemoveHeadList( &LanWorkList
, &LanWorkLock
)) ) {
306 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
308 TI_DbgPrint(DEBUG_DATALINK
, ("WorkItem: %x\n", WorkItem
));
310 Packet
= WorkItem
->Packet
;
311 Adapter
= WorkItem
->Adapter
;
312 BytesTransferred
= WorkItem
->BytesTransferred
;
314 ExFreePool( WorkItem
);
316 IPPacket
.NdisPacket
= Packet
;
318 NdisGetFirstBufferFromPacket(Packet
,
321 &IPPacket
.ContigSize
,
322 &IPPacket
.TotalSize
);
324 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
325 /* Determine which upper layer protocol that should receive
326 this packet and pass it to the correct receive handler */
328 TI_DbgPrint(MID_TRACE
,
329 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
330 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
333 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
334 IPPacket
.Position
= 0;
338 ("Ether Type = %x ContigSize = %d Total = %d\n",
339 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
341 switch (PacketType
) {
344 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
345 IPReceive(Adapter
->Context
, &IPPacket
);
348 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
349 ARPReceive(Adapter
->Context
, &IPPacket
);
354 FreeNdisPacket( Packet
);
356 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving\n"));
357 LanReceiveWorkerBusy
= FALSE
;
360 VOID
LanSubmitReceiveWork(
361 NDIS_HANDLE BindingContext
,
364 UINT BytesTransferred
) {
366 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
369 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
371 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
373 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
375 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
379 WQItem
->Packet
= Packet
;
380 WQItem
->Adapter
= Adapter
;
381 WQItem
->BytesTransferred
= BytesTransferred
;
382 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
383 if( !LanReceiveWorkerBusy
) {
384 LanReceiveWorkerBusy
= TRUE
;
385 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
386 TI_DbgPrint(DEBUG_DATALINK
,
387 ("Work item inserted %x %x\n", &LanWorkItem
, WQItem
));
389 DbgPrint("LAN WORKER BUSY %x %x\n", &LanWorkItem
, WQItem
);
391 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
394 VOID STDCALL
ProtocolTransferDataComplete(
395 NDIS_HANDLE BindingContext
,
398 UINT BytesTransferred
)
400 * FUNCTION: Called by NDIS to complete reception of data
402 * BindingContext = Pointer to a device context (LAN_ADAPTER)
403 * Packet = Pointer to a packet descriptor
404 * Status = Status of the operation
405 * BytesTransferred = Number of bytes transferred
407 * If the packet was successfully received, determine the protocol
408 * type and pass it to the correct receive handler
411 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
413 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
415 TransferDataCompleteCalled
++;
416 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
418 if( Status
!= NDIS_STATUS_SUCCESS
) return;
420 LanSubmitReceiveWork( BindingContext
, Packet
, Status
, BytesTransferred
);
423 NDIS_STATUS STDCALL
ProtocolReceive(
424 NDIS_HANDLE BindingContext
,
425 NDIS_HANDLE MacReceiveContext
,
427 UINT HeaderBufferSize
,
428 PVOID LookaheadBuffer
,
429 UINT LookaheadBufferSize
,
432 * FUNCTION: Called by NDIS when a packet has been received on the physical link
434 * BindingContext = Pointer to a device context (LAN_ADAPTER)
435 * MacReceiveContext = Handle used by underlying NIC driver
436 * HeaderBuffer = Pointer to a buffer containing the packet header
437 * HeaderBufferSize = Number of bytes in HeaderBuffer
438 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
439 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
440 * PacketSize = Overall size of the packet (not including header)
442 * Status of operation
446 UINT PacketType
, BytesTransferred
;
450 NDIS_STATUS NdisStatus
;
451 PNDIS_PACKET NdisPacket
;
452 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
453 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
456 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
458 if (Adapter
->State
!= LAN_STATE_STARTED
) {
459 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
460 return NDIS_STATUS_NOT_ACCEPTED
;
463 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
464 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
465 return NDIS_STATUS_NOT_ACCEPTED
;
468 if (Adapter
->Media
== NdisMedium802_3
) {
469 /* Ethernet and IEEE 802.3 frames can be destinguished by
470 looking at the IEEE 802.3 length field. This field is
471 less than or equal to 1500 for a valid IEEE 802.3 frame
472 and larger than 1500 is it's a valid EtherType value.
473 See RFC 1122, section 2.3.3 for more information */
474 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
475 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
476 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
477 return NDIS_STATUS_NOT_ACCEPTED
;
479 /* We use EtherType constants to destinguish packet types */
482 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
483 /* FIXME: Support other medias */
484 return NDIS_STATUS_NOT_ACCEPTED
;
487 /* Get a transfer data packet */
489 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
490 Adapter
, Adapter
->MTU
));
492 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
494 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
495 PacketSize
+ HeaderBufferSize
);
496 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
497 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
498 return NDIS_STATUS_NOT_ACCEPTED
;
501 PC(NdisPacket
)->PacketType
= PacketType
;
503 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
505 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
507 IPPacket
.NdisPacket
= NdisPacket
;
508 IPPacket
.Position
= 0;
510 TransferDataCalled
++;
512 if (LookaheadBufferSize
== PacketSize
)
514 /* Optimized code path for packets that are fully contained in
515 * the lookahead buffer. */
516 NdisCopyLookaheadData(BufferData
,
519 Adapter
->MacOptions
);
523 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
525 ASSERT(PacketSize
<= Adapter
->MTU
);
527 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
528 MacReceiveContext
, 0, PacketSize
,
529 NdisPacket
, &BytesTransferred
);
533 BytesTransferred
= 0;
536 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
537 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
539 if (NdisStatus
!= NDIS_STATUS_PENDING
)
540 ProtocolTransferDataComplete(BindingContext
,
545 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
547 return NDIS_STATUS_SUCCESS
;
551 VOID STDCALL
ProtocolReceiveComplete(
552 NDIS_HANDLE BindingContext
)
554 * FUNCTION: Called by NDIS when we're done receiving data
556 * BindingContext = Pointer to a device context (LAN_ADAPTER)
559 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
563 VOID STDCALL
ProtocolStatus(
564 NDIS_HANDLE BindingContext
,
565 NDIS_STATUS GenerelStatus
,
567 UINT StatusBufferSize
)
569 * FUNCTION: Called by NDIS when the underlying driver has changed state
571 * BindingContext = Pointer to a device context (LAN_ADAPTER)
572 * GenerelStatus = A generel status code
573 * StatusBuffer = Pointer to a buffer with medium-specific data
574 * StatusBufferSize = Number of bytes in StatusBuffer
577 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
581 VOID STDCALL
ProtocolStatusComplete(
582 NDIS_HANDLE NdisBindingContext
)
584 * FUNCTION: Called by NDIS when a status-change has occurred
586 * BindingContext = Pointer to a device context (LAN_ADAPTER)
589 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
592 VOID STDCALL
ProtocolBindAdapter(
593 OUT PNDIS_STATUS Status
,
594 IN NDIS_HANDLE BindContext
,
595 IN PNDIS_STRING DeviceName
,
596 IN PVOID SystemSpecific1
,
597 IN PVOID SystemSpecific2
)
599 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
600 * bindings, and periodically thereafer as new adapters come online
602 * Status: Return value to NDIS
603 * BindContext: Handle provided by NDIS to track pending binding operations
604 * DeviceName: Name of the miniport device to bind to
605 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
606 * SystemSpecific2: Unused & must not be touched
609 /* XXX confirm that this is still true, or re-word the following comment */
610 /* we get to ignore BindContext because we will never pend an operation with NDIS */
611 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
612 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
618 PNDIS_PACKET NdisPacket
,
623 * FUNCTION: Transmits a packet
625 * Context = Pointer to context information (LAN_ADAPTER)
626 * NdisPacket = Pointer to NDIS packet to send
627 * Offset = Offset in packet where data starts
628 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
629 * Type = LAN protocol type (LAN_PROTO_*)
632 NDIS_STATUS NdisStatus
;
637 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
639 TI_DbgPrint(DEBUG_DATALINK
,
640 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
641 NdisPacket
, Offset
, Adapter
));
643 TI_DbgPrint(DEBUG_DATALINK
,
644 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
645 Adapter
->HWAddress
[0] & 0xff,
646 Adapter
->HWAddress
[1] & 0xff,
647 Adapter
->HWAddress
[2] & 0xff,
648 Adapter
->HWAddress
[3] & 0xff,
649 Adapter
->HWAddress
[4] & 0xff,
650 Adapter
->HWAddress
[5] & 0xff));
652 /* XXX arty -- Handled adjustment in a saner way than before ...
653 * not needed immediately */
654 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
656 LanChainCompletion( Adapter
, NdisPacket
);
658 if (Adapter
->State
== LAN_STATE_STARTED
) {
659 switch (Adapter
->Media
) {
660 case NdisMedium802_3
:
661 EHeader
= (PETH_HEADER
)Data
;
664 /* Unicast address */
665 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
667 /* Broadcast address */
668 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
671 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
675 EHeader
->EType
= ETYPE_IPv4
;
678 EHeader
->EType
= ETYPE_ARP
;
681 EHeader
->EType
= ETYPE_IPv6
;
685 /* Should not happen */
686 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
688 ProtocolSendComplete((NDIS_HANDLE
)Context
,
690 NDIS_STATUS_FAILURE
);
697 /* FIXME: Support other medias */
701 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
705 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
706 ((PCHAR
)LinkAddress
)[0] & 0xff,
707 ((PCHAR
)LinkAddress
)[1] & 0xff,
708 ((PCHAR
)LinkAddress
)[2] & 0xff,
709 ((PCHAR
)LinkAddress
)[3] & 0xff,
710 ((PCHAR
)LinkAddress
)[4] & 0xff,
711 ((PCHAR
)LinkAddress
)[5] & 0xff));
714 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
715 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
716 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
717 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
718 NdisStatus
== NDIS_STATUS_PENDING
?
719 "Pending" : "Complete"));
720 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
722 /* I had a talk with vizzini: these really ought to be here.
723 * we're supposed to see these completed by ndis *only* when
724 * status_pending is returned. Note that this is different from
725 * the situation with IRPs. */
726 if (NdisStatus
!= NDIS_STATUS_PENDING
)
727 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
729 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
734 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
735 OBJECT_ATTRIBUTES Attributes
;
738 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
739 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
743 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
744 PWCHAR RegistryValue
,
745 PUNICODE_STRING String
) {
746 UNICODE_STRING ValueName
;
747 UNICODE_STRING UnicodeString
;
751 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
753 RtlInitUnicodeString(&ValueName
, RegistryValue
);
755 ZwQueryValueKey(RegHandle
,
757 KeyValuePartialInformation
,
762 if (!NT_SUCCESS(Status
))
764 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
765 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
767 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
768 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
769 UnicodeString
.MaximumLength
= Information
->DataLength
;
772 (PWCHAR
)exAllocatePool( NonPagedPool
,
773 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
775 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
777 String
->MaximumLength
= UnicodeString
.MaximumLength
;
778 RtlCopyUnicodeString( String
, &UnicodeString
);
780 return STATUS_SUCCESS
;
784 * Utility to copy and append two unicode strings.
786 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
787 * IN PUNICODE_STRING Second -> Second string to append
788 * IN BOOL Deallocate -> TRUE: Deallocate First string before
794 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
795 PUNICODE_STRING Second
,
798 UNICODE_STRING Ustr
= *ResultFirst
;
799 PWSTR new_string
= ExAllocatePoolWithTag
801 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)), TAG_STRING
);
803 return STATUS_NO_MEMORY
;
805 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
806 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
807 Second
->Buffer
, Second
->Length
);
808 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
809 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
810 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
811 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
812 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
813 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
814 ExFreePool(new_string
);
818 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
819 PUNICODE_STRING TargetKeyName
,
820 PUNICODE_STRING ShortName
,
821 PUNICODE_STRING OutName
) {
822 UNICODE_STRING RootDevice
= { 0 }, LinkageKeyName
= { 0 };
823 UNICODE_STRING DescKeyName
= { 0 }, Linkage
= { 0 };
824 UNICODE_STRING BackSlash
= { 0 };
825 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
828 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
830 RtlInitUnicodeString(&BackSlash
, L
"\\");
831 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
833 RtlInitUnicodeString(&DescKeyName
, L
"");
834 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
835 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
836 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
838 RtlInitUnicodeString(&LinkageKeyName
, L
"");
839 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
840 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
842 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
843 if( !NT_SUCCESS(Status
) ) goto cleanup
;
845 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
846 if( !NT_SUCCESS(Status
) ) goto cleanup
;
848 if( RtlCompareUnicodeString( &RootDevice
, ShortName
, TRUE
) == 0 ) {
849 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
850 if( !NT_SUCCESS(Status
) ) goto cleanup
;
852 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", OutName
);
853 if( !NT_SUCCESS(Status
) ) goto cleanup
;
855 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER NAME: %wZ\n", OutName
));
856 } else Status
= STATUS_UNSUCCESSFUL
;
859 RtlFreeUnicodeString( &RootDevice
);
860 RtlFreeUnicodeString( &LinkageKeyName
);
861 RtlFreeUnicodeString( &DescKeyName
);
862 if( LinkageKey
) NtClose( LinkageKey
);
863 if( DescKey
) NtClose( DescKey
);
865 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
870 static NTSTATUS
FindDeviceNameForAdapter( PUNICODE_STRING ShortName
,
871 PUNICODE_STRING OutName
) {
872 UNICODE_STRING EnumKeyName
, TargetKeyName
;
876 KEY_BASIC_INFORMATION
*Kbio
=
877 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
878 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
881 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
883 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
885 if( !NT_SUCCESS(Status
) )
886 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
887 &EnumKeyName
, Status
));
889 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
890 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
891 Kbio
, KbioLength
, &ResultLength
);
893 if( Status
== STATUS_BUFFER_TOO_SMALL
) {
895 KbioLength
= ResultLength
;
896 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
898 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
899 Kbio
, KbioLength
, &ResultLength
);
901 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
905 if( NT_SUCCESS(Status
) ) {
906 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
908 TargetKeyName
.Buffer
= Kbio
->Name
;
910 Status
= CheckForDeviceDesc
911 ( &EnumKeyName
, &TargetKeyName
, ShortName
, OutName
);
912 if( NT_SUCCESS(Status
) ) {
915 } else Status
= STATUS_SUCCESS
;
919 RtlInitUnicodeString( OutName
, L
"" );
920 AppendUnicodeString( OutName
, &TargetKeyName
, FALSE
);
922 return STATUS_UNSUCCESSFUL
;
925 VOID
GetShortName( PUNICODE_STRING RegistryKey
,
926 PUNICODE_STRING ShortNameOut
) {
928 ShortNameOut
->Buffer
=
929 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
930 Ptr
= ShortNameOut
->Buffer
;
932 while( *Ptr
!= L
'\\' &&
933 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
936 ShortNameOut
->Length
= ShortNameOut
->MaximumLength
=
937 (Ptr
- ShortNameOut
->Buffer
) * sizeof(WCHAR
);
941 PLAN_ADAPTER Adapter
,
942 PNDIS_STRING RegistryPath
)
944 * FUNCTION: Binds a LAN adapter to IP layer
946 * Adapter = Pointer to LAN_ADAPTER structure
948 * We set the lookahead buffer size, set the packet filter and
949 * bind the adapter to IP layer
953 NDIS_STATUS NdisStatus
;
954 LLIP_BIND_INFO BindInfo
;
955 IP_ADDRESS DefaultMask
= { 0 };
956 ULONG Lookahead
= LOOKAHEAD_SIZE
;
958 HANDLE RegHandle
= 0;
959 UNICODE_STRING ShortName
;
961 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
963 Adapter
->State
= LAN_STATE_OPENING
;
965 GetShortName( RegistryPath
, &ShortName
);
967 NdisStatus
= NDISCall(Adapter
,
968 NdisRequestSetInformation
,
969 OID_GEN_CURRENT_LOOKAHEAD
,
972 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
973 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
977 /* Bind the adapter to IP layer */
978 BindInfo
.Context
= Adapter
;
979 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
980 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
981 BindInfo
.MTU
= Adapter
->MTU
;
982 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
983 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
984 BindInfo
.Transmit
= LANTransmit
;
986 IF
= IPCreateInterface(&BindInfo
);
989 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
994 * Query per-adapter configuration from the registry
995 * In case anyone is curious: there *is* an Ndis configuration api
996 * for this sort of thing, but it doesn't really support things like
997 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
998 * protocol drivers developed for win2k and above just use the native
999 * services (ZwOpenKey, etc).
1002 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
1004 if(NT_SUCCESS(Status
)) {
1005 Status
= FindDeviceNameForAdapter( &ShortName
, &IF
->Name
);
1006 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Name: %wZ\n", &IF
->Name
));
1009 DefaultMask
.Type
= IP_ADDRESS_V4
;
1011 IF
->Unicast
= DefaultMask
;
1012 IF
->Netmask
= DefaultMask
;
1014 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
1015 IF
->Broadcast
.Address
.IPv4Address
=
1016 IF
->Unicast
.Address
.IPv4Address
|
1017 ~IF
->Netmask
.Address
.IPv4Address
;
1019 TI_DbgPrint(DEBUG_DATALINK
,("BCAST(IF) %s\n", A2S(&IF
->Broadcast
)));
1021 /* Get maximum link speed */
1022 NdisStatus
= NDISCall(Adapter
,
1023 NdisRequestQueryInformation
,
1028 if( !NT_SUCCESS(NdisStatus
) )
1029 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1031 /* Register interface with IP layer */
1032 IPRegisterInterface(IF
);
1034 /* Set packet filter so we can send and receive packets */
1035 NdisStatus
= NDISCall(Adapter
,
1036 NdisRequestSetInformation
,
1037 OID_GEN_CURRENT_PACKET_FILTER
,
1038 &Adapter
->PacketFilter
,
1041 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1042 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1043 IPDestroyInterface(IF
);
1047 Adapter
->Context
= IF
;
1048 Adapter
->State
= LAN_STATE_STARTED
;
1053 PLAN_ADAPTER Adapter
)
1055 * FUNCTION: Unbinds a LAN adapter from IP layer
1057 * Adapter = Pointer to LAN_ADAPTER structure
1060 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1062 if (Adapter
->State
== LAN_STATE_STARTED
) {
1063 PIP_INTERFACE IF
= Adapter
->Context
;
1065 IPUnregisterInterface(IF
);
1067 IPDestroyInterface(IF
);
1072 NDIS_STATUS
LANRegisterAdapter(
1073 PNDIS_STRING AdapterName
,
1074 PNDIS_STRING RegistryPath
)
1076 * FUNCTION: Registers protocol with an NDIS adapter
1078 * AdapterName = Pointer to string with name of adapter to register
1079 * Adapter = Address of pointer to a LAN_ADAPTER structure
1081 * Status of operation
1085 NDIS_STATUS NdisStatus
;
1086 NDIS_STATUS OpenStatus
;
1088 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1092 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1094 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
1096 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1097 return NDIS_STATUS_RESOURCES
;
1100 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1102 /* Put adapter in stopped state */
1103 IF
->State
= LAN_STATE_STOPPED
;
1105 /* Initialize protecting spin lock */
1106 KeInitializeSpinLock(&IF
->Lock
);
1108 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1110 /* Initialize array with media IDs we support */
1111 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1113 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1114 /* Open the adapter. */
1115 NdisOpenAdapter(&NdisStatus
,
1127 /* Wait until the adapter is opened */
1128 if (NdisStatus
== NDIS_STATUS_PENDING
)
1129 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1130 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1135 IF
->Media
= MediaArray
[MediaIndex
];
1137 /* Fill LAN_ADAPTER structure with some adapter specific information */
1138 switch (IF
->Media
) {
1139 case NdisMedium802_3
:
1140 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1141 IF
->BCastMask
= BCAST_ETH_MASK
;
1142 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1143 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1144 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1145 IF
->MinFrameSize
= 60;
1146 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1148 NDIS_PACKET_TYPE_BROADCAST
|
1149 NDIS_PACKET_TYPE_DIRECTED
|
1150 NDIS_PACKET_TYPE_MULTICAST
;
1154 /* Unsupported media */
1155 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1157 return NDIS_STATUS_NOT_SUPPORTED
;
1160 /* Get maximum frame size */
1161 NdisStatus
= NDISCall(IF
,
1162 NdisRequestQueryInformation
,
1163 OID_GEN_MAXIMUM_FRAME_SIZE
,
1166 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1171 /* Get maximum packet size */
1172 NdisStatus
= NDISCall(IF
,
1173 NdisRequestQueryInformation
,
1174 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1177 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1178 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1183 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1184 NdisStatus
= NDISCall(IF
,
1185 NdisRequestQueryInformation
,
1186 OID_GEN_MAXIMUM_SEND_PACKETS
,
1187 &IF
->MaxSendPackets
,
1189 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1190 /* Legacy NIC drivers may not support this query, if it fails we
1191 assume it can send at least one packet per call to NdisSend(Packets) */
1192 IF
->MaxSendPackets
= 1;
1194 /* Get current hardware address */
1195 NdisStatus
= NDISCall(IF
,
1196 NdisRequestQueryInformation
,
1199 IF
->HWAddressLength
);
1200 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1201 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1206 /* Get maximum link speed */
1207 NdisStatus
= NDISCall(IF
,
1208 NdisRequestQueryInformation
,
1212 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1213 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1218 /* Convert returned link speed to bps (it is in 100bps increments) */
1219 IF
->Speed
= Speed
* 100L;
1221 /* Add adapter to the adapter list */
1222 ExInterlockedInsertTailList(&AdapterListHead
,
1226 /* Bind adapter to IP layer */
1227 BindAdapter(IF
, RegistryPath
);
1229 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1231 return NDIS_STATUS_SUCCESS
;
1235 NDIS_STATUS
LANUnregisterAdapter(
1236 PLAN_ADAPTER Adapter
)
1238 * FUNCTION: Unregisters protocol with NDIS adapter
1240 * Adapter = Pointer to a LAN_ADAPTER structure
1242 * Status of operation
1246 NDIS_HANDLE NdisHandle
;
1247 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1249 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1251 /* Unlink the adapter from the list */
1252 RemoveEntryList(&Adapter
->ListEntry
);
1254 /* Unbind adapter from IP layer */
1255 UnbindAdapter(Adapter
);
1257 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1258 NdisHandle
= Adapter
->NdisHandle
;
1260 Adapter
->NdisHandle
= NULL
;
1261 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1263 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1264 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1265 TcpipWaitForSingleObject(&Adapter
->Event
,
1270 NdisStatus
= Adapter
->NdisStatus
;
1273 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1275 FreeAdapter(Adapter
);
1277 return NDIS_STATUS_SUCCESS
;
1281 NTSTATUS
LANRegisterProtocol(
1284 * FUNCTION: Registers this protocol driver with NDIS
1286 * Name = Name of this protocol driver
1288 * Status of operation
1291 NDIS_STATUS NdisStatus
;
1292 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1294 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1296 InitializeListHead(&AdapterListHead
);
1297 KeInitializeSpinLock(&AdapterListLock
);
1299 /* Set up protocol characteristics */
1300 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1301 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1302 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1303 ProtChars
.Name
.Length
= Name
->Length
;
1304 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1305 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1306 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1307 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1308 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1309 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1310 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1311 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1312 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1313 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1314 ProtChars
.StatusHandler
= ProtocolStatus
;
1315 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1316 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1318 /* Try to register protocol */
1319 NdisRegisterProtocol(&NdisStatus
,
1320 &NdisProtocolHandle
,
1322 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1323 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1325 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1326 return (NTSTATUS
)NdisStatus
;
1329 ProtocolRegistered
= TRUE
;
1331 return STATUS_SUCCESS
;
1335 VOID
LANUnregisterProtocol(
1338 * FUNCTION: Unregisters this protocol driver with NDIS
1339 * NOTES: Does not care wether we are already registered
1342 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1344 if (ProtocolRegistered
) {
1345 NDIS_STATUS NdisStatus
;
1346 PLIST_ENTRY CurrentEntry
;
1347 PLIST_ENTRY NextEntry
;
1348 PLAN_ADAPTER Current
;
1351 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1353 /* Search the list and remove every adapter we find */
1354 CurrentEntry
= AdapterListHead
.Flink
;
1355 while (CurrentEntry
!= &AdapterListHead
) {
1356 NextEntry
= CurrentEntry
->Flink
;
1357 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1359 LANUnregisterAdapter(Current
);
1360 CurrentEntry
= NextEntry
;
1363 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1365 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1366 ProtocolRegistered
= FALSE
;
1371 InitializeListHead( &LanWorkList
);
1372 InitializeListHead( &LanSendCompleteList
);
1373 KeInitializeSpinLock( &LanSendCompleteLock
);
1374 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1377 VOID
LANShutdown() {
1379 PLAN_WQ_ITEM WorkItem
;
1380 PLIST_ENTRY ListEntry
;
1382 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1383 while( !IsListEmpty( &LanWorkList
) ) {
1384 ListEntry
= RemoveHeadList( &LanWorkList
);
1385 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1386 FreeNdisPacket( WorkItem
->Packet
);
1387 ExFreePool( WorkItem
);
1389 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
1391 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
1392 while( !IsListEmpty( &LanSendCompleteList
) ) {
1393 ListEntry
= RemoveHeadList( &LanSendCompleteList
);
1394 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1395 FreeNdisPacket( WorkItem
->Packet
);
1396 ExFreePool( WorkItem
);
1398 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);