1 /* vi: set sw=4 ts=4: */
3 * stolen from net-tools-1.59 and stripped down for busybox by
4 * Erik Andersen <andersen@codepoet.org>
6 * Heavily modified by Manuel Novoa III Mar 12, 2001
8 * Added print_bytes_scaled function to reduce code size.
9 * Added some (potentially) missing defines.
10 * Improved display support for -a and for a named interface.
12 * -----------------------------------------------------------
14 * ifconfig This file contains an implementation of the command
15 * that either displays or sets the characteristics of
16 * one or more of the system's networking interfaces.
19 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
20 * and others. Copyright 1993 MicroWalt Corporation
22 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
24 * Patched to support 'add' and 'del' keywords for INET(4) addresses
25 * by Mrs. Brisby <mrs.brisby@nimh.org>
27 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
28 * - gettext instead of catgets for i18n
29 * 10/1998 - Andi Kleen. Use interface list primitives.
30 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
31 * (default AF was wrong)
35 #include <net/if_arp.h>
36 #include "inet_common.h"
39 #ifdef CONFIG_FEATURE_IPV6
40 # define HAVE_AFINET6 1
45 #define _PATH_PROCNET_DEV "/proc/net/dev"
46 #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
52 * This is in linux/include/net/ipv6.h.
56 struct in6_addr ifr6_addr;
57 uint32_t ifr6_prefixlen;
58 unsigned int ifr6_ifindex;
63 #endif /* HAVE_AFINET6 */
65 /* Defines for glibc2.0 users. */
67 #define SIOCSIFTXQLEN 0x8943
68 #define SIOCGIFTXQLEN 0x8942
71 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
73 #define ifr_qlen ifr_ifru.ifru_mtu
76 #ifndef HAVE_TXQUEUELEN
77 #define HAVE_TXQUEUELEN 1
81 #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
84 /* Display an Internet socket address. */
85 static char *INET_sprint(struct sockaddr *sap, int numeric)
87 static char buff[128];
89 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
90 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
92 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
93 numeric, 0xffffff00) != 0)
99 static int INET_getsock(char *bufp, struct sockaddr *sap)
101 char *sp = bufp, *bp;
104 struct sockaddr_in *sock_in;
106 sock_in = (struct sockaddr_in *) sap;
107 sock_in->sin_family = AF_INET;
108 sock_in->sin_port = 0;
112 for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
115 if ((unsigned)(*sp - 'A') <= 5)
116 bp[i] |= (int) (*sp - ('A' - 10));
117 else if (isdigit(*sp))
118 bp[i] |= (int) (*sp - '0');
126 if ((unsigned)(*sp - 'A') <= 5)
127 bp[i] |= (int) (*sp - ('A' - 10));
128 else if (isdigit(*sp))
129 bp[i] |= (int) (*sp - '0');
135 sock_in->sin_addr.s_addr = htonl(val);
140 static int INET_input(int type, char *bufp, struct sockaddr *sap)
144 return (INET_getsock(bufp, sap));
146 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
148 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
152 static struct aftype inet_aftype = {
154 .title = "DARPA Internet",
157 .sprint = INET_sprint,
164 /* Display an Internet socket address. */
165 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
166 static char *INET6_sprint(struct sockaddr *sap, int numeric)
168 static char buff[128];
170 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
171 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
172 if (INET6_rresolve(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric))
173 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
177 static int INET6_getsock(char *bufp, struct sockaddr *sap)
179 struct sockaddr_in6 *sin6;
181 sin6 = (struct sockaddr_in6 *) sap;
182 sin6->sin6_family = AF_INET6;
185 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
191 static int INET6_input(int type, char *bufp, struct sockaddr *sap)
195 return (INET6_getsock(bufp, sap));
197 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
201 static struct aftype inet6_aftype = {
205 .alen = sizeof(struct in6_addr),
206 .sprint = INET6_sprint,
207 .input = INET6_input,
211 #endif /* HAVE_AFINET6 */
213 /* Display an UNSPEC address. */
214 static char *UNSPEC_print(unsigned char *ptr)
216 static char buff[sizeof(struct sockaddr) * 3 + 1];
221 for (i = 0; i < sizeof(struct sockaddr); i++) {
222 /* careful -- not every libc's sprintf returns # bytes written */
223 sprintf(pos, "%02X-", (*ptr++ & 0377));
226 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
231 /* Display an UNSPEC socket address. */
232 static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
236 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
237 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
238 return UNSPEC_print((unsigned char *)sap->sa_data);
241 static struct aftype unspec_aftype = {
242 "unspec", "UNSPEC", AF_UNSPEC, 0,
243 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
247 static struct aftype * const aftypes[] = {
256 /* Check our protocol family table for this family. */
257 struct aftype *get_aftype(const char *name)
259 struct aftype * const *afp;
262 while (*afp != NULL) {
263 if (!strcmp((*afp)->name, name))
270 /* Check our protocol family table for this family. */
271 static struct aftype *get_afntype(int af)
273 struct aftype * const *afp;
276 while (*afp != NULL) {
277 if ((*afp)->af == af)
284 /* Check our protocol family table for this family and return its socket */
285 static int get_socket_for_af(int af)
287 struct aftype * const *afp;
290 while (*afp != NULL) {
291 if ((*afp)->af == af)
298 struct user_net_device_stats {
299 unsigned long long rx_packets; /* total packets received */
300 unsigned long long tx_packets; /* total packets transmitted */
301 unsigned long long rx_bytes; /* total bytes received */
302 unsigned long long tx_bytes; /* total bytes transmitted */
303 unsigned long rx_errors; /* bad packets received */
304 unsigned long tx_errors; /* packet transmit problems */
305 unsigned long rx_dropped; /* no space in linux buffers */
306 unsigned long tx_dropped; /* no space available in linux */
307 unsigned long rx_multicast; /* multicast packets received */
308 unsigned long rx_compressed;
309 unsigned long tx_compressed;
310 unsigned long collisions;
312 /* detailed rx_errors: */
313 unsigned long rx_length_errors;
314 unsigned long rx_over_errors; /* receiver ring buff overflow */
315 unsigned long rx_crc_errors; /* recved pkt with crc error */
316 unsigned long rx_frame_errors; /* recv'd frame alignment error */
317 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
318 unsigned long rx_missed_errors; /* receiver missed packet */
319 /* detailed tx_errors */
320 unsigned long tx_aborted_errors;
321 unsigned long tx_carrier_errors;
322 unsigned long tx_fifo_errors;
323 unsigned long tx_heartbeat_errors;
324 unsigned long tx_window_errors;
328 struct interface *next, *prev;
329 char name[IFNAMSIZ]; /* interface name */
330 short type; /* if type */
331 short flags; /* various flags */
332 int metric; /* routing metric */
333 int mtu; /* MTU value */
334 int tx_queue_len; /* transmit queue length */
335 struct ifmap map; /* hardware setup */
336 struct sockaddr addr; /* IP address */
337 struct sockaddr dstaddr; /* P-P IP address */
338 struct sockaddr broadaddr; /* IP broadcast address */
339 struct sockaddr netmask; /* IP network mask */
341 char hwaddr[32]; /* HW address */
342 int statistics_valid;
343 struct user_net_device_stats stats; /* statistics */
344 int keepalive; /* keepalive value for SLIP */
345 int outfill; /* outfill value for SLIP */
349 int interface_opt_a; /* show all interfaces */
351 static struct interface *int_list, *int_last;
352 static int skfd = -1; /* generic raw socket desc. */
355 static int sockets_open(int family)
357 struct aftype * const *aft;
359 static int force = -1;
363 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
365 if (access("/proc/net", R_OK))
368 for (aft = aftypes; *aft; aft++) {
369 struct aftype *af = *aft;
370 int type = SOCK_DGRAM;
372 if (af->af == AF_UNSPEC)
374 if (family && family != af->af)
380 /* Check some /proc file first to not stress kmod */
381 if (!family && !force && af->flag_file) {
382 if (access(af->flag_file, R_OK))
385 af->fd = socket(af->af, type, 0);
390 bb_error_msg("no usable address families found");
395 #ifdef CONFIG_FEATURE_CLEAN_UP
396 static void sockets_close(void)
398 struct aftype * const *aft;
399 for (aft = aftypes; *aft != NULL; aft++) {
400 struct aftype *af = *aft;
409 /* like strcmp(), but knows about numbers */
410 except that the freshly added calls to xatoul() brf on ethernet aliases with
411 uClibc with e.g.: ife->name='lo' name='eth0:1'
412 static int nstrcmp(const char *a, const char *b)
414 const char *a_ptr = a;
415 const char *b_ptr = b;
421 if (!isdigit(*a) && isdigit(*(a+1))) {
429 if (isdigit(*a) && isdigit(*b)) {
430 return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
436 static struct interface *add_interface(char *name)
438 struct interface *ife, **nextp, *new;
440 for (ife = int_last; ife; ife = ife->prev) {
441 int n = /*n*/strcmp(ife->name, name);
449 new = xzalloc(sizeof(*new));
450 safe_strncpy(new->name, name, IFNAMSIZ);
451 nextp = ife ? &ife->next : &int_list;
455 new->next->prev = new;
463 static int if_readconf(void)
471 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
473 skfd2 = get_socket_for_af(AF_INET);
475 bb_perror_msg(("warning: no inet socket available"));
476 /* Try to soldier on with whatever socket we can get hold of. */
477 skfd2 = sockets_open(0);
484 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
485 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
487 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
488 perror("SIOCGIFCONF");
491 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
492 /* assume it overflowed and try again */
500 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
501 add_interface(ifr->ifr_name);
511 static char *get_name(char *name, char *p)
513 /* Extract <name> from nul-terminated p where p matches
514 <name>: after leading whitespace.
515 If match is not made, set name empty and return unchanged p */
516 int namestart=0, nameend=0;
517 while (isspace(p[namestart]))
520 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
522 if (p[nameend]==':') {
523 if ((nameend-namestart)<IFNAMSIZ) {
524 memcpy(name,&p[namestart],nameend-namestart);
525 name[nameend-namestart]='\0';
528 /* Interface name too large */
532 /* trailing ':' not found - return empty */
538 /* If scanf supports size qualifiers for %n conversions, then we can
539 * use a modified fmt that simply stores the position in the fields
540 * having no associated fields in the proc string. Of course, we need
541 * to zero them again when we're done. But that is smaller than the
542 * old approach of multiple scanf occurrences with large numbers of
545 /* static const char * const ss_fmt[] = { */
546 /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
547 /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
548 /* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
551 /* Lie about the size of the int pointed to for %n. */
552 #if INT_MAX == LONG_MAX
553 static const char * const ss_fmt[] = {
554 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
555 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
556 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
559 static const char * const ss_fmt[] = {
560 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
561 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
562 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
567 static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
569 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
571 sscanf(bp, ss_fmt[procnetdev_vsn],
572 &ife->stats.rx_bytes, /* missing for 0 */
573 &ife->stats.rx_packets,
574 &ife->stats.rx_errors,
575 &ife->stats.rx_dropped,
576 &ife->stats.rx_fifo_errors,
577 &ife->stats.rx_frame_errors,
578 &ife->stats.rx_compressed, /* missing for <= 1 */
579 &ife->stats.rx_multicast, /* missing for <= 1 */
580 &ife->stats.tx_bytes, /* missing for 0 */
581 &ife->stats.tx_packets,
582 &ife->stats.tx_errors,
583 &ife->stats.tx_dropped,
584 &ife->stats.tx_fifo_errors,
585 &ife->stats.collisions,
586 &ife->stats.tx_carrier_errors,
587 &ife->stats.tx_compressed /* missing for <= 1 */
590 if (procnetdev_vsn <= 1) {
591 if (procnetdev_vsn == 0) {
592 ife->stats.rx_bytes = 0;
593 ife->stats.tx_bytes = 0;
595 ife->stats.rx_multicast = 0;
596 ife->stats.rx_compressed = 0;
597 ife->stats.tx_compressed = 0;
601 static inline int procnetdev_version(char *buf)
603 if (strstr(buf, "compressed"))
605 if (strstr(buf, "bytes"))
610 static int if_readlist_proc(char *target)
612 static int proc_read;
615 struct interface *ife;
616 int err, procnetdev_vsn;
623 fh = fopen(_PATH_PROCNET_DEV, "r");
625 bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
626 return if_readconf();
628 fgets(buf, sizeof buf, fh); /* eat line */
629 fgets(buf, sizeof buf, fh);
631 procnetdev_vsn = procnetdev_version(buf);
634 while (fgets(buf, sizeof buf, fh)) {
637 s = get_name(name, buf);
638 ife = add_interface(name);
639 get_dev_fields(s, ife, procnetdev_vsn);
640 ife->statistics_valid = 1;
641 if (target && !strcmp(target, name))
645 perror(_PATH_PROCNET_DEV);
653 static int if_readlist(void)
655 int err = if_readlist_proc(NULL);
662 static int for_all_interfaces(int (*doit) (struct interface *, void *),
665 struct interface *ife;
667 if (!int_list && (if_readlist() < 0))
669 for (ife = int_list; ife; ife = ife->next) {
670 int err = doit(ife, cookie);
678 /* Fetch the interface configuration from the kernel. */
679 static int if_fetch(struct interface *ife)
683 char *ifname = ife->name;
685 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
686 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
688 ife->flags = ifr.ifr_flags;
690 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
691 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
692 memset(ife->hwaddr, 0, 32);
694 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
696 ife->type = ifr.ifr_hwaddr.sa_family;
698 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
699 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
702 ife->metric = ifr.ifr_metric;
704 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
705 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
708 ife->mtu = ifr.ifr_mtu;
711 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
712 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
713 ife->map = ifr.ifr_map;
716 memset(&ife->map, 0, sizeof(struct ifmap));
718 #ifdef HAVE_TXQUEUELEN
719 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
720 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
721 ife->tx_queue_len = -1; /* unknown value */
723 ife->tx_queue_len = ifr.ifr_qlen;
725 ife->tx_queue_len = -1; /* unknown value */
729 fd = get_socket_for_af(AF_INET);
731 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
732 ifr.ifr_addr.sa_family = AF_INET;
733 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
735 ife->addr = ifr.ifr_addr;
736 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
737 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
738 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
740 ife->dstaddr = ifr.ifr_dstaddr;
742 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
743 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
744 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
746 ife->broadaddr = ifr.ifr_broadaddr;
748 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
749 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
750 memset(&ife->netmask, 0, sizeof(struct sockaddr));
752 ife->netmask = ifr.ifr_netmask;
754 memset(&ife->addr, 0, sizeof(struct sockaddr));
761 static int do_if_fetch(struct interface *ife)
763 if (if_fetch(ife) < 0) {
766 if (errno == ENODEV) {
767 /* Give better error message for this case. */
768 errmsg = "Device not found";
770 errmsg = strerror(errno);
772 bb_error_msg("%s: error fetching interface information: %s",
779 static const struct hwtype unspec_hwtype = {
783 .print = UNSPEC_print
786 static const struct hwtype loop_hwtype = {
788 .title = "Local Loopback",
789 .type = ARPHRD_LOOPBACK
792 #include <net/if_arp.h>
794 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
795 #include <net/ethernet.h>
797 #include <linux/if_ether.h>
800 /* Display an Ethernet address in readable format. */
801 static char *pr_ether(unsigned char *ptr)
803 static char buff[64];
805 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
806 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
807 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
812 static int in_ether(char *bufp, struct sockaddr *sap);
814 static struct hwtype ether_hwtype = {
817 .type = ARPHRD_ETHER,
823 static unsigned hexchar2int(char c)
827 c &= ~0x20; /* a -> A */
828 if ((unsigned)(c - 'A') <= 5)
829 return c - ('A' - 10);
833 /* Input an Ethernet address and convert to binary. */
834 static int in_ether(char *bufp, struct sockaddr *sap)
841 sap->sa_family = ether_hwtype.type;
842 ptr = (unsigned char*) sap->sa_data;
846 while ((*bufp != '\0') && (i < ETH_ALEN)) {
847 val = hexchar2int(*bufp++) * 0x10;
853 if (c == ':' || c == 0)
856 val |= hexchar2int(c);
864 *ptr++ = (unsigned char) val;
867 /* We might get a semicolon here - not required. */
875 #include <net/if_arp.h>
877 static const struct hwtype ppp_hwtype = {
879 .title = "Point-to-Point Protocol",
883 #ifdef CONFIG_FEATURE_IPV6
884 static const struct hwtype sit_hwtype = {
886 .title = "IPv6-in-IPv4",
888 .print = UNSPEC_print,
889 .suppress_null_addr = 1
893 static const struct hwtype * const hwtypes[] = {
898 #ifdef CONFIG_FEATURE_IPV6
905 static const char * const if_port_text[] = {
906 /* Keep in step with <linux/netdevice.h> */
918 /* Check our hardware type table for this type. */
919 const struct hwtype *get_hwtype(const char *name)
921 const struct hwtype * const *hwp;
924 while (*hwp != NULL) {
925 if (!strcmp((*hwp)->name, name))
932 /* Check our hardware type table for this type. */
933 const struct hwtype *get_hwntype(int type)
935 const struct hwtype * const *hwp;
938 while (*hwp != NULL) {
939 if ((*hwp)->type == type)
946 /* return 1 if address is all zeros */
947 static int hw_null_address(const struct hwtype *hw, void *ap)
950 unsigned char *address = (unsigned char *) ap;
952 for (i = 0; i < hw->alen; i++)
958 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
960 static void print_bytes_scaled(unsigned long long ull, const char *end)
962 unsigned long long int_part;
964 unsigned int frac_part;
972 if (int_part >= 1024) {
973 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
975 ext += 3; /* KiB, MiB, GiB, TiB */
980 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
983 static const char * const ife_print_flags_strs[] = {
1002 static const unsigned short ife_print_flags_mask[] = {
1022 static void ife_print(struct interface *ptr)
1025 const struct hwtype *hw;
1027 int can_compress = 0;
1031 char addr6[40], devname[20];
1032 struct sockaddr_in6 sap;
1033 int plen, scope, dad_status, if_idx;
1037 ap = get_afntype(ptr->addr.sa_family);
1039 ap = get_afntype(0);
1043 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1046 hw = get_hwntype(hf);
1048 hw = get_hwntype(-1);
1050 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
1051 /* For some hardware types (eg Ash, ATM) we don't print the
1052 hardware address if it's null. */
1053 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1054 hw->suppress_null_addr)))
1055 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
1057 if (ptr->flags & IFF_PORTSEL) {
1058 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
1059 if (ptr->flags & IFF_AUTOMEDIA)
1066 printf(" %s addr:%s ", ap->name,
1067 ap->sprint(&ptr->addr, 1));
1068 if (ptr->flags & IFF_POINTOPOINT) {
1069 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
1071 if (ptr->flags & IFF_BROADCAST) {
1072 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
1074 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
1079 #define IPV6_ADDR_ANY 0x0000U
1081 #define IPV6_ADDR_UNICAST 0x0001U
1082 #define IPV6_ADDR_MULTICAST 0x0002U
1083 #define IPV6_ADDR_ANYCAST 0x0004U
1085 #define IPV6_ADDR_LOOPBACK 0x0010U
1086 #define IPV6_ADDR_LINKLOCAL 0x0020U
1087 #define IPV6_ADDR_SITELOCAL 0x0040U
1089 #define IPV6_ADDR_COMPATv4 0x0080U
1091 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
1093 #define IPV6_ADDR_MAPPED 0x1000U
1094 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1096 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1098 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1099 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1100 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1101 &dad_status, devname) != EOF) {
1102 if (!strcmp(devname, ptr->name)) {
1103 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1104 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1105 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1106 inet_pton(AF_INET6, addr6,
1107 (struct sockaddr *) &sap.sin6_addr);
1108 sap.sin6_family = AF_INET6;
1109 printf(" inet6 addr: %s/%d",
1110 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1113 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1117 case IPV6_ADDR_LINKLOCAL:
1120 case IPV6_ADDR_SITELOCAL:
1123 case IPV6_ADDR_COMPATv4:
1126 case IPV6_ADDR_LOOPBACK:
1140 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1142 if (ptr->flags == 0) {
1143 printf("[NO FLAGS] ");
1147 if (ptr->flags & ife_print_flags_mask[i]) {
1148 printf(ife_print_flags_strs[i]);
1150 } while (ife_print_flags_mask[++i]);
1153 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1154 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1155 #ifdef SIOCSKEEPALIVE
1156 if (ptr->outfill || ptr->keepalive)
1157 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
1161 /* If needed, display the interface statistics. */
1163 if (ptr->statistics_valid) {
1164 /* XXX: statistics are currently only printed for the primary address,
1165 * not for the aliases, although strictly speaking they're shared
1170 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1171 ptr->stats.rx_packets, ptr->stats.rx_errors,
1172 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1173 ptr->stats.rx_frame_errors);
1175 printf(" compressed:%lu\n",
1176 ptr->stats.rx_compressed);
1178 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1179 ptr->stats.tx_packets, ptr->stats.tx_errors,
1180 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1181 ptr->stats.tx_carrier_errors);
1182 printf(" collisions:%lu ", ptr->stats.collisions);
1184 printf("compressed:%lu ", ptr->stats.tx_compressed);
1185 if (ptr->tx_queue_len != -1)
1186 printf("txqueuelen:%d ", ptr->tx_queue_len);
1188 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1189 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1193 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1194 ptr->map.base_addr)) {
1197 printf("Interrupt:%d ", ptr->map.irq);
1198 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
1200 printf("Base address:0x%lx ",
1201 (unsigned long) ptr->map.base_addr);
1202 if (ptr->map.mem_start) {
1203 printf("Memory:%lx-%lx ", ptr->map.mem_start,
1207 printf("DMA chan:%x ", ptr->map.dma);
1214 static int do_if_print(struct interface *ife, void *cookie)
1216 int *opt_a = (int *) cookie;
1219 res = do_if_fetch(ife);
1221 if ((ife->flags & IFF_UP) || *opt_a)
1227 static struct interface *lookup_interface(char *name)
1229 struct interface *ife = NULL;
1231 if (if_readlist_proc(name) < 0)
1233 ife = add_interface(name);
1237 /* for ipv4 add/del modes */
1238 static int if_print(char *ifname)
1243 res = for_all_interfaces(do_if_print, &interface_opt_a);
1245 struct interface *ife;
1247 ife = lookup_interface(ifname);
1248 res = do_if_fetch(ife);
1255 int display_interfaces(char *ifname)
1259 /* Create a channel to the NET kernel. */
1260 if ((skfd = sockets_open(0)) < 0) {
1261 bb_perror_msg_and_die("socket");
1264 /* Do we have to show the current setup? */
1265 status = if_print(ifname);
1266 #ifdef CONFIG_FEATURE_CLEAN_UP