Reactos
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
11WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
12#ifdef GetAdaptersAddressesV2
13/* Helper for GetAdaptersAddresses:
14 * Retrieves the list of network adapters from tcpip.sys */
15static
16NTSTATUS
17GetInterfacesList(
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
92static
93NTSTATUS
94GetSnmpInfo(
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
131static
132NTSTATUS
133GetAddrEntries(
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 */
176static
177NTSTATUS
178GetInterfaceEntry(
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 */
216static
217VOID
218EnumerateServerNameSize(
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
232static
233VOID
234EnumerateServerName(
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 PCWSTR Terminator;
242 NTSTATUS Status;
243
244 UNREFERENCED_PARAMETER(Interface);
245
246 ServerAddress->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
247 ServerAddress->Address.lpSockaddr = (PVOID)(ServerAddress + 1);
248 ServerAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
249
250 ServerAddress->Address.lpSockaddr->sa_family = AF_INET;
251 ((LPSOCKADDR_IN)ServerAddress->Address.lpSockaddr)->sin_port = 0;
252
253 Status = RtlIpv4StringToAddressW(NameServer, FALSE, &Terminator,
254 &((LPSOCKADDR_IN)ServerAddress->Address.lpSockaddr)->sin_addr);
255 if (!NT_SUCCESS(Status))
256 {
257 /* Pass along, name conversion failed */
258 ERR("%S is not a valid IP address\n", NameServer);
259 return;
260 }
261
262 /* Go to next item */
263 ServerAddress->Next = (PVOID)(ServerAddress->Address.lpSockaddr + 1);
264 *Ptr = &ServerAddress->Next;
265}
266
267static
268VOID
269QueryFlags(
270 _In_ PUCHAR Interface,
271 _In_ DWORD InterfaceLength,
272 _Out_ LPDWORD Flags)
273{
274 HKEY InterfaceKey;
275 CHAR KeyName[256];
276 DWORD Type, Size, Data;
277
278 *Flags = 0;
279
280 snprintf(KeyName, 256,
281 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
282 InterfaceLength, Interface);
283
284 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
285 {
286 Size = sizeof(DWORD);
287 if (RegQueryValueExA(InterfaceKey, "EnableDHCP", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS &&
288 Type == REG_DWORD && Data == 1)
289 {
290 *Flags |= IP_ADAPTER_DHCP_ENABLED;
291 }
292
293 Size = sizeof(DWORD);
294 if (RegQueryValueExA(InterfaceKey, "RegisterAdapterName", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS &&
295 Type == REG_DWORD && Data == 1)
296 {
297 *Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX;
298 }
299
300 Size = 0;
301 if (RegQueryValueExA(InterfaceKey, "NameServer", NULL, &Type, (LPBYTE)&Data, &Size) != ERROR_SUCCESS)
302 {
303 *Flags |= IP_ADAPTER_DDNS_ENABLED;
304 }
305
306 RegCloseKey(InterfaceKey);
307 }
308
309 // FIXME: handle 0x8 -> 0x20
310}
311
312static
313ULONG
314CountPrefixBits(
315 _In_ ULONG Netmask)
316{
317 ULONG i, BitCount = 0;
318
319 for (i = 0; i < sizeof(ULONG) * 8; i++)
320 {
321 if ((Netmask & (1 << i)) == 0)
322 break;
323 BitCount++;
324 }
325
326 return BitCount;
327}
328
329DWORD
330WINAPI
331DECLSPEC_HOTPATCH
332GetAdaptersAddresses(
333 _In_ ULONG Family,
334 _In_ ULONG Flags,
335 _In_ PVOID Reserved,
336 _Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses,
337 _Inout_ PULONG pOutBufLen)
338{
339 NTSTATUS Status;
340 HANDLE TcpFile;
341 TDIEntityID* InterfacesList;
342 ULONG InterfacesCount;
343 ULONG AdaptersCount = 0;
344 ULONG i;
345 ULONG TotalSize = 0, RemainingSize;
346 BYTE* Ptr = (BYTE*)pAdapterAddresses;
347 DWORD MIN_SIZE = 15 * 1024;
348 PIP_ADAPTER_ADDRESSES PreviousAA = NULL;
349
350 TRACE("Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p\n",
351 Family, Flags, Reserved, pAdapterAddresses, pOutBufLen);
352
353 if (!pOutBufLen)
354 return ERROR_INVALID_PARAMETER;
355
356 // FIXME: the exact needed size should be computed first, BEFORE doing any write to the output buffer.
357 // As suggested by MSDN, require a 15 KB buffer, which allows to React properly to length checks.
358 if(!Ptr || *pOutBufLen < MIN_SIZE)
359 {
360 *pOutBufLen = MIN_SIZE;
361 return ERROR_BUFFER_OVERFLOW;
362 }
363
364 switch(Family)
365 {
366 case AF_INET:
367 break;
368 case AF_INET6:
369 /* One day maybe... */
370 FIXME("IPv6 is not supported in ReactOS!\n");
371 /* We got nothing to say in this case */
372 return ERROR_NO_DATA;
373 break;
374 case AF_UNSPEC:
375 WARN("IPv6 addresses ignored, IPv4 only\n");
376 Family = AF_INET;
377 break;
378 default:
379 ERR("Invalid family 0x%x\n", Family);
380 return ERROR_INVALID_PARAMETER;
381 break;
382 }
383
384 RemainingSize = *pOutBufLen;
385 if (Ptr)
386 ZeroMemory(Ptr, RemainingSize);
387
388 /* open the tcpip driver */
389 Status = openTcpFile(&TcpFile, FILE_READ_DATA);
390 if (!NT_SUCCESS(Status))
391 {
392 ERR("Could not open handle to tcpip.sys. Status %08x\n", Status);
393 return RtlNtStatusToDosError(Status);
394 }
395
396 /* Get the interfaces list */
397 Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount);
398 if (!NT_SUCCESS(Status))
399 {
400 ERR("Could not get adapters list. Status %08x\n", Status);
401 NtClose(TcpFile);
402 return RtlNtStatusToDosError(Status);
403 }
404
405 /* Let's see if we got any adapter. */
406 for (i = 0; i < InterfacesCount; i++)
407 {
408 PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr;
409 ULONG CurrentAASize = 0;
410 ULONG FriendlySize = 0, DescriptionSize = 0;
411 ULONG DhcpDomainSize = 0, DomainSize = 0;
412
413 if (InterfacesList[i].tei_entity == IF_ENTITY)
414 {
415 BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) +
416 RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)];
417 IFEntry* Entry = (IFEntry*)EntryBuffer;
418
419 /* Remember we got one */
420 AdaptersCount++;
421
422 /* Set the pointer to this instance in the previous one*/
423 if(PreviousAA)
424 PreviousAA->Next = CurrentAA;
425
426 /* Of course we need some space for the base structure. */
427 CurrentAASize = sizeof(IP_ADAPTER_ADDRESSES);
428
429 /* Get the entry */
430 Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry);
431 if (!NT_SUCCESS(Status))
432 goto Error;
433
434 TRACE("Got entity %*s, index %u.\n",
435 Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index);
436
437 /* Add the adapter name */
438 CurrentAASize += Entry->if_descrlen + sizeof(CHAR);
439
440 /* Add the DNS suffix */
441 if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK)
442 {
443 HKEY InterfaceKey;
444 CHAR KeyName[256];
445 DWORD ValueType, ValueSize, Data;
446
447 snprintf(KeyName, 256,
448 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
449 Entry->if_descrlen, &Entry->if_descr[0]);
450
451 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
452 {
453 ValueSize = sizeof(DWORD);
454 if (RegQueryValueExW(InterfaceKey, L"EnableDHCP", NULL, &ValueType, (LPBYTE)&Data, &ValueSize) == ERROR_SUCCESS &&
455 ValueType == REG_DWORD && Data == 1)
456 {
457 ValueSize = sizeof(DWORD);
458 if (RegQueryValueExW(InterfaceKey, L"DhcpDomain", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS &&
459 ValueType == REG_SZ)
460 {
461 /* We remove the null char, it will be re-added after */
462 DhcpDomainSize = ValueSize - sizeof(WCHAR);
463 CurrentAASize += DhcpDomainSize;
464 }
465 }
466 else
467 {
468 ValueSize = sizeof(DWORD);
469 if (RegQueryValueExW(InterfaceKey, L"Domain", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS &&
470 ValueType == REG_SZ)
471 {
472 /* We remove the null char, it will be re-added after */
473 DomainSize = ValueSize - sizeof(WCHAR);
474 CurrentAASize += DomainSize;
475 }
476 }
477
478 RegCloseKey(InterfaceKey);
479 }
480 }
481
482 CurrentAASize += sizeof(WCHAR);
483
484 /* Add the description. */
485 if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK)
486 {
487 DescriptionSize = mbstowcs(NULL, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen) * sizeof(WCHAR);
488 CurrentAASize += DescriptionSize;
489 }
490 else
491 {
492 HKEY ConnectionKey;
493 CHAR KeyName[256];
494 CHAR InstanceID[128];
495 DWORD ValueType = 0;
496 DWORD ValueSize = 0;
497
498 snprintf(KeyName, 256,
499 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
500 Entry->if_descrlen, &Entry->if_descr[0]);
501
502 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
503 {
504 ValueSize = 128;
505 RegQueryValueExA(ConnectionKey, "PnpInstanceID", NULL, &ValueType, (LPBYTE)InstanceID, &ValueSize);
506 RegCloseKey(ConnectionKey);
507 }
508
509 if (ValueSize != 0)
510 {
511 sprintf(KeyName, "SYSTEM\\CurrentControlSet\\Enum\\%s", InstanceID);
512
513 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
514 {
515 ValueSize = 0;
516 if (RegQueryValueExW(ConnectionKey, L"DeviceDesc", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS &&
517 ValueType == REG_SZ)
518 {
519 /* We remove the null char, it will be re-added after */
520 DescriptionSize = ValueSize - sizeof(WCHAR);
521 CurrentAASize += DescriptionSize;
522 }
523
524 RegCloseKey(ConnectionKey);
525 }
526 }
527 }
528
529 /* We always make sure to have enough room for empty string */
530 CurrentAASize += sizeof(WCHAR);
531
532 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
533 {
534 if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK)
535 {
536 FriendlySize = mbstowcs(NULL, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen) * sizeof(WCHAR);
537 CurrentAASize += FriendlySize;
538 }
539 else
540 {
541 /* Get the friendly name */
542 HKEY ConnectionKey;
543 CHAR KeyName[256];
544
545 snprintf(KeyName, 256,
546 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
547 Entry->if_descrlen, &Entry->if_descr[0]);
548
549 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
550 {
551 DWORD ValueType;
552 DWORD ValueSize = 0;
553
554 if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS &&
555 ValueType == REG_SZ)
556 {
557 /* We remove the null char, it will be re-added after */
558 FriendlySize = ValueSize - sizeof(WCHAR);
559 CurrentAASize += FriendlySize;
560 }
561
562 RegCloseKey(ConnectionKey);
563 }
564 }
565
566 /* We always make sure to have enough room for empty string */
567 CurrentAASize += sizeof(WCHAR);
568 }
569
570 if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
571 {
572 /* Enumerate the name servers */
573 HKEY InterfaceKey;
574 CHAR KeyName[256];
575
576 snprintf(KeyName, 256,
577 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
578 Entry->if_descrlen, &Entry->if_descr[0]);
579
580 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
581 {
582 EnumNameServers(InterfaceKey, NULL, &CurrentAASize, EnumerateServerNameSize);
583 RegCloseKey(InterfaceKey);
584 }
585 }
586
587 /* This is part of what we will need */
588 TotalSize += CurrentAASize;
589
590 /* Fill in the data */
591 if ((CurrentAA) && (RemainingSize >= CurrentAASize))
592 {
593 CurrentAA->Length = sizeof(IP_ADAPTER_ADDRESSES);
594 CurrentAA->IfIndex = Entry->if_index;
595 CopyMemory(CurrentAA->PhysicalAddress, Entry->if_physaddr, Entry->if_physaddrlen);
596 CurrentAA->PhysicalAddressLength = Entry->if_physaddrlen;
597 QueryFlags(&Entry->if_descr[0], Entry->if_descrlen, &CurrentAA->Flags);
598 CurrentAA->Mtu = Entry->if_mtu;
599 CurrentAA->IfType = Entry->if_type;
600 if(Entry->if_operstatus >= IF_OPER_STATUS_CONNECTING)
601 CurrentAA->OperStatus = IfOperStatusUp;
602 else
603 CurrentAA->OperStatus = IfOperStatusDown;
604
605 /* Next items */
606 Ptr = (BYTE*)(CurrentAA + 1);
607
608 /* Now fill in the name */
609 CopyMemory(Ptr, &Entry->if_descr[0], Entry->if_descrlen);
610 CurrentAA->AdapterName = (PCHAR)Ptr;
611 CurrentAA->AdapterName[Entry->if_descrlen] = '\0';
612 /* Next items */
613 Ptr = (BYTE*)(CurrentAA->AdapterName + Entry->if_descrlen + 1);
614
615 /* The DNS suffix */
616 CurrentAA->DnsSuffix = (PWCHAR)Ptr;
617
618 if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK)
619 {
620 HKEY InterfaceKey;
621 CHAR KeyName[256];
622 DWORD ValueType, ValueSize;
623
624 snprintf(KeyName, 256,
625 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
626 Entry->if_descrlen, &Entry->if_descr[0]);
627
628 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
629 {
630 if (DhcpDomainSize != 0)
631 {
632 ValueSize = DhcpDomainSize + sizeof(WCHAR);
633 if (RegQueryValueExW(InterfaceKey, L"DhcpDomain", NULL, &ValueType, (LPBYTE)CurrentAA->DnsSuffix, &ValueSize) == ERROR_SUCCESS &&
634 ValueType == REG_SZ && ValueSize == DhcpDomainSize + sizeof(WCHAR))
635 {
636 /* We're done, next items */
637 Ptr = (BYTE*)(CurrentAA->DnsSuffix + (ValueSize / sizeof(WCHAR)));
638 }
639 else
640 {
641 /* Fail */
642 ERR("DhcpDomain name changed after probe!\n");
643 DhcpDomainSize = 0;
644 }
645 }
646
647 if (DomainSize != 0)
648 {
649 ValueSize = DomainSize + sizeof(WCHAR);
650 if (RegQueryValueExW(InterfaceKey, L"Domain", NULL, &ValueType, (LPBYTE)CurrentAA->DnsSuffix, &ValueSize) == ERROR_SUCCESS &&
651 ValueType == REG_SZ && ValueSize == DomainSize + sizeof(WCHAR))
652 {
653 /* We're done, next items */
654 Ptr = (BYTE*)(CurrentAA->DnsSuffix + (ValueSize / sizeof(WCHAR)));
655 }
656 else
657 {
658 /* Fail */
659 ERR("Domain name changed after probe!\n");
660 DomainSize = 0;
661 }
662 }
663
664 RegCloseKey(InterfaceKey);
665 }
666 }
667
668 /* In case of failure (or no name) */
669 if ((DhcpDomainSize == 0) && (DomainSize == 0))
670 {
671 CurrentAA->DnsSuffix[0] = L'\0';
672 /* Next items */
673 Ptr = (BYTE*)(CurrentAA->DnsSuffix + 1);
674 }
675
676 /* The description */
677 CurrentAA->Description = (PWCHAR)Ptr;
678
679 if (DescriptionSize != 0)
680 {
681 if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK)
682 {
683 size_t size;
684 size = mbstowcs((PWCHAR)Ptr, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen);
685 CurrentAA->Description = (PWCHAR)Ptr;
686 CurrentAA->Description[size] = '\0';
687 /* Next items */
688 Ptr = (BYTE*)(CurrentAA->Description + size + 1);
689 }
690 else
691 {
692 HKEY ConnectionKey;
693 CHAR KeyName[256];
694 CHAR InstanceID[128];
695 DWORD ValueType = 0;
696 DWORD ValueSize = 0;
697
698 snprintf(KeyName, 256,
699 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
700 Entry->if_descrlen, &Entry->if_descr[0]);
701
702 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
703 {
704 ValueSize = 128;
705 RegQueryValueExA(ConnectionKey, "PnpInstanceID", NULL, &ValueType, (LPBYTE)InstanceID, &ValueSize);
706 RegCloseKey(ConnectionKey);
707 }
708
709 if (ValueSize != 0)
710 {
711 sprintf(KeyName, "SYSTEM\\CurrentControlSet\\Enum\\%s", InstanceID);
712
713 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
714 {
715 ValueSize = DescriptionSize + sizeof(WCHAR);
716 if (RegQueryValueExW(ConnectionKey, L"DeviceDesc", NULL, &ValueType, (LPBYTE)CurrentAA->Description, &ValueSize) == ERROR_SUCCESS &&
717 ValueType == REG_SZ && ValueSize == DescriptionSize + sizeof(WCHAR))
718 {
719 /* We're done, next items */
720 Ptr = (BYTE*)(CurrentAA->Description + (ValueSize / sizeof(WCHAR)));
721 }
722 else
723 {
724 /* Fail */
725 ERR("Description name changed after probe!\n");
726 DescriptionSize = 0;
727 }
728
729 RegCloseKey(ConnectionKey);
730 }
731 }
732 }
733 }
734
735 /* In case of failure (or no name) */
736 if (DescriptionSize == 0)
737 {
738 CurrentAA->Description[0] = L'\0';
739 /* Next items */
740 Ptr = (BYTE*)(CurrentAA->Description + 1);
741 }
742
743 /* The friendly name */
744 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
745 {
746 CurrentAA->FriendlyName = (PWCHAR)Ptr;
747
748 if (FriendlySize != 0)
749 {
750 /* Get the friendly name */
751 if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK)
752 {
753 size_t size;
754 size = mbstowcs(CurrentAA->FriendlyName, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen);
755 CurrentAA->FriendlyName[size] = '\0';
756 /* Next items */
757 Ptr = (BYTE*)(CurrentAA->FriendlyName + size + 1);
758 }
759 else
760 {
761 HKEY ConnectionKey;
762 CHAR KeyName[256];
763
764 snprintf(KeyName, 256,
765 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection",
766 Entry->if_descrlen, &Entry->if_descr[0]);
767
768 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS)
769 {
770 DWORD ValueType;
771 DWORD ValueSize = FriendlySize + sizeof(WCHAR);
772
773 if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, (LPBYTE)CurrentAA->FriendlyName, &ValueSize) == ERROR_SUCCESS &&
774 ValueType == REG_SZ && ValueSize == FriendlySize + sizeof(WCHAR))
775 {
776 /* We're done, next items */
777 Ptr = (BYTE*)(CurrentAA->FriendlyName + (ValueSize / sizeof(WCHAR)));
778 }
779 else
780 {
781 /* Fail */
782 ERR("Friendly name changed after probe!\n");
783 FriendlySize = 0;
784 }
785
786 RegCloseKey(ConnectionKey);
787 }
788 else
789 {
790 /* Fail */
791 FriendlySize = 0;
792 }
793 }
794 }
795
796 /* In case of failure (or no name) */
797 if (FriendlySize == 0)
798 {
799 CurrentAA->FriendlyName[0] = L'\0';
800 /* Next items */
801 Ptr = (BYTE*)(CurrentAA->FriendlyName + 1);
802 }
803 }
804
805 /* The DNS Servers */
806 if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
807 {
808 /* Enumerate the name servers */
809 HKEY InterfaceKey;
810 CHAR KeyName[256];
811
812 snprintf(KeyName, 256,
813 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
814 Entry->if_descrlen, &Entry->if_descr[0]);
815
816 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS)
817 {
818 TRACE("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
819 }
820 else
821 {
822 PIP_ADAPTER_DNS_SERVER_ADDRESS* ServerAddressPtr;
823
824 CurrentAA->FirstDnsServerAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)Ptr;
825 ServerAddressPtr = &CurrentAA->FirstDnsServerAddress;
826
827 EnumNameServers(InterfaceKey, NULL, &ServerAddressPtr, EnumerateServerName);
828 RegCloseKey(InterfaceKey);
829
830 /* Set the last entry in the list as having NULL next member */
831 Ptr = (BYTE*)*ServerAddressPtr;
832 *ServerAddressPtr = NULL;
833 }
834 }
835
836 /* We're done for this interface */
837 PreviousAA = CurrentAA;
838 RemainingSize -= CurrentAASize;
839 }
840 }
841 }
842
843 if (AdaptersCount == 0)
844 {
845 /* Uh? Not even localhost ?! */
846 ERR("No Adapters found!\n");
847 *pOutBufLen = 0;
848 return ERROR_NO_DATA;
849 }
850
851 /* See if we have anything to add */
852 // FIXME: Anycast and multicast
853 if ((Flags & (GAA_FLAG_SKIP_UNICAST | GAA_FLAG_INCLUDE_PREFIX)) == GAA_FLAG_SKIP_UNICAST)
854 goto Success;
855
856 /* Now fill in the addresses */
857 for (i = 0; i < InterfacesCount; i++)
858 {
859 /* Look for network layers */
860 if ((InterfacesList[i].tei_entity == CL_NL_ENTITY)
861 || (InterfacesList[i].tei_entity == CO_NL_ENTITY))
862 {
863 IPSNMPInfo SnmpInfo;
864 PIP_ADAPTER_ADDRESSES CurrentAA = NULL;
865 IPAddrEntry* AddrEntries;
866 ULONG j;
867
868 /* Get its SNMP info */
869 Status = GetSnmpInfo(TcpFile, InterfacesList[i], &SnmpInfo);
870 if (!NT_SUCCESS(Status))
871 goto Error;
872
873 if (SnmpInfo.ipsi_numaddr == 0)
874 continue;
875
876 /* Allocate the address entry array and get them */
877 AddrEntries = HeapAlloc(GetProcessHeap(),
878 HEAP_ZERO_MEMORY,
879 SnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
880 if (!AddrEntries)
881 {
882 Status = STATUS_NO_MEMORY;
883 goto Error;
884 }
885 Status = GetAddrEntries(TcpFile, InterfacesList[i], AddrEntries, SnmpInfo.ipsi_numaddr);
886 if (!NT_SUCCESS(Status))
887 {
888 HeapFree(GetProcessHeap(), 0, AddrEntries);
889 goto Error;
890 }
891
892 for (j = 0; j < SnmpInfo.ipsi_numaddr; j++)
893 {
894 /* Find the adapters struct for this address. */
895 if (pAdapterAddresses)
896 {
897 CurrentAA = pAdapterAddresses;
898 while (CurrentAA)
899 {
900 if (CurrentAA->IfIndex == AddrEntries[j].iae_index)
901 break;
902
903 CurrentAA = CurrentAA->Next;
904 }
905
906 if (!CurrentAA)
907 {
908 ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries[j].iae_index);
909 /* Go to the next address */
910 continue;
911 }
912 }
913
914 TRACE("address is 0x%08x, mask is 0x%08x\n", AddrEntries[j].iae_addr, AddrEntries[j].iae_mask);
915
916 //FIXME: For now reactos only supports unicast addresses
917 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
918 {
919 ULONG Size = sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR);
920
921 if (Ptr && (RemainingSize >= Size))
922 {
923 PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress = (PIP_ADAPTER_UNICAST_ADDRESS)Ptr;
924
925 /* Fill in the structure */
926 UnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
927 UnicastAddress->Next = CurrentAA->FirstUnicastAddress;
928
929 // FIXME: Put meaningful value here
930 UnicastAddress->Flags = 0;
931 UnicastAddress->PrefixOrigin = IpPrefixOriginOther;
932 UnicastAddress->SuffixOrigin = IpSuffixOriginOther;
933 UnicastAddress->DadState = IpDadStatePreferred;
934 UnicastAddress->ValidLifetime = 0xFFFFFFFF;
935 UnicastAddress->PreferredLifetime = 0xFFFFFFFF;
936
937 /* Set the address */
938 //FIXME: ipv4 only (again...)
939 UnicastAddress->Address.lpSockaddr = (LPSOCKADDR)(UnicastAddress + 1);
940 UnicastAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
941 UnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
942 ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_port = 0;
943 ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr = AddrEntries[j].iae_addr;
944
945 CurrentAA->FirstUnicastAddress = UnicastAddress;
946 Ptr += Size;
947 RemainingSize -= Size;
948 }
949
950 TotalSize += Size;
951 }
952
953 if (Flags & GAA_FLAG_INCLUDE_PREFIX)
954 {
955 ULONG Size = sizeof(IP_ADAPTER_PREFIX) + sizeof(SOCKADDR);
956
957 if (Ptr && (RemainingSize >= Size))
958 {
959 PIP_ADAPTER_PREFIX Prefix = (PIP_ADAPTER_PREFIX)Ptr;
960
961 /* Fill in the structure */
962 Prefix->Length = sizeof(IP_ADAPTER_PREFIX);
963 Prefix->Next = CurrentAA->FirstPrefix;
964
965 /* Set the address */
966 //FIXME: ipv4 only (again...)
967 Prefix->Address.lpSockaddr = (LPSOCKADDR)(Prefix + 1);
968 Prefix->Address.iSockaddrLength = sizeof(SOCKADDR);
969 Prefix->Address.lpSockaddr->sa_family = AF_INET;
970 ((LPSOCKADDR_IN)Prefix->Address.lpSockaddr)->sin_port = 0;
971 ((LPSOCKADDR_IN)Prefix->Address.lpSockaddr)->sin_addr.S_un.S_addr = AddrEntries[j].iae_addr & AddrEntries[j].iae_mask;
972
973 /* Compute the prefix size */
974 Prefix->PrefixLength = CountPrefixBits(AddrEntries[j].iae_mask);
975
976 CurrentAA->FirstPrefix = Prefix;
977 Ptr += Size;
978 RemainingSize -= Size;
979 }
980
981 TotalSize += Size;
982 }
983 }
984
985 HeapFree(GetProcessHeap(), 0, AddrEntries);
986 }
987 }
988
989Success:
990 /* We're done */
991 HeapFree(GetProcessHeap(), 0, InterfacesList);
992 NtClose(TcpFile);
993 *pOutBufLen = TotalSize;
994 TRACE("TotalSize: %x\n", *pOutBufLen);
995 return ERROR_SUCCESS;
996
997Error:
998 ERR("Failed! Status 0x%08x\n", Status);
999 *pOutBufLen = 0;
1000 HeapFree(GetProcessHeap(), 0, InterfacesList);
1001 NtClose(TcpFile);
1002 return RtlNtStatusToDosError(Status);
1003}
1004
1005
1006DWORD
1007WINAPI
1008NhpAllocateAndGetInterfaceInfoFromStack(
1009 _Inout_ IP_INTERFACE_NAME_INFO **ppTable,
1010 _Inout_ PDWORD pdwCount,
1011 _In_ BOOL bOrder,
1012 _In_ HANDLE hHeap,
1013 _In_ DWORD dwFlags)
1014{
1015 NTSTATUS Status;
1016 HANDLE TcpFile;
1017 TDIEntityID* InterfacesList;
1018 ULONG InterfacesCount;
1019 ULONG AdaptersCount = 0;
1020 ULONG i, j;
1021 IP_INTERFACE_NAME_INFO *pTable = NULL;
1022 UNICODE_STRING UnicodeGuidString;
1023 ANSI_STRING AnsiGuidString;
1024
1025 TRACE("ppTable %p, pdwCount %p, bOrder %u, hHeap %p, dwFlags %lu\n",
1026 ppTable, pdwCount, bOrder, hHeap, dwFlags);
1027
1028 /* open the tcpip driver */
1029 Status = openTcpFile(&TcpFile, FILE_READ_DATA);
1030 if (!NT_SUCCESS(Status))
1031 {
1032 ERR("Could not open handle to tcpip.sys. Status %08x\n", Status);
1033 return RtlNtStatusToDosError(Status);
1034 }
1035
1036 /* Get the interfaces list */
1037 Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount);
1038 if (!NT_SUCCESS(Status))
1039 {
1040 ERR("Could not get adapters list. Status %08x\n", Status);
1041 NtClose(TcpFile);
1042 return RtlNtStatusToDosError(Status);
1043 }
1044
1045 for (i = 0; i < InterfacesCount; i++)
1046 {
1047 if (InterfacesList[i].tei_entity == IF_ENTITY)
1048 {
1049 BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) +
1050 RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)];
1051 IFEntry* Entry = (IFEntry*)EntryBuffer;
1052
1053 /* Get the entry */
1054 Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry);
1055 if (!NT_SUCCESS(Status))
1056 goto Error;
1057
1058 if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK)
1059 AdaptersCount++;
1060 }
1061 }
1062
1063 TRACE("InterfacesCount %lu AdaptersCount %lu\n", InterfacesCount, AdaptersCount);
1064
1065 pTable = HeapAlloc(hHeap, dwFlags, AdaptersCount * sizeof(IP_INTERFACE_NAME_INFO));
1066 if (pTable == NULL)
1067 {
1068 Status = STATUS_NO_MEMORY;
1069 goto Error;
1070 }
1071
1072 for (i = 0, j = 0; i < InterfacesCount; i++)
1073 {
1074 if (InterfacesList[i].tei_entity == IF_ENTITY)
1075 {
1076 BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) +
1077 RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)];
1078 IFEntry* Entry = (IFEntry*)EntryBuffer;
1079
1080 /* Get the entry */
1081 Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry);
1082 if (!NT_SUCCESS(Status))
1083 goto Error;
1084
1085 TRACE("Got entity %*s, index %u.\n",
1086 Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index);
1087
1088 if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK)
1089 {
1090 pTable[j].Index = Entry->if_index;
1091 pTable[j].MediaType = Entry->if_type;
1092 pTable[j].ConnectionType = 1; //IF_CONNECTION_DEDICATED;
1093 pTable[j].AccessType = 2; //IF_ACCESS_BROADCAST;
1094
1095 AnsiGuidString.Length = Entry->if_descrlen;
1096 AnsiGuidString.MaximumLength = Entry->if_descrlen;
1097 AnsiGuidString.Buffer = (PCHAR)Entry->if_descr;
1098 Status = RtlAnsiStringToUnicodeString(&UnicodeGuidString,
1099 &AnsiGuidString, TRUE);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 ERR("Status %lx\n", Status);
1103 goto Error;
1104 }
1105
1106 Status = RtlGUIDFromString(&UnicodeGuidString, &pTable[j].DeviceGuid);
1107 RtlFreeUnicodeString(&UnicodeGuidString);
1108 if (!NT_SUCCESS(Status))
1109 {
1110 ERR("Status %lx\n", Status);
1111 goto Error;
1112 }
1113
1114 memset(&pTable[j].InterfaceGuid, 0, sizeof(GUID));
1115
1116 j++;
1117 }
1118 }
1119 }
1120
1121 /* We're done */
1122 HeapFree(GetProcessHeap(), 0, InterfacesList);
1123 NtClose(TcpFile);
1124 *ppTable = pTable;
1125 *pdwCount = AdaptersCount;
1126 return ERROR_SUCCESS;
1127
1128Error:
1129 ERR("Failed! Status 0x%08x\n", Status);
1130 if (pTable)
1131 HeapFree(hHeap, 0, pTable);
1132 *ppTable = NULL;
1133 *pdwCount = 0;
1134 HeapFree(GetProcessHeap(), 0, InterfacesList);
1135 NtClose(TcpFile);
1136 return RtlNtStatusToDosError(Status);
1137}
1138
1139#endif