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