Commit 9a11957b authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

nsiproxy.sys: Add static ARP entries which are always present on Windows.

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=53175Signed-off-by: 's avatarPaul Gofman <pgofman@codeweavers.com>
parent 88b77020
......@@ -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)
......
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment