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