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
111 ExFreePoolWithTag(Adapter
, LAN_ADAPTER_TAG
);
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 FreeNdisPacket(Packet
);
237 VOID
LanReceiveWorker( PVOID Context
) {
239 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
241 PLAN_ADAPTER Adapter
;
242 UINT BytesTransferred
;
243 PNDIS_BUFFER NdisBuffer
;
246 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
248 Packet
= WorkItem
->Packet
;
249 Adapter
= WorkItem
->Adapter
;
250 BytesTransferred
= WorkItem
->BytesTransferred
;
252 ExFreePoolWithTag(WorkItem
, WQ_CONTEXT_TAG
);
254 IPInitializePacket(&IPPacket
, 0);
256 IPPacket
.NdisPacket
= Packet
;
258 NdisGetFirstBufferFromPacket(Packet
,
261 &IPPacket
.ContigSize
,
262 &IPPacket
.TotalSize
);
264 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
265 /* Determine which upper layer protocol that should receive
266 this packet and pass it to the correct receive handler */
268 TI_DbgPrint(MID_TRACE
,
269 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
270 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
273 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
274 IPPacket
.Position
= 0;
278 ("Ether Type = %x ContigSize = %d Total = %d\n",
279 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
281 switch (PacketType
) {
284 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
285 IPReceive(Adapter
->Context
, &IPPacket
);
288 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
289 ARPReceive(Adapter
->Context
, &IPPacket
);
292 IPPacket
.Free(&IPPacket
);
296 FreeNdisPacket( Packet
);
299 VOID
LanSubmitReceiveWork(
300 NDIS_HANDLE BindingContext
,
303 UINT BytesTransferred
) {
304 PLAN_WQ_ITEM WQItem
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_WQ_ITEM
),
306 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
308 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
312 WQItem
->Packet
= Packet
;
313 WQItem
->Adapter
= Adapter
;
314 WQItem
->BytesTransferred
= BytesTransferred
;
316 if (!ChewCreate( LanReceiveWorker
, WQItem
))
317 ExFreePoolWithTag(WQItem
, WQ_CONTEXT_TAG
);
320 VOID NTAPI
ProtocolTransferDataComplete(
321 NDIS_HANDLE BindingContext
,
324 UINT BytesTransferred
)
326 * FUNCTION: Called by NDIS to complete reception of data
328 * BindingContext = Pointer to a device context (LAN_ADAPTER)
329 * Packet = Pointer to a packet descriptor
330 * Status = Status of the operation
331 * BytesTransferred = Number of bytes transferred
333 * If the packet was successfully received, determine the protocol
334 * type and pass it to the correct receive handler
337 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
339 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
341 TransferDataCompleteCalled
++;
342 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
344 if( Status
!= NDIS_STATUS_SUCCESS
) return;
346 LanSubmitReceiveWork( BindingContext
, Packet
, Status
, BytesTransferred
);
349 NDIS_STATUS NTAPI
ProtocolReceive(
350 NDIS_HANDLE BindingContext
,
351 NDIS_HANDLE MacReceiveContext
,
353 UINT HeaderBufferSize
,
354 PVOID LookaheadBuffer
,
355 UINT LookaheadBufferSize
,
358 * FUNCTION: Called by NDIS when a packet has been received on the physical link
360 * BindingContext = Pointer to a device context (LAN_ADAPTER)
361 * MacReceiveContext = Handle used by underlying NIC driver
362 * HeaderBuffer = Pointer to a buffer containing the packet header
363 * HeaderBufferSize = Number of bytes in HeaderBuffer
364 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
365 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
366 * PacketSize = Overall size of the packet (not including header)
368 * Status of operation
372 UINT PacketType
, BytesTransferred
;
376 NDIS_STATUS NdisStatus
;
377 PNDIS_PACKET NdisPacket
;
378 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
379 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
381 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
383 if (Adapter
->State
!= LAN_STATE_STARTED
) {
384 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
385 return NDIS_STATUS_NOT_ACCEPTED
;
388 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
389 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
390 return NDIS_STATUS_NOT_ACCEPTED
;
393 if (Adapter
->Media
== NdisMedium802_3
) {
394 /* Ethernet and IEEE 802.3 frames can be destinguished by
395 looking at the IEEE 802.3 length field. This field is
396 less than or equal to 1500 for a valid IEEE 802.3 frame
397 and larger than 1500 is it's a valid EtherType value.
398 See RFC 1122, section 2.3.3 for more information */
399 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
400 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
401 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
402 return NDIS_STATUS_NOT_ACCEPTED
;
404 /* We use EtherType constants to destinguish packet types */
407 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
408 /* FIXME: Support other medias */
409 return NDIS_STATUS_NOT_ACCEPTED
;
412 /* Get a transfer data packet */
414 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
415 Adapter
, Adapter
->MTU
));
417 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
419 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
420 return NDIS_STATUS_NOT_ACCEPTED
;
423 PC(NdisPacket
)->PacketType
= PacketType
;
425 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
427 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
429 IPPacket
.NdisPacket
= NdisPacket
;
430 IPPacket
.Position
= 0;
432 TransferDataCalled
++;
434 if (LookaheadBufferSize
== PacketSize
)
436 /* Optimized code path for packets that are fully contained in
437 * the lookahead buffer. */
438 NdisCopyLookaheadData(BufferData
,
441 Adapter
->MacOptions
);
445 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
446 MacReceiveContext
, 0, PacketSize
,
447 NdisPacket
, &BytesTransferred
);
449 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
451 if (NdisStatus
!= NDIS_STATUS_PENDING
)
452 ProtocolTransferDataComplete(BindingContext
,
457 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
459 return NDIS_STATUS_SUCCESS
;
463 VOID NTAPI
ProtocolReceiveComplete(
464 NDIS_HANDLE BindingContext
)
466 * FUNCTION: Called by NDIS when we're done receiving data
468 * BindingContext = Pointer to a device context (LAN_ADAPTER)
471 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
475 VOID NTAPI
ProtocolStatus(
476 NDIS_HANDLE BindingContext
,
477 NDIS_STATUS GeneralStatus
,
479 UINT StatusBufferSize
)
481 * FUNCTION: Called by NDIS when the underlying driver has changed state
483 * BindingContext = Pointer to a device context (LAN_ADAPTER)
484 * GeneralStatus = A general status code
485 * StatusBuffer = Pointer to a buffer with medium-specific data
486 * StatusBufferSize = Number of bytes in StatusBuffer
489 PLAN_ADAPTER Adapter
= BindingContext
;
491 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
493 switch(GeneralStatus
)
495 case NDIS_STATUS_MEDIA_CONNECT
:
496 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
499 case NDIS_STATUS_MEDIA_DISCONNECT
:
500 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
503 case NDIS_STATUS_RESET_START
:
504 Adapter
->State
= LAN_STATE_RESETTING
;
507 case NDIS_STATUS_RESET_END
:
508 Adapter
->State
= LAN_STATE_STARTED
;
512 DbgPrint("Unhandled status: %x", GeneralStatus
);
519 NDIS_HANDLE NdisBindingContext
,
520 PNET_PNP_EVENT PnPEvent
)
522 switch(PnPEvent
->NetEvent
)
524 case NetEventSetPower
:
525 DbgPrint("Device transitioned to power state %ld\n", PnPEvent
->Buffer
);
526 return NDIS_STATUS_SUCCESS
;
528 case NetEventQueryPower
:
529 DbgPrint("Device wants to go into power state %ld\n", PnPEvent
->Buffer
);
530 return NDIS_STATUS_SUCCESS
;
532 case NetEventQueryRemoveDevice
:
533 DbgPrint("Device is about to be removed\n");
534 return NDIS_STATUS_SUCCESS
;
536 case NetEventCancelRemoveDevice
:
537 DbgPrint("Device removal cancelled\n");
538 return NDIS_STATUS_SUCCESS
;
541 DbgPrint("Unhandled event type: %ld\n", PnPEvent
->NetEvent
);
542 return NDIS_STATUS_SUCCESS
;
546 VOID NTAPI
ProtocolStatusComplete(
547 NDIS_HANDLE NdisBindingContext
)
549 * FUNCTION: Called by NDIS when a status-change has occurred
551 * BindingContext = Pointer to a device context (LAN_ADAPTER)
554 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
557 VOID NTAPI
ProtocolBindAdapter(
558 OUT PNDIS_STATUS Status
,
559 IN NDIS_HANDLE BindContext
,
560 IN PNDIS_STRING DeviceName
,
561 IN PVOID SystemSpecific1
,
562 IN PVOID SystemSpecific2
)
564 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
565 * bindings, and periodically thereafer as new adapters come online
567 * Status: Return value to NDIS
568 * BindContext: Handle provided by NDIS to track pending binding operations
569 * DeviceName: Name of the miniport device to bind to
570 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
571 * SystemSpecific2: Unused & must not be touched
574 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
575 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
581 PNDIS_PACKET NdisPacket
,
586 * FUNCTION: Transmits a packet
588 * Context = Pointer to context information (LAN_ADAPTER)
589 * NdisPacket = Pointer to NDIS packet to send
590 * Offset = Offset in packet where data starts
591 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
592 * Type = LAN protocol type (LAN_PROTO_*)
595 NDIS_STATUS NdisStatus
;
599 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
601 PNDIS_PACKET XmitPacket
;
603 TI_DbgPrint(DEBUG_DATALINK
,
604 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
605 NdisPacket
, Offset
, Adapter
));
607 if (Adapter
->State
!= LAN_STATE_STARTED
) {
608 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
612 TI_DbgPrint(DEBUG_DATALINK
,
613 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
614 Adapter
->HWAddress
[0] & 0xff,
615 Adapter
->HWAddress
[1] & 0xff,
616 Adapter
->HWAddress
[2] & 0xff,
617 Adapter
->HWAddress
[3] & 0xff,
618 Adapter
->HWAddress
[4] & 0xff,
619 Adapter
->HWAddress
[5] & 0xff));
621 GetDataPtr( NdisPacket
, 0, &OldData
, &OldSize
);
623 NdisStatus
= AllocatePacketWithBuffer(&XmitPacket
, NULL
, OldSize
+ Adapter
->HeaderSize
);
624 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
625 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_RESOURCES
);
629 GetDataPtr(XmitPacket
, 0, &Data
, &Size
);
631 RtlCopyMemory(Data
+ Adapter
->HeaderSize
, OldData
, OldSize
);
633 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_SUCCESS
);
635 switch (Adapter
->Media
) {
636 case NdisMedium802_3
:
637 EHeader
= (PETH_HEADER
)Data
;
640 /* Unicast address */
641 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
643 /* Broadcast address */
644 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
647 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
651 EHeader
->EType
= ETYPE_IPv4
;
654 EHeader
->EType
= ETYPE_ARP
;
657 EHeader
->EType
= ETYPE_IPv6
;
666 /* FIXME: Support other medias */
670 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
674 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
675 ((PCHAR
)LinkAddress
)[0] & 0xff,
676 ((PCHAR
)LinkAddress
)[1] & 0xff,
677 ((PCHAR
)LinkAddress
)[2] & 0xff,
678 ((PCHAR
)LinkAddress
)[3] & 0xff,
679 ((PCHAR
)LinkAddress
)[4] & 0xff,
680 ((PCHAR
)LinkAddress
)[5] & 0xff));
683 if (Adapter
->MTU
< Size
) {
684 /* This is NOT a pointer. MSDN explicitly says so. */
685 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket
,
686 TcpLargeSendPacketInfo
) = (PVOID
)((ULONG_PTR
)Adapter
->MTU
);
689 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
690 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
691 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, XmitPacket
);
692 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
693 NdisStatus
== NDIS_STATUS_PENDING
?
694 "Pending" : "Complete"));
695 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
697 /* I had a talk with vizzini: these really ought to be here.
698 * we're supposed to see these completed by ndis *only* when
699 * status_pending is returned. Note that this is different from
700 * the situation with IRPs. */
701 if (NdisStatus
!= NDIS_STATUS_PENDING
)
702 ProtocolSendComplete((NDIS_HANDLE
)Context
, XmitPacket
, NdisStatus
);
706 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
707 OBJECT_ATTRIBUTES Attributes
;
710 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
711 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
715 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
716 PWCHAR RegistryValue
,
717 PUNICODE_STRING String
) {
718 UNICODE_STRING ValueName
;
719 UNICODE_STRING UnicodeString
;
723 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
725 RtlInitUnicodeString(&ValueName
, RegistryValue
);
727 ZwQueryValueKey(RegHandle
,
729 KeyValuePartialInformation
,
734 if (!NT_SUCCESS(Status
))
736 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
737 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
739 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
740 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
741 UnicodeString
.MaximumLength
= Information
->DataLength
;
744 (PWCHAR
)ExAllocatePool( NonPagedPool
,
745 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
747 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
749 String
->MaximumLength
= UnicodeString
.MaximumLength
;
750 RtlCopyUnicodeString( String
, &UnicodeString
);
752 return STATUS_SUCCESS
;
756 * Utility to copy and append two unicode strings.
758 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
759 * IN PUNICODE_STRING Second -> Second string to append
760 * IN BOOL Deallocate -> TRUE: Deallocate First string before
766 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
767 PUNICODE_STRING Second
,
768 BOOLEAN Deallocate
) {
770 UNICODE_STRING Ustr
= *ResultFirst
;
771 PWSTR new_string
= ExAllocatePool
773 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)));
775 return STATUS_NO_MEMORY
;
777 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
778 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
779 Second
->Buffer
, Second
->Length
);
780 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
781 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
782 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
783 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
784 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
785 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
786 ExFreePool(new_string
);
790 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
791 PUNICODE_STRING TargetKeyName
,
792 PUNICODE_STRING Name
,
793 PUNICODE_STRING DeviceDesc
) {
794 UNICODE_STRING RootDevice
= { 0, 0, NULL
}, LinkageKeyName
= { 0, 0, NULL
};
795 UNICODE_STRING DescKeyName
= { 0, 0, NULL
}, Linkage
= { 0, 0, NULL
};
796 UNICODE_STRING BackSlash
= { 0, 0, NULL
};
797 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
800 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
802 RtlInitUnicodeString(&BackSlash
, L
"\\");
803 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
805 RtlInitUnicodeString(&DescKeyName
, L
"");
806 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
807 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
808 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
810 RtlInitUnicodeString(&LinkageKeyName
, L
"");
811 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
812 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
814 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
815 if( !NT_SUCCESS(Status
) ) goto cleanup
;
817 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
818 if( !NT_SUCCESS(Status
) ) goto cleanup
;
820 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
821 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
822 if( !NT_SUCCESS(Status
) ) goto cleanup
;
824 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
825 if( !NT_SUCCESS(Status
) ) goto cleanup
;
827 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
828 } else Status
= STATUS_UNSUCCESSFUL
;
831 RtlFreeUnicodeString( &RootDevice
);
832 RtlFreeUnicodeString( &LinkageKeyName
);
833 RtlFreeUnicodeString( &DescKeyName
);
834 if( LinkageKey
) NtClose( LinkageKey
);
835 if( DescKey
) NtClose( DescKey
);
837 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
842 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
843 PUNICODE_STRING DeviceDesc
) {
844 UNICODE_STRING EnumKeyName
, TargetKeyName
;
848 KEY_BASIC_INFORMATION
*Kbio
=
849 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
850 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
852 RtlInitUnicodeString( DeviceDesc
, NULL
);
854 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
857 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
859 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
861 if( !NT_SUCCESS(Status
) ) {
862 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
863 &EnumKeyName
, Status
));
868 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
869 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
870 Kbio
, KbioLength
, &ResultLength
);
872 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
874 KbioLength
= ResultLength
;
875 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
877 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
879 return STATUS_NO_MEMORY
;
882 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
883 Kbio
, KbioLength
, &ResultLength
);
885 if( !NT_SUCCESS(Status
) ) {
886 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
893 if( NT_SUCCESS(Status
) ) {
894 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
896 TargetKeyName
.Buffer
= Kbio
->Name
;
898 Status
= CheckForDeviceDesc
899 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
900 if( NT_SUCCESS(Status
) ) {
904 } else Status
= STATUS_SUCCESS
;
910 return STATUS_UNSUCCESSFUL
;
913 VOID
GetName( PUNICODE_STRING RegistryKey
,
914 PUNICODE_STRING OutName
) {
916 UNICODE_STRING PartialRegistryKey
;
918 PartialRegistryKey
.Buffer
=
919 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
920 Ptr
= PartialRegistryKey
.Buffer
;
922 while( *Ptr
!= L
'\\' &&
923 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
926 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
927 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
929 RtlInitUnicodeString( OutName
, L
"" );
930 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
934 PLAN_ADAPTER Adapter
,
935 PNDIS_STRING RegistryPath
)
937 * FUNCTION: Binds a LAN adapter to IP layer
939 * Adapter = Pointer to LAN_ADAPTER structure
941 * We set the lookahead buffer size, set the packet filter and
942 * bind the adapter to IP layer
946 NDIS_STATUS NdisStatus
;
947 LLIP_BIND_INFO BindInfo
;
948 IP_ADDRESS DefaultMask
, Router
;
949 ULONG Lookahead
= LOOKAHEAD_SIZE
, Unused
;
951 OBJECT_ATTRIBUTES ObjectAttributes
;
952 HANDLE ParameterHandle
;
953 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo
;
955 UNICODE_STRING IPAddress
= RTL_CONSTANT_STRING(L
"IPAddress");
956 UNICODE_STRING Netmask
= RTL_CONSTANT_STRING(L
"SubnetMask");
957 UNICODE_STRING Gateway
= RTL_CONSTANT_STRING(L
"DefaultGateway");
958 UNICODE_STRING EnableDhcp
= RTL_CONSTANT_STRING(L
"EnableDHCP");
959 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
960 UNICODE_STRING TcpipRegistryPath
;
961 UNICODE_STRING RegistryDataU
;
962 ANSI_STRING RegistryDataA
;
964 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
966 Adapter
->State
= LAN_STATE_OPENING
;
968 NdisStatus
= NDISCall(Adapter
,
969 NdisRequestSetInformation
,
970 OID_GEN_CURRENT_LOOKAHEAD
,
973 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
974 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
978 /* Bind the adapter to IP layer */
979 BindInfo
.Context
= Adapter
;
980 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
981 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
982 BindInfo
.MTU
= Adapter
->MTU
;
983 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
984 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
985 BindInfo
.Transmit
= LANTransmit
;
987 IF
= IPCreateInterface(&BindInfo
);
990 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
995 * Query per-adapter configuration from the registry
996 * In case anyone is curious: there *is* an Ndis configuration api
997 * for this sort of thing, but it doesn't really support things like
998 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
999 * protocol drivers developed for win2k and above just use the native
1000 * services (ZwOpenKey, etc).
1003 GetName( RegistryPath
, &IF
->Name
);
1005 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
1006 if (!NT_SUCCESS(Status
)) {
1007 TI_DbgPrint(MIN_TRACE
, ("Failed to get device description.\n"));
1008 IPDestroyInterface(IF
);
1012 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
1015 TcpipRegistryPath
.MaximumLength
= sizeof(WCHAR
) * 150;
1016 TcpipRegistryPath
.Length
= 0;
1017 TcpipRegistryPath
.Buffer
= Buffer
;
1019 RtlAppendUnicodeStringToString(&TcpipRegistryPath
,
1022 RtlAppendUnicodeStringToString(&TcpipRegistryPath
,
1025 InitializeObjectAttributes(&ObjectAttributes
,
1027 OBJ_CASE_INSENSITIVE
,
1031 AddrInitIPv4(&DefaultMask
, 0);
1033 Status
= ZwOpenKey(&ParameterHandle
, KEY_READ
, &ObjectAttributes
);
1035 if (!NT_SUCCESS(Status
))
1037 IF
->Unicast
= DefaultMask
;
1038 IF
->Netmask
= DefaultMask
;
1042 KeyValueInfo
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
));
1045 ZwClose(ParameterHandle
);
1046 IPDestroyInterface(IF
);
1050 Status
= ZwQueryValueKey(ParameterHandle
,
1052 KeyValuePartialInformation
,
1054 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
),
1056 if (NT_SUCCESS(Status
) && KeyValueInfo
->DataLength
== sizeof(ULONG
) && (*(PULONG
)KeyValueInfo
->Data
) == 0)
1058 RegistryDataU
.MaximumLength
= 16 + sizeof(WCHAR
);
1059 RegistryDataU
.Buffer
= (PWCHAR
)KeyValueInfo
->Data
;
1061 Status
= ZwQueryValueKey(ParameterHandle
,
1063 KeyValuePartialInformation
,
1065 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1067 if (NT_SUCCESS(Status
))
1069 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1071 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1075 AddrInitIPv4(&IF
->Unicast
, inet_addr(RegistryDataA
.Buffer
));
1077 RtlFreeAnsiString(&RegistryDataA
);
1082 IF
->Unicast
= DefaultMask
;
1085 Status
= ZwQueryValueKey(ParameterHandle
,
1087 KeyValuePartialInformation
,
1089 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1091 if (NT_SUCCESS(Status
))
1093 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1095 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1099 AddrInitIPv4(&IF
->Netmask
, inet_addr(RegistryDataA
.Buffer
));
1101 RtlFreeAnsiString(&RegistryDataA
);
1105 IF
->Netmask
= DefaultMask
;
1108 Status
= ZwQueryValueKey(ParameterHandle
,
1110 KeyValuePartialInformation
,
1112 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1114 if (NT_SUCCESS(Status
))
1116 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1118 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1122 AddrInitIPv4(&Router
, inet_addr(RegistryDataA
.Buffer
));
1124 RtlFreeAnsiString(&RegistryDataA
);
1126 if (!AddrIsUnspecified(&Router
)) RouterCreateRoute(&DefaultMask
, &DefaultMask
, &Router
, IF
, 1);
1131 IF
->Unicast
= DefaultMask
;
1132 IF
->Netmask
= DefaultMask
;
1135 ZwClose(ParameterHandle
);
1138 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
1139 IF
->Broadcast
.Address
.IPv4Address
=
1140 IF
->Unicast
.Address
.IPv4Address
|
1141 ~IF
->Netmask
.Address
.IPv4Address
;
1143 TI_DbgPrint(DEBUG_DATALINK
,("BCAST(IF) %s\n", A2S(&IF
->Broadcast
)));
1145 /* Get maximum link speed */
1146 NdisStatus
= NDISCall(Adapter
,
1147 NdisRequestQueryInformation
,
1152 if( !NT_SUCCESS(NdisStatus
) )
1153 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1155 /* Register interface with IP layer */
1156 IPRegisterInterface(IF
);
1158 /* Set packet filter so we can send and receive packets */
1159 NdisStatus
= NDISCall(Adapter
,
1160 NdisRequestSetInformation
,
1161 OID_GEN_CURRENT_PACKET_FILTER
,
1162 &Adapter
->PacketFilter
,
1165 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1166 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1167 IPUnregisterInterface(IF
);
1168 IPDestroyInterface(IF
);
1172 Adapter
->Context
= IF
;
1173 Adapter
->State
= LAN_STATE_STARTED
;
1179 PLAN_ADAPTER Adapter
)
1181 * FUNCTION: Unbinds a LAN adapter from IP layer
1183 * Adapter = Pointer to LAN_ADAPTER structure
1186 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1188 if (Adapter
->State
== LAN_STATE_STARTED
) {
1189 PIP_INTERFACE IF
= Adapter
->Context
;
1191 IPUnregisterInterface(IF
);
1193 IPDestroyInterface(IF
);
1198 NDIS_STATUS
LANRegisterAdapter(
1199 PNDIS_STRING AdapterName
,
1200 PNDIS_STRING RegistryPath
)
1202 * FUNCTION: Registers protocol with an NDIS adapter
1204 * AdapterName = Pointer to string with name of adapter to register
1205 * Adapter = Address of pointer to a LAN_ADAPTER structure
1207 * Status of operation
1211 NDIS_STATUS NdisStatus
;
1212 NDIS_STATUS OpenStatus
;
1214 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1218 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1220 IF
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_ADAPTER
), LAN_ADAPTER_TAG
);
1222 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1223 return NDIS_STATUS_RESOURCES
;
1226 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1228 /* Put adapter in stopped state */
1229 IF
->State
= LAN_STATE_STOPPED
;
1231 /* Initialize protecting spin lock */
1232 KeInitializeSpinLock(&IF
->Lock
);
1234 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1236 /* Initialize array with media IDs we support */
1237 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1239 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1240 /* Open the adapter. */
1241 NdisOpenAdapter(&NdisStatus
,
1253 /* Wait until the adapter is opened */
1254 if (NdisStatus
== NDIS_STATUS_PENDING
)
1255 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1256 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1257 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1258 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1262 IF
->Media
= MediaArray
[MediaIndex
];
1264 /* Fill LAN_ADAPTER structure with some adapter specific information */
1265 switch (IF
->Media
) {
1266 case NdisMedium802_3
:
1267 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1268 IF
->BCastMask
= BCAST_ETH_MASK
;
1269 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1270 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1271 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1272 IF
->MinFrameSize
= 60;
1273 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1275 NDIS_PACKET_TYPE_BROADCAST
|
1276 NDIS_PACKET_TYPE_DIRECTED
|
1277 NDIS_PACKET_TYPE_MULTICAST
;
1281 /* Unsupported media */
1282 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1283 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1284 return NDIS_STATUS_NOT_SUPPORTED
;
1287 /* Get maximum frame size */
1288 NdisStatus
= NDISCall(IF
,
1289 NdisRequestQueryInformation
,
1290 OID_GEN_MAXIMUM_FRAME_SIZE
,
1293 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1294 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (NDISCall)\n", AdapterName
));
1295 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1299 /* Get maximum packet size */
1300 NdisStatus
= NDISCall(IF
,
1301 NdisRequestQueryInformation
,
1302 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1305 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1306 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1307 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1311 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1312 NdisStatus
= NDISCall(IF
,
1313 NdisRequestQueryInformation
,
1314 OID_GEN_MAXIMUM_SEND_PACKETS
,
1315 &IF
->MaxSendPackets
,
1317 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1318 /* Legacy NIC drivers may not support this query, if it fails we
1319 assume it can send at least one packet per call to NdisSend(Packets) */
1320 IF
->MaxSendPackets
= 1;
1322 /* Get current hardware address */
1323 NdisStatus
= NDISCall(IF
,
1324 NdisRequestQueryInformation
,
1327 IF
->HWAddressLength
);
1328 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1329 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1330 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1334 /* Get maximum link speed */
1335 NdisStatus
= NDISCall(IF
,
1336 NdisRequestQueryInformation
,
1340 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1341 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1342 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1346 /* Convert returned link speed to bps (it is in 100bps increments) */
1347 IF
->Speed
= Speed
* 100L;
1349 /* Bind adapter to IP layer */
1350 if( !BindAdapter(IF
, RegistryPath
) ) {
1351 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1352 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1353 return NDIS_STATUS_NOT_ACCEPTED
;
1356 /* Add adapter to the adapter list */
1357 ExInterlockedInsertTailList(&AdapterListHead
,
1361 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1363 return NDIS_STATUS_SUCCESS
;
1367 NDIS_STATUS
LANUnregisterAdapter(
1368 PLAN_ADAPTER Adapter
)
1370 * FUNCTION: Unregisters protocol with NDIS adapter
1372 * Adapter = Pointer to a LAN_ADAPTER structure
1374 * Status of operation
1378 NDIS_HANDLE NdisHandle
;
1379 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1381 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1383 /* Unlink the adapter from the list */
1384 RemoveEntryList(&Adapter
->ListEntry
);
1386 /* Unbind adapter from IP layer */
1387 UnbindAdapter(Adapter
);
1389 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1390 NdisHandle
= Adapter
->NdisHandle
;
1392 Adapter
->NdisHandle
= NULL
;
1393 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1395 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1396 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1397 TcpipWaitForSingleObject(&Adapter
->Event
,
1402 NdisStatus
= Adapter
->NdisStatus
;
1405 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1407 FreeAdapter(Adapter
);
1414 LANUnregisterProtocol(VOID
)
1416 * FUNCTION: Unregisters this protocol driver with NDIS
1417 * NOTES: Does not care wether we are already registered
1420 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1422 if (ProtocolRegistered
) {
1423 NDIS_STATUS NdisStatus
;
1424 PLIST_ENTRY CurrentEntry
;
1425 PLIST_ENTRY NextEntry
;
1426 PLAN_ADAPTER Current
;
1429 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1431 /* Search the list and remove every adapter we find */
1432 CurrentEntry
= AdapterListHead
.Flink
;
1433 while (CurrentEntry
!= &AdapterListHead
) {
1434 NextEntry
= CurrentEntry
->Flink
;
1435 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1437 LANUnregisterAdapter(Current
);
1438 CurrentEntry
= NextEntry
;
1441 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1443 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1444 ProtocolRegistered
= FALSE
;
1450 ProtocolUnbindAdapter(
1451 PNDIS_STATUS Status
,
1452 NDIS_HANDLE ProtocolBindingContext
,
1453 NDIS_HANDLE UnbindContext
)
1455 /* We don't pend any unbinding so we can just ignore UnbindContext */
1456 *Status
= LANUnregisterAdapter((PLAN_ADAPTER
)ProtocolBindingContext
);
1459 NTSTATUS
LANRegisterProtocol(
1462 * FUNCTION: Registers this protocol driver with NDIS
1464 * Name = Name of this protocol driver
1466 * Status of operation
1469 NDIS_STATUS NdisStatus
;
1470 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1472 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1474 InitializeListHead(&AdapterListHead
);
1475 KeInitializeSpinLock(&AdapterListLock
);
1477 /* Set up protocol characteristics */
1478 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1479 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1480 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1481 ProtChars
.Name
.Length
= Name
->Length
;
1482 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1483 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1484 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1485 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1486 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1487 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1488 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1489 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1490 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1491 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1492 ProtChars
.StatusHandler
= ProtocolStatus
;
1493 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1494 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1495 ProtChars
.PnPEventHandler
= ProtocolPnPEvent
;
1496 ProtChars
.UnbindAdapterHandler
= ProtocolUnbindAdapter
;
1497 ProtChars
.UnloadHandler
= LANUnregisterProtocol
;
1499 /* Try to register protocol */
1500 NdisRegisterProtocol(&NdisStatus
,
1501 &NdisProtocolHandle
,
1503 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1504 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1506 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1507 return (NTSTATUS
)NdisStatus
;
1510 ProtocolRegistered
= TRUE
;
1512 return STATUS_SUCCESS
;