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