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;
15 UINT LanReceiveWorkerCalled
= 0;
16 BOOLEAN LanReceiveWorkerBusy
= FALSE
;
18 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
19 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
21 #define NGFP(_Packet) \
24 ULONG _ContigSize, _TotalSize; \
25 PNDIS_BUFFER _NdisBuffer; \
27 TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
28 NdisGetFirstBufferFromPacket(_Packet, \
33 TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
34 TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
35 TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
36 TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
39 typedef struct _LAN_WQ_ITEM
{
43 UINT BytesTransferred
;
44 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
46 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
47 BOOLEAN ProtocolRegistered
= FALSE
;
48 LIST_ENTRY AdapterListHead
;
49 KSPIN_LOCK AdapterListLock
;
53 NDIS_REQUEST_TYPE Type
,
58 * FUNCTION: Send a request to NDIS
60 * Adapter = Pointer to a LAN_ADAPTER structure
61 * Type = Type of request (Set or Query)
62 * OID = Value to be set/queried for
63 * Buffer = Pointer to a buffer to use
64 * Length = Number of bytes in Buffer
70 NDIS_STATUS NdisStatus
;
72 Request
.RequestType
= Type
;
73 if (Type
== NdisRequestSetInformation
) {
74 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
75 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
76 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
78 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
79 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
80 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
83 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
84 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
86 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
89 /* Wait for NDIS to complete the request */
90 if (NdisStatus
== NDIS_STATUS_PENDING
) {
91 KeWaitForSingleObject(&Adapter
->Event
,
96 NdisStatus
= Adapter
->NdisStatus
;
104 PLAN_ADAPTER Adapter
)
106 * FUNCTION: Frees memory for a LAN_ADAPTER structure
108 * Adapter = Pointer to LAN_ADAPTER structure to free
115 NTSTATUS TcpipLanGetDwordOid
116 ( PIP_INTERFACE Interface
,
119 /* Get maximum frame size */
120 if( Interface
->Context
) {
121 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
122 NdisRequestQueryInformation
,
126 } else switch( Oid
) { /* Loopback Case */
127 case OID_GEN_HARDWARE_STATUS
:
128 *Result
= NdisHardwareStatusReady
;
129 return STATUS_SUCCESS
;
132 return STATUS_INVALID_PARAMETER
;
137 VOID NTAPI
ProtocolOpenAdapterComplete(
138 NDIS_HANDLE BindingContext
,
140 NDIS_STATUS OpenErrorStatus
)
142 * FUNCTION: Called by NDIS to complete opening of an adapter
144 * BindingContext = Pointer to a device context (LAN_ADAPTER)
145 * Status = Status of the operation
146 * OpenErrorStatus = Additional status information
149 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
151 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
153 Adapter
->NdisStatus
= Status
;
155 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
159 VOID NTAPI
ProtocolCloseAdapterComplete(
160 NDIS_HANDLE BindingContext
,
163 * FUNCTION: Called by NDIS to complete closing an adapter
165 * BindingContext = Pointer to a device context (LAN_ADAPTER)
166 * Status = Status of the operation
169 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
171 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
173 Adapter
->NdisStatus
= Status
;
175 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
179 VOID NTAPI
ProtocolResetComplete(
180 NDIS_HANDLE BindingContext
,
183 * FUNCTION: Called by NDIS to complete resetting an adapter
185 * BindingContext = Pointer to a device context (LAN_ADAPTER)
186 * Status = Status of the operation
189 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
191 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
193 Adapter
->NdisStatus
= Status
;
195 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
199 VOID NTAPI
ProtocolRequestComplete(
200 NDIS_HANDLE BindingContext
,
201 PNDIS_REQUEST NdisRequest
,
204 * FUNCTION: Called by NDIS to complete a request
206 * BindingContext = Pointer to a device context (LAN_ADAPTER)
207 * NdisRequest = Pointer to an object describing the request
208 * Status = Status of the operation
211 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
213 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
215 /* Save status of request and signal an event */
216 Adapter
->NdisStatus
= Status
;
218 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
222 VOID NTAPI
ProtocolSendComplete(
223 NDIS_HANDLE BindingContext
,
227 * FUNCTION: Called by NDIS to complete sending process
229 * BindingContext = Pointer to a device context (LAN_ADAPTER)
230 * Packet = Pointer to a packet descriptor
231 * Status = Status of the operation
234 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
235 ASSERT_KM_POINTER(Packet
);
236 ASSERT_KM_POINTER(PC(Packet
));
237 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
238 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
239 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
242 VOID
LanReceiveWorker( PVOID Context
) {
244 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
246 PLAN_ADAPTER Adapter
;
247 UINT BytesTransferred
;
248 PNDIS_BUFFER NdisBuffer
;
251 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
253 Packet
= WorkItem
->Packet
;
254 Adapter
= WorkItem
->Adapter
;
255 BytesTransferred
= WorkItem
->BytesTransferred
;
257 IPPacket
.NdisPacket
= Packet
;
259 NdisGetFirstBufferFromPacket(Packet
,
262 &IPPacket
.ContigSize
,
263 &IPPacket
.TotalSize
);
265 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
266 /* Determine which upper layer protocol that should receive
267 this packet and pass it to the correct receive handler */
269 TI_DbgPrint(MID_TRACE
,
270 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
271 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
274 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
275 IPPacket
.Position
= 0;
279 ("Ether Type = %x ContigSize = %d Total = %d\n",
280 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
282 switch (PacketType
) {
285 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
286 IPReceive(Adapter
->Context
, &IPPacket
);
289 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
290 ARPReceive(Adapter
->Context
, &IPPacket
);
295 FreeNdisPacket( Packet
);
298 VOID
LanSubmitReceiveWork(
299 NDIS_HANDLE BindingContext
,
302 UINT BytesTransferred
) {
304 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
307 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
309 WQItem
.Packet
= Packet
;
310 WQItem
.Adapter
= Adapter
;
311 WQItem
.BytesTransferred
= BytesTransferred
;
314 ( &LanWorkItem
, sizeof(LAN_WQ_ITEM
), LanReceiveWorker
, &WQItem
) )
318 VOID NTAPI
ProtocolTransferDataComplete(
319 NDIS_HANDLE BindingContext
,
322 UINT BytesTransferred
)
324 * FUNCTION: Called by NDIS to complete reception of data
326 * BindingContext = Pointer to a device context (LAN_ADAPTER)
327 * Packet = Pointer to a packet descriptor
328 * Status = Status of the operation
329 * BytesTransferred = Number of bytes transferred
331 * If the packet was successfully received, determine the protocol
332 * type and pass it to the correct receive handler
335 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
337 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
339 TransferDataCompleteCalled
++;
340 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
342 if( Status
!= NDIS_STATUS_SUCCESS
) return;
344 LanSubmitReceiveWork( BindingContext
, Packet
, Status
, BytesTransferred
);
347 NDIS_STATUS NTAPI
ProtocolReceive(
348 NDIS_HANDLE BindingContext
,
349 NDIS_HANDLE MacReceiveContext
,
351 UINT HeaderBufferSize
,
352 PVOID LookaheadBuffer
,
353 UINT LookaheadBufferSize
,
356 * FUNCTION: Called by NDIS when a packet has been received on the physical link
358 * BindingContext = Pointer to a device context (LAN_ADAPTER)
359 * MacReceiveContext = Handle used by underlying NIC driver
360 * HeaderBuffer = Pointer to a buffer containing the packet header
361 * HeaderBufferSize = Number of bytes in HeaderBuffer
362 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
363 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
364 * PacketSize = Overall size of the packet (not including header)
366 * Status of operation
370 UINT PacketType
, BytesTransferred
;
374 NDIS_STATUS NdisStatus
;
375 PNDIS_PACKET NdisPacket
;
376 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
377 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
379 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
381 if (Adapter
->State
!= LAN_STATE_STARTED
) {
382 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
383 return NDIS_STATUS_NOT_ACCEPTED
;
386 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
387 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
388 return NDIS_STATUS_NOT_ACCEPTED
;
391 if (Adapter
->Media
== NdisMedium802_3
) {
392 /* Ethernet and IEEE 802.3 frames can be destinguished by
393 looking at the IEEE 802.3 length field. This field is
394 less than or equal to 1500 for a valid IEEE 802.3 frame
395 and larger than 1500 is it's a valid EtherType value.
396 See RFC 1122, section 2.3.3 for more information */
397 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
398 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
399 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
400 return NDIS_STATUS_NOT_ACCEPTED
;
402 /* We use EtherType constants to destinguish packet types */
405 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
406 /* FIXME: Support other medias */
407 return NDIS_STATUS_NOT_ACCEPTED
;
410 /* Get a transfer data packet */
412 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
413 Adapter
, Adapter
->MTU
));
415 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
416 PacketSize
+ HeaderBufferSize
);
417 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
418 return NDIS_STATUS_NOT_ACCEPTED
;
421 PC(NdisPacket
)->PacketType
= PacketType
;
423 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
425 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
427 IPPacket
.NdisPacket
= NdisPacket
;
428 IPPacket
.Position
= 0;
430 TransferDataCalled
++;
432 if (LookaheadBufferSize
== PacketSize
)
434 /* Optimized code path for packets that are fully contained in
435 * the lookahead buffer. */
436 NdisCopyLookaheadData(BufferData
,
439 Adapter
->MacOptions
);
443 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
444 MacReceiveContext
, 0, PacketSize
,
445 NdisPacket
, &BytesTransferred
);
447 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
449 if (NdisStatus
!= NDIS_STATUS_PENDING
)
450 ProtocolTransferDataComplete(BindingContext
,
455 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
457 return NDIS_STATUS_SUCCESS
;
461 VOID NTAPI
ProtocolReceiveComplete(
462 NDIS_HANDLE BindingContext
)
464 * FUNCTION: Called by NDIS when we're done receiving data
466 * BindingContext = Pointer to a device context (LAN_ADAPTER)
469 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
473 VOID NTAPI
ProtocolStatus(
474 NDIS_HANDLE BindingContext
,
475 NDIS_STATUS GeneralStatus
,
477 UINT StatusBufferSize
)
479 * FUNCTION: Called by NDIS when the underlying driver has changed state
481 * BindingContext = Pointer to a device context (LAN_ADAPTER)
482 * GeneralStatus = A general status code
483 * StatusBuffer = Pointer to a buffer with medium-specific data
484 * StatusBufferSize = Number of bytes in StatusBuffer
487 PLAN_ADAPTER Adapter
= BindingContext
;
489 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
491 switch(GeneralStatus
)
493 case NDIS_STATUS_MEDIA_CONNECT
:
494 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
497 case NDIS_STATUS_MEDIA_DISCONNECT
:
498 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
501 case NDIS_STATUS_RESET_START
:
502 Adapter
->State
= LAN_STATE_RESETTING
;
505 case NDIS_STATUS_RESET_END
:
506 Adapter
->State
= LAN_STATE_STARTED
;
510 DbgPrint("Unhandled status: %x", GeneralStatus
);
516 VOID NTAPI
ProtocolStatusComplete(
517 NDIS_HANDLE NdisBindingContext
)
519 * FUNCTION: Called by NDIS when a status-change has occurred
521 * BindingContext = Pointer to a device context (LAN_ADAPTER)
524 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
527 VOID NTAPI
ProtocolBindAdapter(
528 OUT PNDIS_STATUS Status
,
529 IN NDIS_HANDLE BindContext
,
530 IN PNDIS_STRING DeviceName
,
531 IN PVOID SystemSpecific1
,
532 IN PVOID SystemSpecific2
)
534 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
535 * bindings, and periodically thereafer as new adapters come online
537 * Status: Return value to NDIS
538 * BindContext: Handle provided by NDIS to track pending binding operations
539 * DeviceName: Name of the miniport device to bind to
540 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
541 * SystemSpecific2: Unused & must not be touched
544 /* XXX confirm that this is still true, or re-word the following comment */
545 /* we get to ignore BindContext because we will never pend an operation with NDIS */
546 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
547 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
553 PNDIS_PACKET NdisPacket
,
558 * FUNCTION: Transmits a packet
560 * Context = Pointer to context information (LAN_ADAPTER)
561 * NdisPacket = Pointer to NDIS packet to send
562 * Offset = Offset in packet where data starts
563 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
564 * Type = LAN protocol type (LAN_PROTO_*)
567 NDIS_STATUS NdisStatus
;
571 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
574 TI_DbgPrint(DEBUG_DATALINK
,
575 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
576 NdisPacket
, Offset
, Adapter
));
578 if (Adapter
->State
!= LAN_STATE_STARTED
) {
579 ProtocolSendComplete(Context
, NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
583 TI_DbgPrint(DEBUG_DATALINK
,
584 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
585 Adapter
->HWAddress
[0] & 0xff,
586 Adapter
->HWAddress
[1] & 0xff,
587 Adapter
->HWAddress
[2] & 0xff,
588 Adapter
->HWAddress
[3] & 0xff,
589 Adapter
->HWAddress
[4] & 0xff,
590 Adapter
->HWAddress
[5] & 0xff));
592 /* XXX arty -- Handled adjustment in a saner way than before ...
593 * not needed immediately */
594 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
596 switch (Adapter
->Media
) {
597 case NdisMedium802_3
:
598 EHeader
= (PETH_HEADER
)Data
;
601 /* Unicast address */
602 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
604 /* Broadcast address */
605 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
608 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
612 EHeader
->EType
= ETYPE_IPv4
;
615 EHeader
->EType
= ETYPE_ARP
;
618 EHeader
->EType
= ETYPE_IPv6
;
622 /* Should not happen */
623 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
625 ProtocolSendComplete((NDIS_HANDLE
)Context
,
627 NDIS_STATUS_FAILURE
);
634 /* FIXME: Support other medias */
638 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
642 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
643 ((PCHAR
)LinkAddress
)[0] & 0xff,
644 ((PCHAR
)LinkAddress
)[1] & 0xff,
645 ((PCHAR
)LinkAddress
)[2] & 0xff,
646 ((PCHAR
)LinkAddress
)[3] & 0xff,
647 ((PCHAR
)LinkAddress
)[4] & 0xff,
648 ((PCHAR
)LinkAddress
)[5] & 0xff));
651 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
652 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
653 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
654 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
655 NdisStatus
== NDIS_STATUS_PENDING
?
656 "Pending" : "Complete"));
657 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
659 /* I had a talk with vizzini: these really ought to be here.
660 * we're supposed to see these completed by ndis *only* when
661 * status_pending is returned. Note that this is different from
662 * the situation with IRPs. */
663 if (NdisStatus
!= NDIS_STATUS_PENDING
)
664 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
668 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
669 OBJECT_ATTRIBUTES Attributes
;
672 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
673 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
677 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
678 PWCHAR RegistryValue
,
679 PUNICODE_STRING String
) {
680 UNICODE_STRING ValueName
;
681 UNICODE_STRING UnicodeString
;
685 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
687 RtlInitUnicodeString(&ValueName
, RegistryValue
);
689 ZwQueryValueKey(RegHandle
,
691 KeyValuePartialInformation
,
696 if (!NT_SUCCESS(Status
))
698 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
699 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
701 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
702 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
703 UnicodeString
.MaximumLength
= Information
->DataLength
;
706 (PWCHAR
)exAllocatePool( NonPagedPool
,
707 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
709 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
711 String
->MaximumLength
= UnicodeString
.MaximumLength
;
712 RtlCopyUnicodeString( String
, &UnicodeString
);
714 return STATUS_SUCCESS
;
718 * Utility to copy and append two unicode strings.
720 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
721 * IN PUNICODE_STRING Second -> Second string to append
722 * IN BOOL Deallocate -> TRUE: Deallocate First string before
728 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
729 PUNICODE_STRING Second
,
730 BOOLEAN Deallocate
) {
732 UNICODE_STRING Ustr
= *ResultFirst
;
733 PWSTR new_string
= ExAllocatePoolWithTag
735 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)), TAG_STRING
);
737 return STATUS_NO_MEMORY
;
739 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
740 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
741 Second
->Buffer
, Second
->Length
);
742 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
743 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
744 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
745 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
746 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
747 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
748 ExFreePool(new_string
);
752 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
753 PUNICODE_STRING TargetKeyName
,
754 PUNICODE_STRING Name
,
755 PUNICODE_STRING DeviceDesc
) {
756 UNICODE_STRING RootDevice
= { 0, 0, NULL
}, LinkageKeyName
= { 0, 0, NULL
};
757 UNICODE_STRING DescKeyName
= { 0, 0, NULL
}, Linkage
= { 0, 0, NULL
};
758 UNICODE_STRING BackSlash
= { 0, 0, NULL
};
759 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
762 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
764 RtlInitUnicodeString(&BackSlash
, L
"\\");
765 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
767 RtlInitUnicodeString(&DescKeyName
, L
"");
768 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
769 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
770 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
772 RtlInitUnicodeString(&LinkageKeyName
, L
"");
773 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
774 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
776 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
777 if( !NT_SUCCESS(Status
) ) goto cleanup
;
779 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
780 if( !NT_SUCCESS(Status
) ) goto cleanup
;
782 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
783 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
784 if( !NT_SUCCESS(Status
) ) goto cleanup
;
786 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
787 if( !NT_SUCCESS(Status
) ) goto cleanup
;
789 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
790 } else Status
= STATUS_UNSUCCESSFUL
;
793 RtlFreeUnicodeString( &RootDevice
);
794 RtlFreeUnicodeString( &LinkageKeyName
);
795 RtlFreeUnicodeString( &DescKeyName
);
796 if( LinkageKey
) NtClose( LinkageKey
);
797 if( DescKey
) NtClose( DescKey
);
799 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
804 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
805 PUNICODE_STRING DeviceDesc
) {
806 UNICODE_STRING EnumKeyName
, TargetKeyName
;
810 KEY_BASIC_INFORMATION
*Kbio
=
811 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
812 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
814 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
817 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
819 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
821 if( !NT_SUCCESS(Status
) ) {
822 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
823 &EnumKeyName
, Status
));
828 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
829 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
830 Kbio
, KbioLength
, &ResultLength
);
832 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
834 KbioLength
= ResultLength
;
835 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
837 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
839 return STATUS_NO_MEMORY
;
842 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
843 Kbio
, KbioLength
, &ResultLength
);
845 if( !NT_SUCCESS(Status
) ) {
846 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
853 if( NT_SUCCESS(Status
) ) {
854 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
856 TargetKeyName
.Buffer
= Kbio
->Name
;
858 Status
= CheckForDeviceDesc
859 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
860 if( NT_SUCCESS(Status
) ) {
864 } else Status
= STATUS_SUCCESS
;
868 RtlInitUnicodeString( DeviceDesc
, L
"" );
869 AppendUnicodeString( DeviceDesc
, &TargetKeyName
, FALSE
);
872 return STATUS_UNSUCCESSFUL
;
875 VOID
GetName( PUNICODE_STRING RegistryKey
,
876 PUNICODE_STRING OutName
) {
878 UNICODE_STRING PartialRegistryKey
;
880 PartialRegistryKey
.Buffer
=
881 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
882 Ptr
= PartialRegistryKey
.Buffer
;
884 while( *Ptr
!= L
'\\' &&
885 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
888 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
889 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
891 RtlInitUnicodeString( OutName
, L
"" );
892 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
896 PLAN_ADAPTER Adapter
,
897 PNDIS_STRING RegistryPath
)
899 * FUNCTION: Binds a LAN adapter to IP layer
901 * Adapter = Pointer to LAN_ADAPTER structure
903 * We set the lookahead buffer size, set the packet filter and
904 * bind the adapter to IP layer
908 NDIS_STATUS NdisStatus
;
909 LLIP_BIND_INFO BindInfo
;
910 IP_ADDRESS DefaultMask
;
911 ULONG Lookahead
= LOOKAHEAD_SIZE
;
914 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
916 Adapter
->State
= LAN_STATE_OPENING
;
918 NdisStatus
= NDISCall(Adapter
,
919 NdisRequestSetInformation
,
920 OID_GEN_CURRENT_LOOKAHEAD
,
923 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
924 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
928 /* Bind the adapter to IP layer */
929 BindInfo
.Context
= Adapter
;
930 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
931 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
932 BindInfo
.MTU
= Adapter
->MTU
;
933 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
934 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
935 BindInfo
.Transmit
= LANTransmit
;
937 IF
= IPCreateInterface(&BindInfo
);
940 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
945 * Query per-adapter configuration from the registry
946 * In case anyone is curious: there *is* an Ndis configuration api
947 * for this sort of thing, but it doesn't really support things like
948 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
949 * protocol drivers developed for win2k and above just use the native
950 * services (ZwOpenKey, etc).
953 GetName( RegistryPath
, &IF
->Name
);
955 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
957 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
960 AddrInitIPv4(&DefaultMask
, 0);
962 IF
->Unicast
= DefaultMask
;
963 IF
->Netmask
= DefaultMask
;
965 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
966 IF
->Broadcast
.Address
.IPv4Address
=
967 IF
->Unicast
.Address
.IPv4Address
|
968 ~IF
->Netmask
.Address
.IPv4Address
;
970 TI_DbgPrint(DEBUG_DATALINK
,("BCAST(IF) %s\n", A2S(&IF
->Broadcast
)));
972 /* Get maximum link speed */
973 NdisStatus
= NDISCall(Adapter
,
974 NdisRequestQueryInformation
,
979 if( !NT_SUCCESS(NdisStatus
) )
980 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
982 /* Register interface with IP layer */
983 IPRegisterInterface(IF
);
985 /* Set packet filter so we can send and receive packets */
986 NdisStatus
= NDISCall(Adapter
,
987 NdisRequestSetInformation
,
988 OID_GEN_CURRENT_PACKET_FILTER
,
989 &Adapter
->PacketFilter
,
992 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
993 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
994 IPUnregisterInterface(IF
);
995 IPDestroyInterface(IF
);
999 Adapter
->Context
= IF
;
1000 Adapter
->State
= LAN_STATE_STARTED
;
1006 PLAN_ADAPTER Adapter
)
1008 * FUNCTION: Unbinds a LAN adapter from IP layer
1010 * Adapter = Pointer to LAN_ADAPTER structure
1013 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1015 if (Adapter
->State
== LAN_STATE_STARTED
) {
1016 PIP_INTERFACE IF
= Adapter
->Context
;
1018 IPUnregisterInterface(IF
);
1020 IPDestroyInterface(IF
);
1025 NDIS_STATUS
LANRegisterAdapter(
1026 PNDIS_STRING AdapterName
,
1027 PNDIS_STRING RegistryPath
)
1029 * FUNCTION: Registers protocol with an NDIS adapter
1031 * AdapterName = Pointer to string with name of adapter to register
1032 * Adapter = Address of pointer to a LAN_ADAPTER structure
1034 * Status of operation
1038 NDIS_STATUS NdisStatus
;
1039 NDIS_STATUS OpenStatus
;
1041 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1045 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1047 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
1049 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1050 return NDIS_STATUS_RESOURCES
;
1053 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1055 /* Put adapter in stopped state */
1056 IF
->State
= LAN_STATE_STOPPED
;
1058 /* Initialize protecting spin lock */
1059 KeInitializeSpinLock(&IF
->Lock
);
1061 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1063 /* Initialize array with media IDs we support */
1064 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1066 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1067 /* Open the adapter. */
1068 NdisOpenAdapter(&NdisStatus
,
1080 /* Wait until the adapter is opened */
1081 if (NdisStatus
== NDIS_STATUS_PENDING
)
1082 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1083 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1084 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1089 IF
->Media
= MediaArray
[MediaIndex
];
1091 /* Fill LAN_ADAPTER structure with some adapter specific information */
1092 switch (IF
->Media
) {
1093 case NdisMedium802_3
:
1094 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1095 IF
->BCastMask
= BCAST_ETH_MASK
;
1096 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1097 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1098 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1099 IF
->MinFrameSize
= 60;
1100 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1102 NDIS_PACKET_TYPE_BROADCAST
|
1103 NDIS_PACKET_TYPE_DIRECTED
|
1104 NDIS_PACKET_TYPE_MULTICAST
;
1108 /* Unsupported media */
1109 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1111 return NDIS_STATUS_NOT_SUPPORTED
;
1114 /* Get maximum frame size */
1115 NdisStatus
= NDISCall(IF
,
1116 NdisRequestQueryInformation
,
1117 OID_GEN_MAXIMUM_FRAME_SIZE
,
1120 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1121 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (NDISCall)\n", AdapterName
));
1126 /* Get maximum packet size */
1127 NdisStatus
= NDISCall(IF
,
1128 NdisRequestQueryInformation
,
1129 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1132 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1133 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1138 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1139 NdisStatus
= NDISCall(IF
,
1140 NdisRequestQueryInformation
,
1141 OID_GEN_MAXIMUM_SEND_PACKETS
,
1142 &IF
->MaxSendPackets
,
1144 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1145 /* Legacy NIC drivers may not support this query, if it fails we
1146 assume it can send at least one packet per call to NdisSend(Packets) */
1147 IF
->MaxSendPackets
= 1;
1149 /* Get current hardware address */
1150 NdisStatus
= NDISCall(IF
,
1151 NdisRequestQueryInformation
,
1154 IF
->HWAddressLength
);
1155 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1156 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1161 /* Get maximum link speed */
1162 NdisStatus
= NDISCall(IF
,
1163 NdisRequestQueryInformation
,
1167 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1168 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1173 /* Convert returned link speed to bps (it is in 100bps increments) */
1174 IF
->Speed
= Speed
* 100L;
1176 /* Bind adapter to IP layer */
1177 if( !BindAdapter(IF
, RegistryPath
) ) {
1178 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1180 return NDIS_STATUS_NOT_ACCEPTED
;
1183 /* Add adapter to the adapter list */
1184 ExInterlockedInsertTailList(&AdapterListHead
,
1188 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1190 return NDIS_STATUS_SUCCESS
;
1194 NDIS_STATUS
LANUnregisterAdapter(
1195 PLAN_ADAPTER Adapter
)
1197 * FUNCTION: Unregisters protocol with NDIS adapter
1199 * Adapter = Pointer to a LAN_ADAPTER structure
1201 * Status of operation
1205 NDIS_HANDLE NdisHandle
;
1206 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1208 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1210 /* Unlink the adapter from the list */
1211 RemoveEntryList(&Adapter
->ListEntry
);
1213 /* Unbind adapter from IP layer */
1214 UnbindAdapter(Adapter
);
1216 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1217 NdisHandle
= Adapter
->NdisHandle
;
1219 Adapter
->NdisHandle
= NULL
;
1220 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1222 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1223 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1224 TcpipWaitForSingleObject(&Adapter
->Event
,
1229 NdisStatus
= Adapter
->NdisStatus
;
1232 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1234 FreeAdapter(Adapter
);
1240 NTSTATUS
LANRegisterProtocol(
1243 * FUNCTION: Registers this protocol driver with NDIS
1245 * Name = Name of this protocol driver
1247 * Status of operation
1250 NDIS_STATUS NdisStatus
;
1251 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1253 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1255 InitializeListHead(&AdapterListHead
);
1256 KeInitializeSpinLock(&AdapterListLock
);
1258 /* Set up protocol characteristics */
1259 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1260 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1261 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1262 ProtChars
.Name
.Length
= Name
->Length
;
1263 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1264 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1265 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1266 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1267 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1268 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1269 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1270 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1271 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1272 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1273 ProtChars
.StatusHandler
= ProtocolStatus
;
1274 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1275 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1277 /* Try to register protocol */
1278 NdisRegisterProtocol(&NdisStatus
,
1279 &NdisProtocolHandle
,
1281 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1282 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1284 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1285 return (NTSTATUS
)NdisStatus
;
1288 ProtocolRegistered
= TRUE
;
1290 return STATUS_SUCCESS
;
1294 VOID
LANUnregisterProtocol(
1297 * FUNCTION: Unregisters this protocol driver with NDIS
1298 * NOTES: Does not care wether we are already registered
1301 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1303 if (ProtocolRegistered
) {
1304 NDIS_STATUS NdisStatus
;
1305 PLIST_ENTRY CurrentEntry
;
1306 PLIST_ENTRY NextEntry
;
1307 PLAN_ADAPTER Current
;
1310 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1312 /* Search the list and remove every adapter we find */
1313 CurrentEntry
= AdapterListHead
.Flink
;
1314 while (CurrentEntry
!= &AdapterListHead
) {
1315 NextEntry
= CurrentEntry
->Flink
;
1316 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1318 LANUnregisterAdapter(Current
);
1319 CurrentEntry
= NextEntry
;
1322 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1324 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1325 ProtocolRegistered
= FALSE
;