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;
20 #define NGFP(_Packet) \
23 ULONG _ContigSize, _TotalSize; \
24 PNDIS_BUFFER _NdisBuffer; \
26 TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
27 NdisGetFirstBufferFromPacket(_Packet, \
32 TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
33 TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
34 TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
35 TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
38 typedef struct _LAN_WQ_ITEM
{
42 UINT BytesTransferred
;
43 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
45 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
46 BOOLEAN ProtocolRegistered
= FALSE
;
47 LIST_ENTRY AdapterListHead
;
48 KSPIN_LOCK AdapterListLock
;
50 /* Work around being called back into afd at Dpc level */
51 KSPIN_LOCK LanWorkLock
;
52 LIST_ENTRY LanWorkList
;
53 WORK_QUEUE_ITEM LanWorkItem
;
55 /* Double complete protection */
56 KSPIN_LOCK LanSendCompleteLock
;
57 LIST_ENTRY LanSendCompleteList
;
59 VOID
LanChainCompletion( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
60 PLAN_WQ_ITEM PendingCompletion
=
61 ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
63 if( !PendingCompletion
) return;
65 PendingCompletion
->Packet
= NdisPacket
;
66 PendingCompletion
->Adapter
= Adapter
;
68 ExInterlockedInsertTailList( &LanSendCompleteList
,
69 &PendingCompletion
->ListEntry
,
70 &LanSendCompleteLock
);
73 BOOLEAN
LanShouldComplete( PLAN_ADAPTER Adapter
, PNDIS_PACKET NdisPacket
) {
74 PLIST_ENTRY ListEntry
;
75 PLAN_WQ_ITEM CompleteEntry
;
78 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
79 for( ListEntry
= LanSendCompleteList
.Flink
;
80 ListEntry
!= &LanSendCompleteList
;
81 ListEntry
= ListEntry
->Flink
) {
82 CompleteEntry
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
84 if( CompleteEntry
->Adapter
== Adapter
&&
85 CompleteEntry
->Packet
== NdisPacket
) {
86 RemoveEntryList( ListEntry
);
87 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
88 ExFreePool( CompleteEntry
);
92 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);
94 TI_DbgPrint(MID_TRACE
,("NDIS completed the same send packet twice "
95 "(Adapter %x Packet %x)!!\n", Adapter
, NdisPacket
));
96 #ifdef BREAK_ON_DOUBLE_COMPLETE
103 NDIS_STATUS
NDISCall(
104 PLAN_ADAPTER Adapter
,
105 NDIS_REQUEST_TYPE Type
,
110 * FUNCTION: Send a request to NDIS
112 * Adapter = Pointer to a LAN_ADAPTER structure
113 * Type = Type of request (Set or Query)
114 * OID = Value to be set/queried for
115 * Buffer = Pointer to a buffer to use
116 * Length = Number of bytes in Buffer
118 * Status of operation
121 NDIS_REQUEST Request
;
122 NDIS_STATUS NdisStatus
;
124 Request
.RequestType
= Type
;
125 if (Type
== NdisRequestSetInformation
) {
126 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
127 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
128 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
130 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
131 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
132 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
135 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
136 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
138 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
141 /* Wait for NDIS to complete the request */
142 if (NdisStatus
== NDIS_STATUS_PENDING
) {
143 KeWaitForSingleObject(&Adapter
->Event
,
148 NdisStatus
= Adapter
->NdisStatus
;
156 PLAN_ADAPTER Adapter
)
158 * FUNCTION: Frees memory for a LAN_ADAPTER structure
160 * Adapter = Pointer to LAN_ADAPTER structure to free
167 VOID STDCALL
ProtocolOpenAdapterComplete(
168 NDIS_HANDLE BindingContext
,
170 NDIS_STATUS OpenErrorStatus
)
172 * FUNCTION: Called by NDIS to complete opening of an adapter
174 * BindingContext = Pointer to a device context (LAN_ADAPTER)
175 * Status = Status of the operation
176 * OpenErrorStatus = Additional status information
179 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
181 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
183 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
187 VOID STDCALL
ProtocolCloseAdapterComplete(
188 NDIS_HANDLE BindingContext
,
191 * FUNCTION: Called by NDIS to complete closing an adapter
193 * BindingContext = Pointer to a device context (LAN_ADAPTER)
194 * Status = Status of the operation
197 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
199 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
201 Adapter
->NdisStatus
= Status
;
203 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
207 VOID STDCALL
ProtocolResetComplete(
208 NDIS_HANDLE BindingContext
,
211 * FUNCTION: Called by NDIS to complete resetting an adapter
213 * BindingContext = Pointer to a device context (LAN_ADAPTER)
214 * Status = Status of the operation
217 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
221 VOID STDCALL
ProtocolRequestComplete(
222 NDIS_HANDLE BindingContext
,
223 PNDIS_REQUEST NdisRequest
,
226 * FUNCTION: Called by NDIS to complete a request
228 * BindingContext = Pointer to a device context (LAN_ADAPTER)
229 * NdisRequest = Pointer to an object describing the request
230 * Status = Status of the operation
233 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
235 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
237 /* Save status of request and signal an event */
238 Adapter
->NdisStatus
= Status
;
240 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
244 VOID STDCALL
ProtocolSendComplete(
245 NDIS_HANDLE BindingContext
,
249 * FUNCTION: Called by NDIS to complete sending process
251 * BindingContext = Pointer to a device context (LAN_ADAPTER)
252 * Packet = Pointer to a packet descriptor
253 * Status = Status of the operation
256 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
257 if( LanShouldComplete( (PLAN_ADAPTER
)BindingContext
, Packet
) ) {
258 ASSERT_KM_POINTER(Packet
);
259 ASSERT_KM_POINTER(PC(Packet
));
260 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
261 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
262 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
266 VOID STDCALL
LanReceiveWorker( PVOID Context
) {
268 PLIST_ENTRY ListEntry
;
269 PLAN_WQ_ITEM WorkItem
;
271 PLAN_ADAPTER Adapter
;
272 UINT BytesTransferred
;
273 PNDIS_BUFFER NdisBuffer
;
276 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
279 ExInterlockedRemoveHeadList( &LanWorkList
, &LanWorkLock
)) ) {
280 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
282 Packet
= WorkItem
->Packet
;
283 Adapter
= WorkItem
->Adapter
;
284 BytesTransferred
= WorkItem
->BytesTransferred
;
286 ExFreePool( WorkItem
);
288 IPPacket
.NdisPacket
= Packet
;
290 NdisGetFirstBufferFromPacket(Packet
,
293 &IPPacket
.ContigSize
,
294 &IPPacket
.TotalSize
);
296 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
297 /* Determine which upper layer protocol that should receive
298 this packet and pass it to the correct receive handler */
300 TI_DbgPrint(MID_TRACE
,
301 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
302 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
305 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
306 IPPacket
.Position
= 0;
310 ("Ether Type = %x ContigSize = %d Total = %d\n",
311 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
313 switch (PacketType
) {
316 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
317 IPReceive(Adapter
->Context
, &IPPacket
);
320 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
321 ARPReceive(Adapter
->Context
, &IPPacket
);
326 FreeNdisPacket( Packet
);
330 VOID
LanSubmitReceiveWork(
331 NDIS_HANDLE BindingContext
,
334 UINT BytesTransferred
) {
337 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
340 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
342 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
344 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
348 WorkStart
= IsListEmpty( &LanWorkList
);
349 WQItem
->Packet
= Packet
;
350 WQItem
->Adapter
= Adapter
;
351 WQItem
->BytesTransferred
= BytesTransferred
;
352 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
354 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
355 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
358 VOID STDCALL
ProtocolTransferDataComplete(
359 NDIS_HANDLE BindingContext
,
362 UINT BytesTransferred
)
364 * FUNCTION: Called by NDIS to complete reception of data
366 * BindingContext = Pointer to a device context (LAN_ADAPTER)
367 * Packet = Pointer to a packet descriptor
368 * Status = Status of the operation
369 * BytesTransferred = Number of bytes transferred
371 * If the packet was successfully received, determine the protocol
372 * type and pass it to the correct receive handler
375 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
377 TransferDataCompleteCalled
++;
378 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
380 if( Status
!= NDIS_STATUS_SUCCESS
) return;
382 LanSubmitReceiveWork( BindingContext
, Packet
, Status
, BytesTransferred
);
385 NDIS_STATUS STDCALL
ProtocolReceive(
386 NDIS_HANDLE BindingContext
,
387 NDIS_HANDLE MacReceiveContext
,
389 UINT HeaderBufferSize
,
390 PVOID LookaheadBuffer
,
391 UINT LookaheadBufferSize
,
394 * FUNCTION: Called by NDIS when a packet has been received on the physical link
396 * BindingContext = Pointer to a device context (LAN_ADAPTER)
397 * MacReceiveContext = Handle used by underlying NIC driver
398 * HeaderBuffer = Pointer to a buffer containing the packet header
399 * HeaderBufferSize = Number of bytes in HeaderBuffer
400 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
401 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
402 * PacketSize = Overall size of the packet (not including header)
404 * Status of operation
408 UINT PacketType
, BytesTransferred
;
412 NDIS_STATUS NdisStatus
;
413 PNDIS_PACKET NdisPacket
;
414 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
415 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
418 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
420 if (Adapter
->State
!= LAN_STATE_STARTED
) {
421 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
422 return NDIS_STATUS_NOT_ACCEPTED
;
425 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
426 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
427 return NDIS_STATUS_NOT_ACCEPTED
;
430 if (Adapter
->Media
== NdisMedium802_3
) {
431 /* Ethernet and IEEE 802.3 frames can be destinguished by
432 looking at the IEEE 802.3 length field. This field is
433 less than or equal to 1500 for a valid IEEE 802.3 frame
434 and larger than 1500 is it's a valid EtherType value.
435 See RFC 1122, section 2.3.3 for more information */
436 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
437 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
438 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
439 return NDIS_STATUS_NOT_ACCEPTED
;
441 /* We use EtherType constants to destinguish packet types */
444 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
445 /* FIXME: Support other medias */
446 return NDIS_STATUS_NOT_ACCEPTED
;
449 /* Get a transfer data packet */
451 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
452 Adapter
, Adapter
->MTU
));
454 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
456 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
457 PacketSize
+ HeaderBufferSize
);
458 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
459 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
460 return NDIS_STATUS_NOT_ACCEPTED
;
463 PC(NdisPacket
)->PacketType
= PacketType
;
465 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
467 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
469 IPPacket
.NdisPacket
= NdisPacket
;
470 IPPacket
.Position
= 0;
472 TransferDataCalled
++;
474 if (LookaheadBufferSize
== PacketSize
)
476 /* Optimized code path for packets that are fully contained in
477 * the lookahead buffer. */
478 NdisCopyLookaheadData(BufferData
,
481 Adapter
->MacOptions
);
485 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
487 ASSERT(PacketSize
<= Adapter
->MTU
);
489 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
490 MacReceiveContext
, 0, PacketSize
,
491 NdisPacket
, &BytesTransferred
);
495 BytesTransferred
= 0;
498 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
499 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
501 if (NdisStatus
!= NDIS_STATUS_PENDING
)
502 ProtocolTransferDataComplete(BindingContext
,
507 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
509 return NDIS_STATUS_SUCCESS
;
513 VOID STDCALL
ProtocolReceiveComplete(
514 NDIS_HANDLE BindingContext
)
516 * FUNCTION: Called by NDIS when we're done receiving data
518 * BindingContext = Pointer to a device context (LAN_ADAPTER)
521 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
525 VOID STDCALL
ProtocolStatus(
526 NDIS_HANDLE BindingContext
,
527 NDIS_STATUS GenerelStatus
,
529 UINT StatusBufferSize
)
531 * FUNCTION: Called by NDIS when the underlying driver has changed state
533 * BindingContext = Pointer to a device context (LAN_ADAPTER)
534 * GenerelStatus = A generel status code
535 * StatusBuffer = Pointer to a buffer with medium-specific data
536 * StatusBufferSize = Number of bytes in StatusBuffer
539 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
543 VOID STDCALL
ProtocolStatusComplete(
544 NDIS_HANDLE NdisBindingContext
)
546 * FUNCTION: Called by NDIS when a status-change has occurred
548 * BindingContext = Pointer to a device context (LAN_ADAPTER)
551 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
554 VOID STDCALL
ProtocolBindAdapter(
555 OUT PNDIS_STATUS Status
,
556 IN NDIS_HANDLE BindContext
,
557 IN PNDIS_STRING DeviceName
,
558 IN PVOID SystemSpecific1
,
559 IN PVOID SystemSpecific2
)
561 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
562 * bindings, and periodically thereafer as new adapters come online
564 * Status: Return value to NDIS
565 * BindContext: Handle provided by NDIS to track pending binding operations
566 * DeviceName: Name of the miniport device to bind to
567 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
568 * SystemSpecific2: Unused & must not be touched
571 /* XXX confirm that this is still true, or re-word the following comment */
572 /* we get to ignore BindContext because we will never pend an operation with NDIS */
573 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
574 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
580 PNDIS_PACKET NdisPacket
,
585 * FUNCTION: Transmits a packet
587 * Context = Pointer to context information (LAN_ADAPTER)
588 * NdisPacket = Pointer to NDIS packet to send
589 * Offset = Offset in packet where data starts
590 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
591 * Type = LAN protocol type (LAN_PROTO_*)
594 NDIS_STATUS NdisStatus
;
599 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
601 TI_DbgPrint(DEBUG_DATALINK
,
602 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
603 NdisPacket
, Offset
, Adapter
));
605 TI_DbgPrint(DEBUG_DATALINK
,
606 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
607 Adapter
->HWAddress
[0] & 0xff,
608 Adapter
->HWAddress
[1] & 0xff,
609 Adapter
->HWAddress
[2] & 0xff,
610 Adapter
->HWAddress
[3] & 0xff,
611 Adapter
->HWAddress
[4] & 0xff,
612 Adapter
->HWAddress
[5] & 0xff));
614 /* XXX arty -- Handled adjustment in a saner way than before ...
615 * not needed immediately */
616 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
618 if (Adapter
->State
== LAN_STATE_STARTED
) {
619 switch (Adapter
->Media
) {
620 case NdisMedium802_3
:
621 EHeader
= (PETH_HEADER
)Data
;
624 /* Unicast address */
625 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
627 /* Broadcast address */
628 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
631 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
635 EHeader
->EType
= ETYPE_IPv4
;
638 EHeader
->EType
= ETYPE_ARP
;
641 EHeader
->EType
= ETYPE_IPv6
;
645 /* Should not happen */
646 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
648 ProtocolSendComplete((NDIS_HANDLE
)Context
,
650 NDIS_STATUS_FAILURE
);
657 /* FIXME: Support other medias */
661 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
665 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
666 ((PCHAR
)LinkAddress
)[0] & 0xff,
667 ((PCHAR
)LinkAddress
)[1] & 0xff,
668 ((PCHAR
)LinkAddress
)[2] & 0xff,
669 ((PCHAR
)LinkAddress
)[3] & 0xff,
670 ((PCHAR
)LinkAddress
)[4] & 0xff,
671 ((PCHAR
)LinkAddress
)[5] & 0xff));
674 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
675 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
676 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
677 LanChainCompletion( Adapter
, NdisPacket
);
678 TI_DbgPrint(MID_TRACE
, ("NdisSend Done\n"));
679 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
682 if (NdisStatus
!= NDIS_STATUS_PENDING
)
683 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
687 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
693 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
694 OBJECT_ATTRIBUTES Attributes
;
697 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
698 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
702 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
703 PWCHAR RegistryValue
,
704 PIP_ADDRESS Address
) {
705 UNICODE_STRING ValueName
;
706 UNICODE_STRING UnicodeAddress
;
710 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
711 ANSI_STRING AnsiAddress
;
714 RtlInitUnicodeString(&ValueName
, RegistryValue
);
716 ZwQueryValueKey(RegHandle
,
718 KeyValuePartialInformation
,
723 if (!NT_SUCCESS(Status
))
725 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
726 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
728 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
729 UnicodeAddress
.Length
= Information
->DataLength
;
730 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
732 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
734 return STATUS_NO_MEMORY
;
736 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
737 if(!AnsiAddress
.Buffer
)
738 return STATUS_NO_MEMORY
;
740 AnsiAddress
.Length
= AnsiLen
;
741 AnsiAddress
.MaximumLength
= AnsiLen
;
743 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
744 if (!NT_SUCCESS(Status
)) {
745 exFreePool(AnsiAddress
.Buffer
);
746 return STATUS_UNSUCCESSFUL
;
749 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
750 AddrInitIPv4(Address
, inet_addr(AnsiAddress
.Buffer
));
752 return STATUS_SUCCESS
;
755 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
756 PWCHAR RegistryValue
,
757 PUNICODE_STRING String
) {
758 UNICODE_STRING ValueName
;
759 UNICODE_STRING UnicodeString
;
763 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
765 RtlInitUnicodeString(&ValueName
, RegistryValue
);
767 ZwQueryValueKey(RegHandle
,
769 KeyValuePartialInformation
,
774 if (!NT_SUCCESS(Status
))
776 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
777 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
779 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
780 UnicodeString
.Length
= Information
->DataLength
;
781 UnicodeString
.MaximumLength
= Information
->DataLength
;
784 (PWCHAR
)exAllocatePool( NonPagedPool
,
785 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
787 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
789 String
->MaximumLength
= UnicodeString
.MaximumLength
;
790 RtlCopyUnicodeString( String
, &UnicodeString
);
792 return STATUS_SUCCESS
;
795 static VOID GetSimpleAdapterNameFromRegistryPath
796 ( PUNICODE_STRING TargetString
,
797 PUNICODE_STRING RegistryPath
) {
798 PWCHAR i
, LastSlash
= NULL
;
799 UINT NewStringLength
= 0;
801 for( i
= RegistryPath
->Buffer
;
802 i
< RegistryPath
->Buffer
+
803 (RegistryPath
->Length
/ sizeof(WCHAR
));
804 i
++ ) if( *i
== '\\' ) LastSlash
= i
;
806 if( LastSlash
) LastSlash
++; else LastSlash
= RegistryPath
->Buffer
;
808 NewStringLength
= RegistryPath
->MaximumLength
-
809 ((LastSlash
- RegistryPath
->Buffer
) * sizeof(WCHAR
));
811 TargetString
->Buffer
=
812 (PWCHAR
)exAllocatePool( NonPagedPool
, NewStringLength
);
814 if( !TargetString
->Buffer
) {
815 TargetString
->Length
= TargetString
->MaximumLength
= 0;
819 TargetString
->Length
= TargetString
->MaximumLength
= NewStringLength
;
820 RtlCopyMemory( TargetString
->Buffer
, LastSlash
, NewStringLength
);
824 PLAN_ADAPTER Adapter
,
825 PNDIS_STRING RegistryPath
)
827 * FUNCTION: Binds a LAN adapter to IP layer
829 * Adapter = Pointer to LAN_ADAPTER structure
831 * We set the lookahead buffer size, set the packet filter and
832 * bind the adapter to IP layer
836 NDIS_STATUS NdisStatus
;
837 LLIP_BIND_INFO BindInfo
;
838 IP_ADDRESS DefaultGateway
, DefaultMask
= { 0 };
839 ULONG Lookahead
= LOOKAHEAD_SIZE
;
841 HANDLE RegHandle
= 0;
843 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
845 Adapter
->State
= LAN_STATE_OPENING
;
847 NdisStatus
= NDISCall(Adapter
,
848 NdisRequestSetInformation
,
849 OID_GEN_CURRENT_LOOKAHEAD
,
852 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
853 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
857 /* Bind the adapter to IP layer */
858 BindInfo
.Context
= Adapter
;
859 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
860 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
861 BindInfo
.MTU
= Adapter
->MTU
;
862 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
863 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
864 BindInfo
.Transmit
= LANTransmit
;
866 IF
= IPCreateInterface(&BindInfo
);
869 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
874 * Query per-adapter configuration from the registry
875 * In case anyone is curious: there *is* an Ndis configuration api
876 * for this sort of thing, but it doesn't really support things like
877 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
878 * protocol drivers developed for win2k and above just use the native
879 * services (ZwOpenKey, etc).
882 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
884 if(NT_SUCCESS(Status
))
885 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"DefaultGateway",
887 if(!NT_SUCCESS(Status
)) {
888 Status
= STATUS_SUCCESS
;
889 RtlZeroMemory( &DefaultGateway
, sizeof(DefaultGateway
) );
892 if(NT_SUCCESS(Status
))
893 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
895 if(NT_SUCCESS(Status
))
896 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
898 if(NT_SUCCESS(Status
)) {
899 Status
= ReadStringFromRegistry( RegHandle
, L
"DeviceDesc",
902 RtlZeroMemory( &IF
->Name
, sizeof( IF
->Name
) );
904 /* I think that not getting a devicedesc is not a fatal error */
905 if( !NT_SUCCESS(Status
) ) {
906 if( IF
->Name
.Buffer
) exFreePool( IF
->Name
.Buffer
);
907 GetSimpleAdapterNameFromRegistryPath( &IF
->Name
, RegistryPath
);
909 Status
= STATUS_SUCCESS
;
912 if(!NT_SUCCESS(Status
))
914 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
916 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
919 IPDestroyInterface(IF
);
925 ("--> Our IP address on this interface: '%s'\n",
930 ("--> Our net mask on this interface: '%s'\n",
933 if( DefaultGateway
.Address
.IPv4Address
) {
936 ("--> Our gateway is: '%s'\n",
937 A2S(&DefaultGateway
)));
939 /* Create a default route */
940 RouterCreateRoute( &DefaultMask
, /* Zero */
941 &DefaultMask
, /* Zero */
947 /* Get maximum link speed */
948 NdisStatus
= NDISCall(Adapter
,
949 NdisRequestQueryInformation
,
954 if( !NT_SUCCESS(NdisStatus
) )
955 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
957 /* Register interface with IP layer */
958 IPRegisterInterface(IF
);
960 /* Set packet filter so we can send and receive packets */
961 NdisStatus
= NDISCall(Adapter
,
962 NdisRequestSetInformation
,
963 OID_GEN_CURRENT_PACKET_FILTER
,
964 &Adapter
->PacketFilter
,
967 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
968 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
969 IPDestroyInterface(IF
);
973 Adapter
->Context
= IF
;
974 Adapter
->State
= LAN_STATE_STARTED
;
979 PLAN_ADAPTER Adapter
)
981 * FUNCTION: Unbinds a LAN adapter from IP layer
983 * Adapter = Pointer to LAN_ADAPTER structure
986 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
988 if (Adapter
->State
== LAN_STATE_STARTED
) {
989 PIP_INTERFACE IF
= Adapter
->Context
;
991 IPUnregisterInterface(IF
);
993 IPDestroyInterface(IF
);
998 NDIS_STATUS
LANRegisterAdapter(
999 PNDIS_STRING AdapterName
,
1000 PNDIS_STRING RegistryPath
)
1002 * FUNCTION: Registers protocol with an NDIS adapter
1004 * AdapterName = Pointer to string with name of adapter to register
1005 * Adapter = Address of pointer to a LAN_ADAPTER structure
1007 * Status of operation
1011 NDIS_STATUS NdisStatus
;
1012 NDIS_STATUS OpenStatus
;
1014 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1018 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1020 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
1022 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1023 return NDIS_STATUS_RESOURCES
;
1026 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1028 /* Put adapter in stopped state */
1029 IF
->State
= LAN_STATE_STOPPED
;
1031 /* Initialize protecting spin lock */
1032 KeInitializeSpinLock(&IF
->Lock
);
1034 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1036 /* Initialize array with media IDs we support */
1037 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1039 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1040 /* Open the adapter. */
1041 NdisOpenAdapter(&NdisStatus
,
1053 /* Wait until the adapter is opened */
1054 if (NdisStatus
== NDIS_STATUS_PENDING
)
1055 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1056 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1061 IF
->Media
= MediaArray
[MediaIndex
];
1063 /* Fill LAN_ADAPTER structure with some adapter specific information */
1064 switch (IF
->Media
) {
1065 case NdisMedium802_3
:
1066 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1067 IF
->BCastMask
= BCAST_ETH_MASK
;
1068 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1069 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1070 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1071 IF
->MinFrameSize
= 60;
1072 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1074 NDIS_PACKET_TYPE_BROADCAST
|
1075 NDIS_PACKET_TYPE_DIRECTED
|
1076 NDIS_PACKET_TYPE_MULTICAST
;
1080 /* Unsupported media */
1081 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1083 return NDIS_STATUS_NOT_SUPPORTED
;
1086 /* Get maximum frame size */
1087 NdisStatus
= NDISCall(IF
,
1088 NdisRequestQueryInformation
,
1089 OID_GEN_MAXIMUM_FRAME_SIZE
,
1092 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1097 /* Get maximum packet size */
1098 NdisStatus
= NDISCall(IF
,
1099 NdisRequestQueryInformation
,
1100 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1103 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1104 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1109 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1110 NdisStatus
= NDISCall(IF
,
1111 NdisRequestQueryInformation
,
1112 OID_GEN_MAXIMUM_SEND_PACKETS
,
1113 &IF
->MaxSendPackets
,
1115 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1116 /* Legacy NIC drivers may not support this query, if it fails we
1117 assume it can send at least one packet per call to NdisSend(Packets) */
1118 IF
->MaxSendPackets
= 1;
1120 /* Get current hardware address */
1121 NdisStatus
= NDISCall(IF
,
1122 NdisRequestQueryInformation
,
1125 IF
->HWAddressLength
);
1126 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1127 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1132 /* Get maximum link speed */
1133 NdisStatus
= NDISCall(IF
,
1134 NdisRequestQueryInformation
,
1138 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1139 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1144 /* Convert returned link speed to bps (it is in 100bps increments) */
1145 IF
->Speed
= Speed
* 100L;
1147 /* Add adapter to the adapter list */
1148 ExInterlockedInsertTailList(&AdapterListHead
,
1152 /* Bind adapter to IP layer */
1153 BindAdapter(IF
, RegistryPath
);
1155 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1157 return NDIS_STATUS_SUCCESS
;
1161 NDIS_STATUS
LANUnregisterAdapter(
1162 PLAN_ADAPTER Adapter
)
1164 * FUNCTION: Unregisters protocol with NDIS adapter
1166 * Adapter = Pointer to a LAN_ADAPTER structure
1168 * Status of operation
1172 NDIS_HANDLE NdisHandle
;
1173 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1175 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1177 /* Unlink the adapter from the list */
1178 RemoveEntryList(&Adapter
->ListEntry
);
1180 /* Unbind adapter from IP layer */
1181 UnbindAdapter(Adapter
);
1183 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1184 NdisHandle
= Adapter
->NdisHandle
;
1186 Adapter
->NdisHandle
= NULL
;
1187 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1189 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1190 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1191 TcpipWaitForSingleObject(&Adapter
->Event
,
1196 NdisStatus
= Adapter
->NdisStatus
;
1199 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1201 FreeAdapter(Adapter
);
1203 return NDIS_STATUS_SUCCESS
;
1207 NTSTATUS
LANRegisterProtocol(
1210 * FUNCTION: Registers this protocol driver with NDIS
1212 * Name = Name of this protocol driver
1214 * Status of operation
1217 NDIS_STATUS NdisStatus
;
1218 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1220 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1222 InitializeListHead(&AdapterListHead
);
1223 KeInitializeSpinLock(&AdapterListLock
);
1225 /* Set up protocol characteristics */
1226 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1227 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1228 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1229 ProtChars
.Name
.Length
= Name
->Length
;
1230 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1231 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1232 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1233 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1234 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1235 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1236 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1237 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1238 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1239 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1240 ProtChars
.StatusHandler
= ProtocolStatus
;
1241 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1242 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1244 /* Try to register protocol */
1245 NdisRegisterProtocol(&NdisStatus
,
1246 &NdisProtocolHandle
,
1248 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1249 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1251 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1252 return (NTSTATUS
)NdisStatus
;
1255 ProtocolRegistered
= TRUE
;
1257 return STATUS_SUCCESS
;
1261 VOID
LANUnregisterProtocol(
1264 * FUNCTION: Unregisters this protocol driver with NDIS
1265 * NOTES: Does not care wether we are already registered
1268 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1270 if (ProtocolRegistered
) {
1271 NDIS_STATUS NdisStatus
;
1272 PLIST_ENTRY CurrentEntry
;
1273 PLIST_ENTRY NextEntry
;
1274 PLAN_ADAPTER Current
;
1277 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1279 /* Search the list and remove every adapter we find */
1280 CurrentEntry
= AdapterListHead
.Flink
;
1281 while (CurrentEntry
!= &AdapterListHead
) {
1282 NextEntry
= CurrentEntry
->Flink
;
1283 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1285 LANUnregisterAdapter(Current
);
1286 CurrentEntry
= NextEntry
;
1289 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1291 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1292 ProtocolRegistered
= FALSE
;
1297 InitializeListHead( &LanWorkList
);
1298 InitializeListHead( &LanSendCompleteList
);
1299 KeInitializeSpinLock( &LanSendCompleteLock
);
1300 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1303 VOID
LANShutdown() {
1305 PLAN_WQ_ITEM WorkItem
;
1306 PLIST_ENTRY ListEntry
;
1308 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1309 while( !IsListEmpty( &LanWorkList
) ) {
1310 ListEntry
= RemoveHeadList( &LanWorkList
);
1311 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1312 FreeNdisPacket( WorkItem
->Packet
);
1313 ExFreePool( WorkItem
);
1315 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
1317 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
1318 while( !IsListEmpty( &LanSendCompleteList
) ) {
1319 ListEntry
= RemoveHeadList( &LanSendCompleteList
);
1320 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1321 FreeNdisPacket( WorkItem
->Packet
);
1322 ExFreePool( WorkItem
);
1324 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);