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