nsiproxy: Implement IP unicast enumerate_all.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
8e13903665
commit
0978421102
|
@ -411,10 +411,82 @@ static void test_ndis_index_luid( void )
|
|||
ok( err == ERROR_FILE_NOT_FOUND, "got %d\n", err );
|
||||
}
|
||||
|
||||
static void test_ip_unicast( int family )
|
||||
{
|
||||
DWORD rw_sizes[] = { FIELD_OFFSET(struct nsi_ip_unicast_rw, unk[0]), FIELD_OFFSET(struct nsi_ip_unicast_rw, unk[1]),
|
||||
sizeof(struct nsi_ip_unicast_rw) };
|
||||
struct nsi_ipv4_unicast_key *key_tbl, *key4;
|
||||
struct nsi_ipv6_unicast_key *key6;
|
||||
struct nsi_ip_unicast_rw *rw_tbl, *rw;
|
||||
struct nsi_ip_unicast_dynamic *dyn_tbl, *dyn;
|
||||
struct nsi_ip_unicast_static *stat_tbl, *stat;
|
||||
MIB_UNICASTIPADDRESS_TABLE *table;
|
||||
const NPI_MODULEID *mod = (family == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
|
||||
DWORD err, count, i, rw_size, key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
|
||||
|
||||
winetest_push_context( family == AF_INET ? "AF_INET" : "AF_INET6" );
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rw_sizes); i++)
|
||||
{
|
||||
err = NsiAllocateAndGetTable( 1, mod, NSI_IP_UNICAST_TABLE, (void **)&key_tbl, key_size,
|
||||
(void **)&rw_tbl, rw_sizes[i], (void **)&dyn_tbl, sizeof(*dyn_tbl),
|
||||
(void **)&stat_tbl, sizeof(*stat_tbl), &count, 0 );
|
||||
if (!err) break;
|
||||
}
|
||||
ok( !err, "got %d\n", err );
|
||||
rw_size = rw_sizes[i];
|
||||
|
||||
err = GetUnicastIpAddressTable( family, &table );
|
||||
ok( !err, "got %d\n", err );
|
||||
ok( table->NumEntries == count, "table entries %d count %d\n", table->NumEntries, count );
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
MIB_UNICASTIPADDRESS_ROW *row = table->Table + i;
|
||||
rw = (struct nsi_ip_unicast_rw *)((BYTE *)rw_tbl + i * rw_size);
|
||||
dyn = dyn_tbl + i;
|
||||
stat = stat_tbl + i;
|
||||
winetest_push_context( "%d", i );
|
||||
|
||||
ok( row->Address.si_family == family, "mismatch\n" );
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
key4 = key_tbl + i;
|
||||
ok( !memcmp( &row->Address.Ipv4.sin_addr, &key4->addr, sizeof(struct in_addr) ), "mismatch\n" );
|
||||
ok( row->InterfaceLuid.Value == key4->luid.Value, "mismatch\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
key6 = (struct nsi_ipv6_unicast_key *)key_tbl + i;
|
||||
ok( !memcmp( &row->Address.Ipv6.sin6_addr, &key6->addr, sizeof(struct in6_addr) ), "mismatch\n" );
|
||||
ok( row->InterfaceLuid.Value == key6->luid.Value, "mismatch\n" );
|
||||
}
|
||||
ok( row->PrefixOrigin == rw->prefix_origin, "mismatch\n" );
|
||||
ok( row->SuffixOrigin == rw->suffix_origin, "mismatch\n" );
|
||||
ok( row->ValidLifetime == rw->valid_lifetime, "mismatch\n" );
|
||||
ok( row->PreferredLifetime == rw->preferred_lifetime, "mismatch\n" );
|
||||
ok( row->OnLinkPrefixLength == rw->on_link_prefix, "mismatch\n" );
|
||||
/* SkipAsSource */
|
||||
ok( row->DadState == dyn->dad_state, "mismatch\n" );
|
||||
ok( row->ScopeId.Value == dyn->scope_id, "mismatch\n" );
|
||||
todo_wine
|
||||
ok( row->CreationTimeStamp.QuadPart == stat->creation_time, "mismatch\n" );
|
||||
winetest_pop_context();
|
||||
}
|
||||
|
||||
FreeMibTable( table );
|
||||
NsiFreeTable( key_tbl, rw_tbl, dyn_tbl, stat_tbl );
|
||||
winetest_pop_context();
|
||||
}
|
||||
|
||||
START_TEST( nsi )
|
||||
{
|
||||
test_nsi_api();
|
||||
|
||||
test_ndis_ifinfo();
|
||||
test_ndis_index_luid();
|
||||
|
||||
test_ip_unicast( AF_INET );
|
||||
test_ip_unicast( AF_INET6 );
|
||||
}
|
||||
|
|
|
@ -4,5 +4,6 @@ EXTRADLLFLAGS = -Wl,--subsystem,native
|
|||
|
||||
C_SRCS = \
|
||||
device.c \
|
||||
ip.c \
|
||||
ndis.c \
|
||||
nsi.c
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* nsiproxy.sys ipv4 and ipv6 modules
|
||||
*
|
||||
* Copyright 2003, 2006, 2011 Juan Lang
|
||||
* Copyright 2021 Huw Davies
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "winioctl.h"
|
||||
#define USE_WS_PREFIX
|
||||
#include "winsock2.h"
|
||||
#include "ws2ipdef.h"
|
||||
#include "nldef.h"
|
||||
#include "ifdef.h"
|
||||
#include "netiodef.h"
|
||||
#include "wine/nsi.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "nsiproxy_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
|
||||
|
||||
static inline DWORD nsi_popcount( DWORD m )
|
||||
{
|
||||
#ifdef HAVE___BUILTIN_POPCOUNT
|
||||
return __builtin_popcount( m );
|
||||
#else
|
||||
m -= m >> 1 & 0x55555555;
|
||||
m = (m & 0x33333333) + (m >> 2 & 0x33333333);
|
||||
return ((m + (m >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static DWORD mask_v4_to_prefix( struct in_addr *addr )
|
||||
{
|
||||
return nsi_popcount( addr->s_addr );
|
||||
}
|
||||
|
||||
static DWORD mask_v6_to_prefix( struct in6_addr *addr )
|
||||
{
|
||||
DWORD ret;
|
||||
|
||||
ret = nsi_popcount( *(DWORD *)addr->s6_addr );
|
||||
ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 4) );
|
||||
ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 8) );
|
||||
ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 12) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ULONG64 get_boot_time( void )
|
||||
{
|
||||
SYSTEM_TIMEOFDAY_INFORMATION ti;
|
||||
|
||||
NtQuerySystemInformation( SystemTimeOfDayInformation, &ti, sizeof(ti), NULL );
|
||||
return ti.BootTime.QuadPart;
|
||||
}
|
||||
|
||||
static void unicast_fill_entry( struct ifaddrs *entry, void *key, struct nsi_ip_unicast_rw *rw,
|
||||
struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
|
||||
{
|
||||
struct nsi_ipv6_unicast_key placeholder, *key6 = key;
|
||||
struct nsi_ipv4_unicast_key *key4 = key;
|
||||
DWORD scope_id = 0;
|
||||
|
||||
if (!key)
|
||||
{
|
||||
key6 = &placeholder;
|
||||
key4 = (struct nsi_ipv4_unicast_key *)&placeholder;
|
||||
}
|
||||
|
||||
convert_unix_name_to_luid( entry->ifa_name, &key6->luid );
|
||||
|
||||
if (entry->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
memcpy( &key4->addr, &((struct sockaddr_in *)entry->ifa_addr)->sin_addr, sizeof(key4->addr) );
|
||||
key4->pad = 0;
|
||||
}
|
||||
else if (entry->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
memcpy( &key6->addr, &((struct sockaddr_in6 *)entry->ifa_addr)->sin6_addr, sizeof(key6->addr) );
|
||||
scope_id = ((struct sockaddr_in6 *)entry->ifa_addr)->sin6_scope_id;
|
||||
}
|
||||
|
||||
if (rw)
|
||||
{
|
||||
rw->preferred_lifetime = 60000;
|
||||
rw->valid_lifetime = 60000;
|
||||
|
||||
if (key6->luid.Info.IfType != IF_TYPE_SOFTWARE_LOOPBACK)
|
||||
{
|
||||
rw->prefix_origin = IpPrefixOriginDhcp;
|
||||
rw->suffix_origin = IpSuffixOriginDhcp;
|
||||
}
|
||||
else
|
||||
{
|
||||
rw->prefix_origin = IpPrefixOriginManual;
|
||||
rw->suffix_origin = IpSuffixOriginManual;
|
||||
}
|
||||
if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET)
|
||||
rw->on_link_prefix = mask_v4_to_prefix( &((struct sockaddr_in *)entry->ifa_netmask)->sin_addr );
|
||||
else if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET6)
|
||||
rw->on_link_prefix = mask_v6_to_prefix( &((struct sockaddr_in6 *)entry->ifa_netmask)->sin6_addr );
|
||||
else rw->on_link_prefix = 0;
|
||||
rw->unk[0] = 0;
|
||||
rw->unk[1] = 0;
|
||||
}
|
||||
|
||||
if (dyn)
|
||||
{
|
||||
dyn->scope_id = scope_id;
|
||||
dyn->dad_state = IpDadStatePreferred;
|
||||
}
|
||||
|
||||
if (stat) stat->creation_time = get_boot_time();
|
||||
}
|
||||
|
||||
static NTSTATUS ip_unicast_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 ifaddrs *addrs, *entry;
|
||||
int family = (key_size == sizeof(struct nsi_ipv4_unicast_key)) ? AF_INET : AF_INET6;
|
||||
|
||||
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 );
|
||||
|
||||
if (getifaddrs( &addrs )) return STATUS_NO_MORE_ENTRIES;
|
||||
|
||||
for (entry = addrs; entry; entry = entry->ifa_next)
|
||||
{
|
||||
if (!entry->ifa_addr || entry->ifa_addr->sa_family != family) continue;
|
||||
|
||||
if (num < *count)
|
||||
{
|
||||
unicast_fill_entry( entry, key_data, rw_data, dynamic_data, static_data );
|
||||
key_data = (BYTE *)key_data + key_size;
|
||||
rw_data = (BYTE *)rw_data + rw_size;
|
||||
dynamic_data = (BYTE *)dynamic_data + dynamic_size;
|
||||
static_data = (BYTE *)static_data + static_size;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
freeifaddrs( addrs );
|
||||
|
||||
if (!want_data || num <= *count) *count = num;
|
||||
else status = STATUS_MORE_ENTRIES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct module_table ipv4_tables[] =
|
||||
{
|
||||
{
|
||||
NSI_IP_UNICAST_TABLE,
|
||||
{
|
||||
sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ip_unicast_rw),
|
||||
sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
|
||||
},
|
||||
ip_unicast_enumerate_all,
|
||||
},
|
||||
{
|
||||
~0u
|
||||
}
|
||||
};
|
||||
|
||||
const struct module ipv4_module =
|
||||
{
|
||||
&NPI_MS_IPV4_MODULEID,
|
||||
ipv4_tables
|
||||
};
|
||||
|
||||
static struct module_table ipv6_tables[] =
|
||||
{
|
||||
{
|
||||
NSI_IP_UNICAST_TABLE,
|
||||
{
|
||||
sizeof(struct nsi_ipv6_unicast_key), sizeof(struct nsi_ip_unicast_rw),
|
||||
sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
|
||||
},
|
||||
ip_unicast_enumerate_all,
|
||||
},
|
||||
{
|
||||
~0u
|
||||
}
|
||||
};
|
||||
|
||||
const struct module ipv6_module =
|
||||
{
|
||||
&NPI_MS_IPV6_MODULEID,
|
||||
ipv6_tables
|
||||
};
|
|
@ -613,6 +613,27 @@ static NTSTATUS index_luid_get_parameter( const void *key, DWORD key_size, DWORD
|
|||
return status;
|
||||
}
|
||||
|
||||
BOOL convert_unix_name_to_luid( const char *unix_name, NET_LUID *luid )
|
||||
{
|
||||
struct if_entry *entry;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
EnterCriticalSection( &if_list_cs );
|
||||
|
||||
update_if_table();
|
||||
|
||||
LIST_FOR_EACH_ENTRY( entry, &if_list, struct if_entry, entry )
|
||||
if (!strcmp( entry->if_unix_name, unix_name ))
|
||||
{
|
||||
*luid = entry->if_luid;
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
LeaveCriticalSection( &if_list_cs );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct module_table tables[] =
|
||||
{
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(nsi);
|
|||
static const struct module *modules[] =
|
||||
{
|
||||
&ndis_module,
|
||||
&ipv4_module,
|
||||
&ipv6_module,
|
||||
};
|
||||
|
||||
static const struct module_table *get_module_table( const NPI_MODULEID *id, DWORD table )
|
||||
|
|
|
@ -22,6 +22,8 @@ NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params ) DECLSPEC_HI
|
|||
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;
|
||||
|
||||
BOOL convert_unix_name_to_luid( const char *unix_name, NET_LUID *luid ) DECLSPEC_HIDDEN;
|
||||
|
||||
struct module_table
|
||||
{
|
||||
DWORD table;
|
||||
|
@ -43,3 +45,5 @@ struct module
|
|||
};
|
||||
|
||||
extern const struct module ndis_module DECLSPEC_HIDDEN;
|
||||
extern const struct module ipv4_module DECLSPEC_HIDDEN;
|
||||
extern const struct module ipv6_module DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -256,6 +256,7 @@ DWORD WINAPI GetIfTable2(MIB_IF_TABLE2**);
|
|||
DWORD WINAPI GetIfTable2Ex(MIB_IF_TABLE_LEVEL,MIB_IF_TABLE2**);
|
||||
DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY,MIB_IPINTERFACE_TABLE**);
|
||||
DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW*);
|
||||
DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY,MIB_UNICASTIPADDRESS_TABLE**);
|
||||
PCHAR WINAPI if_indextoname(NET_IFINDEX,PCHAR);
|
||||
NET_IFINDEX WINAPI if_nametoindex(PCSTR);
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef __WINE_NSI_H
|
||||
#define __WINE_NSI_H
|
||||
|
||||
#include "inaddr.h"
|
||||
#include "in6addr.h"
|
||||
#include "winioctl.h"
|
||||
|
||||
/* Undocumented NSI NDIS tables */
|
||||
|
@ -94,6 +96,43 @@ struct nsi_ndis_ifinfo_static
|
|||
DWORD phys_medium_type;
|
||||
};
|
||||
|
||||
/* Undocumented NSI IP tables */
|
||||
#define NSI_IP_UNICAST_TABLE 10
|
||||
|
||||
struct nsi_ipv4_unicast_key
|
||||
{
|
||||
NET_LUID luid;
|
||||
IN_ADDR addr;
|
||||
DWORD pad;
|
||||
};
|
||||
|
||||
struct nsi_ipv6_unicast_key
|
||||
{
|
||||
NET_LUID luid;
|
||||
IN6_ADDR addr;
|
||||
};
|
||||
|
||||
struct nsi_ip_unicast_rw
|
||||
{
|
||||
DWORD preferred_lifetime;
|
||||
DWORD valid_lifetime;
|
||||
DWORD prefix_origin;
|
||||
DWORD suffix_origin;
|
||||
DWORD on_link_prefix;
|
||||
DWORD unk[2];
|
||||
};
|
||||
|
||||
struct nsi_ip_unicast_dynamic
|
||||
{
|
||||
DWORD scope_id;
|
||||
DWORD dad_state;
|
||||
};
|
||||
|
||||
struct nsi_ip_unicast_static
|
||||
{
|
||||
ULONG64 creation_time;
|
||||
};
|
||||
|
||||
/* Wine specific ioctl interface */
|
||||
|
||||
#define IOCTL_NSIPROXY_WINE_ENUMERATE_ALL CTL_CODE(FILE_DEVICE_NETWORK, 0x400, METHOD_BUFFERED, 0)
|
||||
|
|
Loading…
Reference in New Issue