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 UINT TransferDataCalled
= 0;
14 UINT TransferDataCompleteCalled
= 0;
16 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
17 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
19 typedef struct _LAN_WQ_ITEM
{
23 UINT BytesTransferred
;
24 BOOLEAN LegacyReceive
;
25 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
27 typedef struct _RECONFIGURE_CONTEXT
{
30 } RECONFIGURE_CONTEXT
, *PRECONFIGURE_CONTEXT
;
32 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
33 BOOLEAN ProtocolRegistered
= FALSE
;
34 LIST_ENTRY AdapterListHead
;
35 KSPIN_LOCK AdapterListLock
;
39 NDIS_REQUEST_TYPE Type
,
44 * FUNCTION: Send a request to NDIS
46 * Adapter = Pointer to a LAN_ADAPTER structure
47 * Type = Type of request (Set or Query)
48 * OID = Value to be set/queried for
49 * Buffer = Pointer to a buffer to use
50 * Length = Number of bytes in Buffer
56 NDIS_STATUS NdisStatus
;
58 Request
.RequestType
= Type
;
59 if (Type
== NdisRequestSetInformation
) {
60 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
61 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
62 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
64 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
65 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
66 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
69 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
70 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
72 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
75 /* Wait for NDIS to complete the request */
76 if (NdisStatus
== NDIS_STATUS_PENDING
) {
77 KeWaitForSingleObject(&Adapter
->Event
,
82 NdisStatus
= Adapter
->NdisStatus
;
88 /* Used by legacy ProtocolReceive for packet type */
90 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter
,
92 ULONG HeaderBufferSize
,
95 PETH_HEADER EthHeader
= HeaderBuffer
;
97 if (HeaderBufferSize
< Adapter
->HeaderSize
)
99 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", HeaderBufferSize
));
100 return NDIS_STATUS_NOT_ACCEPTED
;
103 switch (Adapter
->Media
)
105 case NdisMedium802_3
:
106 /* Ethernet and IEEE 802.3 frames can be destinguished by
107 looking at the IEEE 802.3 length field. This field is
108 less than or equal to 1500 for a valid IEEE 802.3 frame
109 and larger than 1500 is it's a valid EtherType value.
110 See RFC 1122, section 2.3.3 for more information */
112 *PacketType
= EthHeader
->EType
;
116 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
118 /* FIXME: Support other medias */
119 return NDIS_STATUS_NOT_ACCEPTED
;
122 TI_DbgPrint(DEBUG_DATALINK
, ("EtherType (0x%X).\n", *PacketType
));
124 return NDIS_STATUS_SUCCESS
;
127 /* Used by ProtocolReceivePacket for packet type */
129 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter
,
130 PNDIS_PACKET NdisPacket
,
137 HeaderBuffer
= ExAllocatePool(NonPagedPool
,
138 Adapter
->HeaderSize
);
140 return NDIS_STATUS_RESOURCES
;
142 /* Copy the media header */
143 BytesCopied
= CopyPacketToBuffer(HeaderBuffer
,
146 Adapter
->HeaderSize
);
147 if (BytesCopied
!= Adapter
->HeaderSize
)
150 ExFreePool(HeaderBuffer
);
151 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", BytesCopied
));
152 return NDIS_STATUS_NOT_ACCEPTED
;
155 Status
= GetPacketTypeFromHeaderBuffer(Adapter
,
160 ExFreePool(HeaderBuffer
);
167 PLAN_ADAPTER Adapter
)
169 * FUNCTION: Frees memory for a LAN_ADAPTER structure
171 * Adapter = Pointer to LAN_ADAPTER structure to free
174 ExFreePoolWithTag(Adapter
, LAN_ADAPTER_TAG
);
178 NTSTATUS TcpipLanGetDwordOid
179 ( PIP_INTERFACE Interface
,
182 /* Get maximum frame size */
183 if( Interface
->Context
) {
184 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
185 NdisRequestQueryInformation
,
189 } else switch( Oid
) { /* Loopback Case */
190 case OID_GEN_HARDWARE_STATUS
:
191 *Result
= NdisHardwareStatusReady
;
192 return STATUS_SUCCESS
;
193 case OID_GEN_MEDIA_CONNECT_STATUS
:
194 *Result
= NdisMediaStateConnected
;
195 return STATUS_SUCCESS
;
197 return STATUS_INVALID_PARAMETER
;
202 VOID NTAPI
ProtocolOpenAdapterComplete(
203 NDIS_HANDLE BindingContext
,
205 NDIS_STATUS OpenErrorStatus
)
207 * FUNCTION: Called by NDIS to complete opening of an adapter
209 * BindingContext = Pointer to a device context (LAN_ADAPTER)
210 * Status = Status of the operation
211 * OpenErrorStatus = Additional status information
214 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
216 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
218 Adapter
->NdisStatus
= Status
;
220 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
224 VOID NTAPI
ProtocolCloseAdapterComplete(
225 NDIS_HANDLE BindingContext
,
228 * FUNCTION: Called by NDIS to complete closing an adapter
230 * BindingContext = Pointer to a device context (LAN_ADAPTER)
231 * Status = Status of the operation
234 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
236 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
238 Adapter
->NdisStatus
= Status
;
240 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
244 VOID NTAPI
ProtocolResetComplete(
245 NDIS_HANDLE BindingContext
,
248 * FUNCTION: Called by NDIS to complete resetting an adapter
250 * BindingContext = Pointer to a device context (LAN_ADAPTER)
251 * Status = Status of the operation
254 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
256 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
258 Adapter
->NdisStatus
= Status
;
260 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
264 VOID NTAPI
ProtocolRequestComplete(
265 NDIS_HANDLE BindingContext
,
266 PNDIS_REQUEST NdisRequest
,
269 * FUNCTION: Called by NDIS to complete a request
271 * BindingContext = Pointer to a device context (LAN_ADAPTER)
272 * NdisRequest = Pointer to an object describing the request
273 * Status = Status of the operation
276 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
278 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
280 /* Save status of request and signal an event */
281 Adapter
->NdisStatus
= Status
;
283 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
287 VOID NTAPI
ProtocolSendComplete(
288 NDIS_HANDLE BindingContext
,
292 * FUNCTION: Called by NDIS to complete sending process
294 * BindingContext = Pointer to a device context (LAN_ADAPTER)
295 * Packet = Pointer to a packet descriptor
296 * Status = Status of the operation
299 FreeNdisPacket(Packet
);
302 VOID
LanReceiveWorker( PVOID Context
) {
304 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
306 PLAN_ADAPTER Adapter
;
307 UINT BytesTransferred
;
309 BOOLEAN LegacyReceive
;
310 PIP_INTERFACE Interface
;
312 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
314 Packet
= WorkItem
->Packet
;
315 Adapter
= WorkItem
->Adapter
;
316 BytesTransferred
= WorkItem
->BytesTransferred
;
317 LegacyReceive
= WorkItem
->LegacyReceive
;
319 ExFreePoolWithTag(WorkItem
, WQ_CONTEXT_TAG
);
321 Interface
= Adapter
->Context
;
323 IPInitializePacket(&IPPacket
, 0);
325 IPPacket
.NdisPacket
= Packet
;
326 IPPacket
.ReturnPacket
= !LegacyReceive
;
330 /* Packet type is precomputed */
331 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
333 /* Data is at position 0 */
334 IPPacket
.Position
= 0;
336 /* Packet size is determined by bytes transferred */
337 IPPacket
.TotalSize
= BytesTransferred
;
341 /* Determine packet type from media header */
342 if (GetPacketTypeFromNdisPacket(Adapter
,
344 &PacketType
) != NDIS_STATUS_SUCCESS
)
347 IPPacket
.Free(&IPPacket
);
351 /* Data is at the end of the media header */
352 IPPacket
.Position
= Adapter
->HeaderSize
;
354 /* Calculate packet size (excluding media header) */
355 NdisQueryPacketLength(IPPacket
.NdisPacket
, &IPPacket
.TotalSize
);
360 ("Ether Type = %x Total = %d\n",
361 PacketType
, IPPacket
.TotalSize
));
363 /* Update interface stats */
364 Interface
->Stats
.InBytes
+= IPPacket
.TotalSize
+ Adapter
->HeaderSize
;
366 /* NDIS packet is freed in all of these cases */
367 switch (PacketType
) {
370 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
371 IPReceive(Adapter
->Context
, &IPPacket
);
374 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
375 ARPReceive(Adapter
->Context
, &IPPacket
);
378 IPPacket
.Free(&IPPacket
);
383 VOID
LanSubmitReceiveWork(
384 NDIS_HANDLE BindingContext
,
386 UINT BytesTransferred
,
387 BOOLEAN LegacyReceive
) {
388 PLAN_WQ_ITEM WQItem
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_WQ_ITEM
),
390 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
392 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
396 WQItem
->Packet
= Packet
;
397 WQItem
->Adapter
= Adapter
;
398 WQItem
->BytesTransferred
= BytesTransferred
;
399 WQItem
->LegacyReceive
= LegacyReceive
;
401 if (!ChewCreate( LanReceiveWorker
, WQItem
))
402 ExFreePoolWithTag(WQItem
, WQ_CONTEXT_TAG
);
405 VOID NTAPI
ProtocolTransferDataComplete(
406 NDIS_HANDLE BindingContext
,
409 UINT BytesTransferred
)
411 * FUNCTION: Called by NDIS to complete reception of data
413 * BindingContext = Pointer to a device context (LAN_ADAPTER)
414 * Packet = Pointer to a packet descriptor
415 * Status = Status of the operation
416 * BytesTransferred = Number of bytes transferred
418 * If the packet was successfully received, determine the protocol
419 * type and pass it to the correct receive handler
422 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
424 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
426 TransferDataCompleteCalled
++;
427 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
429 if( Status
!= NDIS_STATUS_SUCCESS
) return;
431 LanSubmitReceiveWork(BindingContext
,
437 INT NTAPI
ProtocolReceivePacket(
438 NDIS_HANDLE BindingContext
,
439 PNDIS_PACKET NdisPacket
)
441 PLAN_ADAPTER Adapter
= BindingContext
;
443 if (Adapter
->State
!= LAN_STATE_STARTED
) {
444 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
448 LanSubmitReceiveWork(BindingContext
,
453 /* Hold 1 reference on this packet */
457 NDIS_STATUS NTAPI
ProtocolReceive(
458 NDIS_HANDLE BindingContext
,
459 NDIS_HANDLE MacReceiveContext
,
461 UINT HeaderBufferSize
,
462 PVOID LookaheadBuffer
,
463 UINT LookaheadBufferSize
,
466 * FUNCTION: Called by NDIS when a packet has been received on the physical link
468 * BindingContext = Pointer to a device context (LAN_ADAPTER)
469 * MacReceiveContext = Handle used by underlying NIC driver
470 * HeaderBuffer = Pointer to a buffer containing the packet header
471 * HeaderBufferSize = Number of bytes in HeaderBuffer
472 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
473 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
474 * PacketSize = Overall size of the packet (not including header)
476 * Status of operation
480 UINT BytesTransferred
;
482 NDIS_STATUS NdisStatus
;
483 PNDIS_PACKET NdisPacket
;
484 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
486 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
488 if (Adapter
->State
!= LAN_STATE_STARTED
) {
489 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
490 return NDIS_STATUS_NOT_ACCEPTED
;
493 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
494 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
495 return NDIS_STATUS_NOT_ACCEPTED
;
498 NdisStatus
= GetPacketTypeFromHeaderBuffer(Adapter
,
502 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
503 return NDIS_STATUS_NOT_ACCEPTED
;
505 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
506 Adapter
, Adapter
->MTU
));
508 /* Get a transfer data packet */
509 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
511 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
512 return NDIS_STATUS_NOT_ACCEPTED
;
515 PC(NdisPacket
)->PacketType
= PacketType
;
517 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
519 GetDataPtr( NdisPacket
, 0, &BufferData
, &PacketSize
);
521 TransferDataCalled
++;
523 if (LookaheadBufferSize
== PacketSize
)
525 /* Optimized code path for packets that are fully contained in
526 * the lookahead buffer. */
527 NdisCopyLookaheadData(BufferData
,
530 Adapter
->MacOptions
);
534 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
535 MacReceiveContext
, 0, PacketSize
,
536 NdisPacket
, &BytesTransferred
);
538 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
540 if (NdisStatus
!= NDIS_STATUS_PENDING
)
541 ProtocolTransferDataComplete(BindingContext
,
546 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
548 return NDIS_STATUS_SUCCESS
;
552 VOID NTAPI
ProtocolReceiveComplete(
553 NDIS_HANDLE BindingContext
)
555 * FUNCTION: Called by NDIS when we're done receiving data
557 * BindingContext = Pointer to a device context (LAN_ADAPTER)
560 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
563 BOOLEAN
ReadIpConfiguration(PIP_INTERFACE Interface
)
565 OBJECT_ATTRIBUTES ObjectAttributes
;
566 HANDLE ParameterHandle
;
567 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo
;
569 UNICODE_STRING IPAddress
= RTL_CONSTANT_STRING(L
"IPAddress");
570 UNICODE_STRING Netmask
= RTL_CONSTANT_STRING(L
"SubnetMask");
571 UNICODE_STRING Gateway
= RTL_CONSTANT_STRING(L
"DefaultGateway");
572 UNICODE_STRING EnableDhcp
= RTL_CONSTANT_STRING(L
"EnableDHCP");
573 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
574 UNICODE_STRING TcpipRegistryPath
;
575 UNICODE_STRING RegistryDataU
;
576 ANSI_STRING RegistryDataA
;
579 IP_ADDRESS DefaultMask
, Router
;
581 AddrInitIPv4(&DefaultMask
, 0);
583 TcpipRegistryPath
.MaximumLength
= sizeof(WCHAR
) * 150;
584 TcpipRegistryPath
.Length
= 0;
585 TcpipRegistryPath
.Buffer
= Buffer
;
587 /* Build the registry path */
588 RtlAppendUnicodeStringToString(&TcpipRegistryPath
, &Prefix
);
589 RtlAppendUnicodeStringToString(&TcpipRegistryPath
, &Interface
->Name
);
591 InitializeObjectAttributes(&ObjectAttributes
,
593 OBJ_CASE_INSENSITIVE
,
597 /* Open a handle to the adapter parameters */
598 Status
= ZwOpenKey(&ParameterHandle
, KEY_READ
, &ObjectAttributes
);
600 if (!NT_SUCCESS(Status
))
606 KeyValueInfo
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
));
609 ZwClose(ParameterHandle
);
613 /* Read the EnableDHCP entry */
614 Status
= ZwQueryValueKey(ParameterHandle
,
616 KeyValuePartialInformation
,
618 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
),
620 if (NT_SUCCESS(Status
) && KeyValueInfo
->DataLength
== sizeof(ULONG
) && (*(PULONG
)KeyValueInfo
->Data
) == 0)
622 RegistryDataU
.MaximumLength
= 16 + sizeof(WCHAR
);
623 RegistryDataU
.Buffer
= (PWCHAR
)KeyValueInfo
->Data
;
625 /* Read the IP address */
626 Status
= ZwQueryValueKey(ParameterHandle
,
628 KeyValuePartialInformation
,
630 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
632 if (NT_SUCCESS(Status
))
634 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
636 RtlUnicodeStringToAnsiString(&RegistryDataA
,
640 AddrInitIPv4(&Interface
->Unicast
, inet_addr(RegistryDataA
.Buffer
));
642 RtlFreeAnsiString(&RegistryDataA
);
645 Status
= ZwQueryValueKey(ParameterHandle
,
647 KeyValuePartialInformation
,
649 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
651 if (NT_SUCCESS(Status
))
653 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
655 RtlUnicodeStringToAnsiString(&RegistryDataA
,
659 AddrInitIPv4(&Interface
->Netmask
, inet_addr(RegistryDataA
.Buffer
));
661 RtlFreeAnsiString(&RegistryDataA
);
664 /* We have to wait until both IP address and subnet mask
665 * are read to add the interface route, but we must do it
666 * before we add the default gateway */
667 if (!AddrIsUnspecified(&Interface
->Unicast
) &&
668 !AddrIsUnspecified(&Interface
->Netmask
))
669 IPAddInterfaceRoute(Interface
);
671 /* Read default gateway info */
672 Status
= ZwQueryValueKey(ParameterHandle
,
674 KeyValuePartialInformation
,
676 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
678 if (NT_SUCCESS(Status
))
680 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
682 RtlUnicodeStringToAnsiString(&RegistryDataA
,
686 AddrInitIPv4(&Router
, inet_addr(RegistryDataA
.Buffer
));
688 if (!AddrIsUnspecified(&Router
))
689 RouterCreateRoute(&DefaultMask
, &DefaultMask
, &Router
, Interface
, 1);
691 RtlFreeAnsiString(&RegistryDataA
);
695 ZwClose(ParameterHandle
);
701 BOOLEAN
ReconfigureAdapter(PRECONFIGURE_CONTEXT Context
)
703 PLAN_ADAPTER Adapter
= Context
->Adapter
;
704 PIP_INTERFACE Interface
= Adapter
->Context
;
705 //NDIS_STATUS NdisStatus;
706 IP_ADDRESS DefaultMask
;
708 /* Initialize the default unspecified address (0.0.0.0) */
709 AddrInitIPv4(&DefaultMask
, 0);
710 if (Context
->State
== LAN_STATE_STARTED
&&
711 !Context
->Adapter
->CompletingReset
)
713 /* Read the IP configuration */
714 ReadIpConfiguration(Interface
);
716 /* Compute the broadcast address */
717 Interface
->Broadcast
.Type
= IP_ADDRESS_V4
;
718 Interface
->Broadcast
.Address
.IPv4Address
= Interface
->Unicast
.Address
.IPv4Address
|
719 ~Interface
->Netmask
.Address
.IPv4Address
;
721 else if (!Context
->Adapter
->CompletingReset
)
723 /* Clear IP configuration */
724 Interface
->Unicast
= DefaultMask
;
725 Interface
->Netmask
= DefaultMask
;
726 Interface
->Broadcast
= DefaultMask
;
728 /* Remove all interface routes */
729 RouterRemoveRoutesForInterface(Interface
);
731 /* Destroy all cached neighbors */
732 NBDestroyNeighborsForInterface(Interface
);
735 Context
->Adapter
->CompletingReset
= FALSE
;
737 /* Update the IP and link status information cached in TCP */
738 TCPUpdateInterfaceIPInformation(Interface
);
739 TCPUpdateInterfaceLinkStatus(Interface
);
741 /* We're done here if the adapter isn't connected */
742 if (Context
->State
!= LAN_STATE_STARTED
)
744 Adapter
->State
= Context
->State
;
750 /* Get maximum link speed */
751 NdisStatus
= NDISCall(Adapter
,
752 NdisRequestQueryInformation
,
757 if (!NT_SUCCESS(NdisStatus
))
758 Interface
->Speed
= IP_DEFAULT_LINK_SPEED
;
760 Adapter
->Speed
= Interface
->Speed
* 100L;
762 /* Get maximum frame size */
763 NdisStatus
= NDISCall(Adapter
,
764 NdisRequestQueryInformation
,
765 OID_GEN_MAXIMUM_FRAME_SIZE
,
768 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
771 Interface
->MTU
= Adapter
->MTU
;
773 /* Get maximum packet size */
774 NdisStatus
= NDISCall(Adapter
,
775 NdisRequestQueryInformation
,
776 OID_GEN_MAXIMUM_TOTAL_SIZE
,
777 &Adapter
->MaxPacketSize
,
779 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
783 Adapter
->State
= Context
->State
;
788 VOID
ReconfigureAdapterWorker(PVOID Context
)
790 PRECONFIGURE_CONTEXT ReconfigureContext
= Context
;
792 /* Complete the reconfiguration asynchronously */
793 ReconfigureAdapter(ReconfigureContext
);
795 /* Free the context */
796 ExFreePool(ReconfigureContext
);
799 VOID NTAPI
ProtocolStatus(
800 NDIS_HANDLE BindingContext
,
801 NDIS_STATUS GeneralStatus
,
803 UINT StatusBufferSize
)
805 * FUNCTION: Called by NDIS when the underlying driver has changed state
807 * BindingContext = Pointer to a device context (LAN_ADAPTER)
808 * GeneralStatus = A general status code
809 * StatusBuffer = Pointer to a buffer with medium-specific data
810 * StatusBufferSize = Number of bytes in StatusBuffer
813 PLAN_ADAPTER Adapter
= BindingContext
;
814 PRECONFIGURE_CONTEXT Context
;
816 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
818 /* Ignore the status indication if we have no context yet. We'll get another later */
819 if (!Adapter
->Context
)
822 Context
= ExAllocatePool(NonPagedPool
, sizeof(RECONFIGURE_CONTEXT
));
826 Context
->Adapter
= Adapter
;
828 switch(GeneralStatus
)
830 case NDIS_STATUS_MEDIA_CONNECT
:
831 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
833 if (Adapter
->State
== LAN_STATE_STARTED
)
839 Context
->State
= LAN_STATE_STARTED
;
842 case NDIS_STATUS_MEDIA_DISCONNECT
:
843 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
845 if (Adapter
->State
== LAN_STATE_STOPPED
)
851 Context
->State
= LAN_STATE_STOPPED
;
854 case NDIS_STATUS_RESET_START
:
855 Adapter
->OldState
= Adapter
->State
;
856 Adapter
->State
= LAN_STATE_RESETTING
;
857 /* Nothing else to do here */
861 case NDIS_STATUS_RESET_END
:
862 Adapter
->CompletingReset
= TRUE
;
863 Context
->State
= Adapter
->OldState
;
867 DbgPrint("Unhandled status: %x", GeneralStatus
);
872 /* Queue the work item */
873 if (!ChewCreate(ReconfigureAdapterWorker
, Context
))
877 VOID NTAPI
ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext
)
879 * FUNCTION: Called by NDIS when a status-change has occurred
881 * BindingContext = Pointer to a device context (LAN_ADAPTER)
884 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
889 NDIS_HANDLE NdisBindingContext
,
890 PNET_PNP_EVENT PnPEvent
)
892 switch(PnPEvent
->NetEvent
)
894 case NetEventSetPower
:
895 DbgPrint("Device transitioned to power state %ld\n", PnPEvent
->Buffer
);
896 return NDIS_STATUS_SUCCESS
;
898 case NetEventQueryPower
:
899 DbgPrint("Device wants to go into power state %ld\n", PnPEvent
->Buffer
);
900 return NDIS_STATUS_SUCCESS
;
902 case NetEventQueryRemoveDevice
:
903 DbgPrint("Device is about to be removed\n");
904 return NDIS_STATUS_SUCCESS
;
906 case NetEventCancelRemoveDevice
:
907 DbgPrint("Device removal cancelled\n");
908 return NDIS_STATUS_SUCCESS
;
911 DbgPrint("Unhandled event type: %ld\n", PnPEvent
->NetEvent
);
912 return NDIS_STATUS_SUCCESS
;
916 VOID NTAPI
ProtocolBindAdapter(
917 OUT PNDIS_STATUS Status
,
918 IN NDIS_HANDLE BindContext
,
919 IN PNDIS_STRING DeviceName
,
920 IN PVOID SystemSpecific1
,
921 IN PVOID SystemSpecific2
)
923 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
924 * bindings, and periodically thereafer as new adapters come online
926 * Status: Return value to NDIS
927 * BindContext: Handle provided by NDIS to track pending binding operations
928 * DeviceName: Name of the miniport device to bind to
929 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
930 * SystemSpecific2: Unused & must not be touched
933 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
934 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
940 PNDIS_PACKET NdisPacket
,
945 * FUNCTION: Transmits a packet
947 * Context = Pointer to context information (LAN_ADAPTER)
948 * NdisPacket = Pointer to NDIS packet to send
949 * Offset = Offset in packet where data starts
950 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
951 * Type = LAN protocol type (LAN_PROTO_*)
954 NDIS_STATUS NdisStatus
;
958 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
960 PNDIS_PACKET XmitPacket
;
961 PIP_INTERFACE Interface
= Adapter
->Context
;
963 TI_DbgPrint(DEBUG_DATALINK
,
964 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
965 NdisPacket
, Offset
, Adapter
));
967 if (Adapter
->State
!= LAN_STATE_STARTED
) {
968 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
972 TI_DbgPrint(DEBUG_DATALINK
,
973 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
974 Adapter
->HWAddress
[0] & 0xff,
975 Adapter
->HWAddress
[1] & 0xff,
976 Adapter
->HWAddress
[2] & 0xff,
977 Adapter
->HWAddress
[3] & 0xff,
978 Adapter
->HWAddress
[4] & 0xff,
979 Adapter
->HWAddress
[5] & 0xff));
981 GetDataPtr( NdisPacket
, 0, &OldData
, &OldSize
);
983 NdisStatus
= AllocatePacketWithBuffer(&XmitPacket
, NULL
, OldSize
+ Adapter
->HeaderSize
);
984 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
985 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_RESOURCES
);
989 GetDataPtr(XmitPacket
, 0, &Data
, &Size
);
991 RtlCopyMemory(Data
+ Adapter
->HeaderSize
, OldData
, OldSize
);
993 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_SUCCESS
);
995 switch (Adapter
->Media
) {
996 case NdisMedium802_3
:
997 EHeader
= (PETH_HEADER
)Data
;
1000 /* Unicast address */
1001 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
1003 /* Broadcast address */
1004 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
1007 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
1010 case LAN_PROTO_IPv4
:
1011 EHeader
->EType
= ETYPE_IPv4
;
1014 EHeader
->EType
= ETYPE_ARP
;
1016 case LAN_PROTO_IPv6
:
1017 EHeader
->EType
= ETYPE_IPv6
;
1026 /* FIXME: Support other medias */
1030 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
1034 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
1035 ((PCHAR
)LinkAddress
)[0] & 0xff,
1036 ((PCHAR
)LinkAddress
)[1] & 0xff,
1037 ((PCHAR
)LinkAddress
)[2] & 0xff,
1038 ((PCHAR
)LinkAddress
)[3] & 0xff,
1039 ((PCHAR
)LinkAddress
)[4] & 0xff,
1040 ((PCHAR
)LinkAddress
)[5] & 0xff));
1043 if (Adapter
->MTU
< Size
) {
1044 /* This is NOT a pointer. MSDN explicitly says so. */
1045 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket
,
1046 TcpLargeSendPacketInfo
) = (PVOID
)((ULONG_PTR
)Adapter
->MTU
);
1049 /* Update interface stats */
1050 Interface
->Stats
.OutBytes
+= Size
;
1052 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
1053 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
1054 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, XmitPacket
);
1055 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
1056 NdisStatus
== NDIS_STATUS_PENDING
?
1057 "Pending" : "Complete"));
1058 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
1060 /* I had a talk with vizzini: these really ought to be here.
1061 * we're supposed to see these completed by ndis *only* when
1062 * status_pending is returned. Note that this is different from
1063 * the situation with IRPs. */
1064 if (NdisStatus
!= NDIS_STATUS_PENDING
)
1065 ProtocolSendComplete((NDIS_HANDLE
)Context
, XmitPacket
, NdisStatus
);
1069 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
1070 OBJECT_ATTRIBUTES Attributes
;
1073 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
1074 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
1078 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
1079 PWCHAR RegistryValue
,
1080 PUNICODE_STRING String
) {
1081 UNICODE_STRING ValueName
;
1082 UNICODE_STRING UnicodeString
;
1086 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
1088 RtlInitUnicodeString(&ValueName
, RegistryValue
);
1090 ZwQueryValueKey(RegHandle
,
1092 KeyValuePartialInformation
,
1097 if (!NT_SUCCESS(Status
))
1099 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
1100 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
1102 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
1103 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
1104 UnicodeString
.MaximumLength
= Information
->DataLength
;
1107 (PWCHAR
)ExAllocatePool( NonPagedPool
,
1108 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
1110 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
1112 String
->MaximumLength
= UnicodeString
.MaximumLength
;
1113 RtlCopyUnicodeString( String
, &UnicodeString
);
1115 return STATUS_SUCCESS
;
1119 * Utility to copy and append two unicode strings.
1121 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
1122 * IN PUNICODE_STRING Second -> Second string to append
1123 * IN BOOL Deallocate -> TRUE: Deallocate First string before
1129 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
1130 PUNICODE_STRING Second
,
1131 BOOLEAN Deallocate
) {
1133 UNICODE_STRING Ustr
= *ResultFirst
;
1134 PWSTR new_string
= ExAllocatePool
1136 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)));
1138 return STATUS_NO_MEMORY
;
1140 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
1141 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
1142 Second
->Buffer
, Second
->Length
);
1143 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
1144 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
1145 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
1146 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
1147 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
1148 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
1149 ExFreePool(new_string
);
1153 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
1154 PUNICODE_STRING TargetKeyName
,
1155 PUNICODE_STRING Name
,
1156 PUNICODE_STRING DeviceDesc
) {
1157 UNICODE_STRING RootDevice
= { 0, 0, NULL
}, LinkageKeyName
= { 0, 0, NULL
};
1158 UNICODE_STRING DescKeyName
= { 0, 0, NULL
}, Linkage
= { 0, 0, NULL
};
1159 UNICODE_STRING BackSlash
= { 0, 0, NULL
};
1160 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
1163 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
1165 RtlInitUnicodeString(&BackSlash
, L
"\\");
1166 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
1168 RtlInitUnicodeString(&DescKeyName
, L
"");
1169 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
1170 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
1171 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
1173 RtlInitUnicodeString(&LinkageKeyName
, L
"");
1174 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
1175 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
1177 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
1178 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1180 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
1181 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1183 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
1184 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
1185 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1187 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
1188 if( !NT_SUCCESS(Status
) ) goto cleanup
;
1190 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
1191 } else Status
= STATUS_UNSUCCESSFUL
;
1194 RtlFreeUnicodeString( &RootDevice
);
1195 RtlFreeUnicodeString( &LinkageKeyName
);
1196 RtlFreeUnicodeString( &DescKeyName
);
1197 if( LinkageKey
) NtClose( LinkageKey
);
1198 if( DescKey
) NtClose( DescKey
);
1200 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
1205 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
1206 PUNICODE_STRING DeviceDesc
) {
1207 UNICODE_STRING EnumKeyName
, TargetKeyName
;
1211 KEY_BASIC_INFORMATION
*Kbio
=
1212 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
1213 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
1215 RtlInitUnicodeString( DeviceDesc
, NULL
);
1217 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
1219 RtlInitUnicodeString
1220 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
1222 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
1224 if( !NT_SUCCESS(Status
) ) {
1225 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
1226 &EnumKeyName
, Status
));
1231 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
1232 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
1233 Kbio
, KbioLength
, &ResultLength
);
1235 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
1237 KbioLength
= ResultLength
;
1238 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
1240 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
1242 return STATUS_NO_MEMORY
;
1245 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
1246 Kbio
, KbioLength
, &ResultLength
);
1248 if( !NT_SUCCESS(Status
) ) {
1249 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
1256 if( NT_SUCCESS(Status
) ) {
1257 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
1259 TargetKeyName
.Buffer
= Kbio
->Name
;
1261 Status
= CheckForDeviceDesc
1262 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
1263 if( NT_SUCCESS(Status
) ) {
1267 } else Status
= STATUS_SUCCESS
;
1273 return STATUS_UNSUCCESSFUL
;
1276 VOID
GetName( PUNICODE_STRING RegistryKey
,
1277 PUNICODE_STRING OutName
) {
1279 UNICODE_STRING PartialRegistryKey
;
1281 PartialRegistryKey
.Buffer
=
1282 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
1283 Ptr
= PartialRegistryKey
.Buffer
;
1285 while( *Ptr
!= L
'\\' &&
1286 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
1289 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
1290 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
1292 RtlInitUnicodeString( OutName
, L
"" );
1293 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
1296 BOOLEAN
BindAdapter(
1297 PLAN_ADAPTER Adapter
,
1298 PNDIS_STRING RegistryPath
)
1300 * FUNCTION: Binds a LAN adapter to IP layer
1302 * Adapter = Pointer to LAN_ADAPTER structure
1304 * We set the lookahead buffer size, set the packet filter and
1305 * bind the adapter to IP layer
1309 NDIS_STATUS NdisStatus
;
1310 LLIP_BIND_INFO BindInfo
;
1311 ULONG Lookahead
= LOOKAHEAD_SIZE
;
1313 NDIS_MEDIA_STATE MediaState
;
1315 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1317 Adapter
->State
= LAN_STATE_OPENING
;
1319 NdisStatus
= NDISCall(Adapter
,
1320 NdisRequestSetInformation
,
1321 OID_GEN_CURRENT_LOOKAHEAD
,
1324 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1325 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
1329 /* Bind the adapter to IP layer */
1330 BindInfo
.Context
= Adapter
;
1331 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
1332 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
1333 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
1334 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
1335 BindInfo
.Transmit
= LANTransmit
;
1337 IF
= IPCreateInterface(&BindInfo
);
1340 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1345 * Query per-adapter configuration from the registry
1346 * In case anyone is curious: there *is* an Ndis configuration api
1347 * for this sort of thing, but it doesn't really support things like
1348 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1349 * protocol drivers developed for win2k and above just use the native
1350 * services (ZwOpenKey, etc).
1353 GetName( RegistryPath
, &IF
->Name
);
1355 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
1356 if (!NT_SUCCESS(Status
)) {
1357 TI_DbgPrint(MIN_TRACE
, ("Failed to get device description.\n"));
1358 IPDestroyInterface(IF
);
1362 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
1365 /* Get maximum link speed */
1366 NdisStatus
= NDISCall(Adapter
,
1367 NdisRequestQueryInformation
,
1372 if (!NT_SUCCESS(NdisStatus
))
1373 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1375 Adapter
->Speed
= IF
->Speed
* 100L;
1377 /* Get maximum frame size */
1378 NdisStatus
= NDISCall(Adapter
,
1379 NdisRequestQueryInformation
,
1380 OID_GEN_MAXIMUM_FRAME_SIZE
,
1383 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1386 IF
->MTU
= Adapter
->MTU
;
1388 /* Get maximum packet size */
1389 NdisStatus
= NDISCall(Adapter
,
1390 NdisRequestQueryInformation
,
1391 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1392 &Adapter
->MaxPacketSize
,
1394 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1397 /* Register interface with IP layer */
1398 IPRegisterInterface(IF
);
1400 /* Store adapter context */
1401 Adapter
->Context
= IF
;
1403 /* Get the media state */
1404 NdisStatus
= NDISCall(Adapter
,
1405 NdisRequestQueryInformation
,
1406 OID_GEN_MEDIA_CONNECT_STATUS
,
1408 sizeof(MediaState
));
1409 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1410 TI_DbgPrint(DEBUG_DATALINK
, ("Could not query media status (0x%X).\n", NdisStatus
));
1411 IPUnregisterInterface(IF
);
1412 IPDestroyInterface(IF
);
1416 /* Indicate the current media state */
1417 ProtocolStatus(Adapter
,
1418 (MediaState
== NdisMediaStateConnected
) ? NDIS_STATUS_MEDIA_CONNECT
: NDIS_STATUS_MEDIA_DISCONNECT
,
1421 /* Set packet filter so we can send and receive packets */
1422 NdisStatus
= NDISCall(Adapter
,
1423 NdisRequestSetInformation
,
1424 OID_GEN_CURRENT_PACKET_FILTER
,
1425 &Adapter
->PacketFilter
,
1428 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1429 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1430 IPUnregisterInterface(IF
);
1431 IPDestroyInterface(IF
);
1440 PLAN_ADAPTER Adapter
)
1442 * FUNCTION: Unbinds a LAN adapter from IP layer
1444 * Adapter = Pointer to LAN_ADAPTER structure
1447 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1449 if (Adapter
->State
== LAN_STATE_STARTED
) {
1450 PIP_INTERFACE IF
= Adapter
->Context
;
1452 IPUnregisterInterface(IF
);
1454 IPDestroyInterface(IF
);
1459 NDIS_STATUS
LANRegisterAdapter(
1460 PNDIS_STRING AdapterName
,
1461 PNDIS_STRING RegistryPath
)
1463 * FUNCTION: Registers protocol with an NDIS adapter
1465 * AdapterName = Pointer to string with name of adapter to register
1466 * Adapter = Address of pointer to a LAN_ADAPTER structure
1468 * Status of operation
1472 NDIS_STATUS NdisStatus
;
1473 NDIS_STATUS OpenStatus
;
1475 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1478 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1480 IF
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_ADAPTER
), LAN_ADAPTER_TAG
);
1482 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1483 return NDIS_STATUS_RESOURCES
;
1486 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1488 /* Put adapter in stopped state */
1489 IF
->State
= LAN_STATE_STOPPED
;
1491 /* Initialize protecting spin lock */
1492 KeInitializeSpinLock(&IF
->Lock
);
1494 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1496 /* Initialize array with media IDs we support */
1497 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1499 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1500 /* Open the adapter. */
1501 NdisOpenAdapter(&NdisStatus
,
1513 /* Wait until the adapter is opened */
1514 if (NdisStatus
== NDIS_STATUS_PENDING
)
1515 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1516 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1517 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1518 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1522 IF
->Media
= MediaArray
[MediaIndex
];
1524 /* Fill LAN_ADAPTER structure with some adapter specific information */
1525 switch (IF
->Media
) {
1526 case NdisMedium802_3
:
1527 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1528 IF
->BCastMask
= BCAST_ETH_MASK
;
1529 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1530 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1531 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1532 IF
->MinFrameSize
= 60;
1533 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1535 NDIS_PACKET_TYPE_BROADCAST
|
1536 NDIS_PACKET_TYPE_DIRECTED
|
1537 NDIS_PACKET_TYPE_MULTICAST
;
1541 /* Unsupported media */
1542 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1543 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1544 return NDIS_STATUS_NOT_SUPPORTED
;
1547 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1548 NdisStatus
= NDISCall(IF
,
1549 NdisRequestQueryInformation
,
1550 OID_GEN_MAXIMUM_SEND_PACKETS
,
1551 &IF
->MaxSendPackets
,
1553 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1554 /* Legacy NIC drivers may not support this query, if it fails we
1555 assume it can send at least one packet per call to NdisSend(Packets) */
1556 IF
->MaxSendPackets
= 1;
1558 /* Get current hardware address */
1559 NdisStatus
= NDISCall(IF
,
1560 NdisRequestQueryInformation
,
1563 IF
->HWAddressLength
);
1564 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1565 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1566 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1570 /* Bind adapter to IP layer */
1571 if( !BindAdapter(IF
, RegistryPath
) ) {
1572 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1573 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1574 return NDIS_STATUS_NOT_ACCEPTED
;
1577 /* Add adapter to the adapter list */
1578 ExInterlockedInsertTailList(&AdapterListHead
,
1582 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1584 return NDIS_STATUS_SUCCESS
;
1588 NDIS_STATUS
LANUnregisterAdapter(
1589 PLAN_ADAPTER Adapter
)
1591 * FUNCTION: Unregisters protocol with NDIS adapter
1593 * Adapter = Pointer to a LAN_ADAPTER structure
1595 * Status of operation
1599 NDIS_HANDLE NdisHandle
;
1600 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1602 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1604 /* Unlink the adapter from the list */
1605 RemoveEntryList(&Adapter
->ListEntry
);
1607 /* Unbind adapter from IP layer */
1608 UnbindAdapter(Adapter
);
1610 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1611 NdisHandle
= Adapter
->NdisHandle
;
1613 Adapter
->NdisHandle
= NULL
;
1614 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1616 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1617 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1618 TcpipWaitForSingleObject(&Adapter
->Event
,
1623 NdisStatus
= Adapter
->NdisStatus
;
1626 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1628 FreeAdapter(Adapter
);
1635 LANUnregisterProtocol(VOID
)
1637 * FUNCTION: Unregisters this protocol driver with NDIS
1638 * NOTES: Does not care wether we are already registered
1641 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1643 if (ProtocolRegistered
) {
1644 NDIS_STATUS NdisStatus
;
1645 PLIST_ENTRY CurrentEntry
;
1646 PLIST_ENTRY NextEntry
;
1647 PLAN_ADAPTER Current
;
1650 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1652 /* Search the list and remove every adapter we find */
1653 CurrentEntry
= AdapterListHead
.Flink
;
1654 while (CurrentEntry
!= &AdapterListHead
) {
1655 NextEntry
= CurrentEntry
->Flink
;
1656 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1658 LANUnregisterAdapter(Current
);
1659 CurrentEntry
= NextEntry
;
1662 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1664 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1665 ProtocolRegistered
= FALSE
;
1671 ProtocolUnbindAdapter(
1672 PNDIS_STATUS Status
,
1673 NDIS_HANDLE ProtocolBindingContext
,
1674 NDIS_HANDLE UnbindContext
)
1676 /* We don't pend any unbinding so we can just ignore UnbindContext */
1677 *Status
= LANUnregisterAdapter((PLAN_ADAPTER
)ProtocolBindingContext
);
1680 NTSTATUS
LANRegisterProtocol(
1683 * FUNCTION: Registers this protocol driver with NDIS
1685 * Name = Name of this protocol driver
1687 * Status of operation
1690 NDIS_STATUS NdisStatus
;
1691 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1693 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1695 InitializeListHead(&AdapterListHead
);
1696 KeInitializeSpinLock(&AdapterListLock
);
1698 /* Set up protocol characteristics */
1699 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1700 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1701 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1702 ProtChars
.Name
.Length
= Name
->Length
;
1703 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1704 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1705 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1706 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1707 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1708 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1709 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1710 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1711 ProtChars
.ReceivePacketHandler
= ProtocolReceivePacket
;
1712 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1713 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1714 ProtChars
.StatusHandler
= ProtocolStatus
;
1715 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1716 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1717 ProtChars
.PnPEventHandler
= ProtocolPnPEvent
;
1718 ProtChars
.UnbindAdapterHandler
= ProtocolUnbindAdapter
;
1719 ProtChars
.UnloadHandler
= LANUnregisterProtocol
;
1721 /* Try to register protocol */
1722 NdisRegisterProtocol(&NdisStatus
,
1723 &NdisProtocolHandle
,
1725 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1726 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1728 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1729 return (NTSTATUS
)NdisStatus
;
1732 ProtocolRegistered
= TRUE
;
1734 return STATUS_SUCCESS
;