1 /*
2  * Copyright (c) 2016 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/shell/shell_uart.h>
13 #include <zephyr/net/net_mgmt.h>
14 #include <zephyr/net/net_event.h>
15 #include <zephyr/net/coap_mgmt.h>
16 
17 #include "net_shell_private.h"
18 
19 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
20 #define THREAD_PRIORITY K_PRIO_COOP(2)
21 #define MAX_EVENT_INFO_SIZE NET_EVENT_INFO_MAX_SIZE
22 #define MONITOR_L2_MASK (_NET_EVENT_IF_BASE)
23 #define MONITOR_L3_IPV4_MASK (_NET_EVENT_IPV4_BASE | NET_MGMT_COMMAND_MASK)
24 #define MONITOR_L3_IPV6_MASK (_NET_EVENT_IPV6_BASE | NET_MGMT_COMMAND_MASK)
25 #define MONITOR_L4_MASK (_NET_EVENT_L4_BASE | NET_MGMT_COMMAND_MASK)
26 
27 static bool net_event_monitoring;
28 static bool net_event_shutting_down;
29 static struct net_mgmt_event_callback l2_cb;
30 static struct net_mgmt_event_callback l3_ipv4_cb;
31 static struct net_mgmt_event_callback l3_ipv6_cb;
32 static struct net_mgmt_event_callback l4_cb;
33 static struct k_thread event_mon;
34 static K_THREAD_STACK_DEFINE(event_mon_stack, CONFIG_NET_MGMT_EVENT_MONITOR_STACK_SIZE);
35 
36 struct event_msg {
37 	struct net_if *iface;
38 	size_t len;
39 	uint32_t event;
40 	uint8_t data[MAX_EVENT_INFO_SIZE];
41 };
42 
43 K_MSGQ_DEFINE(event_mon_msgq, sizeof(struct event_msg),
44 	      CONFIG_NET_MGMT_EVENT_QUEUE_SIZE, sizeof(intptr_t));
45 
event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)46 static void event_handler(struct net_mgmt_event_callback *cb,
47 			  uint32_t mgmt_event, struct net_if *iface)
48 {
49 	struct event_msg msg;
50 	int ret;
51 
52 	memset(&msg, 0, sizeof(msg));
53 
54 	msg.len = MIN(sizeof(msg.data), cb->info_length);
55 	msg.event = mgmt_event;
56 	msg.iface = iface;
57 
58 	if (cb->info_length > 0) {
59 		memcpy(msg.data, cb->info, msg.len);
60 	}
61 
62 	ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(10));
63 	if (ret < 0) {
64 		NET_ERR("Cannot write to msgq (%d)\n", ret);
65 	}
66 }
67 
get_l2_desc(uint32_t event)68 static const char *get_l2_desc(uint32_t event)
69 {
70 	static const char *desc = "<unknown event>";
71 
72 	switch (event) {
73 	case NET_EVENT_IF_DOWN:
74 		desc = "down";
75 		break;
76 	case NET_EVENT_IF_UP:
77 		desc = "up";
78 		break;
79 	}
80 
81 	return desc;
82 }
83 
get_l3_desc(struct event_msg * msg,const char ** desc,const char ** desc2,char * extra_info,size_t extra_info_len)84 static char *get_l3_desc(struct event_msg *msg,
85 			 const char **desc, const char **desc2,
86 			 char *extra_info, size_t extra_info_len)
87 {
88 	static const char *desc_unknown = "<unknown event>";
89 	char *info = NULL;
90 
91 #if defined(CONFIG_NET_PMTU)
92 #define MAX_PMTU_INFO_STR_LEN sizeof("changed MTU xxxxx for")
93 	static char pmtu_buf[MAX_PMTU_INFO_STR_LEN + 1];
94 #endif
95 
96 	*desc = desc_unknown;
97 
98 	switch (msg->event) {
99 	case NET_EVENT_IPV6_ADDR_ADD:
100 		*desc = "IPv6 address";
101 		*desc2 = "add";
102 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
103 				     extra_info_len);
104 		break;
105 	case NET_EVENT_IPV6_ADDR_DEPRECATED:
106 		*desc = "IPv6 address";
107 		*desc2 = "deprecated";
108 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
109 				     extra_info_len);
110 		break;
111 	case NET_EVENT_IPV6_ADDR_DEL:
112 		*desc = "IPv6 address";
113 		*desc2 = "del";
114 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
115 				     extra_info_len);
116 		break;
117 	case NET_EVENT_IPV6_MADDR_ADD:
118 		*desc = "IPv6 mcast address";
119 		*desc2 = "add";
120 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
121 				     extra_info_len);
122 		break;
123 	case NET_EVENT_IPV6_MADDR_DEL:
124 		*desc = "IPv6 mcast address";
125 		*desc2 = "del";
126 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
127 				     extra_info_len);
128 		break;
129 	case NET_EVENT_IPV6_PREFIX_ADD:
130 		*desc = "IPv6 prefix";
131 		*desc2 = "add";
132 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
133 				     extra_info_len);
134 		break;
135 	case NET_EVENT_IPV6_PREFIX_DEL:
136 		*desc = "IPv6 prefix";
137 		*desc2 = "del";
138 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
139 				     extra_info_len);
140 		break;
141 	case NET_EVENT_IPV6_MCAST_JOIN:
142 		*desc = "IPv6 mcast";
143 		*desc2 = "join";
144 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
145 				     extra_info_len);
146 		break;
147 	case NET_EVENT_IPV6_MCAST_LEAVE:
148 		*desc = "IPv6 mcast";
149 		*desc2 = "leave";
150 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
151 				     extra_info_len);
152 		break;
153 	case NET_EVENT_IPV6_ROUTER_ADD:
154 		*desc = "IPv6 router";
155 		*desc2 = "add";
156 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
157 				     extra_info_len);
158 		break;
159 	case NET_EVENT_IPV6_ROUTER_DEL:
160 		*desc = "IPv6 router";
161 		*desc2 = "del";
162 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
163 				     extra_info_len);
164 		break;
165 	case NET_EVENT_IPV6_ROUTE_ADD:
166 		*desc = "IPv6 route";
167 		*desc2 = "add";
168 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
169 				     extra_info_len);
170 		break;
171 	case NET_EVENT_IPV6_ROUTE_DEL:
172 		*desc = "IPv6 route";
173 		*desc2 = "del";
174 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
175 				     extra_info_len);
176 		break;
177 	case NET_EVENT_IPV6_DAD_SUCCEED:
178 		*desc = "IPv6 DAD";
179 		*desc2 = "ok";
180 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
181 				     extra_info_len);
182 		break;
183 	case NET_EVENT_IPV6_DAD_FAILED:
184 		*desc = "IPv6 DAD";
185 		*desc2 = "fail";
186 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
187 				     extra_info_len);
188 		break;
189 	case NET_EVENT_IPV6_NBR_ADD:
190 		*desc = "IPv6 neighbor";
191 		*desc2 = "add";
192 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
193 				     extra_info_len);
194 		break;
195 	case NET_EVENT_IPV6_NBR_DEL:
196 		*desc = "IPv6 neighbor";
197 		*desc2 = "del";
198 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
199 				     extra_info_len);
200 		break;
201 	case NET_EVENT_IPV6_PE_ENABLED:
202 		*desc = "IPv6 PE";
203 		*desc2 = "enabled";
204 		break;
205 	case NET_EVENT_IPV6_PE_DISABLED:
206 		*desc = "IPv6 PE";
207 		*desc2 = "disabled";
208 		break;
209 	case NET_EVENT_IPV6_PE_FILTER_ADD:
210 		*desc = "IPv6 PE filter";
211 		*desc2 = "add";
212 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
213 				     extra_info_len);
214 		break;
215 	case NET_EVENT_IPV6_PE_FILTER_DEL:
216 		*desc = "IPv6 PE filter";
217 		*desc2 = "del";
218 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
219 				     extra_info_len);
220 		break;
221 	case NET_EVENT_IPV4_ADDR_ADD:
222 		*desc = "IPv4 address";
223 		*desc2 = "add";
224 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
225 				     extra_info_len);
226 		break;
227 	case NET_EVENT_IPV4_ADDR_DEL:
228 		*desc = "IPv4 address";
229 		*desc2 = "del";
230 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
231 				     extra_info_len);
232 		break;
233 	case NET_EVENT_IPV4_ROUTER_ADD:
234 		*desc = "IPv4 router";
235 		*desc2 = "add";
236 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
237 				     extra_info_len);
238 		break;
239 	case NET_EVENT_IPV4_ROUTER_DEL:
240 		*desc = "IPv4 router";
241 		*desc2 = "del";
242 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
243 				     extra_info_len);
244 		break;
245 	case NET_EVENT_IPV4_DHCP_START:
246 		*desc = "DHCPv4";
247 		*desc2 = "start";
248 		break;
249 	case NET_EVENT_IPV4_DHCP_BOUND:
250 		*desc = "DHCPv4";
251 		*desc2 = "bound";
252 #if defined(CONFIG_NET_DHCPV4)
253 		struct net_if_dhcpv4 *data = (struct net_if_dhcpv4 *)msg->data;
254 
255 		info = net_addr_ntop(AF_INET, &data->requested_ip, extra_info,
256 				     extra_info_len);
257 #endif
258 		break;
259 	case NET_EVENT_IPV4_DHCP_STOP:
260 		*desc = "DHCPv4";
261 		*desc2 = "stop";
262 		break;
263 	case NET_EVENT_IPV4_ACD_SUCCEED:
264 		*desc = "IPv4 ACD";
265 		*desc2 = "ok";
266 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
267 				     extra_info_len);
268 		break;
269 	case NET_EVENT_IPV4_ACD_FAILED:
270 		*desc = "IPv4 ACD";
271 		*desc2 = "fail";
272 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
273 				     extra_info_len);
274 		break;
275 	case NET_EVENT_IPV4_PMTU_CHANGED: {
276 #if defined(CONFIG_NET_IPV4_PMTU)
277 		struct net_event_ipv4_pmtu_info *pmtu_info =
278 			(struct net_event_ipv4_pmtu_info *)msg->data;
279 
280 		*desc = "IPV4 PMTU";
281 		*desc2 = pmtu_buf;
282 		snprintk(pmtu_buf, MAX_PMTU_INFO_STR_LEN,
283 			 "changed MTU %u for", (uint16_t)pmtu_info->mtu);
284 		info = net_addr_ntop(AF_INET, &pmtu_info->dst, extra_info,
285 				     extra_info_len);
286 #endif
287 		break;
288 	}
289 	case NET_EVENT_IPV6_PMTU_CHANGED: {
290 #if defined(CONFIG_NET_IPV6_PMTU)
291 		struct net_event_ipv6_pmtu_info *pmtu_info =
292 			(struct net_event_ipv6_pmtu_info *)msg->data;
293 
294 		*desc = "IPV6 PMTU";
295 		*desc2 = pmtu_buf;
296 		snprintk(pmtu_buf, MAX_PMTU_INFO_STR_LEN,
297 			 "changed MTU %u for", (uint16_t)pmtu_info->mtu);
298 		info = net_addr_ntop(AF_INET6, &pmtu_info->dst, extra_info,
299 				     extra_info_len);
300 #endif
301 		break;
302 	}
303 	}
304 
305 	return info;
306 }
307 
get_l4_desc(uint32_t event)308 static const char *get_l4_desc(uint32_t event)
309 {
310 	static const char *desc = "<unknown event>";
311 
312 	switch (event) {
313 	case NET_EVENT_L4_CONNECTED:
314 		desc = "connected";
315 		break;
316 	case NET_EVENT_L4_DISCONNECTED:
317 		desc = "disconnected";
318 		break;
319 	case NET_EVENT_L4_IPV4_CONNECTED:
320 		desc = "IPv4 connectivity available";
321 		break;
322 	case NET_EVENT_L4_IPV4_DISCONNECTED:
323 		desc = "IPv4 connectivity lost";
324 		break;
325 	case NET_EVENT_L4_IPV6_CONNECTED:
326 		desc = "IPv6 connectivity available";
327 		break;
328 	case NET_EVENT_L4_IPV6_DISCONNECTED:
329 		desc = "IPv6 connectivity lost";
330 		break;
331 	case NET_EVENT_DNS_SERVER_ADD:
332 		desc = "DNS server add";
333 		break;
334 	case NET_EVENT_DNS_SERVER_DEL:
335 		desc = "DNS server del";
336 		break;
337 	case NET_EVENT_HOSTNAME_CHANGED:
338 		desc = "Hostname changed";
339 		break;
340 	case NET_EVENT_COAP_SERVICE_STARTED:
341 		desc = "CoAP service started";
342 		break;
343 	case NET_EVENT_COAP_SERVICE_STOPPED:
344 		desc = "CoAP service stopped";
345 		break;
346 	case NET_EVENT_COAP_OBSERVER_ADDED:
347 		desc = "CoAP observer added";
348 		break;
349 	case NET_EVENT_COAP_OBSERVER_REMOVED:
350 		desc = "CoAP observer removed";
351 		break;
352 	case NET_EVENT_CAPTURE_STARTED:
353 		desc = "Capture started";
354 		break;
355 	case NET_EVENT_CAPTURE_STOPPED:
356 		desc = "Capture stopped";
357 		break;
358 	}
359 
360 	return desc;
361 }
362 
363 /* We use a separate thread in order not to do any shell printing from
364  * event handler callback (to avoid stack size issues).
365  */
event_mon_handler(const struct shell * sh,void * p2,void * p3)366 static void event_mon_handler(const struct shell *sh, void *p2, void *p3)
367 {
368 	char extra_info[NET_IPV6_ADDR_LEN];
369 	struct event_msg msg;
370 
371 	ARG_UNUSED(p2);
372 	ARG_UNUSED(p3);
373 	net_mgmt_init_event_callback(&l2_cb, event_handler,
374 				     MONITOR_L2_MASK);
375 	net_mgmt_add_event_callback(&l2_cb);
376 
377 	net_mgmt_init_event_callback(&l3_ipv4_cb, event_handler,
378 				     MONITOR_L3_IPV4_MASK);
379 	net_mgmt_add_event_callback(&l3_ipv4_cb);
380 
381 	net_mgmt_init_event_callback(&l3_ipv6_cb, event_handler,
382 				     MONITOR_L3_IPV6_MASK);
383 	net_mgmt_add_event_callback(&l3_ipv6_cb);
384 
385 	net_mgmt_init_event_callback(&l4_cb, event_handler,
386 				     MONITOR_L4_MASK);
387 	net_mgmt_add_event_callback(&l4_cb);
388 
389 	while (net_event_shutting_down == false) {
390 		const char *layer_str = "<unknown layer>";
391 		const char *desc = "", *desc2 = "";
392 		char *info = NULL;
393 		uint32_t layer;
394 
395 		(void)k_msgq_get(&event_mon_msgq, &msg, K_FOREVER);
396 
397 		if (msg.iface == NULL && msg.event == 0 && msg.len == 0) {
398 			/* This is the stop message */
399 			continue;
400 		}
401 
402 		layer = NET_MGMT_GET_LAYER(msg.event);
403 		if (layer == NET_MGMT_LAYER_L2) {
404 			layer_str = "L2";
405 			desc = get_l2_desc(msg.event);
406 		} else if (layer == NET_MGMT_LAYER_L3) {
407 			layer_str = "L3";
408 			info = get_l3_desc(&msg, &desc, &desc2,
409 					   extra_info, NET_IPV6_ADDR_LEN);
410 		} else if (layer == NET_MGMT_LAYER_L4) {
411 			layer_str = "L4";
412 			desc = get_l4_desc(msg.event);
413 		}
414 
415 		PR_INFO("EVENT: %s [%d] %s%s%s%s%s\n", layer_str,
416 			net_if_get_by_iface(msg.iface), desc,
417 			desc2 ? " " : "", desc2 ? desc2 : "",
418 			info ? " " : "", info ? info : "");
419 	}
420 
421 	net_mgmt_del_event_callback(&l2_cb);
422 	net_mgmt_del_event_callback(&l3_ipv4_cb);
423 	net_mgmt_del_event_callback(&l3_ipv6_cb);
424 	net_mgmt_del_event_callback(&l4_cb);
425 
426 	k_msgq_purge(&event_mon_msgq);
427 
428 	net_event_monitoring = false;
429 	net_event_shutting_down = false;
430 
431 	PR_INFO("Network event monitoring %s.\n", "disabled");
432 }
433 #endif
434 
cmd_net_events_on(const struct shell * sh,size_t argc,char * argv[])435 static int cmd_net_events_on(const struct shell *sh, size_t argc, char *argv[])
436 {
437 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
438 	k_tid_t tid;
439 
440 	if (net_event_monitoring) {
441 		PR_INFO("Network event monitoring is already %s.\n",
442 			"enabled");
443 		return -ENOEXEC;
444 	}
445 
446 	tid = k_thread_create(&event_mon, event_mon_stack,
447 			      K_THREAD_STACK_SIZEOF(event_mon_stack),
448 			      (k_thread_entry_t)event_mon_handler,
449 			      (void *)sh, NULL, NULL, THREAD_PRIORITY, 0,
450 			      K_FOREVER);
451 	if (!tid) {
452 		PR_ERROR("Cannot create network event monitor thread!");
453 		return -ENOEXEC;
454 	}
455 
456 	k_thread_name_set(tid, "event_mon");
457 
458 	PR_INFO("Network event monitoring %s.\n", "enabled");
459 
460 	net_event_monitoring = true;
461 	net_event_shutting_down = false;
462 
463 	k_thread_start(tid);
464 #else
465 	PR_INFO("Network management events are not supported. "
466 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
467 #endif
468 
469 	return 0;
470 }
471 
cmd_net_events_off(const struct shell * sh,size_t argc,char * argv[])472 static int cmd_net_events_off(const struct shell *sh, size_t argc, char *argv[])
473 {
474 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
475 	static const struct event_msg msg;
476 	int ret;
477 
478 	if (!net_event_monitoring) {
479 		PR_INFO("Network event monitoring is already %s.\n",
480 			"disabled");
481 		return -ENOEXEC;
482 	}
483 
484 	net_event_shutting_down = true;
485 
486 	ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(100));
487 	if (ret < 0) {
488 		PR_ERROR("Cannot write to msgq (%d)\n", ret);
489 		return -ENOEXEC;
490 	}
491 #else
492 	PR_INFO("Network management events are not supported. "
493 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
494 #endif
495 
496 	return 0;
497 }
498 
cmd_net_events(const struct shell * sh,size_t argc,char * argv[])499 static int cmd_net_events(const struct shell *sh, size_t argc, char *argv[])
500 {
501 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
502 	PR("Network event monitoring is %s.\n",
503 	   net_event_monitoring ? "enabled" : "disabled");
504 
505 	if (!argv[1]) {
506 		PR_INFO("Give 'on' to enable event monitoring and "
507 			"'off' to disable it.\n");
508 	}
509 #else
510 	PR_INFO("Network management events are not supported. "
511 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
512 #endif
513 
514 	return 0;
515 }
516 
events_enable(void)517 void events_enable(void)
518 {
519 	static const char * const argv[] = {
520 		"on",
521 		NULL
522 	};
523 
524 	(void)cmd_net_events_on(shell_backend_uart_get_ptr(), 1, (char **)argv);
525 }
526 
527 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_events,
528 	SHELL_CMD(on, NULL, "Turn on network event monitoring.",
529 		  cmd_net_events_on),
530 	SHELL_CMD(off, NULL, "Turn off network event monitoring.",
531 		  cmd_net_events_off),
532 	SHELL_SUBCMD_SET_END
533 );
534 
535 SHELL_SUBCMD_ADD((net), events, &net_cmd_events, "Monitor network management events.",
536 		 cmd_net_events, 1, 1);
537