[PATCH v5 1/1] nsiproxy.sys: Add static ARP entries which are always present on Windows.

Paul Gofman wine at gitlab.winehq.org
Sat Jun 25 18:44:17 CDT 2022


From: Paul Gofman <pgofman at codeweavers.com>

Some apps (Roon or SCP: Secret Laboratory are examples) depend on ARP
table always containing some entries if there is a network adapter present.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53175
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/iphlpapi/tests/iphlpapi.c   | 52 ++++++++++++++++-
 dlls/nsiproxy.sys/ip.c           | 96 +++++++++++++++++++++++++++++++-
 dlls/nsiproxy.sys/unix_private.h |  6 ++
 3 files changed, 152 insertions(+), 2 deletions(-)

diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index 84d5143ba8e..1a0cb76bcf5 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -120,6 +120,11 @@ static const char *ntoa6( IN6_ADDR *ip )
     return buffers[i];
 }
 
+static DWORD ipv4_addr( BYTE b1, BYTE b2, BYTE b3, BYTE b4 )
+{
+    return htonl( (b1 << 24) | (b2 << 16) | (b3 << 8) | b4 );
+}
+
 /*
 still-to-be-tested 98-only functions:
 GetUniDirectionalAdapterInfo
@@ -369,10 +374,16 @@ static void testGetIpForwardTable(void)
 
 static void testGetIpNetTable(void)
 {
-    DWORD apiReturn;
+    DWORD apiReturn, ret, prev_idx;
+    BOOL igmp3_found, ssdp_found;
+    DWORD igmp3_addr, ssdp_addr;
+    MIB_IPNET_TABLE2 *table2;
     ULONG dwSize = 0;
     unsigned int i;
 
+    igmp3_addr = ipv4_addr( 224, 0, 0, 22 );
+    ssdp_addr = ipv4_addr( 239, 255, 255, 250 );
+
     apiReturn = GetIpNetTable(NULL, NULL, FALSE);
     if (apiReturn == ERROR_NOT_SUPPORTED) {
         skip("GetIpNetTable is not supported\n");
@@ -406,6 +417,45 @@ static void testGetIpNetTable(void)
                     ok(ntohl(buf->table[i].dwAddr) <= ntohl(buf->table[i + 1].dwAddr),
                        "Entries are not sorted by address, i %u.\n", i );
             }
+
+            igmp3_found = ssdp_found = FALSE;
+            prev_idx = ~0ul;
+            for (i = 0; i < buf->dwNumEntries; ++i)
+            {
+                if (buf->table[i].dwIndex != prev_idx)
+                {
+                    if (prev_idx != ~0ul)
+                    {
+                        ok( igmp3_found, "%s not found, iface index %lu.\n", ntoa( igmp3_addr ), prev_idx);
+                        ok( ssdp_found || broken(!ssdp_found) /* 239.255.255.250 is always present since Win10 */,
+                            "%s not found.\n", ntoa( ssdp_addr ));
+                    }
+                    prev_idx = buf->table[i].dwIndex;
+                    igmp3_found = ssdp_found = FALSE;
+                }
+                if (buf->table[i].dwAddr == igmp3_addr)
+                    igmp3_found = TRUE;
+                else if (buf->table[i].dwAddr == ssdp_addr)
+                    ssdp_found = TRUE;
+            }
+            ok( igmp3_found, "%s not found.\n", ntoa( igmp3_addr ));
+            ok( ssdp_found || broken(!ssdp_found) /* 239.255.255.250 is always present since Win10 */,
+                "%s not found.\n", ntoa( ssdp_addr ));
+
+            ret = GetIpNetTable2( AF_INET, &table2 );
+            ok( !ret, "got ret %lu.\n", ret );
+            for (i = 0; i < table2->NumEntries; ++i)
+            {
+                MIB_IPNET_ROW2 *row = &table2->Table[i];
+                if (row->Address.Ipv4.sin_addr.s_addr == igmp3_addr
+                    || row->Address.Ipv4.sin_addr.s_addr == ssdp_addr)
+                {
+                    ok( row->State == NlnsPermanent, "got state %d.\n", row->State );
+                    ok( !row->IsRouter, "IsRouter is set.\n" );
+                    ok( !row->IsUnreachable, "IsUnreachable is set.\n" );
+                }
+            }
+            FreeMibTable( table2 );
         }
 
         if (apiReturn == NO_ERROR && winetest_debug > 1)
diff --git a/dlls/nsiproxy.sys/ip.c b/dlls/nsiproxy.sys/ip.c
index 79f3bd80bfe..dbe3a0b46b7 100644
--- a/dlls/nsiproxy.sys/ip.c
+++ b/dlls/nsiproxy.sys/ip.c
@@ -1000,18 +1000,75 @@ static void ipv4_neighbour_fill_entry( struct ipv4_neighbour_data *entry, struct
     }
 }
 
+/* ARP entries for these multicast addresses are always present on Windows for each interface. */
+static DWORD ipv4_multicast_addresses[] =
+{
+    IPV4_ADDR(224, 0, 0, 22),
+    IPV4_ADDR(239, 255, 255, 250),
+};
+
+static void update_static_address_found( DWORD address, UINT if_index, struct nsi_ndis_ifinfo_static *iface,
+                                         unsigned int iface_count )
+{
+    unsigned int i, j;
+
+    for (i = 0; i < ARRAY_SIZE(ipv4_multicast_addresses); ++i)
+        if (ipv4_multicast_addresses[i] == address) break;
+
+    if (i == ARRAY_SIZE(ipv4_multicast_addresses)) return;
+
+    for (j = 0; j < iface_count; ++j)
+    {
+        if (iface[j].if_index == if_index)
+        {
+            iface[j].unk |= 1 << i;
+            return;
+        }
+    }
+}
+
 static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
                                               void *dynamic_data, UINT dynamic_size,
                                               void *static_data, UINT static_size, UINT_PTR *count )
 {
-    UINT num = 0;
+    UINT num = 0, iface_count;
     NTSTATUS status = STATUS_SUCCESS;
     BOOL want_data = key_size || rw_size || dynamic_size || static_size;
+    struct nsi_ndis_ifinfo_static *iface_static;
     struct ipv4_neighbour_data entry;
+    NET_LUID *luid_tbl;
+    unsigned int i, j;
 
     TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
            dynamic_data, dynamic_size, static_data, static_size, count );
 
+    iface_count = 0;
+    if ((status = nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0, NULL, 0,
+                                     NULL, 0, NULL, 0, &iface_count )))
+        return status;
+
+    if (!(luid_tbl = malloc( iface_count * sizeof(*luid_tbl) )))
+        return STATUS_NO_MEMORY;
+
+    if (!(iface_static = malloc( iface_count * sizeof(*iface_static) )))
+    {
+        free( luid_tbl );
+        return STATUS_NO_MEMORY;
+    }
+
+    if ((status = nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid_tbl, sizeof(*luid_tbl),
+                                     NULL, 0, NULL, 0, iface_static, sizeof(*iface_static), &iface_count ))
+        && status != STATUS_BUFFER_OVERFLOW)
+    {
+        free( luid_tbl );
+        free( iface_static );
+        return status;
+    }
+
+    /* Use unk field to indicate whether we found mandatory multicast addresses in the host ARP table. */
+    for (i = 0; i < iface_count; ++i)
+        iface_static[i].unk = 0;
+
 #ifdef __linux__
     {
         char buf[512], *ptr, *s;
@@ -1059,6 +1116,8 @@ static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, UINT key_size, voi
             if (!convert_unix_name_to_luid( ptr, &entry.luid )) continue;
             if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
 
+            update_static_address_found( entry.addr.s_addr, entry.if_index, iface_static, iface_count );
+
             if (num < *count)
             {
                 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
@@ -1119,6 +1178,8 @@ static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, UINT key_size, voi
 #endif
                 entry.is_unreachable = 0; /* FIXME */
 
+                update_static_address_found( entry.addr.s_addr, entry.if_index, iface_static, iface_count );
+
                 if (num < *count)
                 {
                     ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
@@ -1136,9 +1197,42 @@ static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, UINT key_size, voi
     }
 #else
     FIXME( "not implemented\n" );
+    free( luid_tbl );
+    free( iface_static );
     return STATUS_NOT_IMPLEMENTED;
 #endif
 
+    if (!want_data || num <= *count)
+    {
+        /* Certain ipv4 multicast addresses are always present on Windows for each interface.
+         * Add those if they weren't added already. */
+        memset( &entry, 0, sizeof(entry) );
+        entry.state = NlnsPermanent;
+        for (i = 0; i < iface_count; ++i)
+        {
+            entry.if_index = iface_static[i].if_index;
+            entry.luid = luid_tbl[i];
+            for (j = 0; j < ARRAY_SIZE(ipv4_multicast_addresses); ++j)
+            {
+                if (iface_static[i].unk & (1 << j)) continue;
+                if (num <= *count)
+                {
+                    entry.addr.s_addr = ipv4_multicast_addresses[j];
+                    ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
+
+                    if (key_data) key_data = (BYTE *)key_data + key_size;
+                    if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
+                    if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
+                    if (static_data) static_data = (BYTE *)static_data + static_size;
+                }
+                ++num;
+            }
+        }
+    }
+
+    free( luid_tbl );
+    free( iface_static );
+
     if (!want_data || num <= *count) *count = num;
     else status = STATUS_BUFFER_OVERFLOW;
 
diff --git a/dlls/nsiproxy.sys/unix_private.h b/dlls/nsiproxy.sys/unix_private.h
index 8ab56f6d9a3..84fea0c42d2 100644
--- a/dlls/nsiproxy.sys/unix_private.h
+++ b/dlls/nsiproxy.sys/unix_private.h
@@ -18,6 +18,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#ifdef WORDS_BIGENDIAN
+#define IPV4_ADDR(b1, b2, b3, b4) (((unsigned int)b1 << 24) | (b2 << 16) | (b3 << 8) | b4)
+#else
+#define IPV4_ADDR(b1, b2, b3, b4) (((unsigned int)b4 << 24) | (b3 << 16) | (b2 << 8) | b1)
+#endif
+
 NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params ) DECLSPEC_HIDDEN;
 NTSTATUS nsi_get_all_parameters_ex( struct nsi_get_all_parameters_ex *params ) DECLSPEC_HIDDEN;
 NTSTATUS nsi_get_parameter_ex( struct nsi_get_parameter_ex *params ) DECLSPEC_HIDDEN;
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/296



More information about the wine-devel mailing list