nsiproxy.sys: Implement change notifications for NSI_IP_UNICAST_TABLE.
[wine.git] / dlls / nsiproxy.sys / nsi.c
blob2f6d2d59573475fc9db203037cf8c0d1ba04e8be
1 /*
2 * nsiproxy.sys
4 * Copyright 2021 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #if 0
21 #pragma makedep unix
22 #endif
24 #include "config.h"
25 #include <stdarg.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <sys/socket.h>
30 #include <limits.h>
31 #ifdef HAVE_LINUX_RTNETLINK_H
32 #include <linux/rtnetlink.h>
33 #endif
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winternl.h"
40 #include "winioctl.h"
41 #include "ddk/wdm.h"
42 #include "ifdef.h"
43 #define __WINE_INIT_NPI_MODULEID
44 #define USE_WS_PREFIX
45 #include "netiodef.h"
46 #include "wine/nsi.h"
47 #include "wine/debug.h"
48 #include "wine/unixlib.h"
49 #include "unix_private.h"
50 #include "nsiproxy_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(nsi);
54 static const struct module *modules[] =
56 &ndis_module,
57 &ipv4_module,
58 &ipv6_module,
59 &tcp_module,
60 &udp_module,
63 static const struct module_table *get_module_table( const NPI_MODULEID *id, UINT table )
65 const struct module_table *entry;
66 int i;
68 for (i = 0; i < ARRAY_SIZE(modules); i++)
69 if (NmrIsEqualNpiModuleId( modules[i]->module, id ))
70 for (entry = modules[i]->tables; entry->table != ~0u; entry++)
71 if (entry->table == table) return entry;
73 return NULL;
76 NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params )
78 const struct module_table *entry = get_module_table( params->module, params->table );
79 UINT sizes[4] = { params->key_size, params->rw_size, params->dynamic_size, params->static_size };
80 void *data[4] = { params->key_data, params->rw_data, params->dynamic_data, params->static_data };
81 int i;
83 if (!entry || !entry->enumerate_all)
85 WARN( "table not found\n" );
86 return STATUS_INVALID_PARAMETER;
89 for (i = 0; i < ARRAY_SIZE(sizes); i++)
91 if (!sizes[i]) data[i] = NULL;
92 else if (sizes[i] != entry->sizes[i]) return STATUS_INVALID_PARAMETER;
95 return entry->enumerate_all( data[0], sizes[0], data[1], sizes[1], data[2], sizes[2], data[3], sizes[3], &params->count );
98 NTSTATUS nsi_get_all_parameters_ex( struct nsi_get_all_parameters_ex *params )
100 const struct module_table *entry = get_module_table( params->module, params->table );
101 void *rw = params->rw_data;
102 void *dyn = params->dynamic_data;
103 void *stat = params->static_data;
105 if (!entry || !entry->get_all_parameters)
107 WARN( "table not found\n" );
108 return STATUS_INVALID_PARAMETER;
111 if (params->key_size != entry->sizes[0]) return STATUS_INVALID_PARAMETER;
112 if (!params->rw_size) rw = NULL;
113 else if (params->rw_size != entry->sizes[1]) return STATUS_INVALID_PARAMETER;
114 if (!params->dynamic_size) dyn = NULL;
115 else if (params->dynamic_size != entry->sizes[2]) return STATUS_INVALID_PARAMETER;
116 if (!params->static_size) stat = NULL;
117 else if (params->static_size != entry->sizes[3]) return STATUS_INVALID_PARAMETER;
119 return entry->get_all_parameters( params->key, params->key_size, rw, params->rw_size,
120 dyn, params->dynamic_size, stat, params->static_size );
123 NTSTATUS nsi_get_parameter_ex( struct nsi_get_parameter_ex *params )
125 const struct module_table *entry = get_module_table( params->module, params->table );
127 if (!entry || !entry->get_parameter)
129 WARN( "table not found\n" );
130 return STATUS_INVALID_PARAMETER;
133 if (params->param_type > 2) return STATUS_INVALID_PARAMETER;
134 if (params->key_size != entry->sizes[0]) return STATUS_INVALID_PARAMETER;
135 if (params->data_offset + params->data_size > entry->sizes[params->param_type + 1])
136 return STATUS_INVALID_PARAMETER;
137 return entry->get_parameter( params->key, params->key_size, params->param_type,
138 params->data, params->data_size, params->data_offset );
141 static NTSTATUS unix_nsi_enumerate_all_ex( void *args )
143 struct nsi_enumerate_all_ex *params = (struct nsi_enumerate_all_ex *)args;
144 return nsi_enumerate_all_ex( params );
147 static NTSTATUS unix_nsi_get_all_parameters_ex( void *args )
149 struct nsi_get_all_parameters_ex *params = (struct nsi_get_all_parameters_ex *)args;
150 return nsi_get_all_parameters_ex( params );
153 static NTSTATUS unix_nsi_get_parameter_ex( void *args )
155 struct nsi_get_parameter_ex *params = (struct nsi_get_parameter_ex *)args;
156 return nsi_get_parameter_ex( params );
159 #ifdef HAVE_LINUX_RTNETLINK_H
160 static struct
162 const NPI_MODULEID *module;
163 UINT32 table;
165 queued_notifications[256];
166 static unsigned int queued_notification_count;
168 static NTSTATUS add_notification( const NPI_MODULEID *module, UINT32 table )
170 unsigned int i;
172 for (i = 0; i < queued_notification_count; ++i)
173 if (queued_notifications[i].module == module && queued_notifications[i].table == table) return STATUS_SUCCESS;
174 if (queued_notification_count == ARRAY_SIZE(queued_notifications))
176 ERR( "Notification queue full.\n" );
177 return STATUS_NO_MEMORY;
179 queued_notifications[i].module = module;
180 queued_notifications[i].table = table;
181 ++queued_notification_count;
182 return STATUS_SUCCESS;
185 static NTSTATUS poll_netlink(void)
187 static int netlink_fd = -1;
188 char buffer[PIPE_BUF];
189 struct nlmsghdr *nlh;
190 NTSTATUS status;
191 int len;
193 if (netlink_fd == -1)
195 struct sockaddr_nl addr;
197 if ((netlink_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE )) == -1)
199 ERR( "netlink socket creation failed, errno %d.\n", errno );
200 return STATUS_NOT_IMPLEMENTED;
203 memset( &addr, 0, sizeof(addr) );
204 addr.nl_family = AF_NETLINK;
205 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
206 if (bind( netlink_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1)
208 close( netlink_fd );
209 netlink_fd = -1;
210 ERR( "bind failed, errno %d.\n", errno );
211 return STATUS_NOT_IMPLEMENTED;
215 while (1)
217 len = recv( netlink_fd, buffer, sizeof(buffer), 0 );
218 if (len <= 0)
220 if (errno == EINTR) continue;
221 ERR( "error receivng, len %d, errno %d.\n", len, errno );
222 return STATUS_UNSUCCESSFUL;
224 for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len))
226 if (nlh->nlmsg_type == NLMSG_DONE) break;
227 if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR)
229 struct ifaddrmsg *addrmsg = (struct ifaddrmsg *)(nlh + 1);
230 const NPI_MODULEID *module;
232 if (addrmsg->ifa_family == AF_INET) module = &NPI_MS_IPV4_MODULEID;
233 else if (addrmsg->ifa_family == AF_INET6) module = &NPI_MS_IPV6_MODULEID;
234 else
236 WARN( "Unknown addrmsg->ifa_family %d.\n", addrmsg->ifa_family );
237 continue;
239 if ((status = add_notification( module, NSI_IP_UNICAST_TABLE))) return status;
242 if (queued_notification_count) break;
244 return STATUS_SUCCESS;
247 static NTSTATUS unix_nsi_get_notification( void *args )
249 struct nsi_get_notification_params *params = (struct nsi_get_notification_params *)args;
250 NTSTATUS status;
252 if (!queued_notification_count && (status = poll_netlink())) return status;
253 assert( queued_notification_count );
254 params->module = *queued_notifications[0].module;
255 params->table = queued_notifications[0].table;
256 --queued_notification_count;
257 memmove( queued_notifications, queued_notifications + 1, sizeof(*queued_notifications) * queued_notification_count );
258 return STATUS_SUCCESS;
260 #else
261 static NTSTATUS unix_nsi_get_notification( void *args )
263 return STATUS_NOT_IMPLEMENTED;
265 #endif
267 const unixlib_entry_t __wine_unix_call_funcs[] =
269 icmp_cancel_listen,
270 icmp_close,
271 icmp_listen,
272 icmp_send_echo,
273 unix_nsi_enumerate_all_ex,
274 unix_nsi_get_all_parameters_ex,
275 unix_nsi_get_parameter_ex,
276 unix_nsi_get_notification,