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
29 #include <sys/socket.h>
31 #ifdef HAVE_LINUX_RTNETLINK_H
32 #include <linux/rtnetlink.h>
36 #define WIN32_NO_STATUS
43 #define __WINE_INIT_NPI_MODULEID
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
[] =
63 static const struct module_table
*get_module_table( const NPI_MODULEID
*id
, UINT table
)
65 const struct module_table
*entry
;
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
;
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
};
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], ¶ms
->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
162 const NPI_MODULEID
*module
;
165 queued_notifications
[256];
166 static unsigned int queued_notification_count
;
168 static NTSTATUS
add_notification( const NPI_MODULEID
*module
, UINT32 table
)
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
;
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)
210 ERR( "bind failed, errno %d.\n", errno
);
211 return STATUS_NOT_IMPLEMENTED
;
217 len
= recv( netlink_fd
, buffer
, sizeof(buffer
), 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
;
236 WARN( "Unknown addrmsg->ifa_family %d.\n", addrmsg
->ifa_family
);
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
;
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
;
261 static NTSTATUS
unix_nsi_get_notification( void *args
)
263 return STATUS_NOT_IMPLEMENTED
;
267 const unixlib_entry_t __wine_unix_call_funcs
[] =
273 unix_nsi_enumerate_all_ex
,
274 unix_nsi_get_all_parameters_ex
,
275 unix_nsi_get_parameter_ex
,
276 unix_nsi_get_notification
,