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;