source: trunk/mindi-busybox/networking/interface.c @ 904

Last change on this file since 904 was 821, checked in by bruno, 13 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 26.7 KB
Line 
1/*
2 * stolen from net-tools-1.59 and stripped down for busybox by
3 *          Erik Andersen <andersen@codepoet.org>
4 *
5 * Heavily modified by Manuel Novoa III       Mar 12, 2001
6 *
7 * Added print_bytes_scaled function to reduce code size.
8 * Added some (potentially) missing defines.
9 * Improved display support for -a and for a named interface.
10 *
11 * -----------------------------------------------------------
12 *
13 * ifconfig   This file contains an implementation of the command
14 *              that either displays or sets the characteristics of
15 *              one or more of the system's networking interfaces.
16 *
17 * Version:     $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
18 *
19 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
20 *              and others.  Copyright 1993 MicroWalt Corporation
21 *
22 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
23 *
24 * Patched to support 'add' and 'del' keywords for INET(4) addresses
25 * by Mrs. Brisby <mrs.brisby@nimh.org>
26 *
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)
32 */
33
34#include "inet_common.h"
35#include <stdio.h>
36#include <errno.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <ctype.h>
42#include <sys/ioctl.h>
43#include <sys/types.h>
44#include <net/if.h>
45#include <net/if_arp.h>
46#include "busybox.h"
47
48#ifdef CONFIG_FEATURE_IPV6
49# define HAVE_AFINET6 1
50#else
51# undef HAVE_AFINET6
52#endif
53
54#define _PATH_PROCNET_DEV               "/proc/net/dev"
55#define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
56
57#if HAVE_AFINET6
58
59#ifndef _LINUX_IN6_H
60/*
61 *    This is in linux/include/net/ipv6.h.
62 */
63
64struct in6_ifreq {
65    struct in6_addr ifr6_addr;
66    uint32_t ifr6_prefixlen;
67    unsigned int ifr6_ifindex;
68};
69
70#endif
71
72#endif                          /* HAVE_AFINET6 */
73
74/* Defines for glibc2.0 users. */
75#ifndef SIOCSIFTXQLEN
76#define SIOCSIFTXQLEN      0x8943
77#define SIOCGIFTXQLEN      0x8942
78#endif
79
80/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
81#ifndef ifr_qlen
82#define ifr_qlen        ifr_ifru.ifru_mtu
83#endif
84
85#ifndef HAVE_TXQUEUELEN
86#define HAVE_TXQUEUELEN 1
87#endif
88
89#ifndef IFF_DYNAMIC
90#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
91#endif
92
93/* This structure defines protocol families and their handlers. */
94struct aftype {
95    const char *name;
96    const char *title;
97    int af;
98    int alen;
99    char *(*print) (unsigned char *);
100    char *(*sprint) (struct sockaddr *, int numeric);
101    int (*input) (int type, char *bufp, struct sockaddr *);
102    void (*herror) (char *text);
103    int (*rprint) (int options);
104    int (*rinput) (int typ, int ext, char **argv);
105
106    /* may modify src */
107    int (*getmask) (char *src, struct sockaddr * mask, char *name);
108
109    int fd;
110    char *flag_file;
111};
112
113/* Display an Internet socket address. */
114static char *INET_sprint(struct sockaddr *sap, int numeric)
115{
116    static char buff[128];
117
118    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
119        return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
120
121    if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
122                      numeric, 0xffffff00) != 0)
123        return (NULL);
124
125    return (buff);
126}
127
128static struct aftype inet_aftype = {
129    .name =     "inet",
130    .title =    "DARPA Internet",
131    .af =       AF_INET,
132    .alen =     4,
133    .sprint =   INET_sprint,
134    .fd =       -1
135};
136
137#if HAVE_AFINET6
138
139/* Display an Internet socket address. */
140/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
141static char *INET6_sprint(struct sockaddr *sap, int numeric)
142{
143    static char buff[128];
144
145    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
146        return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
147    if (INET6_rresolve
148        (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
149        return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
150    return (buff);
151}
152
153static struct aftype inet6_aftype = {
154    .name =     "inet6",
155    .title =    "IPv6",
156    .af =       AF_INET6,
157    .alen =     sizeof(struct in6_addr),
158    .sprint =   INET6_sprint,
159    .fd =       -1
160};
161
162#endif                          /* HAVE_AFINET6 */
163
164/* Display an UNSPEC address. */
165static char *UNSPEC_print(unsigned char *ptr)
166{
167    static char buff[sizeof(struct sockaddr) * 3 + 1];
168    char *pos;
169    unsigned int i;
170
171    pos = buff;
172    for (i = 0; i < sizeof(struct sockaddr); i++) {
173        /* careful -- not every libc's sprintf returns # bytes written */
174        sprintf(pos, "%02X-", (*ptr++ & 0377));
175        pos += 3;
176    }
177    /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
178    *--pos = '\0';
179    return (buff);
180}
181
182/* Display an UNSPEC socket address. */
183static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
184{
185    static char buf[64];
186
187    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
188        return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
189    return (UNSPEC_print((unsigned char *)sap->sa_data));
190}
191
192static struct aftype unspec_aftype = {
193    "unspec", "UNSPEC", AF_UNSPEC, 0,
194    UNSPEC_print, UNSPEC_sprint, NULL, NULL,
195    NULL,
196};
197
198static struct aftype * const aftypes[] = {
199    &inet_aftype,
200#if HAVE_AFINET6
201    &inet6_aftype,
202#endif
203    &unspec_aftype,
204    NULL
205};
206
207/* Check our protocol family table for this family. */
208static struct aftype *get_afntype(int af)
209{
210    struct aftype * const *afp;
211
212    afp = aftypes;
213    while (*afp != NULL) {
214        if ((*afp)->af == af)
215            return (*afp);
216        afp++;
217    }
218    return (NULL);
219}
220
221/* Check our protocol family table for this family and return its socket */
222static int get_socket_for_af(int af)
223{
224    struct aftype * const *afp;
225
226    afp = aftypes;
227    while (*afp != NULL) {
228        if ((*afp)->af == af)
229            return (*afp)->fd;
230        afp++;
231    }
232    return -1;
233}
234
235struct user_net_device_stats {
236    unsigned long long rx_packets;  /* total packets received       */
237    unsigned long long tx_packets;  /* total packets transmitted    */
238    unsigned long long rx_bytes;    /* total bytes received         */
239    unsigned long long tx_bytes;    /* total bytes transmitted      */
240    unsigned long rx_errors;    /* bad packets received         */
241    unsigned long tx_errors;    /* packet transmit problems     */
242    unsigned long rx_dropped;   /* no space in linux buffers    */
243    unsigned long tx_dropped;   /* no space available in linux  */
244    unsigned long rx_multicast; /* multicast packets received   */
245    unsigned long rx_compressed;
246    unsigned long tx_compressed;
247    unsigned long collisions;
248
249    /* detailed rx_errors: */
250    unsigned long rx_length_errors;
251    unsigned long rx_over_errors;   /* receiver ring buff overflow  */
252    unsigned long rx_crc_errors;    /* recved pkt with crc error    */
253    unsigned long rx_frame_errors;  /* recv'd frame alignment error */
254    unsigned long rx_fifo_errors;   /* recv'r fifo overrun          */
255    unsigned long rx_missed_errors; /* receiver missed packet     */
256    /* detailed tx_errors */
257    unsigned long tx_aborted_errors;
258    unsigned long tx_carrier_errors;
259    unsigned long tx_fifo_errors;
260    unsigned long tx_heartbeat_errors;
261    unsigned long tx_window_errors;
262};
263
264struct interface {
265    struct interface *next, *prev;
266    char name[IFNAMSIZ];    /* interface name        */
267    short type;         /* if type               */
268    short flags;        /* various flags         */
269    int metric;         /* routing metric        */
270    int mtu;            /* MTU value             */
271    int tx_queue_len;   /* transmit queue length */
272    struct ifmap map;   /* hardware setup        */
273    struct sockaddr addr;   /* IP address            */
274    struct sockaddr dstaddr;    /* P-P IP address        */
275    struct sockaddr broadaddr;  /* IP broadcast address  */
276    struct sockaddr netmask;    /* IP network mask       */
277    int has_ip;
278    char hwaddr[32];    /* HW address            */
279    int statistics_valid;
280    struct user_net_device_stats stats; /* statistics            */
281    int keepalive;      /* keepalive value for SLIP */
282    int outfill;        /* outfill value for SLIP */
283};
284
285
286int interface_opt_a = 0;    /* show all interfaces          */
287
288static struct interface *int_list, *int_last;
289static int skfd = -1;   /* generic raw socket desc.     */
290
291
292static int sockets_open(int family)
293{
294    struct aftype * const *aft;
295    int sfd = -1;
296    static int force = -1;
297
298    if (force < 0) {
299        force = 0;
300        if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
301            force = 1;
302        if (access("/proc/net", R_OK))
303            force = 1;
304    }
305    for (aft = aftypes; *aft; aft++) {
306        struct aftype *af = *aft;
307        int type = SOCK_DGRAM;
308
309        if (af->af == AF_UNSPEC)
310            continue;
311        if (family && family != af->af)
312            continue;
313        if (af->fd != -1) {
314            sfd = af->fd;
315            continue;
316        }
317        /* Check some /proc file first to not stress kmod */
318        if (!family && !force && af->flag_file) {
319            if (access(af->flag_file, R_OK))
320                continue;
321        }
322        af->fd = socket(af->af, type, 0);
323        if (af->fd >= 0)
324            sfd = af->fd;
325    }
326    if (sfd < 0) {
327        bb_error_msg("No usable address families found.");
328    }
329    return sfd;
330}
331
332#ifdef CONFIG_FEATURE_CLEAN_UP
333static void sockets_close(void)
334{
335    struct aftype * const *aft;
336    for (aft = aftypes; *aft != NULL; aft++) {
337        struct aftype *af = *aft;
338        if( af->fd != -1 ) {
339            close(af->fd);
340            af->fd = -1;
341        }
342    }
343}
344#endif
345
346/* like strcmp(), but knows about numbers */
347static int nstrcmp(const char *a, const char *b)
348{
349    const char *a_ptr = a;
350    const char *b_ptr = b;
351
352    while (*a == *b) {
353        if (*a == '\0') {
354            return 0;
355        }
356        if (!isdigit(*a) && isdigit(*(a+1))) {
357            a_ptr = a+1;
358            b_ptr = b+1;
359        }
360        a++;
361        b++;
362    }
363
364    if (isdigit(*a) && isdigit(*b)) {
365        return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
366    }
367    return *a - *b;
368}
369
370static struct interface *add_interface(char *name)
371{
372    struct interface *ife, **nextp, *new;
373
374    for (ife = int_last; ife; ife = ife->prev) {
375        int n = nstrcmp(ife->name, name);
376
377        if (n == 0)
378            return ife;
379        if (n < 0)
380            break;
381    }
382
383    new = xzalloc(sizeof(*new));
384    safe_strncpy(new->name, name, IFNAMSIZ);
385    nextp = ife ? &ife->next : &int_list;
386    new->prev = ife;
387    new->next = *nextp;
388    if (new->next)
389        new->next->prev = new;
390    else
391        int_last = new;
392    *nextp = new;
393    return new;
394}
395
396
397static int if_readconf(void)
398{
399    int numreqs = 30;
400    struct ifconf ifc;
401    struct ifreq *ifr;
402    int n, err = -1;
403    int skfd2;
404
405    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
406       (as of 2.1.128) */
407    skfd2 = get_socket_for_af(AF_INET);
408    if (skfd2 < 0) {
409        bb_perror_msg(("warning: no inet socket available"));
410        /* Try to soldier on with whatever socket we can get hold of.  */
411        skfd2 = sockets_open(0);
412        if (skfd2 < 0)
413            return -1;
414    }
415
416    ifc.ifc_buf = NULL;
417    for (;;) {
418        ifc.ifc_len = sizeof(struct ifreq) * numreqs;
419        ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
420
421        if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
422            perror("SIOCGIFCONF");
423            goto out;
424        }
425        if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
426            /* assume it overflowed and try again */
427            numreqs += 10;
428            continue;
429        }
430        break;
431    }
432
433    ifr = ifc.ifc_req;
434    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
435        add_interface(ifr->ifr_name);
436        ifr++;
437    }
438    err = 0;
439
440  out:
441    free(ifc.ifc_buf);
442    return err;
443}
444
445static char *get_name(char *name, char *p)
446{
447    /* Extract <name> from nul-terminated p where p matches
448       <name>: after leading whitespace.
449       If match is not made, set name empty and return unchanged p */
450    int namestart=0, nameend=0;
451    while (isspace(p[namestart]))
452        namestart++;
453    nameend=namestart;
454    while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
455        nameend++;
456    if (p[nameend]==':') {
457        if ((nameend-namestart)<IFNAMSIZ) {
458            memcpy(name,&p[namestart],nameend-namestart);
459            name[nameend-namestart]='\0';
460            p=&p[nameend];
461        } else {
462            /* Interface name too large */
463            name[0]='\0';
464        }
465    } else {
466        /* trailing ':' not found - return empty */
467        name[0]='\0';
468    }
469    return p + 1;
470}
471
472/* If scanf supports size qualifiers for %n conversions, then we can
473 * use a modified fmt that simply stores the position in the fields
474 * having no associated fields in the proc string.  Of course, we need
475 * to zero them again when we're done.  But that is smaller than the
476 * old approach of multiple scanf occurrences with large numbers of
477 * args. */
478
479/* static const char * const ss_fmt[] = { */
480/*  "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
481/*  "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
482/*  "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
483/* }; */
484
485    /* Lie about the size of the int pointed to for %n. */
486#if INT_MAX == LONG_MAX
487static const char * const ss_fmt[] = {
488    "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
489    "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
490    "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
491};
492#else
493static const char * const ss_fmt[] = {
494    "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
495    "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
496    "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
497};
498
499#endif
500
501static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
502{
503    memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
504
505    sscanf(bp, ss_fmt[procnetdev_vsn],
506           &ife->stats.rx_bytes, /* missing for 0 */
507           &ife->stats.rx_packets,
508           &ife->stats.rx_errors,
509           &ife->stats.rx_dropped,
510           &ife->stats.rx_fifo_errors,
511           &ife->stats.rx_frame_errors,
512           &ife->stats.rx_compressed, /* missing for <= 1 */
513           &ife->stats.rx_multicast, /* missing for <= 1 */
514           &ife->stats.tx_bytes, /* missing for 0 */
515           &ife->stats.tx_packets,
516           &ife->stats.tx_errors,
517           &ife->stats.tx_dropped,
518           &ife->stats.tx_fifo_errors,
519           &ife->stats.collisions,
520           &ife->stats.tx_carrier_errors,
521           &ife->stats.tx_compressed /* missing for <= 1 */
522           );
523
524    if (procnetdev_vsn <= 1) {
525        if (procnetdev_vsn == 0) {
526            ife->stats.rx_bytes = 0;
527            ife->stats.tx_bytes = 0;
528        }
529        ife->stats.rx_multicast = 0;
530        ife->stats.rx_compressed = 0;
531        ife->stats.tx_compressed = 0;
532    }
533}
534
535static inline int procnetdev_version(char *buf)
536{
537    if (strstr(buf, "compressed"))
538        return 2;
539    if (strstr(buf, "bytes"))
540        return 1;
541    return 0;
542}
543
544static int if_readlist_proc(char *target)
545{
546    static int proc_read;
547    FILE *fh;
548    char buf[512];
549    struct interface *ife;
550    int err, procnetdev_vsn;
551
552    if (proc_read)
553        return 0;
554    if (!target)
555        proc_read = 1;
556
557    fh = fopen(_PATH_PROCNET_DEV, "r");
558    if (!fh) {
559        bb_perror_msg("Warning: cannot open %s. Limited output.", _PATH_PROCNET_DEV);
560        return if_readconf();
561    }
562    fgets(buf, sizeof buf, fh); /* eat line */
563    fgets(buf, sizeof buf, fh);
564
565    procnetdev_vsn = procnetdev_version(buf);
566
567    err = 0;
568    while (fgets(buf, sizeof buf, fh)) {
569        char *s, name[128];
570
571        s = get_name(name, buf);
572        ife = add_interface(name);
573        get_dev_fields(s, ife, procnetdev_vsn);
574        ife->statistics_valid = 1;
575        if (target && !strcmp(target, name))
576            break;
577    }
578    if (ferror(fh)) {
579        perror(_PATH_PROCNET_DEV);
580        err = -1;
581        proc_read = 0;
582    }
583    fclose(fh);
584    return err;
585}
586
587static int if_readlist(void)
588{
589    int err = if_readlist_proc(NULL);
590
591    if (!err)
592        err = if_readconf();
593    return err;
594}
595
596static int for_all_interfaces(int (*doit) (struct interface *, void *),
597                              void *cookie)
598{
599    struct interface *ife;
600
601    if (!int_list && (if_readlist() < 0))
602        return -1;
603    for (ife = int_list; ife; ife = ife->next) {
604        int err = doit(ife, cookie);
605
606        if (err)
607            return err;
608    }
609    return 0;
610}
611
612/* Fetch the interface configuration from the kernel. */
613static int if_fetch(struct interface *ife)
614{
615    struct ifreq ifr;
616    int fd;
617    char *ifname = ife->name;
618
619    strcpy(ifr.ifr_name, ifname);
620    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
621        return (-1);
622    ife->flags = ifr.ifr_flags;
623
624    strcpy(ifr.ifr_name, ifname);
625    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
626        memset(ife->hwaddr, 0, 32);
627    else
628        memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
629
630    ife->type = ifr.ifr_hwaddr.sa_family;
631
632    strcpy(ifr.ifr_name, ifname);
633    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
634        ife->metric = 0;
635    else
636        ife->metric = ifr.ifr_metric;
637
638    strcpy(ifr.ifr_name, ifname);
639    if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
640        ife->mtu = 0;
641    else
642        ife->mtu = ifr.ifr_mtu;
643
644#ifdef SIOCGIFMAP
645    strcpy(ifr.ifr_name, ifname);
646    if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
647        ife->map = ifr.ifr_map;
648    else
649#endif
650        memset(&ife->map, 0, sizeof(struct ifmap));
651
652#ifdef HAVE_TXQUEUELEN
653    strcpy(ifr.ifr_name, ifname);
654    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
655        ife->tx_queue_len = -1; /* unknown value */
656    else
657        ife->tx_queue_len = ifr.ifr_qlen;
658#else
659    ife->tx_queue_len = -1; /* unknown value */
660#endif
661
662    /* IPv4 address? */
663    fd = get_socket_for_af(AF_INET);
664    if (fd >= 0) {
665        strcpy(ifr.ifr_name, ifname);
666        ifr.ifr_addr.sa_family = AF_INET;
667        if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
668            ife->has_ip = 1;
669            ife->addr = ifr.ifr_addr;
670            strcpy(ifr.ifr_name, ifname);
671            if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
672                memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
673            else
674                ife->dstaddr = ifr.ifr_dstaddr;
675
676            strcpy(ifr.ifr_name, ifname);
677            if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
678                memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
679            else
680                ife->broadaddr = ifr.ifr_broadaddr;
681
682            strcpy(ifr.ifr_name, ifname);
683            if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
684                memset(&ife->netmask, 0, sizeof(struct sockaddr));
685            else
686                ife->netmask = ifr.ifr_netmask;
687        } else
688            memset(&ife->addr, 0, sizeof(struct sockaddr));
689    }
690
691    return 0;
692}
693
694
695static int do_if_fetch(struct interface *ife)
696{
697    if (if_fetch(ife) < 0) {
698        char *errmsg;
699
700        if (errno == ENODEV) {
701            /* Give better error message for this case. */
702            errmsg = "Device not found";
703        } else {
704            errmsg = strerror(errno);
705        }
706        bb_error_msg("%s: error fetching interface information: %s",
707                ife->name, errmsg);
708        return -1;
709    }
710    return 0;
711}
712
713/* This structure defines hardware protocols and their handlers. */
714struct hwtype {
715    const char * const name;
716    const char *title;
717    int type;
718    int alen;
719    char *(*print) (unsigned char *);
720    int (*input) (char *, struct sockaddr *);
721    int (*activate) (int fd);
722    int suppress_null_addr;
723};
724
725static const struct hwtype unspec_hwtype = {
726    .name =     "unspec",
727    .title =    "UNSPEC",
728    .type =     -1,
729    .print =    UNSPEC_print
730};
731
732static const struct hwtype loop_hwtype = {
733    .name =     "loop",
734    .title =    "Local Loopback",
735    .type =     ARPHRD_LOOPBACK
736};
737
738#include <net/if_arp.h>
739
740#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
741#include <net/ethernet.h>
742#else
743#include <linux/if_ether.h>
744#endif
745
746/* Display an Ethernet address in readable format. */
747static char *pr_ether(unsigned char *ptr)
748{
749    static char buff[64];
750
751    snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
752             (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
753             (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
754        );
755    return (buff);
756}
757
758static const struct hwtype ether_hwtype = {
759    .name =     "ether",
760    .title =    "Ethernet",
761    .type =     ARPHRD_ETHER,
762    .alen =     ETH_ALEN,
763    .print =    pr_ether
764};
765
766#include <net/if_arp.h>
767
768static const struct hwtype ppp_hwtype = {
769    .name =     "ppp",
770    .title =    "Point-to-Point Protocol",
771    .type =     ARPHRD_PPP
772};
773
774#ifdef CONFIG_FEATURE_IPV6
775static const struct hwtype sit_hwtype = {
776    .name =         "sit",
777    .title =        "IPv6-in-IPv4",
778    .type =         ARPHRD_SIT,
779    .print =        UNSPEC_print,
780    .suppress_null_addr =   1
781} ;
782#endif
783
784static const struct hwtype * const hwtypes[] = {
785    &loop_hwtype,
786    &ether_hwtype,
787    &ppp_hwtype,
788    &unspec_hwtype,
789#ifdef CONFIG_FEATURE_IPV6
790    &sit_hwtype,
791#endif
792    NULL
793};
794
795#ifdef IFF_PORTSEL
796static const char * const if_port_text[] = {
797    /* Keep in step with <linux/netdevice.h> */
798    "unknown",
799    "10base2",
800    "10baseT",
801    "AUI",
802    "100baseT",
803    "100baseTX",
804    "100baseFX",
805    NULL
806};
807#endif
808
809/* Check our hardware type table for this type. */
810static const struct hwtype *get_hwntype(int type)
811{
812    const struct hwtype * const *hwp;
813
814    hwp = hwtypes;
815    while (*hwp != NULL) {
816        if ((*hwp)->type == type)
817            return (*hwp);
818        hwp++;
819    }
820    return (NULL);
821}
822
823/* return 1 if address is all zeros */
824static int hw_null_address(const struct hwtype *hw, void *ap)
825{
826    unsigned int i;
827    unsigned char *address = (unsigned char *) ap;
828
829    for (i = 0; i < hw->alen; i++)
830        if (address[i])
831            return 0;
832    return 1;
833}
834
835static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
836
837static void print_bytes_scaled(unsigned long long ull, const char *end)
838{
839    unsigned long long int_part;
840    const char *ext;
841    unsigned int frac_part;
842    int i;
843
844    frac_part = 0;
845    ext = TRext;
846    int_part = ull;
847    i = 4;
848    do {
849        if (int_part >= 1024) {
850            frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
851            int_part /= 1024;
852            ext += 3;   /* KiB, MiB, GiB, TiB */
853        }
854        --i;
855    } while (i);
856
857    printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
858}
859
860static const char * const ife_print_flags_strs[] = {
861    "UP ",
862    "BROADCAST ",
863    "DEBUG ",
864    "LOOPBACK ",
865    "POINTOPOINT ",
866    "NOTRAILERS ",
867    "RUNNING ",
868    "NOARP ",
869    "PROMISC ",
870    "ALLMULTI ",
871    "SLAVE ",
872    "MASTER ",
873    "MULTICAST ",
874#ifdef HAVE_DYNAMIC
875    "DYNAMIC "
876#endif
877};
878
879static const unsigned short ife_print_flags_mask[] = {
880    IFF_UP,
881    IFF_BROADCAST,
882    IFF_DEBUG,
883    IFF_LOOPBACK,
884    IFF_POINTOPOINT,
885    IFF_NOTRAILERS,
886    IFF_RUNNING,
887    IFF_NOARP,
888    IFF_PROMISC,
889    IFF_ALLMULTI,
890    IFF_SLAVE,
891    IFF_MASTER,
892    IFF_MULTICAST,
893#ifdef HAVE_DYNAMIC
894    IFF_DYNAMIC
895#endif
896    0
897};
898
899static void ife_print(struct interface *ptr)
900{
901    struct aftype *ap;
902    const struct hwtype *hw;
903    int hf;
904    int can_compress = 0;
905
906#if HAVE_AFINET6
907    FILE *f;
908    char addr6[40], devname[20];
909    struct sockaddr_in6 sap;
910    int plen, scope, dad_status, if_idx;
911    char addr6p[8][5];
912#endif
913
914    ap = get_afntype(ptr->addr.sa_family);
915    if (ap == NULL)
916        ap = get_afntype(0);
917
918    hf = ptr->type;
919
920    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
921        can_compress = 1;
922
923    hw = get_hwntype(hf);
924    if (hw == NULL)
925        hw = get_hwntype(-1);
926
927    printf("%-9.9s Link encap:%s  ", ptr->name, hw->title);
928    /* For some hardware types (eg Ash, ATM) we don't print the
929       hardware address if it's null.  */
930    if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
931                                hw->suppress_null_addr)))
932        printf("HWaddr %s  ", hw->print((unsigned char *)ptr->hwaddr));
933#ifdef IFF_PORTSEL
934    if (ptr->flags & IFF_PORTSEL) {
935        printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
936        if (ptr->flags & IFF_AUTOMEDIA)
937            printf("(auto)");
938    }
939#endif
940    printf("\n");
941
942    if (ptr->has_ip) {
943        printf("          %s addr:%s ", ap->name,
944               ap->sprint(&ptr->addr, 1));
945        if (ptr->flags & IFF_POINTOPOINT) {
946            printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
947        }
948        if (ptr->flags & IFF_BROADCAST) {
949            printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
950        }
951        printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
952    }
953
954#if HAVE_AFINET6
955
956#define IPV6_ADDR_ANY           0x0000U
957
958#define IPV6_ADDR_UNICAST       0x0001U
959#define IPV6_ADDR_MULTICAST     0x0002U
960#define IPV6_ADDR_ANYCAST       0x0004U
961
962#define IPV6_ADDR_LOOPBACK      0x0010U
963#define IPV6_ADDR_LINKLOCAL     0x0020U
964#define IPV6_ADDR_SITELOCAL     0x0040U
965
966#define IPV6_ADDR_COMPATv4      0x0080U
967
968#define IPV6_ADDR_SCOPE_MASK    0x00f0U
969
970#define IPV6_ADDR_MAPPED        0x1000U
971#define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
972
973    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
974        while (fscanf
975               (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
976                addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
977                addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
978                &dad_status, devname) != EOF) {
979            if (!strcmp(devname, ptr->name)) {
980                sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
981                        addr6p[0], addr6p[1], addr6p[2], addr6p[3],
982                        addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
983                inet_pton(AF_INET6, addr6,
984                          (struct sockaddr *) &sap.sin6_addr);
985                sap.sin6_family = AF_INET6;
986                printf("          inet6 addr: %s/%d",
987                       inet6_aftype.sprint((struct sockaddr *) &sap, 1),
988                       plen);
989                printf(" Scope:");
990                switch (scope & IPV6_ADDR_SCOPE_MASK) {
991                case 0:
992                    printf("Global");
993                    break;
994                case IPV6_ADDR_LINKLOCAL:
995                    printf("Link");
996                    break;
997                case IPV6_ADDR_SITELOCAL:
998                    printf("Site");
999                    break;
1000                case IPV6_ADDR_COMPATv4:
1001                    printf("Compat");
1002                    break;
1003                case IPV6_ADDR_LOOPBACK:
1004                    printf("Host");
1005                    break;
1006                default:
1007                    printf("Unknown");
1008                }
1009                printf("\n");
1010            }
1011        }
1012        fclose(f);
1013    }
1014#endif
1015
1016    printf("          ");
1017    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1018
1019    if (ptr->flags == 0) {
1020        printf("[NO FLAGS] ");
1021    } else {
1022        int i = 0;
1023        do {
1024            if (ptr->flags & ife_print_flags_mask[i]) {
1025                printf(ife_print_flags_strs[i]);
1026            }
1027        } while (ife_print_flags_mask[++i]);
1028    }
1029
1030    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1031    printf(" MTU:%d  Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1032#ifdef SIOCSKEEPALIVE
1033    if (ptr->outfill || ptr->keepalive)
1034        printf("  Outfill:%d  Keepalive:%d", ptr->outfill, ptr->keepalive);
1035#endif
1036    printf("\n");
1037
1038    /* If needed, display the interface statistics. */
1039
1040    if (ptr->statistics_valid) {
1041        /* XXX: statistics are currently only printed for the primary address,
1042         *      not for the aliases, although strictly speaking they're shared
1043         *      by all addresses.
1044         */
1045        printf("          ");
1046
1047        printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1048               ptr->stats.rx_packets, ptr->stats.rx_errors,
1049               ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1050               ptr->stats.rx_frame_errors);
1051        if (can_compress)
1052            printf("             compressed:%lu\n",
1053                   ptr->stats.rx_compressed);
1054        printf("          ");
1055        printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1056               ptr->stats.tx_packets, ptr->stats.tx_errors,
1057               ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1058               ptr->stats.tx_carrier_errors);
1059        printf("          collisions:%lu ", ptr->stats.collisions);
1060        if (can_compress)
1061            printf("compressed:%lu ", ptr->stats.tx_compressed);
1062        if (ptr->tx_queue_len != -1)
1063            printf("txqueuelen:%d ", ptr->tx_queue_len);
1064        printf("\n          R");
1065        print_bytes_scaled(ptr->stats.rx_bytes, "  T");
1066        print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1067
1068    }
1069
1070    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1071         ptr->map.base_addr)) {
1072        printf("          ");
1073        if (ptr->map.irq)
1074            printf("Interrupt:%d ", ptr->map.irq);
1075        if (ptr->map.base_addr >= 0x100)    /* Only print devices using it for
1076                                               I/O maps */
1077            printf("Base address:0x%lx ",
1078                   (unsigned long) ptr->map.base_addr);
1079        if (ptr->map.mem_start) {
1080            printf("Memory:%lx-%lx ", ptr->map.mem_start,
1081                   ptr->map.mem_end);
1082        }
1083        if (ptr->map.dma)
1084            printf("DMA chan:%x ", ptr->map.dma);
1085        printf("\n");
1086    }
1087    printf("\n");
1088}
1089
1090
1091static int do_if_print(struct interface *ife, void *cookie)
1092{
1093    int *opt_a = (int *) cookie;
1094    int res;
1095
1096    res = do_if_fetch(ife);
1097    if (res >= 0) {
1098        if ((ife->flags & IFF_UP) || *opt_a)
1099            ife_print(ife);
1100    }
1101    return res;
1102}
1103
1104static struct interface *lookup_interface(char *name)
1105{
1106    struct interface *ife = NULL;
1107
1108    if (if_readlist_proc(name) < 0)
1109        return NULL;
1110    ife = add_interface(name);
1111    return ife;
1112}
1113
1114/* for ipv4 add/del modes */
1115static int if_print(char *ifname)
1116{
1117    int res;
1118
1119    if (!ifname) {
1120        res = for_all_interfaces(do_if_print, &interface_opt_a);
1121    } else {
1122        struct interface *ife;
1123
1124        ife = lookup_interface(ifname);
1125        res = do_if_fetch(ife);
1126        if (res >= 0)
1127            ife_print(ife);
1128    }
1129    return res;
1130}
1131
1132int display_interfaces(char *ifname);
1133int display_interfaces(char *ifname)
1134{
1135    int status;
1136
1137    /* Create a channel to the NET kernel. */
1138    if ((skfd = sockets_open(0)) < 0) {
1139        bb_perror_msg_and_die("socket");
1140    }
1141
1142    /* Do we have to show the current setup? */
1143    status = if_print(ifname);
1144#ifdef CONFIG_FEATURE_CLEAN_UP
1145    sockets_close();
1146#endif
1147    exit(status < 0);
1148}
Note: See TracBrowser for help on using the repository browser.