1 /*
2  * Copyright (c) 2019-2020, Prevas A/S
3  * Copyright (c) 2022-2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @file
10  * @brief UDP transport for the mcumgr SMP protocol.
11  */
12 
13 #include <assert.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/init.h>
16 #include <zephyr/net/socket.h>
17 #include <zephyr/net/net_if.h>
18 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
19 #include <zephyr/mgmt/mcumgr/smp/smp.h>
20 #include <zephyr/mgmt/mcumgr/transport/smp.h>
21 #include <zephyr/mgmt/mcumgr/transport/smp_udp.h>
22 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
23 #include <zephyr/net/net_mgmt.h>
24 #include <zephyr/net/net_event.h>
25 #include <zephyr/net/conn_mgr_monitor.h>
26 #include <errno.h>
27 
28 #include <mgmt/mcumgr/transport/smp_internal.h>
29 
30 #define LOG_LEVEL CONFIG_MCUMGR_LOG_LEVEL
31 #include <zephyr/logging/log.h>
32 LOG_MODULE_REGISTER(smp_udp);
33 
34 BUILD_ASSERT(CONFIG_MCUMGR_TRANSPORT_UDP_MTU != 0, "CONFIG_MCUMGR_TRANSPORT_UDP_MTU must be > 0");
35 
36 #if !defined(CONFIG_MCUMGR_TRANSPORT_UDP_IPV4) && !defined(CONFIG_MCUMGR_TRANSPORT_UDP_IPV6)
37 BUILD_ASSERT(0, "Either IPv4 or IPv6 SMP must be enabled for the MCUmgr UDP SMP transport using "
38 		"CONFIG_MCUMGR_TRANSPORT_UDP_IPV4 or CONFIG_MCUMGR_TRANSPORT_UDP_IPV6");
39 #endif
40 
41 BUILD_ASSERT(sizeof(struct sockaddr) <= CONFIG_MCUMGR_TRANSPORT_NETBUF_USER_DATA_SIZE,
42 	     "CONFIG_MCUMGR_TRANSPORT_NETBUF_USER_DATA_SIZE must be >= sizeof(struct sockaddr)");
43 
44 enum proto_type {
45 	PROTOCOL_IPV4 = 0,
46 	PROTOCOL_IPV6,
47 };
48 
49 struct config {
50 	int sock;
51 	enum proto_type proto;
52 	struct k_sem network_ready_sem;
53 	struct smp_transport smp_transport;
54 	char recv_buffer[CONFIG_MCUMGR_TRANSPORT_UDP_MTU];
55 	struct k_thread thread;
56 	K_KERNEL_STACK_MEMBER(stack, CONFIG_MCUMGR_TRANSPORT_UDP_STACK_SIZE);
57 };
58 
59 struct configs {
60 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
61 	struct config ipv4;
62 #ifdef CONFIG_SMP_CLIENT
63 	struct smp_client_transport_entry ipv4_transport;
64 #endif
65 #endif
66 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
67 	struct config ipv6;
68 #ifdef CONFIG_SMP_CLIENT
69 	struct smp_client_transport_entry ipv6_transport;
70 #endif
71 #endif
72 };
73 
74 static bool threads_created;
75 
76 static struct configs smp_udp_configs;
77 
78 static struct net_mgmt_event_callback smp_udp_mgmt_cb;
79 
smp_udp_proto_to_name(enum proto_type proto)80 static const char *smp_udp_proto_to_name(enum proto_type proto)
81 {
82 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
83 	if (proto == PROTOCOL_IPV4) {
84 		return "IPv4";
85 	}
86 #endif
87 
88 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
89 	if (proto == PROTOCOL_IPV6) {
90 		return "IPv6";
91 	}
92 #endif
93 
94 	return "??";
95 }
96 
97 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
smp_udp4_tx(struct net_buf * nb)98 static int smp_udp4_tx(struct net_buf *nb)
99 {
100 	int ret;
101 	struct sockaddr *addr = net_buf_user_data(nb);
102 
103 	ret = zsock_sendto(smp_udp_configs.ipv4.sock, nb->data, nb->len, 0, addr, sizeof(*addr));
104 
105 	if (ret < 0) {
106 		if (errno == ENOMEM) {
107 			ret = MGMT_ERR_EMSGSIZE;
108 		} else {
109 			ret = MGMT_ERR_EINVAL;
110 		}
111 	} else {
112 		ret = MGMT_ERR_EOK;
113 	}
114 
115 	smp_packet_free(nb);
116 
117 	return ret;
118 }
119 #endif
120 
121 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
smp_udp6_tx(struct net_buf * nb)122 static int smp_udp6_tx(struct net_buf *nb)
123 {
124 	int ret;
125 	struct sockaddr *addr = net_buf_user_data(nb);
126 
127 	ret = zsock_sendto(smp_udp_configs.ipv6.sock, nb->data, nb->len, 0, addr, sizeof(*addr));
128 
129 	if (ret < 0) {
130 		if (errno == ENOMEM) {
131 			ret = MGMT_ERR_EMSGSIZE;
132 		} else {
133 			ret = MGMT_ERR_EINVAL;
134 		}
135 	} else {
136 		ret = MGMT_ERR_EOK;
137 	}
138 
139 	smp_packet_free(nb);
140 
141 	return ret;
142 }
143 #endif
144 
smp_udp_get_mtu(const struct net_buf * nb)145 static uint16_t smp_udp_get_mtu(const struct net_buf *nb)
146 {
147 	ARG_UNUSED(nb);
148 
149 	return CONFIG_MCUMGR_TRANSPORT_UDP_MTU;
150 }
151 
smp_udp_ud_copy(struct net_buf * dst,const struct net_buf * src)152 static int smp_udp_ud_copy(struct net_buf *dst, const struct net_buf *src)
153 {
154 	struct sockaddr *src_ud = net_buf_user_data(src);
155 	struct sockaddr *dst_ud = net_buf_user_data(dst);
156 
157 	net_ipaddr_copy(dst_ud, src_ud);
158 
159 	return MGMT_ERR_EOK;
160 }
161 
create_socket(enum proto_type proto,int * sock)162 static int create_socket(enum proto_type proto, int *sock)
163 {
164 	int tmp_sock;
165 	int err;
166 	struct sockaddr *addr;
167 	socklen_t addr_len = 0;
168 
169 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
170 	struct sockaddr_in addr4;
171 #endif
172 
173 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
174 	struct sockaddr_in6 addr6;
175 #endif
176 
177 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
178 	if (proto == PROTOCOL_IPV4) {
179 		addr_len = sizeof(struct sockaddr_in);
180 		memset(&addr4, 0, sizeof(addr4));
181 		addr4.sin_family = AF_INET;
182 		addr4.sin_port = htons(CONFIG_MCUMGR_TRANSPORT_UDP_PORT);
183 		addr4.sin_addr.s_addr = htonl(INADDR_ANY);
184 		addr = (struct sockaddr *)&addr4;
185 	}
186 #endif
187 
188 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
189 	if (proto == PROTOCOL_IPV6) {
190 		addr_len = sizeof(struct sockaddr_in6);
191 		memset(&addr6, 0, sizeof(addr6));
192 		addr6.sin6_family = AF_INET6;
193 		addr6.sin6_port = htons(CONFIG_MCUMGR_TRANSPORT_UDP_PORT);
194 		addr6.sin6_addr = in6addr_any;
195 		addr = (struct sockaddr *)&addr6;
196 	}
197 #endif
198 
199 	tmp_sock = zsock_socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
200 	err = errno;
201 
202 	if (tmp_sock < 0) {
203 		LOG_ERR("Could not open receive socket (%s), err: %i",
204 			smp_udp_proto_to_name(proto), err);
205 
206 		return -err;
207 	}
208 
209 	if (zsock_bind(tmp_sock, addr, addr_len) < 0) {
210 		err = errno;
211 		LOG_ERR("Could not bind to receive socket (%s), err: %i",
212 			smp_udp_proto_to_name(proto), err);
213 
214 		zsock_close(tmp_sock);
215 
216 		return -err;
217 	}
218 
219 	*sock = tmp_sock;
220 	return 0;
221 }
222 
smp_udp_receive_thread(void * p1,void * p2,void * p3)223 static void smp_udp_receive_thread(void *p1, void *p2, void *p3)
224 {
225 	struct config *conf = (struct config *)p1;
226 	int rc;
227 
228 	ARG_UNUSED(p2);
229 	ARG_UNUSED(p3);
230 
231 	(void)k_sem_take(&conf->network_ready_sem, K_FOREVER);
232 	rc = create_socket(conf->proto, &conf->sock);
233 
234 	if (rc < 0) {
235 		return;
236 	}
237 
238 	__ASSERT(rc >= 0, "Socket is invalid");
239 	LOG_INF("Started (%s)", smp_udp_proto_to_name(conf->proto));
240 
241 	while (1) {
242 		struct sockaddr addr;
243 		socklen_t addr_len = sizeof(addr);
244 
245 		int len = zsock_recvfrom(conf->sock, conf->recv_buffer,
246 					 CONFIG_MCUMGR_TRANSPORT_UDP_MTU, 0, &addr, &addr_len);
247 
248 		if (len > 0) {
249 			struct sockaddr *ud;
250 			struct net_buf *nb;
251 
252 			/* Store sender address in user data for reply */
253 			nb = smp_packet_alloc();
254 			if (!nb) {
255 				LOG_ERR("Failed to allocate mcumgr buffer");
256 				/* No free space, drop SMP frame */
257 				continue;
258 			}
259 			net_buf_add_mem(nb, conf->recv_buffer, len);
260 			ud = net_buf_user_data(nb);
261 			net_ipaddr_copy(ud, &addr);
262 
263 			smp_rx_req(&conf->smp_transport, nb);
264 		} else if (len < 0) {
265 			LOG_ERR("recvfrom error (%s): %i, %d", smp_udp_proto_to_name(conf->proto),
266 				errno, len);
267 		}
268 	}
269 }
270 
smp_udp_open_iface(struct net_if * iface,void * user_data)271 static void smp_udp_open_iface(struct net_if *iface, void *user_data)
272 {
273 	ARG_UNUSED(user_data);
274 
275 	if (net_if_is_up(iface)) {
276 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
277 		if (net_if_flag_is_set(iface, NET_IF_IPV4) &&
278 		    k_thread_join(&smp_udp_configs.ipv4.thread, K_NO_WAIT) == -EBUSY) {
279 			k_sem_give(&smp_udp_configs.ipv4.network_ready_sem);
280 		}
281 #endif
282 
283 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
284 		if (net_if_flag_is_set(iface, NET_IF_IPV6) &&
285 		    k_thread_join(&smp_udp_configs.ipv6.thread, K_NO_WAIT) == -EBUSY) {
286 			k_sem_give(&smp_udp_configs.ipv6.network_ready_sem);
287 		}
288 #endif
289 	}
290 }
291 
smp_udp_net_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)292 static void smp_udp_net_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
293 				      struct net_if *iface)
294 {
295 	ARG_UNUSED(cb);
296 
297 	if (mgmt_event == NET_EVENT_IF_UP) {
298 		smp_udp_open_iface(iface, NULL);
299 	}
300 }
301 
create_thread(struct config * conf,const char * name)302 static void create_thread(struct config *conf, const char *name)
303 {
304 	k_thread_create(&(conf->thread), conf->stack,
305 			K_KERNEL_STACK_SIZEOF(conf->stack),
306 			smp_udp_receive_thread, conf, NULL, NULL,
307 			CONFIG_MCUMGR_TRANSPORT_UDP_THREAD_PRIO, 0, K_FOREVER);
308 
309 	k_thread_name_set(&(conf->thread), name);
310 	k_thread_start(&(conf->thread));
311 }
312 
smp_udp_open(void)313 int smp_udp_open(void)
314 {
315 	bool started = false;
316 
317 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
318 	if (k_thread_join(&smp_udp_configs.ipv4.thread, K_NO_WAIT) == 0 ||
319 	    threads_created == false) {
320 		(void)k_sem_reset(&smp_udp_configs.ipv4.network_ready_sem);
321 		create_thread(&smp_udp_configs.ipv4, "smp_udp4");
322 		started = true;
323 	} else {
324 		LOG_ERR("IPv4 UDP MCUmgr thread is already running");
325 	}
326 #endif
327 
328 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
329 	if (k_thread_join(&smp_udp_configs.ipv6.thread, K_NO_WAIT) == 0 ||
330 	    threads_created == false) {
331 		(void)k_sem_reset(&smp_udp_configs.ipv6.network_ready_sem);
332 		create_thread(&smp_udp_configs.ipv6, "smp_udp6");
333 		started = true;
334 	} else {
335 		LOG_ERR("IPv6 UDP MCUmgr thread is already running");
336 	}
337 #endif
338 
339 	if (started) {
340 		/* One or more threads were started, check existing interfaces */
341 		threads_created = true;
342 		net_if_foreach(smp_udp_open_iface, NULL);
343 	}
344 
345 	return 0;
346 }
347 
smp_udp_close(void)348 int smp_udp_close(void)
349 {
350 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
351 	if (k_thread_join(&smp_udp_configs.ipv4.thread, K_NO_WAIT) == -EBUSY) {
352 		k_thread_abort(&(smp_udp_configs.ipv4.thread));
353 
354 		if (smp_udp_configs.ipv4.sock >= 0) {
355 			zsock_close(smp_udp_configs.ipv4.sock);
356 			smp_udp_configs.ipv4.sock = -1;
357 		}
358 	} else {
359 		LOG_ERR("IPv4 UDP MCUmgr thread is not running");
360 	}
361 #endif
362 
363 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
364 	if (k_thread_join(&smp_udp_configs.ipv6.thread, K_NO_WAIT) == -EBUSY) {
365 		k_thread_abort(&(smp_udp_configs.ipv6.thread));
366 
367 		if (smp_udp_configs.ipv6.sock >= 0) {
368 			zsock_close(smp_udp_configs.ipv6.sock);
369 			smp_udp_configs.ipv6.sock = -1;
370 		}
371 	} else {
372 		LOG_ERR("IPv6 UDP MCUmgr thread is not running");
373 	}
374 #endif
375 
376 	return 0;
377 }
378 
smp_udp_start(void)379 static void smp_udp_start(void)
380 {
381 	int rc;
382 
383 	threads_created = false;
384 
385 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4
386 	smp_udp_configs.ipv4.proto = PROTOCOL_IPV4;
387 	smp_udp_configs.ipv4.sock = -1;
388 
389 	k_sem_init(&smp_udp_configs.ipv4.network_ready_sem, 0, 1);
390 	smp_udp_configs.ipv4.smp_transport.functions.output = smp_udp4_tx;
391 	smp_udp_configs.ipv4.smp_transport.functions.get_mtu = smp_udp_get_mtu;
392 	smp_udp_configs.ipv4.smp_transport.functions.ud_copy = smp_udp_ud_copy;
393 
394 	rc = smp_transport_init(&smp_udp_configs.ipv4.smp_transport);
395 #ifdef CONFIG_SMP_CLIENT
396 	if (rc == 0) {
397 		smp_udp_configs.ipv4_transport.smpt = &smp_udp_configs.ipv4.smp_transport;
398 		smp_udp_configs.ipv4_transport.smpt_type = SMP_UDP_IPV4_TRANSPORT;
399 		smp_client_transport_register(&smp_udp_configs.ipv4_transport);
400 	}
401 #endif
402 	if (rc) {
403 		LOG_ERR("Failed to register IPv4 UDP MCUmgr SMP transport: %d", rc);
404 	}
405 #endif
406 
407 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6
408 	smp_udp_configs.ipv6.proto = PROTOCOL_IPV6;
409 	smp_udp_configs.ipv6.sock = -1;
410 
411 	k_sem_init(&smp_udp_configs.ipv6.network_ready_sem, 0, 1);
412 	smp_udp_configs.ipv6.smp_transport.functions.output = smp_udp6_tx;
413 	smp_udp_configs.ipv6.smp_transport.functions.get_mtu = smp_udp_get_mtu;
414 	smp_udp_configs.ipv6.smp_transport.functions.ud_copy = smp_udp_ud_copy;
415 
416 	rc = smp_transport_init(&smp_udp_configs.ipv6.smp_transport);
417 #ifdef CONFIG_SMP_CLIENT
418 	if (rc == 0) {
419 		smp_udp_configs.ipv6_transport.smpt = &smp_udp_configs.ipv6.smp_transport;
420 		smp_udp_configs.ipv6_transport.smpt_type = SMP_UDP_IPV6_TRANSPORT;
421 		smp_client_transport_register(&smp_udp_configs.ipv6_transport);
422 	}
423 #endif
424 
425 	if (rc) {
426 		LOG_ERR("Failed to register IPv6 UDP MCUmgr SMP transport: %d", rc);
427 	}
428 #endif
429 
430 	net_mgmt_init_event_callback(&smp_udp_mgmt_cb, smp_udp_net_event_handler, NET_EVENT_IF_UP);
431 	net_mgmt_add_event_callback(&smp_udp_mgmt_cb);
432 
433 #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_AUTOMATIC_INIT
434 	smp_udp_open();
435 #endif
436 }
437 
438 MCUMGR_HANDLER_DEFINE(smp_udp, smp_udp_start);
439