xref: /reactos/dll/win32/iphlpapi/address.c (revision 4eace8d7)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/iphlpapi/address.c
5  * PURPOSE:         iphlpapi implementation - Adapter Address APIs
6  * PROGRAMMERS:     Jérôme Gardou (jerome.gardou@reactos.org)
7  */
8 
9 #include "iphlpapi_private.h"
10 
11 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
12 #ifdef GetAdaptersAddressesV2
13 /* Helper for GetAdaptersAddresses:
14  * Retrieves the list of network adapters from tcpip.sys */
15 static
16 NTSTATUS
GetInterfacesList(_In_ HANDLE TcpFile,_Out_ TDIEntityID ** EntityList,_Out_ ULONG * InterfaceCount)17 GetInterfacesList(
18     _In_ HANDLE TcpFile,
19     _Out_ TDIEntityID **EntityList,
20     _Out_ ULONG* InterfaceCount)
21 {
22 
23     TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
24     IO_STATUS_BLOCK StatusBlock;
25     NTSTATUS Status;
26     ULONG_PTR BufferSize;
27 
28     ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
29     TcpQueryInfo.ID.toi_class = INFO_CLASS_GENERIC;
30     TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
31     TcpQueryInfo.ID.toi_id = ENTITY_LIST_ID;
32     TcpQueryInfo.ID.toi_entity.tei_entity = GENERIC_ENTITY;
33     TcpQueryInfo.ID.toi_entity.tei_instance = 0;
34 
35     Status = NtDeviceIoControlFile(
36         TcpFile,
37         NULL,
38         NULL,
39         NULL,
40         &StatusBlock,
41         IOCTL_TCP_QUERY_INFORMATION_EX,
42         &TcpQueryInfo,
43         sizeof(TcpQueryInfo),
44         NULL,
45         0);
46     if (Status == STATUS_PENDING)
47     {
48         /* So we have to wait a bit */
49         Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
50         if (NT_SUCCESS(Status))
51             Status = StatusBlock.Status;
52     }
53 
54     if (!NT_SUCCESS(Status))
55         return Status;
56 
57     BufferSize = StatusBlock.Information;
58     *EntityList = HeapAlloc(GetProcessHeap(), 0, BufferSize);
59     if (!*EntityList)
60         return STATUS_NO_MEMORY;
61 
62     /* Do the real call */
63     Status = NtDeviceIoControlFile(
64         TcpFile,
65         NULL,
66         NULL,
67         NULL,
68         &StatusBlock,
69         IOCTL_TCP_QUERY_INFORMATION_EX,
70         &TcpQueryInfo,
71         sizeof(TcpQueryInfo),
72         *EntityList,
73         BufferSize);
74     if (Status == STATUS_PENDING)
75     {
76         /* So we have to wait a bit */
77         Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
78         if (NT_SUCCESS(Status))
79             Status = StatusBlock.Status;
80     }
81 
82     if (!NT_SUCCESS(Status))
83     {
84         HeapFree(GetProcessHeap(), 0, *EntityList);
85         return Status;
86     }
87 
88     *InterfaceCount = BufferSize / sizeof(TDIEntityID);
89     return Status;
90 }
91 
92 static
93 NTSTATUS
GetSnmpInfo(_In_ HANDLE TcpFile,_In_ TDIEntityID InterfaceID,_Out_ IPSNMPInfo * Info)94 GetSnmpInfo(
95     _In_ HANDLE TcpFile,
96     _In_ TDIEntityID InterfaceID,
97     _Out_ IPSNMPInfo* Info)
98 {
99     TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
100     IO_STATUS_BLOCK StatusBlock;
101     NTSTATUS Status;
102 
103     ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
104     TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
105     TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
106     TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID;
107     TcpQueryInfo.ID.toi_entity = InterfaceID;
108 
109     Status = NtDeviceIoControlFile(
110         TcpFile,
111         NULL,
112         NULL,
113         NULL,
114         &StatusBlock,
115         IOCTL_TCP_QUERY_INFORMATION_EX,
116         &TcpQueryInfo,
117         sizeof(TcpQueryInfo),
118         Info,
119         sizeof(*Info));
120     if (Status == STATUS_PENDING)
121     {
122         /* So we have to wait a bit */
123         Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
124         if (NT_SUCCESS(Status))
125             Status = StatusBlock.Status;
126     }
127 
128     return Status;
129 }
130 
131 static
132 NTSTATUS
GetAddrEntries(_In_ HANDLE TcpFile,_In_ TDIEntityID InterfaceID,_Out_ IPAddrEntry * Entries,_In_ ULONG NumEntries)133 GetAddrEntries(
134     _In_ HANDLE TcpFile,
135     _In_ TDIEntityID InterfaceID,
136     _Out_ IPAddrEntry* Entries,
137     _In_ ULONG NumEntries)
138 {
139     TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
140     IO_STATUS_BLOCK StatusBlock;
141     NTSTATUS Status;
142 
143     ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
144     TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
145     TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
146     TcpQueryInfo.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
147     TcpQueryInfo.ID.toi_entity = InterfaceID;
148 
149     Status = NtDeviceIoControlFile(
150         TcpFile,
151         NULL,
152         NULL,
153         NULL,
154         &StatusBlock,
155         IOCTL_TCP_QUERY_INFORMATION_EX,
156         &TcpQueryInfo,
157         sizeof(TcpQueryInfo),
158         Entries,
159         NumEntries * sizeof(Entries[0]));
160     if (Status == STATUS_PENDING)
161     {
162         /* So we have to wait a bit */
163         Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
164         if (NT_SUCCESS(Status))
165             Status = StatusBlock.Status;
166     }
167 
168     return Status;
169 }
170 
171 /*
172  * Fills the IFEntry buffer from tcpip.sys.
173  * The buffer size MUST be FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1]).
174  * See MSDN IFEntry struct definition if you don't believe me. ;-)
175  */
176 static
177 NTSTATUS
GetInterfaceEntry(_In_ HANDLE TcpFile,_In_ TDIEntityID InterfaceID,_Out_ IFEntry * Entry)178 GetInterfaceEntry(
179     _In_ HANDLE TcpFile,
180     _In_ TDIEntityID InterfaceID,
181     _Out_ IFEntry* Entry)
182 {
183     TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
184     IO_STATUS_BLOCK StatusBlock;
185     NTSTATUS Status;
186 
187     ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
188     TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
189     TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
190     TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID;
191     TcpQueryInfo.ID.toi_entity = InterfaceID;
192 
193     Status = NtDeviceIoControlFile(
194         TcpFile,
195         NULL,
196         NULL,
197         NULL,
198         &StatusBlock,
199         IOCTL_TCP_QUERY_INFORMATION_EX,
200         &TcpQueryInfo,
201         sizeof(TcpQueryInfo),
202         Entry,
203         FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1]));
204     if (Status == STATUS_PENDING)
205     {
206         /* So we have to wait a bit */
207         Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
208         if (NT_SUCCESS(Status))
209             Status = StatusBlock.Status;
210     }
211 
212     return Status;
213 }
214 
215 /* Helpers to get the list of DNS for an interface */
216 static
217 VOID
EnumerateServerNameSize(_In_ PWCHAR Interface,_In_ PWCHAR NameServer,_Inout_ PVOID Data)218 EnumerateServerNameSize(
219     _In_ PWCHAR Interface,
220     _In_ PWCHAR NameServer,
221     _Inout_ PVOID Data)
222 {
223     ULONG* BufferSize = Data;
224 
225     /* This is just sizing here */
226     UNREFERENCED_PARAMETER(Interface);
227     UNREFERENCED_PARAMETER(NameServer);
228 
229     *BufferSize += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR);
230 }
231 
232 static
233 VOID
EnumerateServerName(_In_ PWCHAR Interface,_In_ PWCHAR NameServer,_Inout_ PVOID Data)234 EnumerateServerName(
235     _In_ PWCHAR Interface,
236     _In_ PWCHAR NameServer,
237     _Inout_ PVOID Data)
238 {
239     PIP_ADAPTER_DNS_SERVER_ADDRESS** Ptr = Data;
240     PIP_ADAPTER_DNS_SERVER_ADDRESS ServerAddress = **Ptr;
241 
242     UNREFERENCED_PARAMETER(Interface);
243 
244     ServerAddress->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
245     ServerAddress->Address.lpSockaddr = (PVOID)(ServerAddress + 1);
246     ServerAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
247 
248 
249     /* Get the address from the server name string */
250     //FIXME: Only ipv4 for now...
251     if (WSAStringToAddressW(
252         NameServer,
253         AF_INET,
254         NULL,
255         ServerAddress->Address.lpSockaddr,
256         &ServerAddress->Address.iSockaddrLength))
257     {
258         /* Pass along, name conversion failed */
259         ERR("%S is not a valid IP address\n", NameServer);
260         return;
261     }
262 
263     /* Go to next item */
264     ServerAddress->Next = (PVOID)(ServerAddress->Address.lpSockaddr + 1);
265     *Ptr = &ServerAddress->Next;
266 }
267 
268 static
269 VOID
QueryFlags(_In_ PUCHAR Interface,_In_ DWORD InterfaceLength,_Out_ LPDWORD Flags)270 QueryFlags(
271     _In_ PUCHAR Interface,
272     _In_ DWORD InterfaceLength,
273     _Out_ LPDWORD Flags)
274 {
275     HKEY InterfaceKey;
276     CHAR KeyName[256];
277     DWORD Type, Size, Data;
278 
279     *Flags = 0;
280 
281     snprintf(KeyName, 256,
282              "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
283              InterfaceLength, Interface);
284 
285     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
286     {
287         Size = sizeof(DWORD);
288         if (RegQueryValueExA(InterfaceKey, "EnableDHCP", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS &&
289             Type == REG_DWORD && Data == 1)
290         {
291             *Flags |= IP_ADAPTER_DHCP_ENABLED;
292         }
293 
294         Size = sizeof(DWORD);
295         if (RegQueryValueExA(InterfaceKey, "RegisterAdapterName", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS &&
296             Type == REG_DWORD && Data == 1)
297         {
298             *Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX;
299         }
300 
301         Size = 0;
302         if (RegQueryValueExA(InterfaceKey, "NameServer", NULL, &Type, (LPBYTE)&Data, &Size) != ERROR_SUCCESS)
303         {
304             *Flags |= IP_ADAPTER_DDNS_ENABLED;
305         }
306 
307         RegCloseKey(InterfaceKey);
308     }
309 
310     // FIXME: handle 0x8 -> 0x20
311 }
312 
313 DWORD
314 WINAPI
315 DECLSPEC_HOTPATCH
GetAdaptersAddresses(_In_ ULONG Family,_In_ ULONG Flags,_In_ PVOID Reserved,_Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses,_Inout_ PULONG pOutBufLen)316 GetAdaptersAddresses(
317     _In_ ULONG Family,
318     _In_ ULONG Flags,
319     _In_ PVOID Reserved,
320     _Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses,
321     _Inout_ PULONG pOutBufLen)
322 {
323     NTSTATUS Status;
324     HANDLE TcpFile;
325     TDIEntityID* InterfacesList;
326     ULONG InterfacesCount;
327     ULONG AdaptersCount = 0;
328     ULONG i;
329     ULONG TotalSize = 0, RemainingSize;
330     BYTE* Ptr = (BYTE*)pAdapterAddresses;
331     DWORD MIN_SIZE = 15 * 1024;
332     PIP_ADAPTER_ADDRESSES PreviousAA = NULL;
333 
334     TRACE("Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p\n",
335           Family, Flags, Reserved, pAdapterAddresses, pOutBufLen);
336 
337     if (!pOutBufLen)
338         return ERROR_INVALID_PARAMETER;
339 
340     // FIXME: the exact needed size should be computed first, BEFORE doing any write to the output buffer.
341     // As suggested by MSDN, require a 15 KB buffer, which allows to React properly to length checks.
342     if(!Ptr || *pOutBufLen < MIN_SIZE)
343     {
344         *pOutBufLen = MIN_SIZE;
345         return ERROR_BUFFER_OVERFLOW;
346     }
347 
348     switch(Family)
349     {
350         case AF_INET:
351             break;
352         case AF_INET6:
353             /* One day maybe... */
354             FIXME("IPv6 is not supported in ReactOS!\n");
355             /* We got nothing to say in this case */
356             return ERROR_NO_DATA;
357             break;
358         case AF_UNSPEC:
359             WARN("IPv6 addresses ignored, IPv4 only\n");
360             Family = AF_INET;
361             break;
362         default:
363             ERR("Invalid family 0x%x\n", Family);
364             return ERROR_INVALID_PARAMETER;
365             break;
366     }
367 
368     RemainingSize = *pOutBufLen;
369     if (Ptr)
370         ZeroMemory(Ptr, RemainingSize);
371 
372     /* open the tcpip driver */
373     Status = openTcpFile(&TcpFile, FILE_READ_DATA);
374     if (!NT_SUCCESS(Status))
375     {
376         ERR("Could not open handle to tcpip.sys. Status %08x\n", Status);
377         return RtlNtStatusToDosError(Status);
378     }
379 
380     /* Get the interfaces list */
381     Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount);
382     if (!NT_SUCCESS(Status))
383     {
384         ERR("Could not get adapters list. Status %08x\n", Status);
385         NtClose(TcpFile);
386         return RtlNtStatusToDosError(Status);
387     }
388 
389     /* Let's see if we got any adapter. */
390     for (i = 0; i < InterfacesCount; i++)
391     {
392         PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr;
393         ULONG CurrentAASize = 0;
394         ULONG FriendlySize = 0;
395 
396         if (InterfacesList[i].tei_entity == IF_ENTITY)
397         {
398             BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) +
399                              RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)];
400             IFEntry* Entry = (IFEntry*)EntryBuffer;
401 
402             /* Remember we got one */
403             AdaptersCount++;
404 
405             /* Set the pointer to this instance in the previous one*/
406             if(PreviousAA)
407                 PreviousAA->Next = CurrentAA;
408 
409             /* Of course we need some space for the base structure. */
410             CurrentAASize = sizeof(IP_ADAPTER_ADDRESSES);
411 
412             /* Get the entry */
413             Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry);
414             if (!NT_SUCCESS(Status))
415                 goto Error;
416 
417             TRACE("Got entity %*s, index %u.\n",
418                 Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index);
419 
420             /* Add the adapter name */
421             CurrentAASize += Entry->if_descrlen + sizeof(CHAR);
422 
423             /* Add the DNS suffix */
424             CurrentAASize += sizeof(WCHAR);
425 
426             /* Add the description. */
427             CurrentAASize += sizeof(WCHAR);
428 
429             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
430             {
431                 /* Get the friendly name */
432                 HKEY ConnectionKey;
433                 CHAR KeyName[256];
434 
435                 snprintf(KeyName, 256,
436                     "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
437                     Entry->if_descrlen, &Entry->if_descr[0]);
438 
439                 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
440                 {
441                     DWORD ValueType;
442                     DWORD ValueSize = 0;
443 
444                     if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS &&
445                         ValueType == REG_SZ)
446                     {
447                         /* We remove the null char, it will be re-added after */
448                         FriendlySize = ValueSize - sizeof(WCHAR);
449                         CurrentAASize += FriendlySize;
450                     }
451 
452                     RegCloseKey(ConnectionKey);
453                 }
454 
455                 /* We always make sure to have enough room for empty string */
456                 CurrentAASize += sizeof(WCHAR);
457             }
458 
459             if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
460             {
461                 /* Enumerate the name servers */
462                 HKEY InterfaceKey;
463                 CHAR KeyName[256];
464 
465                 snprintf(KeyName, 256,
466                     "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
467                     Entry->if_descrlen, &Entry->if_descr[0]);
468 
469                 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
470                 {
471                     EnumNameServers(InterfaceKey, NULL, &CurrentAASize, EnumerateServerNameSize);
472                     RegCloseKey(InterfaceKey);
473                 }
474             }
475 
476             /* This is part of what we will need */
477             TotalSize += CurrentAASize;
478 
479             /* Fill in the data */
480             if ((CurrentAA) && (RemainingSize >= CurrentAASize))
481             {
482                 CurrentAA->Length = sizeof(IP_ADAPTER_ADDRESSES);
483                 CurrentAA->IfIndex = Entry->if_index;
484                 CopyMemory(CurrentAA->PhysicalAddress, Entry->if_physaddr, Entry->if_physaddrlen);
485                 CurrentAA->PhysicalAddressLength = Entry->if_physaddrlen;
486                 QueryFlags(&Entry->if_descr[0], Entry->if_descrlen, &CurrentAA->Flags);
487                 CurrentAA->Mtu = Entry->if_mtu;
488                 CurrentAA->IfType = Entry->if_type;
489                 if(Entry->if_operstatus >= IF_OPER_STATUS_CONNECTING)
490                     CurrentAA->OperStatus = IfOperStatusUp;
491                 else
492                     CurrentAA->OperStatus = IfOperStatusDown;
493 
494                 /* Next items */
495                 Ptr = (BYTE*)(CurrentAA + 1);
496 
497                 /* Now fill in the name */
498                 CopyMemory(Ptr, &Entry->if_descr[0], Entry->if_descrlen);
499                 CurrentAA->AdapterName = (PCHAR)Ptr;
500                 CurrentAA->AdapterName[Entry->if_descrlen] = '\0';
501                 /* Next items */
502                 Ptr = (BYTE*)(CurrentAA->AdapterName + Entry->if_descrlen + 1);
503 
504                 /* The DNS suffix */
505                 CurrentAA->DnsSuffix = (PWCHAR)Ptr;
506                 CurrentAA->DnsSuffix[0] = L'\0';
507                 /* Next items */
508                 Ptr = (BYTE*)(CurrentAA->DnsSuffix + 1);
509 
510                 /* The description */
511                 CurrentAA->Description = (PWCHAR)Ptr;
512                 CurrentAA->Description[0] = L'\0';
513                 /* Next items */
514                 Ptr = (BYTE*)(CurrentAA->Description + 1);
515 
516                 /* The friendly name */
517                 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
518                 {
519                     CurrentAA->FriendlyName = (PWCHAR)Ptr;
520 
521                     if (FriendlySize != 0)
522                     {
523                         /* Get the friendly name */
524                         HKEY ConnectionKey;
525                         CHAR KeyName[256];
526 
527                         snprintf(KeyName, 256,
528                             "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
529                             Entry->if_descrlen, &Entry->if_descr[0]);
530 
531                         if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
532                         {
533                             DWORD ValueType;
534                             DWORD ValueSize = FriendlySize + sizeof(WCHAR);
535 
536                             if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, (LPBYTE)CurrentAA->FriendlyName, &ValueSize) == ERROR_SUCCESS &&
537                                 ValueType == REG_SZ && ValueSize == FriendlySize + sizeof(WCHAR))
538                             {
539                                 /* We're done, next items */
540                                 Ptr = (BYTE*)(CurrentAA->FriendlyName + (ValueSize / sizeof(WCHAR)));
541                             }
542                             else
543                             {
544                                 /* Fail */
545                                 ERR("Friendly name changed after probe!\n");
546                                 FriendlySize = 0;
547                             }
548 
549                             RegCloseKey(ConnectionKey);
550                         }
551                         else
552                         {
553                             /* Fail */
554                             FriendlySize = 0;
555                         }
556                     }
557 
558                     /* In case of failure (or no name) */
559                     if (FriendlySize == 0)
560                     {
561                         CurrentAA->FriendlyName[0] = L'\0';
562                         /* Next items */
563                         Ptr = (BYTE*)(CurrentAA->FriendlyName + 1);
564                     }
565                 }
566 
567                 /* The DNS Servers */
568                 if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
569                 {
570                     /* Enumerate the name servers */
571                     HKEY InterfaceKey;
572                     CHAR KeyName[256];
573 
574                     snprintf(KeyName, 256,
575                         "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
576                         Entry->if_descrlen, &Entry->if_descr[0]);
577 
578                     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS)
579                     {
580                         TRACE("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
581                     }
582                     else
583                     {
584                         PIP_ADAPTER_DNS_SERVER_ADDRESS* ServerAddressPtr;
585 
586                         CurrentAA->FirstDnsServerAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)Ptr;
587                         ServerAddressPtr = &CurrentAA->FirstDnsServerAddress;
588 
589                         EnumNameServers(InterfaceKey, NULL, &ServerAddressPtr, EnumerateServerName);
590                         RegCloseKey(InterfaceKey);
591 
592                         /* Set the last entry in the list as having NULL next member */
593                         Ptr = (BYTE*)*ServerAddressPtr;
594                         *ServerAddressPtr = NULL;
595                     }
596                 }
597 
598                 /* We're done for this interface */
599                 PreviousAA = CurrentAA;
600                 RemainingSize -= CurrentAASize;
601             }
602         }
603     }
604 
605     if (AdaptersCount == 0)
606     {
607         /* Uh? Not even localhost ?! */
608         ERR("No Adapters found!\n");
609         *pOutBufLen = 0;
610         return ERROR_NO_DATA;
611     }
612 
613     /* See if we have anything to add */
614     // FIXME: Anycast and multicast
615     if ((Flags & (GAA_FLAG_SKIP_UNICAST | GAA_FLAG_INCLUDE_PREFIX)) == GAA_FLAG_SKIP_UNICAST)
616         goto Success;
617 
618     /* Now fill in the addresses */
619     for (i = 0; i < InterfacesCount; i++)
620     {
621         /* Look for network layers */
622         if ((InterfacesList[i].tei_entity == CL_NL_ENTITY)
623                 || (InterfacesList[i].tei_entity == CO_NL_ENTITY))
624         {
625             IPSNMPInfo SnmpInfo;
626             PIP_ADAPTER_ADDRESSES CurrentAA = NULL;
627             IPAddrEntry* AddrEntries;
628             ULONG j;
629 
630             /* Get its SNMP info */
631             Status = GetSnmpInfo(TcpFile, InterfacesList[i], &SnmpInfo);
632             if (!NT_SUCCESS(Status))
633                 goto Error;
634 
635             if (SnmpInfo.ipsi_numaddr == 0)
636                 continue;
637 
638             /* Allocate the address entry array and get them */
639             AddrEntries = HeapAlloc(GetProcessHeap(),
640                 HEAP_ZERO_MEMORY,
641                 SnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
642             if (!AddrEntries)
643             {
644                 Status = STATUS_NO_MEMORY;
645                 goto Error;
646             }
647             Status = GetAddrEntries(TcpFile, InterfacesList[i], AddrEntries, SnmpInfo.ipsi_numaddr);
648             if (!NT_SUCCESS(Status))
649             {
650                 HeapFree(GetProcessHeap(), 0, AddrEntries);
651                 goto Error;
652             }
653 
654             for (j = 0; j < SnmpInfo.ipsi_numaddr; j++)
655             {
656                 /* Find the adapters struct for this address. */
657                 if (pAdapterAddresses)
658                 {
659                     CurrentAA = pAdapterAddresses;
660                     while (CurrentAA)
661                     {
662                         if (CurrentAA->IfIndex == AddrEntries[j].iae_index)
663                             break;
664 
665                         CurrentAA = CurrentAA->Next;
666                     }
667 
668                     if (!CurrentAA)
669                     {
670                         ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries[j].iae_index);
671                         /* Go to the next address */
672                         continue;
673                     }
674                 }
675 
676                 TRACE("address is 0x%08x, mask is 0x%08x\n", AddrEntries[j].iae_addr, AddrEntries[j].iae_mask);
677 
678                 //FIXME: For now reactos only supports unicast addresses
679                 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
680                 {
681                     ULONG Size = sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR);
682 
683                     if (Ptr && (RemainingSize >= Size))
684                     {
685                         PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress = (PIP_ADAPTER_UNICAST_ADDRESS)Ptr;
686 
687                         /* Fill in the structure */
688                         UnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
689                         UnicastAddress->Next = CurrentAA->FirstUnicastAddress;
690 
691                         // FIXME: Put meaningful value here
692                         UnicastAddress->Flags = 0;
693                         UnicastAddress->PrefixOrigin = IpPrefixOriginOther;
694                         UnicastAddress->SuffixOrigin = IpSuffixOriginOther;
695                         UnicastAddress->DadState = IpDadStatePreferred;
696                         UnicastAddress->ValidLifetime = 0xFFFFFFFF;
697                         UnicastAddress->PreferredLifetime = 0xFFFFFFFF;
698 
699                         /* Set the address */
700                         //FIXME: ipv4 only (again...)
701                         UnicastAddress->Address.lpSockaddr = (LPSOCKADDR)(UnicastAddress + 1);
702                         UnicastAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
703                         UnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
704                         ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_port = 0;
705                         memcpy(&((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_addr, &AddrEntries[j].iae_addr, sizeof(AddrEntries[j].iae_addr));
706 
707                         CurrentAA->FirstUnicastAddress = UnicastAddress;
708                         Ptr += Size;
709                         RemainingSize -= Size;
710                     }
711 
712                     TotalSize += Size;
713                 }
714 
715                 if (Flags & GAA_FLAG_INCLUDE_PREFIX)
716                 {
717                     ULONG Size = sizeof(IP_ADAPTER_PREFIX) + sizeof(SOCKADDR);
718 
719                     if (Ptr && (RemainingSize >= Size))
720                     {
721                         PIP_ADAPTER_PREFIX Prefix = (PIP_ADAPTER_PREFIX)Ptr;
722 
723                         /* Fill in the structure */
724                         Prefix->Length = sizeof(IP_ADAPTER_PREFIX);
725                         Prefix->Next = CurrentAA->FirstPrefix;
726 
727                         /* Set the address */
728                         //FIXME: ipv4 only (again...)
729                         Prefix->Address.lpSockaddr = (LPSOCKADDR)(Prefix + 1);
730                         Prefix->Address.iSockaddrLength = sizeof(AddrEntries[j].iae_mask);
731                         Prefix->Address.lpSockaddr->sa_family = AF_INET;
732                         memcpy(Prefix->Address.lpSockaddr->sa_data, &AddrEntries[j].iae_mask, sizeof(AddrEntries[j].iae_mask));
733 
734                         /* Compute the prefix size */
735                         _BitScanReverse(&Prefix->PrefixLength, AddrEntries[j].iae_mask);
736 
737                         CurrentAA->FirstPrefix = Prefix;
738                         Ptr += Size;
739                         RemainingSize -= Size;
740                     }
741 
742                     TotalSize += Size;
743                 }
744             }
745 
746             HeapFree(GetProcessHeap(), 0, AddrEntries);
747         }
748     }
749 
750 Success:
751     /* We're done */
752     HeapFree(GetProcessHeap(), 0, InterfacesList);
753     NtClose(TcpFile);
754     *pOutBufLen = TotalSize;
755     TRACE("TotalSize: %x\n", *pOutBufLen);
756     return ERROR_SUCCESS;
757 
758 Error:
759     ERR("Failed! Status 0x%08x\n", Status);
760     *pOutBufLen = 0;
761     HeapFree(GetProcessHeap(), 0, InterfacesList);
762     NtClose(TcpFile);
763     return RtlNtStatusToDosError(Status);
764 }
765 #endif
766