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 typedef struct _LAN_WQ_ITEM
{
17 UINT BytesTransferred
;
18 } LAN_WQ_ITEM
, *PLAN_WQ_ITEM
;
20 NDIS_HANDLE NdisProtocolHandle
= (NDIS_HANDLE
)NULL
;
21 BOOLEAN ProtocolRegistered
= FALSE
;
22 LIST_ENTRY AdapterListHead
;
23 KSPIN_LOCK AdapterListLock
;
25 /* Work around being called back into afd at Dpc level */
26 KSPIN_LOCK LanWorkLock
;
27 LIST_ENTRY LanWorkList
;
28 WORK_QUEUE_ITEM LanWorkItem
;
32 NDIS_REQUEST_TYPE Type
,
37 * FUNCTION: Send a request to NDIS
39 * Adapter = Pointer to a LAN_ADAPTER structure
40 * Type = Type of request (Set or Query)
41 * OID = Value to be set/queried for
42 * Buffer = Pointer to a buffer to use
43 * Length = Number of bytes in Buffer
49 NDIS_STATUS NdisStatus
;
51 Request
.RequestType
= Type
;
52 if (Type
== NdisRequestSetInformation
) {
53 Request
.DATA
.SET_INFORMATION
.Oid
= OID
;
54 Request
.DATA
.SET_INFORMATION
.InformationBuffer
= Buffer
;
55 Request
.DATA
.SET_INFORMATION
.InformationBufferLength
= Length
;
57 Request
.DATA
.QUERY_INFORMATION
.Oid
= OID
;
58 Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= Buffer
;
59 Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= Length
;
62 if (Adapter
->State
!= LAN_STATE_RESETTING
) {
63 NdisRequest(&NdisStatus
, Adapter
->NdisHandle
, &Request
);
65 NdisStatus
= NDIS_STATUS_NOT_ACCEPTED
;
68 /* Wait for NDIS to complete the request */
69 if (NdisStatus
== NDIS_STATUS_PENDING
) {
70 KeWaitForSingleObject(&Adapter
->Event
,
75 NdisStatus
= Adapter
->NdisStatus
;
85 * FUNCTION: Frees memory for a LAN_ADAPTER structure
87 * Adapter = Pointer to LAN_ADAPTER structure to free
94 VOID STDCALL
ProtocolOpenAdapterComplete(
95 NDIS_HANDLE BindingContext
,
97 NDIS_STATUS OpenErrorStatus
)
99 * FUNCTION: Called by NDIS to complete opening of an adapter
101 * BindingContext = Pointer to a device context (LAN_ADAPTER)
102 * Status = Status of the operation
103 * OpenErrorStatus = Additional status information
106 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
108 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
110 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
114 VOID STDCALL
ProtocolCloseAdapterComplete(
115 NDIS_HANDLE BindingContext
,
118 * FUNCTION: Called by NDIS to complete closing an adapter
120 * BindingContext = Pointer to a device context (LAN_ADAPTER)
121 * Status = Status of the operation
124 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
126 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
128 Adapter
->NdisStatus
= Status
;
130 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
134 VOID STDCALL
ProtocolResetComplete(
135 NDIS_HANDLE BindingContext
,
138 * FUNCTION: Called by NDIS to complete resetting an adapter
140 * BindingContext = Pointer to a device context (LAN_ADAPTER)
141 * Status = Status of the operation
144 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
148 VOID STDCALL
ProtocolRequestComplete(
149 NDIS_HANDLE BindingContext
,
150 PNDIS_REQUEST NdisRequest
,
153 * FUNCTION: Called by NDIS to complete a request
155 * BindingContext = Pointer to a device context (LAN_ADAPTER)
156 * NdisRequest = Pointer to an object describing the request
157 * Status = Status of the operation
160 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
162 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
164 /* Save status of request and signal an event */
165 Adapter
->NdisStatus
= Status
;
167 KeSetEvent(&Adapter
->Event
, 0, FALSE
);
171 VOID STDCALL
ProtocolSendComplete(
172 NDIS_HANDLE BindingContext
,
176 * FUNCTION: Called by NDIS to complete sending process
178 * BindingContext = Pointer to a device context (LAN_ADAPTER)
179 * Packet = Pointer to a packet descriptor
180 * Status = Status of the operation
183 TI_DbgPrint(DEBUG_DATALINK
, ("Calling completion routine\n"));
184 ASSERT_KM_POINTER(Packet
);
185 ASSERT_KM_POINTER(PC(Packet
));
186 ASSERT_KM_POINTER(PC(Packet
)->DLComplete
);
187 (*PC(Packet
)->DLComplete
)( PC(Packet
)->Context
, Packet
, Status
);
188 TI_DbgPrint(DEBUG_DATALINK
, ("Finished\n"));
191 VOID STDCALL
LanReceiveWorker( PVOID Context
) {
193 PLIST_ENTRY ListEntry
;
194 PLAN_WQ_ITEM WorkItem
;
196 PLAN_ADAPTER Adapter
;
197 UINT BytesTransferred
;
198 PNDIS_BUFFER NdisBuffer
;
202 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
205 ExInterlockedRemoveHeadList( &LanWorkList
, &LanWorkLock
)) ) {
206 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
208 Packet
= WorkItem
->Packet
;
209 Adapter
= WorkItem
->Adapter
;
210 BytesTransferred
= WorkItem
->BytesTransferred
;
212 ExFreePool( WorkItem
);
214 IPPacket
.NdisPacket
= Packet
;
216 NdisGetFirstBufferFromPacket(Packet
,
219 &IPPacket
.ContigSize
,
220 &IPPacket
.TotalSize
);
222 IPPacket
.ContigSize
= IPPacket
.TotalSize
= BytesTransferred
;
223 /* Determine which upper layer protocol that should receive
224 this packet and pass it to the correct receive handler */
226 TI_DbgPrint(MID_TRACE
,
227 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
228 IPPacket
.ContigSize
, IPPacket
.TotalSize
,
231 /*OskitDumpBuffer( IPPacket.Header, IPPacket.TotalSize );*/
233 PacketType
= PC(IPPacket
.NdisPacket
)->PacketType
;
234 IPPacket
.Position
= 0;
238 ("Ether Type = %x ContigSize = %d Total = %d\n",
239 PacketType
, IPPacket
.ContigSize
, IPPacket
.TotalSize
));
241 switch (PacketType
) {
244 TI_DbgPrint(MID_TRACE
,("Received IP Packet\n"));
245 IPReceive(Adapter
->Context
, &IPPacket
);
248 TI_DbgPrint(MID_TRACE
,("Received ARP Packet\n"));
249 ARPReceive(Adapter
->Context
, &IPPacket
);
254 FreeNdisPacket( Packet
);
258 VOID STDCALL
ProtocolTransferDataComplete(
259 NDIS_HANDLE BindingContext
,
262 UINT BytesTransferred
)
264 * FUNCTION: Called by NDIS to complete reception of data
266 * BindingContext = Pointer to a device context (LAN_ADAPTER)
267 * Packet = Pointer to a packet descriptor
268 * Status = Status of the operation
269 * BytesTransferred = Number of bytes transferred
271 * If the packet was successfully received, determine the protocol
272 * type and pass it to the correct receive handler
277 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
279 if( Status
!= NDIS_STATUS_SUCCESS
) return;
280 WQItem
= ExAllocatePool( NonPagedPool
, sizeof(LAN_WQ_ITEM
) );
281 if( !WQItem
) return;
283 TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock
);
284 WorkStart
= IsListEmpty( &LanWorkList
);
285 WQItem
->Packet
= Packet
;
286 WQItem
->Adapter
= Adapter
;
287 WQItem
->BytesTransferred
= BytesTransferred
;
288 InsertTailList( &LanWorkList
, &WQItem
->ListEntry
);
290 ExQueueWorkItem( &LanWorkItem
, CriticalWorkQueue
);
291 TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock
);
294 NDIS_STATUS STDCALL
ProtocolReceive(
295 NDIS_HANDLE BindingContext
,
296 NDIS_HANDLE MacReceiveContext
,
298 UINT HeaderBufferSize
,
299 PVOID LookaheadBuffer
,
300 UINT LookaheadBufferSize
,
303 * FUNCTION: Called by NDIS when a packet has been received on the physical link
305 * BindingContext = Pointer to a device context (LAN_ADAPTER)
306 * MacReceiveContext = Handle used by underlying NIC driver
307 * HeaderBuffer = Pointer to a buffer containing the packet header
308 * HeaderBufferSize = Number of bytes in HeaderBuffer
309 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
310 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
311 * PacketSize = Overall size of the packet (not including header)
313 * Status of operation
317 UINT PacketType
, BytesTransferred
;
321 NDIS_STATUS NdisStatus
;
322 PNDIS_PACKET NdisPacket
;
323 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)BindingContext
;
324 PETH_HEADER EHeader
= (PETH_HEADER
)HeaderBuffer
;
326 TI_DbgPrint(DEBUG_DATALINK
, ("Called. (packetsize %d)\n",PacketSize
));
328 if (Adapter
->State
!= LAN_STATE_STARTED
) {
329 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter is stopped.\n"));
330 return NDIS_STATUS_NOT_ACCEPTED
;
333 if (HeaderBufferSize
< Adapter
->HeaderSize
) {
334 TI_DbgPrint(DEBUG_DATALINK
, ("Runt frame received.\n"));
335 return NDIS_STATUS_NOT_ACCEPTED
;
338 if (Adapter
->Media
== NdisMedium802_3
) {
339 /* Ethernet and IEEE 802.3 frames can be destinguished by
340 looking at the IEEE 802.3 length field. This field is
341 less than or equal to 1500 for a valid IEEE 802.3 frame
342 and larger than 1500 is it's a valid EtherType value.
343 See RFC 1122, section 2.3.3 for more information */
344 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
345 if (((EType
= EHeader
->EType
) != ETYPE_IPv4
) && (EType
!= ETYPE_ARP
)) {
346 TI_DbgPrint(DEBUG_DATALINK
, ("Not IP or ARP frame. EtherType (0x%X).\n", EType
));
347 return NDIS_STATUS_NOT_ACCEPTED
;
349 /* We use EtherType constants to destinguish packet types */
352 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
353 /* FIXME: Support other medias */
354 return NDIS_STATUS_NOT_ACCEPTED
;
357 /* Get a transfer data packet */
359 TI_DbgPrint(DEBUG_DATALINK
, ("Adapter: %x (MTU %d)\n",
360 Adapter
, Adapter
->MTU
));
362 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
,
363 PacketSize
+ HeaderBufferSize
);
364 if( NdisStatus
!= NDIS_STATUS_SUCCESS
) {
365 return NDIS_STATUS_NOT_ACCEPTED
;
368 PC(NdisPacket
)->PacketType
= PacketType
;
370 TI_DbgPrint(DEBUG_DATALINK
, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize
,PacketSize
));
372 GetDataPtr( NdisPacket
, 0, &BufferData
, &temp
);
374 IPPacket
.NdisPacket
= NdisPacket
;
375 IPPacket
.Position
= 0;
377 if (LookaheadBufferSize
== PacketSize
)
379 /* Optimized code path for packets that are fully contained in
380 * the lookahead buffer. */
381 NdisCopyLookaheadData(BufferData
,
384 Adapter
->MacOptions
);
388 if (NdisStatus
== NDIS_STATUS_SUCCESS
)
390 ASSERT(PacketSize
<= Adapter
->MTU
);
392 NdisTransferData(&NdisStatus
, Adapter
->NdisHandle
,
393 MacReceiveContext
, 0, PacketSize
,
394 NdisPacket
, &BytesTransferred
);
398 BytesTransferred
= 0;
401 TI_DbgPrint(DEBUG_DATALINK
, ("Calling complete\n"));
403 if (NdisStatus
!= NDIS_STATUS_PENDING
)
404 ProtocolTransferDataComplete(BindingContext
,
409 TI_DbgPrint(DEBUG_DATALINK
, ("leaving\n"));
411 return NDIS_STATUS_SUCCESS
;
415 VOID STDCALL
ProtocolReceiveComplete(
416 NDIS_HANDLE BindingContext
)
418 * FUNCTION: Called by NDIS when we're done receiving data
420 * BindingContext = Pointer to a device context (LAN_ADAPTER)
423 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
427 VOID STDCALL
ProtocolStatus(
428 NDIS_HANDLE BindingContext
,
429 NDIS_STATUS GenerelStatus
,
431 UINT StatusBufferSize
)
433 * FUNCTION: Called by NDIS when the underlying driver has changed state
435 * BindingContext = Pointer to a device context (LAN_ADAPTER)
436 * GenerelStatus = A generel status code
437 * StatusBuffer = Pointer to a buffer with medium-specific data
438 * StatusBufferSize = Number of bytes in StatusBuffer
441 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
445 VOID STDCALL
ProtocolStatusComplete(
446 NDIS_HANDLE NdisBindingContext
)
448 * FUNCTION: Called by NDIS when a status-change has occurred
450 * BindingContext = Pointer to a device context (LAN_ADAPTER)
453 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
456 VOID STDCALL
ProtocolBindAdapter(
457 OUT PNDIS_STATUS Status
,
458 IN NDIS_HANDLE BindContext
,
459 IN PNDIS_STRING DeviceName
,
460 IN PVOID SystemSpecific1
,
461 IN PVOID SystemSpecific2
)
463 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
464 * bindings, and periodically thereafer as new adapters come online
466 * Status: Return value to NDIS
467 * BindContext: Handle provided by NDIS to track pending binding operations
468 * DeviceName: Name of the miniport device to bind to
469 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
470 * SystemSpecific2: Unused & must not be touched
473 /* XXX confirm that this is still true, or re-word the following comment */
474 /* we get to ignore BindContext because we will never pend an operation with NDIS */
475 TI_DbgPrint(DEBUG_DATALINK
, ("Called with registry path %wZ for %wZ\n", SystemSpecific1
, DeviceName
));
476 *Status
= LANRegisterAdapter(DeviceName
, SystemSpecific1
);
482 PNDIS_PACKET NdisPacket
,
487 * FUNCTION: Transmits a packet
489 * Context = Pointer to context information (LAN_ADAPTER)
490 * NdisPacket = Pointer to NDIS packet to send
491 * Offset = Offset in packet where data starts
492 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
493 * Type = LAN protocol type (LAN_PROTO_*)
496 NDIS_STATUS NdisStatus
;
501 PLAN_ADAPTER Adapter
= (PLAN_ADAPTER
)Context
;
503 TI_DbgPrint(DEBUG_DATALINK
,
504 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
505 NdisPacket
, Offset
, Adapter
));
507 TI_DbgPrint(DEBUG_DATALINK
,
508 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
509 Adapter
->HWAddress
[0] & 0xff,
510 Adapter
->HWAddress
[1] & 0xff,
511 Adapter
->HWAddress
[2] & 0xff,
512 Adapter
->HWAddress
[3] & 0xff,
513 Adapter
->HWAddress
[4] & 0xff,
514 Adapter
->HWAddress
[5] & 0xff));
516 /* XXX arty -- Handled adjustment in a saner way than before ...
517 * not needed immediately */
518 GetDataPtr( NdisPacket
, 0, &Data
, &Size
);
520 if (Adapter
->State
== LAN_STATE_STARTED
) {
521 switch (Adapter
->Media
) {
522 case NdisMedium802_3
:
523 EHeader
= (PETH_HEADER
)Data
;
526 /* Unicast address */
527 RtlCopyMemory(EHeader
->DstAddr
, LinkAddress
, IEEE_802_ADDR_LENGTH
);
529 /* Broadcast address */
530 RtlFillMemory(EHeader
->DstAddr
, IEEE_802_ADDR_LENGTH
, 0xFF);
533 RtlCopyMemory(EHeader
->SrcAddr
, Adapter
->HWAddress
, IEEE_802_ADDR_LENGTH
);
537 EHeader
->EType
= ETYPE_IPv4
;
540 EHeader
->EType
= ETYPE_ARP
;
543 EHeader
->EType
= ETYPE_IPv6
;
547 /* Should not happen */
548 TI_DbgPrint(MIN_TRACE
, ("Unknown LAN protocol.\n"));
550 ProtocolSendComplete((NDIS_HANDLE
)Context
,
552 NDIS_STATUS_FAILURE
);
559 /* FIXME: Support other medias */
563 TI_DbgPrint( MID_TRACE
, ("LinkAddress: %x\n", LinkAddress
));
567 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
568 ((PCHAR
)LinkAddress
)[0] & 0xff,
569 ((PCHAR
)LinkAddress
)[1] & 0xff,
570 ((PCHAR
)LinkAddress
)[2] & 0xff,
571 ((PCHAR
)LinkAddress
)[3] & 0xff,
572 ((PCHAR
)LinkAddress
)[4] & 0xff,
573 ((PCHAR
)LinkAddress
)[5] & 0xff));
576 /*OskitDumpBuffer( Data, Size );*/
578 TcpipAcquireSpinLock( &Adapter
->Lock
, &OldIrql
);
579 TI_DbgPrint(MID_TRACE
, ("NdisSend\n"));
580 NdisSend(&NdisStatus
, Adapter
->NdisHandle
, NdisPacket
);
581 TI_DbgPrint(MID_TRACE
, ("NdisSend Done\n"));
582 TcpipReleaseSpinLock( &Adapter
->Lock
, OldIrql
);
584 if (NdisStatus
!= NDIS_STATUS_PENDING
)
585 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NdisStatus
);
587 ProtocolSendComplete((NDIS_HANDLE
)Context
, NdisPacket
, NDIS_STATUS_CLOSED
);
592 OpenRegistryKey( PNDIS_STRING RegistryPath
, PHANDLE RegHandle
) {
593 OBJECT_ATTRIBUTES Attributes
;
596 InitializeObjectAttributes(&Attributes
, RegistryPath
, OBJ_CASE_INSENSITIVE
, 0, 0);
597 Status
= ZwOpenKey(RegHandle
, GENERIC_READ
, &Attributes
);
601 static NTSTATUS
ReadIPAddressFromRegistry( HANDLE RegHandle
,
602 PWCHAR RegistryValue
,
603 PIP_ADDRESS
*Address
) {
604 UNICODE_STRING ValueName
;
605 UNICODE_STRING UnicodeAddress
;
609 PKEY_VALUE_PARTIAL_INFORMATION Information
= (PKEY_VALUE_PARTIAL_INFORMATION
)buf
;
610 ANSI_STRING AnsiAddress
;
613 RtlInitUnicodeString(&ValueName
, RegistryValue
);
615 ZwQueryValueKey(RegHandle
,
617 KeyValuePartialInformation
,
622 if (!NT_SUCCESS(Status
))
624 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
625 TI_DbgPrint(MIN_TRACE
, ("Information DataLength: 0x%x\n", Information
->DataLength
));
627 UnicodeAddress
.Buffer
= (PWCHAR
)&Information
->Data
;
628 UnicodeAddress
.Length
= Information
->DataLength
;
629 UnicodeAddress
.MaximumLength
= Information
->DataLength
;
631 AnsiLen
= RtlUnicodeStringToAnsiSize(&UnicodeAddress
);
633 return STATUS_NO_MEMORY
;
635 AnsiAddress
.Buffer
= exAllocatePoolWithTag(PagedPool
, AnsiLen
, 0x01020304);
636 if(!AnsiAddress
.Buffer
)
637 return STATUS_NO_MEMORY
;
639 AnsiAddress
.Length
= AnsiLen
;
640 AnsiAddress
.MaximumLength
= AnsiLen
;
642 Status
= RtlUnicodeStringToAnsiString(&AnsiAddress
, &UnicodeAddress
, FALSE
);
643 if (!NT_SUCCESS(Status
)) {
644 exFreePool(AnsiAddress
.Buffer
);
645 return STATUS_UNSUCCESSFUL
;
648 AnsiAddress
.Buffer
[AnsiAddress
.Length
] = 0;
649 *Address
= AddrBuildIPv4(inet_addr(AnsiAddress
.Buffer
));
651 exFreePool(AnsiAddress
.Buffer
);
652 return STATUS_UNSUCCESSFUL
;
655 return *Address
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
659 PLAN_ADAPTER Adapter
,
660 PNDIS_STRING RegistryPath
)
662 * FUNCTION: Binds a LAN adapter to IP layer
664 * Adapter = Pointer to LAN_ADAPTER structure
666 * We set the lookahead buffer size, set the packet filter and
667 * bind the adapter to IP layer
671 PIP_ADDRESS Address
= 0;
672 PIP_ADDRESS Netmask
= 0;
673 NDIS_STATUS NdisStatus
;
674 LLIP_BIND_INFO BindInfo
;
675 ULONG Lookahead
= LOOKAHEAD_SIZE
;
677 HANDLE RegHandle
= 0;
679 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
681 Adapter
->State
= LAN_STATE_OPENING
;
683 NdisStatus
= NDISCall(Adapter
,
684 NdisRequestSetInformation
,
685 OID_GEN_CURRENT_LOOKAHEAD
,
688 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
689 TI_DbgPrint(MID_TRACE
, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus
));
693 /* Bind the adapter to IP layer */
694 BindInfo
.Context
= Adapter
;
695 BindInfo
.HeaderSize
= Adapter
->HeaderSize
;
696 BindInfo
.MinFrameSize
= Adapter
->MinFrameSize
;
697 BindInfo
.MTU
= Adapter
->MTU
;
698 BindInfo
.Address
= (PUCHAR
)&Adapter
->HWAddress
;
699 BindInfo
.AddressLength
= Adapter
->HWAddressLength
;
700 BindInfo
.Transmit
= LANTransmit
;
702 IF
= IPCreateInterface(&BindInfo
);
705 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
710 * Query per-adapter configuration from the registry
711 * In case anyone is curious: there *is* an Ndis configuration api
712 * for this sort of thing, but it doesn't really support things like
713 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
714 * protocol drivers developed for win2k and above just use the native
715 * services (ZwOpenKey, etc).
718 Status
= OpenRegistryKey( RegistryPath
, &RegHandle
);
720 if(NT_SUCCESS(Status
))
721 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"IPAddress",
723 if(NT_SUCCESS(Status
))
724 Status
= ReadIPAddressFromRegistry( RegHandle
, L
"SubnetMask",
727 if(!NT_SUCCESS(Status
) || !Address
|| !Netmask
)
729 TI_DbgPrint(MIN_TRACE
, ("Unable to open protocol-specific registry key: 0x%x\n", Status
));
731 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
734 IPDestroyInterface(IF
);
740 ("--> Our IP address on this interface: '%s'\n",
745 ("--> Our net mask on this interface: '%s'\n",
748 /* Create a net table entry for this interface */
749 if (!IPCreateNTE(IF
, Address
, AddrCountPrefixBits(Netmask
))) {
750 TI_DbgPrint(MIN_TRACE
, ("IPCreateNTE() failed.\n"));
751 IPDestroyInterface(IF
);
755 /* Register interface with IP layer */
756 IPRegisterInterface(IF
);
758 /* Set packet filter so we can send and receive packets */
759 NdisStatus
= NDISCall(Adapter
,
760 NdisRequestSetInformation
,
761 OID_GEN_CURRENT_PACKET_FILTER
,
762 &Adapter
->PacketFilter
,
764 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
765 TI_DbgPrint(MID_TRACE
, ("Could not set packet filter (0x%X).\n", NdisStatus
));
766 IPDestroyInterface(IF
);
770 Adapter
->Context
= IF
;
771 Adapter
->State
= LAN_STATE_STARTED
;
776 PLAN_ADAPTER Adapter
)
778 * FUNCTION: Unbinds a LAN adapter from IP layer
780 * Adapter = Pointer to LAN_ADAPTER structure
783 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
785 if (Adapter
->State
== LAN_STATE_STARTED
) {
786 PIP_INTERFACE IF
= Adapter
->Context
;
788 IPUnregisterInterface(IF
);
790 IPDestroyInterface(IF
);
795 NDIS_STATUS
LANRegisterAdapter(
796 PNDIS_STRING AdapterName
,
797 PNDIS_STRING RegistryPath
)
799 * FUNCTION: Registers protocol with an NDIS adapter
801 * AdapterName = Pointer to string with name of adapter to register
802 * Adapter = Address of pointer to a LAN_ADAPTER structure
804 * Status of operation
808 NDIS_STATUS NdisStatus
;
809 NDIS_STATUS OpenStatus
;
811 NDIS_MEDIUM MediaArray
[MAX_MEDIA
];
815 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
817 IF
= exAllocatePool(NonPagedPool
, sizeof(LAN_ADAPTER
));
819 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
820 return NDIS_STATUS_RESOURCES
;
823 RtlZeroMemory(IF
, sizeof(LAN_ADAPTER
));
825 /* Put adapter in stopped state */
826 IF
->State
= LAN_STATE_STOPPED
;
828 /* Initialize protecting spin lock */
829 KeInitializeSpinLock(&IF
->Lock
);
831 KeInitializeEvent(&IF
->Event
, SynchronizationEvent
, FALSE
);
833 /* Initialize array with media IDs we support */
834 MediaArray
[MEDIA_ETH
] = NdisMedium802_3
;
836 TI_DbgPrint(DEBUG_DATALINK
,("opening adapter %wZ\n", AdapterName
));
837 /* Open the adapter. */
838 NdisOpenAdapter(&NdisStatus
,
850 /* Wait until the adapter is opened */
851 if (NdisStatus
== NDIS_STATUS_PENDING
)
852 KeWaitForSingleObject(&IF
->Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
853 else if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
858 IF
->Media
= MediaArray
[MediaIndex
];
860 /* Fill LAN_ADAPTER structure with some adapter specific information */
862 case NdisMedium802_3
:
863 IF
->HWAddressLength
= IEEE_802_ADDR_LENGTH
;
864 IF
->BCastMask
= BCAST_ETH_MASK
;
865 IF
->BCastCheck
= BCAST_ETH_CHECK
;
866 IF
->BCastOffset
= BCAST_ETH_OFFSET
;
867 IF
->HeaderSize
= sizeof(ETH_HEADER
);
868 IF
->MinFrameSize
= 60;
869 AddressOID
= OID_802_3_CURRENT_ADDRESS
;
871 NDIS_PACKET_TYPE_BROADCAST
|
872 NDIS_PACKET_TYPE_DIRECTED
|
873 NDIS_PACKET_TYPE_MULTICAST
;
877 /* Unsupported media */
878 TI_DbgPrint(MIN_TRACE
, ("Unsupported media.\n"));
880 return NDIS_STATUS_NOT_SUPPORTED
;
883 /* Get maximum frame size */
884 NdisStatus
= NDISCall(IF
,
885 NdisRequestQueryInformation
,
886 OID_GEN_MAXIMUM_FRAME_SIZE
,
889 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
894 /* Get maximum packet size */
895 NdisStatus
= NDISCall(IF
,
896 NdisRequestQueryInformation
,
897 OID_GEN_MAXIMUM_TOTAL_SIZE
,
900 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
901 TI_DbgPrint(MIN_TRACE
, ("Query for maximum packet size failed.\n"));
906 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
907 NdisStatus
= NDISCall(IF
,
908 NdisRequestQueryInformation
,
909 OID_GEN_MAXIMUM_SEND_PACKETS
,
912 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
913 /* Legacy NIC drivers may not support this query, if it fails we
914 assume it can send at least one packet per call to NdisSend(Packets) */
915 IF
->MaxSendPackets
= 1;
917 /* Get current hardware address */
918 NdisStatus
= NDISCall(IF
,
919 NdisRequestQueryInformation
,
922 IF
->HWAddressLength
);
923 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
924 TI_DbgPrint(MIN_TRACE
, ("Query for current hardware address failed.\n"));
929 /* Get maximum link speed */
930 NdisStatus
= NDISCall(IF
,
931 NdisRequestQueryInformation
,
935 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
936 TI_DbgPrint(MIN_TRACE
, ("Query for maximum link speed failed.\n"));
941 /* Convert returned link speed to bps (it is in 100bps increments) */
942 IF
->Speed
= Speed
* 100L;
944 /* Add adapter to the adapter list */
945 ExInterlockedInsertTailList(&AdapterListHead
,
949 /* Bind adapter to IP layer */
950 BindAdapter(IF
, RegistryPath
);
952 TI_DbgPrint(DEBUG_DATALINK
, ("Leaving.\n"));
954 return NDIS_STATUS_SUCCESS
;
958 NDIS_STATUS
LANUnregisterAdapter(
959 PLAN_ADAPTER Adapter
)
961 * FUNCTION: Unregisters protocol with NDIS adapter
963 * Adapter = Pointer to a LAN_ADAPTER structure
965 * Status of operation
969 NDIS_HANDLE NdisHandle
;
970 NDIS_STATUS NdisStatus
= NDIS_STATUS_SUCCESS
;
972 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
974 /* Unlink the adapter from the list */
975 RemoveEntryList(&Adapter
->ListEntry
);
977 /* Unbind adapter from IP layer */
978 UnbindAdapter(Adapter
);
980 TcpipAcquireSpinLock(&Adapter
->Lock
, &OldIrql
);
981 NdisHandle
= Adapter
->NdisHandle
;
983 Adapter
->NdisHandle
= NULL
;
984 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
986 NdisCloseAdapter(&NdisStatus
, NdisHandle
);
987 if (NdisStatus
== NDIS_STATUS_PENDING
) {
988 TcpipWaitForSingleObject(&Adapter
->Event
,
993 NdisStatus
= Adapter
->NdisStatus
;
996 TcpipReleaseSpinLock(&Adapter
->Lock
, OldIrql
);
998 FreeAdapter(Adapter
);
1000 return NDIS_STATUS_SUCCESS
;
1004 NTSTATUS
LANRegisterProtocol(
1007 * FUNCTION: Registers this protocol driver with NDIS
1009 * Name = Name of this protocol driver
1011 * Status of operation
1014 NDIS_STATUS NdisStatus
;
1015 NDIS_PROTOCOL_CHARACTERISTICS ProtChars
;
1017 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1019 InitializeListHead(&AdapterListHead
);
1020 KeInitializeSpinLock(&AdapterListLock
);
1022 /* Set up protocol characteristics */
1023 RtlZeroMemory(&ProtChars
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1024 ProtChars
.MajorNdisVersion
= NDIS_VERSION_MAJOR
;
1025 ProtChars
.MinorNdisVersion
= NDIS_VERSION_MINOR
;
1026 ProtChars
.Name
.Length
= Name
->Length
;
1027 ProtChars
.Name
.Buffer
= Name
->Buffer
;
1028 ProtChars
.Name
.MaximumLength
= Name
->MaximumLength
;
1029 ProtChars
.OpenAdapterCompleteHandler
= ProtocolOpenAdapterComplete
;
1030 ProtChars
.CloseAdapterCompleteHandler
= ProtocolCloseAdapterComplete
;
1031 ProtChars
.ResetCompleteHandler
= ProtocolResetComplete
;
1032 ProtChars
.RequestCompleteHandler
= ProtocolRequestComplete
;
1033 ProtChars
.SendCompleteHandler
= ProtocolSendComplete
;
1034 ProtChars
.TransferDataCompleteHandler
= ProtocolTransferDataComplete
;
1035 ProtChars
.ReceiveHandler
= ProtocolReceive
;
1036 ProtChars
.ReceiveCompleteHandler
= ProtocolReceiveComplete
;
1037 ProtChars
.StatusHandler
= ProtocolStatus
;
1038 ProtChars
.StatusCompleteHandler
= ProtocolStatusComplete
;
1039 ProtChars
.BindAdapterHandler
= ProtocolBindAdapter
;
1041 /* Try to register protocol */
1042 NdisRegisterProtocol(&NdisStatus
,
1043 &NdisProtocolHandle
,
1045 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
));
1046 if (NdisStatus
!= NDIS_STATUS_SUCCESS
)
1048 TI_DbgPrint(MID_TRACE
, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus
));
1049 return (NTSTATUS
)NdisStatus
;
1052 ProtocolRegistered
= TRUE
;
1054 return STATUS_SUCCESS
;
1058 VOID
LANUnregisterProtocol(
1061 * FUNCTION: Unregisters this protocol driver with NDIS
1062 * NOTES: Does not care wether we are already registered
1065 TI_DbgPrint(DEBUG_DATALINK
, ("Called.\n"));
1067 if (ProtocolRegistered
) {
1068 NDIS_STATUS NdisStatus
;
1069 PLIST_ENTRY CurrentEntry
;
1070 PLIST_ENTRY NextEntry
;
1071 PLAN_ADAPTER Current
;
1074 TcpipAcquireSpinLock(&AdapterListLock
, &OldIrql
);
1076 /* Search the list and remove every adapter we find */
1077 CurrentEntry
= AdapterListHead
.Flink
;
1078 while (CurrentEntry
!= &AdapterListHead
) {
1079 NextEntry
= CurrentEntry
->Flink
;
1080 Current
= CONTAINING_RECORD(CurrentEntry
, LAN_ADAPTER
, ListEntry
);
1082 LANUnregisterAdapter(Current
);
1083 CurrentEntry
= NextEntry
;
1086 TcpipReleaseSpinLock(&AdapterListLock
, OldIrql
);
1088 NdisDeregisterProtocol(&NdisStatus
, NdisProtocolHandle
);
1089 ProtocolRegistered
= FALSE
;
1094 InitializeListHead( &LanWorkList
);
1095 ExInitializeWorkItem( &LanWorkItem
, LanReceiveWorker
, NULL
);
1098 VOID
LANShutdown() {
1100 PLAN_WQ_ITEM WorkItem
;
1101 PLIST_ENTRY ListEntry
;
1103 TcpipAcquireSpinLock( &LanWorkLock
, &OldIrql
);
1104 while( !IsListEmpty( &LanWorkList
) ) {
1105 ListEntry
= RemoveHeadList( &LanWorkList
);
1106 WorkItem
= CONTAINING_RECORD(ListEntry
, LAN_WQ_ITEM
, ListEntry
);
1107 FreeNdisPacket( WorkItem
->Packet
);
1108 ExFreePool( WorkItem
);
1110 TcpipReleaseSpinLock( &LanWorkLock
, OldIrql
);