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