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 #if defined(CONFIG_NET_L2_ETHERNET)
12 #include <zephyr/net/ethernet.h>
13 #endif
14 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
15 #include <zephyr/net/ethernet_mgmt.h>
16 #endif
17 #if defined(CONFIG_NET_L2_VIRTUAL)
18 #include <zephyr/net/virtual.h>
19 #endif
20 
21 #include "net_shell_private.h"
22 
23 #if defined(CONFIG_NET_L2_ETHERNET) && defined(CONFIG_NET_NATIVE)
24 struct ethernet_capabilities {
25 	enum ethernet_hw_caps capability;
26 	const char * const description;
27 };
28 
29 #define EC(cap, desc) { .capability = cap, .description = desc }
30 
31 static struct ethernet_capabilities eth_hw_caps[] = {
32 	EC(ETHERNET_HW_TX_CHKSUM_OFFLOAD, "TX checksum offload"),
33 	EC(ETHERNET_HW_RX_CHKSUM_OFFLOAD, "RX checksum offload"),
34 	EC(ETHERNET_HW_VLAN,              "Virtual LAN"),
35 	EC(ETHERNET_HW_VLAN_TAG_STRIP,    "VLAN Tag stripping"),
36 	EC(ETHERNET_AUTO_NEGOTIATION_SET, "Auto negotiation"),
37 	EC(ETHERNET_LINK_10BASE_T,        "10 Mbits"),
38 	EC(ETHERNET_LINK_100BASE_T,       "100 Mbits"),
39 	EC(ETHERNET_LINK_1000BASE_T,      "1 Gbits"),
40 	EC(ETHERNET_DUPLEX_SET,           "Half/full duplex"),
41 	EC(ETHERNET_PTP,                  "IEEE 802.1AS gPTP clock"),
42 	EC(ETHERNET_QAV,                  "IEEE 802.1Qav (credit shaping)"),
43 	EC(ETHERNET_QBV,                  "IEEE 802.1Qbv (scheduled traffic)"),
44 	EC(ETHERNET_QBU,                  "IEEE 802.1Qbu (frame preemption)"),
45 	EC(ETHERNET_TXTIME,               "TXTIME"),
46 	EC(ETHERNET_PROMISC_MODE,         "Promiscuous mode"),
47 	EC(ETHERNET_PRIORITY_QUEUES,      "Priority queues"),
48 	EC(ETHERNET_HW_FILTERING,         "MAC address filtering"),
49 	EC(ETHERNET_DSA_SLAVE_PORT,       "DSA slave port"),
50 	EC(ETHERNET_DSA_MASTER_PORT,      "DSA master port"),
51 };
52 
print_supported_ethernet_capabilities(const struct shell * sh,struct net_if * iface)53 static void print_supported_ethernet_capabilities(
54 	const struct shell *sh, struct net_if *iface)
55 {
56 	enum ethernet_hw_caps caps = net_eth_get_hw_capabilities(iface);
57 	int i;
58 
59 	for (i = 0; i < ARRAY_SIZE(eth_hw_caps); i++) {
60 		if (caps & eth_hw_caps[i].capability) {
61 			PR("\t%s\n", eth_hw_caps[i].description);
62 		}
63 	}
64 }
65 #endif /* CONFIG_NET_L2_ETHERNET */
66 
67 #if defined(CONFIG_NET_NATIVE)
iface_flags2str(struct net_if * iface)68 static const char *iface_flags2str(struct net_if *iface)
69 {
70 	static char str[sizeof("POINTOPOINT") + sizeof("PROMISC") +
71 			sizeof("NO_AUTO_START") + sizeof("SUSPENDED") +
72 			sizeof("MCAST_FORWARD") + sizeof("IPv4") +
73 			sizeof("IPv6") + sizeof("NO_ND") + sizeof("NO_MLD")];
74 	int pos = 0;
75 
76 	if (net_if_flag_is_set(iface, NET_IF_POINTOPOINT)) {
77 		pos += snprintk(str + pos, sizeof(str) - pos,
78 				"POINTOPOINT,");
79 	}
80 
81 	if (net_if_flag_is_set(iface, NET_IF_PROMISC)) {
82 		pos += snprintk(str + pos, sizeof(str) - pos,
83 				"PROMISC,");
84 	}
85 
86 	if (net_if_flag_is_set(iface, NET_IF_NO_AUTO_START)) {
87 		pos += snprintk(str + pos, sizeof(str) - pos,
88 				"NO_AUTO_START,");
89 	} else {
90 		pos += snprintk(str + pos, sizeof(str) - pos,
91 				"AUTO_START,");
92 	}
93 
94 	if (net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) {
95 		pos += snprintk(str + pos, sizeof(str) - pos,
96 				"MCAST_FORWARD,");
97 	}
98 
99 	if (net_if_flag_is_set(iface, NET_IF_IPV4)) {
100 		pos += snprintk(str + pos, sizeof(str) - pos,
101 				"IPv4,");
102 	}
103 
104 	if (net_if_flag_is_set(iface, NET_IF_IPV6)) {
105 		pos += snprintk(str + pos, sizeof(str) - pos,
106 				"IPv6,");
107 	}
108 
109 	if (net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) {
110 		pos += snprintk(str + pos, sizeof(str) - pos,
111 				"NO_ND,");
112 	}
113 
114 	if (net_if_flag_is_set(iface, NET_IF_IPV6_NO_MLD)) {
115 		pos += snprintk(str + pos, sizeof(str) - pos,
116 				"NO_MLD,");
117 	}
118 
119 	/* get rid of last ',' character */
120 	str[pos - 1] = '\0';
121 
122 	return str;
123 }
124 #endif
125 
iface_cb(struct net_if * iface,void * user_data)126 static void iface_cb(struct net_if *iface, void *user_data)
127 {
128 #if defined(CONFIG_NET_NATIVE)
129 	struct net_shell_user_data *data = user_data;
130 	const struct shell *sh = data->sh;
131 
132 #if defined(CONFIG_NET_IPV6)
133 	struct net_if_ipv6_prefix *prefix;
134 	struct net_if_router *router;
135 	struct net_if_ipv6 *ipv6;
136 #endif
137 #if defined(CONFIG_NET_IPV4)
138 	struct net_if_ipv4 *ipv4;
139 #endif
140 #if defined(CONFIG_NET_VLAN)
141 	struct ethernet_context *eth_ctx;
142 #endif
143 #if defined(CONFIG_NET_IP)
144 	struct net_if_addr *unicast;
145 	struct net_if_mcast_addr *mcast;
146 #endif
147 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
148 	struct ethernet_req_params params;
149 	int ret;
150 #endif
151 	const char *extra;
152 #if defined(CONFIG_NET_IP)
153 	int i, count;
154 #endif
155 
156 	if (data->user_data && data->user_data != iface) {
157 		return;
158 	}
159 
160 #if defined(CONFIG_NET_INTERFACE_NAME)
161 	char ifname[CONFIG_NET_INTERFACE_NAME_LEN + 1] = { 0 };
162 	int ret_name;
163 
164 	ret_name = net_if_get_name(iface, ifname, sizeof(ifname) - 1);
165 	if (ret_name < 1 || ifname[0] == '\0') {
166 		snprintk(ifname, sizeof(ifname), "?");
167 	}
168 
169 	PR("\nInterface %s (%p) (%s) [%d]\n", ifname, iface, iface2str(iface, &extra),
170 	   net_if_get_by_iface(iface));
171 #else
172 	PR("\nInterface %p (%s) [%d]\n", iface, iface2str(iface, &extra),
173 	   net_if_get_by_iface(iface));
174 #endif
175 	PR("===========================%s\n", extra);
176 
177 	if (!net_if_is_up(iface)) {
178 		PR_INFO("Interface is down.\n");
179 
180 		/* Show detailed information only when user asks information
181 		 * about one specific network interface.
182 		 */
183 		if (data->user_data == NULL) {
184 			return;
185 		}
186 	}
187 
188 #ifdef CONFIG_NET_POWER_MANAGEMENT
189 	if (net_if_is_suspended(iface)) {
190 		PR_INFO("Interface is suspended, thus not able to tx/rx.\n");
191 	}
192 #endif
193 
194 #if defined(CONFIG_NET_L2_VIRTUAL)
195 	if (!sys_slist_is_empty(&iface->config.virtual_interfaces)) {
196 		struct virtual_interface_context *ctx, *tmp;
197 
198 		PR("Virtual interfaces attached to this : ");
199 		SYS_SLIST_FOR_EACH_CONTAINER_SAFE(
200 					&iface->config.virtual_interfaces,
201 					ctx, tmp, node) {
202 			if (ctx->virtual_iface == iface) {
203 				continue;
204 			}
205 
206 			PR("%d ", net_if_get_by_iface(ctx->virtual_iface));
207 		}
208 
209 		PR("\n");
210 	}
211 
212 	if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL)) {
213 		struct net_if *orig_iface;
214 		char *name, buf[CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN];
215 
216 		name = net_virtual_get_name(iface, buf, sizeof(buf));
217 		if (!(name && name[0])) {
218 			name = "<unknown>";
219 		}
220 
221 		PR("Virtual name : %s\n", name);
222 
223 		orig_iface = net_virtual_get_iface(iface);
224 		if (orig_iface == NULL) {
225 			PR("No attached network interface.\n");
226 		} else {
227 			PR("Attached  : %d (%s / %p)\n",
228 			   net_if_get_by_iface(orig_iface),
229 			   iface2str(orig_iface, NULL),
230 			   orig_iface);
231 		}
232 	}
233 #endif /* CONFIG_NET_L2_VIRTUAL */
234 
235 	net_if_lock(iface);
236 	if (net_if_get_link_addr(iface) &&
237 	    net_if_get_link_addr(iface)->addr) {
238 		PR("Link addr : %s\n",
239 		   net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
240 				      net_if_get_link_addr(iface)->len));
241 	}
242 	net_if_unlock(iface);
243 
244 	PR("MTU       : %d\n", net_if_get_mtu(iface));
245 	PR("Flags     : %s\n", iface_flags2str(iface));
246 	PR("Device    : %s (%p)\n",
247 	   net_if_get_device(iface) ? net_if_get_device(iface)->name : "<?>",
248 	   net_if_get_device(iface));
249 
250 #if defined(CONFIG_NET_L2_ETHERNET_MGMT)
251 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
252 		count = 0;
253 		ret = net_mgmt(NET_REQUEST_ETHERNET_GET_PRIORITY_QUEUES_NUM,
254 				iface, &params,
255 				sizeof(struct ethernet_req_params));
256 
257 		if (!ret && params.priority_queues_num) {
258 			count = params.priority_queues_num;
259 			PR("Priority queues:\n");
260 			for (i = 0; i < count; ++i) {
261 				params.qav_param.queue_id = i;
262 				params.qav_param.type =
263 					ETHERNET_QAV_PARAM_TYPE_STATUS;
264 				ret = net_mgmt(
265 					NET_REQUEST_ETHERNET_GET_QAV_PARAM,
266 					iface, &params,
267 					sizeof(struct ethernet_req_params));
268 
269 				PR("\t%d: Qav ", i);
270 				if (ret) {
271 					PR("not supported\n");
272 				} else {
273 					PR("%s\n",
274 						params.qav_param.enabled ?
275 						"enabled" :
276 						"disabled");
277 				}
278 			}
279 		}
280 	}
281 #endif
282 
283 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
284 	PR("Promiscuous mode : %s\n",
285 	   net_if_is_promisc(iface) ? "enabled" : "disabled");
286 #endif
287 
288 #if defined(CONFIG_NET_VLAN)
289 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
290 		eth_ctx = net_if_l2_data(iface);
291 
292 		if (eth_ctx->vlan_enabled) {
293 			for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
294 				if (eth_ctx->vlan[i].iface != iface ||
295 				    eth_ctx->vlan[i].tag ==
296 							NET_VLAN_TAG_UNSPEC) {
297 					continue;
298 				}
299 
300 				PR("VLAN tag  : %d (0x%x)\n",
301 				   eth_ctx->vlan[i].tag,
302 				   eth_ctx->vlan[i].tag);
303 			}
304 		} else {
305 			PR("VLAN not enabled\n");
306 		}
307 	}
308 #endif
309 
310 #ifdef CONFIG_NET_L2_ETHERNET
311 	if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
312 		PR("Ethernet capabilities supported:\n");
313 		print_supported_ethernet_capabilities(sh, iface);
314 	}
315 #endif /* CONFIG_NET_L2_ETHERNET */
316 
317 #if defined(CONFIG_NET_IPV6)
318 	count = 0;
319 
320 	if (!net_if_flag_is_set(iface, NET_IF_IPV6)) {
321 		PR("%s not %s for this interface.\n", "IPv6", "enabled");
322 		ipv6 = NULL;
323 		goto skip_ipv6;
324 	}
325 
326 	ipv6 = iface->config.ip.ipv6;
327 
328 	PR("IPv6 unicast addresses (max %d):\n", NET_IF_MAX_IPV6_ADDR);
329 	for (i = 0; ipv6 && i < NET_IF_MAX_IPV6_ADDR; i++) {
330 		unicast = &ipv6->unicast[i];
331 
332 		if (!unicast->is_used) {
333 			continue;
334 		}
335 
336 		PR("\t%s %s %s%s%s\n",
337 		   net_sprint_ipv6_addr(&unicast->address.in6_addr),
338 		   addrtype2str(unicast->addr_type),
339 		   addrstate2str(unicast->addr_state),
340 		   unicast->is_infinite ? " infinite" : "",
341 		   unicast->is_mesh_local ? " meshlocal" : "");
342 		count++;
343 	}
344 
345 	if (count == 0) {
346 		PR("\t<none>\n");
347 	}
348 
349 	count = 0;
350 
351 	PR("IPv6 multicast addresses (max %d):\n", NET_IF_MAX_IPV6_MADDR);
352 	for (i = 0; ipv6 && i < NET_IF_MAX_IPV6_MADDR; i++) {
353 		mcast = &ipv6->mcast[i];
354 
355 		if (!mcast->is_used) {
356 			continue;
357 		}
358 
359 		PR("\t%s\n", net_sprint_ipv6_addr(&mcast->address.in6_addr));
360 
361 		count++;
362 	}
363 
364 	if (count == 0) {
365 		PR("\t<none>\n");
366 	}
367 
368 	count = 0;
369 
370 	PR("IPv6 prefixes (max %d):\n", NET_IF_MAX_IPV6_PREFIX);
371 	for (i = 0; ipv6 && i < NET_IF_MAX_IPV6_PREFIX; i++) {
372 		prefix = &ipv6->prefix[i];
373 
374 		if (!prefix->is_used) {
375 			continue;
376 		}
377 
378 		PR("\t%s/%d%s\n",
379 		   net_sprint_ipv6_addr(&prefix->prefix),
380 		   prefix->len, prefix->is_infinite ? " infinite" : "");
381 
382 		count++;
383 	}
384 
385 	if (count == 0) {
386 		PR("\t<none>\n");
387 	}
388 
389 	router = net_if_ipv6_router_find_default(iface, NULL);
390 	if (router) {
391 		PR("IPv6 default router :\n");
392 		PR("\t%s%s\n",
393 		   net_sprint_ipv6_addr(&router->address.in6_addr),
394 		   router->is_infinite ? " infinite" : "");
395 	}
396 
397 skip_ipv6:
398 
399 	if (ipv6) {
400 		PR("IPv6 hop limit           : %d\n",
401 		   ipv6->hop_limit);
402 		PR("IPv6 base reachable time : %d\n",
403 		   ipv6->base_reachable_time);
404 		PR("IPv6 reachable time      : %d\n",
405 		   ipv6->reachable_time);
406 		PR("IPv6 retransmit timer    : %d\n",
407 		   ipv6->retrans_timer);
408 	}
409 #endif /* CONFIG_NET_IPV6 */
410 
411 #if defined(CONFIG_NET_IPV4)
412 	/* No need to print IPv4 information for interface that does not
413 	 * support that protocol.
414 	 */
415 	if (
416 #if defined(CONFIG_NET_L2_IEEE802154)
417 		(net_if_l2(iface) == &NET_L2_GET_NAME(IEEE802154)) ||
418 #endif
419 #if defined(CONFIG_NET_L2_BT)
420 		 (net_if_l2(iface) == &NET_L2_GET_NAME(BLUETOOTH)) ||
421 #endif
422 		 0) {
423 		PR_WARNING("%s not %s for this interface.\n", "IPv4",
424 			   "supported");
425 		return;
426 	}
427 
428 	count = 0;
429 
430 	if (!net_if_flag_is_set(iface, NET_IF_IPV4)) {
431 		PR("%s not %s for this interface.\n", "IPv4", "enabled");
432 		ipv4 = NULL;
433 		goto skip_ipv4;
434 	}
435 
436 	ipv4 = iface->config.ip.ipv4;
437 
438 	PR("IPv4 unicast addresses (max %d):\n", NET_IF_MAX_IPV4_ADDR);
439 	for (i = 0; ipv4 && i < NET_IF_MAX_IPV4_ADDR; i++) {
440 		unicast = &ipv4->unicast[i];
441 
442 		if (!unicast->is_used) {
443 			continue;
444 		}
445 
446 		PR("\t%s %s %s%s\n",
447 		   net_sprint_ipv4_addr(&unicast->address.in_addr),
448 		   addrtype2str(unicast->addr_type),
449 		   addrstate2str(unicast->addr_state),
450 		   unicast->is_infinite ? " infinite" : "");
451 
452 		count++;
453 	}
454 
455 	if (count == 0) {
456 		PR("\t<none>\n");
457 	}
458 
459 	count = 0;
460 
461 	PR("IPv4 multicast addresses (max %d):\n", NET_IF_MAX_IPV4_MADDR);
462 	for (i = 0; ipv4 && i < NET_IF_MAX_IPV4_MADDR; i++) {
463 		mcast = &ipv4->mcast[i];
464 
465 		if (!mcast->is_used) {
466 			continue;
467 		}
468 
469 		PR("\t%s\n", net_sprint_ipv4_addr(&mcast->address.in_addr));
470 
471 		count++;
472 	}
473 
474 	if (count == 0) {
475 		PR("\t<none>\n");
476 	}
477 
478 skip_ipv4:
479 
480 	if (ipv4) {
481 		PR("IPv4 gateway : %s\n",
482 		   net_sprint_ipv4_addr(&ipv4->gw));
483 		PR("IPv4 netmask : %s\n",
484 		   net_sprint_ipv4_addr(&ipv4->netmask));
485 	}
486 #endif /* CONFIG_NET_IPV4 */
487 
488 #if defined(CONFIG_NET_DHCPV4)
489 	PR("DHCPv4 lease time : %u\n",
490 	   iface->config.dhcpv4.lease_time);
491 	PR("DHCPv4 renew time : %u\n",
492 	   iface->config.dhcpv4.renewal_time);
493 	PR("DHCPv4 server     : %s\n",
494 	   net_sprint_ipv4_addr(&iface->config.dhcpv4.server_id));
495 	PR("DHCPv4 requested  : %s\n",
496 	   net_sprint_ipv4_addr(&iface->config.dhcpv4.requested_ip));
497 	PR("DHCPv4 state      : %s\n",
498 	   net_dhcpv4_state_name(iface->config.dhcpv4.state));
499 	PR("DHCPv4 attempts   : %d\n",
500 	   iface->config.dhcpv4.attempts);
501 #endif /* CONFIG_NET_DHCPV4 */
502 
503 #else
504 	ARG_UNUSED(iface);
505 	ARG_UNUSED(user_data);
506 
507 #endif /* CONFIG_NET_NATIVE */
508 }
509 
cmd_net_set_mac(const struct shell * sh,size_t argc,char * argv[])510 static int cmd_net_set_mac(const struct shell *sh, size_t argc, char *argv[])
511 {
512 #if !defined(CONFIG_NET_L2_ETHERNET) || !defined(CONFIG_NET_L2_ETHERNET_MGMT)
513 	PR_WARNING("Unsupported command, please enable CONFIG_NET_L2_ETHERNET "
514 		"and CONFIG_NET_L2_ETHERNET_MGMT\n");
515 	return -ENOEXEC;
516 #else
517 	struct net_if *iface;
518 	struct ethernet_req_params params;
519 	char *mac_addr = params.mac_address.addr;
520 	int idx;
521 	int ret;
522 
523 	if (argc < 3) {
524 		PR_WARNING("Missing interface index and/or MAC address\n");
525 		goto err;
526 	}
527 
528 	idx = get_iface_idx(sh, argv[1]);
529 	if (idx < 0) {
530 		goto err;
531 	}
532 
533 	iface = net_if_get_by_index(idx);
534 	if (!iface) {
535 		PR_WARNING("No such interface in index %d\n", idx);
536 		goto err;
537 	}
538 
539 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
540 		PR_WARNING("MAC address can be set only for Ethernet\n");
541 		goto err;
542 	}
543 
544 	if ((net_bytes_from_str(mac_addr, sizeof(params.mac_address), argv[2]) < 0) ||
545 	    !net_eth_is_addr_valid(&params.mac_address)) {
546 		PR_WARNING("Invalid MAC address: %s\n", argv[2]);
547 		goto err;
548 	}
549 
550 	ret = net_mgmt(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, iface, &params, sizeof(params));
551 	if (ret < 0) {
552 		if (ret == -EACCES) {
553 			PR_WARNING("MAC address cannot be set when interface is operational\n");
554 			goto err;
555 		}
556 		PR_WARNING("Failed to set MAC address (%d)\n", ret);
557 		goto err;
558 	}
559 
560 	PR_INFO("MAC address set to %s\n",
561 		net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
562 		net_if_get_link_addr(iface)->len));
563 
564 	return 0;
565 err:
566 	return -ENOEXEC;
567 #endif /* CONFIG_NET_L2_ETHERNET */
568 }
569 
cmd_net_iface_up(const struct shell * sh,size_t argc,char * argv[])570 static int cmd_net_iface_up(const struct shell *sh, size_t argc, char *argv[])
571 {
572 	struct net_if *iface;
573 	int idx, ret;
574 
575 	idx = get_iface_idx(sh, argv[1]);
576 	if (idx < 0) {
577 		return -ENOEXEC;
578 	}
579 
580 	iface = net_if_get_by_index(idx);
581 	if (!iface) {
582 		PR_WARNING("No such interface in index %d\n", idx);
583 		return -ENOEXEC;
584 	}
585 
586 	if (net_if_is_up(iface)) {
587 		PR_WARNING("Interface %d is already up.\n", idx);
588 		return -ENOEXEC;
589 	}
590 
591 	ret = net_if_up(iface);
592 	if (ret) {
593 		PR_WARNING("Cannot take interface %d up (%d)\n", idx, ret);
594 		return -ENOEXEC;
595 	}
596 
597 	PR("Interface %d is up\n", idx);
598 
599 	return 0;
600 }
601 
cmd_net_iface_down(const struct shell * sh,size_t argc,char * argv[])602 static int cmd_net_iface_down(const struct shell *sh, size_t argc, char *argv[])
603 {
604 	struct net_if *iface;
605 	int idx, ret;
606 
607 	idx = get_iface_idx(sh, argv[1]);
608 	if (idx < 0) {
609 		return -ENOEXEC;
610 	}
611 
612 	iface = net_if_get_by_index(idx);
613 	if (!iface) {
614 		PR_WARNING("No such interface in index %d\n", idx);
615 		return -ENOEXEC;
616 	}
617 
618 	ret = net_if_down(iface);
619 	if (ret) {
620 		PR_WARNING("Cannot take interface %d down (%d)\n", idx, ret);
621 		return -ENOEXEC;
622 	}
623 
624 	PR("Interface %d is down\n", idx);
625 
626 	return 0;
627 }
628 
cmd_net_iface(const struct shell * sh,size_t argc,char * argv[])629 static int cmd_net_iface(const struct shell *sh, size_t argc, char *argv[])
630 {
631 	struct net_if *iface = NULL;
632 	struct net_shell_user_data user_data;
633 	int idx;
634 
635 	if (argv[1]) {
636 		idx = get_iface_idx(sh, argv[1]);
637 		if (idx < 0) {
638 			return -ENOEXEC;
639 		}
640 
641 		iface = net_if_get_by_index(idx);
642 		if (!iface) {
643 			PR_WARNING("No such interface in index %d\n", idx);
644 			return -ENOEXEC;
645 		}
646 	}
647 
648 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
649 	PR("Hostname: %s\n\n", net_hostname_get());
650 #endif
651 
652 	user_data.sh = sh;
653 	user_data.user_data = iface;
654 
655 	net_if_foreach(iface_cb, &user_data);
656 
657 	return 0;
658 }
659 
660 #if defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
661 
662 #include "iface_dynamic.h"
663 
664 #endif /* CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
665 
666 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_iface,
667 	SHELL_CMD(up, IFACE_DYN_CMD,
668 		  "'net iface up <index>' takes network interface up.",
669 		  cmd_net_iface_up),
670 	SHELL_CMD(down, IFACE_DYN_CMD,
671 		  "'net iface down <index>' takes network interface "
672 		  "down.",
673 		  cmd_net_iface_down),
674 	SHELL_CMD(show, IFACE_DYN_CMD,
675 		  "'net iface <index>' shows network interface "
676 		  "information.",
677 		  cmd_net_iface),
678 	SHELL_CMD(set_mac, IFACE_DYN_CMD,
679 		  "'net iface set_mac <index> <MAC>' sets MAC address for the network interface.",
680 		  cmd_net_set_mac),
681 	SHELL_SUBCMD_SET_END
682 );
683 
684 SHELL_SUBCMD_ADD((net), iface, &net_cmd_iface,
685 		 "Print information about network interfaces.",
686 		 cmd_net_iface, 1, 1);
687