Move sed over to the generic llist_t for append. Saves about 90 bytes.
[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  * Pruned unused code using KEEP_UNUSED define.
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  *              This program is free software; you can redistribute it
24  *              and/or  modify it under  the terms of  the GNU General
25  *              Public  License as  published  by  the  Free  Software
26  *              Foundation;  either  version 2 of the License, or  (at
27  *              your option) any later version.
28  *
29  * Patched to support 'add' and 'del' keywords for INET(4) addresses
30  * by Mrs. Brisby <mrs.brisby@nimh.org>
31  *
32  * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
33  *                     - gettext instead of catgets for i18n
34  *          10/1998  - Andi Kleen. Use interface list primitives.
35  *          20001008 - Bernd Eckenfels, Patch from RH for setting mtu
36  *                      (default AF was wrong)
37  */
38
39 /* #define KEEP_UNUSED */
40
41 /*
42  *
43  * Protocol Families.
44  *
45  */
46 #define HAVE_AFINET 1
47
48 /*
49  *
50  * Device Hardware types.
51  *
52  */
53 #define HAVE_HWETHER    1
54 #define HAVE_HWPPP      1
55 #undef HAVE_HWSLIP
56
57
58 #include "inet_common.h"
59 #include <stdio.h>
60 #include <errno.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <fcntl.h>
65 #include <ctype.h>
66 #include <sys/ioctl.h>
67 #include <sys/types.h>
68 #include <net/if.h>
69 #include <net/if_arp.h>
70 #include "busybox.h"
71
72 #ifdef CONFIG_FEATURE_IPV6
73 # define HAVE_AFINET6 1
74 #else
75 # undef HAVE_AFINET6
76 #endif
77
78 #define _PATH_PROCNET_DEV               "/proc/net/dev"
79 #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
80 #define new(p) ((p) = xcalloc(1,sizeof(*(p))))
81 #define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
82
83 #ifdef HAVE_HWSLIP
84 #include <net/if_slip.h>
85 #endif
86
87 #if HAVE_AFINET6
88
89 #ifndef _LINUX_IN6_H
90 /*
91  *    This is in linux/include/net/ipv6.h.
92  */
93
94 struct in6_ifreq {
95         struct in6_addr ifr6_addr;
96         uint32_t ifr6_prefixlen;
97         unsigned int ifr6_ifindex;
98 };
99
100 #endif
101
102 #endif                                                  /* HAVE_AFINET6 */
103
104 /* Defines for glibc2.0 users. */
105 #ifndef SIOCSIFTXQLEN
106 #define SIOCSIFTXQLEN      0x8943
107 #define SIOCGIFTXQLEN      0x8942
108 #endif
109
110 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
111 #ifndef ifr_qlen
112 #define ifr_qlen        ifr_ifru.ifru_mtu
113 #endif
114
115 #ifndef HAVE_TXQUEUELEN
116 #define HAVE_TXQUEUELEN 1
117 #endif
118
119 #ifndef IFF_DYNAMIC
120 #define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
121 #endif
122
123 /* This structure defines protocol families and their handlers. */
124 struct aftype {
125         const char *name;
126         const char *title;
127         int af;
128         int alen;
129         char *(*print) (unsigned char *);
130         char *(*sprint) (struct sockaddr *, int numeric);
131         int (*input) (int type, char *bufp, struct sockaddr *);
132         void (*herror) (char *text);
133         int (*rprint) (int options);
134         int (*rinput) (int typ, int ext, char **argv);
135
136         /* may modify src */
137         int (*getmask) (char *src, struct sockaddr * mask, char *name);
138
139         int fd;
140         char *flag_file;
141 };
142
143 #ifdef KEEP_UNUSED
144
145 static int flag_unx;
146 static int flag_inet;
147
148 static struct aftrans_t {
149         char *alias;
150         char *name;
151         int *flag;
152 } aftrans[] = {
153
154         {
155         "ip", "inet", &flag_inet},
156 #ifdef HAVE_AFINET6
157         {
158         "ip6", "inet6", &flag_inet6},
159 #endif
160         {
161         "inet", "inet", &flag_inet},
162 #ifdef HAVE_AFINET6
163         {
164         "inet6", "inet6", &flag_inet6},
165 #endif
166         {
167         "unix", "unix", &flag_unx}, {
168         "tcpip", "inet", &flag_inet},
169         {
170         0, 0, 0}
171 };
172
173 static char afname[256] = "";
174 #endif                                                  /* KEEP_UNUSED */
175
176 #if HAVE_AFUNIX
177
178 /* Display a UNIX domain address. */
179 static char *UNIX_print(unsigned char *ptr)
180 {
181         return (ptr);
182 }
183
184
185 /* Display a UNIX domain address. */
186 static char *UNIX_sprint(struct sockaddr *sap, int numeric)
187 {
188         static char buf[64];
189
190         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
191                 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
192         return (UNIX_print(sap->sa_data));
193 }
194
195
196 static struct aftype unix_aftype = {
197         "unix", "UNIX Domain", AF_UNIX, 0,
198         UNIX_print, UNIX_sprint, NULL, NULL,
199         NULL, NULL, NULL,
200         -1,
201         "/proc/net/unix"
202 };
203 #endif                                                  /* HAVE_AFUNIX */
204
205 #if HAVE_AFINET
206
207 #ifdef KEEP_UNUSED
208 static void INET_reserror(char *text)
209 {
210         herror(text);
211 }
212
213 /* Display an Internet socket address. */
214 static char *INET_print(unsigned char *ptr)
215 {
216         return (inet_ntoa((*(struct in_addr *) ptr)));
217 }
218 #endif                                                  /* KEEP_UNUSED */
219
220 /* Display an Internet socket address. */
221 static char *INET_sprint(struct sockaddr *sap, int numeric)
222 {
223         static char buff[128];
224
225         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
226                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
227
228         if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
229                                           numeric, 0xffffff00) != 0)
230                 return (NULL);
231
232         return (buff);
233 }
234
235 #ifdef KEEP_UNUSED
236 static char *INET_sprintmask(struct sockaddr *sap, int numeric,
237                                                          unsigned int netmask)
238 {
239         static char buff[128];
240
241         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
242                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
243         if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
244                                           numeric, netmask) != 0)
245                 return (NULL);
246         return (buff);
247 }
248
249 static int INET_getsock(char *bufp, struct sockaddr *sap)
250 {
251         char *sp = bufp, *bp;
252         unsigned int i;
253         unsigned val;
254         struct sockaddr_in *sin;
255
256         sin = (struct sockaddr_in *) sap;
257         sin->sin_family = AF_INET;
258         sin->sin_port = 0;
259
260         val = 0;
261         bp = (char *) &val;
262         for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
263                 *sp = toupper(*sp);
264
265                 if ((*sp >= 'A') && (*sp <= 'F'))
266                         bp[i] |= (int) (*sp - 'A') + 10;
267                 else if ((*sp >= '0') && (*sp <= '9'))
268                         bp[i] |= (int) (*sp - '0');
269                 else
270                         return (-1);
271
272                 bp[i] <<= 4;
273                 sp++;
274                 *sp = toupper(*sp);
275
276                 if ((*sp >= 'A') && (*sp <= 'F'))
277                         bp[i] |= (int) (*sp - 'A') + 10;
278                 else if ((*sp >= '0') && (*sp <= '9'))
279                         bp[i] |= (int) (*sp - '0');
280                 else
281                         return (-1);
282
283                 sp++;
284         }
285         sin->sin_addr.s_addr = htonl(val);
286
287         return (sp - bufp);
288 }
289
290 static int INET_input(int type, char *bufp, struct sockaddr *sap)
291 {
292         switch (type) {
293         case 1:
294                 return (INET_getsock(bufp, sap));
295         case 256:
296                 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
297         default:
298                 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
299         }
300 }
301
302 static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
303 {
304         struct sockaddr_in *mask = (struct sockaddr_in *) m;
305         char *slash, *end;
306         int prefix;
307
308         if ((slash = strchr(adr, '/')) == NULL)
309                 return 0;
310
311         *slash++ = '\0';
312         prefix = strtoul(slash, &end, 0);
313         if (*end != '\0')
314                 return -1;
315
316         if (name) {
317                 sprintf(name, "/%d", prefix);
318         }
319         mask->sin_family = AF_INET;
320         mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
321         return 1;
322 }
323 #endif                                                  /* KEEP_UNUSED */
324
325 static struct aftype inet_aftype = {
326         "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
327         NULL /* UNUSED INET_print */ , INET_sprint,
328         NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
329         NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
330         NULL /* UNUSED INET_getnetmask */ ,
331         -1,
332         NULL
333 };
334
335 #endif                                                  /* HAVE_AFINET */
336
337 #if HAVE_AFINET6
338
339 #ifdef KEEP_UNUSED
340 static void INET6_reserror(char *text)
341 {
342         herror(text);
343 }
344
345 /* Display an Internet socket address. */
346 static char *INET6_print(unsigned char *ptr)
347 {
348         static char name[80];
349
350         inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
351         return name;
352 }
353 #endif                                                  /* KEEP_UNUSED */
354
355 /* Display an Internet socket address. */
356 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
357 static char *INET6_sprint(struct sockaddr *sap, int numeric)
358 {
359         static char buff[128];
360
361         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
362                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
363         if (INET6_rresolve
364                 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
365                 return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
366         return (buff);
367 }
368
369 #ifdef KEEP_UNUSED
370 static int INET6_getsock(char *bufp, struct sockaddr *sap)
371 {
372         struct sockaddr_in6 *sin6;
373
374         sin6 = (struct sockaddr_in6 *) sap;
375         sin6->sin6_family = AF_INET6;
376         sin6->sin6_port = 0;
377
378         if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
379                 return (-1);
380
381         return 16;                      /* ?;) */
382 }
383
384 static int INET6_input(int type, char *bufp, struct sockaddr *sap)
385 {
386         switch (type) {
387         case 1:
388                 return (INET6_getsock(bufp, sap));
389         default:
390                 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
391         }
392 }
393 #endif                                                  /* KEEP_UNUSED */
394
395 static struct aftype inet6_aftype = {
396         "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
397         NULL /* UNUSED INET6_print */ , INET6_sprint,
398         NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
399         NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
400         NULL /* UNUSED INET6_getnetmask */ ,
401         -1,
402         NULL
403 };
404
405 #endif                                                  /* HAVE_AFINET6 */
406
407 /* Display an UNSPEC address. */
408 static char *UNSPEC_print(unsigned char *ptr)
409 {
410         static char buff[sizeof(struct sockaddr) * 3 + 1];
411         char *pos;
412         unsigned int i;
413
414         pos = buff;
415         for (i = 0; i < sizeof(struct sockaddr); i++) {
416                 /* careful -- not every libc's sprintf returns # bytes written */
417                 sprintf(pos, "%02X-", (*ptr++ & 0377));
418                 pos += 3;
419         }
420         /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
421         *--pos = '\0';
422         return (buff);
423 }
424
425 /* Display an UNSPEC socket address. */
426 static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
427 {
428         static char buf[64];
429
430         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
431                 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
432         return (UNSPEC_print((unsigned char *)sap->sa_data));
433 }
434
435 static struct aftype unspec_aftype = {
436         "unspec", "UNSPEC", AF_UNSPEC, 0,
437         UNSPEC_print, UNSPEC_sprint, NULL, NULL,
438         NULL,
439 };
440
441 static struct aftype * const aftypes[] = {
442 #if HAVE_AFUNIX
443         &unix_aftype,
444 #endif
445 #if HAVE_AFINET
446         &inet_aftype,
447 #endif
448 #if HAVE_AFINET6
449         &inet6_aftype,
450 #endif
451         &unspec_aftype,
452         NULL
453 };
454
455 #ifdef KEEP_UNUSED
456 static short sVafinit = 0;
457
458 static void afinit()
459 {
460         unspec_aftype.title = _("UNSPEC");
461 #if HAVE_AFUNIX
462         unix_aftype.title = _("UNIX Domain");
463 #endif
464 #if HAVE_AFINET
465         inet_aftype.title = _("DARPA Internet");
466 #endif
467 #if HAVE_AFINET6
468         inet6_aftype.title = _("IPv6");
469 #endif
470         sVafinit = 1;
471 }
472
473 static int aftrans_opt(const char *arg)
474 {
475         struct aftrans_t *paft;
476         char *tmp1, *tmp2;
477         char buf[256];
478
479         safe_strncpy(buf, arg, sizeof(buf));
480
481         tmp1 = buf;
482
483         while (tmp1) {
484
485                 tmp2 = strchr(tmp1, ',');
486
487                 if (tmp2)
488                         *(tmp2++) = '\0';
489
490                 paft = aftrans;
491                 for (paft = aftrans; paft->alias; paft++) {
492                         if (strcmp(tmp1, paft->alias))
493                                 continue;
494                         if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
495                                 bb_error_msg(_("Too many address family arguments."));
496                                 return (0);
497                         }
498                         if (paft->flag)
499                                 (*paft->flag)++;
500                         if (afname[0])
501                                 strcat(afname, ",");
502                         strcat(afname, paft->name);
503                         break;
504                 }
505                 if (!paft->alias) {
506                         bb_error_msg(_("Unknown address family `%s'."), tmp1);
507                         return (1);
508                 }
509                 tmp1 = tmp2;
510         }
511
512         return (0);
513 }
514
515 /* set the default AF list from the program name or a constant value    */
516 static void aftrans_def(char *tool, char *argv0, char *dflt)
517 {
518         char *tmp;
519         char *buf;
520
521         strcpy(afname, dflt);
522
523         if (!(tmp = strrchr(argv0, '/')))
524                 tmp = argv0;    /* no slash?! */
525         else
526                 tmp++;
527
528         if (!(buf = strdup(tmp)))
529                 return;
530
531         if (strlen(tool) >= strlen(tmp)) {
532                 free(buf);
533                 return;
534         }
535         tmp = buf + (strlen(tmp) - strlen(tool));
536
537         if (strcmp(tmp, tool) != 0) {
538                 free(buf);
539                 return;
540         }
541         *tmp = '\0';
542         if ((tmp = strchr(buf, '_')))
543                 *tmp = '\0';
544
545         afname[0] = '\0';
546         if (aftrans_opt(buf))
547                 strcpy(afname, buf);
548
549         free(buf);
550 }
551
552 /* Check our protocol family table for this family. */
553 static struct aftype *get_aftype(const char *name)
554 {
555         struct aftype * const *afp;
556
557 #ifdef KEEP_UNUSED
558         if (!sVafinit)
559                 afinit();
560 #endif                                                  /* KEEP_UNUSED */
561
562         afp = aftypes;
563         while (*afp != NULL) {
564                 if (!strcmp((*afp)->name, name))
565                         return (*afp);
566                 afp++;
567         }
568         if (strchr(name, ','))
569                 bb_error_msg(_("Please don't supply more than one address family."));
570         return (NULL);
571 }
572 #endif                                                  /* KEEP_UNUSED */
573
574 /* Check our protocol family table for this family. */
575 static struct aftype *get_afntype(int af)
576 {
577         struct aftype * const *afp;
578
579 #ifdef KEEP_UNUSED
580         if (!sVafinit)
581                 afinit();
582 #endif                                                  /* KEEP_UNUSED */
583
584         afp = aftypes;
585         while (*afp != NULL) {
586                 if ((*afp)->af == af)
587                         return (*afp);
588                 afp++;
589         }
590         return (NULL);
591 }
592
593 /* Check our protocol family table for this family and return its socket */
594 static int get_socket_for_af(int af)
595 {
596         struct aftype * const *afp;
597
598 #ifdef KEEP_UNUSED
599         if (!sVafinit)
600                 afinit();
601 #endif                                                  /* KEEP_UNUSED */
602
603         afp = aftypes;
604         while (*afp != NULL) {
605                 if ((*afp)->af == af)
606                         return (*afp)->fd;
607                 afp++;
608         }
609         return -1;
610 }
611
612 #ifdef KEEP_UNUSED
613 /* type: 0=all, 1=getroute */
614 static void print_aflist(int type)
615 {
616         int count = 0;
617         char *txt;
618         struct aftype * const *afp;
619
620 #ifdef KEEP_UNUSED
621         if (!sVafinit)
622                 afinit();
623 #endif                                                  /* KEEP_UNUSED */
624
625         afp = aftypes;
626         while (*afp != NULL) {
627                 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
628                         afp++;
629                         continue;
630                 }
631                 if ((count % 3) == 0)
632                         fprintf(stderr, count ? "\n    " : "    ");
633                 txt = (*afp)->name;
634                 if (!txt)
635                         txt = "..";
636                 fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
637                 count++;
638                 afp++;
639         }
640         fprintf(stderr, "\n");
641 }
642 #endif                                                  /* KEEP_UNUSED */
643
644 struct user_net_device_stats {
645         unsigned long long rx_packets;  /* total packets received       */
646         unsigned long long tx_packets;  /* total packets transmitted    */
647         unsigned long long rx_bytes;    /* total bytes received         */
648         unsigned long long tx_bytes;    /* total bytes transmitted      */
649         unsigned long rx_errors;        /* bad packets received         */
650         unsigned long tx_errors;        /* packet transmit problems     */
651         unsigned long rx_dropped;       /* no space in linux buffers    */
652         unsigned long tx_dropped;       /* no space available in linux  */
653         unsigned long rx_multicast;     /* multicast packets received   */
654         unsigned long rx_compressed;
655         unsigned long tx_compressed;
656         unsigned long collisions;
657
658         /* detailed rx_errors: */
659         unsigned long rx_length_errors;
660         unsigned long rx_over_errors;   /* receiver ring buff overflow  */
661         unsigned long rx_crc_errors;    /* recved pkt with crc error    */
662         unsigned long rx_frame_errors;  /* recv'd frame alignment error */
663         unsigned long rx_fifo_errors;   /* recv'r fifo overrun          */
664         unsigned long rx_missed_errors; /* receiver missed packet     */
665         /* detailed tx_errors */
666         unsigned long tx_aborted_errors;
667         unsigned long tx_carrier_errors;
668         unsigned long tx_fifo_errors;
669         unsigned long tx_heartbeat_errors;
670         unsigned long tx_window_errors;
671 };
672
673 struct interface {
674         struct interface *next, *prev;
675         char name[IFNAMSIZ];    /* interface name        */
676         short type;                     /* if type               */
677         short flags;            /* various flags         */
678         int metric;                     /* routing metric        */
679         int mtu;                        /* MTU value             */
680         int tx_queue_len;       /* transmit queue length */
681         struct ifmap map;       /* hardware setup        */
682         struct sockaddr addr;   /* IP address            */
683         struct sockaddr dstaddr;        /* P-P IP address        */
684         struct sockaddr broadaddr;      /* IP broadcast address  */
685         struct sockaddr netmask;        /* IP network mask       */
686         int has_ip;
687         char hwaddr[32];        /* HW address            */
688         int statistics_valid;
689         struct user_net_device_stats stats;     /* statistics            */
690         int keepalive;          /* keepalive value for SLIP */
691         int outfill;            /* outfill value for SLIP */
692 };
693
694
695 int interface_opt_a = 0;        /* show all interfaces          */
696
697 #ifdef KEEP_UNUSED
698 static int opt_i = 0;   /* show the statistics          */
699 static int opt_v = 0;   /* debugging output flag        */
700
701 static int addr_family = 0;     /* currently selected AF        */
702 #endif                                                  /* KEEP_UNUSED */
703
704 static struct interface *int_list, *int_last;
705 static int skfd = -1;   /* generic raw socket desc.     */
706
707
708 static int sockets_open(int family)
709 {
710         struct aftype * const *aft;
711         int sfd = -1;
712         static int force = -1;
713
714         if (force < 0) {
715                 force = 0;
716                 if (get_kernel_revision() < KRELEASE(2, 1, 0))
717                         force = 1;
718                 if (access("/proc/net", R_OK))
719                         force = 1;
720         }
721         for (aft = aftypes; *aft; aft++) {
722                 struct aftype *af = *aft;
723                 int type = SOCK_DGRAM;
724
725                 if (af->af == AF_UNSPEC)
726                         continue;
727                 if (family && family != af->af)
728                         continue;
729                 if (af->fd != -1) {
730                         sfd = af->fd;
731                         continue;
732                 }
733                 /* Check some /proc file first to not stress kmod */
734                 if (!family && !force && af->flag_file) {
735                         if (access(af->flag_file, R_OK))
736                                 continue;
737                 }
738                 af->fd = socket(af->af, type, 0);
739                 if (af->fd >= 0)
740                         sfd = af->fd;
741         }
742         if (sfd < 0) {
743                 bb_error_msg(_("No usable address families found."));
744         }
745         return sfd;
746 }
747
748 #ifdef CONFIG_FEATURE_CLEAN_UP
749 static void sockets_close(void)
750 {
751         struct aftype * const *aft;
752         for (aft = aftypes; *aft != NULL; aft++) {
753                 struct aftype *af = *aft;
754                 if( af->fd != -1 ) {
755                         close(af->fd);
756                         af->fd = -1;
757                 }
758         }
759 }
760 #endif
761
762 /* like strcmp(), but knows about numbers */
763 static int nstrcmp(const char *a, const char *b)
764 {
765         const char *a_ptr = a;
766         const char *b_ptr = b;
767
768         while (*a == *b) {
769                 if (*a == '\0') {
770                         return 0;
771                 }
772                 if (!isdigit(*a) && isdigit(*(a+1))) {
773                         a_ptr = a+1;
774                         b_ptr = b+1;
775                 }
776                 a++;
777                 b++;
778         }
779
780         if (isdigit(*a) && isdigit(*b)) {
781                 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
782         }
783         return *a - *b;
784 }
785
786 static struct interface *add_interface(char *name)
787 {
788         struct interface *ife, **nextp, *new;
789
790         for (ife = int_last; ife; ife = ife->prev) {
791                 int n = nstrcmp(ife->name, name);
792
793                 if (n == 0)
794                         return ife;
795                 if (n < 0)
796                         break;
797         }
798         new(new);
799         safe_strncpy(new->name, name, IFNAMSIZ);
800         nextp = ife ? &ife->next : &int_list;
801         new->prev = ife;
802         new->next = *nextp;
803         if (new->next)
804                 new->next->prev = new;
805         else
806                 int_last = new;
807         *nextp = new;
808         return new;
809 }
810
811
812 static int if_readconf(void)
813 {
814         int numreqs = 30;
815         struct ifconf ifc;
816         struct ifreq *ifr;
817         int n, err = -1;
818         int skfd2;
819
820         /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
821            (as of 2.1.128) */
822         skfd2 = get_socket_for_af(AF_INET);
823         if (skfd2 < 0) {
824                 bb_perror_msg(("warning: no inet socket available"));
825                 /* Try to soldier on with whatever socket we can get hold of.  */
826                 skfd2 = sockets_open(0);
827                 if (skfd2 < 0)
828                         return -1;
829         }
830
831         ifc.ifc_buf = NULL;
832         for (;;) {
833                 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
834                 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
835
836                 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
837                         perror("SIOCGIFCONF");
838                         goto out;
839                 }
840                 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
841                         /* assume it overflowed and try again */
842                         numreqs += 10;
843                         continue;
844                 }
845                 break;
846         }
847
848         ifr = ifc.ifc_req;
849         for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
850                 add_interface(ifr->ifr_name);
851                 ifr++;
852         }
853         err = 0;
854
855   out:
856         free(ifc.ifc_buf);
857         return err;
858 }
859
860 static char *get_name(char *name, char *p)
861 {
862         /* Extract <name>[:<alias>] from nul-terminated p where p matches
863            <name>[:<alias>]: after leading whitespace.
864            If match is not made, set name empty and return unchanged p */
865         int namestart=0, nameend=0, aliasend;
866         while (isspace(p[namestart]))
867                 namestart++;
868         nameend=namestart;
869         while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
870                 nameend++;
871         if (p[nameend]==':') {
872                 aliasend=nameend+1;
873                 while (p[aliasend] && isdigit(p[aliasend]))
874                         aliasend++;
875                 if (p[aliasend]==':') {
876                         nameend=aliasend;
877                 }
878                 if ((nameend-namestart)<IFNAMSIZ) {
879                         memcpy(name,&p[namestart],nameend-namestart);
880                         name[nameend-namestart]='\0';
881                         p=&p[nameend];
882                 } else {
883                         /* Interface name too large */
884                         name[0]='\0';
885                 }
886         } else {
887                 /* first ':' not found - return empty */
888                 name[0]='\0';
889         }
890         return p + 1;
891 }
892
893 /* If scanf supports size qualifiers for %n conversions, then we can
894  * use a modified fmt that simply stores the position in the fields
895  * having no associated fields in the proc string.  Of course, we need
896  * to zero them again when we're done.  But that is smaller than the
897  * old approach of multiple scanf occurrences with large numbers of
898  * args. */
899
900 /* static const char * const ss_fmt[] = { */
901 /*      "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
902 /*      "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
903 /*      "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
904 /* }; */
905
906         /* Lie about the size of the int pointed to for %n. */
907 #if INT_MAX == LONG_MAX
908 static const char * const ss_fmt[] = {
909         "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
910         "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
911         "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
912 };
913 #else
914 static const char * const ss_fmt[] = {
915         "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
916         "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
917         "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
918 };
919
920 #endif
921
922 static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
923 {
924         memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
925
926         sscanf(bp, ss_fmt[procnetdev_vsn],
927                    &ife->stats.rx_bytes, /* missing for 0 */
928                    &ife->stats.rx_packets,
929                    &ife->stats.rx_errors,
930                    &ife->stats.rx_dropped,
931                    &ife->stats.rx_fifo_errors,
932                    &ife->stats.rx_frame_errors,
933                    &ife->stats.rx_compressed, /* missing for <= 1 */
934                    &ife->stats.rx_multicast, /* missing for <= 1 */
935                    &ife->stats.tx_bytes, /* missing for 0 */
936                    &ife->stats.tx_packets,
937                    &ife->stats.tx_errors,
938                    &ife->stats.tx_dropped,
939                    &ife->stats.tx_fifo_errors,
940                    &ife->stats.collisions,
941                    &ife->stats.tx_carrier_errors,
942                    &ife->stats.tx_compressed /* missing for <= 1 */
943                    );
944
945         if (procnetdev_vsn <= 1) {
946                 if (procnetdev_vsn == 0) {
947                         ife->stats.rx_bytes = 0;
948                         ife->stats.tx_bytes = 0;
949                 }
950                 ife->stats.rx_multicast = 0;
951                 ife->stats.rx_compressed = 0;
952                 ife->stats.tx_compressed = 0;
953         }
954 }
955
956 static inline int procnetdev_version(char *buf)
957 {
958         if (strstr(buf, "compressed"))
959                 return 2;
960         if (strstr(buf, "bytes"))
961                 return 1;
962         return 0;
963 }
964
965 static int if_readlist_proc(char *target)
966 {
967         static int proc_read;
968         FILE *fh;
969         char buf[512];
970         struct interface *ife;
971         int err, procnetdev_vsn;
972
973         if (proc_read)
974                 return 0;
975         if (!target)
976                 proc_read = 1;
977
978         fh = fopen(_PATH_PROCNET_DEV, "r");
979         if (!fh) {
980                 bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
981                 return if_readconf();
982         }
983         fgets(buf, sizeof buf, fh);     /* eat line */
984         fgets(buf, sizeof buf, fh);
985
986         procnetdev_vsn = procnetdev_version(buf);
987
988         err = 0;
989         while (fgets(buf, sizeof buf, fh)) {
990                 char *s, name[128];
991
992                 s = get_name(name, buf);
993                 ife = add_interface(name);
994                 get_dev_fields(s, ife, procnetdev_vsn);
995                 ife->statistics_valid = 1;
996                 if (target && !strcmp(target, name))
997                         break;
998         }
999         if (ferror(fh)) {
1000                 perror(_PATH_PROCNET_DEV);
1001                 err = -1;
1002                 proc_read = 0;
1003         }
1004         fclose(fh);
1005         return err;
1006 }
1007
1008 static int if_readlist(void)
1009 {
1010         int err = if_readlist_proc(NULL);
1011
1012         if (!err)
1013                 err = if_readconf();
1014         return err;
1015 }
1016
1017 static int for_all_interfaces(int (*doit) (struct interface *, void *),
1018                                                           void *cookie)
1019 {
1020         struct interface *ife;
1021
1022         if (!int_list && (if_readlist() < 0))
1023                 return -1;
1024         for (ife = int_list; ife; ife = ife->next) {
1025                 int err = doit(ife, cookie);
1026
1027                 if (err)
1028                         return err;
1029         }
1030         return 0;
1031 }
1032
1033 /* Fetch the interface configuration from the kernel. */
1034 static int if_fetch(struct interface *ife)
1035 {
1036         struct ifreq ifr;
1037         int fd;
1038         char *ifname = ife->name;
1039
1040         strcpy(ifr.ifr_name, ifname);
1041         if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1042                 return (-1);
1043         ife->flags = ifr.ifr_flags;
1044
1045         strcpy(ifr.ifr_name, ifname);
1046         if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1047                 memset(ife->hwaddr, 0, 32);
1048         else
1049                 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
1050
1051         ife->type = ifr.ifr_hwaddr.sa_family;
1052
1053         strcpy(ifr.ifr_name, ifname);
1054         if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1055                 ife->metric = 0;
1056         else
1057                 ife->metric = ifr.ifr_metric;
1058
1059         strcpy(ifr.ifr_name, ifname);
1060         if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1061                 ife->mtu = 0;
1062         else
1063                 ife->mtu = ifr.ifr_mtu;
1064
1065 #ifdef HAVE_HWSLIP
1066         if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1067                 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1068                 ife->type == ARPHRD_ADAPT) {
1069 #ifdef SIOCGOUTFILL
1070                 strcpy(ifr.ifr_name, ifname);
1071                 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1072                         ife->outfill = 0;
1073                 else
1074                         ife->outfill = (unsigned int) ifr.ifr_data;
1075 #endif
1076 #ifdef SIOCGKEEPALIVE
1077                 strcpy(ifr.ifr_name, ifname);
1078                 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1079                         ife->keepalive = 0;
1080                 else
1081                         ife->keepalive = (unsigned int) ifr.ifr_data;
1082 #endif
1083         }
1084 #endif
1085
1086 #ifdef SIOCGIFMAP
1087         strcpy(ifr.ifr_name, ifname);
1088         if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
1089                 ife->map = ifr.ifr_map;
1090         else
1091 #endif
1092                 memset(&ife->map, 0, sizeof(struct ifmap));
1093
1094 #ifdef HAVE_TXQUEUELEN
1095         strcpy(ifr.ifr_name, ifname);
1096         if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1097                 ife->tx_queue_len = -1; /* unknown value */
1098         else
1099                 ife->tx_queue_len = ifr.ifr_qlen;
1100 #else
1101         ife->tx_queue_len = -1; /* unknown value */
1102 #endif
1103
1104 #if HAVE_AFINET
1105         /* IPv4 address? */
1106         fd = get_socket_for_af(AF_INET);
1107         if (fd >= 0) {
1108                 strcpy(ifr.ifr_name, ifname);
1109                 ifr.ifr_addr.sa_family = AF_INET;
1110                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1111                         ife->has_ip = 1;
1112                         ife->addr = ifr.ifr_addr;
1113                         strcpy(ifr.ifr_name, ifname);
1114                         if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1115                                 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1116                         else
1117                                 ife->dstaddr = ifr.ifr_dstaddr;
1118
1119                         strcpy(ifr.ifr_name, ifname);
1120                         if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1121                                 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1122                         else
1123                                 ife->broadaddr = ifr.ifr_broadaddr;
1124
1125                         strcpy(ifr.ifr_name, ifname);
1126                         if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1127                                 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1128                         else
1129                                 ife->netmask = ifr.ifr_netmask;
1130                 } else
1131                         memset(&ife->addr, 0, sizeof(struct sockaddr));
1132         }
1133 #endif
1134
1135         return 0;
1136 }
1137
1138
1139 static int do_if_fetch(struct interface *ife)
1140 {
1141         if (if_fetch(ife) < 0) {
1142                 char *errmsg;
1143
1144                 if (errno == ENODEV) {
1145                         /* Give better error message for this case. */
1146                         errmsg = _("Device not found");
1147                 } else {
1148                         errmsg = strerror(errno);
1149                 }
1150                 bb_error_msg(_("%s: error fetching interface information: %s"),
1151                                 ife->name, errmsg);
1152                 return -1;
1153         }
1154         return 0;
1155 }
1156
1157 /* This structure defines hardware protocols and their handlers. */
1158 struct hwtype {
1159         const char * const name;
1160         const char *title;
1161         int type;
1162         int alen;
1163         char *(*print) (unsigned char *);
1164         int (*input) (char *, struct sockaddr *);
1165         int (*activate) (int fd);
1166         int suppress_null_addr;
1167 };
1168
1169 static const struct hwtype unspec_hwtype = {
1170         "unspec", "UNSPEC", -1, 0,
1171         UNSPEC_print, NULL, NULL
1172 };
1173
1174 static const struct hwtype loop_hwtype = {
1175         "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1176         NULL, NULL, NULL
1177 };
1178
1179 #if HAVE_HWETHER
1180 #include <net/if_arp.h>
1181
1182 #if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
1183 #include <net/ethernet.h>
1184 #else
1185 #include <linux/if_ether.h>
1186 #endif
1187
1188 /* Display an Ethernet address in readable format. */
1189 static char *pr_ether(unsigned char *ptr)
1190 {
1191         static char buff[64];
1192
1193         snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1194                          (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1195                          (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1196                 );
1197         return (buff);
1198 }
1199
1200 #ifdef KEEP_UNUSED
1201 /* Input an Ethernet address and convert to binary. */
1202 static int in_ether(char *bufp, struct sockaddr *sap)
1203 {
1204         unsigned char *ptr;
1205         char c, *orig;
1206         int i;
1207         unsigned val;
1208
1209         sap->sa_family = ether_hwtype.type;
1210         ptr = sap->sa_data;
1211
1212         i = 0;
1213         orig = bufp;
1214         while ((*bufp != '\0') && (i < ETH_ALEN)) {
1215                 val = 0;
1216                 c = *bufp++;
1217                 if (isdigit(c))
1218                         val = c - '0';
1219                 else if (c >= 'a' && c <= 'f')
1220                         val = c - 'a' + 10;
1221                 else if (c >= 'A' && c <= 'F')
1222                         val = c - 'A' + 10;
1223                 else {
1224 #ifdef DEBUG
1225                         bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
1226 #endif
1227                         errno = EINVAL;
1228                         return (-1);
1229                 }
1230                 val <<= 4;
1231                 c = *bufp;
1232                 if (isdigit(c))
1233                         val |= c - '0';
1234                 else if (c >= 'a' && c <= 'f')
1235                         val |= c - 'a' + 10;
1236                 else if (c >= 'A' && c <= 'F')
1237                         val |= c - 'A' + 10;
1238                 else if (c == ':' || c == 0)
1239                         val >>= 4;
1240                 else {
1241 #ifdef DEBUG
1242                         bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
1243 #endif
1244                         errno = EINVAL;
1245                         return (-1);
1246                 }
1247                 if (c != 0)
1248                         bufp++;
1249                 *ptr++ = (unsigned char) (val & 0377);
1250                 i++;
1251
1252                 /* We might get a semicolon here - not required. */
1253                 if (*bufp == ':') {
1254 #ifdef DEBUG
1255                         if (i == ETH_ALEN) {
1256                                 bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
1257                         }
1258 #endif
1259                         bufp++;
1260                 }
1261         }
1262
1263 #ifdef DEBUG
1264         /* That's it.  Any trailing junk? */
1265         if ((i == ETH_ALEN) && (*bufp != '\0')) {
1266                 bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
1267                 errno = EINVAL;
1268                 return (-1);
1269         }
1270         bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
1271 #endif
1272
1273         return (0);
1274 }
1275 #endif                                                  /* KEEP_UNUSED */
1276
1277
1278 static const struct hwtype ether_hwtype = {
1279         "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1280         pr_ether, NULL /* UNUSED in_ether */ , NULL
1281 };
1282
1283
1284 #endif                                                  /* HAVE_HWETHER */
1285
1286
1287 #if HAVE_HWPPP
1288
1289 #include <net/if_arp.h>
1290
1291 #ifdef KEEP_UNUSED
1292 /* Start the PPP encapsulation on the file descriptor. */
1293 static int do_ppp(int fd)
1294 {
1295         bb_error_msg(_("You cannot start PPP with this program."));
1296         return -1;
1297 }
1298 #endif                                                  /* KEEP_UNUSED */
1299
1300 static const struct hwtype ppp_hwtype = {
1301         "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1302         NULL, NULL, NULL /* UNUSED do_ppp */ , 0
1303 };
1304
1305
1306 #endif                                                  /* HAVE_PPP */
1307
1308 static const struct hwtype * const hwtypes[] = {
1309
1310         &loop_hwtype,
1311
1312 #if HAVE_HWSLIP
1313         &slip_hwtype,
1314         &cslip_hwtype,
1315         &slip6_hwtype,
1316         &cslip6_hwtype,
1317         &adaptive_hwtype,
1318 #endif
1319 #if HAVE_HWSTRIP
1320         &strip_hwtype,
1321 #endif
1322 #if HAVE_HWETHER
1323         &ether_hwtype,
1324 #endif
1325 #if HAVE_HWTUNNEL
1326         &tunnel_hwtype,
1327 #endif
1328 #if HAVE_HWPPP
1329         &ppp_hwtype,
1330 #endif
1331         &unspec_hwtype,
1332         NULL
1333 };
1334
1335 #ifdef KEEP_UNUSED
1336 static short sVhwinit = 0;
1337
1338 static void hwinit()
1339 {
1340         loop_hwtype.title = _("Local Loopback");
1341         unspec_hwtype.title = _("UNSPEC");
1342 #if HAVE_HWSLIP
1343         slip_hwtype.title = _("Serial Line IP");
1344         cslip_hwtype.title = _("VJ Serial Line IP");
1345         slip6_hwtype.title = _("6-bit Serial Line IP");
1346         cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1347         adaptive_hwtype.title = _("Adaptive Serial Line IP");
1348 #endif
1349 #if HAVE_HWETHER
1350         ether_hwtype.title = _("Ethernet");
1351 #endif
1352 #if HAVE_HWTUNNEL
1353         tunnel_hwtype.title = _("IPIP Tunnel");
1354 #endif
1355 #if HAVE_HWPPP
1356         ppp_hwtype.title = _("Point-to-Point Protocol");
1357 #endif
1358         sVhwinit = 1;
1359 }
1360 #endif                                                  /* KEEP_UNUSED */
1361
1362 #ifdef IFF_PORTSEL
1363 #if 0
1364 static const char * const if_port_text[][4] = {
1365         /* Keep in step with <linux/netdevice.h> */
1366         {"unknown", NULL, NULL, NULL},
1367         {"10base2", "bnc", "coax", NULL},
1368         {"10baseT", "utp", "tpe", NULL},
1369         {"AUI", "thick", "db15", NULL},
1370         {"100baseT", NULL, NULL, NULL},
1371         {"100baseTX", NULL, NULL, NULL},
1372         {"100baseFX", NULL, NULL, NULL},
1373         {NULL, NULL, NULL, NULL},
1374 };
1375 #else
1376 static const char * const if_port_text[] = {
1377         /* Keep in step with <linux/netdevice.h> */
1378         "unknown",
1379         "10base2",
1380         "10baseT",
1381         "AUI",
1382         "100baseT",
1383         "100baseTX",
1384         "100baseFX",
1385         NULL
1386 };
1387 #endif
1388 #endif
1389
1390 /* Check our hardware type table for this type. */
1391 static const struct hwtype *get_hwntype(int type)
1392 {
1393         const struct hwtype * const *hwp;
1394
1395 #ifdef KEEP_UNUSED
1396         if (!sVhwinit)
1397                 hwinit();
1398 #endif                                                  /* KEEP_UNUSED */
1399
1400         hwp = hwtypes;
1401         while (*hwp != NULL) {
1402                 if ((*hwp)->type == type)
1403                         return (*hwp);
1404                 hwp++;
1405         }
1406         return (NULL);
1407 }
1408
1409 /* return 1 if address is all zeros */
1410 static int hw_null_address(const struct hwtype *hw, void *ap)
1411 {
1412         unsigned int i;
1413         unsigned char *address = (unsigned char *) ap;
1414
1415         for (i = 0; i < hw->alen; i++)
1416                 if (address[i])
1417                         return 0;
1418         return 1;
1419 }
1420
1421 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
1422
1423 static void print_bytes_scaled(unsigned long long ull, const char *end)
1424 {
1425         unsigned long long int_part;
1426         const char *ext;
1427         unsigned int frac_part;
1428         int i;
1429
1430         frac_part = 0;
1431         ext = TRext;
1432         int_part = ull;
1433         i = 4;
1434         do {
1435 #if 0
1436                 /* This does correct rounding and is a little larger.  But it
1437                  * uses KiB as the smallest displayed unit. */
1438                 if ((int_part < (1024*1024 - 51)) || !--i) {
1439                         i = 0;
1440                         int_part += 51;         /* 1024*.05 = 51.2 */
1441                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1442                 }
1443                 int_part /= 1024;
1444                 ext += 3;       /* KiB, MiB, GiB, TiB */
1445 #else
1446                 if (int_part >= 1024) {
1447                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1448                         int_part /= 1024;
1449                         ext += 3;       /* KiB, MiB, GiB, TiB */
1450                 }
1451                 --i;
1452 #endif
1453         } while (i);
1454
1455         printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
1456 }
1457
1458 static const char * const ife_print_flags_strs[] = {
1459         "UP ",
1460         "BROADCAST ",
1461         "DEBUG ",
1462         "LOOPBACK ",
1463         "POINTOPOINT ",
1464         "NOTRAILERS ",
1465         "RUNNING ",
1466         "NOARP ",
1467         "PROMISC ",
1468         "ALLMULTI ",
1469         "SLAVE ",
1470         "MASTER ",
1471         "MULTICAST ",
1472 #ifdef HAVE_DYNAMIC
1473         "DYNAMIC "
1474 #endif
1475 };
1476
1477 static const unsigned short ife_print_flags_mask[] = {
1478         IFF_UP,
1479         IFF_BROADCAST,
1480         IFF_DEBUG,
1481         IFF_LOOPBACK,
1482         IFF_POINTOPOINT,
1483         IFF_NOTRAILERS,
1484         IFF_RUNNING,
1485         IFF_NOARP,
1486         IFF_PROMISC,
1487         IFF_ALLMULTI,
1488         IFF_SLAVE,
1489         IFF_MASTER,
1490         IFF_MULTICAST,
1491 #ifdef HAVE_DYNAMIC
1492         IFF_DYNAMIC
1493 #endif
1494         0
1495 };
1496
1497 static void ife_print(struct interface *ptr)
1498 {
1499         struct aftype *ap;
1500         const struct hwtype *hw;
1501         int hf;
1502         int can_compress = 0;
1503
1504 #if HAVE_AFINET6
1505         FILE *f;
1506         char addr6[40], devname[20];
1507         struct sockaddr_in6 sap;
1508         int plen, scope, dad_status, if_idx;
1509         char addr6p[8][5];
1510 #endif
1511
1512         ap = get_afntype(ptr->addr.sa_family);
1513         if (ap == NULL)
1514                 ap = get_afntype(0);
1515
1516         hf = ptr->type;
1517
1518         if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1519                 can_compress = 1;
1520
1521         hw = get_hwntype(hf);
1522         if (hw == NULL)
1523                 hw = get_hwntype(-1);
1524
1525         printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
1526         /* For some hardware types (eg Ash, ATM) we don't print the
1527            hardware address if it's null.  */
1528         if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1529                                                                 hw->suppress_null_addr)))
1530                 printf(_("HWaddr %s  "), hw->print((unsigned char *)ptr->hwaddr));
1531 #ifdef IFF_PORTSEL
1532         if (ptr->flags & IFF_PORTSEL) {
1533                 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
1534                 if (ptr->flags & IFF_AUTOMEDIA)
1535                         printf(_("(auto)"));
1536         }
1537 #endif
1538         printf("\n");
1539
1540 #if HAVE_AFINET
1541         if (ptr->has_ip) {
1542                 printf(_("          %s addr:%s "), ap->name,
1543                            ap->sprint(&ptr->addr, 1));
1544                 if (ptr->flags & IFF_POINTOPOINT) {
1545                         printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1546                 }
1547                 if (ptr->flags & IFF_BROADCAST) {
1548                         printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1549                 }
1550                 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1551         }
1552 #endif
1553
1554 #if HAVE_AFINET6
1555
1556 #define IPV6_ADDR_ANY           0x0000U
1557
1558 #define IPV6_ADDR_UNICAST       0x0001U
1559 #define IPV6_ADDR_MULTICAST     0x0002U
1560 #define IPV6_ADDR_ANYCAST       0x0004U
1561
1562 #define IPV6_ADDR_LOOPBACK      0x0010U
1563 #define IPV6_ADDR_LINKLOCAL     0x0020U
1564 #define IPV6_ADDR_SITELOCAL     0x0040U
1565
1566 #define IPV6_ADDR_COMPATv4      0x0080U
1567
1568 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
1569
1570 #define IPV6_ADDR_MAPPED        0x1000U
1571 #define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
1572
1573         if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1574                 while (fscanf
1575                            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1576                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1577                                 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1578                                 &dad_status, devname) != EOF) {
1579                         if (!strcmp(devname, ptr->name)) {
1580                                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1581                                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1582                                                 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1583                                 inet_pton(AF_INET6, addr6,
1584                                                   (struct sockaddr *) &sap.sin6_addr);
1585                                 sap.sin6_family = AF_INET6;
1586                                 printf(_("          inet6 addr: %s/%d"),
1587                                            inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1588                                            plen);
1589                                 printf(_(" Scope:"));
1590                                 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1591                                 case 0:
1592                                         printf(_("Global"));
1593                                         break;
1594                                 case IPV6_ADDR_LINKLOCAL:
1595                                         printf(_("Link"));
1596                                         break;
1597                                 case IPV6_ADDR_SITELOCAL:
1598                                         printf(_("Site"));
1599                                         break;
1600                                 case IPV6_ADDR_COMPATv4:
1601                                         printf(_("Compat"));
1602                                         break;
1603                                 case IPV6_ADDR_LOOPBACK:
1604                                         printf(_("Host"));
1605                                         break;
1606                                 default:
1607                                         printf(_("Unknown"));
1608                                 }
1609                                 printf("\n");
1610                         }
1611                 }
1612                 fclose(f);
1613         }
1614 #endif
1615
1616         printf("          ");
1617         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1618
1619         if (ptr->flags == 0) {
1620                 printf(_("[NO FLAGS] "));
1621         } else {
1622                 int i = 0;
1623                 do {
1624                         if (ptr->flags & ife_print_flags_mask[i]) {
1625                                 printf(_(ife_print_flags_strs[i]));
1626                         }
1627                 } while (ife_print_flags_mask[++i]);
1628         }
1629
1630         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1631         printf(_(" MTU:%d  Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1632 #ifdef SIOCSKEEPALIVE
1633         if (ptr->outfill || ptr->keepalive)
1634                 printf(_("  Outfill:%d  Keepalive:%d"), ptr->outfill, ptr->keepalive);
1635 #endif
1636         printf("\n");
1637
1638         /* If needed, display the interface statistics. */
1639
1640         if (ptr->statistics_valid) {
1641                 /* XXX: statistics are currently only printed for the primary address,
1642                  *      not for the aliases, although strictly speaking they're shared
1643                  *      by all addresses.
1644                  */
1645                 printf("          ");
1646
1647                 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1648                            ptr->stats.rx_packets, ptr->stats.rx_errors,
1649                            ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1650                            ptr->stats.rx_frame_errors);
1651                 if (can_compress)
1652                         printf("             compressed:%lu\n",
1653                                    ptr->stats.rx_compressed);
1654                 printf("          ");
1655                 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1656                            ptr->stats.tx_packets, ptr->stats.tx_errors,
1657                            ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1658                            ptr->stats.tx_carrier_errors);
1659                 printf("          collisions:%lu ", ptr->stats.collisions);
1660                 if (can_compress)
1661                         printf("compressed:%lu ", ptr->stats.tx_compressed);
1662                 if (ptr->tx_queue_len != -1)
1663                         printf("txqueuelen:%d ", ptr->tx_queue_len);
1664                 printf("\n          R");
1665                 print_bytes_scaled(ptr->stats.rx_bytes, "  T");
1666                 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1667
1668         }
1669
1670         if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1671                  ptr->map.base_addr)) {
1672                 printf("          ");
1673                 if (ptr->map.irq)
1674                         printf(_("Interrupt:%d "), ptr->map.irq);
1675                 if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for
1676                                                                                            I/O maps */
1677                         printf(_("Base address:0x%lx "),
1678                                    (unsigned long) ptr->map.base_addr);
1679                 if (ptr->map.mem_start) {
1680                         printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
1681                                    ptr->map.mem_end);
1682                 }
1683                 if (ptr->map.dma)
1684                         printf(_("DMA chan:%x "), ptr->map.dma);
1685                 printf("\n");
1686         }
1687         printf("\n");
1688 }
1689
1690
1691 static int do_if_print(struct interface *ife, void *cookie)
1692 {
1693         int *opt_a = (int *) cookie;
1694         int res;
1695
1696         res = do_if_fetch(ife);
1697         if (res >= 0) {
1698                 if ((ife->flags & IFF_UP) || *opt_a)
1699                         ife_print(ife);
1700         }
1701         return res;
1702 }
1703
1704 static struct interface *lookup_interface(char *name)
1705 {
1706         struct interface *ife = NULL;
1707
1708         if (if_readlist_proc(name) < 0)
1709                 return NULL;
1710         ife = add_interface(name);
1711         return ife;
1712 }
1713
1714 /* for ipv4 add/del modes */
1715 static int if_print(char *ifname)
1716 {
1717         int res;
1718
1719         if (!ifname) {
1720                 res = for_all_interfaces(do_if_print, &interface_opt_a);
1721         } else {
1722                 struct interface *ife;
1723
1724                 ife = lookup_interface(ifname);
1725                 res = do_if_fetch(ife);
1726                 if (res >= 0)
1727                         ife_print(ife);
1728         }
1729         return res;
1730 }
1731
1732 int display_interfaces(char *ifname)
1733 {
1734         int status;
1735
1736         /* Create a channel to the NET kernel. */
1737         if ((skfd = sockets_open(0)) < 0) {
1738                 bb_perror_msg_and_die("socket");
1739         }
1740
1741         /* Do we have to show the current setup? */
1742         status = if_print(ifname);
1743 #ifdef CONFIG_FEATURE_CLEAN_UP
1744         sockets_close();
1745 #endif
1746         exit(status < 0);
1747 }