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/net/mld.h>
12 
13 #include "net_shell_private.h"
14 #include "../ip/ipv6.h"
15 
16 #if defined(CONFIG_NET_IPV6_FRAGMENT)
ipv6_frag_cb(struct net_ipv6_reassembly * reass,void * user_data)17 void ipv6_frag_cb(struct net_ipv6_reassembly *reass, void *user_data)
18 {
19 	struct net_shell_user_data *data = user_data;
20 	const struct shell *sh = data->sh;
21 	int *count = data->user_data;
22 	char src[ADDR_LEN];
23 	int i;
24 
25 	if (!*count) {
26 		PR("\nIPv6 reassembly Id         Remain "
27 		   "Src             \tDst\n");
28 	}
29 
30 	snprintk(src, ADDR_LEN, "%s", net_sprint_ipv6_addr(&reass->src));
31 
32 	PR("%p      0x%08x  %5d %16s\t%16s\n", reass, reass->id,
33 	   k_ticks_to_ms_ceil32(k_work_delayable_remaining_get(&reass->timer)),
34 	   src, net_sprint_ipv6_addr(&reass->dst));
35 
36 	for (i = 0; i < CONFIG_NET_IPV6_FRAGMENT_MAX_PKT; i++) {
37 		if (reass->pkt[i]) {
38 			struct net_buf *frag = reass->pkt[i]->frags;
39 
40 			PR("[%d] pkt %p->", i, reass->pkt[i]);
41 
42 			while (frag) {
43 				PR("%p", frag);
44 
45 				frag = frag->frags;
46 				if (frag) {
47 					PR("->");
48 				}
49 			}
50 
51 			PR("\n");
52 		}
53 	}
54 
55 	(*count)++;
56 }
57 #endif /* CONFIG_NET_IPV6_FRAGMENT */
58 
59 #if defined(CONFIG_NET_IPV6_PE)
ipv6_pe_filter_cb(struct in6_addr * prefix,bool is_denylist,void * user_data)60 static void ipv6_pe_filter_cb(struct in6_addr *prefix, bool is_denylist,
61 			      void *user_data)
62 {
63 	struct net_shell_user_data *data = user_data;
64 	const struct shell *sh = data->sh;
65 	int *count = data->user_data;
66 	char ipaddr[INET6_ADDRSTRLEN + 1];
67 
68 	net_addr_ntop(AF_INET6, prefix, ipaddr, sizeof(ipaddr) - 1);
69 
70 	if (*count == 0) {
71 		PR("IPv6 privacy extension %s list filters :\n",
72 		   is_denylist ? "deny" : "allow");
73 	}
74 
75 	PR("[%d] %s/64\n", *count, ipaddr);
76 
77 	(*count)++;
78 }
79 #endif /* CONFIG_NET_IPV6_PE */
80 
81 #if defined(CONFIG_NET_IPV6)
address_lifetime_cb(struct net_if * iface,void * user_data)82 static void address_lifetime_cb(struct net_if *iface, void *user_data)
83 {
84 	struct net_shell_user_data *data = user_data;
85 	const struct shell *sh = data->sh;
86 	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
87 	const char *extra;
88 
89 	ARG_UNUSED(user_data);
90 
91 	PR("\nIPv6 addresses for interface %d (%p) (%s)\n",
92 	   net_if_get_by_iface(iface), iface, iface2str(iface, &extra));
93 	PR("============================================%s\n", extra);
94 
95 	if (!ipv6) {
96 		PR("No IPv6 config found for this interface.\n");
97 		return;
98 	}
99 
100 	PR("Type      \tState    \tLifetime (sec)\tRef\tAddress\n");
101 
102 	ARRAY_FOR_EACH(ipv6->unicast, i) {
103 		char remaining_str[sizeof("01234567890")];
104 		uint8_t prefix_len = 128U;
105 
106 		if (!ipv6->unicast[i].is_used ||
107 		    ipv6->unicast[i].address.family != AF_INET6) {
108 			continue;
109 		}
110 
111 #if defined(CONFIG_NET_NATIVE_IPV6)
112 		struct net_if_ipv6_prefix *prefix;
113 		uint32_t remaining;
114 
115 		remaining = net_timeout_remaining(&ipv6->unicast[i].lifetime,
116 						  k_uptime_get_32());
117 
118 		prefix = net_if_ipv6_prefix_get(iface,
119 					   &ipv6->unicast[i].address.in6_addr);
120 		if (prefix) {
121 			prefix_len = prefix->len;
122 		}
123 
124 		if (ipv6->unicast[i].is_infinite) {
125 			snprintk(remaining_str, sizeof(remaining_str) - 1,
126 				 "infinite");
127 		} else {
128 			snprintk(remaining_str, sizeof(remaining_str) - 1,
129 				 "%u", remaining);
130 		}
131 #else
132 	snprintk(remaining_str, sizeof(remaining_str) - 1, "infinite");
133 #endif /* CONFIG_NET_NATIVE_IPV6 */
134 
135 		PR("%s  \t%s\t%14s\t%ld\t%s/%d%s\n",
136 		   addrtype2str(ipv6->unicast[i].addr_type),
137 		   addrstate2str(ipv6->unicast[i].addr_state),
138 		   remaining_str, atomic_get(&ipv6->unicast[i].atomic_ref),
139 		   net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr),
140 		   prefix_len,
141 		   ipv6->unicast[i].is_temporary ? " (temporary)" : "");
142 	}
143 }
144 #endif /* CONFIG_NET_IPV6 */
145 
cmd_net_ipv6(const struct shell * sh,size_t argc,char * argv[])146 static int cmd_net_ipv6(const struct shell *sh, size_t argc, char *argv[])
147 {
148 #if defined(CONFIG_NET_IPV6)
149 	struct net_shell_user_data user_data;
150 #endif /* CONFIG_NET_IPV6 */
151 
152 	PR("IPv6 support                              : %s\n",
153 	   IS_ENABLED(CONFIG_NET_IPV6) ?
154 	   "enabled" : "disabled");
155 	if (!IS_ENABLED(CONFIG_NET_IPV6)) {
156 		return -ENOEXEC;
157 	}
158 
159 #if defined(CONFIG_NET_NATIVE_IPV6)
160 	PR("IPv6 fragmentation support                : %s\n",
161 	   IS_ENABLED(CONFIG_NET_IPV6_FRAGMENT) ? "enabled" :
162 	   "disabled");
163 	PR("Multicast Listener Discovery support      : %s\n",
164 	   IS_ENABLED(CONFIG_NET_IPV6_MLD) ? "enabled" :
165 	   "disabled");
166 	PR("Neighbor cache support                    : %s\n",
167 	   IS_ENABLED(CONFIG_NET_IPV6_NBR_CACHE) ? "enabled" :
168 	   "disabled");
169 	PR("Neighbor discovery support                : %s\n",
170 	   IS_ENABLED(CONFIG_NET_IPV6_ND) ? "enabled" :
171 	   "disabled");
172 	PR("Duplicate address detection (DAD) support : %s\n",
173 	   IS_ENABLED(CONFIG_NET_IPV6_DAD) ? "enabled" :
174 	   "disabled");
175 	PR("Router advertisement RDNSS option support : %s\n",
176 	   IS_ENABLED(CONFIG_NET_IPV6_RA_RDNSS) ? "enabled" :
177 	   "disabled");
178 	PR("6lo header compression support            : %s\n",
179 	   IS_ENABLED(CONFIG_NET_6LO) ? "enabled" :
180 	   "disabled");
181 
182 	if (IS_ENABLED(CONFIG_NET_6LO_CONTEXT)) {
183 		PR("6lo context based compression "
184 		   "support     : %s\n",
185 		   IS_ENABLED(CONFIG_NET_6LO_CONTEXT) ? "enabled" :
186 		   "disabled");
187 	}
188 
189 	PR("Privacy extension support                 : %s\n",
190 	   IS_ENABLED(CONFIG_NET_IPV6_PE) ? "enabled" : "disabled");
191 	PR("SLAAC IID generation method               : %s\n",
192 	   IS_ENABLED(CONFIG_NET_IPV6_IID_STABLE) ?
193 	   "stable (RFC 7217)" : "EUI-64 (RFC 4862)");
194 
195 #if defined(CONFIG_NET_IPV6_PE)
196 	PR("Max number of IPv6 privacy extension filters "
197 	   "                : %d\n",
198 	   CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT);
199 #endif /* CONFIG_NET_IPV6_PE */
200 
201 	PR("Path MTU Discovery (PMTU)                 : %s\n",
202 	   IS_ENABLED(CONFIG_NET_IPV6_PMTU) ? "enabled" : "disabled");
203 
204 #endif /* CONFIG_NET_NATIVE_IPV6 */
205 
206 #if defined(CONFIG_NET_IPV6)
207 	PR("Max number of IPv6 network interfaces "
208 	   "in the system          : %d\n",
209 	   CONFIG_NET_IF_MAX_IPV6_COUNT);
210 	PR("Max number of unicast IPv6 addresses "
211 	   "per network interface   : %d\n",
212 	   CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT);
213 	PR("Max number of multicast IPv6 addresses "
214 	   "per network interface : %d\n",
215 	   CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT);
216 	PR("Max number of IPv6 prefixes per network "
217 	   "interface            : %d\n",
218 	   CONFIG_NET_IF_IPV6_PREFIX_COUNT);
219 
220 	user_data.sh = sh;
221 	user_data.user_data = NULL;
222 
223 	/* Print information about address lifetime */
224 	net_if_foreach(address_lifetime_cb, &user_data);
225 #endif /* CONFIG_NET_IPV6 */
226 
227 	return 0;
228 }
229 
cmd_net_ip6_add(const struct shell * sh,size_t argc,char * argv[])230 static int cmd_net_ip6_add(const struct shell *sh, size_t argc, char *argv[])
231 {
232 #if defined(CONFIG_NET_IPV6)
233 	struct net_if *iface = NULL;
234 	int idx;
235 	struct in6_addr addr;
236 
237 	if (argc != 3) {
238 		PR_ERROR("Correct usage: net ipv6 add <index> <address>\n");
239 		return -EINVAL;
240 	}
241 
242 	idx = get_iface_idx(sh, argv[1]);
243 	if (idx < 0) {
244 		return -ENOEXEC;
245 	}
246 
247 	iface = net_if_get_by_index(idx);
248 	if (!iface) {
249 		PR_WARNING("No such interface in index %d\n", idx);
250 		return -ENOENT;
251 	}
252 
253 	if (net_addr_pton(AF_INET6, argv[2], &addr)) {
254 		PR_ERROR("Invalid address: %s\n", argv[2]);
255 		return -EINVAL;
256 	}
257 
258 	if (net_ipv6_is_addr_mcast(&addr)) {
259 		int ret;
260 
261 		ret = net_ipv6_mld_join(iface, &addr);
262 		if (ret < 0) {
263 			PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n",
264 				 "join", net_sprint_ipv6_addr(&addr), idx, ret);
265 			if (ret == -ENOTSUP) {
266 				PR_INFO("Enable CONFIG_NET_IPV6_MLD for %s multicast "
267 					"group\n", "joining");
268 			}
269 			return ret;
270 		}
271 	} else {
272 		if (!net_if_ipv6_addr_add(iface, &addr, NET_ADDR_MANUAL, 0)) {
273 			PR_ERROR("Failed to add %s address to interface %p\n", argv[2], iface);
274 		}
275 	}
276 
277 #else /* CONFIG_NET_IPV6 */
278 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_IPV6", "IPv6");
279 #endif /* CONFIG_NET_IPV6 */
280 	return 0;
281 }
282 
cmd_net_ip6_del(const struct shell * sh,size_t argc,char * argv[])283 static int cmd_net_ip6_del(const struct shell *sh, size_t argc, char *argv[])
284 {
285 #if defined(CONFIG_NET_IPV6)
286 	struct net_if *iface = NULL;
287 	int idx;
288 	struct in6_addr addr;
289 
290 	if (argc != 3) {
291 		PR_ERROR("Correct usage: net ipv6 del <index> <address>\n");
292 		return -EINVAL;
293 	}
294 
295 	idx = get_iface_idx(sh, argv[1]);
296 	if (idx < 0) {
297 		return -ENOEXEC;
298 	}
299 
300 	iface = net_if_get_by_index(idx);
301 	if (!iface) {
302 		PR_WARNING("No such interface in index %d\n", idx);
303 		return -ENOENT;
304 	}
305 
306 	if (net_addr_pton(AF_INET6, argv[2], &addr)) {
307 		PR_ERROR("Invalid address: %s\n", argv[2]);
308 		return -EINVAL;
309 	}
310 
311 	if (net_ipv6_is_addr_mcast(&addr)) {
312 		int ret;
313 
314 		ret = net_ipv6_mld_leave(iface, &addr);
315 		if (ret < 0) {
316 			PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n",
317 				 "leave", net_sprint_ipv6_addr(&addr), idx, ret);
318 			if (ret == -ENOTSUP) {
319 				PR_INFO("Enable CONFIG_NET_IPV6_MLD for %s multicast "
320 					"group\n", "leaving");
321 			}
322 			return ret;
323 		}
324 	} else {
325 		if (!net_if_ipv6_addr_rm(iface, &addr)) {
326 			PR_ERROR("Failed to delete %s\n", argv[2]);
327 			return -1;
328 		}
329 	}
330 
331 #else /* CONFIG_NET_IPV6 */
332 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_IPV6", "IPv6");
333 #endif /* CONFIG_NET_IPV6 */
334 	return 0;
335 }
336 
cmd_net_ip6_pe(const struct shell * sh,size_t argc,char * argv[])337 static int cmd_net_ip6_pe(const struct shell *sh, size_t argc, char *argv[])
338 {
339 #if defined(CONFIG_NET_NATIVE_IPV6)
340 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
341 	bool do_allowlisting = true;
342 	struct in6_addr prefix;
343 	bool do_add;
344 	int arg = 1;
345 	int ret;
346 
347 	if (argc == 0) {
348 		PR_ERROR("Correct usage: net ipv6 pe [add | del] [allow | deny] [<prefix>]\n");
349 		return -EINVAL;
350 	}
351 
352 	if (argc == 1) {
353 		struct net_shell_user_data user_data;
354 		int count = 0;
355 
356 		user_data.sh = sh;
357 		user_data.user_data = &count;
358 
359 		count = net_ipv6_pe_filter_foreach(ipv6_pe_filter_cb, &user_data);
360 		if (count == 0) {
361 			PR("No privacy extension filters found.");
362 		}
363 
364 		return 0;
365 	}
366 
367 	if (strcmp(argv[arg], "add") == 0) {
368 		arg++;
369 		do_add = true;
370 	} else if (strcmp(argv[arg], "del") == 0) {
371 		arg++;
372 		do_add = false;
373 	} else {
374 		PR("Unknown sub-option \"%s\"\n", argv[arg]);
375 		return 0;
376 	}
377 
378 	if (!argv[arg]) {
379 		PR("No sub-options given. See \"help net ipv6\" "
380 		   "command for details.\n");
381 		return 0;
382 	}
383 
384 	if (strcmp(argv[arg], "allow") == 0) {
385 		arg++;
386 	} else if (strcmp(argv[arg], "deny") == 0) {
387 		arg++;
388 		do_allowlisting = false;
389 	}
390 
391 	if (!argv[arg]) {
392 		PR("No sub-options given. See \"help net ipv6\" "
393 		   "command for details.\n");
394 		return 0;
395 	}
396 
397 	ret = net_addr_pton(AF_INET6, argv[arg], &prefix);
398 	if (ret < 0) {
399 		PR("Invalid prefix \"%s\"\n", argv[arg]);
400 		if (strstr(argv[arg], "/")) {
401 			PR("Do not add the prefix length.\n");
402 		}
403 
404 		return 0;
405 	}
406 
407 	if (do_add) {
408 		ret = net_ipv6_pe_add_filter(&prefix, !do_allowlisting);
409 	} else {
410 		ret = net_ipv6_pe_del_filter(&prefix);
411 	}
412 
413 	if (ret < 0) {
414 		if (ret == -EALREADY) {
415 			PR("Filter %s already in %s list\n",
416 			   net_sprint_ipv6_addr(&prefix),
417 			   do_allowlisting ? "allow" : "deny");
418 		} else if (ret == -ENOENT) {
419 			PR("No such filter %s found\n",
420 			   net_sprint_ipv6_addr(&prefix));
421 		} else {
422 			PR("Cannot %s %s %sfilter (%d)\n",
423 			   do_add ? "add" : "delete",
424 			   argv[arg],
425 			   do_add ?
426 			   (do_allowlisting ? "allowlist " :
427 			    "denylist ") : "",
428 			   ret);
429 		}
430 
431 		return 0;
432 	}
433 
434 	PR("%s %s%sfilter for %s\n",
435 	   do_add ? "Added" : "Deleted",
436 	   do_add ? (do_allowlisting ? "allow" : "deny") : "",
437 	   do_add ? " list " : "",
438 	   argv[arg]);
439 #else
440 	PR("IPv6 privacy extension filter support is disabled.\n");
441 	PR("Set CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 to enable it.\n");
442 #endif
443 #else /* CONFIG_NET_NATIVE_IPV6 */
444 	PR_INFO("Set %s and %s to enable native %s support.\n",
445 			"CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
446 #endif /* CONFIG_NET_NATIVE_IPV6 */
447 	return 0;
448 }
449 
450 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_ip6,
451 	SHELL_CMD(add, NULL,
452 		  "'net ipv6 add <index> <address>' adds the address to the interface.",
453 		  cmd_net_ip6_add),
454 	SHELL_CMD(del, NULL,
455 		  "'net ipv6 del <index> <address>' deletes the address from the interface.",
456 		  cmd_net_ip6_del),
457 	SHELL_CMD(pe, NULL,
458 		  "net ipv6 pe add [allow|deny] <IPv6 prefix>\n"
459 		  "Add IPv6 address to filter list. The allow/deny "
460 		  "parameter tells if this is allow listed (accepted) or "
461 		  "deny listed (declined) prefix. Default is to allow list "
462 		  "the prefix.\n"
463 		  "ipv6 pe del <IPv6 prefix>\n"
464 		  "Delete IPv6 address from filter list.",
465 		  cmd_net_ip6_pe),
466 	SHELL_SUBCMD_SET_END
467 );
468 
469 SHELL_SUBCMD_ADD((net), ipv6, &net_cmd_ip6,
470 		 "Print information about IPv6 specific information and "
471 		 "configuration.",
472 		 cmd_net_ipv6, 1, 0);
473