Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
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-winehq
Commits
a58f3e04
Commit
a58f3e04
authored
Jul 26, 2023
by
Paul Gofman
Committed by
Alexandre Julliard
Aug 01, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nsiproxy.sys: Implement change notifications for NSI_IP_UNICAST_TABLE.
parent
79165b16
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
183 additions
and
2 deletions
+183
-2
device.c
dlls/nsiproxy.sys/device.c
+55
-1
nsi.c
dlls/nsiproxy.sys/nsi.c
+121
-1
nsiproxy_private.h
dlls/nsiproxy.sys/nsiproxy_private.h
+7
-0
No files found.
dlls/nsiproxy.sys/device.c
View file @
a58f3e04
...
...
@@ -51,6 +51,12 @@ DECLARE_CRITICAL_SECTION( nsiproxy_cs );
static
LIST_ENTRY
request_queue
=
LIST_ENTRY_INIT
(
request_queue
);
static
LIST_ENTRY
notification_queue
=
LIST_ENTRY_INIT
(
notification_queue
);
struct
notification_data
{
NPI_MODULEID
module
;
UINT
table
;
};
static
NTSTATUS
nsiproxy_call
(
unsigned
int
code
,
void
*
args
)
{
return
WINE_UNIX_CALL
(
code
,
args
);
...
...
@@ -65,6 +71,7 @@ enum unix_calls
nsi_enumerate_all_ex
,
nsi_get_all_parameters_ex
,
nsi_get_parameter_ex
,
nsi_get_notification
,
};
static
NTSTATUS
nsiproxy_enumerate_all
(
IRP
*
irp
)
...
...
@@ -270,6 +277,7 @@ static void WINAPI change_notification_cancel( DEVICE_OBJECT *device, IRP *irp )
EnterCriticalSection
(
&
nsiproxy_cs
);
RemoveEntryList
(
&
irp
->
Tail
.
Overlay
.
ListEntry
);
free
(
irp
->
Tail
.
Overlay
.
DriverContext
[
0
]
);
LeaveCriticalSection
(
&
nsiproxy_cs
);
irp
->
IoStatus
.
Status
=
STATUS_CANCELLED
;
...
...
@@ -281,10 +289,12 @@ static NTSTATUS nsiproxy_change_notification( IRP *irp )
IO_STACK_LOCATION
*
irpsp
=
IoGetCurrentIrpStackLocation
(
irp
);
struct
nsiproxy_request_notification
*
in
=
(
struct
nsiproxy_request_notification
*
)
irp
->
AssociatedIrp
.
SystemBuffer
;
DWORD
in_len
=
irpsp
->
Parameters
.
DeviceIoControl
.
InputBufferLength
;
struct
notification_data
*
data
;
FIXME
(
"
\n
"
);
TRACE
(
"irp %p.
\n
"
,
irp
);
if
(
in_len
<
sizeof
(
*
in
))
return
STATUS_INVALID_PARAMETER
;
if
(
!
(
data
=
calloc
(
1
,
sizeof
(
*
data
)
)))
return
STATUS_NO_MEMORY
;
/* FIXME: validate module and table. */
EnterCriticalSection
(
&
nsiproxy_cs
);
...
...
@@ -294,10 +304,14 @@ static NTSTATUS nsiproxy_change_notification( IRP *irp )
/* IRP was canceled before we set cancel routine */
InitializeListHead
(
&
irp
->
Tail
.
Overlay
.
ListEntry
);
LeaveCriticalSection
(
&
nsiproxy_cs
);
free
(
data
);
return
STATUS_CANCELLED
;
}
InsertTailList
(
&
notification_queue
,
&
irp
->
Tail
.
Overlay
.
ListEntry
);
IoMarkIrpPending
(
irp
);
data
->
module
=
in
->
module
;
data
->
table
=
in
->
table
;
irp
->
Tail
.
Overlay
.
DriverContext
[
0
]
=
data
;
LeaveCriticalSection
(
&
nsiproxy_cs
);
return
STATUS_PENDING
;
...
...
@@ -466,6 +480,44 @@ static DWORD WINAPI request_thread_proc( void *arg )
return
0
;
}
static
DWORD
WINAPI
notification_thread_proc
(
void
*
arg
)
{
struct
nsi_get_notification_params
params
;
LIST_ENTRY
*
entry
,
*
next
;
NTSTATUS
status
;
while
(
!
(
status
=
nsiproxy_call
(
nsi_get_notification
,
&
params
)))
{
EnterCriticalSection
(
&
nsiproxy_cs
);
for
(
entry
=
notification_queue
.
Flink
;
entry
!=
&
notification_queue
;
entry
=
next
)
{
IRP
*
irp
=
CONTAINING_RECORD
(
entry
,
IRP
,
Tail
.
Overlay
.
ListEntry
);
struct
notification_data
*
data
=
irp
->
Tail
.
Overlay
.
DriverContext
[
0
];
next
=
entry
->
Flink
;
if
(
irp
->
Cancel
)
{
/* Cancel routine should care of freeing data and completing IRP. */
TRACE
(
"irp %p canceled.
\n
"
,
irp
);
continue
;
}
if
(
!
NmrIsEqualNpiModuleId
(
&
data
->
module
,
&
params
.
module
)
||
data
->
table
!=
params
.
table
)
continue
;
irp
->
IoStatus
.
Status
=
0
;
RemoveEntryList
(
entry
);
irp
->
Tail
.
Overlay
.
DriverContext
[
0
]
=
NULL
;
free
(
data
);
TRACE
(
"completing irp %p.
\n
"
,
irp
);
IoCompleteRequest
(
irp
,
IO_NO_INCREMENT
);
}
LeaveCriticalSection
(
&
nsiproxy_cs
);
}
WARN
(
"nsi_get_notification failed, status %#lx.
\n
"
,
status
);
return
0
;
}
NTSTATUS
WINAPI
DriverEntry
(
DRIVER_OBJECT
*
driver
,
UNICODE_STRING
*
path
)
{
NTSTATUS
status
;
...
...
@@ -483,6 +535,8 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
request_event
=
CreateEventW
(
NULL
,
FALSE
,
FALSE
,
NULL
);
thread
=
CreateThread
(
NULL
,
0
,
request_thread_proc
,
NULL
,
0
,
NULL
);
CloseHandle
(
thread
);
thread
=
CreateThread
(
NULL
,
0
,
notification_thread_proc
,
NULL
,
0
,
NULL
);
CloseHandle
(
thread
);
return
STATUS_SUCCESS
;
}
dlls/nsiproxy.sys/nsi.c
View file @
a58f3e04
...
...
@@ -21,7 +21,16 @@
#pragma makedep unix
#endif
#include "config.h"
#include <stdarg.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <limits.h>
#ifdef HAVE_LINUX_RTNETLINK_H
#include <linux/rtnetlink.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
...
...
@@ -32,11 +41,13 @@
#include "ddk/wdm.h"
#include "ifdef.h"
#define __WINE_INIT_NPI_MODULEID
#define USE_WS_PREFIX
#include "netiodef.h"
#include "wine/nsi.h"
#include "wine/debug.h"
#include "wine/unixlib.h"
#include "unix_private.h"
#include "nsiproxy_private.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
nsi
);
...
...
@@ -145,6 +156,114 @@ static NTSTATUS unix_nsi_get_parameter_ex( void *args )
return
nsi_get_parameter_ex
(
params
);
}
#ifdef HAVE_LINUX_RTNETLINK_H
static
struct
{
const
NPI_MODULEID
*
module
;
UINT32
table
;
}
queued_notifications
[
256
];
static
unsigned
int
queued_notification_count
;
static
NTSTATUS
add_notification
(
const
NPI_MODULEID
*
module
,
UINT32
table
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
queued_notification_count
;
++
i
)
if
(
queued_notifications
[
i
].
module
==
module
&&
queued_notifications
[
i
].
table
==
table
)
return
STATUS_SUCCESS
;
if
(
queued_notification_count
==
ARRAY_SIZE
(
queued_notifications
))
{
ERR
(
"Notification queue full.
\n
"
);
return
STATUS_NO_MEMORY
;
}
queued_notifications
[
i
].
module
=
module
;
queued_notifications
[
i
].
table
=
table
;
++
queued_notification_count
;
return
STATUS_SUCCESS
;
}
static
NTSTATUS
poll_netlink
(
void
)
{
static
int
netlink_fd
=
-
1
;
char
buffer
[
PIPE_BUF
];
struct
nlmsghdr
*
nlh
;
NTSTATUS
status
;
int
len
;
if
(
netlink_fd
==
-
1
)
{
struct
sockaddr_nl
addr
;
if
((
netlink_fd
=
socket
(
PF_NETLINK
,
SOCK_RAW
,
NETLINK_ROUTE
))
==
-
1
)
{
ERR
(
"netlink socket creation failed, errno %d.
\n
"
,
errno
);
return
STATUS_NOT_IMPLEMENTED
;
}
memset
(
&
addr
,
0
,
sizeof
(
addr
)
);
addr
.
nl_family
=
AF_NETLINK
;
addr
.
nl_groups
=
RTMGRP_IPV4_IFADDR
|
RTMGRP_IPV6_IFADDR
;
if
(
bind
(
netlink_fd
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
)
)
==
-
1
)
{
close
(
netlink_fd
);
netlink_fd
=
-
1
;
ERR
(
"bind failed, errno %d.
\n
"
,
errno
);
return
STATUS_NOT_IMPLEMENTED
;
}
}
while
(
1
)
{
len
=
recv
(
netlink_fd
,
buffer
,
sizeof
(
buffer
),
0
);
if
(
len
<=
0
)
{
if
(
errno
==
EINTR
)
continue
;
ERR
(
"error receivng, len %d, errno %d.
\n
"
,
len
,
errno
);
return
STATUS_UNSUCCESSFUL
;
}
for
(
nlh
=
(
struct
nlmsghdr
*
)
buffer
;
NLMSG_OK
(
nlh
,
len
);
nlh
=
NLMSG_NEXT
(
nlh
,
len
))
{
if
(
nlh
->
nlmsg_type
==
NLMSG_DONE
)
break
;
if
(
nlh
->
nlmsg_type
==
RTM_NEWADDR
||
nlh
->
nlmsg_type
==
RTM_DELADDR
)
{
struct
ifaddrmsg
*
addrmsg
=
(
struct
ifaddrmsg
*
)(
nlh
+
1
);
const
NPI_MODULEID
*
module
;
if
(
addrmsg
->
ifa_family
==
AF_INET
)
module
=
&
NPI_MS_IPV4_MODULEID
;
else
if
(
addrmsg
->
ifa_family
==
AF_INET6
)
module
=
&
NPI_MS_IPV6_MODULEID
;
else
{
WARN
(
"Unknown addrmsg->ifa_family %d.
\n
"
,
addrmsg
->
ifa_family
);
continue
;
}
if
((
status
=
add_notification
(
module
,
NSI_IP_UNICAST_TABLE
)))
return
status
;
}
}
if
(
queued_notification_count
)
break
;
}
return
STATUS_SUCCESS
;
}
static
NTSTATUS
unix_nsi_get_notification
(
void
*
args
)
{
struct
nsi_get_notification_params
*
params
=
(
struct
nsi_get_notification_params
*
)
args
;
NTSTATUS
status
;
if
(
!
queued_notification_count
&&
(
status
=
poll_netlink
()))
return
status
;
assert
(
queued_notification_count
);
params
->
module
=
*
queued_notifications
[
0
].
module
;
params
->
table
=
queued_notifications
[
0
].
table
;
--
queued_notification_count
;
memmove
(
queued_notifications
,
queued_notifications
+
1
,
sizeof
(
*
queued_notifications
)
*
queued_notification_count
);
return
STATUS_SUCCESS
;
}
#else
static
NTSTATUS
unix_nsi_get_notification
(
void
*
args
)
{
return
STATUS_NOT_IMPLEMENTED
;
}
#endif
const
unixlib_entry_t
__wine_unix_call_funcs
[]
=
{
icmp_cancel_listen
,
...
...
@@ -153,5 +272,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
icmp_send_echo
,
unix_nsi_enumerate_all_ex
,
unix_nsi_get_all_parameters_ex
,
unix_nsi_get_parameter_ex
unix_nsi_get_parameter_ex
,
unix_nsi_get_notification
,
};
dlls/nsiproxy.sys/nsiproxy_private.h
View file @
a58f3e04
...
...
@@ -84,3 +84,10 @@ struct icmp_echo_reply_64
ULONGLONG
options_ptr
;
}
opts
;
};
struct
nsi_get_notification_params
{
/* output parameters */
NPI_MODULEID
module
;
UINT32
table
;
};
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