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 /*OskitDumpBuffer( IPPacket.Header, IPPacket.TotalSize );*/
233 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
234 IPPacket
.Position
= 0;
238 ("Ether Type = %x ContigSize = %d Total = %d\n",
239 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
241 switch (PacketType
) {
244 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
245 IPReceive(Adapter
->Context
, &IPPacket
);
248 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
249 ARPReceive(Adapter
->Context
, &IPPacket
);
254 FreeNdisPacket( Packet
);
258 VOID STDCALL
ProtocolTransferDataComplete(
259 NDIS_HANDLE BindingContext
,
262 UINT BytesTransferred
)
264 * FUNCTION: Called by NDIS to complete reception of data
266 * BindingContext = Pointer to a device context (LAN_ADAPTER)
267 * Packet = Pointer to a packet descriptor
268 * Status = Status of the operation
269 * BytesTransferred = Number of bytes transferred
271 * If the packet was successfully received, determine the protocol
272 * type and pass it to the correct receive handler
277 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
279 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
281 if( Status
!= NDIS_STATUS_SUCCESS
) return;
282 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
283 if( !WQItem
) return;
285 TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock
);
286 WorkStart
= IsListEmpty( &LanWorkList
);
287 WQItem
->Packet
= Packet
;
288 WQItem
->Adapter
= Adapter
;
289 WQItem
->BytesTransferred
= BytesTransferred
;
290 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
292 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
293 TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock
);
296 NDIS_STATUS STDCALL
ProtocolReceive(
297 NDIS_HANDLE BindingContext
,
298 NDIS_HANDLE MacReceiveContext
,
300 UINT HeaderBufferSize
,
301 PVOID LookaheadBuffer
,
302 UINT LookaheadBufferSize
,
305 * FUNCTION: Called by NDIS when a packet has been received on the physical link
307 * BindingContext = Pointer to a device context (LAN_ADAPTER)
308 * MacReceiveContext = Handle used by underlying NIC driver
309 * HeaderBuffer = Pointer to a buffer containing the packet header
310 * HeaderBufferSize = Number of bytes in HeaderBuffer
311 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
312 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
313 * PacketSize = Overall size of the packet (not including header)
315 * Status of operation
319 UINT PacketType
, BytesTransferred
;
323 NDIS_STATUS NdisStatus
;
324 PNDIS_PACKET NdisPacket
;
325 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
326 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
328 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
330 if (Adapter
->State
!= LAN_STATE_STARTED
) {
331 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
332 return NDIS_STATUS_NOT_ACCEPTED
;
335 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
336 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
337 return NDIS_STATUS_NOT_ACCEPTED
;
340 if (Adapter
->Media
== NdisMedium802_3
) {
341 /* Ethernet and IEEE 802.3 frames can be destinguished by
342 looking at the IEEE 802.3 length field. This field is
343 less than or equal to 1500 for a valid IEEE 802.3 frame
344 and larger than 1500 is it's a valid EtherType value.
345 See RFC 1122, section 2.3.3 for more information */
346 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
347 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
348 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
349 return NDIS_STATUS_NOT_ACCEPTED
;
351 /* We use EtherType constants to destinguish packet types */
354 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
355 /* FIXME: Support other medias */
356 return NDIS_STATUS_NOT_ACCEPTED
;
359 /* Get a transfer data packet */
361 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
362 Adapter
, Adapter
->MTU
));
364 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
365 PacketSize
+ HeaderBufferSize
);
366 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
367 return NDIS_STATUS_NOT_ACCEPTED
;
370 PC(NdisPacket
)->PacketType
= PacketType
;
372 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
374 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
376 IPPacket
.NdisPacket
= NdisPacket
;
377 IPPacket
.Position
= 0;
379 if (LookaheadBufferSize
== PacketSize
)
381 /* Optimized code path for packets that are fully contained in
382 * the lookahead buffer. */
383 NdisCopyLookaheadData(BufferData
,
386 Adapter
->MacOptions
);
390 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
392 ASSERT(PacketSize
<= Adapter
->MTU
);
394 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
395 MacReceiveContext
, 0, PacketSize
,
396 NdisPacket
, &BytesTransferred
);
400 BytesTransferred
= 0;
403 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
405 if (NdisStatus
!= NDIS_STATUS_PENDING
)
406 ProtocolTransferDataComplete(BindingContext
,
411 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
413 return NDIS_STATUS_SUCCESS
;
417 VOID STDCALL
ProtocolReceiveComplete(
418 NDIS_HANDLE BindingContext
)
420 * FUNCTION: Called by NDIS when we're done receiving data
422 * BindingContext = Pointer to a device context (LAN_ADAPTER)
425 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
429 VOID STDCALL
ProtocolStatus(
430 NDIS_HANDLE BindingContext
,
431 NDIS_STATUS GenerelStatus
,
433 UINT StatusBufferSize
)
435 * FUNCTION: Called by NDIS when the underlying driver has changed state
437 * BindingContext = Pointer to a device context (LAN_ADAPTER)
438 * GenerelStatus = A generel status code
439 * StatusBuffer = Pointer to a buffer with medium-specific data
440 * StatusBufferSize = Number of bytes in StatusBuffer
443 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
447 VOID STDCALL
ProtocolStatusComplete(
448 NDIS_HANDLE NdisBindingContext
)
450 * FUNCTION: Called by NDIS when a status-change has occurred
452 * BindingContext = Pointer to a device context (LAN_ADAPTER)
455 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
458 VOID STDCALL
ProtocolBindAdapter(
459 OUT PNDIS_STATUS Status
,
460 IN NDIS_HANDLE BindContext
,
461 IN PNDIS_STRING DeviceName
,
462 IN PVOID SystemSpecific1
,
463 IN PVOID SystemSpecific2
)
465 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
466 * bindings, and periodically thereafer as new adapters come online
468 * Status: Return value to NDIS
469 * BindContext: Handle provided by NDIS to track pending binding operations
470 * DeviceName: Name of the miniport device to bind to
471 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
472 * SystemSpecific2: Unused & must not be touched
475 /* XXX confirm that this is still true, or re-word the following comment */
476 /* we get to ignore BindContext because we will never pend an operation with NDIS */
477 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
478 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
484 PNDIS_PACKET NdisPacket
,
489 * FUNCTION: Transmits a packet
491 * Context = Pointer to context information (LAN_ADAPTER)
492 * NdisPacket = Pointer to NDIS packet to send
493 * Offset = Offset in packet where data starts
494 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
495 * Type = LAN protocol type (LAN_PROTO_*)
498 NDIS_STATUS NdisStatus
;
503 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
505 TI_DbgPrint(DEBUG_DATALINK
,
506 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
507 NdisPacket
, Offset
, Adapter
));
509 TI_DbgPrint(DEBUG_DATALINK
,
510 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
511 Adapter
->HWAddress
[0] & 0xff,
512 Adapter
->HWAddress
[1] & 0xff,
513 Adapter
->HWAddress
[2] & 0xff,
514 Adapter
->HWAddress
[3] & 0xff,
515 Adapter
->HWAddress
[4] & 0xff,
516 Adapter
->HWAddress
[5] & 0xff));
518 /* XXX arty -- Handled adjustment in a saner way than before ...
519 * not needed immediately */
520 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
522 if (Adapter
->State
== LAN_STATE_STARTED
) {
523 switch (Adapter
->Media
) {
524 case NdisMedium802_3
:
525 EHeader
= (PETH_HEADER
)Data
;
528 /* Unicast address */
529 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
531 /* Broadcast address */
532 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
535 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
539 EHeader
->EType
= ETYPE_IPv4
;
542 EHeader
->EType
= ETYPE_ARP
;
545 EHeader
->EType
= ETYPE_IPv6
;
549 /* Should not happen */
550 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
552 ProtocolSendComplete((NDIS_HANDLE
)Context
,
554 NDIS_STATUS_FAILURE
);
561 /* FIXME: Support other medias */
565 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
569 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
570 ((PCHAR
)LinkAddress
)[0] & 0xff,
571 ((PCHAR
)LinkAddress
)[1] & 0xff,
572 ((PCHAR
)LinkAddress
)[2] & 0xff,
573 ((PCHAR
)LinkAddress
)[3] & 0xff,
574 ((PCHAR
)LinkAddress
)[4] & 0xff,
575 ((PCHAR
)LinkAddress
)[5] & 0xff));
578 /*OskitDumpBuffer( Data, Size );*/
580 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
581 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
582 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
583 TI_DbgPrint(MID_TRACE
, ("NdisSend Done\n"));
584 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
586 if (NdisStatus
!= NDIS_STATUS_PENDING
)
587 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
589 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
594 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
595 OBJECT_ATTRIBUTES Attributes
;
598 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
599 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
603 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
604 PWCHAR RegistryValue
,
605 PIP_ADDRESS Address
) {
606 UNICODE_STRING ValueName
;
607 UNICODE_STRING UnicodeAddress
;
611 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
612 ANSI_STRING AnsiAddress
;
615 RtlInitUnicodeString(&ValueName
, RegistryValue
);
617 ZwQueryValueKey(RegHandle
,
619 KeyValuePartialInformation
,
624 if (!NT_SUCCESS(Status
))
626 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
627 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
629 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
630 UnicodeAddress
.Length
= Information
->DataLength
;
631 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
633 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
635 return STATUS_NO_MEMORY
;
637 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
638 if(!AnsiAddress
.Buffer
)
639 return STATUS_NO_MEMORY
;
641 AnsiAddress
.Length
= AnsiLen
;
642 AnsiAddress
.MaximumLength
= AnsiLen
;
644 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
645 if (!NT_SUCCESS(Status
)) {
646 exFreePool(AnsiAddress
.Buffer
);
647 return STATUS_UNSUCCESSFUL
;
650 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
651 AddrInitIPv4(Address
, inet_addr(AnsiAddress
.Buffer
));
653 return STATUS_SUCCESS
;
656 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
657 PWCHAR RegistryValue
,
658 PUNICODE_STRING String
) {
659 UNICODE_STRING ValueName
;
660 UNICODE_STRING UnicodeString
;
664 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
666 RtlInitUnicodeString(&ValueName
, RegistryValue
);
668 ZwQueryValueKey(RegHandle
,
670 KeyValuePartialInformation
,
675 if (!NT_SUCCESS(Status
))
677 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
678 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
680 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
681 UnicodeString
.Length
= Information
->DataLength
;
682 UnicodeString
.MaximumLength
= Information
->DataLength
;
685 (PWCHAR
)exAllocatePool( NonPagedPool
,
686 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
688 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
690 String
->MaximumLength
= UnicodeString
.MaximumLength
;
691 RtlCopyUnicodeString( String
, &UnicodeString
);
693 return STATUS_SUCCESS
;
696 static VOID GetSimpleAdapterNameFromRegistryPath
697 ( PUNICODE_STRING TargetString
,
698 PUNICODE_STRING RegistryPath
) {
699 PWCHAR i
, LastSlash
= NULL
;
700 UINT NewStringLength
= 0;
702 for( i
= RegistryPath
->Buffer
;
703 i
< RegistryPath
->Buffer
+
704 (RegistryPath
->Length
/ sizeof(WCHAR
));
705 i
++ ) if( *i
== '\\' ) LastSlash
= i
;
707 if( LastSlash
) LastSlash
++; else LastSlash
= RegistryPath
->Buffer
;
709 NewStringLength
= RegistryPath
->MaximumLength
-
710 ((LastSlash
- RegistryPath
->Buffer
) * sizeof(WCHAR
));
712 TargetString
->Buffer
=
713 (PWCHAR
)exAllocatePool( NonPagedPool
, NewStringLength
);
715 if( !TargetString
->Buffer
) {
716 TargetString
->Length
= TargetString
->MaximumLength
= 0;
720 TargetString
->Length
= TargetString
->MaximumLength
= NewStringLength
;
721 RtlCopyMemory( TargetString
->Buffer
, LastSlash
, NewStringLength
);
725 PLAN_ADAPTER Adapter
,
726 PNDIS_STRING RegistryPath
)
728 * FUNCTION: Binds a LAN adapter to IP layer
730 * Adapter = Pointer to LAN_ADAPTER structure
732 * We set the lookahead buffer size, set the packet filter and
733 * bind the adapter to IP layer
737 NDIS_STATUS NdisStatus
;
738 LLIP_BIND_INFO BindInfo
;
739 IP_ADDRESS DefaultGateway
, DefaultMask
= { 0 };
740 ULONG Lookahead
= LOOKAHEAD_SIZE
;
742 HANDLE RegHandle
= 0;
744 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
746 Adapter
->State
= LAN_STATE_OPENING
;
748 NdisStatus
= NDISCall(Adapter
,
749 NdisRequestSetInformation
,
750 OID_GEN_CURRENT_LOOKAHEAD
,
753 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
754 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
758 /* Bind the adapter to IP layer */
759 BindInfo
.Context
= Adapter
;
760 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
761 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
762 BindInfo
.MTU
= Adapter
->MTU
;
763 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
764 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
765 BindInfo
.Transmit
= LANTransmit
;
767 IF
= IPCreateInterface(&BindInfo
);
770 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
775 * Query per-adapter configuration from the registry
776 * In case anyone is curious: there *is* an Ndis configuration api
777 * for this sort of thing, but it doesn't really support things like
778 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
779 * protocol drivers developed for win2k and above just use the native
780 * services (ZwOpenKey, etc).
783 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
785 if(NT_SUCCESS(Status
))
786 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"DefaultGateway",
788 if(!NT_SUCCESS(Status
)) {
789 Status
= STATUS_SUCCESS
;
790 RtlZeroMemory( &DefaultGateway
, sizeof(DefaultGateway
) );
793 if(NT_SUCCESS(Status
))
794 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
796 if(NT_SUCCESS(Status
))
797 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
799 if(NT_SUCCESS(Status
)) {
800 Status
= ReadStringFromRegistry( RegHandle
, L
"DeviceDesc",
803 RtlZeroMemory( &IF
->Name
, sizeof( IF
->Name
) );
805 /* I think that not getting a devicedesc is not a fatal error */
806 if( !NT_SUCCESS(Status
) ) {
807 if( IF
->Name
.Buffer
) exFreePool( IF
->Name
.Buffer
);
808 GetSimpleAdapterNameFromRegistryPath( &IF
->Name
, RegistryPath
);
810 Status
= STATUS_SUCCESS
;
813 if(!NT_SUCCESS(Status
))
815 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
817 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
820 IPDestroyInterface(IF
);
826 ("--> Our IP address on this interface: '%s'\n",
831 ("--> Our net mask on this interface: '%s'\n",
834 if( DefaultGateway
.Address
.IPv4Address
) {
837 ("--> Our gateway is: '%s'\n",
838 A2S(&DefaultGateway
)));
840 /* Create a default route */
841 RouterCreateRoute( &DefaultMask
, /* Zero */
842 &DefaultMask
, /* Zero */
848 /* Register interface with IP layer */
849 IPRegisterInterface(IF
);
851 /* Set packet filter so we can send and receive packets */
852 NdisStatus
= NDISCall(Adapter
,
853 NdisRequestSetInformation
,
854 OID_GEN_CURRENT_PACKET_FILTER
,
855 &Adapter
->PacketFilter
,
857 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
858 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
859 IPDestroyInterface(IF
);
863 Adapter
->Context
= IF
;
864 Adapter
->State
= LAN_STATE_STARTED
;
869 PLAN_ADAPTER Adapter
)
871 * FUNCTION: Unbinds a LAN adapter from IP layer
873 * Adapter = Pointer to LAN_ADAPTER structure
876 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
878 if (Adapter
->State
== LAN_STATE_STARTED
) {
879 PIP_INTERFACE IF
= Adapter
->Context
;
881 IPUnregisterInterface(IF
);
883 IPDestroyInterface(IF
);
888 NDIS_STATUS
LANRegisterAdapter(
889 PNDIS_STRING AdapterName
,
890 PNDIS_STRING RegistryPath
)
892 * FUNCTION: Registers protocol with an NDIS adapter
894 * AdapterName = Pointer to string with name of adapter to register
895 * Adapter = Address of pointer to a LAN_ADAPTER structure
897 * Status of operation
901 NDIS_STATUS NdisStatus
;
902 NDIS_STATUS OpenStatus
;
904 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
908 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
910 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
912 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
913 return NDIS_STATUS_RESOURCES
;
916 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
918 /* Put adapter in stopped state */
919 IF
->State
= LAN_STATE_STOPPED
;
921 /* Initialize protecting spin lock */
922 KeInitializeSpinLock(&IF
->Lock
);
924 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
926 /* Initialize array with media IDs we support */
927 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
929 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
930 /* Open the adapter. */
931 NdisOpenAdapter(&NdisStatus
,
943 /* Wait until the adapter is opened */
944 if (NdisStatus
== NDIS_STATUS_PENDING
)
945 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
946 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
951 IF
->Media
= MediaArray
[MediaIndex
];
953 /* Fill LAN_ADAPTER structure with some adapter specific information */
955 case NdisMedium802_3
:
956 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
957 IF
->BCastMask
= BCAST_ETH_MASK
;
958 IF
->BCastCheck
= BCAST_ETH_CHECK
;
959 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
960 IF
->HeaderSize
= sizeof(ETH_HEADER
);
961 IF
->MinFrameSize
= 60;
962 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
964 NDIS_PACKET_TYPE_BROADCAST
|
965 NDIS_PACKET_TYPE_DIRECTED
|
966 NDIS_PACKET_TYPE_MULTICAST
;
970 /* Unsupported media */
971 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
973 return NDIS_STATUS_NOT_SUPPORTED
;
976 /* Get maximum frame size */
977 NdisStatus
= NDISCall(IF
,
978 NdisRequestQueryInformation
,
979 OID_GEN_MAXIMUM_FRAME_SIZE
,
982 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
987 /* Get maximum packet size */
988 NdisStatus
= NDISCall(IF
,
989 NdisRequestQueryInformation
,
990 OID_GEN_MAXIMUM_TOTAL_SIZE
,
993 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
994 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
999 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1000 NdisStatus
= NDISCall(IF
,
1001 NdisRequestQueryInformation
,
1002 OID_GEN_MAXIMUM_SEND_PACKETS
,
1003 &IF
->MaxSendPackets
,
1005 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1006 /* Legacy NIC drivers may not support this query, if it fails we
1007 assume it can send at least one packet per call to NdisSend(Packets) */
1008 IF
->MaxSendPackets
= 1;
1010 /* Get current hardware address */
1011 NdisStatus
= NDISCall(IF
,
1012 NdisRequestQueryInformation
,
1015 IF
->HWAddressLength
);
1016 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1017 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1022 /* Get maximum link speed */
1023 NdisStatus
= NDISCall(IF
,
1024 NdisRequestQueryInformation
,
1028 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1029 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1034 /* Convert returned link speed to bps (it is in 100bps increments) */
1035 IF
->Speed
= Speed
* 100L;
1037 /* Add adapter to the adapter list */
1038 ExInterlockedInsertTailList(&AdapterListHead
,
1042 /* Bind adapter to IP layer */
1043 BindAdapter(IF
, RegistryPath
);
1045 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1047 return NDIS_STATUS_SUCCESS
;
1051 NDIS_STATUS
LANUnregisterAdapter(
1052 PLAN_ADAPTER Adapter
)
1054 * FUNCTION: Unregisters protocol with NDIS adapter
1056 * Adapter = Pointer to a LAN_ADAPTER structure
1058 * Status of operation
1062 NDIS_HANDLE NdisHandle
;
1063 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1065 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1067 /* Unlink the adapter from the list */
1068 RemoveEntryList(&Adapter
->ListEntry
);
1070 /* Unbind adapter from IP layer */
1071 UnbindAdapter(Adapter
);
1073 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1074 NdisHandle
= Adapter
->NdisHandle
;
1076 Adapter
->NdisHandle
= NULL
;
1077 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1079 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1080 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1081 TcpipWaitForSingleObject(&Adapter
->Event
,
1086 NdisStatus
= Adapter
->NdisStatus
;
1089 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1091 FreeAdapter(Adapter
);
1093 return NDIS_STATUS_SUCCESS
;
1097 NTSTATUS
LANRegisterProtocol(
1100 * FUNCTION: Registers this protocol driver with NDIS
1102 * Name = Name of this protocol driver
1104 * Status of operation
1107 NDIS_STATUS NdisStatus
;
1108 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1110 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1112 InitializeListHead(&AdapterListHead
);
1113 KeInitializeSpinLock(&AdapterListLock
);
1115 /* Set up protocol characteristics */
1116 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1117 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1118 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1119 ProtChars
.Name
.Length
= Name
->Length
;
1120 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1121 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1122 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1123 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1124 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1125 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1126 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1127 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1128 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1129 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1130 ProtChars
.StatusHandler
= ProtocolStatus
;
1131 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1132 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1134 /* Try to register protocol */
1135 NdisRegisterProtocol(&NdisStatus
,
1136 &NdisProtocolHandle
,
1138 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1139 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1141 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1142 return (NTSTATUS
)NdisStatus
;
1145 ProtocolRegistered
= TRUE
;
1147 return STATUS_SUCCESS
;
1151 VOID
LANUnregisterProtocol(
1154 * FUNCTION: Unregisters this protocol driver with NDIS
1155 * NOTES: Does not care wether we are already registered
1158 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1160 if (ProtocolRegistered
) {
1161 NDIS_STATUS NdisStatus
;
1162 PLIST_ENTRY CurrentEntry
;
1163 PLIST_ENTRY NextEntry
;
1164 PLAN_ADAPTER Current
;
1167 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1169 /* Search the list and remove every adapter we find */
1170 CurrentEntry
= AdapterListHead
.Flink
;
1171 while (CurrentEntry
!= &AdapterListHead
) {
1172 NextEntry
= CurrentEntry
->Flink
;
1173 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1175 LANUnregisterAdapter(Current
);
1176 CurrentEntry
= NextEntry
;
1179 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1181 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1182 ProtocolRegistered
= FALSE
;
1187 InitializeListHead( &LanWorkList
);
1188 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1191 VOID
LANShutdown() {
1193 PLAN_WQ_ITEM WorkItem
;
1194 PLIST_ENTRY ListEntry
;
1196 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1197 while( !IsListEmpty( &LanWorkList
) ) {
1198 ListEntry
= RemoveHeadList( &LanWorkList
);
1199 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1200 FreeNdisPacket( WorkItem
->Packet
);
1201 ExFreePool( WorkItem
);
1203 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);