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 LanReceiveWorkerCalled
++;
283 ASSERT(LanReceiveWorkerCalled
<= TransferDataCompleteCalled
);
285 Packet
= WorkItem
->Packet
;
286 Adapter
= WorkItem
->Adapter
;
287 BytesTransferred
= WorkItem
->BytesTransferred
;
289 ExFreePool( WorkItem
);
291 IPPacket
.NdisPacket
= Packet
;
293 NdisGetFirstBufferFromPacket(Packet
,
296 &IPPacket
.ContigSize
,
297 &IPPacket
.TotalSize
);
299 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
300 /* Determine which upper layer protocol that should receive
301 this packet and pass it to the correct receive handler */
303 TI_DbgPrint(MID_TRACE
,
304 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
305 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
308 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
309 IPPacket
.Position
= 0;
313 ("Ether Type = %x ContigSize = %d Total = %d\n",
314 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
316 switch (PacketType
) {
319 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
320 IPReceive(Adapter
->Context
, &IPPacket
);
323 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
324 ARPReceive(Adapter
->Context
, &IPPacket
);
329 FreeNdisPacket( Packet
);
333 VOID STDCALL
ProtocolTransferDataComplete(
334 NDIS_HANDLE BindingContext
,
337 UINT BytesTransferred
)
339 * FUNCTION: Called by NDIS to complete reception of data
341 * BindingContext = Pointer to a device context (LAN_ADAPTER)
342 * Packet = Pointer to a packet descriptor
343 * Status = Status of the operation
344 * BytesTransferred = Number of bytes transferred
346 * If the packet was successfully received, determine the protocol
347 * type and pass it to the correct receive handler
352 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
355 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
357 if( Status
!= NDIS_STATUS_SUCCESS
) return;
358 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
360 TransferDataCompleteCalled
++;
362 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
364 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
366 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
370 WorkStart
= IsListEmpty( &LanWorkList
);
371 WQItem
->Packet
= Packet
;
372 WQItem
->Adapter
= Adapter
;
373 WQItem
->BytesTransferred
= BytesTransferred
;
374 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
376 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
377 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
380 NDIS_STATUS STDCALL
ProtocolReceive(
381 NDIS_HANDLE BindingContext
,
382 NDIS_HANDLE MacReceiveContext
,
384 UINT HeaderBufferSize
,
385 PVOID LookaheadBuffer
,
386 UINT LookaheadBufferSize
,
389 * FUNCTION: Called by NDIS when a packet has been received on the physical link
391 * BindingContext = Pointer to a device context (LAN_ADAPTER)
392 * MacReceiveContext = Handle used by underlying NIC driver
393 * HeaderBuffer = Pointer to a buffer containing the packet header
394 * HeaderBufferSize = Number of bytes in HeaderBuffer
395 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
396 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
397 * PacketSize = Overall size of the packet (not including header)
399 * Status of operation
403 UINT PacketType
, BytesTransferred
;
407 NDIS_STATUS NdisStatus
;
408 PNDIS_PACKET NdisPacket
;
409 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
410 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
413 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
415 if (Adapter
->State
!= LAN_STATE_STARTED
) {
416 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
417 return NDIS_STATUS_NOT_ACCEPTED
;
420 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
421 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
422 return NDIS_STATUS_NOT_ACCEPTED
;
425 if (Adapter
->Media
== NdisMedium802_3
) {
426 /* Ethernet and IEEE 802.3 frames can be destinguished by
427 looking at the IEEE 802.3 length field. This field is
428 less than or equal to 1500 for a valid IEEE 802.3 frame
429 and larger than 1500 is it's a valid EtherType value.
430 See RFC 1122, section 2.3.3 for more information */
431 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
432 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
433 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
434 return NDIS_STATUS_NOT_ACCEPTED
;
436 /* We use EtherType constants to destinguish packet types */
439 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
440 /* FIXME: Support other medias */
441 return NDIS_STATUS_NOT_ACCEPTED
;
444 /* Get a transfer data packet */
446 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
447 Adapter
, Adapter
->MTU
));
449 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
451 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
452 PacketSize
+ HeaderBufferSize
);
453 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
454 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
455 return NDIS_STATUS_NOT_ACCEPTED
;
458 PC(NdisPacket
)->PacketType
= PacketType
;
460 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
462 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
464 IPPacket
.NdisPacket
= NdisPacket
;
465 IPPacket
.Position
= 0;
467 TransferDataCalled
++;
469 if (LookaheadBufferSize
== PacketSize
)
471 /* Optimized code path for packets that are fully contained in
472 * the lookahead buffer. */
473 NdisCopyLookaheadData(BufferData
,
476 Adapter
->MacOptions
);
480 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
482 ASSERT(PacketSize
<= Adapter
->MTU
);
484 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
485 MacReceiveContext
, 0, PacketSize
,
486 NdisPacket
, &BytesTransferred
);
490 BytesTransferred
= 0;
493 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
494 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
496 if (NdisStatus
!= NDIS_STATUS_PENDING
)
497 ProtocolTransferDataComplete(BindingContext
,
502 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
504 return NDIS_STATUS_SUCCESS
;
508 VOID STDCALL
ProtocolReceiveComplete(
509 NDIS_HANDLE BindingContext
)
511 * FUNCTION: Called by NDIS when we're done receiving data
513 * BindingContext = Pointer to a device context (LAN_ADAPTER)
516 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
520 VOID STDCALL
ProtocolStatus(
521 NDIS_HANDLE BindingContext
,
522 NDIS_STATUS GenerelStatus
,
524 UINT StatusBufferSize
)
526 * FUNCTION: Called by NDIS when the underlying driver has changed state
528 * BindingContext = Pointer to a device context (LAN_ADAPTER)
529 * GenerelStatus = A generel status code
530 * StatusBuffer = Pointer to a buffer with medium-specific data
531 * StatusBufferSize = Number of bytes in StatusBuffer
534 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
538 VOID STDCALL
ProtocolStatusComplete(
539 NDIS_HANDLE NdisBindingContext
)
541 * FUNCTION: Called by NDIS when a status-change has occurred
543 * BindingContext = Pointer to a device context (LAN_ADAPTER)
546 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
549 VOID STDCALL
ProtocolBindAdapter(
550 OUT PNDIS_STATUS Status
,
551 IN NDIS_HANDLE BindContext
,
552 IN PNDIS_STRING DeviceName
,
553 IN PVOID SystemSpecific1
,
554 IN PVOID SystemSpecific2
)
556 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
557 * bindings, and periodically thereafer as new adapters come online
559 * Status: Return value to NDIS
560 * BindContext: Handle provided by NDIS to track pending binding operations
561 * DeviceName: Name of the miniport device to bind to
562 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
563 * SystemSpecific2: Unused & must not be touched
566 /* XXX confirm that this is still true, or re-word the following comment */
567 /* we get to ignore BindContext because we will never pend an operation with NDIS */
568 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
569 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
575 PNDIS_PACKET NdisPacket
,
580 * FUNCTION: Transmits a packet
582 * Context = Pointer to context information (LAN_ADAPTER)
583 * NdisPacket = Pointer to NDIS packet to send
584 * Offset = Offset in packet where data starts
585 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
586 * Type = LAN protocol type (LAN_PROTO_*)
589 NDIS_STATUS NdisStatus
;
594 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
596 TI_DbgPrint(DEBUG_DATALINK
,
597 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
598 NdisPacket
, Offset
, Adapter
));
600 TI_DbgPrint(DEBUG_DATALINK
,
601 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
602 Adapter
->HWAddress
[0] & 0xff,
603 Adapter
->HWAddress
[1] & 0xff,
604 Adapter
->HWAddress
[2] & 0xff,
605 Adapter
->HWAddress
[3] & 0xff,
606 Adapter
->HWAddress
[4] & 0xff,
607 Adapter
->HWAddress
[5] & 0xff));
609 /* XXX arty -- Handled adjustment in a saner way than before ...
610 * not needed immediately */
611 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
613 if (Adapter
->State
== LAN_STATE_STARTED
) {
614 switch (Adapter
->Media
) {
615 case NdisMedium802_3
:
616 EHeader
= (PETH_HEADER
)Data
;
619 /* Unicast address */
620 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
622 /* Broadcast address */
623 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
626 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
630 EHeader
->EType
= ETYPE_IPv4
;
633 EHeader
->EType
= ETYPE_ARP
;
636 EHeader
->EType
= ETYPE_IPv6
;
640 /* Should not happen */
641 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
643 ProtocolSendComplete((NDIS_HANDLE
)Context
,
645 NDIS_STATUS_FAILURE
);
652 /* FIXME: Support other medias */
656 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
660 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
661 ((PCHAR
)LinkAddress
)[0] & 0xff,
662 ((PCHAR
)LinkAddress
)[1] & 0xff,
663 ((PCHAR
)LinkAddress
)[2] & 0xff,
664 ((PCHAR
)LinkAddress
)[3] & 0xff,
665 ((PCHAR
)LinkAddress
)[4] & 0xff,
666 ((PCHAR
)LinkAddress
)[5] & 0xff));
669 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
670 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
671 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
672 LanChainCompletion( Adapter
, NdisPacket
);
673 TI_DbgPrint(MID_TRACE
, ("NdisSend Done\n"));
674 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
676 if (NdisStatus
!= NDIS_STATUS_PENDING
)
677 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
679 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
684 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
685 OBJECT_ATTRIBUTES Attributes
;
688 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
689 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
693 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
694 PWCHAR RegistryValue
,
695 PIP_ADDRESS Address
) {
696 UNICODE_STRING ValueName
;
697 UNICODE_STRING UnicodeAddress
;
701 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
702 ANSI_STRING AnsiAddress
;
705 RtlInitUnicodeString(&ValueName
, RegistryValue
);
707 ZwQueryValueKey(RegHandle
,
709 KeyValuePartialInformation
,
714 if (!NT_SUCCESS(Status
))
716 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
717 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
719 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
720 UnicodeAddress
.Length
= Information
->DataLength
;
721 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
723 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
725 return STATUS_NO_MEMORY
;
727 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
728 if(!AnsiAddress
.Buffer
)
729 return STATUS_NO_MEMORY
;
731 AnsiAddress
.Length
= AnsiLen
;
732 AnsiAddress
.MaximumLength
= AnsiLen
;
734 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
735 if (!NT_SUCCESS(Status
)) {
736 exFreePool(AnsiAddress
.Buffer
);
737 return STATUS_UNSUCCESSFUL
;
740 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
741 AddrInitIPv4(Address
, inet_addr(AnsiAddress
.Buffer
));
743 return STATUS_SUCCESS
;
746 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
747 PWCHAR RegistryValue
,
748 PUNICODE_STRING String
) {
749 UNICODE_STRING ValueName
;
750 UNICODE_STRING UnicodeString
;
754 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
756 RtlInitUnicodeString(&ValueName
, RegistryValue
);
758 ZwQueryValueKey(RegHandle
,
760 KeyValuePartialInformation
,
765 if (!NT_SUCCESS(Status
))
767 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
768 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
770 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
771 UnicodeString
.Length
= Information
->DataLength
;
772 UnicodeString
.MaximumLength
= Information
->DataLength
;
775 (PWCHAR
)exAllocatePool( NonPagedPool
,
776 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
778 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
780 String
->MaximumLength
= UnicodeString
.MaximumLength
;
781 RtlCopyUnicodeString( String
, &UnicodeString
);
783 return STATUS_SUCCESS
;
786 static VOID GetSimpleAdapterNameFromRegistryPath
787 ( PUNICODE_STRING TargetString
,
788 PUNICODE_STRING RegistryPath
) {
789 PWCHAR i
, LastSlash
= NULL
;
790 UINT NewStringLength
= 0;
792 for( i
= RegistryPath
->Buffer
;
793 i
< RegistryPath
->Buffer
+
794 (RegistryPath
->Length
/ sizeof(WCHAR
));
795 i
++ ) if( *i
== '\\' ) LastSlash
= i
;
797 if( LastSlash
) LastSlash
++; else LastSlash
= RegistryPath
->Buffer
;
799 NewStringLength
= RegistryPath
->MaximumLength
-
800 ((LastSlash
- RegistryPath
->Buffer
) * sizeof(WCHAR
));
802 TargetString
->Buffer
=
803 (PWCHAR
)exAllocatePool( NonPagedPool
, NewStringLength
);
805 if( !TargetString
->Buffer
) {
806 TargetString
->Length
= TargetString
->MaximumLength
= 0;
810 TargetString
->Length
= TargetString
->MaximumLength
= NewStringLength
;
811 RtlCopyMemory( TargetString
->Buffer
, LastSlash
, NewStringLength
);
815 PLAN_ADAPTER Adapter
,
816 PNDIS_STRING RegistryPath
)
818 * FUNCTION: Binds a LAN adapter to IP layer
820 * Adapter = Pointer to LAN_ADAPTER structure
822 * We set the lookahead buffer size, set the packet filter and
823 * bind the adapter to IP layer
827 NDIS_STATUS NdisStatus
;
828 LLIP_BIND_INFO BindInfo
;
829 IP_ADDRESS DefaultGateway
, DefaultMask
= { 0 };
830 ULONG Lookahead
= LOOKAHEAD_SIZE
;
832 HANDLE RegHandle
= 0;
834 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
836 Adapter
->State
= LAN_STATE_OPENING
;
838 NdisStatus
= NDISCall(Adapter
,
839 NdisRequestSetInformation
,
840 OID_GEN_CURRENT_LOOKAHEAD
,
843 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
844 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
848 /* Bind the adapter to IP layer */
849 BindInfo
.Context
= Adapter
;
850 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
851 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
852 BindInfo
.MTU
= Adapter
->MTU
;
853 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
854 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
855 BindInfo
.Transmit
= LANTransmit
;
857 IF
= IPCreateInterface(&BindInfo
);
860 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
865 * Query per-adapter configuration from the registry
866 * In case anyone is curious: there *is* an Ndis configuration api
867 * for this sort of thing, but it doesn't really support things like
868 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
869 * protocol drivers developed for win2k and above just use the native
870 * services (ZwOpenKey, etc).
873 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
875 if(NT_SUCCESS(Status
))
876 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"DefaultGateway",
878 if(!NT_SUCCESS(Status
)) {
879 Status
= STATUS_SUCCESS
;
880 RtlZeroMemory( &DefaultGateway
, sizeof(DefaultGateway
) );
883 if(NT_SUCCESS(Status
))
884 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
886 if(NT_SUCCESS(Status
))
887 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
889 if(NT_SUCCESS(Status
)) {
890 Status
= ReadStringFromRegistry( RegHandle
, L
"DeviceDesc",
893 RtlZeroMemory( &IF
->Name
, sizeof( IF
->Name
) );
895 /* I think that not getting a devicedesc is not a fatal error */
896 if( !NT_SUCCESS(Status
) ) {
897 if( IF
->Name
.Buffer
) exFreePool( IF
->Name
.Buffer
);
898 GetSimpleAdapterNameFromRegistryPath( &IF
->Name
, RegistryPath
);
900 Status
= STATUS_SUCCESS
;
903 if(!NT_SUCCESS(Status
))
905 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
907 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
910 IPDestroyInterface(IF
);
916 ("--> Our IP address on this interface: '%s'\n",
921 ("--> Our net mask on this interface: '%s'\n",
924 if( DefaultGateway
.Address
.IPv4Address
) {
927 ("--> Our gateway is: '%s'\n",
928 A2S(&DefaultGateway
)));
930 /* Create a default route */
931 RouterCreateRoute( &DefaultMask
, /* Zero */
932 &DefaultMask
, /* Zero */
938 /* Register interface with IP layer */
939 IPRegisterInterface(IF
);
941 /* Set packet filter so we can send and receive packets */
942 NdisStatus
= NDISCall(Adapter
,
943 NdisRequestSetInformation
,
944 OID_GEN_CURRENT_PACKET_FILTER
,
945 &Adapter
->PacketFilter
,
947 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
948 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
949 IPDestroyInterface(IF
);
953 Adapter
->Context
= IF
;
954 Adapter
->State
= LAN_STATE_STARTED
;
959 PLAN_ADAPTER Adapter
)
961 * FUNCTION: Unbinds a LAN adapter from IP layer
963 * Adapter = Pointer to LAN_ADAPTER structure
966 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
968 if (Adapter
->State
== LAN_STATE_STARTED
) {
969 PIP_INTERFACE IF
= Adapter
->Context
;
971 IPUnregisterInterface(IF
);
973 IPDestroyInterface(IF
);
978 NDIS_STATUS
LANRegisterAdapter(
979 PNDIS_STRING AdapterName
,
980 PNDIS_STRING RegistryPath
)
982 * FUNCTION: Registers protocol with an NDIS adapter
984 * AdapterName = Pointer to string with name of adapter to register
985 * Adapter = Address of pointer to a LAN_ADAPTER structure
987 * Status of operation
991 NDIS_STATUS NdisStatus
;
992 NDIS_STATUS OpenStatus
;
994 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
998 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1000 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
1002 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1003 return NDIS_STATUS_RESOURCES
;
1006 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1008 /* Put adapter in stopped state */
1009 IF
->State
= LAN_STATE_STOPPED
;
1011 /* Initialize protecting spin lock */
1012 KeInitializeSpinLock(&IF
->Lock
);
1014 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1016 /* Initialize array with media IDs we support */
1017 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1019 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1020 /* Open the adapter. */
1021 NdisOpenAdapter(&NdisStatus
,
1033 /* Wait until the adapter is opened */
1034 if (NdisStatus
== NDIS_STATUS_PENDING
)
1035 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1036 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1041 IF
->Media
= MediaArray
[MediaIndex
];
1043 /* Fill LAN_ADAPTER structure with some adapter specific information */
1044 switch (IF
->Media
) {
1045 case NdisMedium802_3
:
1046 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1047 IF
->BCastMask
= BCAST_ETH_MASK
;
1048 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1049 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1050 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1051 IF
->MinFrameSize
= 60;
1052 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1054 NDIS_PACKET_TYPE_BROADCAST
|
1055 NDIS_PACKET_TYPE_DIRECTED
|
1056 NDIS_PACKET_TYPE_MULTICAST
;
1060 /* Unsupported media */
1061 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1063 return NDIS_STATUS_NOT_SUPPORTED
;
1066 /* Get maximum frame size */
1067 NdisStatus
= NDISCall(IF
,
1068 NdisRequestQueryInformation
,
1069 OID_GEN_MAXIMUM_FRAME_SIZE
,
1072 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1077 /* Get maximum packet size */
1078 NdisStatus
= NDISCall(IF
,
1079 NdisRequestQueryInformation
,
1080 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1083 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1084 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1089 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1090 NdisStatus
= NDISCall(IF
,
1091 NdisRequestQueryInformation
,
1092 OID_GEN_MAXIMUM_SEND_PACKETS
,
1093 &IF
->MaxSendPackets
,
1095 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1096 /* Legacy NIC drivers may not support this query, if it fails we
1097 assume it can send at least one packet per call to NdisSend(Packets) */
1098 IF
->MaxSendPackets
= 1;
1100 /* Get current hardware address */
1101 NdisStatus
= NDISCall(IF
,
1102 NdisRequestQueryInformation
,
1105 IF
->HWAddressLength
);
1106 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1107 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1112 /* Get maximum link speed */
1113 NdisStatus
= NDISCall(IF
,
1114 NdisRequestQueryInformation
,
1118 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1119 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1124 /* Convert returned link speed to bps (it is in 100bps increments) */
1125 IF
->Speed
= Speed
* 100L;
1127 /* Add adapter to the adapter list */
1128 ExInterlockedInsertTailList(&AdapterListHead
,
1132 /* Bind adapter to IP layer */
1133 BindAdapter(IF
, RegistryPath
);
1135 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1137 return NDIS_STATUS_SUCCESS
;
1141 NDIS_STATUS
LANUnregisterAdapter(
1142 PLAN_ADAPTER Adapter
)
1144 * FUNCTION: Unregisters protocol with NDIS adapter
1146 * Adapter = Pointer to a LAN_ADAPTER structure
1148 * Status of operation
1152 NDIS_HANDLE NdisHandle
;
1153 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1155 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1157 /* Unlink the adapter from the list */
1158 RemoveEntryList(&Adapter
->ListEntry
);
1160 /* Unbind adapter from IP layer */
1161 UnbindAdapter(Adapter
);
1163 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1164 NdisHandle
= Adapter
->NdisHandle
;
1166 Adapter
->NdisHandle
= NULL
;
1167 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1169 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1170 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1171 TcpipWaitForSingleObject(&Adapter
->Event
,
1176 NdisStatus
= Adapter
->NdisStatus
;
1179 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1181 FreeAdapter(Adapter
);
1183 return NDIS_STATUS_SUCCESS
;
1187 NTSTATUS
LANRegisterProtocol(
1190 * FUNCTION: Registers this protocol driver with NDIS
1192 * Name = Name of this protocol driver
1194 * Status of operation
1197 NDIS_STATUS NdisStatus
;
1198 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1200 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1202 InitializeListHead(&AdapterListHead
);
1203 KeInitializeSpinLock(&AdapterListLock
);
1205 /* Set up protocol characteristics */
1206 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1207 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1208 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1209 ProtChars
.Name
.Length
= Name
->Length
;
1210 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1211 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1212 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1213 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1214 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1215 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1216 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1217 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1218 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1219 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1220 ProtChars
.StatusHandler
= ProtocolStatus
;
1221 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1222 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1224 /* Try to register protocol */
1225 NdisRegisterProtocol(&NdisStatus
,
1226 &NdisProtocolHandle
,
1228 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1229 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1231 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1232 return (NTSTATUS
)NdisStatus
;
1235 ProtocolRegistered
= TRUE
;
1237 return STATUS_SUCCESS
;
1241 VOID
LANUnregisterProtocol(
1244 * FUNCTION: Unregisters this protocol driver with NDIS
1245 * NOTES: Does not care wether we are already registered
1248 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1250 if (ProtocolRegistered
) {
1251 NDIS_STATUS NdisStatus
;
1252 PLIST_ENTRY CurrentEntry
;
1253 PLIST_ENTRY NextEntry
;
1254 PLAN_ADAPTER Current
;
1257 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1259 /* Search the list and remove every adapter we find */
1260 CurrentEntry
= AdapterListHead
.Flink
;
1261 while (CurrentEntry
!= &AdapterListHead
) {
1262 NextEntry
= CurrentEntry
->Flink
;
1263 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1265 LANUnregisterAdapter(Current
);
1266 CurrentEntry
= NextEntry
;
1269 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1271 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1272 ProtocolRegistered
= FALSE
;
1277 InitializeListHead( &LanWorkList
);
1278 InitializeListHead( &LanSendCompleteList
);
1279 KeInitializeSpinLock( &LanSendCompleteLock
);
1280 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1283 VOID
LANShutdown() {
1285 PLAN_WQ_ITEM WorkItem
;
1286 PLIST_ENTRY ListEntry
;
1288 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1289 while( !IsListEmpty( &LanWorkList
) ) {
1290 ListEntry
= RemoveHeadList( &LanWorkList
);
1291 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1292 FreeNdisPacket( WorkItem
->Packet
);
1293 ExFreePool( WorkItem
);
1295 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);
1297 KeAcquireSpinLock( &LanSendCompleteLock
, &OldIrql
);
1298 while( !IsListEmpty( &LanSendCompleteList
) ) {
1299 ListEntry
= RemoveHeadList( &LanSendCompleteList
);
1300 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1301 FreeNdisPacket( WorkItem
->Packet
);
1302 ExFreePool( WorkItem
);
1304 KeReleaseSpinLock( &LanSendCompleteLock
, OldIrql
);