d97b0422e6a6fb534b9b81860cce952fa9af98be
[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 #define new(p) ((p) = xcalloc(1,sizeof(*(p))))
80
81 #if HAVE_AFINET6
82
83 #ifndef _LINUX_IN6_H
84 /*
85  *    This is in linux/include/net/ipv6.h.
86  */
87
88 struct in6_ifreq {
89         struct in6_addr ifr6_addr;
90         uint32_t ifr6_prefixlen;
91         unsigned int ifr6_ifindex;
92 };
93
94 #endif
95
96 #endif                                                  /* HAVE_AFINET6 */
97
98 /* Defines for glibc2.0 users. */
99 #ifndef SIOCSIFTXQLEN
100 #define SIOCSIFTXQLEN      0x8943
101 #define SIOCGIFTXQLEN      0x8942
102 #endif
103
104 /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
105 #ifndef ifr_qlen
106 #define ifr_qlen        ifr_ifru.ifru_mtu
107 #endif
108
109 #ifndef HAVE_TXQUEUELEN
110 #define HAVE_TXQUEUELEN 1
111 #endif
112
113 #ifndef IFF_DYNAMIC
114 #define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
115 #endif
116
117 /* This structure defines protocol families and their handlers. */
118 struct aftype {
119         const char *name;
120         const char *title;
121         int af;
122         int alen;
123         char *(*print) (unsigned char *);
124         char *(*sprint) (struct sockaddr *, int numeric);
125         int (*input) (int type, char *bufp, struct sockaddr *);
126         void (*herror) (char *text);
127         int (*rprint) (int options);
128         int (*rinput) (int typ, int ext, char **argv);
129
130         /* may modify src */
131         int (*getmask) (char *src, struct sockaddr * mask, char *name);
132
133         int fd;
134         char *flag_file;
135 };
136
137 #ifdef KEEP_UNUSED
138
139 static int flag_unx;
140 static int flag_inet;
141
142 static struct aftrans_t {
143         char *alias;
144         char *name;
145         int *flag;
146 } aftrans[] = {
147
148         {
149         "ip", "inet", &flag_inet},
150 #ifdef HAVE_AFINET6
151         {
152         "ip6", "inet6", &flag_inet6},
153 #endif
154         {
155         "inet", "inet", &flag_inet},
156 #ifdef HAVE_AFINET6
157         {
158         "inet6", "inet6", &flag_inet6},
159 #endif
160         {
161         "unix", "unix", &flag_unx}, {
162         "tcpip", "inet", &flag_inet},
163         {
164         0, 0, 0}
165 };
166
167 static char afname[256] = "";
168 #endif                                                  /* KEEP_UNUSED */
169
170 #if HAVE_AFUNIX
171
172 /* Display a UNIX domain address. */
173 static char *UNIX_print(unsigned char *ptr)
174 {
175         return (ptr);
176 }
177
178
179 /* Display a UNIX domain address. */
180 static char *UNIX_sprint(struct sockaddr *sap, int numeric)
181 {
182         static char buf[64];
183
184         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
185                 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
186         return (UNIX_print(sap->sa_data));
187 }
188
189
190 static struct aftype unix_aftype = {
191         "unix", "UNIX Domain", AF_UNIX, 0,
192         UNIX_print, UNIX_sprint, NULL, NULL,
193         NULL, NULL, NULL,
194         -1,
195         "/proc/net/unix"
196 };
197 #endif                                                  /* HAVE_AFUNIX */
198
199 #if HAVE_AFINET
200
201 #ifdef KEEP_UNUSED
202 static void INET_reserror(char *text)
203 {
204         herror(text);
205 }
206
207 /* Display an Internet socket address. */
208 static char *INET_print(unsigned char *ptr)
209 {
210         return (inet_ntoa((*(struct in_addr *) ptr)));
211 }
212 #endif                                                  /* KEEP_UNUSED */
213
214 /* Display an Internet socket address. */
215 static char *INET_sprint(struct sockaddr *sap, int numeric)
216 {
217         static char buff[128];
218
219         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
220                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
221
222         if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
223                                           numeric, 0xffffff00) != 0)
224                 return (NULL);
225
226         return (buff);
227 }
228
229 #ifdef KEEP_UNUSED
230 static char *INET_sprintmask(struct sockaddr *sap, int numeric,
231                                                          unsigned int netmask)
232 {
233         static char buff[128];
234
235         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
236                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
237         if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
238                                           numeric, netmask) != 0)
239                 return (NULL);
240         return (buff);
241 }
242
243 static int INET_getsock(char *bufp, struct sockaddr *sap)
244 {
245         char *sp = bufp, *bp;
246         unsigned int i;
247         unsigned val;
248         struct sockaddr_in *sin;
249
250         sin = (struct sockaddr_in *) sap;
251         sin->sin_family = AF_INET;
252         sin->sin_port = 0;
253
254         val = 0;
255         bp = (char *) &val;
256         for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
257                 *sp = toupper(*sp);
258
259                 if ((*sp >= 'A') && (*sp <= 'F'))
260                         bp[i] |= (int) (*sp - 'A') + 10;
261                 else if ((*sp >= '0') && (*sp <= '9'))
262                         bp[i] |= (int) (*sp - '0');
263                 else
264                         return (-1);
265
266                 bp[i] <<= 4;
267                 sp++;
268                 *sp = toupper(*sp);
269
270                 if ((*sp >= 'A') && (*sp <= 'F'))
271                         bp[i] |= (int) (*sp - 'A') + 10;
272                 else if ((*sp >= '0') && (*sp <= '9'))
273                         bp[i] |= (int) (*sp - '0');
274                 else
275                         return (-1);
276
277                 sp++;
278         }
279         sin->sin_addr.s_addr = htonl(val);
280
281         return (sp - bufp);
282 }
283
284 static int INET_input(int type, char *bufp, struct sockaddr *sap)
285 {
286         switch (type) {
287         case 1:
288                 return (INET_getsock(bufp, sap));
289         case 256:
290                 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
291         default:
292                 return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
293         }
294 }
295
296 static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
297 {
298         struct sockaddr_in *mask = (struct sockaddr_in *) m;
299         char *slash, *end;
300         int prefix;
301
302         if ((slash = strchr(adr, '/')) == NULL)
303                 return 0;
304
305         *slash++ = '\0';
306         prefix = strtoul(slash, &end, 0);
307         if (*end != '\0')
308                 return -1;
309
310         if (name) {
311                 sprintf(name, "/%d", prefix);
312         }
313         mask->sin_family = AF_INET;
314         mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix));
315         return 1;
316 }
317 #endif                                                  /* KEEP_UNUSED */
318
319 static struct aftype inet_aftype = {
320         "inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
321         NULL /* UNUSED INET_print */ , INET_sprint,
322         NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
323         NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
324         NULL /* UNUSED INET_getnetmask */ ,
325         -1,
326         NULL
327 };
328
329 #endif                                                  /* HAVE_AFINET */
330
331 #if HAVE_AFINET6
332
333 #ifdef KEEP_UNUSED
334 static void INET6_reserror(char *text)
335 {
336         herror(text);
337 }
338
339 /* Display an Internet socket address. */
340 static char *INET6_print(unsigned char *ptr)
341 {
342         static char name[80];
343
344         inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
345         return name;
346 }
347 #endif                                                  /* KEEP_UNUSED */
348
349 /* Display an Internet socket address. */
350 /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
351 static char *INET6_sprint(struct sockaddr *sap, int numeric)
352 {
353         static char buff[128];
354
355         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
356                 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
357         if (INET6_rresolve
358                 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
359                 return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
360         return (buff);
361 }
362
363 #ifdef KEEP_UNUSED
364 static int INET6_getsock(char *bufp, struct sockaddr *sap)
365 {
366         struct sockaddr_in6 *sin6;
367
368         sin6 = (struct sockaddr_in6 *) sap;
369         sin6->sin6_family = AF_INET6;
370         sin6->sin6_port = 0;
371
372         if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
373                 return (-1);
374
375         return 16;                      /* ?;) */
376 }
377
378 static int INET6_input(int type, char *bufp, struct sockaddr *sap)
379 {
380         switch (type) {
381         case 1:
382                 return (INET6_getsock(bufp, sap));
383         default:
384                 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
385         }
386 }
387 #endif                                                  /* KEEP_UNUSED */
388
389 static struct aftype inet6_aftype = {
390         "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
391         NULL /* UNUSED INET6_print */ , INET6_sprint,
392         NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
393         NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
394         NULL /* UNUSED INET6_getnetmask */ ,
395         -1,
396         NULL
397 };
398
399 #endif                                                  /* HAVE_AFINET6 */
400
401 /* Display an UNSPEC address. */
402 static char *UNSPEC_print(unsigned char *ptr)
403 {
404         static char buff[sizeof(struct sockaddr) * 3 + 1];
405         char *pos;
406         unsigned int i;
407
408         pos = buff;
409         for (i = 0; i < sizeof(struct sockaddr); i++) {
410                 /* careful -- not every libc's sprintf returns # bytes written */
411                 sprintf(pos, "%02X-", (*ptr++ & 0377));
412                 pos += 3;
413         }
414         /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
415         *--pos = '\0';
416         return (buff);
417 }
418
419 /* Display an UNSPEC socket address. */
420 static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
421 {
422         static char buf[64];
423
424         if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
425                 return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf));
426         return (UNSPEC_print((unsigned char *)sap->sa_data));
427 }
428
429 static struct aftype unspec_aftype = {
430         "unspec", "UNSPEC", AF_UNSPEC, 0,
431         UNSPEC_print, UNSPEC_sprint, NULL, NULL,
432         NULL,
433 };
434
435 static struct aftype * const aftypes[] = {
436 #if HAVE_AFUNIX
437         &unix_aftype,
438 #endif
439 #if HAVE_AFINET
440         &inet_aftype,
441 #endif
442 #if HAVE_AFINET6
443         &inet6_aftype,
444 #endif
445         &unspec_aftype,
446         NULL
447 };
448
449 #ifdef KEEP_UNUSED
450 static short sVafinit = 0;
451
452 static void afinit()
453 {
454         unspec_aftype.title = _("UNSPEC");
455 #if HAVE_AFUNIX
456         unix_aftype.title = _("UNIX Domain");
457 #endif
458 #if HAVE_AFINET
459         inet_aftype.title = _("DARPA Internet");
460 #endif
461 #if HAVE_AFINET6
462         inet6_aftype.title = _("IPv6");
463 #endif
464         sVafinit = 1;
465 }
466
467 static int aftrans_opt(const char *arg)
468 {
469         struct aftrans_t *paft;
470         char *tmp1, *tmp2;
471         char buf[256];
472
473         safe_strncpy(buf, arg, sizeof(buf));
474
475         tmp1 = buf;
476
477         while (tmp1) {
478
479                 tmp2 = strchr(tmp1, ',');
480
481                 if (tmp2)
482                         *(tmp2++) = '\0';
483
484                 paft = aftrans;
485                 for (paft = aftrans; paft->alias; paft++) {
486                         if (strcmp(tmp1, paft->alias))
487                                 continue;
488                         if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) {
489                                 bb_error_msg(_("Too many address family arguments."));
490                                 return (0);
491                         }
492                         if (paft->flag)
493                                 (*paft->flag)++;
494                         if (afname[0])
495                                 strcat(afname, ",");
496                         strcat(afname, paft->name);
497                         break;
498                 }
499                 if (!paft->alias) {
500                         bb_error_msg(_("Unknown address family `%s'."), tmp1);
501                         return (1);
502                 }
503                 tmp1 = tmp2;
504         }
505
506         return (0);
507 }
508
509 /* set the default AF list from the program name or a constant value    */
510 static void aftrans_def(char *tool, char *argv0, char *dflt)
511 {
512         char *tmp;
513         char *buf;
514
515         strcpy(afname, dflt);
516
517         if (!(tmp = strrchr(argv0, '/')))
518                 tmp = argv0;    /* no slash?! */
519         else
520                 tmp++;
521
522         if (!(buf = strdup(tmp)))
523                 return;
524
525         if (strlen(tool) >= strlen(tmp)) {
526                 free(buf);
527                 return;
528         }
529         tmp = buf + (strlen(tmp) - strlen(tool));
530
531         if (strcmp(tmp, tool) != 0) {
532                 free(buf);
533                 return;
534         }
535         *tmp = '\0';
536         if ((tmp = strchr(buf, '_')))
537                 *tmp = '\0';
538
539         afname[0] = '\0';
540         if (aftrans_opt(buf))
541                 strcpy(afname, buf);
542
543         free(buf);
544 }
545
546 /* Check our protocol family table for this family. */
547 static struct aftype *get_aftype(const char *name)
548 {
549         struct aftype * const *afp;
550
551 #ifdef KEEP_UNUSED
552         if (!sVafinit)
553                 afinit();
554 #endif                                                  /* KEEP_UNUSED */
555
556         afp = aftypes;
557         while (*afp != NULL) {
558                 if (!strcmp((*afp)->name, name))
559                         return (*afp);
560                 afp++;
561         }
562         if (strchr(name, ','))
563                 bb_error_msg(_("Please don't supply more than one address family."));
564         return (NULL);
565 }
566 #endif                                                  /* KEEP_UNUSED */
567
568 /* Check our protocol family table for this family. */
569 static struct aftype *get_afntype(int af)
570 {
571         struct aftype * const *afp;
572
573 #ifdef KEEP_UNUSED
574         if (!sVafinit)
575                 afinit();
576 #endif                                                  /* KEEP_UNUSED */
577
578         afp = aftypes;
579         while (*afp != NULL) {
580                 if ((*afp)->af == af)
581                         return (*afp);
582                 afp++;
583         }
584         return (NULL);
585 }
586
587 /* Check our protocol family table for this family and return its socket */
588 static int get_socket_for_af(int af)
589 {
590         struct aftype * const *afp;
591
592 #ifdef KEEP_UNUSED
593         if (!sVafinit)
594                 afinit();
595 #endif                                                  /* KEEP_UNUSED */
596
597         afp = aftypes;
598         while (*afp != NULL) {
599                 if ((*afp)->af == af)
600                         return (*afp)->fd;
601                 afp++;
602         }
603         return -1;
604 }
605
606 #ifdef KEEP_UNUSED
607 /* type: 0=all, 1=getroute */
608 static void print_aflist(int type)
609 {
610         int count = 0;
611         char *txt;
612         struct aftype * const *afp;
613
614 #ifdef KEEP_UNUSED
615         if (!sVafinit)
616                 afinit();
617 #endif                                                  /* KEEP_UNUSED */
618
619         afp = aftypes;
620         while (*afp != NULL) {
621                 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
622                         afp++;
623                         continue;
624                 }
625                 if ((count % 3) == 0)
626                         fprintf(stderr, count ? "\n    " : "    ");
627                 txt = (*afp)->name;
628                 if (!txt)
629                         txt = "..";
630                 fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
631                 count++;
632                 afp++;
633         }
634         fprintf(stderr, "\n");
635 }
636 #endif                                                  /* KEEP_UNUSED */
637
638 struct user_net_device_stats {
639         unsigned long long rx_packets;  /* total packets received       */
640         unsigned long long tx_packets;  /* total packets transmitted    */
641         unsigned long long rx_bytes;    /* total bytes received         */
642         unsigned long long tx_bytes;    /* total bytes transmitted      */
643         unsigned long rx_errors;        /* bad packets received         */
644         unsigned long tx_errors;        /* packet transmit problems     */
645         unsigned long rx_dropped;       /* no space in linux buffers    */
646         unsigned long tx_dropped;       /* no space available in linux  */
647         unsigned long rx_multicast;     /* multicast packets received   */
648         unsigned long rx_compressed;
649         unsigned long tx_compressed;
650         unsigned long collisions;
651
652         /* detailed rx_errors: */
653         unsigned long rx_length_errors;
654         unsigned long rx_over_errors;   /* receiver ring buff overflow  */
655         unsigned long rx_crc_errors;    /* recved pkt with crc error    */
656         unsigned long rx_frame_errors;  /* recv'd frame alignment error */
657         unsigned long rx_fifo_errors;   /* recv'r fifo overrun          */
658         unsigned long rx_missed_errors; /* receiver missed packet     */
659         /* detailed tx_errors */
660         unsigned long tx_aborted_errors;
661         unsigned long tx_carrier_errors;
662         unsigned long tx_fifo_errors;
663         unsigned long tx_heartbeat_errors;
664         unsigned long tx_window_errors;
665 };
666
667 struct interface {
668         struct interface *next, *prev;
669         char name[IFNAMSIZ];    /* interface name        */
670         short type;                     /* if type               */
671         short flags;            /* various flags         */
672         int metric;                     /* routing metric        */
673         int mtu;                        /* MTU value             */
674         int tx_queue_len;       /* transmit queue length */
675         struct ifmap map;       /* hardware setup        */
676         struct sockaddr addr;   /* IP address            */
677         struct sockaddr dstaddr;        /* P-P IP address        */
678         struct sockaddr broadaddr;      /* IP broadcast address  */
679         struct sockaddr netmask;        /* IP network mask       */
680         int has_ip;
681         char hwaddr[32];        /* HW address            */
682         int statistics_valid;
683         struct user_net_device_stats stats;     /* statistics            */
684         int keepalive;          /* keepalive value for SLIP */
685         int outfill;            /* outfill value for SLIP */
686 };
687
688
689 int interface_opt_a = 0;        /* show all interfaces          */
690
691 #ifdef KEEP_UNUSED
692 static int opt_i = 0;   /* show the statistics          */
693 static int opt_v = 0;   /* debugging output flag        */
694
695 static int addr_family = 0;     /* currently selected AF        */
696 #endif                                                  /* KEEP_UNUSED */
697
698 static struct interface *int_list, *int_last;
699 static int skfd = -1;   /* generic raw socket desc.     */
700
701
702 static int sockets_open(int family)
703 {
704         struct aftype * const *aft;
705         int sfd = -1;
706         static int force = -1;
707
708         if (force < 0) {
709                 force = 0;
710                 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
711                         force = 1;
712                 if (access("/proc/net", R_OK))
713                         force = 1;
714         }
715         for (aft = aftypes; *aft; aft++) {
716                 struct aftype *af = *aft;
717                 int type = SOCK_DGRAM;
718
719                 if (af->af == AF_UNSPEC)
720                         continue;
721                 if (family && family != af->af)
722                         continue;
723                 if (af->fd != -1) {
724                         sfd = af->fd;
725                         continue;
726                 }
727                 /* Check some /proc file first to not stress kmod */
728                 if (!family && !force && af->flag_file) {
729                         if (access(af->flag_file, R_OK))
730                                 continue;
731                 }
732                 af->fd = socket(af->af, type, 0);
733                 if (af->fd >= 0)
734                         sfd = af->fd;
735         }
736         if (sfd < 0) {
737                 bb_error_msg(_("No usable address families found."));
738         }
739         return sfd;
740 }
741
742 #ifdef CONFIG_FEATURE_CLEAN_UP
743 static void sockets_close(void)
744 {
745         struct aftype * const *aft;
746         for (aft = aftypes; *aft != NULL; aft++) {
747                 struct aftype *af = *aft;
748                 if( af->fd != -1 ) {
749                         close(af->fd);
750                         af->fd = -1;
751                 }
752         }
753 }
754 #endif
755
756 /* like strcmp(), but knows about numbers */
757 static int nstrcmp(const char *a, const char *b)
758 {
759         const char *a_ptr = a;
760         const char *b_ptr = b;
761
762         while (*a == *b) {
763                 if (*a == '\0') {
764                         return 0;
765                 }
766                 if (!isdigit(*a) && isdigit(*(a+1))) {
767                         a_ptr = a+1;
768                         b_ptr = b+1;
769                 }
770                 a++;
771                 b++;
772         }
773
774         if (isdigit(*a) && isdigit(*b)) {
775                 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
776         }
777         return *a - *b;
778 }
779
780 static struct interface *add_interface(char *name)
781 {
782         struct interface *ife, **nextp, *new;
783
784         for (ife = int_last; ife; ife = ife->prev) {
785                 int n = nstrcmp(ife->name, name);
786
787                 if (n == 0)
788                         return ife;
789                 if (n < 0)
790                         break;
791         }
792         new(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 }