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 #include <zephyr/random/random.h>
10 #include <strings.h>
11 LOG_MODULE_DECLARE(net_shell);
12 
13 #include <zephyr/sys/base64.h>
14 
15 #if defined(CONFIG_NET_L2_ETHERNET)
16 #include <zephyr/net/ethernet.h>
17 #endif
18 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
19 #include <zephyr/net/ethernet_mgmt.h>
20 #endif
21 #if defined(CONFIG_NET_L2_VIRTUAL)
22 #include <zephyr/net/virtual.h>
23 #include <zephyr/net/virtual_mgmt.h>
24 #endif
25 #if defined(CONFIG_ETH_PHY_DRIVER)
26 #include <zephyr/net/phy.h>
27 #endif
28 
29 #include "net_shell_private.h"
30 
31 #define UNICAST_MASK GENMASK(7, 1)
32 #define LOCAL_BIT BIT(1)
33 
34 #if defined(CONFIG_NET_L2_ETHERNET) && defined(CONFIG_NET_NATIVE)
35 struct ethernet_capabilities {
36 	enum ethernet_hw_caps capability;
37 	const char * const description;
38 };
39 
40 #define EC(cap, desc) { .capability = cap, .description = desc }
41 
42 static struct ethernet_capabilities eth_hw_caps[] = {
43 	EC(ETHERNET_HW_TX_CHKSUM_OFFLOAD, "TX checksum offload"),
44 	EC(ETHERNET_HW_RX_CHKSUM_OFFLOAD, "RX checksum offload"),
45 	EC(ETHERNET_HW_VLAN,              "Virtual LAN"),
46 	EC(ETHERNET_HW_VLAN_TAG_STRIP,    "VLAN Tag stripping"),
47 	EC(ETHERNET_LINK_10BASE,          "10 Mbits"),
48 	EC(ETHERNET_LINK_100BASE,         "100 Mbits"),
49 	EC(ETHERNET_LINK_1000BASE,        "1 Gbits"),
50 	EC(ETHERNET_LINK_2500BASE,        "2.5 Gbits"),
51 	EC(ETHERNET_LINK_5000BASE,        "5 Gbits"),
52 	EC(ETHERNET_PTP,                  "IEEE 802.1AS gPTP clock"),
53 	EC(ETHERNET_QAV,                  "IEEE 802.1Qav (credit shaping)"),
54 	EC(ETHERNET_QBV,                  "IEEE 802.1Qbv (scheduled traffic)"),
55 	EC(ETHERNET_QBU,                  "IEEE 802.1Qbu (frame preemption)"),
56 	EC(ETHERNET_TXTIME,               "TXTIME"),
57 	EC(ETHERNET_PROMISC_MODE,         "Promiscuous mode"),
58 	EC(ETHERNET_PRIORITY_QUEUES,      "Priority queues"),
59 	EC(ETHERNET_HW_FILTERING,         "MAC address filtering"),
60 	EC(ETHERNET_DSA_USER_PORT,        "DSA user port"),
61 	EC(ETHERNET_DSA_CONDUIT_PORT,     "DSA conduit port"),
62 	EC(ETHERNET_TXTIME,               "TXTIME supported"),
63 	EC(ETHERNET_TXINJECTION_MODE,     "TX-Injection supported"),
64 };
65 
print_supported_ethernet_capabilities(const struct shell * sh,struct net_if * iface)66 static void print_supported_ethernet_capabilities(
67 	const struct shell *sh, struct net_if *iface)
68 {
69 	enum ethernet_hw_caps caps = net_eth_get_hw_capabilities(iface);
70 
71 	ARRAY_FOR_EACH(eth_hw_caps, i) {
72 		if (caps & eth_hw_caps[i].capability) {
73 			PR("\t%s\n", eth_hw_caps[i].description);
74 		}
75 	}
76 }
77 #endif /* CONFIG_NET_L2_ETHERNET */
78 
79 #ifdef CONFIG_ETH_PHY_DRIVER
print_phy_link_state(const struct shell * sh,const struct device * phy_dev)80 static void print_phy_link_state(const struct shell *sh, const struct device *phy_dev)
81 {
82 	struct phy_link_state link;
83 	int ret;
84 
85 	ret = phy_get_link_state(phy_dev, &link);
86 	if (ret < 0) {
87 		PR_ERROR("Failed to get link state (%d)\n", ret);
88 		return;
89 	}
90 
91 	PR("Ethernet link speed: %s ", PHY_LINK_IS_SPEED_1000M(link.speed)  ? "1 Gbits"
92 				       : PHY_LINK_IS_SPEED_100M(link.speed) ? "100 Mbits"
93 									    : "10 Mbits");
94 
95 	PR("%s-duplex\n", PHY_LINK_IS_FULL_DUPLEX(link.speed) ? "full" : "half");
96 }
97 #endif
98 
iface_flags2str(struct net_if * iface)99 static const char *iface_flags2str(struct net_if *iface)
100 {
101 	static char str[sizeof("POINTOPOINT") + sizeof("PROMISC") +
102 			sizeof("NO_AUTO_START") + sizeof("SUSPENDED") +
103 			sizeof("MCAST_FORWARD") + sizeof("IPv4") +
104 			sizeof("IPv6") + sizeof("NO_ND") + sizeof("NO_MLD")];
105 	int pos = 0;
106 
107 	if (net_if_flag_is_set(iface, NET_IF_POINTOPOINT)) {
108 		pos += snprintk(str + pos, sizeof(str) - pos,
109 				"POINTOPOINT,");
110 	}
111 
112 	if (net_if_flag_is_set(iface, NET_IF_PROMISC)) {
113 		pos += snprintk(str + pos, sizeof(str) - pos,
114 				"PROMISC,");
115 	}
116 
117 	if (net_if_flag_is_set(iface, NET_IF_NO_AUTO_START)) {
118 		pos += snprintk(str + pos, sizeof(str) - pos,
119 				"NO_AUTO_START,");
120 	} else {
121 		pos += snprintk(str + pos, sizeof(str) - pos,
122 				"AUTO_START,");
123 	}
124 
125 	if (net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) {
126 		pos += snprintk(str + pos, sizeof(str) - pos,
127 				"MCAST_FORWARD,");
128 	}
129 
130 	if (net_if_flag_is_set(iface, NET_IF_IPV4)) {
131 		pos += snprintk(str + pos, sizeof(str) - pos,
132 				"IPv4,");
133 	}
134 
135 	if (net_if_flag_is_set(iface, NET_IF_IPV6)) {
136 		pos += snprintk(str + pos, sizeof(str) - pos,
137 				"IPv6,");
138 	}
139 
140 	if (net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) {
141 		pos += snprintk(str + pos, sizeof(str) - pos,
142 				"NO_ND,");
143 	}
144 
145 	if (net_if_flag_is_set(iface, NET_IF_IPV6_NO_MLD)) {
146 		pos += snprintk(str + pos, sizeof(str) - pos,
147 				"NO_MLD,");
148 	}
149 
150 	/* get rid of last ',' character */
151 	str[pos - 1] = '\0';
152 
153 	return str;
154 }
155 
iface_cb(struct net_if * iface,void * user_data)156 static void iface_cb(struct net_if *iface, void *user_data)
157 {
158 	struct net_shell_user_data *data = user_data;
159 	const struct shell *sh = data->sh;
160 	int ret;
161 
162 	ARG_UNUSED(ret); /* could be unused depending on config */
163 
164 #if defined(CONFIG_NET_NATIVE_IPV6)
165 	struct net_if_ipv6_prefix *prefix;
166 	struct net_if_router *router;
167 #endif
168 #if defined(CONFIG_NET_IPV6)
169 	struct net_if_ipv6 *ipv6;
170 #endif
171 #if defined(CONFIG_NET_IPV4)
172 	struct net_if_ipv4 *ipv4;
173 #endif
174 #if defined(CONFIG_NET_IP)
175 	struct net_if_addr *unicast;
176 	struct net_if_mcast_addr *mcast;
177 #endif
178 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
179 	struct ethernet_req_params params;
180 #endif
181 	const char *extra;
182 #if defined(CONFIG_NET_IP) || defined(CONFIG_NET_L2_ETHERNET_MGMT)
183 	int count;
184 #endif
185 
186 	if (data->user_data && data->user_data != iface) {
187 		return;
188 	}
189 
190 #if defined(CONFIG_NET_INTERFACE_NAME)
191 	char ifname[CONFIG_NET_INTERFACE_NAME_LEN + 1] = { 0 };
192 	int ret_name;
193 
194 	ret_name = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
195 	if (ret_name < 1 || ifname[0] == '\0') {
196 		snprintk(ifname, sizeof(ifname), "?");
197 	}
198 
199 	PR("\nInterface %s (%p) (%s) [%d]\n", ifname, iface, iface2str(iface, &extra),
200 	   net_if_get_by_iface(iface));
201 #else
202 	PR("\nInterface %p (%s) [%d]\n", iface, iface2str(iface, &extra),
203 	   net_if_get_by_iface(iface));
204 #endif
205 	PR("===========================%s\n", extra);
206 
207 	if (!net_if_is_up(iface)) {
208 		PR_INFO("Interface is down.\n");
209 
210 		/* Show detailed information only when user asks information
211 		 * about one specific network interface.
212 		 */
213 		if (data->user_data == NULL) {
214 			return;
215 		}
216 	}
217 
218 #ifdef CONFIG_NET_POWER_MANAGEMENT
219 	if (net_if_is_suspended(iface)) {
220 		PR_INFO("Interface is suspended, thus not able to tx/rx.\n");
221 	}
222 #endif
223 
224 #if defined(CONFIG_NET_L2_VIRTUAL)
225 	if (!sys_slist_is_empty(&iface->config.virtual_interfaces)) {
226 		struct virtual_interface_context *ctx, *tmp;
227 
228 		PR("Virtual interfaces attached to this : ");
229 		SYS_SLIST_FOR_EACH_CONTAINER_SAFE(
230 					&iface->config.virtual_interfaces,
231 					ctx, tmp, node) {
232 			if (ctx->virtual_iface == iface) {
233 				continue;
234 			}
235 
236 			PR("%d ", net_if_get_by_iface(ctx->virtual_iface));
237 		}
238 
239 		PR("\n");
240 	}
241 
242 	if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
243 		struct net_if *orig_iface;
244 		char *name, buf[CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN];
245 
246 		name = net_virtual_get_name(iface, buf, sizeof(buf));
247 		if (!(name && name[0])) {
248 			name = "<unknown>";
249 		}
250 
251 		PR("Virtual name : %s\n", name);
252 
253 		orig_iface = net_virtual_get_iface(iface);
254 		if (orig_iface == NULL) {
255 			PR("No attached network interface.\n");
256 		} else {
257 			PR("Attached  : %d (%s / %p)\n",
258 			   net_if_get_by_iface(orig_iface),
259 			   iface2str(orig_iface, NULL),
260 			   orig_iface);
261 		}
262 	}
263 
264 	if (IS_ENABLED(CONFIG_NET_VPN) &&
265 	    net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
266 		if (net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VPN) {
267 			struct virtual_interface_req_params vparams = { 0 };
268 			char public_key[NET_VIRTUAL_MAX_PUBLIC_KEY_LEN * 2];
269 			size_t olen;
270 
271 			ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_GET_PUBLIC_KEY,
272 				       iface, &vparams, sizeof(vparams));
273 			if (ret < 0) {
274 				PR_WARNING("Cannot get VPN public key (%d)\n", ret);
275 			} else {
276 				bool all_zeros = true;
277 
278 				for (int i = 0;
279 				     all_zeros && i < NET_VIRTUAL_MAX_PUBLIC_KEY_LEN; i++) {
280 					all_zeros = (vparams.public_key.data[i] == 0);
281 				}
282 
283 				if (all_zeros) {
284 					PR("Public key: <not set>\n");
285 				} else {
286 					(void)base64_encode(public_key, sizeof(public_key),
287 							    &olen, vparams.public_key.data,
288 							    vparams.public_key.len);
289 
290 					PR("Public key: %s\n", public_key);
291 				}
292 			}
293 		}
294 	}
295 #endif /* CONFIG_NET_L2_VIRTUAL */
296 
297 	net_if_lock(iface);
298 	if (net_if_get_link_addr(iface)->len > 0) {
299 		PR("Link addr : %s\n",
300 		   net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
301 				      net_if_get_link_addr(iface)->len));
302 	}
303 	net_if_unlock(iface);
304 
305 	PR("MTU       : %d\n", net_if_get_mtu(iface));
306 	PR("Flags     : %s\n", iface_flags2str(iface));
307 	PR("Device    : %s (%p)\n",
308 	   net_if_get_device(iface) ? net_if_get_device(iface)->name : "<?>",
309 	   net_if_get_device(iface));
310 
311 	PR("Status    : oper=%s, admin=%s, carrier=%s\n",
312 	   net_if_oper_state2str(net_if_oper_state(iface)),
313 	   net_if_is_admin_up(iface) ? "UP" : "DOWN",
314 	   net_if_is_carrier_ok(iface) ? "ON" : "OFF");
315 
316 #if defined(CONFIG_NET_IF_LOG_LEVEL_DBG)
317 	/* Print low level details only if debug is enabled */
318 	if (IS_ENABLED(CONFIG_NET_IPV4) && net_if_flag_is_set(iface, NET_IF_IPV4)) {
319 		PR("IPv4 TTL             : %d\n", net_if_ipv4_get_ttl(iface));
320 		PR("IPv4 mcast TTL       : %d\n", net_if_ipv4_get_mcast_ttl(iface));
321 	}
322 
323 	if (IS_ENABLED(CONFIG_NET_IPV6) && net_if_flag_is_set(iface, NET_IF_IPV6)) {
324 		PR("IPv6 hop limit       : %d\n", net_if_ipv6_get_hop_limit(iface));
325 		PR("IPv6 mcast hop limit : %d\n",
326 		   net_if_ipv6_get_mcast_hop_limit(iface));
327 	}
328 #endif /* CONFIG_NET_IF_LOG_LEVEL_DBG */
329 
330 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
331 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
332 		count = 0;
333 		ret = net_mgmt(NET_REQUEST_ETHERNET_GET_PRIORITY_QUEUES_NUM,
334 				iface, &params,
335 				sizeof(struct ethernet_req_params));
336 
337 		if (!ret && params.priority_queues_num) {
338 			count = params.priority_queues_num;
339 			PR("Priority queues:\n");
340 			for (int i = 0; i < count; ++i) {
341 				params.qav_param.queue_id = i;
342 				params.qav_param.type =
343 					ETHERNET_QAV_PARAM_TYPE_STATUS;
344 				ret = net_mgmt(
345 					NET_REQUEST_ETHERNET_GET_QAV_PARAM,
346 					iface, &params,
347 					sizeof(struct ethernet_req_params));
348 
349 				PR("\t%d: Qav ", i);
350 				if (ret) {
351 					PR("not supported\n");
352 				} else {
353 					PR("%s\n",
354 						params.qav_param.enabled ?
355 						"enabled" :
356 						"disabled");
357 				}
358 			}
359 		}
360 	}
361 #endif
362 
363 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
364 	PR("Promiscuous mode : %s\n",
365 	   net_if_is_promisc(iface) ? "enabled" : "disabled");
366 #endif
367 
368 #if defined(CONFIG_NET_VLAN)
369 	if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
370 		if (net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VLAN) {
371 			uint16_t tag;
372 
373 			tag = net_eth_get_vlan_tag(iface);
374 			if (tag == NET_VLAN_TAG_UNSPEC) {
375 				PR("VLAN not configured\n");
376 			} else {
377 				PR("VLAN tag  : %d (0x%03x)\n", tag, tag);
378 			}
379 		}
380 	}
381 #endif
382 
383 #ifdef CONFIG_NET_L2_ETHERNET
384 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
385 		PR("Ethernet capabilities supported:\n");
386 		print_supported_ethernet_capabilities(sh, iface);
387 
388 #ifdef CONFIG_ETH_PHY_DRIVER
389 		const struct device *phy_dev = net_eth_get_phy(iface);
390 
391 		PR("Ethernet PHY device: %s (%p)\n", (phy_dev != NULL) ? phy_dev->name : "<none>",
392 		   phy_dev);
393 		if (phy_dev != NULL) {
394 			print_phy_link_state(sh, phy_dev);
395 		}
396 #endif /* CONFIG_ETH_PHY_DRIVER */
397 	}
398 #endif /* CONFIG_NET_L2_ETHERNET */
399 
400 #if defined(CONFIG_NET_IPV6)
401 	count = 0;
402 	ipv6 = iface->config.ip.ipv6;
403 
404 	if (!net_if_flag_is_set(iface, NET_IF_IPV6) || ipv6 == NULL) {
405 		PR("%s not %s for this interface.\n", "IPv6", "enabled");
406 		ipv6 = NULL;
407 		goto skip_ipv6;
408 	}
409 
410 	PR("IPv6 unicast addresses (max %d):\n", NET_IF_MAX_IPV6_ADDR);
411 	ARRAY_FOR_EACH(ipv6->unicast, i) {
412 		unicast = &ipv6->unicast[i];
413 
414 		if (!unicast->is_used) {
415 			continue;
416 		}
417 
418 		PR("\t%s %s %s%s%s%s\n",
419 		   net_sprint_ipv6_addr(&unicast->address.in6_addr),
420 		   addrtype2str(unicast->addr_type),
421 		   addrstate2str(unicast->addr_state),
422 		   unicast->is_infinite ? " infinite" : "",
423 		   unicast->is_mesh_local ? " meshlocal" : "",
424 		   unicast->is_temporary ? " temporary" : "");
425 		count++;
426 	}
427 
428 	if (count == 0) {
429 		PR("\t<none>\n");
430 	}
431 
432 	count = 0;
433 
434 	PR("IPv6 multicast addresses (max %d):\n", NET_IF_MAX_IPV6_MADDR);
435 	ARRAY_FOR_EACH(ipv6->mcast, i) {
436 		mcast = &ipv6->mcast[i];
437 
438 		if (!mcast->is_used) {
439 			continue;
440 		}
441 
442 		PR("\t%s%s\n", net_sprint_ipv6_addr(&mcast->address.in6_addr),
443 		   net_if_ipv6_maddr_is_joined(mcast) ? "" : "  <not joined>");
444 
445 		count++;
446 	}
447 
448 	if (count == 0) {
449 		PR("\t<none>\n");
450 	}
451 
452 #if defined(CONFIG_NET_NATIVE_IPV6)
453 	count = 0;
454 
455 	PR("IPv6 prefixes (max %d):\n", NET_IF_MAX_IPV6_PREFIX);
456 	ARRAY_FOR_EACH(ipv6->prefix, i) {
457 		prefix = &ipv6->prefix[i];
458 
459 		if (!prefix->is_used) {
460 			continue;
461 		}
462 
463 		PR("\t%s/%d%s\n",
464 		   net_sprint_ipv6_addr(&prefix->prefix),
465 		   prefix->len, prefix->is_infinite ? " infinite" : "");
466 
467 		count++;
468 	}
469 
470 	if (count == 0) {
471 		PR("\t<none>\n");
472 	}
473 
474 	router = net_if_ipv6_router_find_default(iface, NULL);
475 	if (router) {
476 		PR("IPv6 default router :\n");
477 		PR("\t%s%s\n",
478 		   net_sprint_ipv6_addr(&router->address.in6_addr),
479 		   router->is_infinite ? " infinite" : "");
480 	}
481 #endif /* CONFIG_NET_NATIVE_IPV6 */
482 
483 skip_ipv6:
484 
485 #if defined(CONFIG_NET_IPV6_PE)
486 	PR("IPv6 privacy extension   : %s (preferring %s addresses)\n",
487 	   iface->pe_enabled ? "enabled" : "disabled",
488 	   iface->pe_prefer_public ? "public" : "temporary");
489 #endif
490 
491 	if (ipv6) {
492 		PR("IPv6 hop limit           : %d\n",
493 		   ipv6->hop_limit);
494 		PR("IPv6 base reachable time : %d\n",
495 		   ipv6->base_reachable_time);
496 		PR("IPv6 reachable time      : %d\n",
497 		   ipv6->reachable_time);
498 		PR("IPv6 retransmit timer    : %d\n",
499 		   ipv6->retrans_timer);
500 	}
501 
502 #if defined(CONFIG_NET_DHCPV6)
503 	if (net_if_flag_is_set(iface, NET_IF_IPV6)) {
504 		if (iface->config.dhcpv6.state != NET_DHCPV6_DISABLED) {
505 			PR("DHCPv6 renewal time (T1) : %llu ms\n",
506 			   iface->config.dhcpv6.t1);
507 			PR("DHCPv6 rebind time (T2)  : %llu ms\n",
508 			   iface->config.dhcpv6.t2);
509 			PR("DHCPv6 expire time       : %llu ms\n",
510 			   iface->config.dhcpv6.expire);
511 			if (iface->config.dhcpv6.params.request_addr) {
512 				PR("DHCPv6 address           : %s\n",
513 				   net_sprint_ipv6_addr(&iface->config.dhcpv6.addr));
514 			}
515 
516 			if (iface->config.dhcpv6.params.request_prefix) {
517 				PR("DHCPv6 prefix            : %s\n",
518 				   net_sprint_ipv6_addr(&iface->config.dhcpv6.prefix));
519 			}
520 		}
521 
522 		PR("DHCPv6 state             : %s\n",
523 		   net_dhcpv6_state_name(iface->config.dhcpv6.state));
524 	}
525 #endif /* CONFIG_NET_DHCPV6 */
526 #endif /* CONFIG_NET_IPV6 */
527 
528 #if defined(CONFIG_NET_IPV4)
529 	/* No need to print IPv4 information for interface that does not
530 	 * support that protocol.
531 	 */
532 	if (
533 #if defined(CONFIG_NET_L2_IEEE802154)
534 		(net_if_l2(iface) == &NET_L2_GET_NAME(IEEE802154)) ||
535 #endif
536 		 0) {
537 		PR_WARNING("%s not %s for this interface.\n", "IPv4",
538 			   "supported");
539 		return;
540 	}
541 
542 	count = 0;
543 	ipv4 = iface->config.ip.ipv4;
544 
545 	if (!net_if_flag_is_set(iface, NET_IF_IPV4) || ipv4 == NULL) {
546 		PR("%s not %s for this interface.\n", "IPv4", "enabled");
547 		ipv4 = NULL;
548 		goto skip_ipv4;
549 	}
550 
551 	PR("IPv4 unicast addresses (max %d):\n", NET_IF_MAX_IPV4_ADDR);
552 	ARRAY_FOR_EACH(ipv4->unicast, i) {
553 		unicast = &ipv4->unicast[i].ipv4;
554 
555 		if (!unicast->is_used) {
556 			continue;
557 		}
558 
559 		PR("\t%s/%s %s %s%s\n",
560 		   net_sprint_ipv4_addr(&unicast->address.in_addr),
561 		   net_sprint_ipv4_addr(&ipv4->unicast[i].netmask),
562 
563 		   addrtype2str(unicast->addr_type),
564 		   addrstate2str(unicast->addr_state),
565 		   unicast->is_infinite ? " infinite" : "");
566 
567 		count++;
568 	}
569 
570 	if (count == 0) {
571 		PR("\t<none>\n");
572 	}
573 
574 	count = 0;
575 
576 	PR("IPv4 multicast addresses (max %d):\n", NET_IF_MAX_IPV4_MADDR);
577 	ARRAY_FOR_EACH(ipv4->mcast, i) {
578 		mcast = &ipv4->mcast[i];
579 
580 		if (!mcast->is_used) {
581 			continue;
582 		}
583 
584 		PR("\t%s%s\n", net_sprint_ipv4_addr(&mcast->address.in_addr),
585 		   net_if_ipv4_maddr_is_joined(mcast) ? "" : "  <not joined>");
586 
587 		count++;
588 	}
589 
590 	if (count == 0) {
591 		PR("\t<none>\n");
592 	}
593 
594 skip_ipv4:
595 
596 	if (ipv4) {
597 		PR("IPv4 gateway : %s\n",
598 		   net_sprint_ipv4_addr(&ipv4->gw));
599 	}
600 #endif /* CONFIG_NET_IPV4 */
601 
602 #if defined(CONFIG_NET_DHCPV4)
603 	if (net_if_flag_is_set(iface, NET_IF_IPV4)) {
604 		if (iface->config.dhcpv4.state != NET_DHCPV4_DISABLED) {
605 			PR("DHCPv4 lease time : %u\n",
606 			   iface->config.dhcpv4.lease_time);
607 			PR("DHCPv4 renew time : %u\n",
608 			   iface->config.dhcpv4.renewal_time);
609 			PR("DHCPv4 server     : %s\n",
610 			   net_sprint_ipv4_addr(&iface->config.dhcpv4.server_id));
611 			PR("DHCPv4 requested  : %s\n",
612 			   net_sprint_ipv4_addr(&iface->config.dhcpv4.requested_ip));
613 			PR("DHCPv4 state      : %s\n",
614 			   net_dhcpv4_state_name(iface->config.dhcpv4.state));
615 			PR("DHCPv4 attempts   : %d\n",
616 			   iface->config.dhcpv4.attempts);
617 		}
618 
619 		PR("DHCPv4 state      : %s\n",
620 		   net_dhcpv4_state_name(iface->config.dhcpv4.state));
621 	}
622 #endif /* CONFIG_NET_DHCPV4 */
623 }
624 
cmd_net_set_mac(const struct shell * sh,size_t argc,char * argv[])625 static int cmd_net_set_mac(const struct shell *sh, size_t argc, char *argv[])
626 {
627 #if !defined(CONFIG_NET_L2_ETHERNET) || !defined(CONFIG_NET_L2_ETHERNET_MGMT)
628 	PR_WARNING("Unsupported command, please enable CONFIG_NET_L2_ETHERNET "
629 		"and CONFIG_NET_L2_ETHERNET_MGMT\n");
630 	return -ENOEXEC;
631 #else
632 	struct net_if *iface;
633 	struct ethernet_req_params params;
634 	char *mac_addr = params.mac_address.addr;
635 	int idx;
636 	int ret;
637 
638 	if (argc < 3) {
639 		PR_WARNING("Missing interface index and/or MAC address\n");
640 		goto err;
641 	}
642 
643 	idx = get_iface_idx(sh, argv[1]);
644 	if (idx < 0) {
645 		goto err;
646 	}
647 
648 	iface = net_if_get_by_index(idx);
649 	if (!iface) {
650 		PR_WARNING("No such interface in index %d\n", idx);
651 		goto err;
652 	}
653 
654 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
655 		PR_WARNING("MAC address can be set only for Ethernet\n");
656 		goto err;
657 	}
658 
659 	if (!strncasecmp(argv[2], "random", 6)) {
660 		sys_rand_get(mac_addr, NET_ETH_ADDR_LEN);
661 		mac_addr[0] = (mac_addr[0] & UNICAST_MASK) | LOCAL_BIT;
662 	} else {
663 		if ((net_bytes_from_str(mac_addr, sizeof(params.mac_address), argv[2]) < 0) ||
664 		    !net_eth_is_addr_valid(&params.mac_address)) {
665 			PR_WARNING("Invalid MAC address: %s\n", argv[2]);
666 			goto err;
667 		}
668 	}
669 
670 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, iface, &params, sizeof(params));
671 	if (ret < 0) {
672 		if (ret == -EACCES) {
673 			PR_WARNING("MAC address cannot be set when interface is operational\n");
674 			goto err;
675 		}
676 		PR_WARNING("Failed to set MAC address (%d)\n", ret);
677 		goto err;
678 	}
679 
680 	PR_INFO("MAC address set to %s\n",
681 		net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
682 		net_if_get_link_addr(iface)->len));
683 
684 	return 0;
685 err:
686 	return -ENOEXEC;
687 #endif /* CONFIG_NET_L2_ETHERNET */
688 }
689 
cmd_net_iface_up(const struct shell * sh,size_t argc,char * argv[])690 static int cmd_net_iface_up(const struct shell *sh, size_t argc, char *argv[])
691 {
692 	struct net_if *iface;
693 	int idx, ret;
694 
695 	idx = get_iface_idx(sh, argv[1]);
696 	if (idx < 0) {
697 		return -ENOEXEC;
698 	}
699 
700 	iface = net_if_get_by_index(idx);
701 	if (!iface) {
702 		PR_WARNING("No such interface in index %d\n", idx);
703 		return -ENOEXEC;
704 	}
705 
706 	if (net_if_is_up(iface)) {
707 		PR_WARNING("Interface %d is already up.\n", idx);
708 		return -ENOEXEC;
709 	}
710 
711 	ret = net_if_up(iface);
712 	if (ret) {
713 		PR_WARNING("Cannot take interface %d up (%d)\n", idx, ret);
714 		return -ENOEXEC;
715 	}
716 
717 	PR("Interface %d is up\n", idx);
718 
719 	return 0;
720 }
721 
cmd_net_iface_down(const struct shell * sh,size_t argc,char * argv[])722 static int cmd_net_iface_down(const struct shell *sh, size_t argc, char *argv[])
723 {
724 	struct net_if *iface;
725 	int idx, ret;
726 
727 	idx = get_iface_idx(sh, argv[1]);
728 	if (idx < 0) {
729 		return -ENOEXEC;
730 	}
731 
732 	iface = net_if_get_by_index(idx);
733 	if (!iface) {
734 		PR_WARNING("No such interface in index %d\n", idx);
735 		return -ENOEXEC;
736 	}
737 
738 	ret = net_if_down(iface);
739 	if (ret) {
740 		PR_WARNING("Cannot take interface %d down (%d)\n", idx, ret);
741 		return -ENOEXEC;
742 	}
743 
744 	PR("Interface %d is down\n", idx);
745 
746 	return 0;
747 }
748 
cmd_net_iface(const struct shell * sh,size_t argc,char * argv[])749 static int cmd_net_iface(const struct shell *sh, size_t argc, char *argv[])
750 {
751 	struct net_if *iface = NULL;
752 	struct net_shell_user_data user_data;
753 	int idx;
754 
755 	if (argv[1]) {
756 		idx = get_iface_idx(sh, argv[1]);
757 		if (idx < 0) {
758 			return -ENOEXEC;
759 		}
760 
761 		iface = net_if_get_by_index(idx);
762 		if (!iface) {
763 			PR_WARNING("No such interface in index %d\n", idx);
764 			return -ENOEXEC;
765 		}
766 	}
767 
768 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
769 	PR("Hostname: %s\n", net_hostname_get());
770 #endif
771 	PR("Default interface: %d\n\n",
772 	   net_if_get_by_iface(net_if_get_default()));
773 
774 	user_data.sh = sh;
775 	user_data.user_data = iface;
776 
777 	net_if_foreach(iface_cb, &user_data);
778 
779 	return 0;
780 }
781 
cmd_net_default_iface(const struct shell * sh,size_t argc,char * argv[])782 static int cmd_net_default_iface(const struct shell *sh, size_t argc, char *argv[])
783 {
784 	struct net_if *iface = NULL;
785 	int idx;
786 
787 	if (argc < 2) {
788 		iface = net_if_get_default();
789 		if (!iface) {
790 			PR_WARNING("No default interface\n");
791 			return -ENOEXEC;
792 		}
793 
794 		idx = net_if_get_by_iface(iface);
795 		PR("Default interface: %d\n", idx);
796 	} else {
797 		int new_idx;
798 
799 		idx = get_iface_idx(sh, argv[1]);
800 		if (idx < 0) {
801 			return -ENOEXEC;
802 		}
803 
804 		net_if_set_default(net_if_get_by_index(idx));
805 
806 		new_idx = net_if_get_by_iface(net_if_get_default());
807 		if (new_idx != idx) {
808 			PR_WARNING("Failed to set default interface to %d\n", idx);
809 			return -ENOEXEC;
810 		}
811 
812 		PR("Default interface: %d\n", new_idx);
813 	}
814 
815 	return 0;
816 }
817 
818 #if defined(CONFIG_ETH_PHY_DRIVER)
cmd_net_link_speed(const struct shell * sh,size_t argc,char * argv[])819 static int cmd_net_link_speed(const struct shell *sh, size_t argc, char *argv[])
820 {
821 	int idx = get_iface_idx(sh, argv[1]);
822 	const struct device *phy_dev;
823 	bool half_duplex = false;
824 	uint16_t user_input_spd;
825 	struct net_if *iface;
826 	uint16_t speed = 0U;
827 	uint16_t flags = 0U;
828 	int ret;
829 
830 	if (argc < 3) {
831 		PR_WARNING("Usage: net iface set_link <index> "
832 			   "<Speed:10/100/1000/2500/5000> [Duplex]:h/f>\n");
833 		return -ENOEXEC;
834 	}
835 
836 	iface = net_if_get_by_index(idx);
837 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
838 		PR_WARNING("Interface %d is not Ethernet type\n", idx);
839 		return -EINVAL;
840 	}
841 
842 	phy_dev = net_eth_get_phy(iface);
843 	if (!phy_dev) {
844 		PR_WARNING("No PHY device found for interface %d\n", idx);
845 		return -ENOEXEC;
846 	}
847 
848 	for (int k = 2; k < argc; k++) {
849 		if ((k + 1 < argc) && (argv[k+1][0] == 'h')) {
850 			half_duplex = true;
851 		} else {
852 			half_duplex = false;
853 		}
854 
855 		user_input_spd = shell_strtoul(argv[k], 10, &ret);
856 		switch (user_input_spd) {
857 		case 0:
858 			if (strcmp(argv[k], "no-autoneg") == 0) {
859 				flags |= PHY_FLAG_AUTO_NEGOTIATION_DISABLED;
860 				continue;
861 			}
862 			break;
863 		case 10:
864 			speed |= half_duplex ? LINK_HALF_10BASE : LINK_FULL_10BASE;
865 			break;
866 		case 100:
867 			speed |= half_duplex ? LINK_HALF_100BASE : LINK_FULL_100BASE;
868 			break;
869 		case 1000:
870 			speed |= half_duplex ? LINK_HALF_1000BASE :  LINK_FULL_1000BASE;
871 			break;
872 		case 2500:
873 			if (half_duplex) {
874 				PR_WARNING("2500BASE half-duplex not supported\n");
875 				return -ENOTSUP;
876 			}
877 			speed |= LINK_FULL_2500BASE;
878 			break;
879 		case 5000:
880 			if (half_duplex) {
881 				PR_WARNING("5000BASE half-duplex not supported\n");
882 				return -ENOTSUP;
883 			}
884 			speed |= LINK_FULL_5000BASE;
885 			break;
886 		default:
887 			PR_WARNING("Unsupported speed %d\n", user_input_spd);
888 			return -ENOTSUP;
889 		}
890 	}
891 
892 	if (speed != 0U) {
893 		return phy_configure_link(phy_dev, speed, flags);
894 	}
895 	PR_WARNING("No speed specified\n");
896 	return -ENOEXEC;
897 }
898 #endif /* CONFIG_ETH_PHY_DRIVER */
899 
900 #if defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
901 
902 #include "iface_dynamic.h"
903 
904 #endif /* CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
905 
906 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_iface,
907 	SHELL_CMD(up, IFACE_DYN_CMD,
908 		  "'net iface up <index>' takes network interface up.",
909 		  cmd_net_iface_up),
910 	SHELL_CMD(down, IFACE_DYN_CMD,
911 		  "'net iface down <index>' takes network interface "
912 		  "down.",
913 		  cmd_net_iface_down),
914 	SHELL_CMD(show, IFACE_DYN_CMD,
915 		  "'net iface <index>' shows network interface "
916 		  "information.",
917 		  cmd_net_iface),
918 	SHELL_CMD(set_mac, IFACE_DYN_CMD,
919 		  "'net iface set_mac <index> <MAC>' sets MAC address for the network interface.",
920 		  cmd_net_set_mac),
921 	SHELL_CMD(default, IFACE_DYN_CMD,
922 		  "'net iface default [<index>]' displays or sets the default network interface.",
923 		  cmd_net_default_iface),
924 #if defined(CONFIG_ETH_PHY_DRIVER)
925 	SHELL_CMD(set_link, IFACE_DYN_CMD,
926 		  "'net iface set_link <index> <Speed 10/100/1000/2500/5000> "
927 		  "<Duplex[optional]:h/f>'"
928 		  " sets link speed for the network interface.",
929 		  cmd_net_link_speed),
930 #endif /* CONFIG_ETH_PHY_DRIVER */
931 	SHELL_SUBCMD_SET_END
932 );
933 
934 SHELL_SUBCMD_ADD((net), iface, &net_cmd_iface,
935 		 "Print information about network interfaces.",
936 		 cmd_net_iface, 1, 1);
937