afd/connect.c:
[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 PacketType = PC(IPPacket.NdisPacket)->PacketType;
232 IPPacket.Position = 0;
233
234 TI_DbgPrint
235 (DEBUG_DATALINK,
236 ("Ether Type = %x ContigSize = %d Total = %d\n",
237 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
238
239 switch (PacketType) {
240 case ETYPE_IPv4:
241 case ETYPE_IPv6:
242 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
243 IPReceive(Adapter->Context, &IPPacket);
244 break;
245 case ETYPE_ARP:
246 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
247 ARPReceive(Adapter->Context, &IPPacket);
248 default:
249 break;
250 }
251
252 FreeNdisPacket( Packet );
253 }
254 }
255
256 VOID STDCALL ProtocolTransferDataComplete(
257 NDIS_HANDLE BindingContext,
258 PNDIS_PACKET Packet,
259 NDIS_STATUS Status,
260 UINT BytesTransferred)
261 /*
262 * FUNCTION: Called by NDIS to complete reception of data
263 * ARGUMENTS:
264 * BindingContext = Pointer to a device context (LAN_ADAPTER)
265 * Packet = Pointer to a packet descriptor
266 * Status = Status of the operation
267 * BytesTransferred = Number of bytes transferred
268 * NOTES:
269 * If the packet was successfully received, determine the protocol
270 * type and pass it to the correct receive handler
271 */
272 {
273 BOOLEAN WorkStart;
274 PLAN_WQ_ITEM WQItem;
275 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
276
277 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
278
279 if( Status != NDIS_STATUS_SUCCESS ) return;
280 WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
281 if( !WQItem ) return;
282
283 TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock );
284 WorkStart = IsListEmpty( &LanWorkList );
285 WQItem->Packet = Packet;
286 WQItem->Adapter = Adapter;
287 WQItem->BytesTransferred = BytesTransferred;
288 InsertTailList( &LanWorkList, &WQItem->ListEntry );
289 if( WorkStart )
290 ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
291 TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock );
292 }
293
294 NDIS_STATUS STDCALL ProtocolReceive(
295 NDIS_HANDLE BindingContext,
296 NDIS_HANDLE MacReceiveContext,
297 PVOID HeaderBuffer,
298 UINT HeaderBufferSize,
299 PVOID LookaheadBuffer,
300 UINT LookaheadBufferSize,
301 UINT PacketSize)
302 /*
303 * FUNCTION: Called by NDIS when a packet has been received on the physical link
304 * ARGUMENTS:
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)
312 * RETURNS:
313 * Status of operation
314 */
315 {
316 USHORT EType;
317 UINT PacketType, BytesTransferred;
318 UINT temp;
319 IP_PACKET IPPacket;
320 PCHAR BufferData;
321 NDIS_STATUS NdisStatus;
322 PNDIS_PACKET NdisPacket;
323 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
324 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
325
326 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
327
328 if (Adapter->State != LAN_STATE_STARTED) {
329 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
330 return NDIS_STATUS_NOT_ACCEPTED;
331 }
332
333 if (HeaderBufferSize < Adapter->HeaderSize) {
334 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
335 return NDIS_STATUS_NOT_ACCEPTED;
336 }
337
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;
348 }
349 /* We use EtherType constants to destinguish packet types */
350 PacketType = EType;
351 } else {
352 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
353 /* FIXME: Support other medias */
354 return NDIS_STATUS_NOT_ACCEPTED;
355 }
356
357 /* Get a transfer data packet */
358
359 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
360 Adapter, Adapter->MTU));
361
362 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
363 PacketSize + HeaderBufferSize );
364 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
365 return NDIS_STATUS_NOT_ACCEPTED;
366 }
367
368 PC(NdisPacket)->PacketType = PacketType;
369
370 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
371
372 GetDataPtr( NdisPacket, 0, &BufferData, &temp );
373
374 IPPacket.NdisPacket = NdisPacket;
375 IPPacket.Position = 0;
376
377 if (LookaheadBufferSize == PacketSize)
378 {
379 /* Optimized code path for packets that are fully contained in
380 * the lookahead buffer. */
381 NdisCopyLookaheadData(BufferData,
382 LookaheadBuffer,
383 LookaheadBufferSize,
384 Adapter->MacOptions);
385 }
386 else
387 {
388 if (NdisStatus == NDIS_STATUS_SUCCESS)
389 {
390 ASSERT(PacketSize <= Adapter->MTU);
391
392 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
393 MacReceiveContext, 0, PacketSize,
394 NdisPacket, &BytesTransferred);
395 }
396 else
397 {
398 BytesTransferred = 0;
399 }
400 }
401 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
402
403 if (NdisStatus != NDIS_STATUS_PENDING)
404 ProtocolTransferDataComplete(BindingContext,
405 NdisPacket,
406 NdisStatus,
407 PacketSize);
408
409 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
410
411 return NDIS_STATUS_SUCCESS;
412 }
413
414
415 VOID STDCALL ProtocolReceiveComplete(
416 NDIS_HANDLE BindingContext)
417 /*
418 * FUNCTION: Called by NDIS when we're done receiving data
419 * ARGUMENTS:
420 * BindingContext = Pointer to a device context (LAN_ADAPTER)
421 */
422 {
423 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
424 }
425
426
427 VOID STDCALL ProtocolStatus(
428 NDIS_HANDLE BindingContext,
429 NDIS_STATUS GenerelStatus,
430 PVOID StatusBuffer,
431 UINT StatusBufferSize)
432 /*
433 * FUNCTION: Called by NDIS when the underlying driver has changed state
434 * ARGUMENTS:
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
439 */
440 {
441 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
442 }
443
444
445 VOID STDCALL ProtocolStatusComplete(
446 NDIS_HANDLE NdisBindingContext)
447 /*
448 * FUNCTION: Called by NDIS when a status-change has occurred
449 * ARGUMENTS:
450 * BindingContext = Pointer to a device context (LAN_ADAPTER)
451 */
452 {
453 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
454 }
455
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)
462 /*
463 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
464 * bindings, and periodically thereafer as new adapters come online
465 * ARGUMENTS:
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
471 */
472 {
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);
477 }
478
479
480 VOID LANTransmit(
481 PVOID Context,
482 PNDIS_PACKET NdisPacket,
483 UINT Offset,
484 PVOID LinkAddress,
485 USHORT Type)
486 /*
487 * FUNCTION: Transmits a packet
488 * ARGUMENTS:
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_*)
494 */
495 {
496 NDIS_STATUS NdisStatus;
497 PETH_HEADER EHeader;
498 PCHAR Data;
499 UINT Size;
500 KIRQL OldIrql;
501 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
502
503 TI_DbgPrint(DEBUG_DATALINK,
504 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
505 NdisPacket, Offset, Adapter));
506
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));
515
516 /* XXX arty -- Handled adjustment in a saner way than before ...
517 * not needed immediately */
518 GetDataPtr( NdisPacket, 0, &Data, &Size );
519
520 if (Adapter->State == LAN_STATE_STARTED) {
521 switch (Adapter->Media) {
522 case NdisMedium802_3:
523 EHeader = (PETH_HEADER)Data;
524
525 if (LinkAddress) {
526 /* Unicast address */
527 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
528 } else {
529 /* Broadcast address */
530 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
531 }
532
533 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
534
535 switch (Type) {
536 case LAN_PROTO_IPv4:
537 EHeader->EType = ETYPE_IPv4;
538 break;
539 case LAN_PROTO_ARP:
540 EHeader->EType = ETYPE_ARP;
541 break;
542 case LAN_PROTO_IPv6:
543 EHeader->EType = ETYPE_IPv6;
544 break;
545 default:
546 #ifdef DBG
547 /* Should not happen */
548 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
549
550 ProtocolSendComplete((NDIS_HANDLE)Context,
551 NdisPacket,
552 NDIS_STATUS_FAILURE);
553 #endif
554 return;
555 }
556 break;
557
558 default:
559 /* FIXME: Support other medias */
560 break;
561 }
562
563 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
564 if( LinkAddress ) {
565 TI_DbgPrint
566 ( MID_TRACE,
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));
574 }
575
576 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
577 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
578 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
579 TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
580 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
581
582 if (NdisStatus != NDIS_STATUS_PENDING)
583 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
584 } else {
585 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
586 }
587 }
588
589 static NTSTATUS
590 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
591 OBJECT_ATTRIBUTES Attributes;
592 NTSTATUS Status;
593
594 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
595 Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes);
596 return Status;
597 }
598
599 static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle,
600 PWCHAR RegistryValue,
601 PIP_ADDRESS Address ) {
602 UNICODE_STRING ValueName;
603 UNICODE_STRING UnicodeAddress;
604 NTSTATUS Status;
605 ULONG ResultLength;
606 UCHAR buf[1024];
607 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
608 ANSI_STRING AnsiAddress;
609 ULONG AnsiLen;
610
611 RtlInitUnicodeString(&ValueName, RegistryValue);
612 Status =
613 ZwQueryValueKey(RegHandle,
614 &ValueName,
615 KeyValuePartialInformation,
616 Information,
617 sizeof(buf),
618 &ResultLength);
619
620 if (!NT_SUCCESS(Status))
621 return Status;
622 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
623 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
624
625 UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
626 UnicodeAddress.Length = Information->DataLength;
627 UnicodeAddress.MaximumLength = Information->DataLength;
628
629 AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
630 if(!AnsiLen)
631 return STATUS_NO_MEMORY;
632
633 AnsiAddress.Buffer = exAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
634 if(!AnsiAddress.Buffer)
635 return STATUS_NO_MEMORY;
636
637 AnsiAddress.Length = AnsiLen;
638 AnsiAddress.MaximumLength = AnsiLen;
639
640 Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
641 if (!NT_SUCCESS(Status)) {
642 exFreePool(AnsiAddress.Buffer);
643 return STATUS_UNSUCCESSFUL;
644 }
645
646 AnsiAddress.Buffer[AnsiAddress.Length] = 0;
647 AddrInitIPv4(Address, inet_addr(AnsiAddress.Buffer));
648
649 return STATUS_SUCCESS;
650 }
651
652 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
653 PWCHAR RegistryValue,
654 PUNICODE_STRING String ) {
655 UNICODE_STRING ValueName;
656 UNICODE_STRING UnicodeString;
657 NTSTATUS Status;
658 ULONG ResultLength;
659 UCHAR buf[1024];
660 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
661
662 RtlInitUnicodeString(&ValueName, RegistryValue);
663 Status =
664 ZwQueryValueKey(RegHandle,
665 &ValueName,
666 KeyValuePartialInformation,
667 Information,
668 sizeof(buf),
669 &ResultLength);
670
671 if (!NT_SUCCESS(Status))
672 return Status;
673 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
674 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
675
676 UnicodeString.Buffer = (PWCHAR)&Information->Data;
677 UnicodeString.Length = Information->DataLength;
678 UnicodeString.MaximumLength = Information->DataLength;
679
680 String->Buffer =
681 (PWCHAR)exAllocatePool( NonPagedPool,
682 UnicodeString.MaximumLength + sizeof(WCHAR) );
683
684 if( !String->Buffer ) return STATUS_NO_MEMORY;
685
686 String->MaximumLength = UnicodeString.MaximumLength;
687 RtlCopyUnicodeString( String, &UnicodeString );
688
689 return STATUS_SUCCESS;
690 }
691
692 static VOID GetSimpleAdapterNameFromRegistryPath
693 ( PUNICODE_STRING TargetString,
694 PUNICODE_STRING RegistryPath ) {
695 PWCHAR i, LastSlash = NULL;
696 UINT NewStringLength = 0;
697
698 for( i = RegistryPath->Buffer;
699 i < RegistryPath->Buffer +
700 (RegistryPath->Length / sizeof(WCHAR));
701 i++ ) if( *i == '\\' ) LastSlash = i;
702
703 if( LastSlash ) LastSlash++; else LastSlash = RegistryPath->Buffer;
704
705 NewStringLength = RegistryPath->MaximumLength -
706 ((LastSlash - RegistryPath->Buffer) * sizeof(WCHAR));
707
708 TargetString->Buffer =
709 (PWCHAR)exAllocatePool( NonPagedPool, NewStringLength );
710
711 if( !TargetString->Buffer ) {
712 TargetString->Length = TargetString->MaximumLength = 0;
713 return;
714 }
715
716 TargetString->Length = TargetString->MaximumLength = NewStringLength;
717 RtlCopyMemory( TargetString->Buffer, LastSlash, NewStringLength );
718 }
719
720 VOID BindAdapter(
721 PLAN_ADAPTER Adapter,
722 PNDIS_STRING RegistryPath)
723 /*
724 * FUNCTION: Binds a LAN adapter to IP layer
725 * ARGUMENTS:
726 * Adapter = Pointer to LAN_ADAPTER structure
727 * NOTES:
728 * We set the lookahead buffer size, set the packet filter and
729 * bind the adapter to IP layer
730 */
731 {
732 PIP_INTERFACE IF;
733 NDIS_STATUS NdisStatus;
734 LLIP_BIND_INFO BindInfo;
735 IP_ADDRESS DefaultGateway, DefaultMask = { 0 };
736 ULONG Lookahead = LOOKAHEAD_SIZE;
737 NTSTATUS Status;
738 HANDLE RegHandle = 0;
739
740 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
741
742 Adapter->State = LAN_STATE_OPENING;
743
744 NdisStatus = NDISCall(Adapter,
745 NdisRequestSetInformation,
746 OID_GEN_CURRENT_LOOKAHEAD,
747 &Lookahead,
748 sizeof(ULONG));
749 if (NdisStatus != NDIS_STATUS_SUCCESS) {
750 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
751 return;
752 }
753
754 /* Bind the adapter to IP layer */
755 BindInfo.Context = Adapter;
756 BindInfo.HeaderSize = Adapter->HeaderSize;
757 BindInfo.MinFrameSize = Adapter->MinFrameSize;
758 BindInfo.MTU = Adapter->MTU;
759 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
760 BindInfo.AddressLength = Adapter->HWAddressLength;
761 BindInfo.Transmit = LANTransmit;
762
763 IF = IPCreateInterface(&BindInfo);
764
765 if (!IF) {
766 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
767 return;
768 }
769
770 /*
771 * Query per-adapter configuration from the registry
772 * In case anyone is curious: there *is* an Ndis configuration api
773 * for this sort of thing, but it doesn't really support things like
774 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
775 * protocol drivers developed for win2k and above just use the native
776 * services (ZwOpenKey, etc).
777 */
778
779 Status = OpenRegistryKey( RegistryPath, &RegHandle );
780
781 if(NT_SUCCESS(Status))
782 Status = ReadIPAddressFromRegistry( RegHandle, L"DefaultGateway",
783 &DefaultGateway );
784 if(!NT_SUCCESS(Status)) {
785 Status = STATUS_SUCCESS;
786 RtlZeroMemory( &DefaultGateway, sizeof(DefaultGateway) );
787 }
788
789 if(NT_SUCCESS(Status))
790 Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress",
791 &IF->Unicast );
792 if(NT_SUCCESS(Status))
793 Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask",
794 &IF->Netmask );
795 if(NT_SUCCESS(Status)) {
796 Status = ReadStringFromRegistry( RegHandle, L"DeviceDesc",
797 &IF->Name );
798
799 RtlZeroMemory( &IF->Name, sizeof( IF->Name ) );
800
801 /* I think that not getting a devicedesc is not a fatal error */
802 if( !NT_SUCCESS(Status) ) {
803 if( IF->Name.Buffer ) exFreePool( IF->Name.Buffer );
804 GetSimpleAdapterNameFromRegistryPath( &IF->Name, RegistryPath );
805 }
806 Status = STATUS_SUCCESS;
807 }
808
809 if(!NT_SUCCESS(Status))
810 {
811 TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
812
813 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
814 if(RegHandle)
815 ZwClose(RegHandle);
816 IPDestroyInterface(IF);
817 return;
818 }
819
820 TI_DbgPrint
821 (MID_TRACE,
822 ("--> Our IP address on this interface: '%s'\n",
823 A2S(&IF->Unicast)));
824
825 TI_DbgPrint
826 (MID_TRACE,
827 ("--> Our net mask on this interface: '%s'\n",
828 A2S(&IF->Netmask)));
829
830 if( DefaultGateway.Address.IPv4Address ) {
831 TI_DbgPrint
832 (MID_TRACE,
833 ("--> Our gateway is: '%s'\n",
834 A2S(&DefaultGateway)));
835
836 /* Create a default route */
837 RouterCreateRoute( &DefaultMask, /* Zero */
838 &DefaultMask, /* Zero */
839 &DefaultGateway,
840 IF,
841 1 );
842 }
843
844 /* Register interface with IP layer */
845 IPRegisterInterface(IF);
846
847 /* Set packet filter so we can send and receive packets */
848 NdisStatus = NDISCall(Adapter,
849 NdisRequestSetInformation,
850 OID_GEN_CURRENT_PACKET_FILTER,
851 &Adapter->PacketFilter,
852 sizeof(UINT));
853 if (NdisStatus != NDIS_STATUS_SUCCESS) {
854 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
855 IPDestroyInterface(IF);
856 return;
857 }
858
859 Adapter->Context = IF;
860 Adapter->State = LAN_STATE_STARTED;
861 }
862
863
864 VOID UnbindAdapter(
865 PLAN_ADAPTER Adapter)
866 /*
867 * FUNCTION: Unbinds a LAN adapter from IP layer
868 * ARGUMENTS:
869 * Adapter = Pointer to LAN_ADAPTER structure
870 */
871 {
872 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
873
874 if (Adapter->State == LAN_STATE_STARTED) {
875 PIP_INTERFACE IF = Adapter->Context;
876
877 IPUnregisterInterface(IF);
878
879 IPDestroyInterface(IF);
880 }
881 }
882
883
884 NDIS_STATUS LANRegisterAdapter(
885 PNDIS_STRING AdapterName,
886 PNDIS_STRING RegistryPath)
887 /*
888 * FUNCTION: Registers protocol with an NDIS adapter
889 * ARGUMENTS:
890 * AdapterName = Pointer to string with name of adapter to register
891 * Adapter = Address of pointer to a LAN_ADAPTER structure
892 * RETURNS:
893 * Status of operation
894 */
895 {
896 PLAN_ADAPTER IF;
897 NDIS_STATUS NdisStatus;
898 NDIS_STATUS OpenStatus;
899 UINT MediaIndex;
900 NDIS_MEDIUM MediaArray[MAX_MEDIA];
901 UINT AddressOID;
902 UINT Speed;
903
904 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
905
906 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
907 if (!IF) {
908 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
909 return NDIS_STATUS_RESOURCES;
910 }
911
912 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
913
914 /* Put adapter in stopped state */
915 IF->State = LAN_STATE_STOPPED;
916
917 /* Initialize protecting spin lock */
918 KeInitializeSpinLock(&IF->Lock);
919
920 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
921
922 /* Initialize array with media IDs we support */
923 MediaArray[MEDIA_ETH] = NdisMedium802_3;
924
925 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
926 /* Open the adapter. */
927 NdisOpenAdapter(&NdisStatus,
928 &OpenStatus,
929 &IF->NdisHandle,
930 &MediaIndex,
931 MediaArray,
932 MAX_MEDIA,
933 NdisProtocolHandle,
934 IF,
935 AdapterName,
936 0,
937 NULL);
938
939 /* Wait until the adapter is opened */
940 if (NdisStatus == NDIS_STATUS_PENDING)
941 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
942 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
943 exFreePool(IF);
944 return NdisStatus;
945 }
946
947 IF->Media = MediaArray[MediaIndex];
948
949 /* Fill LAN_ADAPTER structure with some adapter specific information */
950 switch (IF->Media) {
951 case NdisMedium802_3:
952 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
953 IF->BCastMask = BCAST_ETH_MASK;
954 IF->BCastCheck = BCAST_ETH_CHECK;
955 IF->BCastOffset = BCAST_ETH_OFFSET;
956 IF->HeaderSize = sizeof(ETH_HEADER);
957 IF->MinFrameSize = 60;
958 AddressOID = OID_802_3_CURRENT_ADDRESS;
959 IF->PacketFilter =
960 NDIS_PACKET_TYPE_BROADCAST |
961 NDIS_PACKET_TYPE_DIRECTED |
962 NDIS_PACKET_TYPE_MULTICAST;
963 break;
964
965 default:
966 /* Unsupported media */
967 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
968 exFreePool(IF);
969 return NDIS_STATUS_NOT_SUPPORTED;
970 }
971
972 /* Get maximum frame size */
973 NdisStatus = NDISCall(IF,
974 NdisRequestQueryInformation,
975 OID_GEN_MAXIMUM_FRAME_SIZE,
976 &IF->MTU,
977 sizeof(UINT));
978 if (NdisStatus != NDIS_STATUS_SUCCESS) {
979 exFreePool(IF);
980 return NdisStatus;
981 }
982
983 /* Get maximum packet size */
984 NdisStatus = NDISCall(IF,
985 NdisRequestQueryInformation,
986 OID_GEN_MAXIMUM_TOTAL_SIZE,
987 &IF->MaxPacketSize,
988 sizeof(UINT));
989 if (NdisStatus != NDIS_STATUS_SUCCESS) {
990 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
991 exFreePool(IF);
992 return NdisStatus;
993 }
994
995 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
996 NdisStatus = NDISCall(IF,
997 NdisRequestQueryInformation,
998 OID_GEN_MAXIMUM_SEND_PACKETS,
999 &IF->MaxSendPackets,
1000 sizeof(UINT));
1001 if (NdisStatus != NDIS_STATUS_SUCCESS)
1002 /* Legacy NIC drivers may not support this query, if it fails we
1003 assume it can send at least one packet per call to NdisSend(Packets) */
1004 IF->MaxSendPackets = 1;
1005
1006 /* Get current hardware address */
1007 NdisStatus = NDISCall(IF,
1008 NdisRequestQueryInformation,
1009 AddressOID,
1010 &IF->HWAddress,
1011 IF->HWAddressLength);
1012 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1013 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1014 exFreePool(IF);
1015 return NdisStatus;
1016 }
1017
1018 /* Get maximum link speed */
1019 NdisStatus = NDISCall(IF,
1020 NdisRequestQueryInformation,
1021 OID_GEN_LINK_SPEED,
1022 &Speed,
1023 sizeof(UINT));
1024 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1025 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1026 exFreePool(IF);
1027 return NdisStatus;
1028 }
1029
1030 /* Convert returned link speed to bps (it is in 100bps increments) */
1031 IF->Speed = Speed * 100L;
1032
1033 /* Add adapter to the adapter list */
1034 ExInterlockedInsertTailList(&AdapterListHead,
1035 &IF->ListEntry,
1036 &AdapterListLock);
1037
1038 /* Bind adapter to IP layer */
1039 BindAdapter(IF, RegistryPath);
1040
1041 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1042
1043 return NDIS_STATUS_SUCCESS;
1044 }
1045
1046
1047 NDIS_STATUS LANUnregisterAdapter(
1048 PLAN_ADAPTER Adapter)
1049 /*
1050 * FUNCTION: Unregisters protocol with NDIS adapter
1051 * ARGUMENTS:
1052 * Adapter = Pointer to a LAN_ADAPTER structure
1053 * RETURNS:
1054 * Status of operation
1055 */
1056 {
1057 KIRQL OldIrql;
1058 NDIS_HANDLE NdisHandle;
1059 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1060
1061 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1062
1063 /* Unlink the adapter from the list */
1064 RemoveEntryList(&Adapter->ListEntry);
1065
1066 /* Unbind adapter from IP layer */
1067 UnbindAdapter(Adapter);
1068
1069 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1070 NdisHandle = Adapter->NdisHandle;
1071 if (NdisHandle) {
1072 Adapter->NdisHandle = NULL;
1073 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1074
1075 NdisCloseAdapter(&NdisStatus, NdisHandle);
1076 if (NdisStatus == NDIS_STATUS_PENDING) {
1077 TcpipWaitForSingleObject(&Adapter->Event,
1078 UserRequest,
1079 KernelMode,
1080 FALSE,
1081 NULL);
1082 NdisStatus = Adapter->NdisStatus;
1083 }
1084 } else
1085 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1086
1087 FreeAdapter(Adapter);
1088
1089 return NDIS_STATUS_SUCCESS;
1090 }
1091
1092
1093 NTSTATUS LANRegisterProtocol(
1094 PNDIS_STRING Name)
1095 /*
1096 * FUNCTION: Registers this protocol driver with NDIS
1097 * ARGUMENTS:
1098 * Name = Name of this protocol driver
1099 * RETURNS:
1100 * Status of operation
1101 */
1102 {
1103 NDIS_STATUS NdisStatus;
1104 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1105
1106 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1107
1108 InitializeListHead(&AdapterListHead);
1109 KeInitializeSpinLock(&AdapterListLock);
1110
1111 /* Set up protocol characteristics */
1112 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1113 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1114 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1115 ProtChars.Name.Length = Name->Length;
1116 ProtChars.Name.Buffer = Name->Buffer;
1117 ProtChars.Name.MaximumLength = Name->MaximumLength;
1118 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1119 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1120 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1121 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1122 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1123 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1124 ProtChars.ReceiveHandler = ProtocolReceive;
1125 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1126 ProtChars.StatusHandler = ProtocolStatus;
1127 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1128 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1129
1130 /* Try to register protocol */
1131 NdisRegisterProtocol(&NdisStatus,
1132 &NdisProtocolHandle,
1133 &ProtChars,
1134 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1135 if (NdisStatus != NDIS_STATUS_SUCCESS)
1136 {
1137 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1138 return (NTSTATUS)NdisStatus;
1139 }
1140
1141 ProtocolRegistered = TRUE;
1142
1143 return STATUS_SUCCESS;
1144 }
1145
1146
1147 VOID LANUnregisterProtocol(
1148 VOID)
1149 /*
1150 * FUNCTION: Unregisters this protocol driver with NDIS
1151 * NOTES: Does not care wether we are already registered
1152 */
1153 {
1154 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1155
1156 if (ProtocolRegistered) {
1157 NDIS_STATUS NdisStatus;
1158 PLIST_ENTRY CurrentEntry;
1159 PLIST_ENTRY NextEntry;
1160 PLAN_ADAPTER Current;
1161 KIRQL OldIrql;
1162
1163 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1164
1165 /* Search the list and remove every adapter we find */
1166 CurrentEntry = AdapterListHead.Flink;
1167 while (CurrentEntry != &AdapterListHead) {
1168 NextEntry = CurrentEntry->Flink;
1169 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1170 /* Unregister it */
1171 LANUnregisterAdapter(Current);
1172 CurrentEntry = NextEntry;
1173 }
1174
1175 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1176
1177 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1178 ProtocolRegistered = FALSE;
1179 }
1180 }
1181
1182 VOID LANStartup() {
1183 InitializeListHead( &LanWorkList );
1184 ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
1185 }
1186
1187 VOID LANShutdown() {
1188 KIRQL OldIrql;
1189 PLAN_WQ_ITEM WorkItem;
1190 PLIST_ENTRY ListEntry;
1191
1192 TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
1193 while( !IsListEmpty( &LanWorkList ) ) {
1194 ListEntry = RemoveHeadList( &LanWorkList );
1195 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1196 FreeNdisPacket( WorkItem->Packet );
1197 ExFreePool( WorkItem );
1198 }
1199 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
1200 }
1201
1202 /* EOF */