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