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"
40 #if ENABLE_FEATURE_HWIB
41 /* #include <linux/if_infiniband.h> */
42 #undef INFINIBAND_ALEN
43 #define INFINIBAND_ALEN 20
46 #if ENABLE_FEATURE_IPV6
47 # define HAVE_AFINET6 1
52 #define _PATH_PROCNET_DEV "/proc/net/dev"
53 #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
59 * This is in linux/include/net/ipv6.h.
63 struct in6_addr ifr6_addr
;
64 uint32_t ifr6_prefixlen
;
65 unsigned int ifr6_ifindex
;
70 #endif /* HAVE_AFINET6 */
72 /* Defines for glibc2.0 users. */
74 #define SIOCSIFTXQLEN 0x8943
75 #define SIOCGIFTXQLEN 0x8942
78 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
80 #define ifr_qlen ifr_ifru.ifru_mtu
83 #ifndef HAVE_TXQUEUELEN
84 #define HAVE_TXQUEUELEN 1
88 #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
91 /* Display an Internet socket address. */
92 static const char* FAST_FUNC
INET_sprint(struct sockaddr
*sap
, int numeric
)
94 static char *buff
; /* defaults to NULL */
97 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
99 buff
= INET_rresolve((struct sockaddr_in
*) sap
, numeric
, 0xffffff00);
103 #ifdef UNUSED_AND_BUGGY
104 static int INET_getsock(char *bufp
, struct sockaddr
*sap
)
106 char *sp
= bufp
, *bp
;
109 struct sockaddr_in
*sock_in
;
111 sock_in
= (struct sockaddr_in
*) sap
;
112 sock_in
->sin_family
= AF_INET
;
113 sock_in
->sin_port
= 0;
117 for (i
= 0; i
< sizeof(sock_in
->sin_addr
.s_addr
); i
++) {
120 if ((unsigned)(*sp
- 'A') <= 5)
121 bp
[i
] |= (int) (*sp
- ('A' - 10));
122 else if (isdigit(*sp
))
123 bp
[i
] |= (int) (*sp
- '0');
131 if ((unsigned)(*sp
- 'A') <= 5)
132 bp
[i
] |= (int) (*sp
- ('A' - 10));
133 else if (isdigit(*sp
))
134 bp
[i
] |= (int) (*sp
- '0');
140 sock_in
->sin_addr
.s_addr
= htonl(val
);
146 static int FAST_FUNC
INET_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
148 return INET_resolve(bufp
, (struct sockaddr_in
*) sap
, 0);
152 return (INET_getsock(bufp, sap));
154 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
156 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
161 static const struct aftype inet_aftype
= {
163 .title
= "DARPA Internet",
166 .sprint
= INET_sprint
,
172 /* Display an Internet socket address. */
173 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
174 static const char* FAST_FUNC
INET6_sprint(struct sockaddr
*sap
, int numeric
)
179 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
181 buff
= INET6_rresolve((struct sockaddr_in6
*) sap
, numeric
);
186 static int INET6_getsock(char *bufp
, struct sockaddr
*sap
)
188 struct sockaddr_in6
*sin6
;
190 sin6
= (struct sockaddr_in6
*) sap
;
191 sin6
->sin6_family
= AF_INET6
;
194 if (inet_pton(AF_INET6
, bufp
, sin6
->sin6_addr
.s6_addr
) <= 0)
201 static int FAST_FUNC
INET6_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
203 return INET6_resolve(bufp
, (struct sockaddr_in6
*) sap
);
207 return (INET6_getsock(bufp, sap));
209 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
214 static const struct aftype inet6_aftype
= {
218 .alen
= sizeof(struct in6_addr
),
219 .sprint
= INET6_sprint
,
220 .input
= INET6_input
,
223 #endif /* HAVE_AFINET6 */
225 /* Display an UNSPEC address. */
226 static char* FAST_FUNC
UNSPEC_print(unsigned char *ptr
)
234 buff
= xmalloc(sizeof(struct sockaddr
) * 3 + 1);
236 for (i
= 0; i
< sizeof(struct sockaddr
); i
++) {
237 /* careful -- not every libc's sprintf returns # bytes written */
238 sprintf(pos
, "%02X-", (*ptr
++ & 0377));
241 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
246 /* Display an UNSPEC socket address. */
247 static const char* FAST_FUNC
UNSPEC_sprint(struct sockaddr
*sap
, int numeric UNUSED_PARAM
)
249 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
251 return UNSPEC_print((unsigned char *)sap
->sa_data
);
254 static const struct aftype unspec_aftype
= {
259 .print
= UNSPEC_print
,
260 .sprint
= UNSPEC_sprint
,
263 static const struct aftype
*const aftypes
[] = {
272 /* Check our protocol family table for this family. */
273 const struct aftype
* FAST_FUNC
get_aftype(const char *name
)
275 const struct aftype
*const *afp
;
278 while (*afp
!= NULL
) {
279 if (!strcmp((*afp
)->name
, name
))
286 /* Check our protocol family table for this family. */
287 static const struct aftype
*get_afntype(int af
)
289 const struct aftype
*const *afp
;
292 while (*afp
!= NULL
) {
293 if ((*afp
)->af
== af
)
300 struct user_net_device_stats
{
301 unsigned long long rx_packets
; /* total packets received */
302 unsigned long long tx_packets
; /* total packets transmitted */
303 unsigned long long rx_bytes
; /* total bytes received */
304 unsigned long long tx_bytes
; /* total bytes transmitted */
305 unsigned long rx_errors
; /* bad packets received */
306 unsigned long tx_errors
; /* packet transmit problems */
307 unsigned long rx_dropped
; /* no space in linux buffers */
308 unsigned long tx_dropped
; /* no space available in linux */
309 unsigned long rx_multicast
; /* multicast packets received */
310 unsigned long rx_compressed
;
311 unsigned long tx_compressed
;
312 unsigned long collisions
;
314 /* detailed rx_errors: */
315 unsigned long rx_length_errors
;
316 unsigned long rx_over_errors
; /* receiver ring buff overflow */
317 unsigned long rx_crc_errors
; /* recved pkt with crc error */
318 unsigned long rx_frame_errors
; /* recv'd frame alignment error */
319 unsigned long rx_fifo_errors
; /* recv'r fifo overrun */
320 unsigned long rx_missed_errors
; /* receiver missed packet */
321 /* detailed tx_errors */
322 unsigned long tx_aborted_errors
;
323 unsigned long tx_carrier_errors
;
324 unsigned long tx_fifo_errors
;
325 unsigned long tx_heartbeat_errors
;
326 unsigned long tx_window_errors
;
330 struct interface
*next
, *prev
;
331 char name
[IFNAMSIZ
]; /* interface name */
332 short type
; /* if type */
333 short flags
; /* various flags */
334 int metric
; /* routing metric */
335 int mtu
; /* MTU value */
336 int tx_queue_len
; /* transmit queue length */
337 struct ifmap map
; /* hardware setup */
338 struct sockaddr addr
; /* IP address */
339 struct sockaddr dstaddr
; /* P-P IP address */
340 struct sockaddr broadaddr
; /* IP broadcast address */
341 struct sockaddr netmask
; /* IP network mask */
343 char hwaddr
[32]; /* HW address */
344 int statistics_valid
;
345 struct user_net_device_stats stats
; /* statistics */
346 int keepalive
; /* keepalive value for SLIP */
347 int outfill
; /* outfill value for SLIP */
351 smallint interface_opt_a
; /* show all interfaces */
353 static struct interface
*int_list
, *int_last
;
357 /* like strcmp(), but knows about numbers */
358 except that the freshly added calls to
xatoul() brf on ethernet aliases with
359 uClibc with e
.g
.: ife
->name
='lo' name
='eth0:1'
360 static int nstrcmp(const char *a
, const char *b
)
362 const char *a_ptr
= a
;
363 const char *b_ptr
= b
;
369 if (!isdigit(*a
) && isdigit(*(a
+1))) {
377 if (isdigit(*a
) && isdigit(*b
)) {
378 return xatoul(a_ptr
) > xatoul(b_ptr
) ? 1 : -1;
384 static struct interface
*add_interface(char *name
)
386 struct interface
*ife
, **nextp
, *new;
388 for (ife
= int_last
; ife
; ife
= ife
->prev
) {
389 int n
= /*n*/strcmp(ife
->name
, name
);
397 new = xzalloc(sizeof(*new));
398 strncpy_IFNAMSIZ(new->name
, name
);
399 nextp
= ife
? &ife
->next
: &int_list
;
403 new->next
->prev
= new;
410 static char *get_name(char *name
, char *p
)
412 /* Extract <name> from nul-terminated p where p matches
413 <name>: after leading whitespace.
414 If match is not made, set name empty and return unchanged p */
415 int namestart
= 0, nameend
= 0;
417 while (isspace(p
[namestart
]))
420 while (p
[nameend
] && p
[nameend
] != ':' && !isspace(p
[nameend
]))
422 if (p
[nameend
] == ':') {
423 if ((nameend
- namestart
) < IFNAMSIZ
) {
424 memcpy(name
, &p
[namestart
], nameend
- namestart
);
425 name
[nameend
- namestart
] = '\0';
428 /* Interface name too large */
432 /* trailing ':' not found - return empty */
438 /* If scanf supports size qualifiers for %n conversions, then we can
439 * use a modified fmt that simply stores the position in the fields
440 * having no associated fields in the proc string. Of course, we need
441 * to zero them again when we're done. But that is smaller than the
442 * old approach of multiple scanf occurrences with large numbers of
445 /* static const char *const ss_fmt[] = { */
446 /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
447 /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
448 /* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
451 /* Lie about the size of the int pointed to for %n. */
452 #if INT_MAX == LONG_MAX
453 static const char *const ss_fmt
[] = {
454 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
455 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
456 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
459 static const char *const ss_fmt
[] = {
460 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
461 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
462 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
467 static void get_dev_fields(char *bp
, struct interface
*ife
, int procnetdev_vsn
)
469 memset(&ife
->stats
, 0, sizeof(struct user_net_device_stats
));
471 sscanf(bp
, ss_fmt
[procnetdev_vsn
],
472 &ife
->stats
.rx_bytes
, /* missing for 0 */
473 &ife
->stats
.rx_packets
,
474 &ife
->stats
.rx_errors
,
475 &ife
->stats
.rx_dropped
,
476 &ife
->stats
.rx_fifo_errors
,
477 &ife
->stats
.rx_frame_errors
,
478 &ife
->stats
.rx_compressed
, /* missing for <= 1 */
479 &ife
->stats
.rx_multicast
, /* missing for <= 1 */
480 &ife
->stats
.tx_bytes
, /* missing for 0 */
481 &ife
->stats
.tx_packets
,
482 &ife
->stats
.tx_errors
,
483 &ife
->stats
.tx_dropped
,
484 &ife
->stats
.tx_fifo_errors
,
485 &ife
->stats
.collisions
,
486 &ife
->stats
.tx_carrier_errors
,
487 &ife
->stats
.tx_compressed
/* missing for <= 1 */
490 if (procnetdev_vsn
<= 1) {
491 if (procnetdev_vsn
== 0) {
492 ife
->stats
.rx_bytes
= 0;
493 ife
->stats
.tx_bytes
= 0;
495 ife
->stats
.rx_multicast
= 0;
496 ife
->stats
.rx_compressed
= 0;
497 ife
->stats
.tx_compressed
= 0;
501 static int procnetdev_version(char *buf
)
503 if (strstr(buf
, "compressed"))
505 if (strstr(buf
, "bytes"))
510 static int if_readconf(void)
520 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
522 skfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
524 bb_perror_msg("error: no inet socket available");
529 ifc
.ifc_len
= sizeof(struct ifreq
) * numreqs
;
530 ifc
.ifc_buf
= xrealloc(ifc
.ifc_buf
, ifc
.ifc_len
);
532 if (ioctl_or_warn(skfd
, SIOCGIFCONF
, &ifc
) < 0) {
535 if (ifc
.ifc_len
== (int)(sizeof(struct ifreq
) * numreqs
)) {
536 /* assume it overflowed and try again */
544 for (n
= 0; n
< ifc
.ifc_len
; n
+= sizeof(struct ifreq
)) {
545 add_interface(ifr
->ifr_name
);
556 static int if_readlist_proc(char *target
)
558 static smallint proc_read
;
562 struct interface
*ife
;
563 int err
, procnetdev_vsn
;
570 fh
= fopen_or_warn(_PATH_PROCNET_DEV
, "r");
572 return if_readconf();
574 fgets(buf
, sizeof buf
, fh
); /* eat line */
575 fgets(buf
, sizeof buf
, fh
);
577 procnetdev_vsn
= procnetdev_version(buf
);
580 while (fgets(buf
, sizeof buf
, fh
)) {
583 s
= get_name(name
, buf
);
584 ife
= add_interface(name
);
585 get_dev_fields(s
, ife
, procnetdev_vsn
);
586 ife
->statistics_valid
= 1;
587 if (target
&& !strcmp(target
, name
))
591 bb_perror_msg(_PATH_PROCNET_DEV
);
599 static int if_readlist(void)
601 int err
= if_readlist_proc(NULL
);
602 /* Needed in order to get ethN:M aliases */
608 /* Fetch the interface configuration from the kernel. */
609 static int if_fetch(struct interface
*ife
)
612 char *ifname
= ife
->name
;
615 skfd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
617 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
618 if (ioctl(skfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
622 ife
->flags
= ifr
.ifr_flags
;
624 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
625 memset(ife
->hwaddr
, 0, 32);
626 if (ioctl(skfd
, SIOCGIFHWADDR
, &ifr
) >= 0)
627 memcpy(ife
->hwaddr
, ifr
.ifr_hwaddr
.sa_data
, 8);
629 ife
->type
= ifr
.ifr_hwaddr
.sa_family
;
631 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
633 if (ioctl(skfd
, SIOCGIFMETRIC
, &ifr
) >= 0)
634 ife
->metric
= ifr
.ifr_metric
;
636 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
638 if (ioctl(skfd
, SIOCGIFMTU
, &ifr
) >= 0)
639 ife
->mtu
= ifr
.ifr_mtu
;
641 memset(&ife
->map
, 0, sizeof(struct ifmap
));
643 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
644 if (ioctl(skfd
, SIOCGIFMAP
, &ifr
) == 0)
645 ife
->map
= ifr
.ifr_map
;
648 #ifdef HAVE_TXQUEUELEN
649 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
650 ife
->tx_queue_len
= -1; /* unknown value */
651 if (ioctl(skfd
, SIOCGIFTXQLEN
, &ifr
) >= 0)
652 ife
->tx_queue_len
= ifr
.ifr_qlen
;
654 ife
->tx_queue_len
= -1; /* unknown value */
657 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
658 ifr
.ifr_addr
.sa_family
= AF_INET
;
659 memset(&ife
->addr
, 0, sizeof(struct sockaddr
));
660 if (ioctl(skfd
, SIOCGIFADDR
, &ifr
) == 0) {
662 ife
->addr
= ifr
.ifr_addr
;
663 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
664 memset(&ife
->dstaddr
, 0, sizeof(struct sockaddr
));
665 if (ioctl(skfd
, SIOCGIFDSTADDR
, &ifr
) >= 0)
666 ife
->dstaddr
= ifr
.ifr_dstaddr
;
668 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
669 memset(&ife
->broadaddr
, 0, sizeof(struct sockaddr
));
670 if (ioctl(skfd
, SIOCGIFBRDADDR
, &ifr
) >= 0)
671 ife
->broadaddr
= ifr
.ifr_broadaddr
;
673 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
674 memset(&ife
->netmask
, 0, sizeof(struct sockaddr
));
675 if (ioctl(skfd
, SIOCGIFNETMASK
, &ifr
) >= 0)
676 ife
->netmask
= ifr
.ifr_netmask
;
683 static int do_if_fetch(struct interface
*ife
)
685 if (if_fetch(ife
) < 0) {
688 if (errno
== ENODEV
) {
689 /* Give better error message for this case. */
690 errmsg
= "Device not found";
692 errmsg
= strerror(errno
);
694 bb_error_msg("%s: error fetching interface information: %s",
701 static const struct hwtype unspec_hwtype
= {
705 .print
= UNSPEC_print
708 static const struct hwtype loop_hwtype
= {
710 .title
= "Local Loopback",
711 .type
= ARPHRD_LOOPBACK
714 #include <net/if_arp.h>
716 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
717 #include <net/ethernet.h>
719 #include <linux/if_ether.h>
722 /* Display an Ethernet address in readable format. */
723 static char* FAST_FUNC
ether_print(unsigned char *ptr
)
728 buff
= xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
729 (ptr
[0] & 0377), (ptr
[1] & 0377), (ptr
[2] & 0377),
730 (ptr
[3] & 0377), (ptr
[4] & 0377), (ptr
[5] & 0377)
735 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
);
737 static const struct hwtype ether_hwtype
= {
740 .type
= ARPHRD_ETHER
,
742 .print
= ether_print
,
746 static unsigned hexchar2int(char c
)
750 c
&= ~0x20; /* a -> A */
751 if ((unsigned)(c
- 'A') <= 5)
752 return c
- ('A' - 10);
756 /* Input an Ethernet address and convert to binary. */
757 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
)
764 sap
->sa_family
= ether_hwtype
.type
;
765 ptr
= (unsigned char*) sap
->sa_data
;
768 while ((*bufp
!= '\0') && (i
< ETH_ALEN
)) {
769 val
= hexchar2int(*bufp
++) * 0x10;
775 if (c
== ':' || c
== 0)
778 val
|= hexchar2int(c
);
786 *ptr
++ = (unsigned char) val
;
789 /* We might get a semicolon here - not required. */
797 #include <net/if_arp.h>
799 static const struct hwtype ppp_hwtype
= {
801 .title
= "Point-to-Point Protocol",
805 #if ENABLE_FEATURE_IPV6
806 static const struct hwtype sit_hwtype
= {
808 .title
= "IPv6-in-IPv4",
810 .print
= UNSPEC_print
,
811 .suppress_null_addr
= 1
814 #if ENABLE_FEATURE_HWIB
815 static const struct hwtype ib_hwtype
= {
816 .name
= "infiniband",
817 .title
= "InfiniBand",
818 .type
= ARPHRD_INFINIBAND
,
819 .alen
= INFINIBAND_ALEN
,
820 .print
= UNSPEC_print
,
826 static const struct hwtype
*const hwtypes
[] = {
831 #if ENABLE_FEATURE_IPV6
834 #if ENABLE_FEATURE_HWIB
841 static const char *const if_port_text
[] = {
842 /* Keep in step with <linux/netdevice.h> */
854 /* Check our hardware type table for this type. */
855 const struct hwtype
* FAST_FUNC
get_hwtype(const char *name
)
857 const struct hwtype
*const *hwp
;
860 while (*hwp
!= NULL
) {
861 if (!strcmp((*hwp
)->name
, name
))
868 /* Check our hardware type table for this type. */
869 const struct hwtype
* FAST_FUNC
get_hwntype(int type
)
871 const struct hwtype
*const *hwp
;
874 while (*hwp
!= NULL
) {
875 if ((*hwp
)->type
== type
)
882 /* return 1 if address is all zeros */
883 static int hw_null_address(const struct hwtype
*hw
, void *ap
)
886 unsigned char *address
= (unsigned char *) ap
;
888 for (i
= 0; i
< hw
->alen
; i
++)
894 static const char TRext
[] ALIGN1
= "\0\0\0Ki\0Mi\0Gi\0Ti";
896 static void print_bytes_scaled(unsigned long long ull
, const char *end
)
898 unsigned long long int_part
;
900 unsigned int frac_part
;
908 if (int_part
>= 1024) {
909 frac_part
= ((((unsigned int) int_part
) & (1024-1)) * 10) / 1024;
911 ext
+= 3; /* KiB, MiB, GiB, TiB */
916 printf("X bytes:%llu (%llu.%u %sB)%s", ull
, int_part
, frac_part
, ext
, end
);
921 #define IPV6_ADDR_ANY 0x0000U
923 #define IPV6_ADDR_UNICAST 0x0001U
924 #define IPV6_ADDR_MULTICAST 0x0002U
925 #define IPV6_ADDR_ANYCAST 0x0004U
927 #define IPV6_ADDR_LOOPBACK 0x0010U
928 #define IPV6_ADDR_LINKLOCAL 0x0020U
929 #define IPV6_ADDR_SITELOCAL 0x0040U
931 #define IPV6_ADDR_COMPATv4 0x0080U
933 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
935 #define IPV6_ADDR_MAPPED 0x1000U
936 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
939 static void ife_print6(struct interface
*ptr
)
943 char addr6
[40], devname
[20];
944 struct sockaddr_in6 sap
;
945 int plen
, scope
, dad_status
, if_idx
;
948 f
= fopen_for_read(_PATH_PROCNET_IFINET6
);
953 (f
, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
954 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3], addr6p
[4],
955 addr6p
[5], addr6p
[6], addr6p
[7], &if_idx
, &plen
, &scope
,
956 &dad_status
, devname
) != EOF
958 if (!strcmp(devname
, ptr
->name
)) {
959 sprintf(addr6
, "%s:%s:%s:%s:%s:%s:%s:%s",
960 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3],
961 addr6p
[4], addr6p
[5], addr6p
[6], addr6p
[7]);
962 inet_pton(AF_INET6
, addr6
,
963 (struct sockaddr
*) &sap
.sin6_addr
);
964 sap
.sin6_family
= AF_INET6
;
965 printf(" inet6 addr: %s/%d",
966 INET6_sprint((struct sockaddr
*) &sap
, 1),
969 switch (scope
& IPV6_ADDR_SCOPE_MASK
) {
973 case IPV6_ADDR_LINKLOCAL
:
976 case IPV6_ADDR_SITELOCAL
:
979 case IPV6_ADDR_COMPATv4
:
982 case IPV6_ADDR_LOOPBACK
:
993 #define ife_print6(a) ((void)0)
997 static void ife_print(struct interface
*ptr
)
999 const struct aftype
*ap
;
1000 const struct hwtype
*hw
;
1002 int can_compress
= 0;
1004 ap
= get_afntype(ptr
->addr
.sa_family
);
1006 ap
= get_afntype(0);
1010 if (hf
== ARPHRD_CSLIP
|| hf
== ARPHRD_CSLIP6
)
1013 hw
= get_hwntype(hf
);
1015 hw
= get_hwntype(-1);
1017 printf("%-10.10s Link encap:%s ", ptr
->name
, hw
->title
);
1018 /* For some hardware types (eg Ash, ATM) we don't print the
1019 hardware address if it's null. */
1020 if (hw
->print
!= NULL
1021 && !(hw_null_address(hw
, ptr
->hwaddr
) && hw
->suppress_null_addr
)
1023 printf("HWaddr %s ", hw
->print((unsigned char *)ptr
->hwaddr
));
1026 if (ptr
->flags
& IFF_PORTSEL
) {
1027 printf("Media:%s", if_port_text
[ptr
->map
.port
] /* [0] */);
1028 if (ptr
->flags
& IFF_AUTOMEDIA
)
1035 printf(" %s addr:%s ", ap
->name
,
1036 ap
->sprint(&ptr
->addr
, 1));
1037 if (ptr
->flags
& IFF_POINTOPOINT
) {
1038 printf(" P-t-P:%s ", ap
->sprint(&ptr
->dstaddr
, 1));
1040 if (ptr
->flags
& IFF_BROADCAST
) {
1041 printf(" Bcast:%s ", ap
->sprint(&ptr
->broadaddr
, 1));
1043 printf(" Mask:%s\n", ap
->sprint(&ptr
->netmask
, 1));
1049 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1051 if (ptr
->flags
== 0) {
1052 printf("[NO FLAGS] ");
1054 static const char ife_print_flags_strs
[] ALIGN1
=
1072 static const unsigned short ife_print_flags_mask
[] ALIGN2
= {
1090 const unsigned short *mask
= ife_print_flags_mask
;
1091 const char *str
= ife_print_flags_strs
;
1093 if (ptr
->flags
& *mask
) {
1097 str
+= strlen(str
) + 1;
1101 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1102 printf(" MTU:%d Metric:%d", ptr
->mtu
, ptr
->metric
? ptr
->metric
: 1);
1103 #ifdef SIOCSKEEPALIVE
1104 if (ptr
->outfill
|| ptr
->keepalive
)
1105 printf(" Outfill:%d Keepalive:%d", ptr
->outfill
, ptr
->keepalive
);
1109 /* If needed, display the interface statistics. */
1111 if (ptr
->statistics_valid
) {
1112 /* XXX: statistics are currently only printed for the primary address,
1113 * not for the aliases, although strictly speaking they're shared
1118 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1119 ptr
->stats
.rx_packets
, ptr
->stats
.rx_errors
,
1120 ptr
->stats
.rx_dropped
, ptr
->stats
.rx_fifo_errors
,
1121 ptr
->stats
.rx_frame_errors
);
1123 printf(" compressed:%lu\n",
1124 ptr
->stats
.rx_compressed
);
1126 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1127 ptr
->stats
.tx_packets
, ptr
->stats
.tx_errors
,
1128 ptr
->stats
.tx_dropped
, ptr
->stats
.tx_fifo_errors
,
1129 ptr
->stats
.tx_carrier_errors
);
1130 printf(" collisions:%lu ", ptr
->stats
.collisions
);
1132 printf("compressed:%lu ", ptr
->stats
.tx_compressed
);
1133 if (ptr
->tx_queue_len
!= -1)
1134 printf("txqueuelen:%d ", ptr
->tx_queue_len
);
1136 print_bytes_scaled(ptr
->stats
.rx_bytes
, " T");
1137 print_bytes_scaled(ptr
->stats
.tx_bytes
, "\n");
1140 if (ptr
->map
.irq
|| ptr
->map
.mem_start
1141 || ptr
->map
.dma
|| ptr
->map
.base_addr
1145 printf("Interrupt:%d ", ptr
->map
.irq
);
1146 if (ptr
->map
.base_addr
>= 0x100) /* Only print devices using it for
1148 printf("Base address:0x%lx ",
1149 (unsigned long) ptr
->map
.base_addr
);
1150 if (ptr
->map
.mem_start
) {
1151 printf("Memory:%lx-%lx ", ptr
->map
.mem_start
,
1155 printf("DMA chan:%x ", ptr
->map
.dma
);
1161 static int do_if_print(struct interface
*ife
) /*, int *opt_a)*/
1165 res
= do_if_fetch(ife
);
1167 if ((ife
->flags
& IFF_UP
) || interface_opt_a
)
1173 static struct interface
*lookup_interface(char *name
)
1175 struct interface
*ife
= NULL
;
1177 if (if_readlist_proc(name
) < 0)
1179 ife
= add_interface(name
);
1184 static int for_all_interfaces(int (*doit
) (struct interface
*, void *),
1187 struct interface
*ife
;
1189 if (!int_list
&& (if_readlist() < 0))
1191 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1192 int err
= doit(ife
, cookie
);
1201 /* for ipv4 add/del modes */
1202 static int if_print(char *ifname
)
1204 struct interface
*ife
;
1208 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
1209 if (!int_list
&& (if_readlist() < 0))
1211 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1212 int err
= do_if_print(ife
); /*, &interface_opt_a);*/
1218 ife
= lookup_interface(ifname
);
1219 res
= do_if_fetch(ife
);
1225 #if ENABLE_FEATURE_HWIB
1226 /* Input an Infiniband address and convert to binary. */
1227 int FAST_FUNC
in_ib(const char *bufp
, struct sockaddr
*sap
)
1235 sap
->sa_family
= ib_hwtype
.type
;
1236 ptr
= (unsigned char *) sap
->sa_data
;
1240 while ((*bufp
!= '\0') && (i
< INFINIBAND_ALEN
)) {
1245 else if (c
>= 'a' && c
<= 'f')
1247 else if (c
>= 'A' && c
<= 'F')
1257 else if (c
>= 'a' && c
<= 'f')
1258 val
|= c
- 'a' + 10;
1259 else if (c
>= 'A' && c
<= 'F')
1260 val
|= c
- 'A' + 10;
1261 else if (c
== ':' || c
== 0)
1269 *ptr
++ = (unsigned char) (val
& 0377);
1272 /* We might get a semicolon here - not required. */
1278 fprintf(stderr
, "in_ib(%s): %s\n", orig
, UNSPEC_print(sap
->sa_data
));
1285 int FAST_FUNC
display_interfaces(char *ifname
)
1289 status
= if_print(ifname
);
1291 return (status
< 0); /* status < 0 == 1 -- error */