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