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