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 EVENT_MON_STACK_SIZE 1024
21 #define THREAD_PRIORITY K_PRIO_COOP(2)
22 #define MAX_EVENT_INFO_SIZE NET_EVENT_INFO_MAX_SIZE
23 #define MONITOR_L2_MASK (_NET_EVENT_IF_BASE)
24 #define MONITOR_L3_IPV4_MASK (_NET_EVENT_IPV4_BASE)
25 #define MONITOR_L3_IPV6_MASK (_NET_EVENT_IPV6_BASE)
26 #define MONITOR_L4_MASK (_NET_EVENT_L4_BASE)
27 
28 static bool net_event_monitoring;
29 static bool net_event_shutting_down;
30 static struct net_mgmt_event_callback l2_cb;
31 static struct net_mgmt_event_callback l3_ipv4_cb;
32 static struct net_mgmt_event_callback l3_ipv6_cb;
33 static struct net_mgmt_event_callback l4_cb;
34 static struct k_thread event_mon;
35 static K_THREAD_STACK_DEFINE(event_mon_stack, EVENT_MON_STACK_SIZE);
36 
37 struct event_msg {
38 	struct net_if *iface;
39 	size_t len;
40 	uint32_t event;
41 	uint8_t data[MAX_EVENT_INFO_SIZE];
42 };
43 
44 K_MSGQ_DEFINE(event_mon_msgq, sizeof(struct event_msg),
45 	      CONFIG_NET_MGMT_EVENT_QUEUE_SIZE, sizeof(intptr_t));
46 
event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)47 static void event_handler(struct net_mgmt_event_callback *cb,
48 			  uint32_t mgmt_event, struct net_if *iface)
49 {
50 	struct event_msg msg;
51 	int ret;
52 
53 	memset(&msg, 0, sizeof(msg));
54 
55 	msg.len = MIN(sizeof(msg.data), cb->info_length);
56 	msg.event = mgmt_event;
57 	msg.iface = iface;
58 
59 	if (cb->info_length > 0) {
60 		memcpy(msg.data, cb->info, msg.len);
61 	}
62 
63 	ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(10));
64 	if (ret < 0) {
65 		NET_ERR("Cannot write to msgq (%d)\n", ret);
66 	}
67 }
68 
get_l2_desc(uint32_t event)69 static const char *get_l2_desc(uint32_t event)
70 {
71 	static const char *desc = "<unknown event>";
72 
73 	switch (event) {
74 	case NET_EVENT_IF_DOWN:
75 		desc = "down";
76 		break;
77 	case NET_EVENT_IF_UP:
78 		desc = "up";
79 		break;
80 	}
81 
82 	return desc;
83 }
84 
get_l3_desc(struct event_msg * msg,const char ** desc,const char ** desc2,char * extra_info,size_t extra_info_len)85 static char *get_l3_desc(struct event_msg *msg,
86 			 const char **desc, const char **desc2,
87 			 char *extra_info, size_t extra_info_len)
88 {
89 	static const char *desc_unknown = "<unknown event>";
90 	char *info = NULL;
91 
92 	*desc = desc_unknown;
93 
94 	switch (msg->event) {
95 	case NET_EVENT_IPV6_ADDR_ADD:
96 		*desc = "IPv6 address";
97 		*desc2 = "add";
98 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
99 				     extra_info_len);
100 		break;
101 	case NET_EVENT_IPV6_ADDR_DEL:
102 		*desc = "IPv6 address";
103 		*desc2 = "del";
104 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
105 				     extra_info_len);
106 		break;
107 	case NET_EVENT_IPV6_MADDR_ADD:
108 		*desc = "IPv6 mcast address";
109 		*desc2 = "add";
110 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
111 				     extra_info_len);
112 		break;
113 	case NET_EVENT_IPV6_MADDR_DEL:
114 		*desc = "IPv6 mcast address";
115 		*desc2 = "del";
116 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
117 				     extra_info_len);
118 		break;
119 	case NET_EVENT_IPV6_PREFIX_ADD:
120 		*desc = "IPv6 prefix";
121 		*desc2 = "add";
122 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
123 				     extra_info_len);
124 		break;
125 	case NET_EVENT_IPV6_PREFIX_DEL:
126 		*desc = "IPv6 prefix";
127 		*desc2 = "del";
128 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
129 				     extra_info_len);
130 		break;
131 	case NET_EVENT_IPV6_MCAST_JOIN:
132 		*desc = "IPv6 mcast";
133 		*desc2 = "join";
134 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
135 				     extra_info_len);
136 		break;
137 	case NET_EVENT_IPV6_MCAST_LEAVE:
138 		*desc = "IPv6 mcast";
139 		*desc2 = "leave";
140 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
141 				     extra_info_len);
142 		break;
143 	case NET_EVENT_IPV6_ROUTER_ADD:
144 		*desc = "IPv6 router";
145 		*desc2 = "add";
146 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
147 				     extra_info_len);
148 		break;
149 	case NET_EVENT_IPV6_ROUTER_DEL:
150 		*desc = "IPv6 router";
151 		*desc2 = "del";
152 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
153 				     extra_info_len);
154 		break;
155 	case NET_EVENT_IPV6_ROUTE_ADD:
156 		*desc = "IPv6 route";
157 		*desc2 = "add";
158 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
159 				     extra_info_len);
160 		break;
161 	case NET_EVENT_IPV6_ROUTE_DEL:
162 		*desc = "IPv6 route";
163 		*desc2 = "del";
164 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
165 				     extra_info_len);
166 		break;
167 	case NET_EVENT_IPV6_DAD_SUCCEED:
168 		*desc = "IPv6 DAD";
169 		*desc2 = "ok";
170 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
171 				     extra_info_len);
172 		break;
173 	case NET_EVENT_IPV6_DAD_FAILED:
174 		*desc = "IPv6 DAD";
175 		*desc2 = "fail";
176 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
177 				     extra_info_len);
178 		break;
179 	case NET_EVENT_IPV6_NBR_ADD:
180 		*desc = "IPv6 neighbor";
181 		*desc2 = "add";
182 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
183 				     extra_info_len);
184 		break;
185 	case NET_EVENT_IPV6_NBR_DEL:
186 		*desc = "IPv6 neighbor";
187 		*desc2 = "del";
188 		info = net_addr_ntop(AF_INET6, msg->data, extra_info,
189 				     extra_info_len);
190 		break;
191 	case NET_EVENT_IPV4_ADDR_ADD:
192 		*desc = "IPv4 address";
193 		*desc2 = "add";
194 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
195 				     extra_info_len);
196 		break;
197 	case NET_EVENT_IPV4_ADDR_DEL:
198 		*desc = "IPv4 address";
199 		*desc2 = "del";
200 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
201 				     extra_info_len);
202 		break;
203 	case NET_EVENT_IPV4_ROUTER_ADD:
204 		*desc = "IPv4 router";
205 		*desc2 = "add";
206 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
207 				     extra_info_len);
208 		break;
209 	case NET_EVENT_IPV4_ROUTER_DEL:
210 		*desc = "IPv4 router";
211 		*desc2 = "del";
212 		info = net_addr_ntop(AF_INET, msg->data, extra_info,
213 				     extra_info_len);
214 		break;
215 	case NET_EVENT_IPV4_DHCP_START:
216 		*desc = "DHCPv4";
217 		*desc2 = "start";
218 		break;
219 	case NET_EVENT_IPV4_DHCP_BOUND:
220 		*desc = "DHCPv4";
221 		*desc2 = "bound";
222 #if defined(CONFIG_NET_DHCPV4)
223 		struct net_if_dhcpv4 *data = (struct net_if_dhcpv4 *)msg->data;
224 
225 		info = net_addr_ntop(AF_INET, &data->requested_ip, extra_info,
226 				     extra_info_len);
227 #endif
228 		break;
229 	case NET_EVENT_IPV4_DHCP_STOP:
230 		*desc = "DHCPv4";
231 		*desc2 = "stop";
232 		break;
233 	}
234 
235 	return info;
236 }
237 
get_l4_desc(uint32_t event)238 static const char *get_l4_desc(uint32_t event)
239 {
240 	static const char *desc = "<unknown event>";
241 
242 	switch (event) {
243 	case NET_EVENT_L4_CONNECTED:
244 		desc = "connected";
245 		break;
246 	case NET_EVENT_L4_DISCONNECTED:
247 		desc = "disconnected";
248 		break;
249 	case NET_EVENT_DNS_SERVER_ADD:
250 		desc = "DNS server add";
251 		break;
252 	case NET_EVENT_DNS_SERVER_DEL:
253 		desc = "DNS server del";
254 		break;
255 	case NET_EVENT_COAP_SERVICE_STARTED:
256 		desc = "CoAP service started";
257 		break;
258 	case NET_EVENT_COAP_SERVICE_STOPPED:
259 		desc = "CoAP service stopped";
260 		break;
261 	case NET_EVENT_COAP_OBSERVER_ADDED:
262 		desc = "CoAP observer added";
263 		break;
264 	case NET_EVENT_COAP_OBSERVER_REMOVED:
265 		desc = "CoAP observer removed";
266 		break;
267 	}
268 
269 	return desc;
270 }
271 
272 /* We use a separate thread in order not to do any shell printing from
273  * event handler callback (to avoid stack size issues).
274  */
event_mon_handler(const struct shell * sh)275 static void event_mon_handler(const struct shell *sh)
276 {
277 	char extra_info[NET_IPV6_ADDR_LEN];
278 	struct event_msg msg;
279 
280 	net_mgmt_init_event_callback(&l2_cb, event_handler,
281 				     MONITOR_L2_MASK);
282 	net_mgmt_add_event_callback(&l2_cb);
283 
284 	net_mgmt_init_event_callback(&l3_ipv4_cb, event_handler,
285 				     MONITOR_L3_IPV4_MASK);
286 	net_mgmt_add_event_callback(&l3_ipv4_cb);
287 
288 	net_mgmt_init_event_callback(&l3_ipv6_cb, event_handler,
289 				     MONITOR_L3_IPV6_MASK);
290 	net_mgmt_add_event_callback(&l3_ipv6_cb);
291 
292 	net_mgmt_init_event_callback(&l4_cb, event_handler,
293 				     MONITOR_L4_MASK);
294 	net_mgmt_add_event_callback(&l4_cb);
295 
296 	while (net_event_shutting_down == false) {
297 		const char *layer_str = "<unknown layer>";
298 		const char *desc = "", *desc2 = "";
299 		char *info = NULL;
300 		uint32_t layer;
301 
302 		(void)k_msgq_get(&event_mon_msgq, &msg, K_FOREVER);
303 
304 		if (msg.iface == NULL && msg.event == 0 && msg.len == 0) {
305 			/* This is the stop message */
306 			continue;
307 		}
308 
309 		layer = NET_MGMT_GET_LAYER(msg.event);
310 		if (layer == NET_MGMT_LAYER_L2) {
311 			layer_str = "L2";
312 			desc = get_l2_desc(msg.event);
313 		} else if (layer == NET_MGMT_LAYER_L3) {
314 			layer_str = "L3";
315 			info = get_l3_desc(&msg, &desc, &desc2,
316 					   extra_info, NET_IPV6_ADDR_LEN);
317 		} else if (layer == NET_MGMT_LAYER_L4) {
318 			layer_str = "L4";
319 			desc = get_l4_desc(msg.event);
320 		}
321 
322 		PR_INFO("EVENT: %s [%d] %s%s%s%s%s\n", layer_str,
323 			net_if_get_by_iface(msg.iface), desc,
324 			desc2 ? " " : "", desc2 ? desc2 : "",
325 			info ? " " : "", info ? info : "");
326 	}
327 
328 	net_mgmt_del_event_callback(&l2_cb);
329 	net_mgmt_del_event_callback(&l3_ipv4_cb);
330 	net_mgmt_del_event_callback(&l3_ipv6_cb);
331 	net_mgmt_del_event_callback(&l4_cb);
332 
333 	k_msgq_purge(&event_mon_msgq);
334 
335 	net_event_monitoring = false;
336 	net_event_shutting_down = false;
337 
338 	PR_INFO("Network event monitoring %s.\n", "disabled");
339 }
340 #endif
341 
cmd_net_events_on(const struct shell * sh,size_t argc,char * argv[])342 static int cmd_net_events_on(const struct shell *sh, size_t argc, char *argv[])
343 {
344 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
345 	k_tid_t tid;
346 
347 	if (net_event_monitoring) {
348 		PR_INFO("Network event monitoring is already %s.\n",
349 			"enabled");
350 		return -ENOEXEC;
351 	}
352 
353 	tid = k_thread_create(&event_mon, event_mon_stack,
354 			      K_THREAD_STACK_SIZEOF(event_mon_stack),
355 			      (k_thread_entry_t)event_mon_handler,
356 			      (void *)sh, NULL, NULL, THREAD_PRIORITY, 0,
357 			      K_FOREVER);
358 	if (!tid) {
359 		PR_ERROR("Cannot create network event monitor thread!");
360 		return -ENOEXEC;
361 	}
362 
363 	k_thread_name_set(tid, "event_mon");
364 
365 	PR_INFO("Network event monitoring %s.\n", "enabled");
366 
367 	net_event_monitoring = true;
368 	net_event_shutting_down = false;
369 
370 	k_thread_start(tid);
371 #else
372 	PR_INFO("Network management events are not supported. "
373 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
374 #endif
375 
376 	return 0;
377 }
378 
cmd_net_events_off(const struct shell * sh,size_t argc,char * argv[])379 static int cmd_net_events_off(const struct shell *sh, size_t argc, char *argv[])
380 {
381 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
382 	static const struct event_msg msg;
383 	int ret;
384 
385 	if (!net_event_monitoring) {
386 		PR_INFO("Network event monitoring is already %s.\n",
387 			"disabled");
388 		return -ENOEXEC;
389 	}
390 
391 	net_event_shutting_down = true;
392 
393 	ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(100));
394 	if (ret < 0) {
395 		PR_ERROR("Cannot write to msgq (%d)\n", ret);
396 		return -ENOEXEC;
397 	}
398 #else
399 	PR_INFO("Network management events are not supported. "
400 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
401 #endif
402 
403 	return 0;
404 }
405 
cmd_net_events(const struct shell * sh,size_t argc,char * argv[])406 static int cmd_net_events(const struct shell *sh, size_t argc, char *argv[])
407 {
408 #if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
409 	PR("Network event monitoring is %s.\n",
410 	   net_event_monitoring ? "enabled" : "disabled");
411 
412 	if (!argv[1]) {
413 		PR_INFO("Give 'on' to enable event monitoring and "
414 			"'off' to disable it.\n");
415 	}
416 #else
417 	PR_INFO("Network management events are not supported. "
418 		"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
419 #endif
420 
421 	return 0;
422 }
423 
events_enable(void)424 void events_enable(void)
425 {
426 	static const char * const argv[] = {
427 		"on",
428 		NULL
429 	};
430 
431 	(void)cmd_net_events_on(shell_backend_uart_get_ptr(), 1, (char **)argv);
432 }
433 
434 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_events,
435 	SHELL_CMD(on, NULL, "Turn on network event monitoring.",
436 		  cmd_net_events_on),
437 	SHELL_CMD(off, NULL, "Turn off network event monitoring.",
438 		  cmd_net_events_off),
439 	SHELL_SUBCMD_SET_END
440 );
441 
442 SHELL_SUBCMD_ADD((net), events, &net_cmd_events, "Monitor network management events.",
443 		 cmd_net_events, 1, 1);
444