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