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, ¶ms,
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, ¶ms,
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(¶ms.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, ¶ms, 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