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