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(&copy_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