Reactos
at master 1139 lines 41 kB view raw
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