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 source tree.
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)
34 #include <net/if_arp.h>
35 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
36 # include <net/ethernet.h>
38 # include <linux/if_ether.h>
41 #include "inet_common.h"
43 #if ENABLE_FEATURE_HWIB
44 /* #include <linux/if_infiniband.h> */
45 # undef INFINIBAND_ALEN
46 # define INFINIBAND_ALEN 20
49 #if ENABLE_FEATURE_IPV6
50 # define HAVE_AFINET6 1
55 #define _PATH_PROCNET_DEV "/proc/net/dev"
56 #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
61 * This is from linux/include/net/ipv6.h
64 struct in6_addr ifr6_addr
;
65 uint32_t ifr6_prefixlen
;
66 unsigned int ifr6_ifindex
;
69 #endif /* HAVE_AFINET6 */
71 /* Defines for glibc2.0 users. */
73 # define SIOCSIFTXQLEN 0x8943
74 # define SIOCGIFTXQLEN 0x8942
77 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
79 # define ifr_qlen ifr_ifru.ifru_mtu
82 #ifndef HAVE_TXQUEUELEN
83 # define HAVE_TXQUEUELEN 1
87 # define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
90 /* Display an Internet socket address. */
91 static const char* FAST_FUNC
INET_sprint(struct sockaddr
*sap
, int numeric
)
93 static char *buff
; /* defaults to NULL */
96 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
98 buff
= INET_rresolve((struct sockaddr_in
*) sap
, numeric
, 0xffffff00);
102 #ifdef UNUSED_AND_BUGGY
103 static int INET_getsock(char *bufp
, struct sockaddr
*sap
)
105 char *sp
= bufp
, *bp
;
108 struct sockaddr_in
*sock_in
;
110 sock_in
= (struct sockaddr_in
*) sap
;
111 sock_in
->sin_family
= AF_INET
;
112 sock_in
->sin_port
= 0;
116 for (i
= 0; i
< sizeof(sock_in
->sin_addr
.s_addr
); i
++) {
119 if ((unsigned)(*sp
- 'A') <= 5)
120 bp
[i
] |= (int) (*sp
- ('A' - 10));
121 else if (isdigit(*sp
))
122 bp
[i
] |= (int) (*sp
- '0');
130 if ((unsigned)(*sp
- 'A') <= 5)
131 bp
[i
] |= (int) (*sp
- ('A' - 10));
132 else if (isdigit(*sp
))
133 bp
[i
] |= (int) (*sp
- '0');
139 sock_in
->sin_addr
.s_addr
= htonl(val
);
145 static int FAST_FUNC
INET_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
147 return INET_resolve(bufp
, (struct sockaddr_in
*) sap
, 0);
151 return (INET_getsock(bufp, sap));
153 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
155 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
160 static const struct aftype inet_aftype
= {
162 .title
= "DARPA Internet",
165 .sprint
= INET_sprint
,
171 /* Display an Internet socket address. */
172 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
173 static const char* FAST_FUNC
INET6_sprint(struct sockaddr
*sap
, int numeric
)
178 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
180 buff
= INET6_rresolve((struct sockaddr_in6
*) sap
, numeric
);
185 static int INET6_getsock(char *bufp
, struct sockaddr
*sap
)
187 struct sockaddr_in6
*sin6
;
189 sin6
= (struct sockaddr_in6
*) sap
;
190 sin6
->sin6_family
= AF_INET6
;
193 if (inet_pton(AF_INET6
, bufp
, sin6
->sin6_addr
.s6_addr
) <= 0)
200 static int FAST_FUNC
INET6_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
202 return INET6_resolve(bufp
, (struct sockaddr_in6
*) sap
);
206 return (INET6_getsock(bufp, sap));
208 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
213 static const struct aftype inet6_aftype
= {
217 .alen
= sizeof(struct in6_addr
),
218 .sprint
= INET6_sprint
,
219 .input
= INET6_input
,
222 #endif /* HAVE_AFINET6 */
224 /* Display an UNSPEC address. */
225 static char* FAST_FUNC
UNSPEC_print(unsigned char *ptr
)
233 buff
= xmalloc(sizeof(struct sockaddr
) * 3 + 1);
235 for (i
= 0; i
< sizeof(struct sockaddr
); i
++) {
236 /* careful -- not every libc's sprintf returns # bytes written */
237 sprintf(pos
, "%02X-", (*ptr
++ & 0377));
240 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
245 /* Display an UNSPEC socket address. */
246 static const char* FAST_FUNC
UNSPEC_sprint(struct sockaddr
*sap
, int numeric UNUSED_PARAM
)
248 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
250 return UNSPEC_print((unsigned char *)sap
->sa_data
);
253 static const struct aftype unspec_aftype
= {
258 .print
= UNSPEC_print
,
259 .sprint
= UNSPEC_sprint
,
262 static const struct aftype
*const aftypes
[] = {
271 /* Check our protocol family table for this family. */
272 const struct aftype
* FAST_FUNC
get_aftype(const char *name
)
274 const struct aftype
*const *afp
;
277 while (*afp
!= NULL
) {
278 if (!strcmp((*afp
)->name
, name
))
285 /* Check our protocol family table for this family. */
286 static const struct aftype
*get_afntype(int af
)
288 const struct aftype
*const *afp
;
291 while (*afp
!= NULL
) {
292 if ((*afp
)->af
== af
)
299 struct user_net_device_stats
{
300 unsigned long long rx_packets
; /* total packets received */
301 unsigned long long tx_packets
; /* total packets transmitted */
302 unsigned long long rx_bytes
; /* total bytes received */
303 unsigned long long tx_bytes
; /* total bytes transmitted */
304 unsigned long rx_errors
; /* bad packets received */
305 unsigned long tx_errors
; /* packet transmit problems */
306 unsigned long rx_dropped
; /* no space in linux buffers */
307 unsigned long tx_dropped
; /* no space available in linux */
308 unsigned long rx_multicast
; /* multicast packets received */
309 unsigned long rx_compressed
;
310 unsigned long tx_compressed
;
311 unsigned long collisions
;
313 /* detailed rx_errors: */
314 unsigned long rx_length_errors
;
315 unsigned long rx_over_errors
; /* receiver ring buff overflow */
316 unsigned long rx_crc_errors
; /* recved pkt with crc error */
317 unsigned long rx_frame_errors
; /* recv'd frame alignment error */
318 unsigned long rx_fifo_errors
; /* recv'r fifo overrun */
319 unsigned long rx_missed_errors
; /* receiver missed packet */
320 /* detailed tx_errors */
321 unsigned long tx_aborted_errors
;
322 unsigned long tx_carrier_errors
;
323 unsigned long tx_fifo_errors
;
324 unsigned long tx_heartbeat_errors
;
325 unsigned long tx_window_errors
;
329 struct interface
*next
, *prev
;
330 char name
[IFNAMSIZ
]; /* interface name */
331 short type
; /* if type */
332 short flags
; /* various flags */
333 int metric
; /* routing metric */
334 int mtu
; /* MTU value */
335 int tx_queue_len
; /* transmit queue length */
336 struct ifmap map
; /* hardware setup */
337 struct sockaddr addr
; /* IP address */
338 struct sockaddr dstaddr
; /* P-P IP address */
339 struct sockaddr broadaddr
; /* IP broadcast address */
340 struct sockaddr netmask
; /* IP network mask */
342 char hwaddr
[32]; /* HW address */
343 int statistics_valid
;
344 struct user_net_device_stats stats
; /* statistics */
345 int keepalive
; /* keepalive value for SLIP */
346 int outfill
; /* outfill value for SLIP */
350 smallint interface_opt_a
; /* show all interfaces */
352 static struct interface
*int_list
, *int_last
;
356 /* like strcmp(), but knows about numbers */
357 except that the freshly added calls to
xatoul() brf on ethernet aliases with
358 uClibc with e
.g
.: ife
->name
='lo' name
='eth0:1'
359 static int nstrcmp(const char *a
, const char *b
)
361 const char *a_ptr
= a
;
362 const char *b_ptr
= b
;
368 if (!isdigit(*a
) && isdigit(*(a
+1))) {
376 if (isdigit(*a
) && isdigit(*b
)) {
377 return xatoul(a_ptr
) > xatoul(b_ptr
) ? 1 : -1;
383 static struct interface
*add_interface(char *name
)
385 struct interface
*ife
, **nextp
, *new;
387 for (ife
= int_last
; ife
; ife
= ife
->prev
) {
388 int n
= /*n*/strcmp(ife
->name
, name
);
396 new = xzalloc(sizeof(*new));
397 strncpy_IFNAMSIZ(new->name
, name
);
398 nextp
= ife
? &ife
->next
: &int_list
;
402 new->next
->prev
= new;
409 static char *get_name(char *name
, char *p
)
411 /* Extract <name> from nul-terminated p where p matches
412 * <name>: after leading whitespace.
413 * If match is not made, set name empty and return unchanged p
416 char *namestart
= skip_whitespace(p
);
419 while (*nameend
&& *nameend
!= ':' && !isspace(*nameend
))
421 if (*nameend
== ':') {
422 if ((nameend
- namestart
) < IFNAMSIZ
) {
423 memcpy(name
, namestart
, nameend
- namestart
);
424 name
[nameend
- namestart
] = '\0';
427 /* Interface name too large */
431 /* trailing ':' not found - return empty */
437 /* If scanf supports size qualifiers for %n conversions, then we can
438 * use a modified fmt that simply stores the position in the fields
439 * having no associated fields in the proc string. Of course, we need
440 * to zero them again when we're done. But that is smaller than the
441 * old approach of multiple scanf occurrences with large numbers of
444 /* static const char *const ss_fmt[] = { */
445 /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
446 /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
447 /* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
450 /* Lie about the size of the int pointed to for %n. */
451 #if INT_MAX == LONG_MAX
452 static const char *const ss_fmt
[] = {
453 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
454 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
455 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
458 static const char *const ss_fmt
[] = {
459 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
460 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
461 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
466 static void get_dev_fields(char *bp
, struct interface
*ife
, int procnetdev_vsn
)
468 memset(&ife
->stats
, 0, sizeof(struct user_net_device_stats
));
470 sscanf(bp
, ss_fmt
[procnetdev_vsn
],
471 &ife
->stats
.rx_bytes
, /* missing for 0 */
472 &ife
->stats
.rx_packets
,
473 &ife
->stats
.rx_errors
,
474 &ife
->stats
.rx_dropped
,
475 &ife
->stats
.rx_fifo_errors
,
476 &ife
->stats
.rx_frame_errors
,
477 &ife
->stats
.rx_compressed
, /* missing for <= 1 */
478 &ife
->stats
.rx_multicast
, /* missing for <= 1 */
479 &ife
->stats
.tx_bytes
, /* missing for 0 */
480 &ife
->stats
.tx_packets
,
481 &ife
->stats
.tx_errors
,
482 &ife
->stats
.tx_dropped
,
483 &ife
->stats
.tx_fifo_errors
,
484 &ife
->stats
.collisions
,
485 &ife
->stats
.tx_carrier_errors
,
486 &ife
->stats
.tx_compressed
/* missing for <= 1 */
489 if (procnetdev_vsn
<= 1) {
490 if (procnetdev_vsn
== 0) {
491 ife
->stats
.rx_bytes
= 0;
492 ife
->stats
.tx_bytes
= 0;
494 ife
->stats
.rx_multicast
= 0;
495 ife
->stats
.rx_compressed
= 0;
496 ife
->stats
.tx_compressed
= 0;
500 static int procnetdev_version(char *buf
)
502 if (strstr(buf
, "compressed"))
504 if (strstr(buf
, "bytes"))
509 static int if_readconf(void)
519 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
521 skfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
523 bb_perror_msg("error: no inet socket available");
528 ifc
.ifc_len
= sizeof(struct ifreq
) * numreqs
;
529 ifc
.ifc_buf
= xrealloc(ifc
.ifc_buf
, ifc
.ifc_len
);
531 if (ioctl_or_warn(skfd
, SIOCGIFCONF
, &ifc
) < 0) {
534 if (ifc
.ifc_len
== (int)(sizeof(struct ifreq
) * numreqs
)) {
535 /* assume it overflowed and try again */
543 for (n
= 0; n
< ifc
.ifc_len
; n
+= sizeof(struct ifreq
)) {
544 add_interface(ifr
->ifr_name
);
555 static int if_readlist_proc(char *target
)
557 static smallint proc_read
;
561 struct interface
*ife
;
562 int err
, procnetdev_vsn
;
569 fh
= fopen_or_warn(_PATH_PROCNET_DEV
, "r");
571 return if_readconf();
573 fgets(buf
, sizeof buf
, fh
); /* eat line */
574 fgets(buf
, sizeof buf
, fh
);
576 procnetdev_vsn
= procnetdev_version(buf
);
579 while (fgets(buf
, sizeof buf
, fh
)) {
582 s
= get_name(name
, buf
);
583 ife
= add_interface(name
);
584 get_dev_fields(s
, ife
, procnetdev_vsn
);
585 ife
->statistics_valid
= 1;
586 if (target
&& !strcmp(target
, name
))
590 bb_perror_msg(_PATH_PROCNET_DEV
);
598 static int if_readlist(void)
600 int err
= if_readlist_proc(NULL
);
601 /* Needed in order to get ethN:M aliases */
607 /* Fetch the interface configuration from the kernel. */
608 static int if_fetch(struct interface
*ife
)
611 char *ifname
= ife
->name
;
614 skfd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
616 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
617 if (ioctl(skfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
621 ife
->flags
= ifr
.ifr_flags
;
623 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
624 memset(ife
->hwaddr
, 0, 32);
625 if (ioctl(skfd
, SIOCGIFHWADDR
, &ifr
) >= 0)
626 memcpy(ife
->hwaddr
, ifr
.ifr_hwaddr
.sa_data
, 8);
628 ife
->type
= ifr
.ifr_hwaddr
.sa_family
;
630 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
632 if (ioctl(skfd
, SIOCGIFMETRIC
, &ifr
) >= 0)
633 ife
->metric
= ifr
.ifr_metric
;
635 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
637 if (ioctl(skfd
, SIOCGIFMTU
, &ifr
) >= 0)
638 ife
->mtu
= ifr
.ifr_mtu
;
640 memset(&ife
->map
, 0, sizeof(struct ifmap
));
642 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
643 if (ioctl(skfd
, SIOCGIFMAP
, &ifr
) == 0)
644 ife
->map
= ifr
.ifr_map
;
647 #ifdef HAVE_TXQUEUELEN
648 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
649 ife
->tx_queue_len
= -1; /* unknown value */
650 if (ioctl(skfd
, SIOCGIFTXQLEN
, &ifr
) >= 0)
651 ife
->tx_queue_len
= ifr
.ifr_qlen
;
653 ife
->tx_queue_len
= -1; /* unknown value */
656 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
657 ifr
.ifr_addr
.sa_family
= AF_INET
;
658 memset(&ife
->addr
, 0, sizeof(struct sockaddr
));
659 if (ioctl(skfd
, SIOCGIFADDR
, &ifr
) == 0) {
661 ife
->addr
= ifr
.ifr_addr
;
662 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
663 memset(&ife
->dstaddr
, 0, sizeof(struct sockaddr
));
664 if (ioctl(skfd
, SIOCGIFDSTADDR
, &ifr
) >= 0)
665 ife
->dstaddr
= ifr
.ifr_dstaddr
;
667 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
668 memset(&ife
->broadaddr
, 0, sizeof(struct sockaddr
));
669 if (ioctl(skfd
, SIOCGIFBRDADDR
, &ifr
) >= 0)
670 ife
->broadaddr
= ifr
.ifr_broadaddr
;
672 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
673 memset(&ife
->netmask
, 0, sizeof(struct sockaddr
));
674 if (ioctl(skfd
, SIOCGIFNETMASK
, &ifr
) >= 0)
675 ife
->netmask
= ifr
.ifr_netmask
;
682 static int do_if_fetch(struct interface
*ife
)
684 if (if_fetch(ife
) < 0) {
687 if (errno
== ENODEV
) {
688 /* Give better error message for this case. */
689 errmsg
= "Device not found";
691 errmsg
= strerror(errno
);
693 bb_error_msg("%s: error fetching interface information: %s",
700 static const struct hwtype unspec_hwtype
= {
704 .print
= UNSPEC_print
707 static const struct hwtype loop_hwtype
= {
709 .title
= "Local Loopback",
710 .type
= ARPHRD_LOOPBACK
713 /* Display an Ethernet address in readable format. */
714 static char* FAST_FUNC
ether_print(unsigned char *ptr
)
719 buff
= xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
720 (ptr
[0] & 0377), (ptr
[1] & 0377), (ptr
[2] & 0377),
721 (ptr
[3] & 0377), (ptr
[4] & 0377), (ptr
[5] & 0377)
726 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
);
728 static const struct hwtype ether_hwtype
= {
731 .type
= ARPHRD_ETHER
,
733 .print
= ether_print
,
737 static unsigned hexchar2int(char c
)
741 c
&= ~0x20; /* a -> A */
742 if ((unsigned)(c
- 'A') <= 5)
743 return c
- ('A' - 10);
747 /* Input an Ethernet address and convert to binary. */
748 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
)
755 sap
->sa_family
= ether_hwtype
.type
;
756 ptr
= (unsigned char*) sap
->sa_data
;
759 while ((*bufp
!= '\0') && (i
< ETH_ALEN
)) {
760 val
= hexchar2int(*bufp
++) * 0x10;
766 if (c
== ':' || c
== 0)
769 val
|= hexchar2int(c
);
777 *ptr
++ = (unsigned char) val
;
780 /* We might get a semicolon here - not required. */
788 static const struct hwtype ppp_hwtype
= {
790 .title
= "Point-to-Point Protocol",
794 #if ENABLE_FEATURE_IPV6
795 static const struct hwtype sit_hwtype
= {
797 .title
= "IPv6-in-IPv4",
799 .print
= UNSPEC_print
,
800 .suppress_null_addr
= 1
803 #if ENABLE_FEATURE_HWIB
804 static const struct hwtype ib_hwtype
= {
805 .name
= "infiniband",
806 .title
= "InfiniBand",
807 .type
= ARPHRD_INFINIBAND
,
808 .alen
= INFINIBAND_ALEN
,
809 .print
= UNSPEC_print
,
815 static const struct hwtype
*const hwtypes
[] = {
820 #if ENABLE_FEATURE_IPV6
823 #if ENABLE_FEATURE_HWIB
830 static const char *const if_port_text
[] = {
831 /* Keep in step with <linux/netdevice.h> */
843 /* Check our hardware type table for this type. */
844 const struct hwtype
* FAST_FUNC
get_hwtype(const char *name
)
846 const struct hwtype
*const *hwp
;
849 while (*hwp
!= NULL
) {
850 if (!strcmp((*hwp
)->name
, name
))
857 /* Check our hardware type table for this type. */
858 const struct hwtype
* FAST_FUNC
get_hwntype(int type
)
860 const struct hwtype
*const *hwp
;
863 while (*hwp
!= NULL
) {
864 if ((*hwp
)->type
== type
)
871 /* return 1 if address is all zeros */
872 static int hw_null_address(const struct hwtype
*hw
, void *ap
)
875 unsigned char *address
= (unsigned char *) ap
;
877 for (i
= 0; i
< hw
->alen
; i
++)
883 static const char TRext
[] ALIGN1
= "\0\0\0Ki\0Mi\0Gi\0Ti";
885 static void print_bytes_scaled(unsigned long long ull
, const char *end
)
887 unsigned long long int_part
;
889 unsigned int frac_part
;
897 if (int_part
>= 1024) {
898 frac_part
= ((((unsigned int) int_part
) & (1024-1)) * 10) / 1024;
900 ext
+= 3; /* KiB, MiB, GiB, TiB */
905 printf("X bytes:%llu (%llu.%u %sB)%s", ull
, int_part
, frac_part
, ext
, end
);
910 #define IPV6_ADDR_ANY 0x0000U
912 #define IPV6_ADDR_UNICAST 0x0001U
913 #define IPV6_ADDR_MULTICAST 0x0002U
914 #define IPV6_ADDR_ANYCAST 0x0004U
916 #define IPV6_ADDR_LOOPBACK 0x0010U
917 #define IPV6_ADDR_LINKLOCAL 0x0020U
918 #define IPV6_ADDR_SITELOCAL 0x0040U
920 #define IPV6_ADDR_COMPATv4 0x0080U
922 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
924 #define IPV6_ADDR_MAPPED 0x1000U
925 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
928 static void ife_print6(struct interface
*ptr
)
931 char addr6
[40], devname
[20];
932 struct sockaddr_in6 sap
;
933 int plen
, scope
, dad_status
, if_idx
;
936 f
= fopen_for_read(_PATH_PROCNET_IFINET6
);
941 (f
, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
942 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3], addr6p
[4],
943 addr6p
[5], addr6p
[6], addr6p
[7], &if_idx
, &plen
, &scope
,
944 &dad_status
, devname
) != EOF
946 if (!strcmp(devname
, ptr
->name
)) {
947 sprintf(addr6
, "%s:%s:%s:%s:%s:%s:%s:%s",
948 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3],
949 addr6p
[4], addr6p
[5], addr6p
[6], addr6p
[7]);
950 inet_pton(AF_INET6
, addr6
,
951 (struct sockaddr
*) &sap
.sin6_addr
);
952 sap
.sin6_family
= AF_INET6
;
953 printf(" inet6 addr: %s/%d",
954 INET6_sprint((struct sockaddr
*) &sap
, 1),
957 switch (scope
& IPV6_ADDR_SCOPE_MASK
) {
961 case IPV6_ADDR_LINKLOCAL
:
964 case IPV6_ADDR_SITELOCAL
:
967 case IPV6_ADDR_COMPATv4
:
970 case IPV6_ADDR_LOOPBACK
:
981 #define ife_print6(a) ((void)0)
984 static void ife_print(struct interface
*ptr
)
986 const struct aftype
*ap
;
987 const struct hwtype
*hw
;
989 int can_compress
= 0;
991 ap
= get_afntype(ptr
->addr
.sa_family
);
997 if (hf
== ARPHRD_CSLIP
|| hf
== ARPHRD_CSLIP6
)
1000 hw
= get_hwntype(hf
);
1002 hw
= get_hwntype(-1);
1004 printf("%-10s Link encap:%s ", ptr
->name
, hw
->title
);
1005 /* For some hardware types (eg Ash, ATM) we don't print the
1006 hardware address if it's null. */
1007 if (hw
->print
!= NULL
1008 && !(hw_null_address(hw
, ptr
->hwaddr
) && hw
->suppress_null_addr
)
1010 printf("HWaddr %s ", hw
->print((unsigned char *)ptr
->hwaddr
));
1013 if (ptr
->flags
& IFF_PORTSEL
) {
1014 printf("Media:%s", if_port_text
[ptr
->map
.port
] /* [0] */);
1015 if (ptr
->flags
& IFF_AUTOMEDIA
)
1022 printf(" %s addr:%s ", ap
->name
,
1023 ap
->sprint(&ptr
->addr
, 1));
1024 if (ptr
->flags
& IFF_POINTOPOINT
) {
1025 printf(" P-t-P:%s ", ap
->sprint(&ptr
->dstaddr
, 1));
1027 if (ptr
->flags
& IFF_BROADCAST
) {
1028 printf(" Bcast:%s ", ap
->sprint(&ptr
->broadaddr
, 1));
1030 printf(" Mask:%s\n", ap
->sprint(&ptr
->netmask
, 1));
1036 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1038 if (ptr
->flags
== 0) {
1039 printf("[NO FLAGS] ");
1041 static const char ife_print_flags_strs
[] ALIGN1
=
1059 static const unsigned short ife_print_flags_mask
[] ALIGN2
= {
1077 const unsigned short *mask
= ife_print_flags_mask
;
1078 const char *str
= ife_print_flags_strs
;
1080 if (ptr
->flags
& *mask
) {
1084 str
+= strlen(str
) + 1;
1088 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1089 printf(" MTU:%d Metric:%d", ptr
->mtu
, ptr
->metric
? ptr
->metric
: 1);
1090 #ifdef SIOCSKEEPALIVE
1091 if (ptr
->outfill
|| ptr
->keepalive
)
1092 printf(" Outfill:%d Keepalive:%d", ptr
->outfill
, ptr
->keepalive
);
1096 /* If needed, display the interface statistics. */
1098 if (ptr
->statistics_valid
) {
1099 /* XXX: statistics are currently only printed for the primary address,
1100 * not for the aliases, although strictly speaking they're shared
1105 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1106 ptr
->stats
.rx_packets
, ptr
->stats
.rx_errors
,
1107 ptr
->stats
.rx_dropped
, ptr
->stats
.rx_fifo_errors
,
1108 ptr
->stats
.rx_frame_errors
);
1110 printf(" compressed:%lu\n",
1111 ptr
->stats
.rx_compressed
);
1113 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1114 ptr
->stats
.tx_packets
, ptr
->stats
.tx_errors
,
1115 ptr
->stats
.tx_dropped
, ptr
->stats
.tx_fifo_errors
,
1116 ptr
->stats
.tx_carrier_errors
);
1117 printf(" collisions:%lu ", ptr
->stats
.collisions
);
1119 printf("compressed:%lu ", ptr
->stats
.tx_compressed
);
1120 if (ptr
->tx_queue_len
!= -1)
1121 printf("txqueuelen:%d ", ptr
->tx_queue_len
);
1123 print_bytes_scaled(ptr
->stats
.rx_bytes
, " T");
1124 print_bytes_scaled(ptr
->stats
.tx_bytes
, "\n");
1127 if (ptr
->map
.irq
|| ptr
->map
.mem_start
1128 || ptr
->map
.dma
|| ptr
->map
.base_addr
1132 printf("Interrupt:%d ", ptr
->map
.irq
);
1133 if (ptr
->map
.base_addr
>= 0x100) /* Only print devices using it for
1135 printf("Base address:0x%lx ",
1136 (unsigned long) ptr
->map
.base_addr
);
1137 if (ptr
->map
.mem_start
) {
1138 printf("Memory:%lx-%lx ", ptr
->map
.mem_start
,
1142 printf("DMA chan:%x ", ptr
->map
.dma
);
1148 static int do_if_print(struct interface
*ife
) /*, int *opt_a)*/
1152 res
= do_if_fetch(ife
);
1154 if ((ife
->flags
& IFF_UP
) || interface_opt_a
)
1160 static struct interface
*lookup_interface(char *name
)
1162 struct interface
*ife
= NULL
;
1164 if (if_readlist_proc(name
) < 0)
1166 ife
= add_interface(name
);
1171 static int for_all_interfaces(int (*doit
) (struct interface
*, void *),
1174 struct interface
*ife
;
1176 if (!int_list
&& (if_readlist() < 0))
1178 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1179 int err
= doit(ife
, cookie
);
1187 /* for ipv4 add/del modes */
1188 static int if_print(char *ifname
)
1190 struct interface
*ife
;
1194 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
1195 if (!int_list
&& (if_readlist() < 0))
1197 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1198 int err
= do_if_print(ife
); /*, &interface_opt_a);*/
1204 ife
= lookup_interface(ifname
);
1205 res
= do_if_fetch(ife
);
1211 #if ENABLE_FEATURE_HWIB
1212 /* Input an Infiniband address and convert to binary. */
1213 int FAST_FUNC
in_ib(const char *bufp
, struct sockaddr
*sap
)
1215 sap
->sa_family
= ib_hwtype
.type
;
1216 //TODO: error check?
1217 hex2bin((char*)sap
->sa_data
, bufp
, INFINIBAND_ALEN
);
1219 fprintf(stderr
, "in_ib(%s): %s\n", bufp
, UNSPEC_print(sap
->sa_data
));
1225 int FAST_FUNC
display_interfaces(char *ifname
)
1229 status
= if_print(ifname
);
1231 return (status
< 0); /* status < 0 == 1 -- error */