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