nsiproxy: Implement IPv4 neighbour enumerate_all.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
387be3d9a3
commit
c09c65f65c
|
@ -485,6 +485,82 @@ static void test_ip_unicast( int family )
|
|||
winetest_pop_context();
|
||||
}
|
||||
|
||||
static void test_ip_neighbour( int family )
|
||||
{
|
||||
const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
|
||||
DWORD err, i, count, count2, attempt;
|
||||
struct nsi_ipv4_neighbour_key *key_tbl, *key_tbl_2, *key4;
|
||||
struct nsi_ipv6_neighbour_key *key6;
|
||||
struct nsi_ip_neighbour_rw *rw_tbl, *rw;
|
||||
struct nsi_ip_neighbour_dynamic *dyn_tbl, *dyn_tbl_2, *dyn;
|
||||
MIB_IPNET_TABLE2 *table;
|
||||
DWORD key_size = (family == AF_INET) ? sizeof(struct nsi_ipv4_neighbour_key) : sizeof(struct nsi_ipv6_neighbour_key);
|
||||
|
||||
winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
|
||||
|
||||
for (attempt = 0; attempt < 5; attempt++)
|
||||
{
|
||||
err = NsiAllocateAndGetTable( 1, mod, NSI_IP_NEIGHBOUR_TABLE, (void **)&key_tbl, key_size,
|
||||
(void **)&rw_tbl, sizeof(*rw), (void **)&dyn_tbl, sizeof(*dyn),
|
||||
NULL, 0, &count, 0 );
|
||||
todo_wine_if( family == AF_INET6 )
|
||||
ok( !err, "got %x\n", err );
|
||||
if (err) goto err;
|
||||
|
||||
err = GetIpNetTable2( family, &table );
|
||||
todo_wine
|
||||
ok( !err, "got %x\n", err );
|
||||
if (err) goto err;
|
||||
|
||||
err = NsiAllocateAndGetTable( 1, mod, NSI_IP_NEIGHBOUR_TABLE, (void **)&key_tbl_2, key_size,
|
||||
NULL, 0, (void **)&dyn_tbl_2, sizeof(*dyn),
|
||||
NULL, 0, &count2, 0 );
|
||||
ok( !err, "got %x\n", err );
|
||||
if (count == count2 && !memcmp( dyn_tbl, dyn_tbl_2, count * sizeof(*dyn) )) break;
|
||||
NsiFreeTable( key_tbl_2, NULL, dyn_tbl_2, NULL );
|
||||
NsiFreeTable( key_tbl, rw_tbl, dyn_tbl, NULL );
|
||||
}
|
||||
|
||||
ok( count == table->NumEntries, "%d vs %d\n", count, table->NumEntries );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
MIB_IPNET_ROW2 *row = table->Table + i;
|
||||
rw = rw_tbl + i;
|
||||
dyn = dyn_tbl + i;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
key4 = key_tbl + i;
|
||||
ok( key4->addr.s_addr == row->Address.Ipv4.sin_addr.s_addr, "%08x vs %08x\n", key4->addr.s_addr,
|
||||
row->Address.Ipv4.sin_addr.s_addr );
|
||||
ok( key4->luid.Value == row->InterfaceLuid.Value, "%s vs %s\n", wine_dbgstr_longlong( key4->luid.Value ),
|
||||
wine_dbgstr_longlong( row->InterfaceLuid.Value ) );
|
||||
ok( key4->luid2.Value == row->InterfaceLuid.Value, "mismatch\n" );
|
||||
}
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
key6 = (struct nsi_ipv6_neighbour_key *)key_tbl + i;
|
||||
ok( !memcmp( key6->addr.s6_addr, row->Address.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ), "mismatch\n" );
|
||||
ok( key6->luid.Value == row->InterfaceLuid.Value, "mismatch\n" );
|
||||
ok( key6->luid2.Value == row->InterfaceLuid.Value, "mismatch\n" );
|
||||
}
|
||||
|
||||
ok( dyn->phys_addr_len == row->PhysicalAddressLength, "mismatch\n" );
|
||||
ok( !memcmp( rw->phys_addr, row->PhysicalAddress, dyn->phys_addr_len ), "mismatch\n" );
|
||||
ok( dyn->state == row->State, "%x vs %x\n", dyn->state, row->State );
|
||||
ok( dyn->flags.is_router == row->IsRouter, "%x vs %x\n", dyn->flags.is_router, row->IsRouter );
|
||||
ok( dyn->flags.is_unreachable == row->IsUnreachable, "%x vs %x\n", dyn->flags.is_unreachable, row->IsUnreachable );
|
||||
ok( dyn->time == row->ReachabilityTime.LastReachable, "%x vs %x\n", dyn->time, row->ReachabilityTime.LastReachable );
|
||||
}
|
||||
|
||||
NsiFreeTable( key_tbl_2, NULL, dyn_tbl_2, NULL );
|
||||
NsiFreeTable( key_tbl, rw_tbl, dyn_tbl, NULL );
|
||||
|
||||
err:
|
||||
winetest_pop_context();
|
||||
}
|
||||
|
||||
static void test_ip_forward( int family )
|
||||
{
|
||||
DWORD rw_sizes[] = { FIELD_OFFSET(struct nsi_ip_forward_rw, unk),
|
||||
|
@ -606,6 +682,8 @@ START_TEST( nsi )
|
|||
|
||||
test_ip_unicast( AF_INET );
|
||||
test_ip_unicast( AF_INET6 );
|
||||
test_ip_neighbour( AF_INET );
|
||||
test_ip_neighbour( AF_INET6 );
|
||||
test_ip_forward( AF_INET );
|
||||
test_ip_forward( AF_INET6 );
|
||||
}
|
||||
|
|
|
@ -41,10 +41,30 @@
|
|||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP_VAR_H
|
||||
#include <netinet/ip_var.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IF_ETHER_H
|
||||
#include <netinet/if_ether.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_ARP_H
|
||||
#include <net/if_arp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_DL_H
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
|
@ -234,6 +254,193 @@ static NTSTATUS ip_unicast_get_all_parameters( const void *key, DWORD key_size,
|
|||
return status;
|
||||
}
|
||||
|
||||
struct ipv4_neighbour_data
|
||||
{
|
||||
NET_LUID luid;
|
||||
DWORD if_index;
|
||||
struct in_addr addr;
|
||||
BYTE phys_addr[IF_MAX_PHYS_ADDRESS_LENGTH];
|
||||
DWORD state;
|
||||
USHORT phys_addr_len;
|
||||
BOOL is_router;
|
||||
BOOL is_unreachable;
|
||||
};
|
||||
|
||||
static void ipv4_neighbour_fill_entry( struct ipv4_neighbour_data *entry, struct nsi_ipv4_neighbour_key *key, struct nsi_ip_neighbour_rw *rw,
|
||||
struct nsi_ip_neighbour_dynamic *dyn, void *stat )
|
||||
{
|
||||
USHORT phys_addr_len = entry->phys_addr_len > sizeof(rw->phys_addr) ? 0 : entry->phys_addr_len;
|
||||
|
||||
if (key)
|
||||
{
|
||||
key->luid = entry->luid;
|
||||
key->luid2 = entry->luid;
|
||||
key->addr.WS_s_addr = entry->addr.s_addr;
|
||||
key->pad = 0;
|
||||
}
|
||||
|
||||
if (rw)
|
||||
{
|
||||
memcpy( rw->phys_addr, entry->phys_addr, phys_addr_len );
|
||||
memset( rw->phys_addr + entry->phys_addr_len, 0, sizeof(rw->phys_addr) - phys_addr_len );
|
||||
}
|
||||
|
||||
if (dyn)
|
||||
{
|
||||
memset( dyn, 0, sizeof(*dyn) );
|
||||
dyn->state = entry->state;
|
||||
dyn->flags.is_router = entry->is_router;
|
||||
dyn->flags.is_unreachable = entry->is_unreachable;
|
||||
dyn->phys_addr_len = phys_addr_len;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
|
||||
void *dynamic_data, DWORD dynamic_size,
|
||||
void *static_data, DWORD static_size, DWORD_PTR *count )
|
||||
{
|
||||
DWORD num = 0;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
BOOL want_data = key_size || rw_size || dynamic_size || static_size;
|
||||
struct ipv4_neighbour_data entry;
|
||||
|
||||
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 );
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
char buf[512], *ptr;
|
||||
DWORD atf_flags;
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen( "/proc/net/arp", "r" ))) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
/* skip header line */
|
||||
ptr = fgets( buf, sizeof(buf), fp );
|
||||
while ((ptr = fgets( buf, sizeof(buf), fp )))
|
||||
{
|
||||
entry.addr.s_addr = inet_addr( ptr );
|
||||
while (*ptr && !isspace( *ptr )) ptr++;
|
||||
strtoul( ptr + 1, &ptr, 16 ); /* hw type (skip) */
|
||||
atf_flags = strtoul( ptr + 1, &ptr, 16 );
|
||||
|
||||
if (atf_flags & ATF_PERM) entry.state = NlnsPermanent;
|
||||
else if (atf_flags & ATF_COM) entry.state = NlnsReachable;
|
||||
else entry.state = NlnsStale;
|
||||
|
||||
entry.is_router = 0;
|
||||
entry.is_unreachable = !(atf_flags & (ATF_PERM | ATF_COM));
|
||||
|
||||
while (*ptr && isspace( *ptr )) ptr++;
|
||||
entry.phys_addr_len = 0;
|
||||
while (*ptr && !isspace( *ptr ))
|
||||
{
|
||||
if (entry.phys_addr_len >= sizeof(entry.phys_addr))
|
||||
{
|
||||
entry.phys_addr_len = 0;
|
||||
while (*ptr && !isspace( *ptr )) ptr++;
|
||||
break;
|
||||
}
|
||||
entry.phys_addr[entry.phys_addr_len++] = strtoul( ptr, &ptr, 16 );
|
||||
if (*ptr) ptr++;
|
||||
}
|
||||
while (*ptr && isspace( *ptr )) ptr++;
|
||||
while (*ptr && !isspace( *ptr )) ptr++; /* mask (skip) */
|
||||
while (*ptr && isspace( *ptr )) ptr++;
|
||||
|
||||
if (!convert_unix_name_to_luid( ptr, &entry.luid )) continue;
|
||||
if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
|
||||
|
||||
if (num < *count)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
fclose( fp );
|
||||
}
|
||||
#elif defined(HAVE_SYS_SYSCTL_H)
|
||||
{
|
||||
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }, sinarp_len;
|
||||
size_t needed;
|
||||
char *buf = NULL, *lim, *next;
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_inarp *sinarp;
|
||||
struct sockaddr_dl *sdl;
|
||||
|
||||
if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
buf = heap_alloc( needed );
|
||||
if (!buf) return STATUS_NO_MEMORY;
|
||||
|
||||
if (sysctl( mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0 ) == -1)
|
||||
{
|
||||
heap_free( buf );
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
lim = buf + needed;
|
||||
next = buf;
|
||||
while (next < lim)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
sinarp = (struct sockaddr_inarp *)(rtm + 1);
|
||||
if (sinarp->sin_len) sinarp_len = (sinarp->sin_len + sizeof(int)-1) & ~(sizeof(int)-1);
|
||||
else sinarp_len = sizeof(int);
|
||||
sdl = (struct sockaddr_dl *)((char *)sinarp + sinarp_len);
|
||||
|
||||
if (sdl->sdl_alen) /* arp entry */
|
||||
{
|
||||
entry.addr = sinarp->sin_addr;
|
||||
entry.if_index = sdl->sdl_index;
|
||||
if (!convert_index_to_luid( entry.if_index, &entry.luid )) break;
|
||||
entry.phys_addr_len = min( 8, sdl->sdl_alen );
|
||||
if (entry.phys_addr_len > sizeof(entry.phys_addr)) entry.phys_addr_len = 0;
|
||||
memcpy( entry.phys_addr, &sdl->sdl_data[sdl->sdl_nlen], entry.phys_addr_len );
|
||||
if (rtm->rtm_rmx.rmx_expire == 0) entry.state = NlnsPermanent;
|
||||
else entry.state = NlnsReachable;
|
||||
entry.is_router = sinarp->sin_other & SIN_ROUTER;
|
||||
entry.is_unreachable = 0; /* FIXME */
|
||||
|
||||
if (num < *count)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
next += rtm->rtm_msglen;
|
||||
}
|
||||
heap_free( buf );
|
||||
}
|
||||
#else
|
||||
FIXME( "not implemented\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
|
||||
if (!want_data || num <= *count) *count = num;
|
||||
else status = STATUS_MORE_ENTRIES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS ipv6_neighbour_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
|
||||
void *dynamic_data, DWORD dynamic_size,
|
||||
void *static_data, DWORD static_size, DWORD_PTR *count )
|
||||
{
|
||||
FIXME( "not implemented\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
struct ipv4_route_data
|
||||
{
|
||||
NET_LUID luid;
|
||||
|
@ -489,6 +696,14 @@ static struct module_table ipv4_tables[] =
|
|||
ip_unicast_enumerate_all,
|
||||
ip_unicast_get_all_parameters,
|
||||
},
|
||||
{
|
||||
NSI_IP_NEIGHBOUR_TABLE,
|
||||
{
|
||||
sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
|
||||
sizeof(struct nsi_ip_neighbour_dynamic), 0
|
||||
},
|
||||
ipv4_neighbour_enumerate_all,
|
||||
},
|
||||
{
|
||||
NSI_IP_FORWARD_TABLE,
|
||||
{
|
||||
|
@ -519,6 +734,14 @@ static struct module_table ipv6_tables[] =
|
|||
ip_unicast_enumerate_all,
|
||||
ip_unicast_get_all_parameters,
|
||||
},
|
||||
{
|
||||
NSI_IP_NEIGHBOUR_TABLE,
|
||||
{
|
||||
sizeof(struct nsi_ipv6_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
|
||||
sizeof(struct nsi_ip_neighbour_dynamic), 0
|
||||
},
|
||||
ipv6_neighbour_enumerate_all,
|
||||
},
|
||||
{
|
||||
NSI_IP_FORWARD_TABLE,
|
||||
{
|
||||
|
|
|
@ -257,6 +257,8 @@ DWORD WINAPI GetIfTable2Ex(MIB_IF_TABLE_LEVEL,MIB_IF_TABLE2**);
|
|||
DWORD WINAPI GetIpForwardEntry2(MIB_IPFORWARD_ROW2*);
|
||||
DWORD WINAPI GetIpForwardTable2(ADDRESS_FAMILY,MIB_IPFORWARD_TABLE2**);
|
||||
DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY,MIB_IPINTERFACE_TABLE**);
|
||||
DWORD WINAPI GetIpNetEntry2(MIB_IPNET_ROW2*);
|
||||
DWORD WINAPI GetIpNetTable2(ADDRESS_FAMILY,MIB_IPNET_TABLE2**);
|
||||
DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW*);
|
||||
DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY,MIB_UNICASTIPADDRESS_TABLE**);
|
||||
PCHAR WINAPI if_indextoname(NET_IFINDEX,PCHAR);
|
||||
|
|
|
@ -98,6 +98,7 @@ struct nsi_ndis_ifinfo_static
|
|||
|
||||
/* Undocumented NSI IP tables */
|
||||
#define NSI_IP_UNICAST_TABLE 10
|
||||
#define NSI_IP_NEIGHBOUR_TABLE 11
|
||||
#define NSI_IP_FORWARD_TABLE 16
|
||||
|
||||
struct nsi_ipv4_unicast_key
|
||||
|
@ -134,6 +135,39 @@ struct nsi_ip_unicast_static
|
|||
ULONG64 creation_time;
|
||||
};
|
||||
|
||||
struct nsi_ipv4_neighbour_key
|
||||
{
|
||||
NET_LUID luid;
|
||||
NET_LUID luid2;
|
||||
IN_ADDR addr;
|
||||
DWORD pad;
|
||||
};
|
||||
|
||||
struct nsi_ipv6_neighbour_key
|
||||
{
|
||||
NET_LUID luid;
|
||||
NET_LUID luid2;
|
||||
IN6_ADDR addr;
|
||||
};
|
||||
|
||||
struct nsi_ip_neighbour_rw
|
||||
{
|
||||
BYTE phys_addr[IF_MAX_PHYS_ADDRESS_LENGTH];
|
||||
};
|
||||
|
||||
struct nsi_ip_neighbour_dynamic
|
||||
{
|
||||
DWORD state;
|
||||
DWORD time;
|
||||
struct
|
||||
{
|
||||
USHORT is_router : 1;
|
||||
USHORT is_unreachable : 1;
|
||||
} flags;
|
||||
USHORT phys_addr_len;
|
||||
DWORD unk;
|
||||
};
|
||||
|
||||
struct nsi_ipv4_forward_key
|
||||
{
|
||||
DWORD unk;
|
||||
|
|
Loading…
Reference in New Issue