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