- sanity check: assert DISPATCH_LEVEL for the dpc.
[reactos.git] / reactos / drivers / net / tcpip / datalink / lan.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: datalink/lan.c
5 * PURPOSE: Local Area Network media routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 typedef struct _LAN_WQ_ITEM {
14 LIST_ENTRY ListEntry;
15 PNDIS_PACKET Packet;
16 PLAN_ADAPTER Adapter;
17 UINT BytesTransferred;
18 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
19
20 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
21 BOOLEAN ProtocolRegistered = FALSE;
22 LIST_ENTRY AdapterListHead;
23 KSPIN_LOCK AdapterListLock;
24
25 /* Work around being called back into afd at Dpc level */
26 KSPIN_LOCK LanWorkLock;
27 LIST_ENTRY LanWorkList;
28 WORK_QUEUE_ITEM LanWorkItem;
29
30 NDIS_STATUS NDISCall(
31 PLAN_ADAPTER Adapter,
32 NDIS_REQUEST_TYPE Type,
33 NDIS_OID OID,
34 PVOID Buffer,
35 UINT Length)
36 /*
37 * FUNCTION: Send a request to NDIS
38 * ARGUMENTS:
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
44 * RETURNS:
45 * Status of operation
46 */
47 {
48 NDIS_REQUEST Request;
49 NDIS_STATUS NdisStatus;
50
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;
56 } else {
57 Request.DATA.QUERY_INFORMATION.Oid = OID;
58 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
59 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
60 }
61
62 if (Adapter->State != LAN_STATE_RESETTING) {
63 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
64 } else {
65 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
66 }
67
68 /* Wait for NDIS to complete the request */
69 if (NdisStatus == NDIS_STATUS_PENDING) {
70 KeWaitForSingleObject(&Adapter->Event,
71 UserRequest,
72 KernelMode,
73 FALSE,
74 NULL);
75 NdisStatus = Adapter->NdisStatus;
76 }
77
78 return NdisStatus;
79 }
80
81
82 VOID FreeAdapter(
83 PLAN_ADAPTER Adapter)
84 /*
85 * FUNCTION: Frees memory for a LAN_ADAPTER structure
86 * ARGUMENTS:
87 * Adapter = Pointer to LAN_ADAPTER structure to free
88 */
89 {
90 exFreePool(Adapter);
91 }
92
93
94 VOID STDCALL ProtocolOpenAdapterComplete(
95 NDIS_HANDLE BindingContext,
96 NDIS_STATUS Status,
97 NDIS_STATUS OpenErrorStatus)
98 /*
99 * FUNCTION: Called by NDIS to complete opening of an adapter
100 * ARGUMENTS:
101 * BindingContext = Pointer to a device context (LAN_ADAPTER)
102 * Status = Status of the operation
103 * OpenErrorStatus = Additional status information
104 */
105 {
106 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
107
108 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
109
110 KeSetEvent(&Adapter->Event, 0, FALSE);
111 }
112
113
114 VOID STDCALL ProtocolCloseAdapterComplete(
115 NDIS_HANDLE BindingContext,
116 NDIS_STATUS Status)
117 /*
118 * FUNCTION: Called by NDIS to complete closing an adapter
119 * ARGUMENTS:
120 * BindingContext = Pointer to a device context (LAN_ADAPTER)
121 * Status = Status of the operation
122 */
123 {
124 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
125
126 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
127
128 Adapter->NdisStatus = Status;
129
130 KeSetEvent(&Adapter->Event, 0, FALSE);
131 }
132
133
134 VOID STDCALL ProtocolResetComplete(
135 NDIS_HANDLE BindingContext,
136 NDIS_STATUS Status)
137 /*
138 * FUNCTION: Called by NDIS to complete resetting an adapter
139 * ARGUMENTS:
140 * BindingContext = Pointer to a device context (LAN_ADAPTER)
141 * Status = Status of the operation
142 */
143 {
144 TI_DbgPrint(MID_TRACE, ("Called.\n"));
145 }
146
147
148 VOID STDCALL ProtocolRequestComplete(
149 NDIS_HANDLE BindingContext,
150 PNDIS_REQUEST NdisRequest,
151 NDIS_STATUS Status)
152 /*
153 * FUNCTION: Called by NDIS to complete a request
154 * ARGUMENTS:
155 * BindingContext = Pointer to a device context (LAN_ADAPTER)
156 * NdisRequest = Pointer to an object describing the request
157 * Status = Status of the operation
158 */
159 {
160 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
161
162 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
163
164 /* Save status of request and signal an event */
165 Adapter->NdisStatus = Status;
166
167 KeSetEvent(&Adapter->Event, 0, FALSE);
168 }
169
170
171 VOID STDCALL ProtocolSendComplete(
172 NDIS_HANDLE BindingContext,
173 PNDIS_PACKET Packet,
174 NDIS_STATUS Status)
175 /*
176 * FUNCTION: Called by NDIS to complete sending process
177 * ARGUMENTS:
178 * BindingContext = Pointer to a device context (LAN_ADAPTER)
179 * Packet = Pointer to a packet descriptor
180 * Status = Status of the operation
181 */
182 {
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"));
189 }
190
191 VOID STDCALL LanReceiveWorker( PVOID Context ) {
192 UINT PacketType;
193 PLIST_ENTRY ListEntry;
194 PLAN_WQ_ITEM WorkItem;
195 PNDIS_PACKET Packet;
196 PLAN_ADAPTER Adapter;
197 UINT BytesTransferred;
198 PNDIS_BUFFER NdisBuffer;
199 IP_PACKET IPPacket;
200
201
202 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
203
204 while( (ListEntry =
205 ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
206 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
207
208 Packet = WorkItem->Packet;
209 Adapter = WorkItem->Adapter;
210 BytesTransferred = WorkItem->BytesTransferred;
211
212 ExFreePool( WorkItem );
213
214 IPPacket.NdisPacket = Packet;
215
216 NdisGetFirstBufferFromPacket(Packet,
217 &NdisBuffer,
218 &IPPacket.Header,
219 &IPPacket.ContigSize,
220 &IPPacket.TotalSize);
221
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 */
225
226 TI_DbgPrint(MID_TRACE,
227 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
228 IPPacket.ContigSize, IPPacket.TotalSize,
229 BytesTransferred));
230
231 /*OskitDumpBuffer( IPPacket.Header, IPPacket.TotalSize );*/
232
233 PacketType = PC(IPPacket.NdisPacket)->PacketType;
234 IPPacket.Position = 0;
235
236 TI_DbgPrint
237 (DEBUG_DATALINK,
238 ("Ether Type = %x ContigSize = %d Total = %d\n",
239 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
240
241 switch (PacketType) {
242 case ETYPE_IPv4:
243 case ETYPE_IPv6:
244 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
245 IPReceive(Adapter->Context, &IPPacket);
246 break;
247 case ETYPE_ARP:
248 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
249 ARPReceive(Adapter->Context, &IPPacket);
250 default:
251 break;
252 }
253
254 FreeNdisPacket( Packet );
255 }
256 }
257
258 VOID STDCALL ProtocolTransferDataComplete(
259 NDIS_HANDLE BindingContext,
260 PNDIS_PACKET Packet,
261 NDIS_STATUS Status,
262 UINT BytesTransferred)
263 /*
264 * FUNCTION: Called by NDIS to complete reception of data
265 * ARGUMENTS:
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
270 * NOTES:
271 * If the packet was successfully received, determine the protocol
272 * type and pass it to the correct receive handler
273 */
274 {
275 BOOLEAN WorkStart;
276 PLAN_WQ_ITEM WQItem;
277 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
278
279 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
280
281 if( Status != NDIS_STATUS_SUCCESS ) return;
282 WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
283 if( !WQItem ) return;
284
285 TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock );
286 WorkStart = IsListEmpty( &LanWorkList );
287 WQItem->Packet = Packet;
288 WQItem->Adapter = Adapter;
289 WQItem->BytesTransferred = BytesTransferred;
290 InsertTailList( &LanWorkList, &WQItem->ListEntry );
291 if( WorkStart )
292 ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
293 TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock );
294 }
295
296 NDIS_STATUS STDCALL ProtocolReceive(
297 NDIS_HANDLE BindingContext,
298 NDIS_HANDLE MacReceiveContext,
299 PVOID HeaderBuffer,
300 UINT HeaderBufferSize,
301 PVOID LookaheadBuffer,
302 UINT LookaheadBufferSize,
303 UINT PacketSize)
304 /*
305 * FUNCTION: Called by NDIS when a packet has been received on the physical link
306 * ARGUMENTS:
307 * BindingContext = Pointer to a device context (LAN_ADAPTER)
308 * MacReceiveContext = Handle used by underlying NIC driver
309 * HeaderBuffer = Pointer to a buffer containing the packet header
310 * HeaderBufferSize = Number of bytes in HeaderBuffer
311 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
312 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
313 * PacketSize = Overall size of the packet (not including header)
314 * RETURNS:
315 * Status of operation
316 */
317 {
318 USHORT EType;
319 UINT PacketType, BytesTransferred;
320 UINT temp;
321 IP_PACKET IPPacket;
322 PCHAR BufferData;
323 NDIS_STATUS NdisStatus;
324 PNDIS_PACKET NdisPacket;
325 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
326 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
327
328 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
329
330 if (Adapter->State != LAN_STATE_STARTED) {
331 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
332 return NDIS_STATUS_NOT_ACCEPTED;
333 }
334
335 if (HeaderBufferSize < Adapter->HeaderSize) {
336 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
337 return NDIS_STATUS_NOT_ACCEPTED;
338 }
339
340 if (Adapter->Media == NdisMedium802_3) {
341 /* Ethernet and IEEE 802.3 frames can be destinguished by
342 looking at the IEEE 802.3 length field. This field is
343 less than or equal to 1500 for a valid IEEE 802.3 frame
344 and larger than 1500 is it's a valid EtherType value.
345 See RFC 1122, section 2.3.3 for more information */
346 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
347 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
348 TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
349 return NDIS_STATUS_NOT_ACCEPTED;
350 }
351 /* We use EtherType constants to destinguish packet types */
352 PacketType = EType;
353 } else {
354 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
355 /* FIXME: Support other medias */
356 return NDIS_STATUS_NOT_ACCEPTED;
357 }
358
359 /* Get a transfer data packet */
360
361 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
362 Adapter, Adapter->MTU));
363
364 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
365 PacketSize + HeaderBufferSize );
366 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
367 return NDIS_STATUS_NOT_ACCEPTED;
368 }
369
370 PC(NdisPacket)->PacketType = PacketType;
371
372 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
373
374 GetDataPtr( NdisPacket, 0, &BufferData, &temp );
375
376 IPPacket.NdisPacket = NdisPacket;
377 IPPacket.Position = 0;
378
379 if (LookaheadBufferSize == PacketSize)
380 {
381 /* Optimized code path for packets that are fully contained in
382 * the lookahead buffer. */
383 NdisCopyLookaheadData(BufferData,
384 LookaheadBuffer,
385 LookaheadBufferSize,
386 Adapter->MacOptions);
387 }
388 else
389 {
390 if (NdisStatus == NDIS_STATUS_SUCCESS)
391 {
392 ASSERT(PacketSize <= Adapter->MTU);
393
394 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
395 MacReceiveContext, 0, PacketSize,
396 NdisPacket, &BytesTransferred);
397 }
398 else
399 {
400 BytesTransferred = 0;
401 }
402 }
403 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
404
405 if (NdisStatus != NDIS_STATUS_PENDING)
406 ProtocolTransferDataComplete(BindingContext,
407 NdisPacket,
408 NdisStatus,
409 PacketSize);
410
411 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
412
413 return NDIS_STATUS_SUCCESS;
414 }
415
416
417 VOID STDCALL ProtocolReceiveComplete(
418 NDIS_HANDLE BindingContext)
419 /*
420 * FUNCTION: Called by NDIS when we're done receiving data
421 * ARGUMENTS:
422 * BindingContext = Pointer to a device context (LAN_ADAPTER)
423 */
424 {
425 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
426 }
427
428
429 VOID STDCALL ProtocolStatus(
430 NDIS_HANDLE BindingContext,
431 NDIS_STATUS GenerelStatus,
432 PVOID StatusBuffer,
433 UINT StatusBufferSize)
434 /*
435 * FUNCTION: Called by NDIS when the underlying driver has changed state
436 * ARGUMENTS:
437 * BindingContext = Pointer to a device context (LAN_ADAPTER)
438 * GenerelStatus = A generel status code
439 * StatusBuffer = Pointer to a buffer with medium-specific data
440 * StatusBufferSize = Number of bytes in StatusBuffer
441 */
442 {
443 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
444 }
445
446
447 VOID STDCALL ProtocolStatusComplete(
448 NDIS_HANDLE NdisBindingContext)
449 /*
450 * FUNCTION: Called by NDIS when a status-change has occurred
451 * ARGUMENTS:
452 * BindingContext = Pointer to a device context (LAN_ADAPTER)
453 */
454 {
455 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
456 }
457
458 VOID STDCALL ProtocolBindAdapter(
459 OUT PNDIS_STATUS Status,
460 IN NDIS_HANDLE BindContext,
461 IN PNDIS_STRING DeviceName,
462 IN PVOID SystemSpecific1,
463 IN PVOID SystemSpecific2)
464 /*
465 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
466 * bindings, and periodically thereafer as new adapters come online
467 * ARGUMENTS:
468 * Status: Return value to NDIS
469 * BindContext: Handle provided by NDIS to track pending binding operations
470 * DeviceName: Name of the miniport device to bind to
471 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
472 * SystemSpecific2: Unused & must not be touched
473 */
474 {
475 /* XXX confirm that this is still true, or re-word the following comment */
476 /* we get to ignore BindContext because we will never pend an operation with NDIS */
477 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
478 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
479 }
480
481
482 VOID LANTransmit(
483 PVOID Context,
484 PNDIS_PACKET NdisPacket,
485 UINT Offset,
486 PVOID LinkAddress,
487 USHORT Type)
488 /*
489 * FUNCTION: Transmits a packet
490 * ARGUMENTS:
491 * Context = Pointer to context information (LAN_ADAPTER)
492 * NdisPacket = Pointer to NDIS packet to send
493 * Offset = Offset in packet where data starts
494 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
495 * Type = LAN protocol type (LAN_PROTO_*)
496 */
497 {
498 NDIS_STATUS NdisStatus;
499 PETH_HEADER EHeader;
500 PCHAR Data;
501 UINT Size;
502 KIRQL OldIrql;
503 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
504
505 TI_DbgPrint(DEBUG_DATALINK,
506 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
507 NdisPacket, Offset, Adapter));
508
509 TI_DbgPrint(DEBUG_DATALINK,
510 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
511 Adapter->HWAddress[0] & 0xff,
512 Adapter->HWAddress[1] & 0xff,
513 Adapter->HWAddress[2] & 0xff,
514 Adapter->HWAddress[3] & 0xff,
515 Adapter->HWAddress[4] & 0xff,
516 Adapter->HWAddress[5] & 0xff));
517
518 /* XXX arty -- Handled adjustment in a saner way than before ...
519 * not needed immediately */
520 GetDataPtr( NdisPacket, 0, &Data, &Size );
521
522 if (Adapter->State == LAN_STATE_STARTED) {
523 switch (Adapter->Media) {
524 case NdisMedium802_3:
525 EHeader = (PETH_HEADER)Data;
526
527 if (LinkAddress) {
528 /* Unicast address */
529 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
530 } else {
531 /* Broadcast address */
532 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
533 }
534
535 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
536
537 switch (Type) {
538 case LAN_PROTO_IPv4:
539 EHeader->EType = ETYPE_IPv4;
540 break;
541 case LAN_PROTO_ARP:
542 EHeader->EType = ETYPE_ARP;
543 break;
544 case LAN_PROTO_IPv6:
545 EHeader->EType = ETYPE_IPv6;
546 break;
547 default:
548 #ifdef DBG
549 /* Should not happen */
550 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
551
552 ProtocolSendComplete((NDIS_HANDLE)Context,
553 NdisPacket,
554 NDIS_STATUS_FAILURE);
555 #endif
556 return;
557 }
558 break;
559
560 default:
561 /* FIXME: Support other medias */
562 break;
563 }
564
565 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
566 if( LinkAddress ) {
567 TI_DbgPrint
568 ( MID_TRACE,
569 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
570 ((PCHAR)LinkAddress)[0] & 0xff,
571 ((PCHAR)LinkAddress)[1] & 0xff,
572 ((PCHAR)LinkAddress)[2] & 0xff,
573 ((PCHAR)LinkAddress)[3] & 0xff,
574 ((PCHAR)LinkAddress)[4] & 0xff,
575 ((PCHAR)LinkAddress)[5] & 0xff));
576 }
577
578 /*OskitDumpBuffer( Data, Size );*/
579
580 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
581 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
582 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
583 TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
584 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
585
586 if (NdisStatus != NDIS_STATUS_PENDING)
587 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
588 } else {
589 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
590 }
591 }
592
593 static NTSTATUS
594 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
595 OBJECT_ATTRIBUTES Attributes;
596 NTSTATUS Status;
597
598 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
599 Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes);
600 return Status;
601 }
602
603 static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle,
604 PWCHAR RegistryValue,
605 PIP_ADDRESS Address ) {
606 UNICODE_STRING ValueName;
607 UNICODE_STRING UnicodeAddress;
608 NTSTATUS Status;
609 ULONG ResultLength;
610 UCHAR buf[1024];
611 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
612 ANSI_STRING AnsiAddress;
613 ULONG AnsiLen;
614
615 RtlInitUnicodeString(&ValueName, RegistryValue);
616 Status =
617 ZwQueryValueKey(RegHandle,
618 &ValueName,
619 KeyValuePartialInformation,
620 Information,
621 sizeof(buf),
622 &ResultLength);
623
624 if (!NT_SUCCESS(Status))
625 return Status;
626 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
627 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
628
629 UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
630 UnicodeAddress.Length = Information->DataLength;
631 UnicodeAddress.MaximumLength = Information->DataLength;
632
633 AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
634 if(!AnsiLen)
635 return STATUS_NO_MEMORY;
636
637 AnsiAddress.Buffer = exAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
638 if(!AnsiAddress.Buffer)
639 return STATUS_NO_MEMORY;
640
641 AnsiAddress.Length = AnsiLen;
642 AnsiAddress.MaximumLength = AnsiLen;
643
644 Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
645 if (!NT_SUCCESS(Status)) {
646 exFreePool(AnsiAddress.Buffer);
647 return STATUS_UNSUCCESSFUL;
648 }
649
650 AnsiAddress.Buffer[AnsiAddress.Length] = 0;
651 AddrInitIPv4(Address, inet_addr(AnsiAddress.Buffer));
652
653 return STATUS_SUCCESS;
654 }
655
656 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
657 PWCHAR RegistryValue,
658 PUNICODE_STRING String ) {
659 UNICODE_STRING ValueName;
660 UNICODE_STRING UnicodeString;
661 NTSTATUS Status;
662 ULONG ResultLength;
663 UCHAR buf[1024];
664 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
665
666 RtlInitUnicodeString(&ValueName, RegistryValue);
667 Status =
668 ZwQueryValueKey(RegHandle,
669 &ValueName,
670 KeyValuePartialInformation,
671 Information,
672 sizeof(buf),
673 &ResultLength);
674
675 if (!NT_SUCCESS(Status))
676 return Status;
677 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
678 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
679
680 UnicodeString.Buffer = (PWCHAR)&Information->Data;
681 UnicodeString.Length = Information->DataLength;
682 UnicodeString.MaximumLength = Information->DataLength;
683
684 String->Buffer =
685 (PWCHAR)exAllocatePool( NonPagedPool,
686 UnicodeString.MaximumLength + sizeof(WCHAR) );
687
688 if( !String->Buffer ) return STATUS_NO_MEMORY;
689
690 String->MaximumLength = UnicodeString.MaximumLength;
691 RtlCopyUnicodeString( String, &UnicodeString );
692
693 return STATUS_SUCCESS;
694 }
695
696 static VOID GetSimpleAdapterNameFromRegistryPath
697 ( PUNICODE_STRING TargetString,
698 PUNICODE_STRING RegistryPath ) {
699 PWCHAR i, LastSlash = NULL;
700 UINT NewStringLength = 0;
701
702 for( i = RegistryPath->Buffer;
703 i < RegistryPath->Buffer +
704 (RegistryPath->Length / sizeof(WCHAR));
705 i++ ) if( *i == '\\' ) LastSlash = i;
706
707 if( LastSlash ) LastSlash++; else LastSlash = RegistryPath->Buffer;
708
709 NewStringLength = RegistryPath->MaximumLength -
710 ((LastSlash - RegistryPath->Buffer) * sizeof(WCHAR));
711
712 TargetString->Buffer =
713 (PWCHAR)exAllocatePool( NonPagedPool, NewStringLength );
714
715 if( !TargetString->Buffer ) {
716 TargetString->Length = TargetString->MaximumLength = 0;
717 return;
718 }
719
720 TargetString->Length = TargetString->MaximumLength = NewStringLength;
721 RtlCopyMemory( TargetString->Buffer, LastSlash, NewStringLength );
722 }
723
724 VOID BindAdapter(
725 PLAN_ADAPTER Adapter,
726 PNDIS_STRING RegistryPath)
727 /*
728 * FUNCTION: Binds a LAN adapter to IP layer
729 * ARGUMENTS:
730 * Adapter = Pointer to LAN_ADAPTER structure
731 * NOTES:
732 * We set the lookahead buffer size, set the packet filter and
733 * bind the adapter to IP layer
734 */
735 {
736 PIP_INTERFACE IF;
737 NDIS_STATUS NdisStatus;
738 LLIP_BIND_INFO BindInfo;
739 IP_ADDRESS DefaultGateway, DefaultMask = { 0 };
740 ULONG Lookahead = LOOKAHEAD_SIZE;
741 NTSTATUS Status;
742 HANDLE RegHandle = 0;
743
744 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
745
746 Adapter->State = LAN_STATE_OPENING;
747
748 NdisStatus = NDISCall(Adapter,
749 NdisRequestSetInformation,
750 OID_GEN_CURRENT_LOOKAHEAD,
751 &Lookahead,
752 sizeof(ULONG));
753 if (NdisStatus != NDIS_STATUS_SUCCESS) {
754 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
755 return;
756 }
757
758 /* Bind the adapter to IP layer */
759 BindInfo.Context = Adapter;
760 BindInfo.HeaderSize = Adapter->HeaderSize;
761 BindInfo.MinFrameSize = Adapter->MinFrameSize;
762 BindInfo.MTU = Adapter->MTU;
763 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
764 BindInfo.AddressLength = Adapter->HWAddressLength;
765 BindInfo.Transmit = LANTransmit;
766
767 IF = IPCreateInterface(&BindInfo);
768
769 if (!IF) {
770 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
771 return;
772 }
773
774 /*
775 * Query per-adapter configuration from the registry
776 * In case anyone is curious: there *is* an Ndis configuration api
777 * for this sort of thing, but it doesn't really support things like
778 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
779 * protocol drivers developed for win2k and above just use the native
780 * services (ZwOpenKey, etc).
781 */
782
783 Status = OpenRegistryKey( RegistryPath, &RegHandle );
784
785 if(NT_SUCCESS(Status))
786 Status = ReadIPAddressFromRegistry( RegHandle, L"DefaultGateway",
787 &DefaultGateway );
788 if(!NT_SUCCESS(Status)) {
789 Status = STATUS_SUCCESS;
790 RtlZeroMemory( &DefaultGateway, sizeof(DefaultGateway) );
791 }
792
793 if(NT_SUCCESS(Status))
794 Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress",
795 &IF->Unicast );
796 if(NT_SUCCESS(Status))
797 Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask",
798 &IF->Netmask );
799 if(NT_SUCCESS(Status)) {
800 Status = ReadStringFromRegistry( RegHandle, L"DeviceDesc",
801 &IF->Name );
802
803 RtlZeroMemory( &IF->Name, sizeof( IF->Name ) );
804
805 /* I think that not getting a devicedesc is not a fatal error */
806 if( !NT_SUCCESS(Status) ) {
807 if( IF->Name.Buffer ) exFreePool( IF->Name.Buffer );
808 GetSimpleAdapterNameFromRegistryPath( &IF->Name, RegistryPath );
809 }
810 Status = STATUS_SUCCESS;
811 }
812
813 if(!NT_SUCCESS(Status))
814 {
815 TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
816
817 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
818 if(RegHandle)
819 ZwClose(RegHandle);
820 IPDestroyInterface(IF);
821 return;
822 }
823
824 TI_DbgPrint
825 (MID_TRACE,
826 ("--> Our IP address on this interface: '%s'\n",
827 A2S(&IF->Unicast)));
828
829 TI_DbgPrint
830 (MID_TRACE,
831 ("--> Our net mask on this interface: '%s'\n",
832 A2S(&IF->Netmask)));
833
834 if( DefaultGateway.Address.IPv4Address ) {
835 TI_DbgPrint
836 (MID_TRACE,
837 ("--> Our gateway is: '%s'\n",
838 A2S(&DefaultGateway)));
839
840 /* Create a default route */
841 RouterCreateRoute( &DefaultMask, /* Zero */
842 &DefaultMask, /* Zero */
843 &DefaultGateway,
844 IF,
845 1 );
846 }
847
848 /* Register interface with IP layer */
849 IPRegisterInterface(IF);
850
851 /* Set packet filter so we can send and receive packets */
852 NdisStatus = NDISCall(Adapter,
853 NdisRequestSetInformation,
854 OID_GEN_CURRENT_PACKET_FILTER,
855 &Adapter->PacketFilter,
856 sizeof(UINT));
857 if (NdisStatus != NDIS_STATUS_SUCCESS) {
858 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
859 IPDestroyInterface(IF);
860 return;
861 }
862
863 Adapter->Context = IF;
864 Adapter->State = LAN_STATE_STARTED;
865 }
866
867
868 VOID UnbindAdapter(
869 PLAN_ADAPTER Adapter)
870 /*
871 * FUNCTION: Unbinds a LAN adapter from IP layer
872 * ARGUMENTS:
873 * Adapter = Pointer to LAN_ADAPTER structure
874 */
875 {
876 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
877
878 if (Adapter->State == LAN_STATE_STARTED) {
879 PIP_INTERFACE IF = Adapter->Context;
880
881 IPUnregisterInterface(IF);
882
883 IPDestroyInterface(IF);
884 }
885 }
886
887
888 NDIS_STATUS LANRegisterAdapter(
889 PNDIS_STRING AdapterName,
890 PNDIS_STRING RegistryPath)
891 /*
892 * FUNCTION: Registers protocol with an NDIS adapter
893 * ARGUMENTS:
894 * AdapterName = Pointer to string with name of adapter to register
895 * Adapter = Address of pointer to a LAN_ADAPTER structure
896 * RETURNS:
897 * Status of operation
898 */
899 {
900 PLAN_ADAPTER IF;
901 NDIS_STATUS NdisStatus;
902 NDIS_STATUS OpenStatus;
903 UINT MediaIndex;
904 NDIS_MEDIUM MediaArray[MAX_MEDIA];
905 UINT AddressOID;
906 UINT Speed;
907
908 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
909
910 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
911 if (!IF) {
912 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
913 return NDIS_STATUS_RESOURCES;
914 }
915
916 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
917
918 /* Put adapter in stopped state */
919 IF->State = LAN_STATE_STOPPED;
920
921 /* Initialize protecting spin lock */
922 KeInitializeSpinLock(&IF->Lock);
923
924 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
925
926 /* Initialize array with media IDs we support */
927 MediaArray[MEDIA_ETH] = NdisMedium802_3;
928
929 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
930 /* Open the adapter. */
931 NdisOpenAdapter(&NdisStatus,
932 &OpenStatus,
933 &IF->NdisHandle,
934 &MediaIndex,
935 MediaArray,
936 MAX_MEDIA,
937 NdisProtocolHandle,
938 IF,
939 AdapterName,
940 0,
941 NULL);
942
943 /* Wait until the adapter is opened */
944 if (NdisStatus == NDIS_STATUS_PENDING)
945 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
946 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
947 exFreePool(IF);
948 return NdisStatus;
949 }
950
951 IF->Media = MediaArray[MediaIndex];
952
953 /* Fill LAN_ADAPTER structure with some adapter specific information */
954 switch (IF->Media) {
955 case NdisMedium802_3:
956 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
957 IF->BCastMask = BCAST_ETH_MASK;
958 IF->BCastCheck = BCAST_ETH_CHECK;
959 IF->BCastOffset = BCAST_ETH_OFFSET;
960 IF->HeaderSize = sizeof(ETH_HEADER);
961 IF->MinFrameSize = 60;
962 AddressOID = OID_802_3_CURRENT_ADDRESS;
963 IF->PacketFilter =
964 NDIS_PACKET_TYPE_BROADCAST |
965 NDIS_PACKET_TYPE_DIRECTED |
966 NDIS_PACKET_TYPE_MULTICAST;
967 break;
968
969 default:
970 /* Unsupported media */
971 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
972 exFreePool(IF);
973 return NDIS_STATUS_NOT_SUPPORTED;
974 }
975
976 /* Get maximum frame size */
977 NdisStatus = NDISCall(IF,
978 NdisRequestQueryInformation,
979 OID_GEN_MAXIMUM_FRAME_SIZE,
980 &IF->MTU,
981 sizeof(UINT));
982 if (NdisStatus != NDIS_STATUS_SUCCESS) {
983 exFreePool(IF);
984 return NdisStatus;
985 }
986
987 /* Get maximum packet size */
988 NdisStatus = NDISCall(IF,
989 NdisRequestQueryInformation,
990 OID_GEN_MAXIMUM_TOTAL_SIZE,
991 &IF->MaxPacketSize,
992 sizeof(UINT));
993 if (NdisStatus != NDIS_STATUS_SUCCESS) {
994 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
995 exFreePool(IF);
996 return NdisStatus;
997 }
998
999 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1000 NdisStatus = NDISCall(IF,
1001 NdisRequestQueryInformation,
1002 OID_GEN_MAXIMUM_SEND_PACKETS,
1003 &IF->MaxSendPackets,
1004 sizeof(UINT));
1005 if (NdisStatus != NDIS_STATUS_SUCCESS)
1006 /* Legacy NIC drivers may not support this query, if it fails we
1007 assume it can send at least one packet per call to NdisSend(Packets) */
1008 IF->MaxSendPackets = 1;
1009
1010 /* Get current hardware address */
1011 NdisStatus = NDISCall(IF,
1012 NdisRequestQueryInformation,
1013 AddressOID,
1014 &IF->HWAddress,
1015 IF->HWAddressLength);
1016 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1017 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1018 exFreePool(IF);
1019 return NdisStatus;
1020 }
1021
1022 /* Get maximum link speed */
1023 NdisStatus = NDISCall(IF,
1024 NdisRequestQueryInformation,
1025 OID_GEN_LINK_SPEED,
1026 &Speed,
1027 sizeof(UINT));
1028 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1029 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1030 exFreePool(IF);
1031 return NdisStatus;
1032 }
1033
1034 /* Convert returned link speed to bps (it is in 100bps increments) */
1035 IF->Speed = Speed * 100L;
1036
1037 /* Add adapter to the adapter list */
1038 ExInterlockedInsertTailList(&AdapterListHead,
1039 &IF->ListEntry,
1040 &AdapterListLock);
1041
1042 /* Bind adapter to IP layer */
1043 BindAdapter(IF, RegistryPath);
1044
1045 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1046
1047 return NDIS_STATUS_SUCCESS;
1048 }
1049
1050
1051 NDIS_STATUS LANUnregisterAdapter(
1052 PLAN_ADAPTER Adapter)
1053 /*
1054 * FUNCTION: Unregisters protocol with NDIS adapter
1055 * ARGUMENTS:
1056 * Adapter = Pointer to a LAN_ADAPTER structure
1057 * RETURNS:
1058 * Status of operation
1059 */
1060 {
1061 KIRQL OldIrql;
1062 NDIS_HANDLE NdisHandle;
1063 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1064
1065 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1066
1067 /* Unlink the adapter from the list */
1068 RemoveEntryList(&Adapter->ListEntry);
1069
1070 /* Unbind adapter from IP layer */
1071 UnbindAdapter(Adapter);
1072
1073 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1074 NdisHandle = Adapter->NdisHandle;
1075 if (NdisHandle) {
1076 Adapter->NdisHandle = NULL;
1077 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1078
1079 NdisCloseAdapter(&NdisStatus, NdisHandle);
1080 if (NdisStatus == NDIS_STATUS_PENDING) {
1081 TcpipWaitForSingleObject(&Adapter->Event,
1082 UserRequest,
1083 KernelMode,
1084 FALSE,
1085 NULL);
1086 NdisStatus = Adapter->NdisStatus;
1087 }
1088 } else
1089 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1090
1091 FreeAdapter(Adapter);
1092
1093 return NDIS_STATUS_SUCCESS;
1094 }
1095
1096
1097 NTSTATUS LANRegisterProtocol(
1098 PNDIS_STRING Name)
1099 /*
1100 * FUNCTION: Registers this protocol driver with NDIS
1101 * ARGUMENTS:
1102 * Name = Name of this protocol driver
1103 * RETURNS:
1104 * Status of operation
1105 */
1106 {
1107 NDIS_STATUS NdisStatus;
1108 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1109
1110 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1111
1112 InitializeListHead(&AdapterListHead);
1113 KeInitializeSpinLock(&AdapterListLock);
1114
1115 /* Set up protocol characteristics */
1116 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1117 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1118 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1119 ProtChars.Name.Length = Name->Length;
1120 ProtChars.Name.Buffer = Name->Buffer;
1121 ProtChars.Name.MaximumLength = Name->MaximumLength;
1122 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1123 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1124 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1125 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1126 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1127 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1128 ProtChars.ReceiveHandler = ProtocolReceive;
1129 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1130 ProtChars.StatusHandler = ProtocolStatus;
1131 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1132 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1133
1134 /* Try to register protocol */
1135 NdisRegisterProtocol(&NdisStatus,
1136 &NdisProtocolHandle,
1137 &ProtChars,
1138 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1139 if (NdisStatus != NDIS_STATUS_SUCCESS)
1140 {
1141 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1142 return (NTSTATUS)NdisStatus;
1143 }
1144
1145 ProtocolRegistered = TRUE;
1146
1147 return STATUS_SUCCESS;
1148 }
1149
1150
1151 VOID LANUnregisterProtocol(
1152 VOID)
1153 /*
1154 * FUNCTION: Unregisters this protocol driver with NDIS
1155 * NOTES: Does not care wether we are already registered
1156 */
1157 {
1158 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1159
1160 if (ProtocolRegistered) {
1161 NDIS_STATUS NdisStatus;
1162 PLIST_ENTRY CurrentEntry;
1163 PLIST_ENTRY NextEntry;
1164 PLAN_ADAPTER Current;
1165 KIRQL OldIrql;
1166
1167 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1168
1169 /* Search the list and remove every adapter we find */
1170 CurrentEntry = AdapterListHead.Flink;
1171 while (CurrentEntry != &AdapterListHead) {
1172 NextEntry = CurrentEntry->Flink;
1173 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1174 /* Unregister it */
1175 LANUnregisterAdapter(Current);
1176 CurrentEntry = NextEntry;
1177 }
1178
1179 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1180
1181 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1182 ProtocolRegistered = FALSE;
1183 }
1184 }
1185
1186 VOID LANStartup() {
1187 InitializeListHead( &LanWorkList );
1188 ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
1189 }
1190
1191 VOID LANShutdown() {
1192 KIRQL OldIrql;
1193 PLAN_WQ_ITEM WorkItem;
1194 PLIST_ENTRY ListEntry;
1195
1196 TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
1197 while( !IsListEmpty( &LanWorkList ) ) {
1198 ListEntry = RemoveHeadList( &LanWorkList );
1199 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1200 FreeNdisPacket( WorkItem->Packet );
1201 ExFreePool( WorkItem );
1202 }
1203 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
1204 }
1205
1206 /* EOF */