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)
35 #include "inet_common.h"
37 #include <net/if_arp.h>
38 #ifdef HAVE_NET_ETHERNET_H
39 # include <net/ethernet.h>
42 #if ENABLE_FEATURE_HWIB
43 /* #include <linux/if_infiniband.h> */
44 # undef INFINIBAND_ALEN
45 # define INFINIBAND_ALEN 20
48 #if ENABLE_FEATURE_IPV6
49 # define HAVE_AFINET6 1
54 #define _PATH_PROCNET_DEV "/proc/net/dev"
55 #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
60 * This is from linux/include/net/ipv6.h
63 struct in6_addr ifr6_addr
;
64 uint32_t ifr6_prefixlen
;
65 unsigned int ifr6_ifindex
;
68 #endif /* HAVE_AFINET6 */
70 /* Defines for glibc2.0 users. */
72 # define SIOCSIFTXQLEN 0x8943
73 # define SIOCGIFTXQLEN 0x8942
76 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
78 # define ifr_qlen ifr_ifru.ifru_mtu
81 #ifndef HAVE_TXQUEUELEN
82 # define HAVE_TXQUEUELEN 1
86 # define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
89 /* Display an Internet socket address. */
90 static const char* FAST_FUNC
INET_sprint(struct sockaddr
*sap
, int numeric
)
92 static char *buff
; /* defaults to NULL */
95 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
97 buff
= INET_rresolve((struct sockaddr_in
*) sap
, numeric
, 0xffffff00);
101 #ifdef UNUSED_AND_BUGGY
102 static int INET_getsock(char *bufp
, struct sockaddr
*sap
)
104 char *sp
= bufp
, *bp
;
107 struct sockaddr_in
*sock_in
;
109 sock_in
= (struct sockaddr_in
*) sap
;
110 sock_in
->sin_family
= AF_INET
;
111 sock_in
->sin_port
= 0;
115 for (i
= 0; i
< sizeof(sock_in
->sin_addr
.s_addr
); i
++) {
118 if ((unsigned)(*sp
- 'A') <= 5)
119 bp
[i
] |= (int) (*sp
- ('A' - 10));
120 else if (isdigit(*sp
))
121 bp
[i
] |= (int) (*sp
- '0');
129 if ((unsigned)(*sp
- 'A') <= 5)
130 bp
[i
] |= (int) (*sp
- ('A' - 10));
131 else if (isdigit(*sp
))
132 bp
[i
] |= (int) (*sp
- '0');
138 sock_in
->sin_addr
.s_addr
= htonl(val
);
144 static int FAST_FUNC
INET_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
146 return INET_resolve(bufp
, (struct sockaddr_in
*) sap
, 0);
150 return (INET_getsock(bufp, sap));
152 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
154 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
159 static const struct aftype inet_aftype
= {
161 .title
= "DARPA Internet",
164 .sprint
= INET_sprint
,
170 /* Display an Internet socket address. */
171 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
172 static const char* FAST_FUNC
INET6_sprint(struct sockaddr
*sap
, int numeric
)
177 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
179 buff
= INET6_rresolve((struct sockaddr_in6
*) sap
, numeric
);
184 static int INET6_getsock(char *bufp
, struct sockaddr
*sap
)
186 struct sockaddr_in6
*sin6
;
188 sin6
= (struct sockaddr_in6
*) sap
;
189 sin6
->sin6_family
= AF_INET6
;
192 if (inet_pton(AF_INET6
, bufp
, sin6
->sin6_addr
.s6_addr
) <= 0)
199 static int FAST_FUNC
INET6_input(/*int type,*/ const char *bufp
, struct sockaddr
*sap
)
201 return INET6_resolve(bufp
, (struct sockaddr_in6
*) sap
);
205 return (INET6_getsock(bufp, sap));
207 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
212 static const struct aftype inet6_aftype
= {
216 .alen
= sizeof(struct in6_addr
),
217 .sprint
= INET6_sprint
,
218 .input
= INET6_input
,
221 #endif /* HAVE_AFINET6 */
223 /* Display an UNSPEC address. */
224 static char* FAST_FUNC
UNSPEC_print(unsigned char *ptr
)
232 buff
= xmalloc(sizeof(struct sockaddr
) * 3 + 1);
234 for (i
= 0; i
< sizeof(struct sockaddr
); i
++) {
235 /* careful -- not every libc's sprintf returns # bytes written */
236 sprintf(pos
, "%02X-", (*ptr
++ & 0377));
239 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
244 /* Display an UNSPEC socket address. */
245 static const char* FAST_FUNC
UNSPEC_sprint(struct sockaddr
*sap
, int numeric UNUSED_PARAM
)
247 if (sap
->sa_family
== 0xFFFF || sap
->sa_family
== 0)
249 return UNSPEC_print((unsigned char *)sap
->sa_data
);
252 static const struct aftype unspec_aftype
= {
257 .print
= UNSPEC_print
,
258 .sprint
= UNSPEC_sprint
,
261 static const struct aftype
*const aftypes
[] = {
270 /* Check our protocol family table for this family. */
271 const struct aftype
* FAST_FUNC
get_aftype(const char *name
)
273 const struct aftype
*const *afp
;
276 while (*afp
!= NULL
) {
277 if (!strcmp((*afp
)->name
, name
))
284 /* Check our protocol family table for this family. */
285 static const struct aftype
*get_afntype(int af
)
287 const 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 smallint interface_opt_a
; /* show all interfaces */
351 static struct interface
*int_list
, *int_last
;
355 /* like strcmp(), but knows about numbers */
356 except that the freshly added calls to
xatoul() brf on ethernet aliases with
357 uClibc with e
.g
.: ife
->name
='lo' name
='eth0:1'
358 static int nstrcmp(const char *a
, const char *b
)
360 const char *a_ptr
= a
;
361 const char *b_ptr
= b
;
367 if (!isdigit(*a
) && isdigit(*(a
+1))) {
375 if (isdigit(*a
) && isdigit(*b
)) {
376 return xatoul(a_ptr
) > xatoul(b_ptr
) ? 1 : -1;
382 static struct interface
*add_interface(char *name
)
384 struct interface
*ife
, **nextp
, *new;
386 for (ife
= int_last
; ife
; ife
= ife
->prev
) {
387 int n
= /*n*/strcmp(ife
->name
, name
);
395 new = xzalloc(sizeof(*new));
396 strncpy_IFNAMSIZ(new->name
, name
);
397 nextp
= ife
? &ife
->next
: &int_list
;
401 new->next
->prev
= new;
408 static char *get_name(char *name
, char *p
)
410 /* Extract <name> from nul-terminated p where p matches
411 * <name>: after leading whitespace.
412 * If match is not made, set name empty and return unchanged p
415 char *namestart
= skip_whitespace(p
);
418 while (*nameend
&& *nameend
!= ':' && !isspace(*nameend
))
420 if (*nameend
== ':') {
421 if ((nameend
- namestart
) < IFNAMSIZ
) {
422 memcpy(name
, namestart
, nameend
- namestart
);
423 name
[nameend
- namestart
] = '\0';
426 /* Interface name too large */
430 /* trailing ':' not found - return empty */
436 /* If scanf supports size qualifiers for %n conversions, then we can
437 * use a modified fmt that simply stores the position in the fields
438 * having no associated fields in the proc string. Of course, we need
439 * to zero them again when we're done. But that is smaller than the
440 * old approach of multiple scanf occurrences with large numbers of
443 /* static const char *const ss_fmt[] = { */
444 /* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
445 /* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
446 /* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
449 /* Lie about the size of the int pointed to for %n. */
450 #if INT_MAX == LONG_MAX
451 static const char *const ss_fmt
[] = {
452 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
453 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
454 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
457 static const char *const ss_fmt
[] = {
458 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
459 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
460 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
465 static void get_dev_fields(char *bp
, struct interface
*ife
, int procnetdev_vsn
)
467 memset(&ife
->stats
, 0, sizeof(struct user_net_device_stats
));
469 sscanf(bp
, ss_fmt
[procnetdev_vsn
],
470 &ife
->stats
.rx_bytes
, /* missing for 0 */
471 &ife
->stats
.rx_packets
,
472 &ife
->stats
.rx_errors
,
473 &ife
->stats
.rx_dropped
,
474 &ife
->stats
.rx_fifo_errors
,
475 &ife
->stats
.rx_frame_errors
,
476 &ife
->stats
.rx_compressed
, /* missing for <= 1 */
477 &ife
->stats
.rx_multicast
, /* missing for <= 1 */
478 &ife
->stats
.tx_bytes
, /* missing for 0 */
479 &ife
->stats
.tx_packets
,
480 &ife
->stats
.tx_errors
,
481 &ife
->stats
.tx_dropped
,
482 &ife
->stats
.tx_fifo_errors
,
483 &ife
->stats
.collisions
,
484 &ife
->stats
.tx_carrier_errors
,
485 &ife
->stats
.tx_compressed
/* missing for <= 1 */
488 if (procnetdev_vsn
<= 1) {
489 if (procnetdev_vsn
== 0) {
490 ife
->stats
.rx_bytes
= 0;
491 ife
->stats
.tx_bytes
= 0;
493 ife
->stats
.rx_multicast
= 0;
494 ife
->stats
.rx_compressed
= 0;
495 ife
->stats
.tx_compressed
= 0;
499 static int procnetdev_version(char *buf
)
501 if (strstr(buf
, "compressed"))
503 if (strstr(buf
, "bytes"))
508 static int if_readconf(void)
518 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
520 skfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
522 bb_perror_msg("error: no inet socket available");
527 ifc
.ifc_len
= sizeof(struct ifreq
) * numreqs
;
528 ifc
.ifc_buf
= xrealloc(ifc
.ifc_buf
, ifc
.ifc_len
);
530 if (ioctl_or_warn(skfd
, SIOCGIFCONF
, &ifc
) < 0) {
533 if (ifc
.ifc_len
== (int)(sizeof(struct ifreq
) * numreqs
)) {
534 /* assume it overflowed and try again */
542 for (n
= 0; n
< ifc
.ifc_len
; n
+= sizeof(struct ifreq
)) {
543 add_interface(ifr
->ifr_name
);
554 static int if_readlist_proc(char *target
)
556 static smallint proc_read
;
560 struct interface
*ife
;
561 int err
, procnetdev_vsn
;
568 fh
= fopen_or_warn(_PATH_PROCNET_DEV
, "r");
570 return if_readconf();
572 fgets(buf
, sizeof buf
, fh
); /* eat line */
573 fgets(buf
, sizeof buf
, fh
);
575 procnetdev_vsn
= procnetdev_version(buf
);
578 while (fgets(buf
, sizeof buf
, fh
)) {
581 s
= get_name(name
, buf
);
582 ife
= add_interface(name
);
583 get_dev_fields(s
, ife
, procnetdev_vsn
);
584 ife
->statistics_valid
= 1;
585 if (target
&& !strcmp(target
, name
))
589 bb_perror_msg(_PATH_PROCNET_DEV
);
597 static int if_readlist(void)
599 int err
= if_readlist_proc(NULL
);
600 /* Needed in order to get ethN:M aliases */
606 /* Fetch the interface configuration from the kernel. */
607 static int if_fetch(struct interface
*ife
)
610 char *ifname
= ife
->name
;
613 skfd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
615 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
616 if (ioctl(skfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
620 ife
->flags
= ifr
.ifr_flags
;
622 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
623 memset(ife
->hwaddr
, 0, 32);
624 if (ioctl(skfd
, SIOCGIFHWADDR
, &ifr
) >= 0)
625 memcpy(ife
->hwaddr
, ifr
.ifr_hwaddr
.sa_data
, 8);
627 ife
->type
= ifr
.ifr_hwaddr
.sa_family
;
629 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
631 if (ioctl(skfd
, SIOCGIFMETRIC
, &ifr
) >= 0)
632 ife
->metric
= ifr
.ifr_metric
;
634 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
636 if (ioctl(skfd
, SIOCGIFMTU
, &ifr
) >= 0)
637 ife
->mtu
= ifr
.ifr_mtu
;
639 memset(&ife
->map
, 0, sizeof(struct ifmap
));
641 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
642 if (ioctl(skfd
, SIOCGIFMAP
, &ifr
) == 0)
643 ife
->map
= ifr
.ifr_map
;
646 #ifdef HAVE_TXQUEUELEN
647 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
648 ife
->tx_queue_len
= -1; /* unknown value */
649 if (ioctl(skfd
, SIOCGIFTXQLEN
, &ifr
) >= 0)
650 ife
->tx_queue_len
= ifr
.ifr_qlen
;
652 ife
->tx_queue_len
= -1; /* unknown value */
655 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
656 ifr
.ifr_addr
.sa_family
= AF_INET
;
657 memset(&ife
->addr
, 0, sizeof(struct sockaddr
));
658 if (ioctl(skfd
, SIOCGIFADDR
, &ifr
) == 0) {
660 ife
->addr
= ifr
.ifr_addr
;
661 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
662 memset(&ife
->dstaddr
, 0, sizeof(struct sockaddr
));
663 if (ioctl(skfd
, SIOCGIFDSTADDR
, &ifr
) >= 0)
664 ife
->dstaddr
= ifr
.ifr_dstaddr
;
666 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
667 memset(&ife
->broadaddr
, 0, sizeof(struct sockaddr
));
668 if (ioctl(skfd
, SIOCGIFBRDADDR
, &ifr
) >= 0)
669 ife
->broadaddr
= ifr
.ifr_broadaddr
;
671 strncpy_IFNAMSIZ(ifr
.ifr_name
, ifname
);
672 memset(&ife
->netmask
, 0, sizeof(struct sockaddr
));
673 if (ioctl(skfd
, SIOCGIFNETMASK
, &ifr
) >= 0)
674 ife
->netmask
= ifr
.ifr_netmask
;
681 static int do_if_fetch(struct interface
*ife
)
683 if (if_fetch(ife
) < 0) {
686 if (errno
== ENODEV
) {
687 /* Give better error message for this case. */
688 errmsg
= "Device not found";
690 errmsg
= strerror(errno
);
692 bb_error_msg("%s: error fetching interface information: %s",
699 static const struct hwtype unspec_hwtype
= {
703 .print
= UNSPEC_print
706 static const struct hwtype loop_hwtype
= {
708 .title
= "Local Loopback",
709 .type
= ARPHRD_LOOPBACK
712 /* Display an Ethernet address in readable format. */
713 static char* FAST_FUNC
ether_print(unsigned char *ptr
)
718 buff
= xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
719 (ptr
[0] & 0377), (ptr
[1] & 0377), (ptr
[2] & 0377),
720 (ptr
[3] & 0377), (ptr
[4] & 0377), (ptr
[5] & 0377)
725 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
);
727 static const struct hwtype ether_hwtype
= {
730 .type
= ARPHRD_ETHER
,
732 .print
= ether_print
,
736 static unsigned hexchar2int(char c
)
740 c
&= ~0x20; /* a -> A */
741 if ((unsigned)(c
- 'A') <= 5)
742 return c
- ('A' - 10);
746 /* Input an Ethernet address and convert to binary. */
747 static int FAST_FUNC
ether_input(const char *bufp
, struct sockaddr
*sap
)
754 sap
->sa_family
= ether_hwtype
.type
;
755 ptr
= (unsigned char*) sap
->sa_data
;
758 while ((*bufp
!= '\0') && (i
< ETH_ALEN
)) {
759 val
= hexchar2int(*bufp
++) * 0x10;
765 if (c
== ':' || c
== 0)
768 val
|= hexchar2int(c
);
776 *ptr
++ = (unsigned char) val
;
779 /* We might get a semicolon here - not required. */
787 static const struct hwtype ppp_hwtype
= {
789 .title
= "Point-to-Point Protocol",
793 #if ENABLE_FEATURE_IPV6
794 static const struct hwtype sit_hwtype
= {
796 .title
= "IPv6-in-IPv4",
798 .print
= UNSPEC_print
,
799 .suppress_null_addr
= 1
802 #if ENABLE_FEATURE_HWIB
803 static const struct hwtype ib_hwtype
= {
804 .name
= "infiniband",
805 .title
= "InfiniBand",
806 .type
= ARPHRD_INFINIBAND
,
807 .alen
= INFINIBAND_ALEN
,
808 .print
= UNSPEC_print
,
814 static const struct hwtype
*const hwtypes
[] = {
819 #if ENABLE_FEATURE_IPV6
822 #if ENABLE_FEATURE_HWIB
829 static const char *const if_port_text
[] = {
830 /* Keep in step with <linux/netdevice.h> */
842 /* Check our hardware type table for this type. */
843 const struct hwtype
* FAST_FUNC
get_hwtype(const char *name
)
845 const struct hwtype
*const *hwp
;
848 while (*hwp
!= NULL
) {
849 if (!strcmp((*hwp
)->name
, name
))
856 /* Check our hardware type table for this type. */
857 const struct hwtype
* FAST_FUNC
get_hwntype(int type
)
859 const struct hwtype
*const *hwp
;
862 while (*hwp
!= NULL
) {
863 if ((*hwp
)->type
== type
)
870 /* return 1 if address is all zeros */
871 static int hw_null_address(const struct hwtype
*hw
, void *ap
)
874 unsigned char *address
= (unsigned char *) ap
;
876 for (i
= 0; i
< hw
->alen
; i
++)
882 static const char TRext
[] ALIGN1
= "\0\0\0Ki\0Mi\0Gi\0Ti";
884 static void print_bytes_scaled(unsigned long long ull
, const char *end
)
886 unsigned long long int_part
;
888 unsigned int frac_part
;
896 if (int_part
>= 1024) {
897 frac_part
= ((((unsigned int) int_part
) & (1024-1)) * 10) / 1024;
899 ext
+= 3; /* KiB, MiB, GiB, TiB */
904 printf("X bytes:%llu (%llu.%u %sB)%s", ull
, int_part
, frac_part
, ext
, end
);
909 #define IPV6_ADDR_ANY 0x0000U
911 #define IPV6_ADDR_UNICAST 0x0001U
912 #define IPV6_ADDR_MULTICAST 0x0002U
913 #define IPV6_ADDR_ANYCAST 0x0004U
915 #define IPV6_ADDR_LOOPBACK 0x0010U
916 #define IPV6_ADDR_LINKLOCAL 0x0020U
917 #define IPV6_ADDR_SITELOCAL 0x0040U
919 #define IPV6_ADDR_COMPATv4 0x0080U
921 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
923 #define IPV6_ADDR_MAPPED 0x1000U
924 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
927 static void ife_print6(struct interface
*ptr
)
930 char addr6
[40], devname
[20];
931 struct sockaddr_in6 sap
;
932 int plen
, scope
, dad_status
, if_idx
;
935 f
= fopen_for_read(_PATH_PROCNET_IFINET6
);
940 (f
, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
941 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3], addr6p
[4],
942 addr6p
[5], addr6p
[6], addr6p
[7], &if_idx
, &plen
, &scope
,
943 &dad_status
, devname
) != EOF
945 if (!strcmp(devname
, ptr
->name
)) {
946 sprintf(addr6
, "%s:%s:%s:%s:%s:%s:%s:%s",
947 addr6p
[0], addr6p
[1], addr6p
[2], addr6p
[3],
948 addr6p
[4], addr6p
[5], addr6p
[6], addr6p
[7]);
949 inet_pton(AF_INET6
, addr6
,
950 (struct sockaddr
*) &sap
.sin6_addr
);
951 sap
.sin6_family
= AF_INET6
;
952 printf(" inet6 addr: %s/%d",
953 INET6_sprint((struct sockaddr
*) &sap
, 1),
956 switch (scope
& IPV6_ADDR_SCOPE_MASK
) {
960 case IPV6_ADDR_LINKLOCAL
:
963 case IPV6_ADDR_SITELOCAL
:
966 case IPV6_ADDR_COMPATv4
:
969 case IPV6_ADDR_LOOPBACK
:
980 #define ife_print6(a) ((void)0)
983 static void ife_print(struct interface
*ptr
)
985 const struct aftype
*ap
;
986 const struct hwtype
*hw
;
988 int can_compress
= 0;
990 ap
= get_afntype(ptr
->addr
.sa_family
);
996 if (hf
== ARPHRD_CSLIP
|| hf
== ARPHRD_CSLIP6
)
999 hw
= get_hwntype(hf
);
1001 hw
= get_hwntype(-1);
1003 printf("%-10s Link encap:%s ", ptr
->name
, hw
->title
);
1004 /* For some hardware types (eg Ash, ATM) we don't print the
1005 hardware address if it's null. */
1006 if (hw
->print
!= NULL
1007 && !(hw_null_address(hw
, ptr
->hwaddr
) && hw
->suppress_null_addr
)
1009 printf("HWaddr %s ", hw
->print((unsigned char *)ptr
->hwaddr
));
1012 if (ptr
->flags
& IFF_PORTSEL
) {
1013 printf("Media:%s", if_port_text
[ptr
->map
.port
] /* [0] */);
1014 if (ptr
->flags
& IFF_AUTOMEDIA
)
1021 printf(" %s addr:%s ", ap
->name
,
1022 ap
->sprint(&ptr
->addr
, 1));
1023 if (ptr
->flags
& IFF_POINTOPOINT
) {
1024 printf(" P-t-P:%s ", ap
->sprint(&ptr
->dstaddr
, 1));
1026 if (ptr
->flags
& IFF_BROADCAST
) {
1027 printf(" Bcast:%s ", ap
->sprint(&ptr
->broadaddr
, 1));
1029 printf(" Mask:%s\n", ap
->sprint(&ptr
->netmask
, 1));
1035 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1037 if (ptr
->flags
== 0) {
1038 printf("[NO FLAGS] ");
1040 static const char ife_print_flags_strs
[] ALIGN1
=
1058 static const unsigned short ife_print_flags_mask
[] ALIGN2
= {
1076 const unsigned short *mask
= ife_print_flags_mask
;
1077 const char *str
= ife_print_flags_strs
;
1079 if (ptr
->flags
& *mask
) {
1083 str
+= strlen(str
) + 1;
1087 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1088 printf(" MTU:%d Metric:%d", ptr
->mtu
, ptr
->metric
? ptr
->metric
: 1);
1089 #ifdef SIOCSKEEPALIVE
1090 if (ptr
->outfill
|| ptr
->keepalive
)
1091 printf(" Outfill:%d Keepalive:%d", ptr
->outfill
, ptr
->keepalive
);
1095 /* If needed, display the interface statistics. */
1097 if (ptr
->statistics_valid
) {
1098 /* XXX: statistics are currently only printed for the primary address,
1099 * not for the aliases, although strictly speaking they're shared
1104 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1105 ptr
->stats
.rx_packets
, ptr
->stats
.rx_errors
,
1106 ptr
->stats
.rx_dropped
, ptr
->stats
.rx_fifo_errors
,
1107 ptr
->stats
.rx_frame_errors
);
1109 printf(" compressed:%lu\n",
1110 ptr
->stats
.rx_compressed
);
1112 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1113 ptr
->stats
.tx_packets
, ptr
->stats
.tx_errors
,
1114 ptr
->stats
.tx_dropped
, ptr
->stats
.tx_fifo_errors
,
1115 ptr
->stats
.tx_carrier_errors
);
1116 printf(" collisions:%lu ", ptr
->stats
.collisions
);
1118 printf("compressed:%lu ", ptr
->stats
.tx_compressed
);
1119 if (ptr
->tx_queue_len
!= -1)
1120 printf("txqueuelen:%d ", ptr
->tx_queue_len
);
1122 print_bytes_scaled(ptr
->stats
.rx_bytes
, " T");
1123 print_bytes_scaled(ptr
->stats
.tx_bytes
, "\n");
1126 if (ptr
->map
.irq
|| ptr
->map
.mem_start
1127 || ptr
->map
.dma
|| ptr
->map
.base_addr
1131 printf("Interrupt:%d ", ptr
->map
.irq
);
1132 if (ptr
->map
.base_addr
>= 0x100) /* Only print devices using it for
1134 printf("Base address:0x%lx ",
1135 (unsigned long) ptr
->map
.base_addr
);
1136 if (ptr
->map
.mem_start
) {
1137 printf("Memory:%lx-%lx ", ptr
->map
.mem_start
,
1141 printf("DMA chan:%x ", ptr
->map
.dma
);
1147 static int do_if_print(struct interface
*ife
) /*, int *opt_a)*/
1151 res
= do_if_fetch(ife
);
1153 if ((ife
->flags
& IFF_UP
) || interface_opt_a
)
1159 static struct interface
*lookup_interface(char *name
)
1161 struct interface
*ife
= NULL
;
1163 if (if_readlist_proc(name
) < 0)
1165 ife
= add_interface(name
);
1170 static int for_all_interfaces(int (*doit
) (struct interface
*, void *),
1173 struct interface
*ife
;
1175 if (!int_list
&& (if_readlist() < 0))
1177 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1178 int err
= doit(ife
, cookie
);
1186 /* for ipv4 add/del modes */
1187 static int if_print(char *ifname
)
1189 struct interface
*ife
;
1193 /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
1194 if (!int_list
&& (if_readlist() < 0))
1196 for (ife
= int_list
; ife
; ife
= ife
->next
) {
1197 int err
= do_if_print(ife
); /*, &interface_opt_a);*/
1203 ife
= lookup_interface(ifname
);
1204 res
= do_if_fetch(ife
);
1210 #if ENABLE_FEATURE_HWIB
1211 /* Input an Infiniband address and convert to binary. */
1212 int FAST_FUNC
in_ib(const char *bufp
, struct sockaddr
*sap
)
1214 sap
->sa_family
= ib_hwtype
.type
;
1215 //TODO: error check?
1216 hex2bin((char*)sap
->sa_data
, bufp
, INFINIBAND_ALEN
);
1218 fprintf(stderr
, "in_ib(%s): %s\n", bufp
, UNSPEC_print(sap
->sa_data
));
1224 int FAST_FUNC
display_interfaces(char *ifname
)
1228 status
= if_print(ifname
);
1230 return (status
< 0); /* status < 0 == 1 -- error */