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 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
185 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
187 AdjustPacket(Packet
, Adapter
->HeaderSize
, PC(Packet
)->DLOffset
);
188 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
189 (*PC(Packet
)->DLComplete
)(Adapter
->Context
, Packet
, Status
);
190 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
193 VOID STDCALL
LanReceiveWorker( PVOID Context
) {
195 PLIST_ENTRY ListEntry
;
196 PLAN_WQ_ITEM WorkItem
;
198 PLAN_ADAPTER Adapter
;
199 UINT BytesTransferred
;
200 PNDIS_BUFFER NdisBuffer
;
204 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
207 ExInterlockedRemoveHeadList( &LanWorkList
, &LanWorkLock
)) ) {
208 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
210 Packet
= WorkItem
->Packet
;
211 Adapter
= WorkItem
->Adapter
;
212 BytesTransferred
= WorkItem
->BytesTransferred
;
214 ExFreePool( WorkItem
);
216 IPPacket
.NdisPacket
= Packet
;
218 NdisGetFirstBufferFromPacket(Packet
,
221 &IPPacket
.ContigSize
,
222 &IPPacket
.TotalSize
);
224 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
225 /* Determine which upper layer protocol that should receive
226 this packet and pass it to the correct receive handler */
228 OskitDumpBuffer( IPPacket
.Header
, BytesTransferred
);
230 PacketType
= ((PETH_HEADER
)IPPacket
.Header
)->EType
;
231 IPPacket
.Header
= ((PCHAR
)IPPacket
.Header
) + sizeof(ETH_HEADER
);
232 IPPacket
.Position
= sizeof(ETH_HEADER
);
233 IPPacket
.TotalSize
-= sizeof(ETH_HEADER
);
237 ("Ether Type = %x ContigSize = %d Total = %d\n",
238 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
240 switch (PacketType
) {
243 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
244 IPReceive(Adapter
->Context
, &IPPacket
);
247 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
248 ARPReceive(Adapter
->Context
, &IPPacket
);
253 FreeNdisPacket( Packet
);
257 VOID STDCALL
ProtocolTransferDataComplete(
258 NDIS_HANDLE BindingContext
,
261 UINT BytesTransferred
)
263 * FUNCTION: Called by NDIS to complete reception of data
265 * BindingContext = Pointer to a device context (LAN_ADAPTER)
266 * Packet = Pointer to a packet descriptor
267 * Status = Status of the operation
268 * BytesTransferred = Number of bytes transferred
270 * If the packet was successfully received, determine the protocol
271 * type and pass it to the correct receive handler
276 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
278 if( Status
!= NDIS_STATUS_SUCCESS
) return;
279 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
280 if( !WQItem
) return;
282 KeAcquireSpinLockAtDpcLevel( &LanWorkLock
);
283 WorkStart
= IsListEmpty( &LanWorkList
);
284 WQItem
->Packet
= Packet
;
285 WQItem
->Adapter
= Adapter
;
286 WQItem
->BytesTransferred
= BytesTransferred
;
287 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
289 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
290 KeReleaseSpinLockFromDpcLevel( &LanWorkLock
);
293 NDIS_STATUS STDCALL
ProtocolReceive(
294 NDIS_HANDLE BindingContext
,
295 NDIS_HANDLE MacReceiveContext
,
297 UINT HeaderBufferSize
,
298 PVOID LookaheadBuffer
,
299 UINT LookaheadBufferSize
,
302 * FUNCTION: Called by NDIS when a packet has been received on the physical link
304 * BindingContext = Pointer to a device context (LAN_ADAPTER)
305 * MacReceiveContext = Handle used by underlying NIC driver
306 * HeaderBuffer = Pointer to a buffer containing the packet header
307 * HeaderBufferSize = Number of bytes in HeaderBuffer
308 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
309 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
310 * PacketSize = Overall size of the packet (not including header)
312 * Status of operation
316 UINT PacketType
, BytesTransferred
;
319 NDIS_STATUS NdisStatus
;
320 PNDIS_PACKET NdisPacket
;
321 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
322 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
324 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
326 if (Adapter
->State
!= LAN_STATE_STARTED
) {
327 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
328 return NDIS_STATUS_NOT_ACCEPTED
;
331 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
332 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
333 return NDIS_STATUS_NOT_ACCEPTED
;
336 if (Adapter
->Media
== NdisMedium802_3
) {
337 /* Ethernet and IEEE 802.3 frames can be destinguished by
338 looking at the IEEE 802.3 length field. This field is
339 less than or equal to 1500 for a valid IEEE 802.3 frame
340 and larger than 1500 is it's a valid EtherType value.
341 See RFC 1122, section 2.3.3 for more information */
342 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
343 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
344 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
345 return NDIS_STATUS_NOT_ACCEPTED
;
347 /* We use EtherType constants to destinguish packet types */
350 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
351 /* FIXME: Support other medias */
352 return NDIS_STATUS_NOT_ACCEPTED
;
355 /* Get a transfer data packet */
357 KeAcquireSpinLockAtDpcLevel(&Adapter
->Lock
);
358 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
, Adapter
->MTU
);
359 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
360 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
361 return NDIS_STATUS_NOT_ACCEPTED
;
364 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
368 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
371 IPPacket
.NdisPacket
= NdisPacket
;
372 IPPacket
.Position
= 0;
374 if ((LookaheadBufferSize
+ HeaderBufferSize
) < PacketSize
)
376 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
378 NdisTransferData(&NdisStatus
,
382 PacketSize
+ HeaderBufferSize
,
386 TI_DbgPrint(DEBUG_DATALINK
, ("copy\n"));
387 NdisStatus
= NDIS_STATUS_SUCCESS
;
388 BytesTransferred
= PacketSize
;
389 RtlCopyMemory(BufferData
,
392 RtlCopyMemory(BufferData
+ HeaderBufferSize
,
393 LookaheadBuffer
, LookaheadBufferSize
);
395 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
397 /* Release the packet descriptor */
398 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
400 if (NdisStatus
!= NDIS_STATUS_PENDING
)
401 ProtocolTransferDataComplete(BindingContext
,
404 PacketSize
+ HeaderBufferSize
);
406 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
408 return NDIS_STATUS_SUCCESS
;
412 VOID STDCALL
ProtocolReceiveComplete(
413 NDIS_HANDLE BindingContext
)
415 * FUNCTION: Called by NDIS when we're done receiving data
417 * BindingContext = Pointer to a device context (LAN_ADAPTER)
420 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
424 VOID STDCALL
ProtocolStatus(
425 NDIS_HANDLE BindingContext
,
426 NDIS_STATUS GenerelStatus
,
428 UINT StatusBufferSize
)
430 * FUNCTION: Called by NDIS when the underlying driver has changed state
432 * BindingContext = Pointer to a device context (LAN_ADAPTER)
433 * GenerelStatus = A generel status code
434 * StatusBuffer = Pointer to a buffer with medium-specific data
435 * StatusBufferSize = Number of bytes in StatusBuffer
438 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
442 VOID STDCALL
ProtocolStatusComplete(
443 NDIS_HANDLE NdisBindingContext
)
445 * FUNCTION: Called by NDIS when a status-change has occurred
447 * BindingContext = Pointer to a device context (LAN_ADAPTER)
450 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
453 VOID STDCALL
ProtocolBindAdapter(
454 OUT PNDIS_STATUS Status
,
455 IN NDIS_HANDLE BindContext
,
456 IN PNDIS_STRING DeviceName
,
457 IN PVOID SystemSpecific1
,
458 IN PVOID SystemSpecific2
)
460 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
461 * bindings, and periodically thereafer as new adapters come online
463 * Status: Return value to NDIS
464 * BindContext: Handle provided by NDIS to track pending binding operations
465 * DeviceName: Name of the miniport device to bind to
466 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
467 * SystemSpecific2: Unused & must not be touched
470 /* XXX confirm that this is still true, or re-word the following comment */
471 /* we get to ignore BindContext because we will never pend an operation with NDIS */
472 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ\n", SystemSpecific1
));
473 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
479 PNDIS_PACKET NdisPacket
,
484 * FUNCTION: Transmits a packet
486 * Context = Pointer to context information (LAN_ADAPTER)
487 * NdisPacket = Pointer to NDIS packet to send
488 * Offset = Offset in packet where data starts
489 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
490 * Type = LAN protocol type (LAN_PROTO_*)
493 NDIS_STATUS NdisStatus
;
497 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
499 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
501 /* NDIS send routines don't have an offset argument so we
502 must offset the data in upper layers and adjust the
503 packet here. We save the offset in the packet context
504 area so it can be undone before we release the packet */
505 Data
= AdjustPacket(NdisPacket
, Offset
, Adapter
->HeaderSize
);
506 PC(NdisPacket
)->DLOffset
= Offset
;
508 if (Adapter
->State
== LAN_STATE_STARTED
) {
509 switch (Adapter
->Media
) {
510 case NdisMedium802_3
:
511 EHeader
= (PETH_HEADER
)Data
;
514 /* Unicast address */
515 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
517 /* Broadcast address */
518 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
521 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
525 EHeader
->EType
= ETYPE_IPv4
;
528 EHeader
->EType
= ETYPE_ARP
;
531 EHeader
->EType
= ETYPE_IPv6
;
535 /* Should not happen */
536 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
538 ProtocolSendComplete((NDIS_HANDLE
)Context
,
540 NDIS_STATUS_FAILURE
);
547 /* FIXME: Support other medias */
551 KeAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
552 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
553 KeReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
555 if (NdisStatus
!= NDIS_STATUS_PENDING
)
556 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
558 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
563 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
564 OBJECT_ATTRIBUTES Attributes
;
567 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
568 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
572 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
573 PWCHAR RegistryValue
,
574 PIP_ADDRESS
*Address
) {
575 UNICODE_STRING ValueName
;
576 UNICODE_STRING UnicodeAddress
;
580 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
581 ANSI_STRING AnsiAddress
;
584 RtlInitUnicodeString(&ValueName
, RegistryValue
);
586 ZwQueryValueKey(RegHandle
,
588 KeyValuePartialInformation
,
593 if (!NT_SUCCESS(Status
))
595 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
596 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
598 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
599 UnicodeAddress
.Length
= Information
->DataLength
;
600 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
602 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
604 return STATUS_NO_MEMORY
;
606 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
607 if(!AnsiAddress
.Buffer
)
608 return STATUS_NO_MEMORY
;
610 AnsiAddress
.Length
= AnsiLen
;
611 AnsiAddress
.MaximumLength
= AnsiLen
;
613 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
614 if (!NT_SUCCESS(Status
)) {
615 exFreePool(AnsiAddress
.Buffer
);
616 return STATUS_UNSUCCESSFUL
;
619 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
620 *Address
= AddrBuildIPv4(inet_addr(AnsiAddress
.Buffer
));
622 exFreePool(AnsiAddress
.Buffer
);
623 return STATUS_UNSUCCESSFUL
;
626 return *Address
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
630 PLAN_ADAPTER Adapter
,
631 PNDIS_STRING RegistryPath
)
633 * FUNCTION: Binds a LAN adapter to IP layer
635 * Adapter = Pointer to LAN_ADAPTER structure
637 * We set the lookahead buffer size, set the packet filter and
638 * bind the adapter to IP layer
642 PIP_ADDRESS Address
= 0;
643 PIP_ADDRESS Netmask
= 0;
644 NDIS_STATUS NdisStatus
;
645 LLIP_BIND_INFO BindInfo
;
646 ULONG Lookahead
= LOOKAHEAD_SIZE
;
648 HANDLE RegHandle
= 0;
650 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
652 Adapter
->State
= LAN_STATE_OPENING
;
654 NdisStatus
= NDISCall(Adapter
,
655 NdisRequestSetInformation
,
656 OID_GEN_CURRENT_LOOKAHEAD
,
659 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
660 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
664 /* Bind the adapter to IP layer */
665 BindInfo
.Context
= Adapter
;
666 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
667 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
668 BindInfo
.MTU
= Adapter
->MTU
;
669 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
670 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
671 BindInfo
.Transmit
= LANTransmit
;
673 IF
= IPCreateInterface(&BindInfo
);
676 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
681 * Query per-adapter configuration from the registry
682 * In case anyone is curious: there *is* an Ndis configuration api
683 * for this sort of thing, but it doesn't really support things like
684 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
685 * protocol drivers developed for win2k and above just use the native
686 * services (ZwOpenKey, etc).
689 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
691 if(NT_SUCCESS(Status
))
692 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
694 if(NT_SUCCESS(Status
))
695 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
698 if(!NT_SUCCESS(Status
) || !Address
|| !Netmask
)
700 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
702 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
705 if(Address
) Address
->Free(Address
);
706 if(Netmask
) Netmask
->Free(Netmask
);
707 IPDestroyInterface(IF
);
713 ("--> Our IP address on this interface: '%s'\n",
718 ("--> Our net mask on this interface: '%s'\n",
721 /* Create a net table entry for this interface */
722 if (!IPCreateNTE(IF
, Address
, AddrCountPrefixBits(Netmask
))) {
723 Netmask
->Free(Netmask
);
724 TI_DbgPrint(MIN_TRACE
, ("IPCreateNTE() failed.\n"));
725 IPDestroyInterface(IF
);
729 Netmask
->Free(Netmask
);
731 /* Reference the interface for the NTE. The reference
732 for the address is just passed on to the NTE */
735 /* Register interface with IP layer */
736 IPRegisterInterface(IF
);
738 /* Set packet filter so we can send and receive packets */
739 NdisStatus
= NDISCall(Adapter
,
740 NdisRequestSetInformation
,
741 OID_GEN_CURRENT_PACKET_FILTER
,
742 &Adapter
->PacketFilter
,
744 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
745 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
746 IPDestroyInterface(IF
);
750 Adapter
->Context
= IF
;
751 Adapter
->State
= LAN_STATE_STARTED
;
756 PLAN_ADAPTER Adapter
)
758 * FUNCTION: Unbinds a LAN adapter from IP layer
760 * Adapter = Pointer to LAN_ADAPTER structure
763 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
765 if (Adapter
->State
== LAN_STATE_STARTED
) {
766 PIP_INTERFACE IF
= Adapter
->Context
;
768 IPUnregisterInterface(IF
);
770 IPDestroyInterface(IF
);
775 NDIS_STATUS
LANRegisterAdapter(
776 PNDIS_STRING AdapterName
,
777 PNDIS_STRING RegistryPath
)
779 * FUNCTION: Registers protocol with an NDIS adapter
781 * AdapterName = Pointer to string with name of adapter to register
782 * Adapter = Address of pointer to a LAN_ADAPTER structure
784 * Status of operation
788 NDIS_STATUS NdisStatus
;
789 NDIS_STATUS OpenStatus
;
791 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
795 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
797 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
799 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
800 return NDIS_STATUS_RESOURCES
;
803 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
805 /* Put adapter in stopped state */
806 IF
->State
= LAN_STATE_STOPPED
;
808 /* Initialize protecting spin lock */
809 KeInitializeSpinLock(&IF
->Lock
);
811 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
813 /* Initialize array with media IDs we support */
814 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
816 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
817 /* Open the adapter. */
818 NdisOpenAdapter(&NdisStatus
,
830 /* Wait until the adapter is opened */
831 if (NdisStatus
== NDIS_STATUS_PENDING
)
832 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
833 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
838 IF
->Media
= MediaArray
[MediaIndex
];
840 /* Fill LAN_ADAPTER structure with some adapter specific information */
842 case NdisMedium802_3
:
843 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
844 IF
->BCastMask
= BCAST_ETH_MASK
;
845 IF
->BCastCheck
= BCAST_ETH_CHECK
;
846 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
847 IF
->HeaderSize
= sizeof(ETH_HEADER
);
848 IF
->MinFrameSize
= 60;
849 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
851 NDIS_PACKET_TYPE_BROADCAST
|
852 NDIS_PACKET_TYPE_DIRECTED
|
853 NDIS_PACKET_TYPE_MULTICAST
;
857 /* Unsupported media */
858 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
860 return NDIS_STATUS_NOT_SUPPORTED
;
863 /* Get maximum frame size */
864 NdisStatus
= NDISCall(IF
,
865 NdisRequestQueryInformation
,
866 OID_GEN_MAXIMUM_FRAME_SIZE
,
869 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
874 /* Get maximum packet size */
875 NdisStatus
= NDISCall(IF
,
876 NdisRequestQueryInformation
,
877 OID_GEN_MAXIMUM_TOTAL_SIZE
,
880 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
881 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
886 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
887 NdisStatus
= NDISCall(IF
,
888 NdisRequestQueryInformation
,
889 OID_GEN_MAXIMUM_SEND_PACKETS
,
892 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
893 /* Legacy NIC drivers may not support this query, if it fails we
894 assume it can send at least one packet per call to NdisSend(Packets) */
895 IF
->MaxSendPackets
= 1;
897 /* Get current hardware address */
898 NdisStatus
= NDISCall(IF
,
899 NdisRequestQueryInformation
,
902 IF
->HWAddressLength
);
903 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
904 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
909 /* Get maximum link speed */
910 NdisStatus
= NDISCall(IF
,
911 NdisRequestQueryInformation
,
915 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
916 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
921 /* Convert returned link speed to bps (it is in 100bps increments) */
922 IF
->Speed
= Speed
* 100L;
924 /* Add adapter to the adapter list */
925 ExInterlockedInsertTailList(&AdapterListHead
,
929 /* Bind adapter to IP layer */
930 BindAdapter(IF
, RegistryPath
);
932 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
934 return NDIS_STATUS_SUCCESS
;
938 NDIS_STATUS
LANUnregisterAdapter(
939 PLAN_ADAPTER Adapter
)
941 * FUNCTION: Unregisters protocol with NDIS adapter
943 * Adapter = Pointer to a LAN_ADAPTER structure
945 * Status of operation
949 NDIS_HANDLE NdisHandle
;
950 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
952 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
954 /* Unlink the adapter from the list */
955 RemoveEntryList(&Adapter
->ListEntry
);
957 /* Unbind adapter from IP layer */
958 UnbindAdapter(Adapter
);
960 KeAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
961 NdisHandle
= Adapter
->NdisHandle
;
963 Adapter
->NdisHandle
= NULL
;
964 KeReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
966 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
967 if (NdisStatus
== NDIS_STATUS_PENDING
) {
968 KeWaitForSingleObject(&Adapter
->Event
,
973 NdisStatus
= Adapter
->NdisStatus
;
976 KeReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
978 FreeAdapter(Adapter
);
980 return NDIS_STATUS_SUCCESS
;
984 NTSTATUS
LANRegisterProtocol(
987 * FUNCTION: Registers this protocol driver with NDIS
989 * Name = Name of this protocol driver
991 * Status of operation
994 NDIS_STATUS NdisStatus
;
995 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
997 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
999 InitializeListHead(&AdapterListHead
);
1000 KeInitializeSpinLock(&AdapterListLock
);
1002 /* Set up protocol characteristics */
1003 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1004 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1005 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1006 ProtChars
.Name
.Length
= Name
->Length
;
1007 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1008 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1009 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1010 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1011 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1012 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1013 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1014 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1015 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1016 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1017 ProtChars
.StatusHandler
= ProtocolStatus
;
1018 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1019 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1021 /* Try to register protocol */
1022 NdisRegisterProtocol(&NdisStatus
,
1023 &NdisProtocolHandle
,
1025 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1026 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1028 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1029 return (NTSTATUS
)NdisStatus
;
1032 ProtocolRegistered
= TRUE
;
1034 return STATUS_SUCCESS
;
1038 VOID
LANUnregisterProtocol(
1041 * FUNCTION: Unregisters this protocol driver with NDIS
1042 * NOTES: Does not care wether we are already registered
1045 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1047 if (ProtocolRegistered
) {
1048 NDIS_STATUS NdisStatus
;
1049 PLIST_ENTRY CurrentEntry
;
1050 PLIST_ENTRY NextEntry
;
1051 PLAN_ADAPTER Current
;
1054 KeAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1056 /* Search the list and remove every adapter we find */
1057 CurrentEntry
= AdapterListHead
.Flink
;
1058 while (CurrentEntry
!= &AdapterListHead
) {
1059 NextEntry
= CurrentEntry
->Flink
;
1060 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1062 LANUnregisterAdapter(Current
);
1063 CurrentEntry
= NextEntry
;
1066 KeReleaseSpinLock(&AdapterListLock
, OldIrql
);
1068 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1069 ProtocolRegistered
= FALSE
;
1074 InitializeListHead( &LanWorkList
);
1075 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1078 VOID
LANShutdown() {
1080 PLAN_WQ_ITEM WorkItem
;
1081 PLIST_ENTRY ListEntry
;
1083 KeAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1084 while( !IsListEmpty( &LanWorkList
) ) {
1085 ListEntry
= RemoveHeadList( &LanWorkList
);
1086 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1087 FreeNdisPacket( WorkItem
->Packet
);
1088 ExFreePool( WorkItem
);
1090 KeReleaseSpinLock( &LanWorkLock
, OldIrql
);