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
19 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
20 BOOLEAN ProtocolRegistered
= FALSE
;
21 LIST_ENTRY AdapterListHead
;
22 KSPIN_LOCK AdapterListLock
;
27 NDIS_REQUEST_TYPE Type
,
32 * FUNCTION: Send a request to NDIS
34 * Adapter = Pointer to a LAN_ADAPTER structure
35 * Type = Type of request (Set or Query)
36 * OID = Value to be set/queried for
37 * Buffer = Pointer to a buffer to use
38 * Length = Number of bytes in Buffer
44 NDIS_STATUS NdisStatus
;
46 Request
.RequestType
= Type
;
47 if (Type
== NdisRequestSetInformation
) {
48 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
49 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
50 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
52 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
53 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
54 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
57 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
58 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
60 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
63 /* Wait for NDIS to complete the request */
64 if (NdisStatus
== NDIS_STATUS_PENDING
) {
65 KeWaitForSingleObject(&Adapter
->Event
,
70 NdisStatus
= Adapter
->NdisStatus
;
77 PNDIS_PACKET
AllocateTDPacket(
80 * FUNCTION: Allocates an NDIS packet for NdisTransferData
82 * Adapter = Pointer to LAN_ADAPTER structure
84 * Pointer to NDIS packet or NULL if there was not enough free
88 NDIS_STATUS NdisStatus
;
89 PNDIS_PACKET NdisPacket
;
93 NdisAllocatePacket(&NdisStatus
, &NdisPacket
, GlobalPacketPool
);
94 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
97 Data
= ExAllocatePool(NonPagedPool
, Adapter
->MTU
);
99 NdisFreePacket(NdisPacket
);
103 NdisAllocateBuffer(&NdisStatus
,
108 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
109 NdisFreePacket(NdisPacket
);
114 NdisChainBufferAtFront(NdisPacket
, Buffer
);
116 PC(NdisPacket
)->Context
= NULL
; /* End of list */
123 PLAN_ADAPTER Adapter
)
125 * FUNCTION: Frees transfer data packets
127 * Adapter = Pointer to LAN_ADAPTER structure
130 PNDIS_PACKET NdisPacket
, Next
;
132 /* Release transfer data packets */
133 NdisPacket
= Adapter
->TDPackets
;
135 Next
= PC(NdisPacket
)->Context
;
136 FreeNdisPacket(NdisPacket
);
139 Adapter
->TDPackets
= NULL
;
144 PLAN_ADAPTER Adapter
)
146 * FUNCTION: Frees memory for a LAN_ADAPTER structure
148 * Adapter = Pointer to LAN_ADAPTER structure to free
151 FreeTDPackets(Adapter
);
156 VOID
ProtocolOpenAdapterComplete(
157 NDIS_HANDLE BindingContext
,
159 NDIS_STATUS OpenErrorStatus
)
161 * FUNCTION: Called by NDIS to complete opening of an adapter
163 * BindingContext = Pointer to a device context (LAN_ADAPTER)
164 * Status = Status of the operation
165 * OpenErrorStatus = Additional status information
168 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
170 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
172 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
176 VOID
ProtocolCloseAdapterComplete(
177 NDIS_HANDLE BindingContext
,
180 * FUNCTION: Called by NDIS to complete closing an adapter
182 * BindingContext = Pointer to a device context (LAN_ADAPTER)
183 * Status = Status of the operation
186 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
188 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
190 Adapter
->NdisStatus
= Status
;
192 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
196 VOID
ProtocolResetComplete(
197 NDIS_HANDLE BindingContext
,
200 * FUNCTION: Called by NDIS to complete resetting an adapter
202 * BindingContext = Pointer to a device context (LAN_ADAPTER)
203 * Status = Status of the operation
206 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
210 VOID
ProtocolRequestComplete(
211 NDIS_HANDLE BindingContext
,
212 PNDIS_REQUEST NdisRequest
,
215 * FUNCTION: Called by NDIS to complete a request
217 * BindingContext = Pointer to a device context (LAN_ADAPTER)
218 * NdisRequest = Pointer to an object describing the request
219 * Status = Status of the operation
222 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
224 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
226 /* Save status of request and signal an event */
227 Adapter
->NdisStatus
= Status
;
229 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
233 VOID
ProtocolSendComplete(
234 NDIS_HANDLE BindingContext
,
238 * FUNCTION: Called by NDIS to complete sending process
240 * BindingContext = Pointer to a device context (LAN_ADAPTER)
241 * Packet = Pointer to a packet descriptor
242 * Status = Status of the operation
245 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
247 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
249 AdjustPacket(Packet
, Adapter
->HeaderSize
, PC(Packet
)->DLOffset
);
251 (*PC(Packet
)->DLComplete
)(Adapter
->Context
, Packet
, Status
);
255 VOID
ProtocolTransferDataComplete(
256 NDIS_HANDLE BindingContext
,
259 UINT BytesTransferred
)
261 * FUNCTION: Called by NDIS to complete reception of data
263 * BindingContext = Pointer to a device context (LAN_ADAPTER)
264 * Packet = Pointer to a packet descriptor
265 * Status = Status of the operation
266 * BytesTransferred = Number of bytes transferred
268 * If the packet was successfully received, determine the protocol
269 * type and pass it to the correct receive handler
273 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
275 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
277 if (Status
== NDIS_STATUS_SUCCESS
) {
278 PNDIS_BUFFER NdisBuffer
;
281 IPPacket
.NdisPacket
= Packet
;
283 NdisGetFirstBufferFromPacket(Packet
,
286 &IPPacket
.ContigSize
,
287 &IPPacket
.TotalSize
);
289 /* Determine which upper layer protocol that should receive
290 this packet and pass it to the correct receive handler */
291 PacketType
= ((PETH_HEADER
)IPPacket
.Header
)->EType
;
292 switch (PacketType
) {
295 IPReceive(Adapter
->Context
, &IPPacket
);
298 ARPReceive(Adapter
->Context
, &IPPacket
);
304 /* Release the packet descriptor */
305 KeAcquireSpinLockAtDpcLevel(&Adapter
->Lock
);
307 PC(Packet
)->Context
= Adapter
->TDPackets
;
308 Adapter
->TDPackets
= Packet
;
310 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
314 NDIS_STATUS
ProtocolReceive(
315 NDIS_HANDLE BindingContext
,
316 NDIS_HANDLE MacReceiveContext
,
318 UINT HeaderBufferSize
,
319 PVOID LookaheadBuffer
,
320 UINT LookaheadBufferSize
,
323 * FUNCTION: Called by NDIS when a packet has been received on the physical link
325 * BindingContext = Pointer to a device context (LAN_ADAPTER)
326 * MacReceiveContext = Handle used by underlying NIC driver
327 * HeaderBuffer = Pointer to a buffer containing the packet header
328 * HeaderBufferSize = Number of bytes in HeaderBuffer
329 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
330 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
331 * PacketSize = Overall size of the packet (not including header)
333 * Status of operation
339 PNDIS_PACKET NdisPacket
;
340 PNDIS_BUFFER NdisBuffer
;
341 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
342 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
344 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
346 if (Adapter
->State
!= LAN_STATE_STARTED
) {
347 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
348 return NDIS_STATUS_NOT_ACCEPTED
;
351 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
352 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
353 return NDIS_STATUS_NOT_ACCEPTED
;
356 if (Adapter
->Media
== NdisMedium802_3
) {
357 /* Ethernet and IEEE 802.3 frames can be destinguished by
358 looking at the IEEE 802.3 length field. This field is
359 less than or equal to 1500 for a valid IEEE 802.3 frame
360 and larger than 1500 is it's a valid EtherType value.
361 See RFC 1122, section 2.3.3 for more information */
362 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
363 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
364 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
365 return NDIS_STATUS_NOT_ACCEPTED
;
367 /* We use EtherType constants to destinguish packet types */
370 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
371 /* FIXME: Support other medias */
372 return NDIS_STATUS_NOT_ACCEPTED
;
375 /* Get a transfer data packet */
377 KeAcquireSpinLockAtDpcLevel(&Adapter
->Lock
);
379 NdisPacket
= Adapter
->TDPackets
;
380 if (NdisPacket
== (PNDIS_PACKET
)NULL
) {
381 TI_DbgPrint(DEBUG_DATALINK
, ("No available packet descriptors.\n"));
382 /* We don't have a free packet descriptor. Drop the packet */
383 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
384 return NDIS_STATUS_SUCCESS
;
386 Adapter
->TDPackets
= PC(NdisPacket
)->Context
;
388 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
390 if (LookaheadBufferSize
< PacketSize
) {
391 NDIS_STATUS NdisStatus
;
392 UINT BytesTransferred
;
395 NdisTransferData(&NdisStatus
,
402 if (NdisStatus
!= NDIS_STATUS_PENDING
)
403 ProtocolTransferDataComplete(BindingContext
,
408 return NDIS_STATUS_SUCCESS
;
411 /* We got all the data in the lookahead buffer */
413 IPPacket
.NdisPacket
= NdisPacket
;
415 NdisGetFirstBufferFromPacket(NdisPacket
,
418 &IPPacket
.ContigSize
,
419 &IPPacket
.TotalSize
);
421 RtlCopyMemory(IPPacket
.Header
, LookaheadBuffer
, PacketSize
);
423 switch (PacketType
) {
426 IPReceive(Adapter
->Context
, &IPPacket
);
429 ARPReceive(Adapter
->Context
, &IPPacket
);
435 /* Release the packet descriptor */
436 KeAcquireSpinLockAtDpcLevel(&Adapter
->Lock
);
438 PC(NdisPacket
)->Context
= Adapter
->TDPackets
;
439 Adapter
->TDPackets
= NdisPacket
;
441 KeReleaseSpinLockFromDpcLevel(&Adapter
->Lock
);
443 return NDIS_STATUS_SUCCESS
;
447 VOID
ProtocolReceiveComplete(
448 NDIS_HANDLE BindingContext
)
450 * FUNCTION: Called by NDIS when we're done receiving data
452 * BindingContext = Pointer to a device context (LAN_ADAPTER)
455 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
460 NDIS_HANDLE BindingContext
,
461 NDIS_STATUS GenerelStatus
,
463 UINT StatusBufferSize
)
465 * FUNCTION: Called by NDIS when the underlying driver has changed state
467 * BindingContext = Pointer to a device context (LAN_ADAPTER)
468 * GenerelStatus = A generel status code
469 * StatusBuffer = Pointer to a buffer with medium-specific data
470 * StatusBufferSize = Number of bytes in StatusBuffer
473 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
477 VOID
ProtocolStatusComplete(
478 NDIS_HANDLE NdisBindingContext
)
480 * FUNCTION: Called by NDIS when a status-change has occurred
482 * BindingContext = Pointer to a device context (LAN_ADAPTER)
485 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
488 VOID
ProtocolBindAdapter(
489 OUT PNDIS_STATUS Status
,
490 IN NDIS_HANDLE BindContext
,
491 IN PNDIS_STRING DeviceName
,
492 IN PVOID SystemSpecific1
,
493 IN PVOID SystemSpecific2
)
495 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
496 * bindings, and periodically thereafer as new adapters come online
498 * Status: Return value to NDIS
499 * BindContext: Handle provided by NDIS to track pending binding operations
500 * DeviceName: Name of the miniport device to bind to
501 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
502 * SystemSpecific2: Unused & must not be touched
505 /* XXX confirm that this is still true, or re-word the following comment */
506 /* we get to ignore BindContext because we will never pend an operation with NDIS */
507 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ\n", SystemSpecific1
));
508 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
514 PNDIS_PACKET NdisPacket
,
519 * FUNCTION: Transmits a packet
521 * Context = Pointer to context information (LAN_ADAPTER)
522 * NdisPacket = Pointer to NDIS packet to send
523 * Offset = Offset in packet where data starts
524 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
525 * Type = LAN protocol type (LAN_PROTO_*)
528 NDIS_STATUS NdisStatus
;
531 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
533 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
535 /* NDIS send routines don't have an offset argument so we
536 must offset the data in upper layers and adjust the
537 packet here. We save the offset in the packet context
538 area so it can be undone before we release the packet */
539 Data
= AdjustPacket(NdisPacket
, Offset
, Adapter
->HeaderSize
);
540 PC(NdisPacket
)->DLOffset
= Offset
;
542 if (Adapter
->State
== LAN_STATE_STARTED
) {
543 switch (Adapter
->Media
) {
544 case NdisMedium802_3
:
545 EHeader
= (PETH_HEADER
)Data
;
548 /* Unicast address */
549 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
551 /* Broadcast address */
552 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
555 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
559 EHeader
->EType
= ETYPE_IPv4
;
562 EHeader
->EType
= ETYPE_ARP
;
565 EHeader
->EType
= ETYPE_IPv6
;
569 /* Should not happen */
570 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
572 ProtocolSendComplete((NDIS_HANDLE
)Context
,
574 NDIS_STATUS_FAILURE
);
581 /* FIXME: Support other medias */
585 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
586 if (NdisStatus
!= NDIS_STATUS_PENDING
)
587 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
589 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
595 PLAN_ADAPTER Adapter
,
596 PNDIS_STRING RegistryPath
)
598 * FUNCTION: Binds a LAN adapter to IP layer
600 * Adapter = Pointer to LAN_ADAPTER structure
602 * We set the lookahead buffer size, set the packet filter and
603 * bind the adapter to IP layer
610 NDIS_STATUS NdisStatus
;
611 LLIP_BIND_INFO BindInfo
;
612 ULONG Lookahead
= LOOKAHEAD_SIZE
;
614 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
616 Adapter
->State
= LAN_STATE_OPENING
;
618 NdisStatus
= NDISCall(Adapter
,
619 NdisRequestSetInformation
,
620 OID_GEN_CURRENT_LOOKAHEAD
,
623 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
624 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
628 /* Allocate packets for NdisTransferData */
629 /* FIXME: How many should we allocate? */
630 Adapter
->TDPackets
= NULL
;
631 for (i
= 0; i
< 2; i
++) {
632 Packet
= AllocateTDPacket(Adapter
);
634 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
635 FreeTDPackets(Adapter
);
638 PC(Packet
)->Context
= Adapter
->TDPackets
;
639 Adapter
->TDPackets
= Packet
;
642 /* Bind the adapter to IP layer */
643 BindInfo
.Context
= Adapter
;
644 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
645 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
646 BindInfo
.MTU
= Adapter
->MTU
;
647 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
648 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
649 BindInfo
.Transmit
= LANTransmit
;
651 IF
= IPCreateInterface(&BindInfo
);
653 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
654 FreeTDPackets(Adapter
);
660 * Query per-adapter configuration from the registry
661 * In case anyone is curious: there *is* an Ndis configuration api
662 * for this sort of thing, but it doesn't really support things like
663 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
664 * protocol drivers developed for win2k and above just use the native
665 * services (ZwOpenKey, etc).
668 OBJECT_ATTRIBUTES Attributes
;
671 UNICODE_STRING ValueName
;
673 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
675 ANSI_STRING AnsiAddress
;
676 UNICODE_STRING UnicodeAddress
;
679 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
680 Status
= ZwOpenKey(&RegHandle
, GENERIC_READ
, &Attributes
);
682 if(!NT_SUCCESS(Status
))
684 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
686 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
687 FreeTDPackets(Adapter
);
688 IPDestroyInterface(Adapter
->Context
);
692 RtlInitUnicodeString(&ValueName
, L
"IPAddress");
693 ZwQueryValueKey(RegHandle
, &ValueName
, KeyValuePartialInformation
, Information
, sizeof(buf
), &ResultLength
);
696 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
697 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
699 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
700 UnicodeAddress
.Length
= Information
->DataLength
;
701 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
703 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
706 TI_DbgPrint(MIN_TRACE
, ("Unable to calculate address length\n"));
707 FreeTDPackets(Adapter
);
708 IPDestroyInterface(Adapter
->Context
);
712 AnsiAddress
.Buffer
= ExAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
713 if(!AnsiAddress
.Buffer
)
715 TI_DbgPrint(MIN_TRACE
, ("ExAllocatePoolWithTag() failed.\n"));
716 FreeTDPackets(Adapter
);
717 IPDestroyInterface(Adapter
->Context
);
720 AnsiAddress
.Length
= AnsiLen
;
721 AnsiAddress
.MaximumLength
= AnsiLen
;
723 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
724 if (!NT_SUCCESS(Status
))
726 TI_DbgPrint(MIN_TRACE
, ("RtlUnicodeStringToAnsiString() failed with Status 0x%lx.\n", Status
));
727 FreeTDPackets(Adapter
);
728 IPDestroyInterface(Adapter
->Context
);
732 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
733 Address
= AddrBuildIPv4(inet_addr(AnsiAddress
.Buffer
));
735 TI_DbgPrint(MIN_TRACE
, ("AddrBuildIPv4() failed.\n"));
736 FreeTDPackets(Adapter
);
737 IPDestroyInterface(Adapter
->Context
);
741 TI_DbgPrint(MID_TRACE
, ("--> Our IP address on this interface: '%s'\n", A2S(Address
)));
744 /* Create a net table entry for this interface */
745 if (!IPCreateNTE(IF
, Address
, 8)) {
746 TI_DbgPrint(MIN_TRACE
, ("IPCreateNTE() failed.\n"));
747 FreeTDPackets(Adapter
);
748 IPDestroyInterface(IF
);
752 /* Reference the interface for the NTE. The reference
753 for the address is just passed on to the NTE */
756 /* Register interface with IP layer */
757 IPRegisterInterface(IF
);
759 /* Set packet filter so we can send and receive packets */
760 NdisStatus
= NDISCall(Adapter
,
761 NdisRequestSetInformation
,
762 OID_GEN_CURRENT_PACKET_FILTER
,
763 &Adapter
->PacketFilter
,
765 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
766 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
767 FreeTDPackets(Adapter
);
768 IPDestroyInterface(IF
);
772 Adapter
->Context
= IF
;
774 Adapter
->State
= LAN_STATE_STARTED
;
779 PLAN_ADAPTER Adapter
)
781 * FUNCTION: Unbinds a LAN adapter from IP layer
783 * Adapter = Pointer to LAN_ADAPTER structure
786 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
788 if (Adapter
->State
== LAN_STATE_STARTED
) {
789 PIP_INTERFACE IF
= Adapter
->Context
;
791 IPUnregisterInterface(IF
);
793 IPDestroyInterface(IF
);
795 /* Free transfer data packets */
796 FreeTDPackets(Adapter
);
801 NDIS_STATUS
LANRegisterAdapter(
802 PNDIS_STRING AdapterName
,
803 PNDIS_STRING RegistryPath
)
805 * FUNCTION: Registers protocol with an NDIS adapter
807 * AdapterName = Pointer to string with name of adapter to register
808 * Adapter = Address of pointer to a LAN_ADAPTER structure
810 * Status of operation
814 NDIS_STATUS NdisStatus
;
815 NDIS_STATUS OpenStatus
;
816 PNDIS_CONFIGURATION_PARAMETER Parameter
;
818 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
822 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
824 IF
= ExAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
826 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
827 return NDIS_STATUS_RESOURCES
;
830 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
832 /* Put adapter in stopped state */
833 IF
->State
= LAN_STATE_STOPPED
;
835 /* Initialize protecting spin lock */
836 KeInitializeSpinLock(&IF
->Lock
);
838 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
840 /* Initialize array with media IDs we support */
841 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
843 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
844 /* Open the adapter. */
845 NdisOpenAdapter(&NdisStatus
,
857 /* Wait until the adapter is opened */
858 if (NdisStatus
== NDIS_STATUS_PENDING
)
859 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
860 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
865 IF
->Media
= MediaArray
[MediaIndex
];
867 /* Fill LAN_ADAPTER structure with some adapter specific information */
869 case NdisMedium802_3
:
870 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
871 IF
->BCastMask
= BCAST_ETH_MASK
;
872 IF
->BCastCheck
= BCAST_ETH_CHECK
;
873 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
874 IF
->HeaderSize
= sizeof(ETH_HEADER
);
875 IF
->MinFrameSize
= 60;
876 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
878 NDIS_PACKET_TYPE_BROADCAST
|
879 NDIS_PACKET_TYPE_DIRECTED
|
880 NDIS_PACKET_TYPE_MULTICAST
;
884 /* Unsupported media */
885 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
887 return NDIS_STATUS_NOT_SUPPORTED
;
890 /* Get maximum frame size */
891 NdisStatus
= NDISCall(IF
,
892 NdisRequestQueryInformation
,
893 OID_GEN_MAXIMUM_FRAME_SIZE
,
896 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
901 /* Get maximum packet size */
902 NdisStatus
= NDISCall(IF
,
903 NdisRequestQueryInformation
,
904 OID_GEN_MAXIMUM_TOTAL_SIZE
,
907 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
908 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
913 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
914 NdisStatus
= NDISCall(IF
,
915 NdisRequestQueryInformation
,
916 OID_GEN_MAXIMUM_SEND_PACKETS
,
919 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
920 /* Legacy NIC drivers may not support this query, if it fails we
921 assume it can send at least one packet per call to NdisSend(Packets) */
922 IF
->MaxSendPackets
= 1;
924 /* Get current hardware address */
925 NdisStatus
= NDISCall(IF
,
926 NdisRequestQueryInformation
,
929 IF
->HWAddressLength
);
930 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
931 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
936 /* Get maximum link speed */
937 NdisStatus
= NDISCall(IF
,
938 NdisRequestQueryInformation
,
942 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
943 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
948 /* Convert returned link speed to bps (it is in 100bps increments) */
949 IF
->Speed
= Speed
* 100L;
951 /* Add adapter to the adapter list */
952 ExInterlockedInsertTailList(&AdapterListHead
,
956 /* Bind adapter to IP layer */
957 BindAdapter(IF
, RegistryPath
);
959 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
961 return NDIS_STATUS_SUCCESS
;
965 NDIS_STATUS
LANUnregisterAdapter(
966 PLAN_ADAPTER Adapter
)
968 * FUNCTION: Unregisters protocol with NDIS adapter
970 * Adapter = Pointer to a LAN_ADAPTER structure
972 * Status of operation
976 NDIS_HANDLE NdisHandle
;
977 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
979 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
981 /* Unlink the adapter from the list */
982 RemoveEntryList(&Adapter
->ListEntry
);
984 /* Unbind adapter from IP layer */
985 UnbindAdapter(Adapter
);
987 KeAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
988 NdisHandle
= Adapter
->NdisHandle
;
990 Adapter
->NdisHandle
= NULL
;
991 KeReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
993 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
994 if (NdisStatus
== NDIS_STATUS_PENDING
) {
995 KeWaitForSingleObject(&Adapter
->Event
,
1000 NdisStatus
= Adapter
->NdisStatus
;
1003 KeReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1005 FreeAdapter(Adapter
);
1007 return NDIS_STATUS_SUCCESS
;
1011 NTSTATUS
LANRegisterProtocol(
1014 * FUNCTION: Registers this protocol driver with NDIS
1016 * Name = Name of this protocol driver
1018 * Status of operation
1021 NDIS_STATUS NdisStatus
;
1022 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1024 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1026 InitializeListHead(&AdapterListHead
);
1027 KeInitializeSpinLock(&AdapterListLock
);
1029 /* Set up protocol characteristics */
1030 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1031 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1032 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1033 ProtChars
.Name
.Length
= Name
->Length
;
1034 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1035 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1036 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1037 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1038 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1039 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1040 ProtChars
.u2
.SendCompleteHandler
= ProtocolSendComplete
;
1041 ProtChars
.u3
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1042 ProtChars
.u4
.ReceiveHandler
= ProtocolReceive
;
1043 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1044 ProtChars
.StatusHandler
= ProtocolStatus
;
1045 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1046 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1048 /* Try to register protocol */
1049 NdisRegisterProtocol(&NdisStatus
,
1050 &NdisProtocolHandle
,
1052 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1053 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1055 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1056 return (NTSTATUS
)NdisStatus
;
1059 ProtocolRegistered
= TRUE
;
1061 return STATUS_SUCCESS
;
1065 VOID
LANUnregisterProtocol(
1068 * FUNCTION: Unregisters this protocol driver with NDIS
1069 * NOTES: Does not care wether we are already registered
1072 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1074 if (ProtocolRegistered
) {
1075 NDIS_STATUS NdisStatus
;
1076 PLIST_ENTRY CurrentEntry
;
1077 PLIST_ENTRY NextEntry
;
1078 PLAN_ADAPTER Current
;
1081 KeAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1083 /* Search the list and remove every adapter we find */
1084 CurrentEntry
= AdapterListHead
.Flink
;
1085 while (CurrentEntry
!= &AdapterListHead
) {
1086 NextEntry
= CurrentEntry
->Flink
;
1087 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1089 LANUnregisterAdapter(Current
);
1090 CurrentEntry
= NextEntry
;
1093 KeReleaseSpinLock(&AdapterListLock
, OldIrql
);
1095 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1096 ProtocolRegistered
= FALSE
;