Synchronize with trunk revision 59781.
[reactos.git] / drivers / network / 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 UINT TransferDataCalled = 0;
14 UINT TransferDataCompleteCalled = 0;
15
16 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
17 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
18
19 typedef struct _LAN_WQ_ITEM {
20 LIST_ENTRY ListEntry;
21 PNDIS_PACKET Packet;
22 PLAN_ADAPTER Adapter;
23 UINT BytesTransferred;
24 BOOLEAN LegacyReceive;
25 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
26
27 typedef struct _RECONFIGURE_CONTEXT {
28 ULONG State;
29 PLAN_ADAPTER Adapter;
30 } RECONFIGURE_CONTEXT, *PRECONFIGURE_CONTEXT;
31
32 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
33 BOOLEAN ProtocolRegistered = FALSE;
34 LIST_ENTRY AdapterListHead;
35 KSPIN_LOCK AdapterListLock;
36
37 NDIS_STATUS NDISCall(
38 PLAN_ADAPTER Adapter,
39 NDIS_REQUEST_TYPE Type,
40 NDIS_OID OID,
41 PVOID Buffer,
42 UINT Length)
43 /*
44 * FUNCTION: Send a request to NDIS
45 * ARGUMENTS:
46 * Adapter = Pointer to a LAN_ADAPTER structure
47 * Type = Type of request (Set or Query)
48 * OID = Value to be set/queried for
49 * Buffer = Pointer to a buffer to use
50 * Length = Number of bytes in Buffer
51 * RETURNS:
52 * Status of operation
53 */
54 {
55 NDIS_REQUEST Request;
56 NDIS_STATUS NdisStatus;
57
58 Request.RequestType = Type;
59 if (Type == NdisRequestSetInformation) {
60 Request.DATA.SET_INFORMATION.Oid = OID;
61 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
62 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
63 } else {
64 Request.DATA.QUERY_INFORMATION.Oid = OID;
65 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
66 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
67 }
68
69 if (Adapter->State != LAN_STATE_RESETTING) {
70 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
71 } else {
72 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
73 }
74
75 /* Wait for NDIS to complete the request */
76 if (NdisStatus == NDIS_STATUS_PENDING) {
77 KeWaitForSingleObject(&Adapter->Event,
78 UserRequest,
79 KernelMode,
80 FALSE,
81 NULL);
82 NdisStatus = Adapter->NdisStatus;
83 }
84
85 return NdisStatus;
86 }
87
88 /* Used by legacy ProtocolReceive for packet type */
89 NDIS_STATUS
90 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter,
91 PVOID HeaderBuffer,
92 ULONG HeaderBufferSize,
93 PULONG PacketType)
94 {
95 PETH_HEADER EthHeader = HeaderBuffer;
96
97 if (HeaderBufferSize < Adapter->HeaderSize)
98 {
99 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", HeaderBufferSize));
100 return NDIS_STATUS_NOT_ACCEPTED;
101 }
102
103 switch (Adapter->Media)
104 {
105 case NdisMedium802_3:
106 /* Ethernet and IEEE 802.3 frames can be destinguished by
107 looking at the IEEE 802.3 length field. This field is
108 less than or equal to 1500 for a valid IEEE 802.3 frame
109 and larger than 1500 is it's a valid EtherType value.
110 See RFC 1122, section 2.3.3 for more information */
111
112 *PacketType = EthHeader->EType;
113 break;
114
115 default:
116 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
117
118 /* FIXME: Support other medias */
119 return NDIS_STATUS_NOT_ACCEPTED;
120 }
121
122 TI_DbgPrint(DEBUG_DATALINK, ("EtherType (0x%X).\n", *PacketType));
123
124 return NDIS_STATUS_SUCCESS;
125 }
126
127 /* Used by ProtocolReceivePacket for packet type */
128 NDIS_STATUS
129 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter,
130 PNDIS_PACKET NdisPacket,
131 PULONG PacketType)
132 {
133 PVOID HeaderBuffer;
134 ULONG BytesCopied;
135 NDIS_STATUS Status;
136
137 HeaderBuffer = ExAllocatePool(NonPagedPool,
138 Adapter->HeaderSize);
139 if (!HeaderBuffer)
140 return NDIS_STATUS_RESOURCES;
141
142 /* Copy the media header */
143 BytesCopied = CopyPacketToBuffer(HeaderBuffer,
144 NdisPacket,
145 0,
146 Adapter->HeaderSize);
147 if (BytesCopied != Adapter->HeaderSize)
148 {
149 /* Runt frame */
150 ExFreePool(HeaderBuffer);
151 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied));
152 return NDIS_STATUS_NOT_ACCEPTED;
153 }
154
155 Status = GetPacketTypeFromHeaderBuffer(Adapter,
156 HeaderBuffer,
157 BytesCopied,
158 PacketType);
159
160 ExFreePool(HeaderBuffer);
161
162 return Status;
163 }
164
165
166 VOID FreeAdapter(
167 PLAN_ADAPTER Adapter)
168 /*
169 * FUNCTION: Frees memory for a LAN_ADAPTER structure
170 * ARGUMENTS:
171 * Adapter = Pointer to LAN_ADAPTER structure to free
172 */
173 {
174 ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG);
175 }
176
177
178 NTSTATUS TcpipLanGetDwordOid
179 ( PIP_INTERFACE Interface,
180 NDIS_OID Oid,
181 PULONG Result ) {
182 /* Get maximum frame size */
183 if( Interface->Context ) {
184 return NDISCall((PLAN_ADAPTER)Interface->Context,
185 NdisRequestQueryInformation,
186 Oid,
187 Result,
188 sizeof(ULONG));
189 } else switch( Oid ) { /* Loopback Case */
190 case OID_GEN_HARDWARE_STATUS:
191 *Result = NdisHardwareStatusReady;
192 return STATUS_SUCCESS;
193 case OID_GEN_MEDIA_CONNECT_STATUS:
194 *Result = NdisMediaStateConnected;
195 return STATUS_SUCCESS;
196 default:
197 return STATUS_INVALID_PARAMETER;
198 }
199 }
200
201
202 VOID NTAPI ProtocolOpenAdapterComplete(
203 NDIS_HANDLE BindingContext,
204 NDIS_STATUS Status,
205 NDIS_STATUS OpenErrorStatus)
206 /*
207 * FUNCTION: Called by NDIS to complete opening of an adapter
208 * ARGUMENTS:
209 * BindingContext = Pointer to a device context (LAN_ADAPTER)
210 * Status = Status of the operation
211 * OpenErrorStatus = Additional status information
212 */
213 {
214 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
215
216 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
217
218 Adapter->NdisStatus = Status;
219
220 KeSetEvent(&Adapter->Event, 0, FALSE);
221 }
222
223
224 VOID NTAPI ProtocolCloseAdapterComplete(
225 NDIS_HANDLE BindingContext,
226 NDIS_STATUS Status)
227 /*
228 * FUNCTION: Called by NDIS to complete closing an adapter
229 * ARGUMENTS:
230 * BindingContext = Pointer to a device context (LAN_ADAPTER)
231 * Status = Status of the operation
232 */
233 {
234 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
235
236 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
237
238 Adapter->NdisStatus = Status;
239
240 KeSetEvent(&Adapter->Event, 0, FALSE);
241 }
242
243
244 VOID NTAPI ProtocolResetComplete(
245 NDIS_HANDLE BindingContext,
246 NDIS_STATUS Status)
247 /*
248 * FUNCTION: Called by NDIS to complete resetting an adapter
249 * ARGUMENTS:
250 * BindingContext = Pointer to a device context (LAN_ADAPTER)
251 * Status = Status of the operation
252 */
253 {
254 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
255
256 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
257
258 Adapter->NdisStatus = Status;
259
260 KeSetEvent(&Adapter->Event, 0, FALSE);
261 }
262
263
264 VOID NTAPI ProtocolRequestComplete(
265 NDIS_HANDLE BindingContext,
266 PNDIS_REQUEST NdisRequest,
267 NDIS_STATUS Status)
268 /*
269 * FUNCTION: Called by NDIS to complete a request
270 * ARGUMENTS:
271 * BindingContext = Pointer to a device context (LAN_ADAPTER)
272 * NdisRequest = Pointer to an object describing the request
273 * Status = Status of the operation
274 */
275 {
276 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
277
278 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
279
280 /* Save status of request and signal an event */
281 Adapter->NdisStatus = Status;
282
283 KeSetEvent(&Adapter->Event, 0, FALSE);
284 }
285
286
287 VOID NTAPI ProtocolSendComplete(
288 NDIS_HANDLE BindingContext,
289 PNDIS_PACKET Packet,
290 NDIS_STATUS Status)
291 /*
292 * FUNCTION: Called by NDIS to complete sending process
293 * ARGUMENTS:
294 * BindingContext = Pointer to a device context (LAN_ADAPTER)
295 * Packet = Pointer to a packet descriptor
296 * Status = Status of the operation
297 */
298 {
299 FreeNdisPacket(Packet);
300 }
301
302 VOID LanReceiveWorker( PVOID Context ) {
303 ULONG PacketType;
304 PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
305 PNDIS_PACKET Packet;
306 PLAN_ADAPTER Adapter;
307 UINT BytesTransferred;
308 IP_PACKET IPPacket;
309 BOOLEAN LegacyReceive;
310 PIP_INTERFACE Interface;
311
312 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
313
314 Packet = WorkItem->Packet;
315 Adapter = WorkItem->Adapter;
316 BytesTransferred = WorkItem->BytesTransferred;
317 LegacyReceive = WorkItem->LegacyReceive;
318
319 ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG);
320
321 Interface = Adapter->Context;
322
323 IPInitializePacket(&IPPacket, 0);
324
325 IPPacket.NdisPacket = Packet;
326 IPPacket.ReturnPacket = !LegacyReceive;
327
328 if (LegacyReceive)
329 {
330 /* Packet type is precomputed */
331 PacketType = PC(IPPacket.NdisPacket)->PacketType;
332
333 /* Data is at position 0 */
334 IPPacket.Position = 0;
335
336 /* Packet size is determined by bytes transferred */
337 IPPacket.TotalSize = BytesTransferred;
338 }
339 else
340 {
341 /* Determine packet type from media header */
342 if (GetPacketTypeFromNdisPacket(Adapter,
343 IPPacket.NdisPacket,
344 &PacketType) != NDIS_STATUS_SUCCESS)
345 {
346 /* Bad packet */
347 IPPacket.Free(&IPPacket);
348 return;
349 }
350
351 /* Data is at the end of the media header */
352 IPPacket.Position = Adapter->HeaderSize;
353
354 /* Calculate packet size (excluding media header) */
355 NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize);
356 }
357
358 TI_DbgPrint
359 (DEBUG_DATALINK,
360 ("Ether Type = %x Total = %d\n",
361 PacketType, IPPacket.TotalSize));
362
363 /* Update interface stats */
364 Interface->Stats.InBytes += IPPacket.TotalSize + Adapter->HeaderSize;
365
366 /* NDIS packet is freed in all of these cases */
367 switch (PacketType) {
368 case ETYPE_IPv4:
369 case ETYPE_IPv6:
370 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
371 IPReceive(Adapter->Context, &IPPacket);
372 break;
373 case ETYPE_ARP:
374 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
375 ARPReceive(Adapter->Context, &IPPacket);
376 break;
377 default:
378 IPPacket.Free(&IPPacket);
379 break;
380 }
381 }
382
383 VOID LanSubmitReceiveWork(
384 NDIS_HANDLE BindingContext,
385 PNDIS_PACKET Packet,
386 UINT BytesTransferred,
387 BOOLEAN LegacyReceive) {
388 PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
389 WQ_CONTEXT_TAG);
390 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
391
392 TI_DbgPrint(DEBUG_DATALINK,("called\n"));
393
394 if (!WQItem) return;
395
396 WQItem->Packet = Packet;
397 WQItem->Adapter = Adapter;
398 WQItem->BytesTransferred = BytesTransferred;
399 WQItem->LegacyReceive = LegacyReceive;
400
401 if (!ChewCreate( LanReceiveWorker, WQItem ))
402 ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
403 }
404
405 VOID NTAPI ProtocolTransferDataComplete(
406 NDIS_HANDLE BindingContext,
407 PNDIS_PACKET Packet,
408 NDIS_STATUS Status,
409 UINT BytesTransferred)
410 /*
411 * FUNCTION: Called by NDIS to complete reception of data
412 * ARGUMENTS:
413 * BindingContext = Pointer to a device context (LAN_ADAPTER)
414 * Packet = Pointer to a packet descriptor
415 * Status = Status of the operation
416 * BytesTransferred = Number of bytes transferred
417 * NOTES:
418 * If the packet was successfully received, determine the protocol
419 * type and pass it to the correct receive handler
420 */
421 {
422 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
423
424 TI_DbgPrint(DEBUG_DATALINK,("called\n"));
425
426 TransferDataCompleteCalled++;
427 ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
428
429 if( Status != NDIS_STATUS_SUCCESS ) return;
430
431 LanSubmitReceiveWork(BindingContext,
432 Packet,
433 BytesTransferred,
434 TRUE);
435 }
436
437 INT NTAPI ProtocolReceivePacket(
438 NDIS_HANDLE BindingContext,
439 PNDIS_PACKET NdisPacket)
440 {
441 PLAN_ADAPTER Adapter = BindingContext;
442
443 if (Adapter->State != LAN_STATE_STARTED) {
444 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
445 return 0;
446 }
447
448 LanSubmitReceiveWork(BindingContext,
449 NdisPacket,
450 0, /* Unused */
451 FALSE);
452
453 /* Hold 1 reference on this packet */
454 return 1;
455 }
456
457 NDIS_STATUS NTAPI ProtocolReceive(
458 NDIS_HANDLE BindingContext,
459 NDIS_HANDLE MacReceiveContext,
460 PVOID HeaderBuffer,
461 UINT HeaderBufferSize,
462 PVOID LookaheadBuffer,
463 UINT LookaheadBufferSize,
464 UINT PacketSize)
465 /*
466 * FUNCTION: Called by NDIS when a packet has been received on the physical link
467 * ARGUMENTS:
468 * BindingContext = Pointer to a device context (LAN_ADAPTER)
469 * MacReceiveContext = Handle used by underlying NIC driver
470 * HeaderBuffer = Pointer to a buffer containing the packet header
471 * HeaderBufferSize = Number of bytes in HeaderBuffer
472 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
473 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
474 * PacketSize = Overall size of the packet (not including header)
475 * RETURNS:
476 * Status of operation
477 */
478 {
479 ULONG PacketType;
480 UINT BytesTransferred;
481 PCHAR BufferData;
482 NDIS_STATUS NdisStatus;
483 PNDIS_PACKET NdisPacket;
484 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
485
486 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
487
488 if (Adapter->State != LAN_STATE_STARTED) {
489 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
490 return NDIS_STATUS_NOT_ACCEPTED;
491 }
492
493 if (HeaderBufferSize < Adapter->HeaderSize) {
494 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
495 return NDIS_STATUS_NOT_ACCEPTED;
496 }
497
498 NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter,
499 HeaderBuffer,
500 HeaderBufferSize,
501 &PacketType);
502 if (NdisStatus != NDIS_STATUS_SUCCESS)
503 return NDIS_STATUS_NOT_ACCEPTED;
504
505 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
506 Adapter, Adapter->MTU));
507
508 /* Get a transfer data packet */
509 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
510 PacketSize );
511 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
512 return NDIS_STATUS_NOT_ACCEPTED;
513 }
514
515 PC(NdisPacket)->PacketType = PacketType;
516
517 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
518
519 GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize );
520
521 TransferDataCalled++;
522
523 if (LookaheadBufferSize == PacketSize)
524 {
525 /* Optimized code path for packets that are fully contained in
526 * the lookahead buffer. */
527 NdisCopyLookaheadData(BufferData,
528 LookaheadBuffer,
529 LookaheadBufferSize,
530 Adapter->MacOptions);
531 }
532 else
533 {
534 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
535 MacReceiveContext, 0, PacketSize,
536 NdisPacket, &BytesTransferred);
537 }
538 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
539
540 if (NdisStatus != NDIS_STATUS_PENDING)
541 ProtocolTransferDataComplete(BindingContext,
542 NdisPacket,
543 NdisStatus,
544 PacketSize);
545
546 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
547
548 return NDIS_STATUS_SUCCESS;
549 }
550
551
552 VOID NTAPI ProtocolReceiveComplete(
553 NDIS_HANDLE BindingContext)
554 /*
555 * FUNCTION: Called by NDIS when we're done receiving data
556 * ARGUMENTS:
557 * BindingContext = Pointer to a device context (LAN_ADAPTER)
558 */
559 {
560 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
561 }
562
563 BOOLEAN ReadIpConfiguration(PIP_INTERFACE Interface)
564 {
565 OBJECT_ATTRIBUTES ObjectAttributes;
566 HANDLE ParameterHandle;
567 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
568 WCHAR Buffer[150];
569 UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress");
570 UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask");
571 UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway");
572 UNICODE_STRING EnableDhcp = RTL_CONSTANT_STRING(L"EnableDHCP");
573 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
574 UNICODE_STRING TcpipRegistryPath;
575 UNICODE_STRING RegistryDataU;
576 ANSI_STRING RegistryDataA;
577 ULONG Unused;
578 NTSTATUS Status;
579 IP_ADDRESS DefaultMask, Router;
580
581 AddrInitIPv4(&DefaultMask, 0);
582
583 TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150;
584 TcpipRegistryPath.Length = 0;
585 TcpipRegistryPath.Buffer = Buffer;
586
587 /* Build the registry path */
588 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Prefix);
589 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Interface->Name);
590
591 InitializeObjectAttributes(&ObjectAttributes,
592 &TcpipRegistryPath,
593 OBJ_CASE_INSENSITIVE,
594 0,
595 NULL);
596
597 /* Open a handle to the adapter parameters */
598 Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
599
600 if (!NT_SUCCESS(Status))
601 {
602 return FALSE;
603 }
604 else
605 {
606 KeyValueInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR));
607 if (!KeyValueInfo)
608 {
609 ZwClose(ParameterHandle);
610 return FALSE;
611 }
612
613 /* Read the EnableDHCP entry */
614 Status = ZwQueryValueKey(ParameterHandle,
615 &EnableDhcp,
616 KeyValuePartialInformation,
617 KeyValueInfo,
618 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
619 &Unused);
620 if (NT_SUCCESS(Status) && KeyValueInfo->DataLength == sizeof(ULONG) && (*(PULONG)KeyValueInfo->Data) == 0)
621 {
622 RegistryDataU.MaximumLength = 16 + sizeof(WCHAR);
623 RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data;
624
625 /* Read the IP address */
626 Status = ZwQueryValueKey(ParameterHandle,
627 &IPAddress,
628 KeyValuePartialInformation,
629 KeyValueInfo,
630 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
631 &Unused);
632 if (NT_SUCCESS(Status))
633 {
634 RegistryDataU.Length = KeyValueInfo->DataLength;
635
636 RtlUnicodeStringToAnsiString(&RegistryDataA,
637 &RegistryDataU,
638 TRUE);
639
640 AddrInitIPv4(&Interface->Unicast, inet_addr(RegistryDataA.Buffer));
641
642 RtlFreeAnsiString(&RegistryDataA);
643 }
644
645 Status = ZwQueryValueKey(ParameterHandle,
646 &Netmask,
647 KeyValuePartialInformation,
648 KeyValueInfo,
649 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
650 &Unused);
651 if (NT_SUCCESS(Status))
652 {
653 RegistryDataU.Length = KeyValueInfo->DataLength;
654
655 RtlUnicodeStringToAnsiString(&RegistryDataA,
656 &RegistryDataU,
657 TRUE);
658
659 AddrInitIPv4(&Interface->Netmask, inet_addr(RegistryDataA.Buffer));
660
661 RtlFreeAnsiString(&RegistryDataA);
662 }
663
664 /* We have to wait until both IP address and subnet mask
665 * are read to add the interface route, but we must do it
666 * before we add the default gateway */
667 if (!AddrIsUnspecified(&Interface->Unicast) &&
668 !AddrIsUnspecified(&Interface->Netmask))
669 IPAddInterfaceRoute(Interface);
670
671 /* Read default gateway info */
672 Status = ZwQueryValueKey(ParameterHandle,
673 &Gateway,
674 KeyValuePartialInformation,
675 KeyValueInfo,
676 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
677 &Unused);
678 if (NT_SUCCESS(Status))
679 {
680 RegistryDataU.Length = KeyValueInfo->DataLength;
681
682 RtlUnicodeStringToAnsiString(&RegistryDataA,
683 &RegistryDataU,
684 TRUE);
685
686 AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer));
687
688 if (!AddrIsUnspecified(&Router))
689 RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, Interface, 1);
690
691 RtlFreeAnsiString(&RegistryDataA);
692 }
693 }
694
695 ZwClose(ParameterHandle);
696 }
697
698 return TRUE;
699 }
700
701 BOOLEAN ReconfigureAdapter(PRECONFIGURE_CONTEXT Context)
702 {
703 PLAN_ADAPTER Adapter = Context->Adapter;
704 PIP_INTERFACE Interface = Adapter->Context;
705 //NDIS_STATUS NdisStatus;
706 IP_ADDRESS DefaultMask;
707
708 /* Initialize the default unspecified address (0.0.0.0) */
709 AddrInitIPv4(&DefaultMask, 0);
710 if (Context->State == LAN_STATE_STARTED &&
711 !Context->Adapter->CompletingReset)
712 {
713 /* Read the IP configuration */
714 ReadIpConfiguration(Interface);
715
716 /* Compute the broadcast address */
717 Interface->Broadcast.Type = IP_ADDRESS_V4;
718 Interface->Broadcast.Address.IPv4Address = Interface->Unicast.Address.IPv4Address |
719 ~Interface->Netmask.Address.IPv4Address;
720 }
721 else if (!Context->Adapter->CompletingReset)
722 {
723 /* Clear IP configuration */
724 Interface->Unicast = DefaultMask;
725 Interface->Netmask = DefaultMask;
726 Interface->Broadcast = DefaultMask;
727
728 /* Remove all interface routes */
729 RouterRemoveRoutesForInterface(Interface);
730
731 /* Destroy all cached neighbors */
732 NBDestroyNeighborsForInterface(Interface);
733 }
734
735 Context->Adapter->CompletingReset = FALSE;
736
737 /* Update the IP and link status information cached in TCP */
738 TCPUpdateInterfaceIPInformation(Interface);
739 TCPUpdateInterfaceLinkStatus(Interface);
740
741 /* We're done here if the adapter isn't connected */
742 if (Context->State != LAN_STATE_STARTED)
743 {
744 Adapter->State = Context->State;
745 return TRUE;
746 }
747
748 /* NDIS Bug! */
749 #if 0
750 /* Get maximum link speed */
751 NdisStatus = NDISCall(Adapter,
752 NdisRequestQueryInformation,
753 OID_GEN_LINK_SPEED,
754 &Interface->Speed,
755 sizeof(UINT));
756
757 if (!NT_SUCCESS(NdisStatus))
758 Interface->Speed = IP_DEFAULT_LINK_SPEED;
759
760 Adapter->Speed = Interface->Speed * 100L;
761
762 /* Get maximum frame size */
763 NdisStatus = NDISCall(Adapter,
764 NdisRequestQueryInformation,
765 OID_GEN_MAXIMUM_FRAME_SIZE,
766 &Adapter->MTU,
767 sizeof(UINT));
768 if (NdisStatus != NDIS_STATUS_SUCCESS)
769 return FALSE;
770
771 Interface->MTU = Adapter->MTU;
772
773 /* Get maximum packet size */
774 NdisStatus = NDISCall(Adapter,
775 NdisRequestQueryInformation,
776 OID_GEN_MAXIMUM_TOTAL_SIZE,
777 &Adapter->MaxPacketSize,
778 sizeof(UINT));
779 if (NdisStatus != NDIS_STATUS_SUCCESS)
780 return FALSE;
781 #endif
782
783 Adapter->State = Context->State;
784
785 return TRUE;
786 }
787
788 VOID ReconfigureAdapterWorker(PVOID Context)
789 {
790 PRECONFIGURE_CONTEXT ReconfigureContext = Context;
791
792 /* Complete the reconfiguration asynchronously */
793 ReconfigureAdapter(ReconfigureContext);
794
795 /* Free the context */
796 ExFreePool(ReconfigureContext);
797 }
798
799 VOID NTAPI ProtocolStatus(
800 NDIS_HANDLE BindingContext,
801 NDIS_STATUS GeneralStatus,
802 PVOID StatusBuffer,
803 UINT StatusBufferSize)
804 /*
805 * FUNCTION: Called by NDIS when the underlying driver has changed state
806 * ARGUMENTS:
807 * BindingContext = Pointer to a device context (LAN_ADAPTER)
808 * GeneralStatus = A general status code
809 * StatusBuffer = Pointer to a buffer with medium-specific data
810 * StatusBufferSize = Number of bytes in StatusBuffer
811 */
812 {
813 PLAN_ADAPTER Adapter = BindingContext;
814 PRECONFIGURE_CONTEXT Context;
815
816 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
817
818 /* Ignore the status indication if we have no context yet. We'll get another later */
819 if (!Adapter->Context)
820 return;
821
822 Context = ExAllocatePool(NonPagedPool, sizeof(RECONFIGURE_CONTEXT));
823 if (!Context)
824 return;
825
826 Context->Adapter = Adapter;
827
828 switch(GeneralStatus)
829 {
830 case NDIS_STATUS_MEDIA_CONNECT:
831 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
832
833 if (Adapter->State == LAN_STATE_STARTED)
834 {
835 ExFreePool(Context);
836 return;
837 }
838
839 Context->State = LAN_STATE_STARTED;
840 break;
841
842 case NDIS_STATUS_MEDIA_DISCONNECT:
843 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
844
845 if (Adapter->State == LAN_STATE_STOPPED)
846 {
847 ExFreePool(Context);
848 return;
849 }
850
851 Context->State = LAN_STATE_STOPPED;
852 break;
853
854 case NDIS_STATUS_RESET_START:
855 Adapter->OldState = Adapter->State;
856 Adapter->State = LAN_STATE_RESETTING;
857 /* Nothing else to do here */
858 ExFreePool(Context);
859 return;
860
861 case NDIS_STATUS_RESET_END:
862 Adapter->CompletingReset = TRUE;
863 Context->State = Adapter->OldState;
864 break;
865
866 default:
867 DbgPrint("Unhandled status: %x", GeneralStatus);
868 ExFreePool(Context);
869 return;
870 }
871
872 /* Queue the work item */
873 if (!ChewCreate(ReconfigureAdapterWorker, Context))
874 ExFreePool(Context);
875 }
876
877 VOID NTAPI ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext)
878 /*
879 * FUNCTION: Called by NDIS when a status-change has occurred
880 * ARGUMENTS:
881 * BindingContext = Pointer to a device context (LAN_ADAPTER)
882 */
883 {
884 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
885 }
886
887 NDIS_STATUS NTAPI
888 ProtocolPnPEvent(
889 NDIS_HANDLE NdisBindingContext,
890 PNET_PNP_EVENT PnPEvent)
891 {
892 switch(PnPEvent->NetEvent)
893 {
894 case NetEventSetPower:
895 DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer);
896 return NDIS_STATUS_SUCCESS;
897
898 case NetEventQueryPower:
899 DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer);
900 return NDIS_STATUS_SUCCESS;
901
902 case NetEventQueryRemoveDevice:
903 DbgPrint("Device is about to be removed\n");
904 return NDIS_STATUS_SUCCESS;
905
906 case NetEventCancelRemoveDevice:
907 DbgPrint("Device removal cancelled\n");
908 return NDIS_STATUS_SUCCESS;
909
910 default:
911 DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent);
912 return NDIS_STATUS_SUCCESS;
913 }
914 }
915
916 VOID NTAPI ProtocolBindAdapter(
917 OUT PNDIS_STATUS Status,
918 IN NDIS_HANDLE BindContext,
919 IN PNDIS_STRING DeviceName,
920 IN PVOID SystemSpecific1,
921 IN PVOID SystemSpecific2)
922 /*
923 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
924 * bindings, and periodically thereafer as new adapters come online
925 * ARGUMENTS:
926 * Status: Return value to NDIS
927 * BindContext: Handle provided by NDIS to track pending binding operations
928 * DeviceName: Name of the miniport device to bind to
929 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
930 * SystemSpecific2: Unused & must not be touched
931 */
932 {
933 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
934 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
935 }
936
937
938 VOID LANTransmit(
939 PVOID Context,
940 PNDIS_PACKET NdisPacket,
941 UINT Offset,
942 PVOID LinkAddress,
943 USHORT Type)
944 /*
945 * FUNCTION: Transmits a packet
946 * ARGUMENTS:
947 * Context = Pointer to context information (LAN_ADAPTER)
948 * NdisPacket = Pointer to NDIS packet to send
949 * Offset = Offset in packet where data starts
950 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
951 * Type = LAN protocol type (LAN_PROTO_*)
952 */
953 {
954 NDIS_STATUS NdisStatus;
955 PETH_HEADER EHeader;
956 PCHAR Data, OldData;
957 UINT Size, OldSize;
958 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
959 KIRQL OldIrql;
960 PNDIS_PACKET XmitPacket;
961 PIP_INTERFACE Interface = Adapter->Context;
962
963 TI_DbgPrint(DEBUG_DATALINK,
964 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
965 NdisPacket, Offset, Adapter));
966
967 if (Adapter->State != LAN_STATE_STARTED) {
968 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
969 return;
970 }
971
972 TI_DbgPrint(DEBUG_DATALINK,
973 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
974 Adapter->HWAddress[0] & 0xff,
975 Adapter->HWAddress[1] & 0xff,
976 Adapter->HWAddress[2] & 0xff,
977 Adapter->HWAddress[3] & 0xff,
978 Adapter->HWAddress[4] & 0xff,
979 Adapter->HWAddress[5] & 0xff));
980
981 GetDataPtr( NdisPacket, 0, &OldData, &OldSize );
982
983 NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize);
984 if (NdisStatus != NDIS_STATUS_SUCCESS) {
985 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES);
986 return;
987 }
988
989 GetDataPtr(XmitPacket, 0, &Data, &Size);
990
991 RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize);
992
993 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
994
995 switch (Adapter->Media) {
996 case NdisMedium802_3:
997 EHeader = (PETH_HEADER)Data;
998
999 if (LinkAddress) {
1000 /* Unicast address */
1001 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
1002 } else {
1003 /* Broadcast address */
1004 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
1005 }
1006
1007 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
1008
1009 switch (Type) {
1010 case LAN_PROTO_IPv4:
1011 EHeader->EType = ETYPE_IPv4;
1012 break;
1013 case LAN_PROTO_ARP:
1014 EHeader->EType = ETYPE_ARP;
1015 break;
1016 case LAN_PROTO_IPv6:
1017 EHeader->EType = ETYPE_IPv6;
1018 break;
1019 default:
1020 ASSERT(FALSE);
1021 return;
1022 }
1023 break;
1024
1025 default:
1026 /* FIXME: Support other medias */
1027 break;
1028 }
1029
1030 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
1031 if( LinkAddress ) {
1032 TI_DbgPrint
1033 ( MID_TRACE,
1034 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
1035 ((PCHAR)LinkAddress)[0] & 0xff,
1036 ((PCHAR)LinkAddress)[1] & 0xff,
1037 ((PCHAR)LinkAddress)[2] & 0xff,
1038 ((PCHAR)LinkAddress)[3] & 0xff,
1039 ((PCHAR)LinkAddress)[4] & 0xff,
1040 ((PCHAR)LinkAddress)[5] & 0xff));
1041 }
1042
1043 if (Adapter->MTU < Size) {
1044 /* This is NOT a pointer. MSDN explicitly says so. */
1045 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket,
1046 TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU);
1047 }
1048
1049 /* Update interface stats */
1050 Interface->Stats.OutBytes += Size;
1051
1052 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
1053 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
1054 NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket);
1055 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
1056 NdisStatus == NDIS_STATUS_PENDING ?
1057 "Pending" : "Complete"));
1058 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
1059
1060 /* I had a talk with vizzini: these really ought to be here.
1061 * we're supposed to see these completed by ndis *only* when
1062 * status_pending is returned. Note that this is different from
1063 * the situation with IRPs. */
1064 if (NdisStatus != NDIS_STATUS_PENDING)
1065 ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus);
1066 }
1067
1068 static NTSTATUS
1069 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
1070 OBJECT_ATTRIBUTES Attributes;
1071 NTSTATUS Status;
1072
1073 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
1074 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
1075 return Status;
1076 }
1077
1078 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
1079 PWCHAR RegistryValue,
1080 PUNICODE_STRING String ) {
1081 UNICODE_STRING ValueName;
1082 UNICODE_STRING UnicodeString;
1083 NTSTATUS Status;
1084 ULONG ResultLength;
1085 UCHAR buf[1024];
1086 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
1087
1088 RtlInitUnicodeString(&ValueName, RegistryValue);
1089 Status =
1090 ZwQueryValueKey(RegHandle,
1091 &ValueName,
1092 KeyValuePartialInformation,
1093 Information,
1094 sizeof(buf),
1095 &ResultLength);
1096
1097 if (!NT_SUCCESS(Status))
1098 return Status;
1099 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
1100 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
1101
1102 UnicodeString.Buffer = (PWCHAR)&Information->Data;
1103 UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
1104 UnicodeString.MaximumLength = Information->DataLength;
1105
1106 String->Buffer =
1107 (PWCHAR)ExAllocatePool( NonPagedPool,
1108 UnicodeString.MaximumLength + sizeof(WCHAR) );
1109
1110 if( !String->Buffer ) return STATUS_NO_MEMORY;
1111
1112 String->MaximumLength = UnicodeString.MaximumLength;
1113 RtlCopyUnicodeString( String, &UnicodeString );
1114
1115 return STATUS_SUCCESS;
1116 }
1117
1118 /*
1119 * Utility to copy and append two unicode strings.
1120 *
1121 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
1122 * IN PUNICODE_STRING Second -> Second string to append
1123 * IN BOOL Deallocate -> TRUE: Deallocate First string before
1124 * overwriting.
1125 *
1126 * Returns NTSTATUS.
1127 */
1128
1129 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
1130 PUNICODE_STRING Second,
1131 BOOLEAN Deallocate) {
1132 NTSTATUS Status;
1133 UNICODE_STRING Ustr = *ResultFirst;
1134 PWSTR new_string = ExAllocatePool
1135 (PagedPool,
1136 (ResultFirst->Length + Second->Length + sizeof(WCHAR)));
1137 if( !new_string ) {
1138 return STATUS_NO_MEMORY;
1139 }
1140 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
1141 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
1142 Second->Buffer, Second->Length );
1143 if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
1144 ResultFirst->Length = Ustr.Length + Second->Length;
1145 ResultFirst->MaximumLength = ResultFirst->Length;
1146 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
1147 Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
1148 STATUS_SUCCESS : STATUS_NO_MEMORY;
1149 ExFreePool(new_string);
1150 return Status;
1151 }
1152
1153 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
1154 PUNICODE_STRING TargetKeyName,
1155 PUNICODE_STRING Name,
1156 PUNICODE_STRING DeviceDesc ) {
1157 UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
1158 UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
1159 UNICODE_STRING BackSlash = { 0, 0, NULL };
1160 HANDLE DescKey = NULL, LinkageKey = NULL;
1161 NTSTATUS Status;
1162
1163 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
1164
1165 RtlInitUnicodeString(&BackSlash, L"\\");
1166 RtlInitUnicodeString(&Linkage, L"\\Linkage");
1167
1168 RtlInitUnicodeString(&DescKeyName, L"");
1169 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
1170 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
1171 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
1172
1173 RtlInitUnicodeString(&LinkageKeyName, L"");
1174 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
1175 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
1176
1177 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
1178 if( !NT_SUCCESS(Status) ) goto cleanup;
1179
1180 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
1181 if( !NT_SUCCESS(Status) ) goto cleanup;
1182
1183 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
1184 Status = OpenRegistryKey( &DescKeyName, &DescKey );
1185 if( !NT_SUCCESS(Status) ) goto cleanup;
1186
1187 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
1188 if( !NT_SUCCESS(Status) ) goto cleanup;
1189
1190 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
1191 } else Status = STATUS_UNSUCCESSFUL;
1192
1193 cleanup:
1194 RtlFreeUnicodeString( &RootDevice );
1195 RtlFreeUnicodeString( &LinkageKeyName );
1196 RtlFreeUnicodeString( &DescKeyName );
1197 if( LinkageKey ) NtClose( LinkageKey );
1198 if( DescKey ) NtClose( DescKey );
1199
1200 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
1201
1202 return Status;
1203 }
1204
1205 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
1206 PUNICODE_STRING DeviceDesc ) {
1207 UNICODE_STRING EnumKeyName, TargetKeyName;
1208 HANDLE EnumKey;
1209 NTSTATUS Status;
1210 ULONG i;
1211 KEY_BASIC_INFORMATION *Kbio =
1212 ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
1213 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
1214
1215 RtlInitUnicodeString( DeviceDesc, NULL );
1216
1217 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
1218
1219 RtlInitUnicodeString
1220 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
1221
1222 Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
1223
1224 if( !NT_SUCCESS(Status) ) {
1225 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
1226 &EnumKeyName, Status));
1227 ExFreePool( Kbio );
1228 return Status;
1229 }
1230
1231 for( i = 0; NT_SUCCESS(Status); i++ ) {
1232 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
1233 Kbio, KbioLength, &ResultLength );
1234
1235 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
1236 ExFreePool( Kbio );
1237 KbioLength = ResultLength;
1238 Kbio = ExAllocatePool( NonPagedPool, KbioLength );
1239 if( !Kbio ) {
1240 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n"));
1241 NtClose( EnumKey );
1242 return STATUS_NO_MEMORY;
1243 }
1244
1245 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
1246 Kbio, KbioLength, &ResultLength );
1247
1248 if( !NT_SUCCESS(Status) ) {
1249 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
1250 NtClose( EnumKey );
1251 ExFreePool( Kbio );
1252 return Status;
1253 }
1254 }
1255
1256 if( NT_SUCCESS(Status) ) {
1257 TargetKeyName.Length = TargetKeyName.MaximumLength =
1258 Kbio->NameLength;
1259 TargetKeyName.Buffer = Kbio->Name;
1260
1261 Status = CheckForDeviceDesc
1262 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
1263 if( NT_SUCCESS(Status) ) {
1264 NtClose( EnumKey );
1265 ExFreePool( Kbio );
1266 return Status;
1267 } else Status = STATUS_SUCCESS;
1268 }
1269 }
1270
1271 NtClose( EnumKey );
1272 ExFreePool( Kbio );
1273 return STATUS_UNSUCCESSFUL;
1274 }
1275
1276 VOID GetName( PUNICODE_STRING RegistryKey,
1277 PUNICODE_STRING OutName ) {
1278 PWCHAR Ptr;
1279 UNICODE_STRING PartialRegistryKey;
1280
1281 PartialRegistryKey.Buffer =
1282 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
1283 Ptr = PartialRegistryKey.Buffer;
1284
1285 while( *Ptr != L'\\' &&
1286 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
1287 Ptr++;
1288
1289 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
1290 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
1291
1292 RtlInitUnicodeString( OutName, L"" );
1293 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
1294 }
1295
1296 BOOLEAN BindAdapter(
1297 PLAN_ADAPTER Adapter,
1298 PNDIS_STRING RegistryPath)
1299 /*
1300 * FUNCTION: Binds a LAN adapter to IP layer
1301 * ARGUMENTS:
1302 * Adapter = Pointer to LAN_ADAPTER structure
1303 * NOTES:
1304 * We set the lookahead buffer size, set the packet filter and
1305 * bind the adapter to IP layer
1306 */
1307 {
1308 PIP_INTERFACE IF;
1309 NDIS_STATUS NdisStatus;
1310 LLIP_BIND_INFO BindInfo;
1311 ULONG Lookahead = LOOKAHEAD_SIZE;
1312 NTSTATUS Status;
1313 NDIS_MEDIA_STATE MediaState;
1314
1315 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1316
1317 Adapter->State = LAN_STATE_OPENING;
1318
1319 NdisStatus = NDISCall(Adapter,
1320 NdisRequestSetInformation,
1321 OID_GEN_CURRENT_LOOKAHEAD,
1322 &Lookahead,
1323 sizeof(ULONG));
1324 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1325 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
1326 return FALSE;
1327 }
1328
1329 /* Bind the adapter to IP layer */
1330 BindInfo.Context = Adapter;
1331 BindInfo.HeaderSize = Adapter->HeaderSize;
1332 BindInfo.MinFrameSize = Adapter->MinFrameSize;
1333 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
1334 BindInfo.AddressLength = Adapter->HWAddressLength;
1335 BindInfo.Transmit = LANTransmit;
1336
1337 IF = IPCreateInterface(&BindInfo);
1338
1339 if (!IF) {
1340 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1341 return FALSE;
1342 }
1343
1344 /*
1345 * Query per-adapter configuration from the registry
1346 * In case anyone is curious: there *is* an Ndis configuration api
1347 * for this sort of thing, but it doesn't really support things like
1348 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1349 * protocol drivers developed for win2k and above just use the native
1350 * services (ZwOpenKey, etc).
1351 */
1352
1353 GetName( RegistryPath, &IF->Name );
1354
1355 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
1356 if (!NT_SUCCESS(Status)) {
1357 TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n"));
1358 IPDestroyInterface(IF);
1359 return FALSE;
1360 }
1361
1362 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
1363 &IF->Description));
1364
1365 /* Get maximum link speed */
1366 NdisStatus = NDISCall(Adapter,
1367 NdisRequestQueryInformation,
1368 OID_GEN_LINK_SPEED,
1369 &IF->Speed,
1370 sizeof(UINT));
1371
1372 if (!NT_SUCCESS(NdisStatus))
1373 IF->Speed = IP_DEFAULT_LINK_SPEED;
1374
1375 Adapter->Speed = IF->Speed * 100L;
1376
1377 /* Get maximum frame size */
1378 NdisStatus = NDISCall(Adapter,
1379 NdisRequestQueryInformation,
1380 OID_GEN_MAXIMUM_FRAME_SIZE,
1381 &Adapter->MTU,
1382 sizeof(UINT));
1383 if (NdisStatus != NDIS_STATUS_SUCCESS)
1384 return FALSE;
1385
1386 IF->MTU = Adapter->MTU;
1387
1388 /* Get maximum packet size */
1389 NdisStatus = NDISCall(Adapter,
1390 NdisRequestQueryInformation,
1391 OID_GEN_MAXIMUM_TOTAL_SIZE,
1392 &Adapter->MaxPacketSize,
1393 sizeof(UINT));
1394 if (NdisStatus != NDIS_STATUS_SUCCESS)
1395 return FALSE;
1396
1397 /* Register interface with IP layer */
1398 IPRegisterInterface(IF);
1399
1400 /* Store adapter context */
1401 Adapter->Context = IF;
1402
1403 /* Get the media state */
1404 NdisStatus = NDISCall(Adapter,
1405 NdisRequestQueryInformation,
1406 OID_GEN_MEDIA_CONNECT_STATUS,
1407 &MediaState,
1408 sizeof(MediaState));
1409 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1410 TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus));
1411 IPUnregisterInterface(IF);
1412 IPDestroyInterface(IF);
1413 return FALSE;
1414 }
1415
1416 /* Indicate the current media state */
1417 ProtocolStatus(Adapter,
1418 (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
1419 NULL, 0);
1420
1421 /* Set packet filter so we can send and receive packets */
1422 NdisStatus = NDISCall(Adapter,
1423 NdisRequestSetInformation,
1424 OID_GEN_CURRENT_PACKET_FILTER,
1425 &Adapter->PacketFilter,
1426 sizeof(UINT));
1427
1428 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1429 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
1430 IPUnregisterInterface(IF);
1431 IPDestroyInterface(IF);
1432 return FALSE;
1433 }
1434
1435 return TRUE;
1436 }
1437
1438
1439 VOID UnbindAdapter(
1440 PLAN_ADAPTER Adapter)
1441 /*
1442 * FUNCTION: Unbinds a LAN adapter from IP layer
1443 * ARGUMENTS:
1444 * Adapter = Pointer to LAN_ADAPTER structure
1445 */
1446 {
1447 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1448
1449 if (Adapter->State == LAN_STATE_STARTED) {
1450 PIP_INTERFACE IF = Adapter->Context;
1451
1452 IPUnregisterInterface(IF);
1453
1454 IPDestroyInterface(IF);
1455 }
1456 }
1457
1458
1459 NDIS_STATUS LANRegisterAdapter(
1460 PNDIS_STRING AdapterName,
1461 PNDIS_STRING RegistryPath)
1462 /*
1463 * FUNCTION: Registers protocol with an NDIS adapter
1464 * ARGUMENTS:
1465 * AdapterName = Pointer to string with name of adapter to register
1466 * Adapter = Address of pointer to a LAN_ADAPTER structure
1467 * RETURNS:
1468 * Status of operation
1469 */
1470 {
1471 PLAN_ADAPTER IF;
1472 NDIS_STATUS NdisStatus;
1473 NDIS_STATUS OpenStatus;
1474 UINT MediaIndex;
1475 NDIS_MEDIUM MediaArray[MAX_MEDIA];
1476 UINT AddressOID;
1477
1478 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1479
1480 IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG);
1481 if (!IF) {
1482 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1483 return NDIS_STATUS_RESOURCES;
1484 }
1485
1486 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1487
1488 /* Put adapter in stopped state */
1489 IF->State = LAN_STATE_STOPPED;
1490
1491 /* Initialize protecting spin lock */
1492 KeInitializeSpinLock(&IF->Lock);
1493
1494 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1495
1496 /* Initialize array with media IDs we support */
1497 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1498
1499 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1500 /* Open the adapter. */
1501 NdisOpenAdapter(&NdisStatus,
1502 &OpenStatus,
1503 &IF->NdisHandle,
1504 &MediaIndex,
1505 MediaArray,
1506 MAX_MEDIA,
1507 NdisProtocolHandle,
1508 IF,
1509 AdapterName,
1510 0,
1511 NULL);
1512
1513 /* Wait until the adapter is opened */
1514 if (NdisStatus == NDIS_STATUS_PENDING)
1515 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1516 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1517 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
1518 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1519 return NdisStatus;
1520 }
1521
1522 IF->Media = MediaArray[MediaIndex];
1523
1524 /* Fill LAN_ADAPTER structure with some adapter specific information */
1525 switch (IF->Media) {
1526 case NdisMedium802_3:
1527 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1528 IF->BCastMask = BCAST_ETH_MASK;
1529 IF->BCastCheck = BCAST_ETH_CHECK;
1530 IF->BCastOffset = BCAST_ETH_OFFSET;
1531 IF->HeaderSize = sizeof(ETH_HEADER);
1532 IF->MinFrameSize = 60;
1533 AddressOID = OID_802_3_CURRENT_ADDRESS;
1534 IF->PacketFilter =
1535 NDIS_PACKET_TYPE_BROADCAST |
1536 NDIS_PACKET_TYPE_DIRECTED |
1537 NDIS_PACKET_TYPE_MULTICAST;
1538 break;
1539
1540 default:
1541 /* Unsupported media */
1542 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1543 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1544 return NDIS_STATUS_NOT_SUPPORTED;
1545 }
1546
1547 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1548 NdisStatus = NDISCall(IF,
1549 NdisRequestQueryInformation,
1550 OID_GEN_MAXIMUM_SEND_PACKETS,
1551 &IF->MaxSendPackets,
1552 sizeof(UINT));
1553 if (NdisStatus != NDIS_STATUS_SUCCESS)
1554 /* Legacy NIC drivers may not support this query, if it fails we
1555 assume it can send at least one packet per call to NdisSend(Packets) */
1556 IF->MaxSendPackets = 1;
1557
1558 /* Get current hardware address */
1559 NdisStatus = NDISCall(IF,
1560 NdisRequestQueryInformation,
1561 AddressOID,
1562 &IF->HWAddress,
1563 IF->HWAddressLength);
1564 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1565 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1566 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1567 return NdisStatus;
1568 }
1569
1570 /* Bind adapter to IP layer */
1571 if( !BindAdapter(IF, RegistryPath) ) {
1572 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
1573 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1574 return NDIS_STATUS_NOT_ACCEPTED;
1575 }
1576
1577 /* Add adapter to the adapter list */
1578 ExInterlockedInsertTailList(&AdapterListHead,
1579 &IF->ListEntry,
1580 &AdapterListLock);
1581
1582 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1583
1584 return NDIS_STATUS_SUCCESS;
1585 }
1586
1587
1588 NDIS_STATUS LANUnregisterAdapter(
1589 PLAN_ADAPTER Adapter)
1590 /*
1591 * FUNCTION: Unregisters protocol with NDIS adapter
1592 * ARGUMENTS:
1593 * Adapter = Pointer to a LAN_ADAPTER structure
1594 * RETURNS:
1595 * Status of operation
1596 */
1597 {
1598 KIRQL OldIrql;
1599 NDIS_HANDLE NdisHandle;
1600 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1601
1602 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1603
1604 /* Unlink the adapter from the list */
1605 RemoveEntryList(&Adapter->ListEntry);
1606
1607 /* Unbind adapter from IP layer */
1608 UnbindAdapter(Adapter);
1609
1610 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1611 NdisHandle = Adapter->NdisHandle;
1612 if (NdisHandle) {
1613 Adapter->NdisHandle = NULL;
1614 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1615
1616 NdisCloseAdapter(&NdisStatus, NdisHandle);
1617 if (NdisStatus == NDIS_STATUS_PENDING) {
1618 TcpipWaitForSingleObject(&Adapter->Event,
1619 UserRequest,
1620 KernelMode,
1621 FALSE,
1622 NULL);
1623 NdisStatus = Adapter->NdisStatus;
1624 }
1625 } else
1626 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1627
1628 FreeAdapter(Adapter);
1629
1630 return NdisStatus;
1631 }
1632
1633 VOID
1634 NTAPI
1635 LANUnregisterProtocol(VOID)
1636 /*
1637 * FUNCTION: Unregisters this protocol driver with NDIS
1638 * NOTES: Does not care wether we are already registered
1639 */
1640 {
1641 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1642
1643 if (ProtocolRegistered) {
1644 NDIS_STATUS NdisStatus;
1645 PLIST_ENTRY CurrentEntry;
1646 PLIST_ENTRY NextEntry;
1647 PLAN_ADAPTER Current;
1648 KIRQL OldIrql;
1649
1650 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1651
1652 /* Search the list and remove every adapter we find */
1653 CurrentEntry = AdapterListHead.Flink;
1654 while (CurrentEntry != &AdapterListHead) {
1655 NextEntry = CurrentEntry->Flink;
1656 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1657 /* Unregister it */
1658 LANUnregisterAdapter(Current);
1659 CurrentEntry = NextEntry;
1660 }
1661
1662 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1663
1664 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1665 ProtocolRegistered = FALSE;
1666 }
1667 }
1668
1669 VOID
1670 NTAPI
1671 ProtocolUnbindAdapter(
1672 PNDIS_STATUS Status,
1673 NDIS_HANDLE ProtocolBindingContext,
1674 NDIS_HANDLE UnbindContext)
1675 {
1676 /* We don't pend any unbinding so we can just ignore UnbindContext */
1677 *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext);
1678 }
1679
1680 NTSTATUS LANRegisterProtocol(
1681 PNDIS_STRING Name)
1682 /*
1683 * FUNCTION: Registers this protocol driver with NDIS
1684 * ARGUMENTS:
1685 * Name = Name of this protocol driver
1686 * RETURNS:
1687 * Status of operation
1688 */
1689 {
1690 NDIS_STATUS NdisStatus;
1691 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1692
1693 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1694
1695 InitializeListHead(&AdapterListHead);
1696 KeInitializeSpinLock(&AdapterListLock);
1697
1698 /* Set up protocol characteristics */
1699 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1700 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1701 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1702 ProtChars.Name.Length = Name->Length;
1703 ProtChars.Name.Buffer = Name->Buffer;
1704 ProtChars.Name.MaximumLength = Name->MaximumLength;
1705 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1706 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1707 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1708 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1709 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1710 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1711 ProtChars.ReceivePacketHandler = ProtocolReceivePacket;
1712 ProtChars.ReceiveHandler = ProtocolReceive;
1713 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1714 ProtChars.StatusHandler = ProtocolStatus;
1715 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1716 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1717 ProtChars.PnPEventHandler = ProtocolPnPEvent;
1718 ProtChars.UnbindAdapterHandler = ProtocolUnbindAdapter;
1719 ProtChars.UnloadHandler = LANUnregisterProtocol;
1720
1721 /* Try to register protocol */
1722 NdisRegisterProtocol(&NdisStatus,
1723 &NdisProtocolHandle,
1724 &ProtChars,
1725 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1726 if (NdisStatus != NDIS_STATUS_SUCCESS)
1727 {
1728 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1729 return (NTSTATUS)NdisStatus;
1730 }
1731
1732 ProtocolRegistered = TRUE;
1733
1734 return STATUS_SUCCESS;
1735 }
1736
1737 /* EOF */