1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdbool.h>
8 #ifdef CONFIG_ARCH_POSIX
9 #include <fcntl.h>
10 #else
11 #include <zephyr/posix/fcntl.h>
12 #endif
13
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(net_sock_mgmt, CONFIG_NET_SOCKETS_LOG_LEVEL);
16
17 #include <zephyr/kernel.h>
18 #include <zephyr/sys/util.h>
19 #include <zephyr/net/socket.h>
20 #include <zephyr/syscall_handler.h>
21 #include <zephyr/sys/fdtable.h>
22 #include <zephyr/net/socket_net_mgmt.h>
23 #include <zephyr/net/ethernet_mgmt.h>
24
25 #include "sockets_internal.h"
26 #include "net_private.h"
27
28 #define MSG_ALLOC_TIMEOUT K_MSEC(100)
29
30 __net_socket struct net_mgmt_socket {
31 /* Network interface related to this socket */
32 struct net_if *iface;
33
34 /* A way to separate different sockets that listen same events */
35 uintptr_t pid;
36
37 /* net_mgmt mask */
38 uint32_t mask;
39
40 /* Message allocation timeout */
41 k_timeout_t alloc_timeout;
42
43 /* net_mgmt event timeout */
44 k_timeout_t wait_timeout;
45
46 /* Socket protocol */
47 int proto;
48
49 /* Is this entry in use (true) or not (false) */
50 uint8_t is_in_use : 1;
51 };
52
53 static struct net_mgmt_socket
54 mgmt_sockets[CONFIG_NET_SOCKETS_NET_MGMT_MAX_LISTENERS];
55
56 static const struct socket_op_vtable net_mgmt_sock_fd_op_vtable;
57
znet_mgmt_socket(int family,int type,int proto)58 int znet_mgmt_socket(int family, int type, int proto)
59 {
60 struct net_mgmt_socket *mgmt = NULL;
61 int fd, i;
62
63 for (i = 0; i < ARRAY_SIZE(mgmt_sockets); i++) {
64 if (mgmt_sockets[i].is_in_use) {
65 continue;
66 }
67
68 mgmt = &mgmt_sockets[i];
69 }
70
71 if (mgmt == NULL) {
72 errno = ENOENT;
73 return -1;
74 }
75
76 fd = z_reserve_fd();
77 if (fd < 0) {
78 errno = ENOSPC;
79 return -1;
80 }
81
82 mgmt->is_in_use = true;
83 mgmt->proto = proto;
84 mgmt->alloc_timeout = MSG_ALLOC_TIMEOUT;
85 mgmt->wait_timeout = K_FOREVER;
86
87 z_finalize_fd(fd, mgmt,
88 (const struct fd_op_vtable *)&net_mgmt_sock_fd_op_vtable);
89
90 return fd;
91 }
92
znet_mgmt_bind(struct net_mgmt_socket * mgmt,const struct sockaddr * addr,socklen_t addrlen)93 static int znet_mgmt_bind(struct net_mgmt_socket *mgmt,
94 const struct sockaddr *addr,
95 socklen_t addrlen)
96 {
97 struct sockaddr_nm *nm_addr = (struct sockaddr_nm *)addr;
98
99 if (addrlen != sizeof(struct sockaddr_nm)) {
100 return -EINVAL;
101 }
102
103 if (nm_addr->nm_ifindex) {
104 mgmt->iface = net_if_get_by_index(nm_addr->nm_ifindex);
105 if (!mgmt->iface) {
106 errno = ENOENT;
107 return -1;
108 }
109 } else {
110 mgmt->iface = NULL;
111 }
112
113 mgmt->pid = nm_addr->nm_pid;
114
115 if (mgmt->proto == NET_MGMT_EVENT_PROTO) {
116 mgmt->mask = nm_addr->nm_mask;
117
118 if (mgmt->iface) {
119 mgmt->mask |= NET_MGMT_IFACE_BIT;
120 }
121 }
122
123 return 0;
124 }
125
znet_mgmt_sendto(struct net_mgmt_socket * mgmt,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)126 ssize_t znet_mgmt_sendto(struct net_mgmt_socket *mgmt,
127 const void *buf, size_t len,
128 int flags, const struct sockaddr *dest_addr,
129 socklen_t addrlen)
130 {
131 if (mgmt->proto == NET_MGMT_EVENT_PROTO) {
132 /* For net_mgmt events, we only listen and never send */
133 errno = ENOTSUP;
134 return -1;
135 }
136
137 /* Add handling of other network management operations here when
138 * needed.
139 */
140
141 errno = EINVAL;
142 return -1;
143 }
144
znet_mgmt_recvfrom(struct net_mgmt_socket * mgmt,void * buf,size_t max_len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)145 static ssize_t znet_mgmt_recvfrom(struct net_mgmt_socket *mgmt, void *buf,
146 size_t max_len, int flags,
147 struct sockaddr *src_addr,
148 socklen_t *addrlen)
149 {
150 struct sockaddr_nm *nm_addr = (struct sockaddr_nm *)src_addr;
151 k_timeout_t timeout = mgmt->wait_timeout;
152 uint32_t raised_event = 0;
153 uint8_t *copy_to = buf;
154 struct net_mgmt_msghdr hdr;
155 struct net_if *iface;
156 const uint8_t *info;
157 size_t info_len;
158 int ret;
159
160 if (flags & ZSOCK_MSG_DONTWAIT) {
161 timeout = K_NO_WAIT;
162 }
163
164 again:
165 if (mgmt->iface == NULL) {
166 ret = net_mgmt_event_wait(mgmt->mask, &raised_event,
167 &iface, (const void **)&info,
168 &info_len, timeout);
169 } else {
170 ret = net_mgmt_event_wait_on_iface(mgmt->iface,
171 mgmt->mask,
172 &raised_event,
173 (const void **)&info,
174 &info_len,
175 timeout);
176 iface = mgmt->iface;
177 }
178
179 if (ret == -ETIMEDOUT) {
180 errno = EAGAIN;
181 return -1;
182 }
183
184 if (ret < 0) {
185 errno = -ret;
186 return -1;
187 }
188
189 if ((mgmt->mask & raised_event) != raised_event) {
190 if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
191 goto again;
192 }
193
194 errno = EAGAIN;
195 return -1;
196 }
197
198 if (nm_addr) {
199 if (iface) {
200 nm_addr->nm_ifindex = net_if_get_by_iface(iface);
201 } else {
202 nm_addr->nm_ifindex = 0;
203 }
204
205 nm_addr->nm_pid = mgmt->pid;
206 nm_addr->nm_family = AF_NET_MGMT;
207 nm_addr->nm_mask = raised_event;
208 }
209
210 if (info) {
211 ret = info_len + sizeof(hdr);
212 if (ret > max_len) {
213 errno = EMSGSIZE;
214 return -1;
215 }
216
217 memcpy(©_to[sizeof(hdr)], info, info_len);
218 } else {
219 ret = 0;
220 }
221
222 hdr.nm_msg_version = NET_MGMT_SOCKET_VERSION_1;
223 hdr.nm_msg_len = ret;
224
225 memcpy(copy_to, &hdr, sizeof(hdr));
226
227 return ret;
228 }
229
znet_mgmt_getsockopt(struct net_mgmt_socket * mgmt,int level,int optname,void * optval,socklen_t * optlen)230 static int znet_mgmt_getsockopt(struct net_mgmt_socket *mgmt, int level,
231 int optname, void *optval, socklen_t *optlen)
232 {
233 if (level != SOL_NET_MGMT_RAW || !optval || !optlen) {
234 errno = EINVAL;
235 return -1;
236 }
237
238 if (mgmt->iface == NULL) {
239 errno = ENOENT;
240 return -1;
241 }
242
243 if (IS_ENABLED(CONFIG_NET_L2_ETHERNET_MGMT)) {
244 if (optname == NET_REQUEST_ETHERNET_GET_QAV_PARAM) {
245 int ret;
246
247 ret = net_mgmt(NET_REQUEST_ETHERNET_GET_QAV_PARAM,
248 mgmt->iface, (void *)optval, *optlen);
249 if (ret < 0) {
250 errno = -ret;
251 return -1;
252 }
253
254 return 0;
255
256 } else {
257 errno = EINVAL;
258 return -1;
259 }
260 }
261
262 errno = ENOTSUP;
263 return -1;
264 }
265
znet_mgmt_setsockopt(struct net_mgmt_socket * mgmt,int level,int optname,const void * optval,socklen_t optlen)266 static int znet_mgmt_setsockopt(struct net_mgmt_socket *mgmt, int level,
267 int optname, const void *optval,
268 socklen_t optlen)
269 {
270 if (level != SOL_NET_MGMT_RAW || !optval || !optlen) {
271 errno = EINVAL;
272 return -1;
273 }
274
275 if (mgmt->iface == NULL) {
276 errno = ENOENT;
277 return -1;
278 }
279
280 if (IS_ENABLED(CONFIG_NET_L2_ETHERNET_MGMT)) {
281 if (optname == NET_REQUEST_ETHERNET_SET_QAV_PARAM) {
282 int ret;
283
284 ret = net_mgmt(NET_REQUEST_ETHERNET_SET_QAV_PARAM,
285 mgmt->iface, (void *)optval, optlen);
286 if (ret < 0) {
287 errno = -ret;
288 return -1;
289 }
290
291 return 0;
292 } else {
293 errno = EINVAL;
294 return -1;
295 }
296 }
297
298 errno = ENOTSUP;
299 return -1;
300 }
301
net_mgmt_sock_read(void * obj,void * buffer,size_t count)302 static ssize_t net_mgmt_sock_read(void *obj, void *buffer, size_t count)
303 {
304 return znet_mgmt_recvfrom(obj, buffer, count, 0, NULL, 0);
305 }
306
net_mgmt_sock_write(void * obj,const void * buffer,size_t count)307 static ssize_t net_mgmt_sock_write(void *obj, const void *buffer,
308 size_t count)
309 {
310 return znet_mgmt_sendto(obj, buffer, count, 0, NULL, 0);
311 }
312
net_mgmt_sock_ioctl(void * obj,unsigned int request,va_list args)313 static int net_mgmt_sock_ioctl(void *obj, unsigned int request,
314 va_list args)
315 {
316 return 0;
317 }
318
net_mgmt_sock_bind(void * obj,const struct sockaddr * addr,socklen_t addrlen)319 static int net_mgmt_sock_bind(void *obj, const struct sockaddr *addr,
320 socklen_t addrlen)
321 {
322 return znet_mgmt_bind(obj, addr, addrlen);
323 }
324
325 /* The connect() function is not needed */
net_mgmt_sock_connect(void * obj,const struct sockaddr * addr,socklen_t addrlen)326 static int net_mgmt_sock_connect(void *obj, const struct sockaddr *addr,
327 socklen_t addrlen)
328 {
329 return 0;
330 }
331
332 /*
333 * The listen() and accept() functions are without any functionality.
334 */
net_mgmt_sock_listen(void * obj,int backlog)335 static int net_mgmt_sock_listen(void *obj, int backlog)
336 {
337 return 0;
338 }
339
net_mgmt_sock_accept(void * obj,struct sockaddr * addr,socklen_t * addrlen)340 static int net_mgmt_sock_accept(void *obj, struct sockaddr *addr,
341 socklen_t *addrlen)
342 {
343 return 0;
344 }
345
net_mgmt_sock_sendto(void * obj,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)346 static ssize_t net_mgmt_sock_sendto(void *obj, const void *buf,
347 size_t len, int flags,
348 const struct sockaddr *dest_addr,
349 socklen_t addrlen)
350 {
351 return znet_mgmt_sendto(obj, buf, len, flags, dest_addr, addrlen);
352 }
353
net_mgmt_sock_recvfrom(void * obj,void * buf,size_t max_len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)354 static ssize_t net_mgmt_sock_recvfrom(void *obj, void *buf,
355 size_t max_len, int flags,
356 struct sockaddr *src_addr,
357 socklen_t *addrlen)
358 {
359 return znet_mgmt_recvfrom(obj, buf, max_len, flags,
360 src_addr, addrlen);
361 }
362
net_mgmt_sock_getsockopt(void * obj,int level,int optname,void * optval,socklen_t * optlen)363 static int net_mgmt_sock_getsockopt(void *obj, int level, int optname,
364 void *optval, socklen_t *optlen)
365 {
366 return znet_mgmt_getsockopt(obj, level, optname, optval, optlen);
367 }
368
net_mgmt_sock_setsockopt(void * obj,int level,int optname,const void * optval,socklen_t optlen)369 static int net_mgmt_sock_setsockopt(void *obj, int level, int optname,
370 const void *optval, socklen_t optlen)
371 {
372 return znet_mgmt_setsockopt(obj, level, optname, optval, optlen);
373 }
374
375 static const struct socket_op_vtable net_mgmt_sock_fd_op_vtable = {
376 .fd_vtable = {
377 .read = net_mgmt_sock_read,
378 .write = net_mgmt_sock_write,
379 .ioctl = net_mgmt_sock_ioctl,
380 },
381 .bind = net_mgmt_sock_bind,
382 .connect = net_mgmt_sock_connect,
383 .listen = net_mgmt_sock_listen,
384 .accept = net_mgmt_sock_accept,
385 .sendto = net_mgmt_sock_sendto,
386 .recvfrom = net_mgmt_sock_recvfrom,
387 .getsockopt = net_mgmt_sock_getsockopt,
388 .setsockopt = net_mgmt_sock_setsockopt,
389 };
390
net_mgmt_is_supported(int family,int type,int proto)391 static bool net_mgmt_is_supported(int family, int type, int proto)
392 {
393 if ((type != SOCK_RAW && type != SOCK_DGRAM) ||
394 (proto != NET_MGMT_EVENT_PROTO)) {
395 return false;
396 }
397
398 return true;
399 }
400
401 NET_SOCKET_REGISTER(af_net_mgmt, NET_SOCKET_DEFAULT_PRIO, AF_NET_MGMT,
402 net_mgmt_is_supported, znet_mgmt_socket);
403