/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/iphlpapi/address.c * PURPOSE: iphlpapi implementation - Adapter Address APIs * PROGRAMMERS: Jérôme Gardou (jerome.gardou@reactos.org) */ #include "iphlpapi_private.h" WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); #ifdef GetAdaptersAddressesV2 /* Helper for GetAdaptersAddresses: * Retrieves the list of network adapters from tcpip.sys */ static NTSTATUS GetInterfacesList( _In_ HANDLE TcpFile, _Out_ TDIEntityID **EntityList, _Out_ ULONG* InterfaceCount) { TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo; IO_STATUS_BLOCK StatusBlock; NTSTATUS Status; ULONG_PTR BufferSize; ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo)); TcpQueryInfo.ID.toi_class = INFO_CLASS_GENERIC; TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER; TcpQueryInfo.ID.toi_id = ENTITY_LIST_ID; TcpQueryInfo.ID.toi_entity.tei_entity = GENERIC_ENTITY; TcpQueryInfo.ID.toi_entity.tei_instance = 0; Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &StatusBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), NULL, 0); if (Status == STATUS_PENDING) { /* So we have to wait a bit */ Status = NtWaitForSingleObject(TcpFile, FALSE, NULL); if (NT_SUCCESS(Status)) Status = StatusBlock.Status; } if (!NT_SUCCESS(Status)) return Status; BufferSize = StatusBlock.Information; *EntityList = HeapAlloc(GetProcessHeap(), 0, BufferSize); if (!*EntityList) return STATUS_NO_MEMORY; /* Do the real call */ Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &StatusBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), *EntityList, BufferSize); if (Status == STATUS_PENDING) { /* So we have to wait a bit */ Status = NtWaitForSingleObject(TcpFile, FALSE, NULL); if (NT_SUCCESS(Status)) Status = StatusBlock.Status; } if (!NT_SUCCESS(Status)) { HeapFree(GetProcessHeap(), 0, *EntityList); return Status; } *InterfaceCount = BufferSize / sizeof(TDIEntityID); return Status; } static NTSTATUS GetSnmpInfo( _In_ HANDLE TcpFile, _In_ TDIEntityID InterfaceID, _Out_ IPSNMPInfo* Info) { TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo; IO_STATUS_BLOCK StatusBlock; NTSTATUS Status; ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo)); TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL; TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER; TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID; TcpQueryInfo.ID.toi_entity = InterfaceID; Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &StatusBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), Info, sizeof(*Info)); if (Status == STATUS_PENDING) { /* So we have to wait a bit */ Status = NtWaitForSingleObject(TcpFile, FALSE, NULL); if (NT_SUCCESS(Status)) Status = StatusBlock.Status; } return Status; } static NTSTATUS GetAddrEntries( _In_ HANDLE TcpFile, _In_ TDIEntityID InterfaceID, _Out_ IPAddrEntry* Entries, _In_ ULONG NumEntries) { TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo; IO_STATUS_BLOCK StatusBlock; NTSTATUS Status; ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo)); TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL; TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER; TcpQueryInfo.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID; TcpQueryInfo.ID.toi_entity = InterfaceID; Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &StatusBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), Entries, NumEntries * sizeof(Entries[0])); if (Status == STATUS_PENDING) { /* So we have to wait a bit */ Status = NtWaitForSingleObject(TcpFile, FALSE, NULL); if (NT_SUCCESS(Status)) Status = StatusBlock.Status; } return Status; } /* * Fills the IFEntry buffer from tcpip.sys. * The buffer size MUST be FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1]). * See MSDN IFEntry struct definition if you don't believe me. ;-) */ static NTSTATUS GetInterfaceEntry( _In_ HANDLE TcpFile, _In_ TDIEntityID InterfaceID, _Out_ IFEntry* Entry) { TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo; IO_STATUS_BLOCK StatusBlock; NTSTATUS Status; ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo)); TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL; TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER; TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID; TcpQueryInfo.ID.toi_entity = InterfaceID; Status = NtDeviceIoControlFile( TcpFile, NULL, NULL, NULL, &StatusBlock, IOCTL_TCP_QUERY_INFORMATION_EX, &TcpQueryInfo, sizeof(TcpQueryInfo), Entry, FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1])); if (Status == STATUS_PENDING) { /* So we have to wait a bit */ Status = NtWaitForSingleObject(TcpFile, FALSE, NULL); if (NT_SUCCESS(Status)) Status = StatusBlock.Status; } return Status; } /* Helpers to get the list of DNS for an interface */ static VOID EnumerateServerNameSize( _In_ PWCHAR Interface, _In_ PWCHAR NameServer, _Inout_ PVOID Data) { ULONG* BufferSize = Data; /* This is just sizing here */ UNREFERENCED_PARAMETER(Interface); UNREFERENCED_PARAMETER(NameServer); *BufferSize += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR); } static VOID EnumerateServerName( _In_ PWCHAR Interface, _In_ PWCHAR NameServer, _Inout_ PVOID Data) { PIP_ADAPTER_DNS_SERVER_ADDRESS** Ptr = Data; PIP_ADAPTER_DNS_SERVER_ADDRESS ServerAddress = **Ptr; PCWSTR Terminator; NTSTATUS Status; UNREFERENCED_PARAMETER(Interface); ServerAddress->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS); ServerAddress->Address.lpSockaddr = (PVOID)(ServerAddress + 1); ServerAddress->Address.iSockaddrLength = sizeof(SOCKADDR); ServerAddress->Address.lpSockaddr->sa_family = AF_INET; ((LPSOCKADDR_IN)ServerAddress->Address.lpSockaddr)->sin_port = 0; Status = RtlIpv4StringToAddressW(NameServer, FALSE, &Terminator, &((LPSOCKADDR_IN)ServerAddress->Address.lpSockaddr)->sin_addr); if (!NT_SUCCESS(Status)) { /* Pass along, name conversion failed */ ERR("%S is not a valid IP address\n", NameServer); return; } /* Go to next item */ ServerAddress->Next = (PVOID)(ServerAddress->Address.lpSockaddr + 1); *Ptr = &ServerAddress->Next; } static VOID QueryFlags( _In_ PUCHAR Interface, _In_ DWORD InterfaceLength, _Out_ LPDWORD Flags) { HKEY InterfaceKey; CHAR KeyName[256]; DWORD Type, Size, Data; *Flags = 0; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s", InterfaceLength, Interface); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS) { Size = sizeof(DWORD); if (RegQueryValueExA(InterfaceKey, "EnableDHCP", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS && Type == REG_DWORD && Data == 1) { *Flags |= IP_ADAPTER_DHCP_ENABLED; } Size = sizeof(DWORD); if (RegQueryValueExA(InterfaceKey, "RegisterAdapterName", NULL, &Type, (LPBYTE)&Data, &Size) == ERROR_SUCCESS && Type == REG_DWORD && Data == 1) { *Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX; } Size = 0; if (RegQueryValueExA(InterfaceKey, "NameServer", NULL, &Type, (LPBYTE)&Data, &Size) != ERROR_SUCCESS) { *Flags |= IP_ADAPTER_DDNS_ENABLED; } RegCloseKey(InterfaceKey); } // FIXME: handle 0x8 -> 0x20 } static ULONG CountPrefixBits( _In_ ULONG Netmask) { ULONG i, BitCount = 0; for (i = 0; i < sizeof(ULONG) * 8; i++) { if ((Netmask & (1 << i)) == 0) break; BitCount++; } return BitCount; } DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses( _In_ ULONG Family, _In_ ULONG Flags, _In_ PVOID Reserved, _Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses, _Inout_ PULONG pOutBufLen) { NTSTATUS Status; HANDLE TcpFile; TDIEntityID* InterfacesList; ULONG InterfacesCount; ULONG AdaptersCount = 0; ULONG i; ULONG TotalSize = 0, RemainingSize; BYTE* Ptr = (BYTE*)pAdapterAddresses; DWORD MIN_SIZE = 15 * 1024; PIP_ADAPTER_ADDRESSES PreviousAA = NULL; TRACE("Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p\n", Family, Flags, Reserved, pAdapterAddresses, pOutBufLen); if (!pOutBufLen) return ERROR_INVALID_PARAMETER; // FIXME: the exact needed size should be computed first, BEFORE doing any write to the output buffer. // As suggested by MSDN, require a 15 KB buffer, which allows to React properly to length checks. if(!Ptr || *pOutBufLen < MIN_SIZE) { *pOutBufLen = MIN_SIZE; return ERROR_BUFFER_OVERFLOW; } switch(Family) { case AF_INET: break; case AF_INET6: /* One day maybe... */ FIXME("IPv6 is not supported in ReactOS!\n"); /* We got nothing to say in this case */ return ERROR_NO_DATA; break; case AF_UNSPEC: WARN("IPv6 addresses ignored, IPv4 only\n"); Family = AF_INET; break; default: ERR("Invalid family 0x%x\n", Family); return ERROR_INVALID_PARAMETER; break; } RemainingSize = *pOutBufLen; if (Ptr) ZeroMemory(Ptr, RemainingSize); /* open the tcpip driver */ Status = openTcpFile(&TcpFile, FILE_READ_DATA); if (!NT_SUCCESS(Status)) { ERR("Could not open handle to tcpip.sys. Status %08x\n", Status); return RtlNtStatusToDosError(Status); } /* Get the interfaces list */ Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount); if (!NT_SUCCESS(Status)) { ERR("Could not get adapters list. Status %08x\n", Status); NtClose(TcpFile); return RtlNtStatusToDosError(Status); } /* Let's see if we got any adapter. */ for (i = 0; i < InterfacesCount; i++) { PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr; ULONG CurrentAASize = 0; ULONG FriendlySize = 0, DescriptionSize = 0; ULONG DhcpDomainSize = 0, DomainSize = 0; if (InterfacesList[i].tei_entity == IF_ENTITY) { BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) + RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)]; IFEntry* Entry = (IFEntry*)EntryBuffer; /* Remember we got one */ AdaptersCount++; /* Set the pointer to this instance in the previous one*/ if(PreviousAA) PreviousAA->Next = CurrentAA; /* Of course we need some space for the base structure. */ CurrentAASize = sizeof(IP_ADAPTER_ADDRESSES); /* Get the entry */ Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry); if (!NT_SUCCESS(Status)) goto Error; TRACE("Got entity %*s, index %u.\n", Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index); /* Add the adapter name */ CurrentAASize += Entry->if_descrlen + sizeof(CHAR); /* Add the DNS suffix */ if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK) { HKEY InterfaceKey; CHAR KeyName[256]; DWORD ValueType, ValueSize, Data; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS) { ValueSize = sizeof(DWORD); if (RegQueryValueExW(InterfaceKey, L"EnableDHCP", NULL, &ValueType, (LPBYTE)&Data, &ValueSize) == ERROR_SUCCESS && ValueType == REG_DWORD && Data == 1) { ValueSize = sizeof(DWORD); if (RegQueryValueExW(InterfaceKey, L"DhcpDomain", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ) { /* We remove the null char, it will be re-added after */ DhcpDomainSize = ValueSize - sizeof(WCHAR); CurrentAASize += DhcpDomainSize; } } else { ValueSize = sizeof(DWORD); if (RegQueryValueExW(InterfaceKey, L"Domain", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ) { /* We remove the null char, it will be re-added after */ DomainSize = ValueSize - sizeof(WCHAR); CurrentAASize += DomainSize; } } RegCloseKey(InterfaceKey); } } CurrentAASize += sizeof(WCHAR); /* Add the description. */ if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK) { DescriptionSize = mbstowcs(NULL, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen) * sizeof(WCHAR); CurrentAASize += DescriptionSize; } else { HKEY ConnectionKey; CHAR KeyName[256]; CHAR InstanceID[128]; DWORD ValueType = 0; DWORD ValueSize = 0; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { ValueSize = 128; RegQueryValueExA(ConnectionKey, "PnpInstanceID", NULL, &ValueType, (LPBYTE)InstanceID, &ValueSize); RegCloseKey(ConnectionKey); } if (ValueSize != 0) { sprintf(KeyName, "SYSTEM\\CurrentControlSet\\Enum\\%s", InstanceID); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { ValueSize = 0; if (RegQueryValueExW(ConnectionKey, L"DeviceDesc", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ) { /* We remove the null char, it will be re-added after */ DescriptionSize = ValueSize - sizeof(WCHAR); CurrentAASize += DescriptionSize; } RegCloseKey(ConnectionKey); } } } /* We always make sure to have enough room for empty string */ CurrentAASize += sizeof(WCHAR); if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) { if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK) { FriendlySize = mbstowcs(NULL, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen) * sizeof(WCHAR); CurrentAASize += FriendlySize; } else { /* Get the friendly name */ HKEY ConnectionKey; CHAR KeyName[256]; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { DWORD ValueType; DWORD ValueSize = 0; if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, NULL, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ) { /* We remove the null char, it will be re-added after */ FriendlySize = ValueSize - sizeof(WCHAR); CurrentAASize += FriendlySize; } RegCloseKey(ConnectionKey); } } /* We always make sure to have enough room for empty string */ CurrentAASize += sizeof(WCHAR); } if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER)) { /* Enumerate the name servers */ HKEY InterfaceKey; CHAR KeyName[256]; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS) { EnumNameServers(InterfaceKey, NULL, &CurrentAASize, EnumerateServerNameSize); RegCloseKey(InterfaceKey); } } /* This is part of what we will need */ TotalSize += CurrentAASize; /* Fill in the data */ if ((CurrentAA) && (RemainingSize >= CurrentAASize)) { CurrentAA->Length = sizeof(IP_ADAPTER_ADDRESSES); CurrentAA->IfIndex = Entry->if_index; CopyMemory(CurrentAA->PhysicalAddress, Entry->if_physaddr, Entry->if_physaddrlen); CurrentAA->PhysicalAddressLength = Entry->if_physaddrlen; QueryFlags(&Entry->if_descr[0], Entry->if_descrlen, &CurrentAA->Flags); CurrentAA->Mtu = Entry->if_mtu; CurrentAA->IfType = Entry->if_type; if(Entry->if_operstatus >= IF_OPER_STATUS_CONNECTING) CurrentAA->OperStatus = IfOperStatusUp; else CurrentAA->OperStatus = IfOperStatusDown; /* Next items */ Ptr = (BYTE*)(CurrentAA + 1); /* Now fill in the name */ CopyMemory(Ptr, &Entry->if_descr[0], Entry->if_descrlen); CurrentAA->AdapterName = (PCHAR)Ptr; CurrentAA->AdapterName[Entry->if_descrlen] = '\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->AdapterName + Entry->if_descrlen + 1); /* The DNS suffix */ CurrentAA->DnsSuffix = (PWCHAR)Ptr; if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK) { HKEY InterfaceKey; CHAR KeyName[256]; DWORD ValueType, ValueSize; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS) { if (DhcpDomainSize != 0) { ValueSize = DhcpDomainSize + sizeof(WCHAR); if (RegQueryValueExW(InterfaceKey, L"DhcpDomain", NULL, &ValueType, (LPBYTE)CurrentAA->DnsSuffix, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ && ValueSize == DhcpDomainSize + sizeof(WCHAR)) { /* We're done, next items */ Ptr = (BYTE*)(CurrentAA->DnsSuffix + (ValueSize / sizeof(WCHAR))); } else { /* Fail */ ERR("DhcpDomain name changed after probe!\n"); DhcpDomainSize = 0; } } if (DomainSize != 0) { ValueSize = DomainSize + sizeof(WCHAR); if (RegQueryValueExW(InterfaceKey, L"Domain", NULL, &ValueType, (LPBYTE)CurrentAA->DnsSuffix, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ && ValueSize == DomainSize + sizeof(WCHAR)) { /* We're done, next items */ Ptr = (BYTE*)(CurrentAA->DnsSuffix + (ValueSize / sizeof(WCHAR))); } else { /* Fail */ ERR("Domain name changed after probe!\n"); DomainSize = 0; } } RegCloseKey(InterfaceKey); } } /* In case of failure (or no name) */ if ((DhcpDomainSize == 0) && (DomainSize == 0)) { CurrentAA->DnsSuffix[0] = L'\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->DnsSuffix + 1); } /* The description */ CurrentAA->Description = (PWCHAR)Ptr; if (DescriptionSize != 0) { if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK) { size_t size; size = mbstowcs((PWCHAR)Ptr, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen); CurrentAA->Description = (PWCHAR)Ptr; CurrentAA->Description[size] = '\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->Description + size + 1); } else { HKEY ConnectionKey; CHAR KeyName[256]; CHAR InstanceID[128]; DWORD ValueType = 0; DWORD ValueSize = 0; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { ValueSize = 128; RegQueryValueExA(ConnectionKey, "PnpInstanceID", NULL, &ValueType, (LPBYTE)InstanceID, &ValueSize); RegCloseKey(ConnectionKey); } if (ValueSize != 0) { sprintf(KeyName, "SYSTEM\\CurrentControlSet\\Enum\\%s", InstanceID); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { ValueSize = DescriptionSize + sizeof(WCHAR); if (RegQueryValueExW(ConnectionKey, L"DeviceDesc", NULL, &ValueType, (LPBYTE)CurrentAA->Description, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ && ValueSize == DescriptionSize + sizeof(WCHAR)) { /* We're done, next items */ Ptr = (BYTE*)(CurrentAA->Description + (ValueSize / sizeof(WCHAR))); } else { /* Fail */ ERR("Description name changed after probe!\n"); DescriptionSize = 0; } RegCloseKey(ConnectionKey); } } } } /* In case of failure (or no name) */ if (DescriptionSize == 0) { CurrentAA->Description[0] = L'\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->Description + 1); } /* The friendly name */ if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) { CurrentAA->FriendlyName = (PWCHAR)Ptr; if (FriendlySize != 0) { /* Get the friendly name */ if (Entry->if_type == IF_TYPE_SOFTWARE_LOOPBACK) { size_t size; size = mbstowcs(CurrentAA->FriendlyName, (PCSTR)&Entry->if_descr[0], Entry->if_descrlen); CurrentAA->FriendlyName[size] = '\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->FriendlyName + size + 1); } else { HKEY ConnectionKey; CHAR KeyName[256]; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%*s\\Connection", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &ConnectionKey) == ERROR_SUCCESS) { DWORD ValueType; DWORD ValueSize = FriendlySize + sizeof(WCHAR); if (RegQueryValueExW(ConnectionKey, L"Name", NULL, &ValueType, (LPBYTE)CurrentAA->FriendlyName, &ValueSize) == ERROR_SUCCESS && ValueType == REG_SZ && ValueSize == FriendlySize + sizeof(WCHAR)) { /* We're done, next items */ Ptr = (BYTE*)(CurrentAA->FriendlyName + (ValueSize / sizeof(WCHAR))); } else { /* Fail */ ERR("Friendly name changed after probe!\n"); FriendlySize = 0; } RegCloseKey(ConnectionKey); } else { /* Fail */ FriendlySize = 0; } } } /* In case of failure (or no name) */ if (FriendlySize == 0) { CurrentAA->FriendlyName[0] = L'\0'; /* Next items */ Ptr = (BYTE*)(CurrentAA->FriendlyName + 1); } } /* The DNS Servers */ if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER)) { /* Enumerate the name servers */ HKEY InterfaceKey; CHAR KeyName[256]; snprintf(KeyName, 256, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s", Entry->if_descrlen, &Entry->if_descr[0]); if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS) { TRACE("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]); } else { PIP_ADAPTER_DNS_SERVER_ADDRESS* ServerAddressPtr; CurrentAA->FirstDnsServerAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)Ptr; ServerAddressPtr = &CurrentAA->FirstDnsServerAddress; EnumNameServers(InterfaceKey, NULL, &ServerAddressPtr, EnumerateServerName); RegCloseKey(InterfaceKey); /* Set the last entry in the list as having NULL next member */ Ptr = (BYTE*)*ServerAddressPtr; *ServerAddressPtr = NULL; } } /* We're done for this interface */ PreviousAA = CurrentAA; RemainingSize -= CurrentAASize; } } } if (AdaptersCount == 0) { /* Uh? Not even localhost ?! */ ERR("No Adapters found!\n"); *pOutBufLen = 0; return ERROR_NO_DATA; } /* See if we have anything to add */ // FIXME: Anycast and multicast if ((Flags & (GAA_FLAG_SKIP_UNICAST | GAA_FLAG_INCLUDE_PREFIX)) == GAA_FLAG_SKIP_UNICAST) goto Success; /* Now fill in the addresses */ for (i = 0; i < InterfacesCount; i++) { /* Look for network layers */ if ((InterfacesList[i].tei_entity == CL_NL_ENTITY) || (InterfacesList[i].tei_entity == CO_NL_ENTITY)) { IPSNMPInfo SnmpInfo; PIP_ADAPTER_ADDRESSES CurrentAA = NULL; IPAddrEntry* AddrEntries; ULONG j; /* Get its SNMP info */ Status = GetSnmpInfo(TcpFile, InterfacesList[i], &SnmpInfo); if (!NT_SUCCESS(Status)) goto Error; if (SnmpInfo.ipsi_numaddr == 0) continue; /* Allocate the address entry array and get them */ AddrEntries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0])); if (!AddrEntries) { Status = STATUS_NO_MEMORY; goto Error; } Status = GetAddrEntries(TcpFile, InterfacesList[i], AddrEntries, SnmpInfo.ipsi_numaddr); if (!NT_SUCCESS(Status)) { HeapFree(GetProcessHeap(), 0, AddrEntries); goto Error; } for (j = 0; j < SnmpInfo.ipsi_numaddr; j++) { /* Find the adapters struct for this address. */ if (pAdapterAddresses) { CurrentAA = pAdapterAddresses; while (CurrentAA) { if (CurrentAA->IfIndex == AddrEntries[j].iae_index) break; CurrentAA = CurrentAA->Next; } if (!CurrentAA) { ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries[j].iae_index); /* Go to the next address */ continue; } } TRACE("address is 0x%08x, mask is 0x%08x\n", AddrEntries[j].iae_addr, AddrEntries[j].iae_mask); //FIXME: For now reactos only supports unicast addresses if (!(Flags & GAA_FLAG_SKIP_UNICAST)) { ULONG Size = sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR); if (Ptr && (RemainingSize >= Size)) { PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress = (PIP_ADAPTER_UNICAST_ADDRESS)Ptr; /* Fill in the structure */ UnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS); UnicastAddress->Next = CurrentAA->FirstUnicastAddress; // FIXME: Put meaningful value here UnicastAddress->Flags = 0; UnicastAddress->PrefixOrigin = IpPrefixOriginOther; UnicastAddress->SuffixOrigin = IpSuffixOriginOther; UnicastAddress->DadState = IpDadStatePreferred; UnicastAddress->ValidLifetime = 0xFFFFFFFF; UnicastAddress->PreferredLifetime = 0xFFFFFFFF; /* Set the address */ //FIXME: ipv4 only (again...) UnicastAddress->Address.lpSockaddr = (LPSOCKADDR)(UnicastAddress + 1); UnicastAddress->Address.iSockaddrLength = sizeof(SOCKADDR); UnicastAddress->Address.lpSockaddr->sa_family = AF_INET; ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_port = 0; ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr = AddrEntries[j].iae_addr; CurrentAA->FirstUnicastAddress = UnicastAddress; Ptr += Size; RemainingSize -= Size; } TotalSize += Size; } if (Flags & GAA_FLAG_INCLUDE_PREFIX) { ULONG Size = sizeof(IP_ADAPTER_PREFIX) + sizeof(SOCKADDR); if (Ptr && (RemainingSize >= Size)) { PIP_ADAPTER_PREFIX Prefix = (PIP_ADAPTER_PREFIX)Ptr; /* Fill in the structure */ Prefix->Length = sizeof(IP_ADAPTER_PREFIX); Prefix->Next = CurrentAA->FirstPrefix; /* Set the address */ //FIXME: ipv4 only (again...) Prefix->Address.lpSockaddr = (LPSOCKADDR)(Prefix + 1); Prefix->Address.iSockaddrLength = sizeof(SOCKADDR); Prefix->Address.lpSockaddr->sa_family = AF_INET; ((LPSOCKADDR_IN)Prefix->Address.lpSockaddr)->sin_port = 0; ((LPSOCKADDR_IN)Prefix->Address.lpSockaddr)->sin_addr.S_un.S_addr = AddrEntries[j].iae_addr & AddrEntries[j].iae_mask; /* Compute the prefix size */ Prefix->PrefixLength = CountPrefixBits(AddrEntries[j].iae_mask); CurrentAA->FirstPrefix = Prefix; Ptr += Size; RemainingSize -= Size; } TotalSize += Size; } } HeapFree(GetProcessHeap(), 0, AddrEntries); } } Success: /* We're done */ HeapFree(GetProcessHeap(), 0, InterfacesList); NtClose(TcpFile); *pOutBufLen = TotalSize; TRACE("TotalSize: %x\n", *pOutBufLen); return ERROR_SUCCESS; Error: ERR("Failed! Status 0x%08x\n", Status); *pOutBufLen = 0; HeapFree(GetProcessHeap(), 0, InterfacesList); NtClose(TcpFile); return RtlNtStatusToDosError(Status); } DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack( _Inout_ IP_INTERFACE_NAME_INFO **ppTable, _Inout_ PDWORD pdwCount, _In_ BOOL bOrder, _In_ HANDLE hHeap, _In_ DWORD dwFlags) { NTSTATUS Status; HANDLE TcpFile; TDIEntityID* InterfacesList; ULONG InterfacesCount; ULONG AdaptersCount = 0; ULONG i, j; IP_INTERFACE_NAME_INFO *pTable = NULL; UNICODE_STRING UnicodeGuidString; ANSI_STRING AnsiGuidString; TRACE("ppTable %p, pdwCount %p, bOrder %u, hHeap %p, dwFlags %lu\n", ppTable, pdwCount, bOrder, hHeap, dwFlags); /* open the tcpip driver */ Status = openTcpFile(&TcpFile, FILE_READ_DATA); if (!NT_SUCCESS(Status)) { ERR("Could not open handle to tcpip.sys. Status %08x\n", Status); return RtlNtStatusToDosError(Status); } /* Get the interfaces list */ Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount); if (!NT_SUCCESS(Status)) { ERR("Could not get adapters list. Status %08x\n", Status); NtClose(TcpFile); return RtlNtStatusToDosError(Status); } for (i = 0; i < InterfacesCount; i++) { if (InterfacesList[i].tei_entity == IF_ENTITY) { BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) + RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)]; IFEntry* Entry = (IFEntry*)EntryBuffer; /* Get the entry */ Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry); if (!NT_SUCCESS(Status)) goto Error; if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK) AdaptersCount++; } } TRACE("InterfacesCount %lu AdaptersCount %lu\n", InterfacesCount, AdaptersCount); pTable = HeapAlloc(hHeap, dwFlags, AdaptersCount * sizeof(IP_INTERFACE_NAME_INFO)); if (pTable == NULL) { Status = STATUS_NO_MEMORY; goto Error; } for (i = 0, j = 0; i < InterfacesCount; i++) { if (InterfacesList[i].tei_entity == IF_ENTITY) { BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) + RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)]; IFEntry* Entry = (IFEntry*)EntryBuffer; /* Get the entry */ Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry); if (!NT_SUCCESS(Status)) goto Error; TRACE("Got entity %*s, index %u.\n", Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index); if (Entry->if_type != IF_TYPE_SOFTWARE_LOOPBACK) { pTable[j].Index = Entry->if_index; pTable[j].MediaType = Entry->if_type; pTable[j].ConnectionType = 1; //IF_CONNECTION_DEDICATED; pTable[j].AccessType = 2; //IF_ACCESS_BROADCAST; AnsiGuidString.Length = Entry->if_descrlen; AnsiGuidString.MaximumLength = Entry->if_descrlen; AnsiGuidString.Buffer = (PCHAR)Entry->if_descr; Status = RtlAnsiStringToUnicodeString(&UnicodeGuidString, &AnsiGuidString, TRUE); if (!NT_SUCCESS(Status)) { ERR("Status %lx\n", Status); goto Error; } Status = RtlGUIDFromString(&UnicodeGuidString, &pTable[j].DeviceGuid); RtlFreeUnicodeString(&UnicodeGuidString); if (!NT_SUCCESS(Status)) { ERR("Status %lx\n", Status); goto Error; } memset(&pTable[j].InterfaceGuid, 0, sizeof(GUID)); j++; } } } /* We're done */ HeapFree(GetProcessHeap(), 0, InterfacesList); NtClose(TcpFile); *ppTable = pTable; *pdwCount = AdaptersCount; return ERROR_SUCCESS; Error: ERR("Failed! Status 0x%08x\n", Status); if (pTable) HeapFree(hHeap, 0, pTable); *ppTable = NULL; *pdwCount = 0; HeapFree(GetProcessHeap(), 0, InterfacesList); NtClose(TcpFile); return RtlNtStatusToDosError(Status); } #endif