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
17 UINT TransferDataCalled
= 0;
18 UINT TransferDataCompleteCalled
= 0;
20 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
21 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
23 typedef struct _LAN_WQ_ITEM
{
27 UINT BytesTransferred
;
28 BOOLEAN LegacyReceive
;
29 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
31 typedef struct _RECONFIGURE_CONTEXT
{
34 } RECONFIGURE_CONTEXT
, *PRECONFIGURE_CONTEXT
;
36 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
37 BOOLEAN ProtocolRegistered
= FALSE
;
38 LIST_ENTRY AdapterListHead
;
39 KSPIN_LOCK AdapterListLock
;
43 NDIS_REQUEST_TYPE Type
,
48 * FUNCTION: Send a request to NDIS
50 * Adapter = Pointer to a LAN_ADAPTER structure
51 * Type = Type of request (Set or Query)
52 * OID = Value to be set/queried for
53 * Buffer = Pointer to a buffer to use
54 * Length = Number of bytes in Buffer
60 NDIS_STATUS NdisStatus
;
62 Request
.RequestType
= Type
;
63 if (Type
== NdisRequestSetInformation
) {
64 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
65 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
66 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
68 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
69 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
70 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
73 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
74 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
76 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
79 /* Wait for NDIS to complete the request */
80 if (NdisStatus
== NDIS_STATUS_PENDING
) {
81 KeWaitForSingleObject(&Adapter
->Event
,
86 NdisStatus
= Adapter
->NdisStatus
;
92 /* Used by legacy ProtocolReceive for packet type */
94 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter
,
96 ULONG HeaderBufferSize
,
99 PETH_HEADER EthHeader
= HeaderBuffer
;
101 if (HeaderBufferSize
< Adapter
->HeaderSize
)
103 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", HeaderBufferSize
));
104 return NDIS_STATUS_NOT_ACCEPTED
;
107 switch (Adapter
->Media
)
109 case NdisMedium802_3
:
110 /* Ethernet and IEEE 802.3 frames can be distinguished by
111 looking at the IEEE 802.3 length field. This field is
112 less than or equal to 1500 for a valid IEEE 802.3 frame
113 and larger than 1500 is it's a valid EtherType value.
114 See RFC 1122, section 2.3.3 for more information */
116 *PacketType
= EthHeader
->EType
;
120 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
122 /* FIXME: Support other medias */
123 return NDIS_STATUS_NOT_ACCEPTED
;
126 TI_DbgPrint(DEBUG_DATALINK
, ("EtherType (0x%X).\n", *PacketType
));
128 return NDIS_STATUS_SUCCESS
;
131 /* Used by ProtocolReceivePacket for packet type */
133 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter
,
134 PNDIS_PACKET NdisPacket
,
141 HeaderBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
145 return NDIS_STATUS_RESOURCES
;
147 /* Copy the media header */
148 BytesCopied
= CopyPacketToBuffer(HeaderBuffer
,
151 Adapter
->HeaderSize
);
152 if (BytesCopied
!= Adapter
->HeaderSize
)
155 ExFreePoolWithTag(HeaderBuffer
, HEADER_TAG
);
156 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", BytesCopied
));
157 return NDIS_STATUS_NOT_ACCEPTED
;
160 Status
= GetPacketTypeFromHeaderBuffer(Adapter
,
165 ExFreePoolWithTag(HeaderBuffer
, HEADER_TAG
);
172 PLAN_ADAPTER Adapter
)
174 * FUNCTION: Frees memory for a LAN_ADAPTER structure
176 * Adapter = Pointer to LAN_ADAPTER structure to free
179 ExFreePoolWithTag(Adapter
, LAN_ADAPTER_TAG
);
183 NTSTATUS TcpipLanGetDwordOid
184 ( PIP_INTERFACE Interface
,
187 /* Get maximum frame size */
188 if( Interface
->Context
) {
189 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
190 NdisRequestQueryInformation
,
194 } else switch( Oid
) { /* Loopback Case */
195 case OID_GEN_HARDWARE_STATUS
:
196 *Result
= NdisHardwareStatusReady
;
197 return STATUS_SUCCESS
;
198 case OID_GEN_MEDIA_CONNECT_STATUS
:
199 *Result
= NdisMediaStateConnected
;
200 return STATUS_SUCCESS
;
202 return STATUS_INVALID_PARAMETER
;
207 VOID NTAPI
ProtocolOpenAdapterComplete(
208 NDIS_HANDLE BindingContext
,
210 NDIS_STATUS OpenErrorStatus
)
212 * FUNCTION: Called by NDIS to complete opening of an adapter
214 * BindingContext = Pointer to a device context (LAN_ADAPTER)
215 * Status = Status of the operation
216 * OpenErrorStatus = Additional status information
219 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
221 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
223 Adapter
->NdisStatus
= Status
;
225 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
229 VOID NTAPI
ProtocolCloseAdapterComplete(
230 NDIS_HANDLE BindingContext
,
233 * FUNCTION: Called by NDIS to complete closing an adapter
235 * BindingContext = Pointer to a device context (LAN_ADAPTER)
236 * Status = Status of the operation
239 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
241 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
243 Adapter
->NdisStatus
= Status
;
245 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
249 VOID NTAPI
ProtocolResetComplete(
250 NDIS_HANDLE BindingContext
,
253 * FUNCTION: Called by NDIS to complete resetting an adapter
255 * BindingContext = Pointer to a device context (LAN_ADAPTER)
256 * Status = Status of the operation
259 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
261 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
263 Adapter
->NdisStatus
= Status
;
265 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
269 VOID NTAPI
ProtocolRequestComplete(
270 NDIS_HANDLE BindingContext
,
271 PNDIS_REQUEST NdisRequest
,
274 * FUNCTION: Called by NDIS to complete a request
276 * BindingContext = Pointer to a device context (LAN_ADAPTER)
277 * NdisRequest = Pointer to an object describing the request
278 * Status = Status of the operation
281 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
283 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
285 /* Save status of request and signal an event */
286 Adapter
->NdisStatus
= Status
;
288 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
292 VOID NTAPI
ProtocolSendComplete(
293 NDIS_HANDLE BindingContext
,
297 * FUNCTION: Called by NDIS to complete sending process
299 * BindingContext = Pointer to a device context (LAN_ADAPTER)
300 * Packet = Pointer to a packet descriptor
301 * Status = Status of the operation
304 FreeNdisPacket(Packet
);
307 VOID
LanReceiveWorker( PVOID Context
) {
309 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
311 PLAN_ADAPTER Adapter
;
312 UINT BytesTransferred
;
314 BOOLEAN LegacyReceive
;
315 PIP_INTERFACE Interface
;
317 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
319 Packet
= WorkItem
->Packet
;
320 Adapter
= WorkItem
->Adapter
;
321 BytesTransferred
= WorkItem
->BytesTransferred
;
322 LegacyReceive
= WorkItem
->LegacyReceive
;
324 ExFreePoolWithTag(WorkItem
, WQ_CONTEXT_TAG
);
326 Interface
= Adapter
->Context
;
328 IPInitializePacket(&IPPacket
, 0);
330 IPPacket
.NdisPacket
= Packet
;
331 IPPacket
.ReturnPacket
= !LegacyReceive
;
335 /* Packet type is precomputed */
336 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
338 /* Data is at position 0 */
339 IPPacket
.Position
= 0;
341 /* Packet size is determined by bytes transferred */
342 IPPacket
.TotalSize
= BytesTransferred
;
346 /* Determine packet type from media header */
347 if (GetPacketTypeFromNdisPacket(Adapter
,
349 &PacketType
) != NDIS_STATUS_SUCCESS
)
352 IPPacket
.Free(&IPPacket
);
356 /* Data is at the end of the media header */
357 IPPacket
.Position
= Adapter
->HeaderSize
;
359 /* Calculate packet size (excluding media header) */
360 NdisQueryPacketLength(IPPacket
.NdisPacket
, &IPPacket
.TotalSize
);
365 ("Ether Type = %x Total = %d\n",
366 PacketType
, IPPacket
.TotalSize
));
368 /* Update interface stats */
369 Interface
->Stats
.InBytes
+= IPPacket
.TotalSize
+ Adapter
->HeaderSize
;
371 /* NDIS packet is freed in all of these cases */
372 switch (PacketType
) {
375 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
376 IPReceive(Adapter
->Context
, &IPPacket
);
379 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
380 ARPReceive(Adapter
->Context
, &IPPacket
);
383 IPPacket
.Free(&IPPacket
);
388 VOID
LanSubmitReceiveWork(
389 NDIS_HANDLE BindingContext
,
391 UINT BytesTransferred
,
392 BOOLEAN LegacyReceive
) {
393 PLAN_WQ_ITEM WQItem
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_WQ_ITEM
),
395 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
397 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
401 WQItem
->Packet
= Packet
;
402 WQItem
->Adapter
= Adapter
;
403 WQItem
->BytesTransferred
= BytesTransferred
;
404 WQItem
->LegacyReceive
= LegacyReceive
;
406 if (!ChewCreate( LanReceiveWorker
, WQItem
))
407 ExFreePoolWithTag(WQItem
, WQ_CONTEXT_TAG
);
410 VOID NTAPI
ProtocolTransferDataComplete(
411 NDIS_HANDLE BindingContext
,
414 UINT BytesTransferred
)
416 * FUNCTION: Called by NDIS to complete reception of data
418 * BindingContext = Pointer to a device context (LAN_ADAPTER)
419 * Packet = Pointer to a packet descriptor
420 * Status = Status of the operation
421 * BytesTransferred = Number of bytes transferred
423 * If the packet was successfully received, determine the protocol
424 * type and pass it to the correct receive handler
427 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
429 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
431 TransferDataCompleteCalled
++;
432 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
434 if( Status
!= NDIS_STATUS_SUCCESS
) return;
436 LanSubmitReceiveWork(BindingContext
,
442 INT NTAPI
ProtocolReceivePacket(
443 NDIS_HANDLE BindingContext
,
444 PNDIS_PACKET NdisPacket
)
446 PLAN_ADAPTER Adapter
= BindingContext
;
448 if (Adapter
->State
!= LAN_STATE_STARTED
) {
449 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
453 LanSubmitReceiveWork(BindingContext
,
458 /* Hold 1 reference on this packet */
462 NDIS_STATUS NTAPI
ProtocolReceive(
463 NDIS_HANDLE BindingContext
,
464 NDIS_HANDLE MacReceiveContext
,
466 UINT HeaderBufferSize
,
467 PVOID LookaheadBuffer
,
468 UINT LookaheadBufferSize
,
471 * FUNCTION: Called by NDIS when a packet has been received on the physical link
473 * BindingContext = Pointer to a device context (LAN_ADAPTER)
474 * MacReceiveContext = Handle used by underlying NIC driver
475 * HeaderBuffer = Pointer to a buffer containing the packet header
476 * HeaderBufferSize = Number of bytes in HeaderBuffer
477 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
478 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
479 * PacketSize = Overall size of the packet (not including header)
481 * Status of operation
485 UINT BytesTransferred
;
487 NDIS_STATUS NdisStatus
;
488 PNDIS_PACKET NdisPacket
;
489 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
491 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
493 if (Adapter
->State
!= LAN_STATE_STARTED
) {
494 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
495 return NDIS_STATUS_NOT_ACCEPTED
;
498 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
499 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
500 return NDIS_STATUS_NOT_ACCEPTED
;
503 NdisStatus
= GetPacketTypeFromHeaderBuffer(Adapter
,
507 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
508 return NDIS_STATUS_NOT_ACCEPTED
;
510 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
511 Adapter
, Adapter
->MTU
));
513 /* Get a transfer data packet */
514 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
516 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
517 return NDIS_STATUS_NOT_ACCEPTED
;
520 PC(NdisPacket
)->PacketType
= PacketType
;
522 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
524 GetDataPtr( NdisPacket
, 0, &BufferData
, &PacketSize
);
526 TransferDataCalled
++;
528 if (LookaheadBufferSize
== PacketSize
)
530 /* Optimized code path for packets that are fully contained in
531 * the lookahead buffer. */
532 NdisCopyLookaheadData(BufferData
,
535 Adapter
->MacOptions
);
539 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
540 MacReceiveContext
, 0, PacketSize
,
541 NdisPacket
, &BytesTransferred
);
543 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
545 if (NdisStatus
!= NDIS_STATUS_PENDING
)
546 ProtocolTransferDataComplete(BindingContext
,
551 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
553 return NDIS_STATUS_SUCCESS
;
557 VOID NTAPI
ProtocolReceiveComplete(
558 NDIS_HANDLE BindingContext
)
560 * FUNCTION: Called by NDIS when we're done receiving data
562 * BindingContext = Pointer to a device context (LAN_ADAPTER)
565 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
568 BOOLEAN
ReadIpConfiguration(PIP_INTERFACE Interface
)
570 OBJECT_ATTRIBUTES ObjectAttributes
;
571 HANDLE ParameterHandle
;
572 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo
;
574 UNICODE_STRING IPAddress
= RTL_CONSTANT_STRING(L
"IPAddress");
575 UNICODE_STRING Netmask
= RTL_CONSTANT_STRING(L
"SubnetMask");
576 UNICODE_STRING Gateway
= RTL_CONSTANT_STRING(L
"DefaultGateway");
577 UNICODE_STRING EnableDhcp
= RTL_CONSTANT_STRING(L
"EnableDHCP");
578 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
579 UNICODE_STRING TcpipRegistryPath
;
580 UNICODE_STRING RegistryDataU
;
581 ANSI_STRING RegistryDataA
;
584 IP_ADDRESS DefaultMask
, Router
;
586 AddrInitIPv4(&DefaultMask
, 0);
588 TcpipRegistryPath
.MaximumLength
= sizeof(WCHAR
) * 150;
589 TcpipRegistryPath
.Length
= 0;
590 TcpipRegistryPath
.Buffer
= Buffer
;
592 /* Build the registry path */
593 RtlAppendUnicodeStringToString(&TcpipRegistryPath
, &Prefix
);
594 RtlAppendUnicodeStringToString(&TcpipRegistryPath
, &Interface
->Name
);
596 InitializeObjectAttributes(&ObjectAttributes
,
598 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
602 /* Open a handle to the adapter parameters */
603 Status
= ZwOpenKey(&ParameterHandle
, KEY_READ
, &ObjectAttributes
);
605 if (!NT_SUCCESS(Status
))
611 KeyValueInfo
= ExAllocatePoolWithTag(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
), KEY_VALUE_TAG
);
614 ZwClose(ParameterHandle
);
618 /* Read the EnableDHCP entry */
619 Status
= ZwQueryValueKey(ParameterHandle
,
621 KeyValuePartialInformation
,
623 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
),
625 if (NT_SUCCESS(Status
) && KeyValueInfo
->DataLength
== sizeof(ULONG
) && (*(PULONG
)KeyValueInfo
->Data
) == 0)
627 RegistryDataU
.MaximumLength
= 16 + sizeof(WCHAR
);
628 RegistryDataU
.Buffer
= (PWCHAR
)KeyValueInfo
->Data
;
630 /* Read the IP address */
631 Status
= ZwQueryValueKey(ParameterHandle
,
633 KeyValuePartialInformation
,
635 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
637 if (NT_SUCCESS(Status
))
639 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
641 Status
= RtlUnicodeStringToAnsiString(&RegistryDataA
,
644 if (NT_SUCCESS(Status
))
646 AddrInitIPv4(&Interface
->Unicast
,
647 inet_addr(RegistryDataA
.Buffer
));
648 RtlFreeAnsiString(&RegistryDataA
);
652 Status
= ZwQueryValueKey(ParameterHandle
,
654 KeyValuePartialInformation
,
656 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
658 if (NT_SUCCESS(Status
))
660 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
662 Status
= RtlUnicodeStringToAnsiString(&RegistryDataA
,
665 if (NT_SUCCESS(Status
))
667 AddrInitIPv4(&Interface
->Netmask
,
668 inet_addr(RegistryDataA
.Buffer
));
669 RtlFreeAnsiString(&RegistryDataA
);
673 /* We have to wait until both IP address and subnet mask
674 * are read to add the interface route, but we must do it
675 * before we add the default gateway */
676 if (!AddrIsUnspecified(&Interface
->Unicast
) &&
677 !AddrIsUnspecified(&Interface
->Netmask
))
678 IPAddInterfaceRoute(Interface
);
680 /* Read default gateway info */
681 Status
= ZwQueryValueKey(ParameterHandle
,
683 KeyValuePartialInformation
,
685 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
687 if (NT_SUCCESS(Status
))
689 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
691 Status
= RtlUnicodeStringToAnsiString(&RegistryDataA
,
694 if (NT_SUCCESS(Status
))
696 AddrInitIPv4(&Router
, inet_addr(RegistryDataA
.Buffer
));
698 if (!AddrIsUnspecified(&Router
))
699 RouterCreateRoute(&DefaultMask
, &DefaultMask
, &Router
, Interface
, 1);
701 RtlFreeAnsiString(&RegistryDataA
);
706 ExFreePoolWithTag(KeyValueInfo
, KEY_VALUE_TAG
);
707 ZwClose(ParameterHandle
);
713 BOOLEAN
ReconfigureAdapter(PRECONFIGURE_CONTEXT Context
)
715 PLAN_ADAPTER Adapter
= Context
->Adapter
;
716 PIP_INTERFACE Interface
= Adapter
->Context
;
717 //NDIS_STATUS NdisStatus;
718 IP_ADDRESS DefaultMask
;
720 /* Initialize the default unspecified address (0.0.0.0) */
721 AddrInitIPv4(&DefaultMask
, 0);
722 if (Context
->State
== LAN_STATE_STARTED
&&
723 !Context
->Adapter
->CompletingReset
)
725 /* Read the IP configuration */
726 ReadIpConfiguration(Interface
);
728 /* Compute the broadcast address */
729 Interface
->Broadcast
.Type
= IP_ADDRESS_V4
;
730 Interface
->Broadcast
.Address
.IPv4Address
= Interface
->Unicast
.Address
.IPv4Address
|
731 ~Interface
->Netmask
.Address
.IPv4Address
;
733 else if (!Context
->Adapter
->CompletingReset
)
735 /* Clear IP configuration */
736 Interface
->Unicast
= DefaultMask
;
737 Interface
->Netmask
= DefaultMask
;
738 Interface
->Broadcast
= DefaultMask
;
740 /* Remove all interface routes */
741 RouterRemoveRoutesForInterface(Interface
);
743 /* Destroy all cached neighbors */
744 NBDestroyNeighborsForInterface(Interface
);
747 Context
->Adapter
->CompletingReset
= FALSE
;
749 /* Update the IP and link status information cached in TCP */
750 TCPUpdateInterfaceIPInformation(Interface
);
751 TCPUpdateInterfaceLinkStatus(Interface
);
753 /* We're done here if the adapter isn't connected */
754 if (Context
->State
!= LAN_STATE_STARTED
)
756 Adapter
->State
= Context
->State
;
762 /* Get maximum link speed */
763 NdisStatus
= NDISCall(Adapter
,
764 NdisRequestQueryInformation
,
769 if (!NT_SUCCESS(NdisStatus
))
770 Interface
->Speed
= IP_DEFAULT_LINK_SPEED
;
772 Adapter
->Speed
= Interface
->Speed
* 100L;
774 /* Get maximum frame size */
775 NdisStatus
= NDISCall(Adapter
,
776 NdisRequestQueryInformation
,
777 OID_GEN_MAXIMUM_FRAME_SIZE
,
780 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
783 Interface
->MTU
= Adapter
->MTU
;
785 /* Get maximum packet size */
786 NdisStatus
= NDISCall(Adapter
,
787 NdisRequestQueryInformation
,
788 OID_GEN_MAXIMUM_TOTAL_SIZE
,
789 &Adapter
->MaxPacketSize
,
791 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
795 Adapter
->State
= Context
->State
;
800 VOID
ReconfigureAdapterWorker(PVOID Context
)
802 PRECONFIGURE_CONTEXT ReconfigureContext
= Context
;
804 /* Complete the reconfiguration asynchronously */
805 ReconfigureAdapter(ReconfigureContext
);
807 /* Free the context */
808 ExFreePool(ReconfigureContext
);
811 VOID NTAPI
ProtocolStatus(
812 NDIS_HANDLE BindingContext
,
813 NDIS_STATUS GeneralStatus
,
815 UINT StatusBufferSize
)
817 * FUNCTION: Called by NDIS when the underlying driver has changed state
819 * BindingContext = Pointer to a device context (LAN_ADAPTER)
820 * GeneralStatus = A general status code
821 * StatusBuffer = Pointer to a buffer with medium-specific data
822 * StatusBufferSize = Number of bytes in StatusBuffer
825 PLAN_ADAPTER Adapter
= BindingContext
;
826 PRECONFIGURE_CONTEXT Context
;
828 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
830 /* Ignore the status indication if we have no context yet. We'll get another later */
831 if (!Adapter
->Context
)
834 Context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(RECONFIGURE_CONTEXT
), CONTEXT_TAG
);
838 Context
->Adapter
= Adapter
;
840 switch(GeneralStatus
)
842 case NDIS_STATUS_MEDIA_CONNECT
:
843 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
845 if (Adapter
->State
== LAN_STATE_STARTED
)
847 ExFreePoolWithTag(Context
, CONTEXT_TAG
);
851 Context
->State
= LAN_STATE_STARTED
;
854 case NDIS_STATUS_MEDIA_DISCONNECT
:
855 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
857 if (Adapter
->State
== LAN_STATE_STOPPED
)
859 ExFreePoolWithTag(Context
, CONTEXT_TAG
);
863 Context
->State
= LAN_STATE_STOPPED
;
866 case NDIS_STATUS_RESET_START
:
867 Adapter
->OldState
= Adapter
->State
;
868 Adapter
->State
= LAN_STATE_RESETTING
;
869 /* Nothing else to do here */
870 ExFreePoolWithTag(Context
, CONTEXT_TAG
);
873 case NDIS_STATUS_RESET_END
:
874 Adapter
->CompletingReset
= TRUE
;
875 Context
->State
= Adapter
->OldState
;
879 DbgPrint("Unhandled status: %x", GeneralStatus
);
880 ExFreePoolWithTag(Context
, CONTEXT_TAG
);
884 /* Queue the work item */
885 if (!ChewCreate(ReconfigureAdapterWorker
, Context
))
886 ExFreePoolWithTag(Context
, CONTEXT_TAG
);
889 VOID NTAPI
ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext
)
891 * FUNCTION: Called by NDIS when a status-change has occurred
893 * BindingContext = Pointer to a device context (LAN_ADAPTER)
896 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
901 NDIS_HANDLE NdisBindingContext
,
902 PNET_PNP_EVENT PnPEvent
)
904 switch(PnPEvent
->NetEvent
)
906 case NetEventSetPower
:
907 DbgPrint("Device transitioned to power state %ld\n", PnPEvent
->Buffer
);
908 return NDIS_STATUS_SUCCESS
;
910 case NetEventQueryPower
:
911 DbgPrint("Device wants to go into power state %ld\n", PnPEvent
->Buffer
);
912 return NDIS_STATUS_SUCCESS
;
914 case NetEventQueryRemoveDevice
:
915 DbgPrint("Device is about to be removed\n");
916 return NDIS_STATUS_SUCCESS
;
918 case NetEventCancelRemoveDevice
:
919 DbgPrint("Device removal cancelled\n");
920 return NDIS_STATUS_SUCCESS
;
923 DbgPrint("Unhandled event type: %ld\n", PnPEvent
->NetEvent
);
924 return NDIS_STATUS_SUCCESS
;
928 VOID NTAPI
ProtocolBindAdapter(
929 OUT PNDIS_STATUS Status
,
930 IN NDIS_HANDLE BindContext
,
931 IN PNDIS_STRING DeviceName
,
932 IN PVOID SystemSpecific1
,
933 IN PVOID SystemSpecific2
)
935 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
936 * bindings, and periodically thereafter as new adapters come online
938 * Status: Return value to NDIS
939 * BindContext: Handle provided by NDIS to track pending binding operations
940 * DeviceName: Name of the miniport device to bind to
941 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
942 * SystemSpecific2: Unused & must not be touched
945 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
946 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
952 PNDIS_PACKET NdisPacket
,
957 * FUNCTION: Transmits a packet
959 * Context = Pointer to context information (LAN_ADAPTER)
960 * NdisPacket = Pointer to NDIS packet to send
961 * Offset = Offset in packet where data starts
962 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
963 * Type = LAN protocol type (LAN_PROTO_*)
966 NDIS_STATUS NdisStatus
;
970 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
972 PNDIS_PACKET XmitPacket
;
973 PIP_INTERFACE Interface
= Adapter
->Context
;
975 TI_DbgPrint(DEBUG_DATALINK
,
976 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
977 NdisPacket
, Offset
, Adapter
));
979 if (Adapter
->State
!= LAN_STATE_STARTED
) {
980 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
984 TI_DbgPrint(DEBUG_DATALINK
,
985 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
986 Adapter
->HWAddress
[0] & 0xff,
987 Adapter
->HWAddress
[1] & 0xff,
988 Adapter
->HWAddress
[2] & 0xff,
989 Adapter
->HWAddress
[3] & 0xff,
990 Adapter
->HWAddress
[4] & 0xff,
991 Adapter
->HWAddress
[5] & 0xff));
993 GetDataPtr( NdisPacket
, 0, &OldData
, &OldSize
);
995 NdisStatus
= AllocatePacketWithBuffer(&XmitPacket
, NULL
, OldSize
+ Adapter
->HeaderSize
);
996 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
997 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_RESOURCES
);
1001 GetDataPtr(XmitPacket
, 0, &Data
, &Size
);
1003 RtlCopyMemory(Data
+ Adapter
->HeaderSize
, OldData
, OldSize
);
1005 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_SUCCESS
);
1007 switch (Adapter
->Media
) {
1008 case NdisMedium802_3
:
1009 EHeader
= (PETH_HEADER
)Data
;
1012 /* Unicast address */
1013 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
1015 /* Broadcast address */
1016 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
1019 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
1022 case LAN_PROTO_IPv4
:
1023 EHeader
->EType
= ETYPE_IPv4
;
1026 EHeader
->EType
= ETYPE_ARP
;
1028 case LAN_PROTO_IPv6
:
1029 EHeader
->EType
= ETYPE_IPv6
;
1038 /* FIXME: Support other medias */
1042 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
1046 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
1047 ((PCHAR
)LinkAddress
)[0] & 0xff,
1048 ((PCHAR
)LinkAddress
)[1] & 0xff,
1049 ((PCHAR
)LinkAddress
)[2] & 0xff,
1050 ((PCHAR
)LinkAddress
)[3] & 0xff,
1051 ((PCHAR
)LinkAddress
)[4] & 0xff,
1052 ((PCHAR
)LinkAddress
)[5] & 0xff));
1055 if (Adapter
->MTU
< Size
) {
1056 /* This is NOT a pointer. MSDN explicitly says so. */
1057 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket
,
1058 TcpLargeSendPacketInfo
) = (PVOID
)((ULONG_PTR
)Adapter
->MTU
);
1061 /* Update interface stats */
1062 Interface
->Stats
.OutBytes
+= Size
;
1064 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
1065 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
1066 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, XmitPacket
);
1067 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
1068 NdisStatus
== NDIS_STATUS_PENDING
?
1069 "Pending" : "Complete"));
1070 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
1072 /* I had a talk with vizzini: these really ought to be here.
1073 * we're supposed to see these completed by ndis *only* when
1074 * status_pending is returned. Note that this is different from
1075 * the situation with IRPs. */
1076 if (NdisStatus
!= NDIS_STATUS_PENDING
)
1077 ProtocolSendComplete((NDIS_HANDLE
)Context
, XmitPacket
, NdisStatus
);
1081 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
1082 OBJECT_ATTRIBUTES Attributes
;
1085 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, 0, 0);
1086 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
1090 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
1091 PWCHAR RegistryValue
,
1092 PUNICODE_STRING String
) {
1093 UNICODE_STRING ValueName
;
1094 UNICODE_STRING UnicodeString
;
1098 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
1100 RtlInitUnicodeString(&ValueName
, RegistryValue
);
1102 ZwQueryValueKey(RegHandle
,
1104 KeyValuePartialInformation
,
1109 if (!NT_SUCCESS(Status
))
1111 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
1112 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
1114 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
1115 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
1116 UnicodeString
.MaximumLength
= Information
->DataLength
;
1119 (PWCHAR
)ExAllocatePoolWithTag( NonPagedPool
,
1120 UnicodeString
.MaximumLength
+ sizeof(WCHAR
), REG_STR_TAG
);
1122 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
1124 String
->MaximumLength
= UnicodeString
.MaximumLength
;
1125 RtlCopyUnicodeString( String
, &UnicodeString
);
1127 return STATUS_SUCCESS
;
1131 * Utility to copy and append two unicode strings.
1133 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
1134 * IN PUNICODE_STRING Second -> Second string to append
1135 * IN BOOL Deallocate -> TRUE: Deallocate First string before
1141 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
1142 PUNICODE_STRING Second
,
1143 BOOLEAN Deallocate
) {
1145 UNICODE_STRING Ustr
= *ResultFirst
;
1146 PWSTR new_string
= ExAllocatePoolWithTag
1148 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)), TEMP_STRING_TAG
);
1150 return STATUS_NO_MEMORY
;
1152 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
1153 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
1154 Second
->Buffer
, Second
->Length
);
1155 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
1156 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
1157 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
1158 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
1159 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
1160 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
1161 ExFreePoolWithTag(new_string
, TEMP_STRING_TAG
);
1165 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
1166 PUNICODE_STRING TargetKeyName
,
1167 PUNICODE_STRING Name
,
1168 PUNICODE_STRING DeviceDesc
) {
1169 UNICODE_STRING RootDevice
= { 0, 0, NULL
}, LinkageKeyName
= { 0, 0, NULL
};
1170 UNICODE_STRING DescKeyName
= { 0, 0, NULL
}, Linkage
= { 0, 0, NULL
};
1171 UNICODE_STRING BackSlash
= { 0, 0, NULL
};
1172 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
1175 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
1177 RtlInitUnicodeString(&BackSlash
, L
"\\");
1178 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
1180 RtlInitUnicodeString(&DescKeyName
, L
"");
1181 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
1182 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
1183 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
1185 RtlInitUnicodeString(&LinkageKeyName
, L
"");
1186 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
1187 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
1189 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
1190 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1192 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
1193 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1195 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
1196 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
1197 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1199 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
1200 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1202 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
1203 } else Status
= STATUS_UNSUCCESSFUL
;
1206 RtlFreeUnicodeString( &RootDevice
);
1207 RtlFreeUnicodeString( &LinkageKeyName
);
1208 RtlFreeUnicodeString( &DescKeyName
);
1209 if( LinkageKey
) ZwClose( LinkageKey
);
1210 if( DescKey
) ZwClose( DescKey
);
1212 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
1217 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
1218 PUNICODE_STRING DeviceDesc
) {
1219 UNICODE_STRING EnumKeyName
, TargetKeyName
;
1223 KEY_BASIC_INFORMATION
*Kbio
=
1224 ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
), KBIO_TAG
);
1225 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
1227 RtlInitUnicodeString( DeviceDesc
, NULL
);
1229 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
1231 RtlInitUnicodeString
1232 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
1234 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
1236 if( !NT_SUCCESS(Status
) ) {
1237 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
1238 &EnumKeyName
, Status
));
1239 ExFreePoolWithTag( Kbio
, KBIO_TAG
);
1243 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
1244 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
1245 Kbio
, KbioLength
, &ResultLength
);
1247 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
1248 ExFreePoolWithTag( Kbio
, KBIO_TAG
);
1249 KbioLength
= ResultLength
;
1250 Kbio
= ExAllocatePoolWithTag( NonPagedPool
, KbioLength
, KBIO_TAG
);
1252 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
1254 return STATUS_NO_MEMORY
;
1257 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
1258 Kbio
, KbioLength
, &ResultLength
);
1260 if( !NT_SUCCESS(Status
) ) {
1261 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
1263 ExFreePoolWithTag( Kbio
, KBIO_TAG
);
1268 if( NT_SUCCESS(Status
) ) {
1269 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
1271 TargetKeyName
.Buffer
= Kbio
->Name
;
1273 Status
= CheckForDeviceDesc
1274 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
1275 if( NT_SUCCESS(Status
) ) {
1277 ExFreePoolWithTag( Kbio
, KBIO_TAG
);
1279 } else Status
= STATUS_SUCCESS
;
1284 ExFreePoolWithTag( Kbio
, KBIO_TAG
);
1285 return STATUS_UNSUCCESSFUL
;
1288 VOID
GetName( PUNICODE_STRING RegistryKey
,
1289 PUNICODE_STRING OutName
) {
1291 UNICODE_STRING PartialRegistryKey
;
1293 PartialRegistryKey
.Buffer
=
1294 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
1295 Ptr
= PartialRegistryKey
.Buffer
;
1297 while( *Ptr
!= L
'\\' &&
1298 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
1301 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
1302 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
1304 RtlInitUnicodeString( OutName
, L
"" );
1305 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
1308 BOOLEAN
BindAdapter(
1309 PLAN_ADAPTER Adapter
,
1310 PNDIS_STRING RegistryPath
)
1312 * FUNCTION: Binds a LAN adapter to IP layer
1314 * Adapter = Pointer to LAN_ADAPTER structure
1316 * We set the lookahead buffer size, set the packet filter and
1317 * bind the adapter to IP layer
1321 NDIS_STATUS NdisStatus
;
1322 LLIP_BIND_INFO BindInfo
;
1323 ULONG Lookahead
= LOOKAHEAD_SIZE
;
1325 NDIS_MEDIA_STATE MediaState
;
1327 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1329 Adapter
->State
= LAN_STATE_OPENING
;
1331 NdisStatus
= NDISCall(Adapter
,
1332 NdisRequestSetInformation
,
1333 OID_GEN_CURRENT_LOOKAHEAD
,
1336 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1337 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
1341 /* Bind the adapter to IP layer */
1342 BindInfo
.Context
= Adapter
;
1343 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
1344 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
1345 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
1346 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
1347 BindInfo
.Transmit
= LANTransmit
;
1349 IF
= IPCreateInterface(&BindInfo
);
1352 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1357 * Query per-adapter configuration from the registry
1358 * In case anyone is curious: there *is* an Ndis configuration api
1359 * for this sort of thing, but it doesn't really support things like
1360 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1361 * protocol drivers developed for win2k and above just use the native
1362 * services (ZwOpenKey, etc).
1365 GetName( RegistryPath
, &IF
->Name
);
1367 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
1368 if (!NT_SUCCESS(Status
)) {
1369 TI_DbgPrint(MIN_TRACE
, ("Failed to get device description.\n"));
1370 IPDestroyInterface(IF
);
1374 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
1377 /* Get maximum link speed */
1378 NdisStatus
= NDISCall(Adapter
,
1379 NdisRequestQueryInformation
,
1384 if (!NT_SUCCESS(NdisStatus
))
1385 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1387 Adapter
->Speed
= IF
->Speed
* 100L;
1389 /* Get maximum frame size */
1390 NdisStatus
= NDISCall(Adapter
,
1391 NdisRequestQueryInformation
,
1392 OID_GEN_MAXIMUM_FRAME_SIZE
,
1395 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1398 IF
->MTU
= Adapter
->MTU
;
1400 /* Get maximum packet size */
1401 NdisStatus
= NDISCall(Adapter
,
1402 NdisRequestQueryInformation
,
1403 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1404 &Adapter
->MaxPacketSize
,
1406 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1409 /* Register interface with IP layer */
1410 IPRegisterInterface(IF
);
1412 /* Store adapter context */
1413 Adapter
->Context
= IF
;
1415 /* Get the media state */
1416 NdisStatus
= NDISCall(Adapter
,
1417 NdisRequestQueryInformation
,
1418 OID_GEN_MEDIA_CONNECT_STATUS
,
1420 sizeof(MediaState
));
1421 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1422 TI_DbgPrint(DEBUG_DATALINK
, ("Could not query media status (0x%X).\n", NdisStatus
));
1423 IPUnregisterInterface(IF
);
1424 IPDestroyInterface(IF
);
1428 /* Indicate the current media state */
1429 ProtocolStatus(Adapter
,
1430 (MediaState
== NdisMediaStateConnected
) ? NDIS_STATUS_MEDIA_CONNECT
: NDIS_STATUS_MEDIA_DISCONNECT
,
1433 /* Set packet filter so we can send and receive packets */
1434 NdisStatus
= NDISCall(Adapter
,
1435 NdisRequestSetInformation
,
1436 OID_GEN_CURRENT_PACKET_FILTER
,
1437 &Adapter
->PacketFilter
,
1440 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1441 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1442 IPUnregisterInterface(IF
);
1443 IPDestroyInterface(IF
);
1452 PLAN_ADAPTER Adapter
)
1454 * FUNCTION: Unbinds a LAN adapter from IP layer
1456 * Adapter = Pointer to LAN_ADAPTER structure
1459 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1461 if (Adapter
->State
== LAN_STATE_STARTED
) {
1462 PIP_INTERFACE IF
= Adapter
->Context
;
1464 IPUnregisterInterface(IF
);
1466 IPDestroyInterface(IF
);
1471 NDIS_STATUS
LANRegisterAdapter(
1472 PNDIS_STRING AdapterName
,
1473 PNDIS_STRING RegistryPath
)
1475 * FUNCTION: Registers protocol with an NDIS adapter
1477 * AdapterName = Pointer to string with name of adapter to register
1478 * Adapter = Address of pointer to a LAN_ADAPTER structure
1480 * Status of operation
1484 NDIS_STATUS NdisStatus
;
1485 NDIS_STATUS OpenStatus
;
1487 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1490 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1492 IF
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_ADAPTER
), LAN_ADAPTER_TAG
);
1494 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1495 return NDIS_STATUS_RESOURCES
;
1498 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1500 /* Put adapter in stopped state */
1501 IF
->State
= LAN_STATE_STOPPED
;
1503 /* Initialize protecting spin lock */
1504 KeInitializeSpinLock(&IF
->Lock
);
1506 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1508 /* Initialize array with media IDs we support */
1509 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1511 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1512 /* Open the adapter. */
1513 NdisOpenAdapter(&NdisStatus
,
1525 /* Wait until the adapter is opened */
1526 if (NdisStatus
== NDIS_STATUS_PENDING
)
1527 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1528 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1529 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1530 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1534 IF
->Media
= MediaArray
[MediaIndex
];
1536 /* Fill LAN_ADAPTER structure with some adapter specific information */
1537 switch (IF
->Media
) {
1538 case NdisMedium802_3
:
1539 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1540 IF
->BCastMask
= BCAST_ETH_MASK
;
1541 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1542 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1543 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1544 IF
->MinFrameSize
= 60;
1545 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1547 NDIS_PACKET_TYPE_BROADCAST
|
1548 NDIS_PACKET_TYPE_DIRECTED
|
1549 NDIS_PACKET_TYPE_MULTICAST
;
1553 /* Unsupported media */
1554 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1555 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1556 return NDIS_STATUS_NOT_SUPPORTED
;
1559 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1560 NdisStatus
= NDISCall(IF
,
1561 NdisRequestQueryInformation
,
1562 OID_GEN_MAXIMUM_SEND_PACKETS
,
1563 &IF
->MaxSendPackets
,
1565 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1566 /* Legacy NIC drivers may not support this query, if it fails we
1567 assume it can send at least one packet per call to NdisSend(Packets) */
1568 IF
->MaxSendPackets
= 1;
1570 /* Get current hardware address */
1571 NdisStatus
= NDISCall(IF
,
1572 NdisRequestQueryInformation
,
1575 IF
->HWAddressLength
);
1576 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1577 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1578 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1582 /* Bind adapter to IP layer */
1583 if( !BindAdapter(IF
, RegistryPath
) ) {
1584 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1585 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1586 return NDIS_STATUS_NOT_ACCEPTED
;
1589 /* Add adapter to the adapter list */
1590 ExInterlockedInsertTailList(&AdapterListHead
,
1594 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1596 return NDIS_STATUS_SUCCESS
;
1600 NDIS_STATUS
LANUnregisterAdapter(
1601 PLAN_ADAPTER Adapter
)
1603 * FUNCTION: Unregisters protocol with NDIS adapter
1605 * Adapter = Pointer to a LAN_ADAPTER structure
1607 * Status of operation
1611 NDIS_HANDLE NdisHandle
;
1612 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1614 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1616 /* Unlink the adapter from the list */
1617 RemoveEntryList(&Adapter
->ListEntry
);
1619 /* Unbind adapter from IP layer */
1620 UnbindAdapter(Adapter
);
1622 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1623 NdisHandle
= Adapter
->NdisHandle
;
1625 Adapter
->NdisHandle
= NULL
;
1626 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1628 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1629 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1630 TcpipWaitForSingleObject(&Adapter
->Event
,
1635 NdisStatus
= Adapter
->NdisStatus
;
1638 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1640 FreeAdapter(Adapter
);
1647 LANUnregisterProtocol(VOID
)
1649 * FUNCTION: Unregisters this protocol driver with NDIS
1650 * NOTES: Does not care wether we are already registered
1653 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1655 if (ProtocolRegistered
) {
1656 NDIS_STATUS NdisStatus
;
1657 PLIST_ENTRY CurrentEntry
;
1658 PLIST_ENTRY NextEntry
;
1659 PLAN_ADAPTER Current
;
1662 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1664 /* Search the list and remove every adapter we find */
1665 CurrentEntry
= AdapterListHead
.Flink
;
1666 while (CurrentEntry
!= &AdapterListHead
) {
1667 NextEntry
= CurrentEntry
->Flink
;
1668 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1670 LANUnregisterAdapter(Current
);
1671 CurrentEntry
= NextEntry
;
1674 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1676 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1677 ProtocolRegistered
= FALSE
;
1683 ProtocolUnbindAdapter(
1684 PNDIS_STATUS Status
,
1685 NDIS_HANDLE ProtocolBindingContext
,
1686 NDIS_HANDLE UnbindContext
)
1688 /* We don't pend any unbinding so we can just ignore UnbindContext */
1689 *Status
= LANUnregisterAdapter((PLAN_ADAPTER
)ProtocolBindingContext
);
1692 NTSTATUS
LANRegisterProtocol(
1695 * FUNCTION: Registers this protocol driver with NDIS
1697 * Name = Name of this protocol driver
1699 * Status of operation
1702 NDIS_STATUS NdisStatus
;
1703 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1705 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1707 InitializeListHead(&AdapterListHead
);
1708 KeInitializeSpinLock(&AdapterListLock
);
1710 /* Set up protocol characteristics */
1711 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1712 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1713 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1714 ProtChars
.Name
.Length
= Name
->Length
;
1715 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1716 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1717 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1718 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1719 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1720 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1721 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1722 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1723 ProtChars
.ReceivePacketHandler
= ProtocolReceivePacket
;
1724 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1725 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1726 ProtChars
.StatusHandler
= ProtocolStatus
;
1727 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1728 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1729 ProtChars
.PnPEventHandler
= ProtocolPnPEvent
;
1730 ProtChars
.UnbindAdapterHandler
= ProtocolUnbindAdapter
;
1731 ProtChars
.UnloadHandler
= LANUnregisterProtocol
;
1733 /* Try to register protocol */
1734 NdisRegisterProtocol(&NdisStatus
,
1735 &NdisProtocolHandle
,
1737 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1738 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1740 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1741 return (NTSTATUS
)NdisStatus
;
1744 ProtocolRegistered
= TRUE
;
1746 return STATUS_SUCCESS
;