Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
c09c65f6
Commit
c09c65f6
authored
Aug 10, 2021
by
Huw Davies
Committed by
Alexandre Julliard
Aug 10, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nsiproxy: Implement IPv4 neighbour enumerate_all.
Signed-off-by:
Huw Davies
<
huw@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
387be3d9
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
337 additions
and
0 deletions
+337
-0
nsi.c
dlls/nsi/tests/nsi.c
+78
-0
ip.c
dlls/nsiproxy.sys/ip.c
+223
-0
netioapi.h
include/netioapi.h
+2
-0
nsi.h
include/wine/nsi.h
+34
-0
No files found.
dlls/nsi/tests/nsi.c
View file @
c09c65f6
...
...
@@ -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
);
}
dlls/nsiproxy.sys/ip.c
View file @
c09c65f6
...
...
@@ -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
;
...
...
@@ -490,6 +697,14 @@ static struct module_table ipv4_tables[] =
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
,
{
sizeof
(
struct
nsi_ipv4_forward_key
),
sizeof
(
struct
nsi_ip_forward_rw
),
...
...
@@ -520,6 +735,14 @@ static struct module_table ipv6_tables[] =
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
,
{
sizeof
(
struct
nsi_ipv6_forward_key
),
sizeof
(
struct
nsi_ip_forward_rw
),
...
...
include/netioapi.h
View file @
c09c65f6
...
...
@@ -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
);
...
...
include/wine/nsi.h
View file @
c09c65f6
...
...
@@ -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
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment