[SHELL32_APITEST] Follow-up to #6796 (25e2f5f)
[reactos.git] / dll / win32 / iphlpapi / address.c
index 2571536..e3ac925 100644 (file)
@@ -9,7 +9,7 @@
 #include "iphlpapi_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
-
+#ifdef GetAdaptersAddressesV2
 /* Helper for GetAdaptersAddresses:
  * Retrieves the list of network adapters from tcpip.sys */
 static
@@ -265,6 +265,51 @@ EnumerateServerName(
     *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
+}
+
 DWORD
 WINAPI
 DECLSPEC_HOTPATCH
@@ -283,22 +328,41 @@ GetAdaptersAddresses(
     ULONG i;
     ULONG TotalSize = 0, RemainingSize;
     BYTE* Ptr = (BYTE*)pAdapterAddresses;
+    DWORD MIN_SIZE = 15 * 1024;
+    PIP_ADAPTER_ADDRESSES PreviousAA = NULL;
 
-    FIXME("GetAdaptersAddresses - Semi Stub: Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p.\n",
-        Family, Flags, Reserved, pAdapterAddresses, pOutBufLen);
+    TRACE("Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p\n",
+          Family, Flags, Reserved, pAdapterAddresses, pOutBufLen);
 
     if (!pOutBufLen)
         return ERROR_INVALID_PARAMETER;
 
-    if ((Family == AF_INET6) || (Family == AF_UNSPEC))
+    // 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)
     {
-        /* One day maybe... */
-        FIXME("IPv6 is not supported in ReactOS!\n");
-        if (Family == AF_INET6)
-        {
+        *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;
@@ -306,7 +370,7 @@ GetAdaptersAddresses(
         ZeroMemory(Ptr, RemainingSize);
 
     /* open the tcpip driver */
-    Status = openTcpFile(&TcpFile);
+    Status = openTcpFile(&TcpFile, FILE_READ_DATA);
     if (!NT_SUCCESS(Status))
     {
         ERR("Could not open handle to tcpip.sys. Status %08x\n", Status);
@@ -325,8 +389,9 @@ GetAdaptersAddresses(
     /* Let's see if we got any adapter. */
     for (i = 0; i < InterfacesCount; i++)
     {
-        PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr, PreviousAA = NULL;
+        PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr;
         ULONG CurrentAASize = 0;
+        ULONG FriendlySize = 0;
 
         if (InterfacesList[i].tei_entity == IF_ENTITY)
         {
@@ -337,6 +402,10 @@ GetAdaptersAddresses(
             /* 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);
 
@@ -359,8 +428,31 @@ GetAdaptersAddresses(
 
             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
             {
-                /* Just an empty string for now. */
-                FIXME("Should get adapter friendly name.\n");
+                /* 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);
             }
 
@@ -374,12 +466,7 @@ GetAdaptersAddresses(
                     "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)
-                {
-                    ERR("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
-                    Flags |= GAA_FLAG_SKIP_DNS_SERVER;
-                }
-                else
+                if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) == ERROR_SUCCESS)
                 {
                     EnumNameServers(InterfaceKey, NULL, &CurrentAASize, EnumerateServerNameSize);
                     RegCloseKey(InterfaceKey);
@@ -396,11 +483,14 @@ GetAdaptersAddresses(
                 CurrentAA->IfIndex = Entry->if_index;
                 CopyMemory(CurrentAA->PhysicalAddress, Entry->if_physaddr, Entry->if_physaddrlen);
                 CurrentAA->PhysicalAddressLength = Entry->if_physaddrlen;
-                CurrentAA->Flags = 0; // FIXME!
+                QueryFlags(&Entry->if_descr[0], Entry->if_descrlen, &CurrentAA->Flags);
                 CurrentAA->Mtu = Entry->if_mtu;
                 CurrentAA->IfType = Entry->if_type;
-                CurrentAA->OperStatus = Entry->if_operstatus;
-                CurrentAA->Next = PreviousAA;
+                if(Entry->if_operstatus >= IF_OPER_STATUS_CONNECTING)
+                    CurrentAA->OperStatus = IfOperStatusUp;
+                else
+                    CurrentAA->OperStatus = IfOperStatusDown;
+
                 /* Next items */
                 Ptr = (BYTE*)(CurrentAA + 1);
 
@@ -427,9 +517,51 @@ GetAdaptersAddresses(
                 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
                 {
                     CurrentAA->FriendlyName = (PWCHAR)Ptr;
-                    CurrentAA->FriendlyName[0] = L'\0';
-                    /* Next items */
-                    Ptr = (BYTE*)(CurrentAA->FriendlyName + 1);
+
+                    if (FriendlySize != 0)
+                    {
+                        /* 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 = 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 */
@@ -445,7 +577,7 @@ GetAdaptersAddresses(
 
                     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS)
                     {
-                        ERR("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
+                        TRACE("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
                     }
                     else
                     {
@@ -529,6 +661,8 @@ GetAdaptersAddresses(
                     {
                         if (CurrentAA->IfIndex == AddrEntries[j].iae_index)
                             break;
+
+                        CurrentAA = CurrentAA->Next;
                     }
 
                     if (!CurrentAA)
@@ -539,7 +673,7 @@ GetAdaptersAddresses(
                     }
                 }
 
-                ERR("address is 0x%08x, mask is 0x%08x\n", AddrEntries[j].iae_addr, AddrEntries[j].iae_mask);
+                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))
@@ -565,9 +699,10 @@ GetAdaptersAddresses(
                         /* Set the address */
                         //FIXME: ipv4 only (again...)
                         UnicastAddress->Address.lpSockaddr = (LPSOCKADDR)(UnicastAddress + 1);
-                        UnicastAddress->Address.iSockaddrLength = sizeof(AddrEntries[j].iae_addr);
+                        UnicastAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
                         UnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
-                        memcpy(UnicastAddress->Address.lpSockaddr->sa_data, &AddrEntries[j].iae_addr, sizeof(AddrEntries[j].iae_addr));
+                        ((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_port = 0;
+                        memcpy(&((LPSOCKADDR_IN)UnicastAddress->Address.lpSockaddr)->sin_addr, &AddrEntries[j].iae_addr, sizeof(AddrEntries[j].iae_addr));
 
                         CurrentAA->FirstUnicastAddress = UnicastAddress;
                         Ptr += Size;
@@ -617,6 +752,7 @@ Success:
     HeapFree(GetProcessHeap(), 0, InterfacesList);
     NtClose(TcpFile);
     *pOutBufLen = TotalSize;
+    TRACE("TotalSize: %x\n", *pOutBufLen);
     return ERROR_SUCCESS;
 
 Error:
@@ -626,3 +762,4 @@ Error:
     NtClose(TcpFile);
     return RtlNtStatusToDosError(Status);
 }
+#endif