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 typedef struct _LAN_WQ_ITEM
{
17 UINT BytesTransferred
;
18 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
20 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
21 BOOLEAN ProtocolRegistered
= FALSE
;
22 LIST_ENTRY AdapterListHead
;
23 KSPIN_LOCK AdapterListLock
;
25 /* Work around being called back into afd at Dpc level */
26 KSPIN_LOCK LanWorkLock
;
27 LIST_ENTRY LanWorkList
;
28 WORK_QUEUE_ITEM LanWorkItem
;
32 NDIS_REQUEST_TYPE Type
,
37 * FUNCTION: Send a request to NDIS
39 * Adapter = Pointer to a LAN_ADAPTER structure
40 * Type = Type of request (Set or Query)
41 * OID = Value to be set/queried for
42 * Buffer = Pointer to a buffer to use
43 * Length = Number of bytes in Buffer
49 NDIS_STATUS NdisStatus
;
51 Request
.RequestType
= Type
;
52 if (Type
== NdisRequestSetInformation
) {
53 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
54 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
55 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
57 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
58 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
59 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
62 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
63 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
65 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
68 /* Wait for NDIS to complete the request */
69 if (NdisStatus
== NDIS_STATUS_PENDING
) {
70 KeWaitForSingleObject(&Adapter
->Event
,
75 NdisStatus
= Adapter
->NdisStatus
;
85 * FUNCTION: Frees memory for a LAN_ADAPTER structure
87 * Adapter = Pointer to LAN_ADAPTER structure to free
94 VOID STDCALL
ProtocolOpenAdapterComplete(
95 NDIS_HANDLE BindingContext
,
97 NDIS_STATUS OpenErrorStatus
)
99 * FUNCTION: Called by NDIS to complete opening of an adapter
101 * BindingContext = Pointer to a device context (LAN_ADAPTER)
102 * Status = Status of the operation
103 * OpenErrorStatus = Additional status information
106 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
108 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
110 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
114 VOID STDCALL
ProtocolCloseAdapterComplete(
115 NDIS_HANDLE BindingContext
,
118 * FUNCTION: Called by NDIS to complete closing an adapter
120 * BindingContext = Pointer to a device context (LAN_ADAPTER)
121 * Status = Status of the operation
124 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
126 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
128 Adapter
->NdisStatus
= Status
;
130 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
134 VOID STDCALL
ProtocolResetComplete(
135 NDIS_HANDLE BindingContext
,
138 * FUNCTION: Called by NDIS to complete resetting an adapter
140 * BindingContext = Pointer to a device context (LAN_ADAPTER)
141 * Status = Status of the operation
144 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
148 VOID STDCALL
ProtocolRequestComplete(
149 NDIS_HANDLE BindingContext
,
150 PNDIS_REQUEST NdisRequest
,
153 * FUNCTION: Called by NDIS to complete a request
155 * BindingContext = Pointer to a device context (LAN_ADAPTER)
156 * NdisRequest = Pointer to an object describing the request
157 * Status = Status of the operation
160 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
162 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
164 /* Save status of request and signal an event */
165 Adapter
->NdisStatus
= Status
;
167 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
171 VOID STDCALL
ProtocolSendComplete(
172 NDIS_HANDLE BindingContext
,
176 * FUNCTION: Called by NDIS to complete sending process
178 * BindingContext = Pointer to a device context (LAN_ADAPTER)
179 * Packet = Pointer to a packet descriptor
180 * Status = Status of the operation
183 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
184 ASSERT_KM_POINTER(Packet
);
185 ASSERT_KM_POINTER(PC(Packet
));
186 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
187 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
188 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
191 VOID STDCALL
LanReceiveWorker( PVOID Context
) {
193 PLIST_ENTRY ListEntry
;
194 PLAN_WQ_ITEM WorkItem
;
196 PLAN_ADAPTER Adapter
;
197 UINT BytesTransferred
;
198 PNDIS_BUFFER NdisBuffer
;
202 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
205 ExInterlockedRemoveHeadList( &LanWorkList
, &LanWorkLock
)) ) {
206 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
208 Packet
= WorkItem
->Packet
;
209 Adapter
= WorkItem
->Adapter
;
210 BytesTransferred
= WorkItem
->BytesTransferred
;
212 ExFreePool( WorkItem
);
214 IPPacket
.NdisPacket
= Packet
;
216 NdisGetFirstBufferFromPacket(Packet
,
219 &IPPacket
.ContigSize
,
220 &IPPacket
.TotalSize
);
222 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
223 /* Determine which upper layer protocol that should receive
224 this packet and pass it to the correct receive handler */
226 TI_DbgPrint(MID_TRACE
,
227 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
228 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
231 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
232 IPPacket
.Position
= 0;
236 ("Ether Type = %x ContigSize = %d Total = %d\n",
237 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
239 switch (PacketType
) {
242 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
243 IPReceive(Adapter
->Context
, &IPPacket
);
246 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
247 ARPReceive(Adapter
->Context
, &IPPacket
);
252 FreeNdisPacket( Packet
);
256 VOID STDCALL
ProtocolTransferDataComplete(
257 NDIS_HANDLE BindingContext
,
260 UINT BytesTransferred
)
262 * FUNCTION: Called by NDIS to complete reception of data
264 * BindingContext = Pointer to a device context (LAN_ADAPTER)
265 * Packet = Pointer to a packet descriptor
266 * Status = Status of the operation
267 * BytesTransferred = Number of bytes transferred
269 * If the packet was successfully received, determine the protocol
270 * type and pass it to the correct receive handler
275 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
277 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
279 if( Status
!= NDIS_STATUS_SUCCESS
) return;
280 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
281 if( !WQItem
) return;
283 TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock
);
284 WorkStart
= IsListEmpty( &LanWorkList
);
285 WQItem
->Packet
= Packet
;
286 WQItem
->Adapter
= Adapter
;
287 WQItem
->BytesTransferred
= BytesTransferred
;
288 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
290 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
291 TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock
);
294 NDIS_STATUS STDCALL
ProtocolReceive(
295 NDIS_HANDLE BindingContext
,
296 NDIS_HANDLE MacReceiveContext
,
298 UINT HeaderBufferSize
,
299 PVOID LookaheadBuffer
,
300 UINT LookaheadBufferSize
,
303 * FUNCTION: Called by NDIS when a packet has been received on the physical link
305 * BindingContext = Pointer to a device context (LAN_ADAPTER)
306 * MacReceiveContext = Handle used by underlying NIC driver
307 * HeaderBuffer = Pointer to a buffer containing the packet header
308 * HeaderBufferSize = Number of bytes in HeaderBuffer
309 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
310 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
311 * PacketSize = Overall size of the packet (not including header)
313 * Status of operation
317 UINT PacketType
, BytesTransferred
;
321 NDIS_STATUS NdisStatus
;
322 PNDIS_PACKET NdisPacket
;
323 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
324 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
326 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
328 if (Adapter
->State
!= LAN_STATE_STARTED
) {
329 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
330 return NDIS_STATUS_NOT_ACCEPTED
;
333 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
334 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
335 return NDIS_STATUS_NOT_ACCEPTED
;
338 if (Adapter
->Media
== NdisMedium802_3
) {
339 /* Ethernet and IEEE 802.3 frames can be destinguished by
340 looking at the IEEE 802.3 length field. This field is
341 less than or equal to 1500 for a valid IEEE 802.3 frame
342 and larger than 1500 is it's a valid EtherType value.
343 See RFC 1122, section 2.3.3 for more information */
344 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
345 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
346 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
347 return NDIS_STATUS_NOT_ACCEPTED
;
349 /* We use EtherType constants to destinguish packet types */
352 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
353 /* FIXME: Support other medias */
354 return NDIS_STATUS_NOT_ACCEPTED
;
357 /* Get a transfer data packet */
359 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
360 Adapter
, Adapter
->MTU
));
362 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
363 PacketSize
+ HeaderBufferSize
);
364 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
365 return NDIS_STATUS_NOT_ACCEPTED
;
368 PC(NdisPacket
)->PacketType
= PacketType
;
370 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
372 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
374 IPPacket
.NdisPacket
= NdisPacket
;
375 IPPacket
.Position
= 0;
377 if (LookaheadBufferSize
== PacketSize
)
379 /* Optimized code path for packets that are fully contained in
380 * the lookahead buffer. */
381 NdisCopyLookaheadData(BufferData
,
384 Adapter
->MacOptions
);
388 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
390 ASSERT(PacketSize
<= Adapter
->MTU
);
392 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
393 MacReceiveContext
, 0, PacketSize
,
394 NdisPacket
, &BytesTransferred
);
398 BytesTransferred
= 0;
401 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
403 if (NdisStatus
!= NDIS_STATUS_PENDING
)
404 ProtocolTransferDataComplete(BindingContext
,
409 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
411 return NDIS_STATUS_SUCCESS
;
415 VOID STDCALL
ProtocolReceiveComplete(
416 NDIS_HANDLE BindingContext
)
418 * FUNCTION: Called by NDIS when we're done receiving data
420 * BindingContext = Pointer to a device context (LAN_ADAPTER)
423 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
427 VOID STDCALL
ProtocolStatus(
428 NDIS_HANDLE BindingContext
,
429 NDIS_STATUS GenerelStatus
,
431 UINT StatusBufferSize
)
433 * FUNCTION: Called by NDIS when the underlying driver has changed state
435 * BindingContext = Pointer to a device context (LAN_ADAPTER)
436 * GenerelStatus = A generel status code
437 * StatusBuffer = Pointer to a buffer with medium-specific data
438 * StatusBufferSize = Number of bytes in StatusBuffer
441 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
445 VOID STDCALL
ProtocolStatusComplete(
446 NDIS_HANDLE NdisBindingContext
)
448 * FUNCTION: Called by NDIS when a status-change has occurred
450 * BindingContext = Pointer to a device context (LAN_ADAPTER)
453 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
456 VOID STDCALL
ProtocolBindAdapter(
457 OUT PNDIS_STATUS Status
,
458 IN NDIS_HANDLE BindContext
,
459 IN PNDIS_STRING DeviceName
,
460 IN PVOID SystemSpecific1
,
461 IN PVOID SystemSpecific2
)
463 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
464 * bindings, and periodically thereafer as new adapters come online
466 * Status: Return value to NDIS
467 * BindContext: Handle provided by NDIS to track pending binding operations
468 * DeviceName: Name of the miniport device to bind to
469 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
470 * SystemSpecific2: Unused & must not be touched
473 /* XXX confirm that this is still true, or re-word the following comment */
474 /* we get to ignore BindContext because we will never pend an operation with NDIS */
475 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
476 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
482 PNDIS_PACKET NdisPacket
,
487 * FUNCTION: Transmits a packet
489 * Context = Pointer to context information (LAN_ADAPTER)
490 * NdisPacket = Pointer to NDIS packet to send
491 * Offset = Offset in packet where data starts
492 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
493 * Type = LAN protocol type (LAN_PROTO_*)
496 NDIS_STATUS NdisStatus
;
501 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
503 TI_DbgPrint(DEBUG_DATALINK
,
504 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
505 NdisPacket
, Offset
, Adapter
));
507 TI_DbgPrint(DEBUG_DATALINK
,
508 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
509 Adapter
->HWAddress
[0] & 0xff,
510 Adapter
->HWAddress
[1] & 0xff,
511 Adapter
->HWAddress
[2] & 0xff,
512 Adapter
->HWAddress
[3] & 0xff,
513 Adapter
->HWAddress
[4] & 0xff,
514 Adapter
->HWAddress
[5] & 0xff));
516 /* XXX arty -- Handled adjustment in a saner way than before ...
517 * not needed immediately */
518 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
520 if (Adapter
->State
== LAN_STATE_STARTED
) {
521 switch (Adapter
->Media
) {
522 case NdisMedium802_3
:
523 EHeader
= (PETH_HEADER
)Data
;
526 /* Unicast address */
527 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
529 /* Broadcast address */
530 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
533 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
537 EHeader
->EType
= ETYPE_IPv4
;
540 EHeader
->EType
= ETYPE_ARP
;
543 EHeader
->EType
= ETYPE_IPv6
;
547 /* Should not happen */
548 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
550 ProtocolSendComplete((NDIS_HANDLE
)Context
,
552 NDIS_STATUS_FAILURE
);
559 /* FIXME: Support other medias */
563 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
567 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
568 ((PCHAR
)LinkAddress
)[0] & 0xff,
569 ((PCHAR
)LinkAddress
)[1] & 0xff,
570 ((PCHAR
)LinkAddress
)[2] & 0xff,
571 ((PCHAR
)LinkAddress
)[3] & 0xff,
572 ((PCHAR
)LinkAddress
)[4] & 0xff,
573 ((PCHAR
)LinkAddress
)[5] & 0xff));
576 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
577 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
578 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
579 TI_DbgPrint(MID_TRACE
, ("NdisSend Done\n"));
580 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
582 if (NdisStatus
!= NDIS_STATUS_PENDING
)
583 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
585 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
590 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
591 OBJECT_ATTRIBUTES Attributes
;
594 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
595 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
599 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
600 PWCHAR RegistryValue
,
601 PIP_ADDRESS Address
) {
602 UNICODE_STRING ValueName
;
603 UNICODE_STRING UnicodeAddress
;
607 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
608 ANSI_STRING AnsiAddress
;
611 RtlInitUnicodeString(&ValueName
, RegistryValue
);
613 ZwQueryValueKey(RegHandle
,
615 KeyValuePartialInformation
,
620 if (!NT_SUCCESS(Status
))
622 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
623 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
625 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
626 UnicodeAddress
.Length
= Information
->DataLength
;
627 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
629 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
631 return STATUS_NO_MEMORY
;
633 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
634 if(!AnsiAddress
.Buffer
)
635 return STATUS_NO_MEMORY
;
637 AnsiAddress
.Length
= AnsiLen
;
638 AnsiAddress
.MaximumLength
= AnsiLen
;
640 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
641 if (!NT_SUCCESS(Status
)) {
642 exFreePool(AnsiAddress
.Buffer
);
643 return STATUS_UNSUCCESSFUL
;
646 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
647 AddrInitIPv4(Address
, inet_addr(AnsiAddress
.Buffer
));
649 return STATUS_SUCCESS
;
652 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
653 PWCHAR RegistryValue
,
654 PUNICODE_STRING String
) {
655 UNICODE_STRING ValueName
;
656 UNICODE_STRING UnicodeString
;
660 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
662 RtlInitUnicodeString(&ValueName
, RegistryValue
);
664 ZwQueryValueKey(RegHandle
,
666 KeyValuePartialInformation
,
671 if (!NT_SUCCESS(Status
))
673 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
674 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
676 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
677 UnicodeString
.Length
= Information
->DataLength
;
678 UnicodeString
.MaximumLength
= Information
->DataLength
;
681 (PWCHAR
)exAllocatePool( NonPagedPool
,
682 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
684 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
686 String
->MaximumLength
= UnicodeString
.MaximumLength
;
687 RtlCopyUnicodeString( String
, &UnicodeString
);
689 return STATUS_SUCCESS
;
692 static VOID GetSimpleAdapterNameFromRegistryPath
693 ( PUNICODE_STRING TargetString
,
694 PUNICODE_STRING RegistryPath
) {
695 PWCHAR i
, LastSlash
= NULL
;
696 UINT NewStringLength
= 0;
698 for( i
= RegistryPath
->Buffer
;
699 i
< RegistryPath
->Buffer
+
700 (RegistryPath
->Length
/ sizeof(WCHAR
));
701 i
++ ) if( *i
== '\\' ) LastSlash
= i
;
703 if( LastSlash
) LastSlash
++; else LastSlash
= RegistryPath
->Buffer
;
705 NewStringLength
= RegistryPath
->MaximumLength
-
706 ((LastSlash
- RegistryPath
->Buffer
) * sizeof(WCHAR
));
708 TargetString
->Buffer
=
709 (PWCHAR
)exAllocatePool( NonPagedPool
, NewStringLength
);
711 if( !TargetString
->Buffer
) {
712 TargetString
->Length
= TargetString
->MaximumLength
= 0;
716 TargetString
->Length
= TargetString
->MaximumLength
= NewStringLength
;
717 RtlCopyMemory( TargetString
->Buffer
, LastSlash
, NewStringLength
);
721 PLAN_ADAPTER Adapter
,
722 PNDIS_STRING RegistryPath
)
724 * FUNCTION: Binds a LAN adapter to IP layer
726 * Adapter = Pointer to LAN_ADAPTER structure
728 * We set the lookahead buffer size, set the packet filter and
729 * bind the adapter to IP layer
733 NDIS_STATUS NdisStatus
;
734 LLIP_BIND_INFO BindInfo
;
735 IP_ADDRESS DefaultGateway
, DefaultMask
= { 0 };
736 ULONG Lookahead
= LOOKAHEAD_SIZE
;
738 HANDLE RegHandle
= 0;
740 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
742 Adapter
->State
= LAN_STATE_OPENING
;
744 NdisStatus
= NDISCall(Adapter
,
745 NdisRequestSetInformation
,
746 OID_GEN_CURRENT_LOOKAHEAD
,
749 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
750 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
754 /* Bind the adapter to IP layer */
755 BindInfo
.Context
= Adapter
;
756 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
757 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
758 BindInfo
.MTU
= Adapter
->MTU
;
759 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
760 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
761 BindInfo
.Transmit
= LANTransmit
;
763 IF
= IPCreateInterface(&BindInfo
);
766 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
771 * Query per-adapter configuration from the registry
772 * In case anyone is curious: there *is* an Ndis configuration api
773 * for this sort of thing, but it doesn't really support things like
774 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
775 * protocol drivers developed for win2k and above just use the native
776 * services (ZwOpenKey, etc).
779 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
781 if(NT_SUCCESS(Status
))
782 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"DefaultGateway",
784 if(!NT_SUCCESS(Status
)) {
785 Status
= STATUS_SUCCESS
;
786 RtlZeroMemory( &DefaultGateway
, sizeof(DefaultGateway
) );
789 if(NT_SUCCESS(Status
))
790 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
792 if(NT_SUCCESS(Status
))
793 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
795 if(NT_SUCCESS(Status
)) {
796 Status
= ReadStringFromRegistry( RegHandle
, L
"DeviceDesc",
799 RtlZeroMemory( &IF
->Name
, sizeof( IF
->Name
) );
801 /* I think that not getting a devicedesc is not a fatal error */
802 if( !NT_SUCCESS(Status
) ) {
803 if( IF
->Name
.Buffer
) exFreePool( IF
->Name
.Buffer
);
804 GetSimpleAdapterNameFromRegistryPath( &IF
->Name
, RegistryPath
);
806 Status
= STATUS_SUCCESS
;
809 if(!NT_SUCCESS(Status
))
811 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
813 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
816 IPDestroyInterface(IF
);
822 ("--> Our IP address on this interface: '%s'\n",
827 ("--> Our net mask on this interface: '%s'\n",
830 if( DefaultGateway
.Address
.IPv4Address
) {
833 ("--> Our gateway is: '%s'\n",
834 A2S(&DefaultGateway
)));
836 /* Create a default route */
837 RouterCreateRoute( &DefaultMask
, /* Zero */
838 &DefaultMask
, /* Zero */
844 /* Register interface with IP layer */
845 IPRegisterInterface(IF
);
847 /* Set packet filter so we can send and receive packets */
848 NdisStatus
= NDISCall(Adapter
,
849 NdisRequestSetInformation
,
850 OID_GEN_CURRENT_PACKET_FILTER
,
851 &Adapter
->PacketFilter
,
853 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
854 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
855 IPDestroyInterface(IF
);
859 Adapter
->Context
= IF
;
860 Adapter
->State
= LAN_STATE_STARTED
;
865 PLAN_ADAPTER Adapter
)
867 * FUNCTION: Unbinds a LAN adapter from IP layer
869 * Adapter = Pointer to LAN_ADAPTER structure
872 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
874 if (Adapter
->State
== LAN_STATE_STARTED
) {
875 PIP_INTERFACE IF
= Adapter
->Context
;
877 IPUnregisterInterface(IF
);
879 IPDestroyInterface(IF
);
884 NDIS_STATUS
LANRegisterAdapter(
885 PNDIS_STRING AdapterName
,
886 PNDIS_STRING RegistryPath
)
888 * FUNCTION: Registers protocol with an NDIS adapter
890 * AdapterName = Pointer to string with name of adapter to register
891 * Adapter = Address of pointer to a LAN_ADAPTER structure
893 * Status of operation
897 NDIS_STATUS NdisStatus
;
898 NDIS_STATUS OpenStatus
;
900 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
904 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
906 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
908 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
909 return NDIS_STATUS_RESOURCES
;
912 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
914 /* Put adapter in stopped state */
915 IF
->State
= LAN_STATE_STOPPED
;
917 /* Initialize protecting spin lock */
918 KeInitializeSpinLock(&IF
->Lock
);
920 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
922 /* Initialize array with media IDs we support */
923 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
925 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
926 /* Open the adapter. */
927 NdisOpenAdapter(&NdisStatus
,
939 /* Wait until the adapter is opened */
940 if (NdisStatus
== NDIS_STATUS_PENDING
)
941 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
942 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
947 IF
->Media
= MediaArray
[MediaIndex
];
949 /* Fill LAN_ADAPTER structure with some adapter specific information */
951 case NdisMedium802_3
:
952 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
953 IF
->BCastMask
= BCAST_ETH_MASK
;
954 IF
->BCastCheck
= BCAST_ETH_CHECK
;
955 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
956 IF
->HeaderSize
= sizeof(ETH_HEADER
);
957 IF
->MinFrameSize
= 60;
958 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
960 NDIS_PACKET_TYPE_BROADCAST
|
961 NDIS_PACKET_TYPE_DIRECTED
|
962 NDIS_PACKET_TYPE_MULTICAST
;
966 /* Unsupported media */
967 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
969 return NDIS_STATUS_NOT_SUPPORTED
;
972 /* Get maximum frame size */
973 NdisStatus
= NDISCall(IF
,
974 NdisRequestQueryInformation
,
975 OID_GEN_MAXIMUM_FRAME_SIZE
,
978 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
983 /* Get maximum packet size */
984 NdisStatus
= NDISCall(IF
,
985 NdisRequestQueryInformation
,
986 OID_GEN_MAXIMUM_TOTAL_SIZE
,
989 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
990 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
995 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
996 NdisStatus
= NDISCall(IF
,
997 NdisRequestQueryInformation
,
998 OID_GEN_MAXIMUM_SEND_PACKETS
,
1001 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1002 /* Legacy NIC drivers may not support this query, if it fails we
1003 assume it can send at least one packet per call to NdisSend(Packets) */
1004 IF
->MaxSendPackets
= 1;
1006 /* Get current hardware address */
1007 NdisStatus
= NDISCall(IF
,
1008 NdisRequestQueryInformation
,
1011 IF
->HWAddressLength
);
1012 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1013 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1018 /* Get maximum link speed */
1019 NdisStatus
= NDISCall(IF
,
1020 NdisRequestQueryInformation
,
1024 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1025 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1030 /* Convert returned link speed to bps (it is in 100bps increments) */
1031 IF
->Speed
= Speed
* 100L;
1033 /* Add adapter to the adapter list */
1034 ExInterlockedInsertTailList(&AdapterListHead
,
1038 /* Bind adapter to IP layer */
1039 BindAdapter(IF
, RegistryPath
);
1041 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1043 return NDIS_STATUS_SUCCESS
;
1047 NDIS_STATUS
LANUnregisterAdapter(
1048 PLAN_ADAPTER Adapter
)
1050 * FUNCTION: Unregisters protocol with NDIS adapter
1052 * Adapter = Pointer to a LAN_ADAPTER structure
1054 * Status of operation
1058 NDIS_HANDLE NdisHandle
;
1059 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1061 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1063 /* Unlink the adapter from the list */
1064 RemoveEntryList(&Adapter
->ListEntry
);
1066 /* Unbind adapter from IP layer */
1067 UnbindAdapter(Adapter
);
1069 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1070 NdisHandle
= Adapter
->NdisHandle
;
1072 Adapter
->NdisHandle
= NULL
;
1073 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1075 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1076 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1077 TcpipWaitForSingleObject(&Adapter
->Event
,
1082 NdisStatus
= Adapter
->NdisStatus
;
1085 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1087 FreeAdapter(Adapter
);
1089 return NDIS_STATUS_SUCCESS
;
1093 NTSTATUS
LANRegisterProtocol(
1096 * FUNCTION: Registers this protocol driver with NDIS
1098 * Name = Name of this protocol driver
1100 * Status of operation
1103 NDIS_STATUS NdisStatus
;
1104 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1106 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1108 InitializeListHead(&AdapterListHead
);
1109 KeInitializeSpinLock(&AdapterListLock
);
1111 /* Set up protocol characteristics */
1112 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1113 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1114 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1115 ProtChars
.Name
.Length
= Name
->Length
;
1116 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1117 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1118 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1119 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1120 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1121 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1122 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1123 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1124 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1125 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1126 ProtChars
.StatusHandler
= ProtocolStatus
;
1127 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1128 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1130 /* Try to register protocol */
1131 NdisRegisterProtocol(&NdisStatus
,
1132 &NdisProtocolHandle
,
1134 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1135 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1137 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1138 return (NTSTATUS
)NdisStatus
;
1141 ProtocolRegistered
= TRUE
;
1143 return STATUS_SUCCESS
;
1147 VOID
LANUnregisterProtocol(
1150 * FUNCTION: Unregisters this protocol driver with NDIS
1151 * NOTES: Does not care wether we are already registered
1154 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1156 if (ProtocolRegistered
) {
1157 NDIS_STATUS NdisStatus
;
1158 PLIST_ENTRY CurrentEntry
;
1159 PLIST_ENTRY NextEntry
;
1160 PLAN_ADAPTER Current
;
1163 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1165 /* Search the list and remove every adapter we find */
1166 CurrentEntry
= AdapterListHead
.Flink
;
1167 while (CurrentEntry
!= &AdapterListHead
) {
1168 NextEntry
= CurrentEntry
->Flink
;
1169 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1171 LANUnregisterAdapter(Current
);
1172 CurrentEntry
= NextEntry
;
1175 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1177 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1178 ProtocolRegistered
= FALSE
;
1183 InitializeListHead( &LanWorkList
);
1184 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1187 VOID
LANShutdown() {
1189 PLAN_WQ_ITEM WorkItem
;
1190 PLIST_ENTRY ListEntry
;
1192 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1193 while( !IsListEmpty( &LanWorkList
) ) {
1194 ListEntry
= RemoveHeadList( &LanWorkList
);
1195 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1196 FreeNdisPacket( WorkItem
->Packet
);
1197 ExFreePool( WorkItem
);
1199 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);