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 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
28 BOOLEAN ProtocolRegistered
= FALSE
;
29 LIST_ENTRY AdapterListHead
;
30 KSPIN_LOCK AdapterListLock
;
34 NDIS_REQUEST_TYPE Type
,
39 * FUNCTION: Send a request to NDIS
41 * Adapter = Pointer to a LAN_ADAPTER structure
42 * Type = Type of request (Set or Query)
43 * OID = Value to be set/queried for
44 * Buffer = Pointer to a buffer to use
45 * Length = Number of bytes in Buffer
51 NDIS_STATUS NdisStatus
;
53 Request
.RequestType
= Type
;
54 if (Type
== NdisRequestSetInformation
) {
55 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
56 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
57 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
59 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
60 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
61 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
64 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
65 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
67 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
70 /* Wait for NDIS to complete the request */
71 if (NdisStatus
== NDIS_STATUS_PENDING
) {
72 KeWaitForSingleObject(&Adapter
->Event
,
77 NdisStatus
= Adapter
->NdisStatus
;
83 /* Used by legacy ProtocolReceive for packet type */
85 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter
,
87 ULONG HeaderBufferSize
,
90 PETH_HEADER EthHeader
= HeaderBuffer
;
92 if (HeaderBufferSize
< Adapter
->HeaderSize
)
94 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", HeaderBufferSize
));
95 return NDIS_STATUS_NOT_ACCEPTED
;
98 switch (Adapter
->Media
)
100 case NdisMedium802_3
:
101 /* Ethernet and IEEE 802.3 frames can be destinguished by
102 looking at the IEEE 802.3 length field. This field is
103 less than or equal to 1500 for a valid IEEE 802.3 frame
104 and larger than 1500 is it's a valid EtherType value.
105 See RFC 1122, section 2.3.3 for more information */
107 *PacketType
= EthHeader
->EType
;
111 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
113 /* FIXME: Support other medias */
114 return NDIS_STATUS_NOT_ACCEPTED
;
117 TI_DbgPrint(DEBUG_DATALINK
, ("EtherType (0x%X).\n", *PacketType
));
119 return NDIS_STATUS_SUCCESS
;
122 /* Used by ProtocolReceivePacket for packet type */
124 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter
,
125 PNDIS_PACKET NdisPacket
,
132 HeaderBuffer
= ExAllocatePool(NonPagedPool
,
133 Adapter
->HeaderSize
);
135 return NDIS_STATUS_RESOURCES
;
137 /* Copy the media header */
138 BytesCopied
= CopyPacketToBuffer(HeaderBuffer
,
141 Adapter
->HeaderSize
);
142 if (BytesCopied
!= Adapter
->HeaderSize
)
145 ExFreePool(HeaderBuffer
);
146 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame (size %d).\n", BytesCopied
));
147 return NDIS_STATUS_NOT_ACCEPTED
;
150 Status
= GetPacketTypeFromHeaderBuffer(Adapter
,
155 ExFreePool(HeaderBuffer
);
162 PLAN_ADAPTER Adapter
)
164 * FUNCTION: Frees memory for a LAN_ADAPTER structure
166 * Adapter = Pointer to LAN_ADAPTER structure to free
169 ExFreePoolWithTag(Adapter
, LAN_ADAPTER_TAG
);
173 NTSTATUS TcpipLanGetDwordOid
174 ( PIP_INTERFACE Interface
,
177 /* Get maximum frame size */
178 if( Interface
->Context
) {
179 return NDISCall((PLAN_ADAPTER
)Interface
->Context
,
180 NdisRequestQueryInformation
,
184 } else switch( Oid
) { /* Loopback Case */
185 case OID_GEN_HARDWARE_STATUS
:
186 *Result
= NdisHardwareStatusReady
;
187 return STATUS_SUCCESS
;
188 case OID_GEN_MEDIA_CONNECT_STATUS
:
189 *Result
= NdisMediaStateConnected
;
190 return STATUS_SUCCESS
;
192 return STATUS_INVALID_PARAMETER
;
197 VOID NTAPI
ProtocolOpenAdapterComplete(
198 NDIS_HANDLE BindingContext
,
200 NDIS_STATUS OpenErrorStatus
)
202 * FUNCTION: Called by NDIS to complete opening of an adapter
204 * BindingContext = Pointer to a device context (LAN_ADAPTER)
205 * Status = Status of the operation
206 * OpenErrorStatus = Additional status information
209 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
211 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
213 Adapter
->NdisStatus
= Status
;
215 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
219 VOID NTAPI
ProtocolCloseAdapterComplete(
220 NDIS_HANDLE BindingContext
,
223 * FUNCTION: Called by NDIS to complete closing an adapter
225 * BindingContext = Pointer to a device context (LAN_ADAPTER)
226 * Status = Status of the operation
229 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
231 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
233 Adapter
->NdisStatus
= Status
;
235 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
239 VOID NTAPI
ProtocolResetComplete(
240 NDIS_HANDLE BindingContext
,
243 * FUNCTION: Called by NDIS to complete resetting an adapter
245 * BindingContext = Pointer to a device context (LAN_ADAPTER)
246 * Status = Status of the operation
249 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
251 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
253 Adapter
->NdisStatus
= Status
;
255 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
259 VOID NTAPI
ProtocolRequestComplete(
260 NDIS_HANDLE BindingContext
,
261 PNDIS_REQUEST NdisRequest
,
264 * FUNCTION: Called by NDIS to complete a request
266 * BindingContext = Pointer to a device context (LAN_ADAPTER)
267 * NdisRequest = Pointer to an object describing the request
268 * Status = Status of the operation
271 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
273 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
275 /* Save status of request and signal an event */
276 Adapter
->NdisStatus
= Status
;
278 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
282 VOID NTAPI
ProtocolSendComplete(
283 NDIS_HANDLE BindingContext
,
287 * FUNCTION: Called by NDIS to complete sending process
289 * BindingContext = Pointer to a device context (LAN_ADAPTER)
290 * Packet = Pointer to a packet descriptor
291 * Status = Status of the operation
294 FreeNdisPacket(Packet
);
297 VOID
LanReceiveWorker( PVOID Context
) {
299 PLAN_WQ_ITEM WorkItem
= (PLAN_WQ_ITEM
)Context
;
301 PLAN_ADAPTER Adapter
;
302 UINT BytesTransferred
;
304 BOOLEAN LegacyReceive
;
305 PIP_INTERFACE Interface
;
307 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
309 Packet
= WorkItem
->Packet
;
310 Adapter
= WorkItem
->Adapter
;
311 BytesTransferred
= WorkItem
->BytesTransferred
;
312 LegacyReceive
= WorkItem
->LegacyReceive
;
314 ExFreePoolWithTag(WorkItem
, WQ_CONTEXT_TAG
);
316 Interface
= Adapter
->Context
;
318 IPInitializePacket(&IPPacket
, 0);
320 IPPacket
.NdisPacket
= Packet
;
321 IPPacket
.ReturnPacket
= !LegacyReceive
;
325 /* Packet type is precomputed */
326 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
328 /* Data is at position 0 */
329 IPPacket
.Position
= 0;
331 /* Packet size is determined by bytes transferred */
332 IPPacket
.TotalSize
= BytesTransferred
;
336 /* Determine packet type from media header */
337 if (GetPacketTypeFromNdisPacket(Adapter
,
339 &PacketType
) != NDIS_STATUS_SUCCESS
)
342 IPPacket
.Free(&IPPacket
);
346 /* Data is at the end of the media header */
347 IPPacket
.Position
= Adapter
->HeaderSize
;
349 /* Calculate packet size (excluding media header) */
350 NdisQueryPacketLength(IPPacket
.NdisPacket
, &IPPacket
.TotalSize
);
355 ("Ether Type = %x Total = %d\n",
356 PacketType
, IPPacket
.TotalSize
));
358 /* Update interface stats */
359 Interface
->Stats
.InBytes
+= IPPacket
.TotalSize
+ Adapter
->HeaderSize
;
361 /* NDIS packet is freed in all of these cases */
362 switch (PacketType
) {
365 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
366 IPReceive(Adapter
->Context
, &IPPacket
);
369 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
370 ARPReceive(Adapter
->Context
, &IPPacket
);
373 IPPacket
.Free(&IPPacket
);
378 VOID
LanSubmitReceiveWork(
379 NDIS_HANDLE BindingContext
,
381 UINT BytesTransferred
,
382 BOOLEAN LegacyReceive
) {
383 PLAN_WQ_ITEM WQItem
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_WQ_ITEM
),
385 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
387 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
391 WQItem
->Packet
= Packet
;
392 WQItem
->Adapter
= Adapter
;
393 WQItem
->BytesTransferred
= BytesTransferred
;
394 WQItem
->LegacyReceive
= LegacyReceive
;
396 if (!ChewCreate( LanReceiveWorker
, WQItem
))
397 ExFreePoolWithTag(WQItem
, WQ_CONTEXT_TAG
);
400 VOID NTAPI
ProtocolTransferDataComplete(
401 NDIS_HANDLE BindingContext
,
404 UINT BytesTransferred
)
406 * FUNCTION: Called by NDIS to complete reception of data
408 * BindingContext = Pointer to a device context (LAN_ADAPTER)
409 * Packet = Pointer to a packet descriptor
410 * Status = Status of the operation
411 * BytesTransferred = Number of bytes transferred
413 * If the packet was successfully received, determine the protocol
414 * type and pass it to the correct receive handler
417 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
419 TI_DbgPrint(DEBUG_DATALINK
,("called\n"));
421 TransferDataCompleteCalled
++;
422 ASSERT(TransferDataCompleteCalled
<= TransferDataCalled
);
424 if( Status
!= NDIS_STATUS_SUCCESS
) return;
426 LanSubmitReceiveWork(BindingContext
,
432 INT NTAPI
ProtocolReceivePacket(
433 NDIS_HANDLE BindingContext
,
434 PNDIS_PACKET NdisPacket
)
436 PLAN_ADAPTER Adapter
= BindingContext
;
438 if (Adapter
->State
!= LAN_STATE_STARTED
) {
439 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
443 LanSubmitReceiveWork(BindingContext
,
448 /* Hold 1 reference on this packet */
452 NDIS_STATUS NTAPI
ProtocolReceive(
453 NDIS_HANDLE BindingContext
,
454 NDIS_HANDLE MacReceiveContext
,
456 UINT HeaderBufferSize
,
457 PVOID LookaheadBuffer
,
458 UINT LookaheadBufferSize
,
461 * FUNCTION: Called by NDIS when a packet has been received on the physical link
463 * BindingContext = Pointer to a device context (LAN_ADAPTER)
464 * MacReceiveContext = Handle used by underlying NIC driver
465 * HeaderBuffer = Pointer to a buffer containing the packet header
466 * HeaderBufferSize = Number of bytes in HeaderBuffer
467 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
468 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
469 * PacketSize = Overall size of the packet (not including header)
471 * Status of operation
475 UINT BytesTransferred
;
477 NDIS_STATUS NdisStatus
;
478 PNDIS_PACKET NdisPacket
;
479 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
481 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
483 if (Adapter
->State
!= LAN_STATE_STARTED
) {
484 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
485 return NDIS_STATUS_NOT_ACCEPTED
;
488 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
489 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
490 return NDIS_STATUS_NOT_ACCEPTED
;
493 NdisStatus
= GetPacketTypeFromHeaderBuffer(Adapter
,
497 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
498 return NDIS_STATUS_NOT_ACCEPTED
;
500 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
501 Adapter
, Adapter
->MTU
));
503 /* Get a transfer data packet */
504 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
506 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
507 return NDIS_STATUS_NOT_ACCEPTED
;
510 PC(NdisPacket
)->PacketType
= PacketType
;
512 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
514 GetDataPtr( NdisPacket
, 0, &BufferData
, &PacketSize
);
516 TransferDataCalled
++;
518 if (LookaheadBufferSize
== PacketSize
)
520 /* Optimized code path for packets that are fully contained in
521 * the lookahead buffer. */
522 NdisCopyLookaheadData(BufferData
,
525 Adapter
->MacOptions
);
529 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
530 MacReceiveContext
, 0, PacketSize
,
531 NdisPacket
, &BytesTransferred
);
533 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
535 if (NdisStatus
!= NDIS_STATUS_PENDING
)
536 ProtocolTransferDataComplete(BindingContext
,
541 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
543 return NDIS_STATUS_SUCCESS
;
547 VOID NTAPI
ProtocolReceiveComplete(
548 NDIS_HANDLE BindingContext
)
550 * FUNCTION: Called by NDIS when we're done receiving data
552 * BindingContext = Pointer to a device context (LAN_ADAPTER)
555 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
559 VOID NTAPI
ProtocolStatus(
560 NDIS_HANDLE BindingContext
,
561 NDIS_STATUS GeneralStatus
,
563 UINT StatusBufferSize
)
565 * FUNCTION: Called by NDIS when the underlying driver has changed state
567 * BindingContext = Pointer to a device context (LAN_ADAPTER)
568 * GeneralStatus = A general status code
569 * StatusBuffer = Pointer to a buffer with medium-specific data
570 * StatusBufferSize = Number of bytes in StatusBuffer
573 PLAN_ADAPTER Adapter
= BindingContext
;
575 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
577 switch(GeneralStatus
)
579 case NDIS_STATUS_MEDIA_CONNECT
:
580 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
583 case NDIS_STATUS_MEDIA_DISCONNECT
:
584 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
587 case NDIS_STATUS_RESET_START
:
588 Adapter
->State
= LAN_STATE_RESETTING
;
591 case NDIS_STATUS_RESET_END
:
592 Adapter
->State
= LAN_STATE_STARTED
;
596 DbgPrint("Unhandled status: %x", GeneralStatus
);
603 NDIS_HANDLE NdisBindingContext
,
604 PNET_PNP_EVENT PnPEvent
)
606 switch(PnPEvent
->NetEvent
)
608 case NetEventSetPower
:
609 DbgPrint("Device transitioned to power state %ld\n", PnPEvent
->Buffer
);
610 return NDIS_STATUS_SUCCESS
;
612 case NetEventQueryPower
:
613 DbgPrint("Device wants to go into power state %ld\n", PnPEvent
->Buffer
);
614 return NDIS_STATUS_SUCCESS
;
616 case NetEventQueryRemoveDevice
:
617 DbgPrint("Device is about to be removed\n");
618 return NDIS_STATUS_SUCCESS
;
620 case NetEventCancelRemoveDevice
:
621 DbgPrint("Device removal cancelled\n");
622 return NDIS_STATUS_SUCCESS
;
625 DbgPrint("Unhandled event type: %ld\n", PnPEvent
->NetEvent
);
626 return NDIS_STATUS_SUCCESS
;
630 VOID NTAPI
ProtocolStatusComplete(
631 NDIS_HANDLE NdisBindingContext
)
633 * FUNCTION: Called by NDIS when a status-change has occurred
635 * BindingContext = Pointer to a device context (LAN_ADAPTER)
638 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
641 VOID NTAPI
ProtocolBindAdapter(
642 OUT PNDIS_STATUS Status
,
643 IN NDIS_HANDLE BindContext
,
644 IN PNDIS_STRING DeviceName
,
645 IN PVOID SystemSpecific1
,
646 IN PVOID SystemSpecific2
)
648 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
649 * bindings, and periodically thereafer as new adapters come online
651 * Status: Return value to NDIS
652 * BindContext: Handle provided by NDIS to track pending binding operations
653 * DeviceName: Name of the miniport device to bind to
654 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
655 * SystemSpecific2: Unused & must not be touched
658 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
659 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
665 PNDIS_PACKET NdisPacket
,
670 * FUNCTION: Transmits a packet
672 * Context = Pointer to context information (LAN_ADAPTER)
673 * NdisPacket = Pointer to NDIS packet to send
674 * Offset = Offset in packet where data starts
675 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
676 * Type = LAN protocol type (LAN_PROTO_*)
679 NDIS_STATUS NdisStatus
;
683 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
685 PNDIS_PACKET XmitPacket
;
686 PIP_INTERFACE Interface
= Adapter
->Context
;
688 TI_DbgPrint(DEBUG_DATALINK
,
689 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
690 NdisPacket
, Offset
, Adapter
));
692 if (Adapter
->State
!= LAN_STATE_STARTED
) {
693 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
697 TI_DbgPrint(DEBUG_DATALINK
,
698 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
699 Adapter
->HWAddress
[0] & 0xff,
700 Adapter
->HWAddress
[1] & 0xff,
701 Adapter
->HWAddress
[2] & 0xff,
702 Adapter
->HWAddress
[3] & 0xff,
703 Adapter
->HWAddress
[4] & 0xff,
704 Adapter
->HWAddress
[5] & 0xff));
706 GetDataPtr( NdisPacket
, 0, &OldData
, &OldSize
);
708 NdisStatus
= AllocatePacketWithBuffer(&XmitPacket
, NULL
, OldSize
+ Adapter
->HeaderSize
);
709 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
710 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_RESOURCES
);
714 GetDataPtr(XmitPacket
, 0, &Data
, &Size
);
716 RtlCopyMemory(Data
+ Adapter
->HeaderSize
, OldData
, OldSize
);
718 (*PC(NdisPacket
)->DLComplete
)(PC(NdisPacket
)->Context
, NdisPacket
, NDIS_STATUS_SUCCESS
);
720 switch (Adapter
->Media
) {
721 case NdisMedium802_3
:
722 EHeader
= (PETH_HEADER
)Data
;
725 /* Unicast address */
726 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
728 /* Broadcast address */
729 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
732 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
736 EHeader
->EType
= ETYPE_IPv4
;
739 EHeader
->EType
= ETYPE_ARP
;
742 EHeader
->EType
= ETYPE_IPv6
;
751 /* FIXME: Support other medias */
755 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
759 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
760 ((PCHAR
)LinkAddress
)[0] & 0xff,
761 ((PCHAR
)LinkAddress
)[1] & 0xff,
762 ((PCHAR
)LinkAddress
)[2] & 0xff,
763 ((PCHAR
)LinkAddress
)[3] & 0xff,
764 ((PCHAR
)LinkAddress
)[4] & 0xff,
765 ((PCHAR
)LinkAddress
)[5] & 0xff));
768 if (Adapter
->MTU
< Size
) {
769 /* This is NOT a pointer. MSDN explicitly says so. */
770 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket
,
771 TcpLargeSendPacketInfo
) = (PVOID
)((ULONG_PTR
)Adapter
->MTU
);
774 /* Update interface stats */
775 Interface
->Stats
.OutBytes
+= Size
;
777 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
778 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
779 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, XmitPacket
);
780 TI_DbgPrint(MID_TRACE
, ("NdisSend %s\n",
781 NdisStatus
== NDIS_STATUS_PENDING
?
782 "Pending" : "Complete"));
783 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
785 /* I had a talk with vizzini: these really ought to be here.
786 * we're supposed to see these completed by ndis *only* when
787 * status_pending is returned. Note that this is different from
788 * the situation with IRPs. */
789 if (NdisStatus
!= NDIS_STATUS_PENDING
)
790 ProtocolSendComplete((NDIS_HANDLE
)Context
, XmitPacket
, NdisStatus
);
794 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
795 OBJECT_ATTRIBUTES Attributes
;
798 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
799 Status
= ZwOpenKey(RegHandle
, KEY_ALL_ACCESS
, &Attributes
);
803 static NTSTATUS
ReadStringFromRegistry( HANDLE RegHandle
,
804 PWCHAR RegistryValue
,
805 PUNICODE_STRING String
) {
806 UNICODE_STRING ValueName
;
807 UNICODE_STRING UnicodeString
;
811 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
813 RtlInitUnicodeString(&ValueName
, RegistryValue
);
815 ZwQueryValueKey(RegHandle
,
817 KeyValuePartialInformation
,
822 if (!NT_SUCCESS(Status
))
824 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
825 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
827 UnicodeString
.Buffer
= (PWCHAR
)&Information
->Data
;
828 UnicodeString
.Length
= Information
->DataLength
- sizeof(WCHAR
);
829 UnicodeString
.MaximumLength
= Information
->DataLength
;
832 (PWCHAR
)ExAllocatePool( NonPagedPool
,
833 UnicodeString
.MaximumLength
+ sizeof(WCHAR
) );
835 if( !String
->Buffer
) return STATUS_NO_MEMORY
;
837 String
->MaximumLength
= UnicodeString
.MaximumLength
;
838 RtlCopyUnicodeString( String
, &UnicodeString
);
840 return STATUS_SUCCESS
;
844 * Utility to copy and append two unicode strings.
846 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
847 * IN PUNICODE_STRING Second -> Second string to append
848 * IN BOOL Deallocate -> TRUE: Deallocate First string before
854 NTSTATUS NTAPI
AppendUnicodeString(PUNICODE_STRING ResultFirst
,
855 PUNICODE_STRING Second
,
856 BOOLEAN Deallocate
) {
858 UNICODE_STRING Ustr
= *ResultFirst
;
859 PWSTR new_string
= ExAllocatePool
861 (ResultFirst
->Length
+ Second
->Length
+ sizeof(WCHAR
)));
863 return STATUS_NO_MEMORY
;
865 memcpy( new_string
, ResultFirst
->Buffer
, ResultFirst
->Length
);
866 memcpy( new_string
+ ResultFirst
->Length
/ sizeof(WCHAR
),
867 Second
->Buffer
, Second
->Length
);
868 if( Deallocate
) RtlFreeUnicodeString(ResultFirst
);
869 ResultFirst
->Length
= Ustr
.Length
+ Second
->Length
;
870 ResultFirst
->MaximumLength
= ResultFirst
->Length
;
871 new_string
[ResultFirst
->Length
/ sizeof(WCHAR
)] = 0;
872 Status
= RtlCreateUnicodeString(ResultFirst
,new_string
) ?
873 STATUS_SUCCESS
: STATUS_NO_MEMORY
;
874 ExFreePool(new_string
);
878 static NTSTATUS
CheckForDeviceDesc( PUNICODE_STRING EnumKeyName
,
879 PUNICODE_STRING TargetKeyName
,
880 PUNICODE_STRING Name
,
881 PUNICODE_STRING DeviceDesc
) {
882 UNICODE_STRING RootDevice
= { 0, 0, NULL
}, LinkageKeyName
= { 0, 0, NULL
};
883 UNICODE_STRING DescKeyName
= { 0, 0, NULL
}, Linkage
= { 0, 0, NULL
};
884 UNICODE_STRING BackSlash
= { 0, 0, NULL
};
885 HANDLE DescKey
= NULL
, LinkageKey
= NULL
;
888 TI_DbgPrint(DEBUG_DATALINK
,("EnumKeyName %wZ\n", EnumKeyName
));
890 RtlInitUnicodeString(&BackSlash
, L
"\\");
891 RtlInitUnicodeString(&Linkage
, L
"\\Linkage");
893 RtlInitUnicodeString(&DescKeyName
, L
"");
894 AppendUnicodeString( &DescKeyName
, EnumKeyName
, FALSE
);
895 AppendUnicodeString( &DescKeyName
, &BackSlash
, TRUE
);
896 AppendUnicodeString( &DescKeyName
, TargetKeyName
, TRUE
);
898 RtlInitUnicodeString(&LinkageKeyName
, L
"");
899 AppendUnicodeString( &LinkageKeyName
, &DescKeyName
, FALSE
);
900 AppendUnicodeString( &LinkageKeyName
, &Linkage
, TRUE
);
902 Status
= OpenRegistryKey( &LinkageKeyName
, &LinkageKey
);
903 if( !NT_SUCCESS(Status
) ) goto cleanup
;
905 Status
= ReadStringFromRegistry( LinkageKey
, L
"RootDevice", &RootDevice
);
906 if( !NT_SUCCESS(Status
) ) goto cleanup
;
908 if( RtlCompareUnicodeString( &RootDevice
, Name
, TRUE
) == 0 ) {
909 Status
= OpenRegistryKey( &DescKeyName
, &DescKey
);
910 if( !NT_SUCCESS(Status
) ) goto cleanup
;
912 Status
= ReadStringFromRegistry( DescKey
, L
"DriverDesc", DeviceDesc
);
913 if( !NT_SUCCESS(Status
) ) goto cleanup
;
915 TI_DbgPrint(DEBUG_DATALINK
,("ADAPTER DESC: %wZ\n", DeviceDesc
));
916 } else Status
= STATUS_UNSUCCESSFUL
;
919 RtlFreeUnicodeString( &RootDevice
);
920 RtlFreeUnicodeString( &LinkageKeyName
);
921 RtlFreeUnicodeString( &DescKeyName
);
922 if( LinkageKey
) NtClose( LinkageKey
);
923 if( DescKey
) NtClose( DescKey
);
925 TI_DbgPrint(DEBUG_DATALINK
,("Returning %x\n", Status
));
930 static NTSTATUS
FindDeviceDescForAdapter( PUNICODE_STRING Name
,
931 PUNICODE_STRING DeviceDesc
) {
932 UNICODE_STRING EnumKeyName
, TargetKeyName
;
936 KEY_BASIC_INFORMATION
*Kbio
=
937 ExAllocatePool(NonPagedPool
, sizeof(KEY_BASIC_INFORMATION
));
938 ULONG KbioLength
= sizeof(KEY_BASIC_INFORMATION
), ResultLength
;
940 RtlInitUnicodeString( DeviceDesc
, NULL
);
942 if( !Kbio
) return STATUS_INSUFFICIENT_RESOURCES
;
945 (&EnumKeyName
, CCS_ROOT L
"\\Control\\Class\\" TCPIP_GUID
);
947 Status
= OpenRegistryKey( &EnumKeyName
, &EnumKey
);
949 if( !NT_SUCCESS(Status
) ) {
950 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't open Enum key %wZ: %x\n",
951 &EnumKeyName
, Status
));
956 for( i
= 0; NT_SUCCESS(Status
); i
++ ) {
957 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
958 Kbio
, KbioLength
, &ResultLength
);
960 if( Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) {
962 KbioLength
= ResultLength
;
963 Kbio
= ExAllocatePool( NonPagedPool
, KbioLength
);
965 TI_DbgPrint(DEBUG_DATALINK
,("Failed to allocate memory\n"));
967 return STATUS_NO_MEMORY
;
970 Status
= ZwEnumerateKey( EnumKey
, i
, KeyBasicInformation
,
971 Kbio
, KbioLength
, &ResultLength
);
973 if( !NT_SUCCESS(Status
) ) {
974 TI_DbgPrint(DEBUG_DATALINK
,("Couldn't enum key child %d\n", i
));
981 if( NT_SUCCESS(Status
) ) {
982 TargetKeyName
.Length
= TargetKeyName
.MaximumLength
=
984 TargetKeyName
.Buffer
= Kbio
->Name
;
986 Status
= CheckForDeviceDesc
987 ( &EnumKeyName
, &TargetKeyName
, Name
, DeviceDesc
);
988 if( NT_SUCCESS(Status
) ) {
992 } else Status
= STATUS_SUCCESS
;
998 return STATUS_UNSUCCESSFUL
;
1001 VOID
GetName( PUNICODE_STRING RegistryKey
,
1002 PUNICODE_STRING OutName
) {
1004 UNICODE_STRING PartialRegistryKey
;
1006 PartialRegistryKey
.Buffer
=
1007 RegistryKey
->Buffer
+ wcslen(CCS_ROOT L
"\\Services\\");
1008 Ptr
= PartialRegistryKey
.Buffer
;
1010 while( *Ptr
!= L
'\\' &&
1011 ((PCHAR
)Ptr
) < ((PCHAR
)RegistryKey
->Buffer
) + RegistryKey
->Length
)
1014 PartialRegistryKey
.Length
= PartialRegistryKey
.MaximumLength
=
1015 (Ptr
- PartialRegistryKey
.Buffer
) * sizeof(WCHAR
);
1017 RtlInitUnicodeString( OutName
, L
"" );
1018 AppendUnicodeString( OutName
, &PartialRegistryKey
, FALSE
);
1021 BOOLEAN
BindAdapter(
1022 PLAN_ADAPTER Adapter
,
1023 PNDIS_STRING RegistryPath
)
1025 * FUNCTION: Binds a LAN adapter to IP layer
1027 * Adapter = Pointer to LAN_ADAPTER structure
1029 * We set the lookahead buffer size, set the packet filter and
1030 * bind the adapter to IP layer
1034 NDIS_STATUS NdisStatus
;
1035 LLIP_BIND_INFO BindInfo
;
1036 IP_ADDRESS DefaultMask
, Router
;
1037 ULONG Lookahead
= LOOKAHEAD_SIZE
, Unused
;
1039 OBJECT_ATTRIBUTES ObjectAttributes
;
1040 HANDLE ParameterHandle
;
1041 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo
;
1043 UNICODE_STRING IPAddress
= RTL_CONSTANT_STRING(L
"IPAddress");
1044 UNICODE_STRING Netmask
= RTL_CONSTANT_STRING(L
"SubnetMask");
1045 UNICODE_STRING Gateway
= RTL_CONSTANT_STRING(L
"DefaultGateway");
1046 UNICODE_STRING EnableDhcp
= RTL_CONSTANT_STRING(L
"EnableDHCP");
1047 UNICODE_STRING Prefix
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
1048 UNICODE_STRING TcpipRegistryPath
;
1049 UNICODE_STRING RegistryDataU
;
1050 ANSI_STRING RegistryDataA
;
1052 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1054 Adapter
->State
= LAN_STATE_OPENING
;
1056 NdisStatus
= NDISCall(Adapter
,
1057 NdisRequestSetInformation
,
1058 OID_GEN_CURRENT_LOOKAHEAD
,
1061 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1062 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
1066 /* Bind the adapter to IP layer */
1067 BindInfo
.Context
= Adapter
;
1068 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
1069 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
1070 BindInfo
.MTU
= Adapter
->MTU
;
1071 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
1072 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
1073 BindInfo
.Transmit
= LANTransmit
;
1075 IF
= IPCreateInterface(&BindInfo
);
1078 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1083 * Query per-adapter configuration from the registry
1084 * In case anyone is curious: there *is* an Ndis configuration api
1085 * for this sort of thing, but it doesn't really support things like
1086 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1087 * protocol drivers developed for win2k and above just use the native
1088 * services (ZwOpenKey, etc).
1091 GetName( RegistryPath
, &IF
->Name
);
1093 Status
= FindDeviceDescForAdapter( &IF
->Name
, &IF
->Description
);
1094 if (!NT_SUCCESS(Status
)) {
1095 TI_DbgPrint(MIN_TRACE
, ("Failed to get device description.\n"));
1096 IPDestroyInterface(IF
);
1100 TI_DbgPrint(DEBUG_DATALINK
,("Adapter Description: %wZ\n",
1103 TcpipRegistryPath
.MaximumLength
= sizeof(WCHAR
) * 150;
1104 TcpipRegistryPath
.Length
= 0;
1105 TcpipRegistryPath
.Buffer
= Buffer
;
1107 RtlAppendUnicodeStringToString(&TcpipRegistryPath
,
1110 RtlAppendUnicodeStringToString(&TcpipRegistryPath
,
1113 InitializeObjectAttributes(&ObjectAttributes
,
1115 OBJ_CASE_INSENSITIVE
,
1119 AddrInitIPv4(&DefaultMask
, 0);
1121 Status
= ZwOpenKey(&ParameterHandle
, KEY_READ
, &ObjectAttributes
);
1123 if (!NT_SUCCESS(Status
))
1125 IF
->Unicast
= DefaultMask
;
1126 IF
->Netmask
= DefaultMask
;
1130 KeyValueInfo
= ExAllocatePool(PagedPool
, sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
));
1133 ZwClose(ParameterHandle
);
1134 IPDestroyInterface(IF
);
1138 Status
= ZwQueryValueKey(ParameterHandle
,
1140 KeyValuePartialInformation
,
1142 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
),
1144 if (NT_SUCCESS(Status
) && KeyValueInfo
->DataLength
== sizeof(ULONG
) && (*(PULONG
)KeyValueInfo
->Data
) == 0)
1146 RegistryDataU
.MaximumLength
= 16 + sizeof(WCHAR
);
1147 RegistryDataU
.Buffer
= (PWCHAR
)KeyValueInfo
->Data
;
1149 Status
= ZwQueryValueKey(ParameterHandle
,
1151 KeyValuePartialInformation
,
1153 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1155 if (NT_SUCCESS(Status
))
1157 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1159 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1163 AddrInitIPv4(&IF
->Unicast
, inet_addr(RegistryDataA
.Buffer
));
1165 RtlFreeAnsiString(&RegistryDataA
);
1170 IF
->Unicast
= DefaultMask
;
1173 Status
= ZwQueryValueKey(ParameterHandle
,
1175 KeyValuePartialInformation
,
1177 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1179 if (NT_SUCCESS(Status
))
1181 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1183 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1187 AddrInitIPv4(&IF
->Netmask
, inet_addr(RegistryDataA
.Buffer
));
1189 RtlFreeAnsiString(&RegistryDataA
);
1193 IF
->Netmask
= DefaultMask
;
1196 Status
= ZwQueryValueKey(ParameterHandle
,
1198 KeyValuePartialInformation
,
1200 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 16 * sizeof(WCHAR
),
1202 if (NT_SUCCESS(Status
))
1204 RegistryDataU
.Length
= KeyValueInfo
->DataLength
;
1206 RtlUnicodeStringToAnsiString(&RegistryDataA
,
1210 AddrInitIPv4(&Router
, inet_addr(RegistryDataA
.Buffer
));
1212 RtlFreeAnsiString(&RegistryDataA
);
1214 if (!AddrIsUnspecified(&Router
)) RouterCreateRoute(&DefaultMask
, &DefaultMask
, &Router
, IF
, 1);
1219 IF
->Unicast
= DefaultMask
;
1220 IF
->Netmask
= DefaultMask
;
1223 ZwClose(ParameterHandle
);
1226 IF
->Broadcast
.Type
= IP_ADDRESS_V4
;
1227 IF
->Broadcast
.Address
.IPv4Address
=
1228 IF
->Unicast
.Address
.IPv4Address
|
1229 ~IF
->Netmask
.Address
.IPv4Address
;
1231 TI_DbgPrint(DEBUG_DATALINK
,("BCAST(IF) %s\n", A2S(&IF
->Broadcast
)));
1233 /* Get maximum link speed */
1234 NdisStatus
= NDISCall(Adapter
,
1235 NdisRequestQueryInformation
,
1240 if( !NT_SUCCESS(NdisStatus
) )
1241 IF
->Speed
= IP_DEFAULT_LINK_SPEED
;
1243 /* Register interface with IP layer */
1244 IPRegisterInterface(IF
);
1246 /* Set packet filter so we can send and receive packets */
1247 NdisStatus
= NDISCall(Adapter
,
1248 NdisRequestSetInformation
,
1249 OID_GEN_CURRENT_PACKET_FILTER
,
1250 &Adapter
->PacketFilter
,
1253 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1254 TI_DbgPrint(DEBUG_DATALINK
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
1255 IPUnregisterInterface(IF
);
1256 IPDestroyInterface(IF
);
1260 Adapter
->Context
= IF
;
1261 Adapter
->State
= LAN_STATE_STARTED
;
1267 PLAN_ADAPTER Adapter
)
1269 * FUNCTION: Unbinds a LAN adapter from IP layer
1271 * Adapter = Pointer to LAN_ADAPTER structure
1274 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1276 if (Adapter
->State
== LAN_STATE_STARTED
) {
1277 PIP_INTERFACE IF
= Adapter
->Context
;
1279 IPUnregisterInterface(IF
);
1281 IPDestroyInterface(IF
);
1286 NDIS_STATUS
LANRegisterAdapter(
1287 PNDIS_STRING AdapterName
,
1288 PNDIS_STRING RegistryPath
)
1290 * FUNCTION: Registers protocol with an NDIS adapter
1292 * AdapterName = Pointer to string with name of adapter to register
1293 * Adapter = Address of pointer to a LAN_ADAPTER structure
1295 * Status of operation
1299 NDIS_STATUS NdisStatus
;
1300 NDIS_STATUS OpenStatus
;
1302 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
1306 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1308 IF
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(LAN_ADAPTER
), LAN_ADAPTER_TAG
);
1310 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
1311 return NDIS_STATUS_RESOURCES
;
1314 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
1316 /* Put adapter in stopped state */
1317 IF
->State
= LAN_STATE_STOPPED
;
1319 /* Initialize protecting spin lock */
1320 KeInitializeSpinLock(&IF
->Lock
);
1322 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
1324 /* Initialize array with media IDs we support */
1325 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
1327 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
1328 /* Open the adapter. */
1329 NdisOpenAdapter(&NdisStatus
,
1341 /* Wait until the adapter is opened */
1342 if (NdisStatus
== NDIS_STATUS_PENDING
)
1343 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1344 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1345 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ\n", AdapterName
));
1346 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1350 IF
->Media
= MediaArray
[MediaIndex
];
1352 /* Fill LAN_ADAPTER structure with some adapter specific information */
1353 switch (IF
->Media
) {
1354 case NdisMedium802_3
:
1355 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
1356 IF
->BCastMask
= BCAST_ETH_MASK
;
1357 IF
->BCastCheck
= BCAST_ETH_CHECK
;
1358 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
1359 IF
->HeaderSize
= sizeof(ETH_HEADER
);
1360 IF
->MinFrameSize
= 60;
1361 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
1363 NDIS_PACKET_TYPE_BROADCAST
|
1364 NDIS_PACKET_TYPE_DIRECTED
|
1365 NDIS_PACKET_TYPE_MULTICAST
;
1369 /* Unsupported media */
1370 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
1371 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1372 return NDIS_STATUS_NOT_SUPPORTED
;
1375 /* Get maximum frame size */
1376 NdisStatus
= NDISCall(IF
,
1377 NdisRequestQueryInformation
,
1378 OID_GEN_MAXIMUM_FRAME_SIZE
,
1381 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1382 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (NDISCall)\n", AdapterName
));
1383 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1387 /* Get maximum packet size */
1388 NdisStatus
= NDISCall(IF
,
1389 NdisRequestQueryInformation
,
1390 OID_GEN_MAXIMUM_TOTAL_SIZE
,
1393 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1394 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
1395 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1399 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1400 NdisStatus
= NDISCall(IF
,
1401 NdisRequestQueryInformation
,
1402 OID_GEN_MAXIMUM_SEND_PACKETS
,
1403 &IF
->MaxSendPackets
,
1405 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1406 /* Legacy NIC drivers may not support this query, if it fails we
1407 assume it can send at least one packet per call to NdisSend(Packets) */
1408 IF
->MaxSendPackets
= 1;
1410 /* Get current hardware address */
1411 NdisStatus
= NDISCall(IF
,
1412 NdisRequestQueryInformation
,
1415 IF
->HWAddressLength
);
1416 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1417 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
1418 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1422 /* Get maximum link speed */
1423 NdisStatus
= NDISCall(IF
,
1424 NdisRequestQueryInformation
,
1428 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
1429 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
1430 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1434 /* Convert returned link speed to bps (it is in 100bps increments) */
1435 IF
->Speed
= Speed
* 100L;
1437 /* Bind adapter to IP layer */
1438 if( !BindAdapter(IF
, RegistryPath
) ) {
1439 TI_DbgPrint(DEBUG_DATALINK
,("denying adapter %wZ (BindAdapter)\n", AdapterName
));
1440 ExFreePoolWithTag(IF
, LAN_ADAPTER_TAG
);
1441 return NDIS_STATUS_NOT_ACCEPTED
;
1444 /* Add adapter to the adapter list */
1445 ExInterlockedInsertTailList(&AdapterListHead
,
1449 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
1451 return NDIS_STATUS_SUCCESS
;
1455 NDIS_STATUS
LANUnregisterAdapter(
1456 PLAN_ADAPTER Adapter
)
1458 * FUNCTION: Unregisters protocol with NDIS adapter
1460 * Adapter = Pointer to a LAN_ADAPTER structure
1462 * Status of operation
1466 NDIS_HANDLE NdisHandle
;
1467 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
1469 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1471 /* Unlink the adapter from the list */
1472 RemoveEntryList(&Adapter
->ListEntry
);
1474 /* Unbind adapter from IP layer */
1475 UnbindAdapter(Adapter
);
1477 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
1478 NdisHandle
= Adapter
->NdisHandle
;
1480 Adapter
->NdisHandle
= NULL
;
1481 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1483 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
1484 if (NdisStatus
== NDIS_STATUS_PENDING
) {
1485 TcpipWaitForSingleObject(&Adapter
->Event
,
1490 NdisStatus
= Adapter
->NdisStatus
;
1493 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
1495 FreeAdapter(Adapter
);
1502 LANUnregisterProtocol(VOID
)
1504 * FUNCTION: Unregisters this protocol driver with NDIS
1505 * NOTES: Does not care wether we are already registered
1508 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1510 if (ProtocolRegistered
) {
1511 NDIS_STATUS NdisStatus
;
1512 PLIST_ENTRY CurrentEntry
;
1513 PLIST_ENTRY NextEntry
;
1514 PLAN_ADAPTER Current
;
1517 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1519 /* Search the list and remove every adapter we find */
1520 CurrentEntry
= AdapterListHead
.Flink
;
1521 while (CurrentEntry
!= &AdapterListHead
) {
1522 NextEntry
= CurrentEntry
->Flink
;
1523 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1525 LANUnregisterAdapter(Current
);
1526 CurrentEntry
= NextEntry
;
1529 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1531 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1532 ProtocolRegistered
= FALSE
;
1538 ProtocolUnbindAdapter(
1539 PNDIS_STATUS Status
,
1540 NDIS_HANDLE ProtocolBindingContext
,
1541 NDIS_HANDLE UnbindContext
)
1543 /* We don't pend any unbinding so we can just ignore UnbindContext */
1544 *Status
= LANUnregisterAdapter((PLAN_ADAPTER
)ProtocolBindingContext
);
1547 NTSTATUS
LANRegisterProtocol(
1550 * FUNCTION: Registers this protocol driver with NDIS
1552 * Name = Name of this protocol driver
1554 * Status of operation
1557 NDIS_STATUS NdisStatus
;
1558 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1560 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1562 InitializeListHead(&AdapterListHead
);
1563 KeInitializeSpinLock(&AdapterListLock
);
1565 /* Set up protocol characteristics */
1566 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1567 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1568 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1569 ProtChars
.Name
.Length
= Name
->Length
;
1570 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1571 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1572 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1573 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1574 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1575 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1576 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1577 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1578 ProtChars
.ReceivePacketHandler
= ProtocolReceivePacket
;
1579 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1580 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1581 ProtChars
.StatusHandler
= ProtocolStatus
;
1582 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1583 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1584 ProtChars
.PnPEventHandler
= ProtocolPnPEvent
;
1585 ProtChars
.UnbindAdapterHandler
= ProtocolUnbindAdapter
;
1586 ProtChars
.UnloadHandler
= LANUnregisterProtocol
;
1588 /* Try to register protocol */
1589 NdisRegisterProtocol(&NdisStatus
,
1590 &NdisProtocolHandle
,
1592 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1593 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1595 TI_DbgPrint(DEBUG_DATALINK
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1596 return (NTSTATUS
)NdisStatus
;
1599 ProtocolRegistered
= TRUE
;
1601 return STATUS_SUCCESS
;