Tito, farmatito at tiscali dot it writes:
[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.23 2004/07/23 01:49:46 bug1 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 *a, const char *b)
893 {
894         const char *a_ptr = a;
895         const char *b_ptr = b;
896
897         while (*a == *b) {
898                 if (*a == '\0') {
899                         return 0;
900                 }
901                 if (!isdigit(*a) && isdigit(*(a+1))) {
902                         a_ptr = a+1;
903                         b_ptr = b+1;
904                 }
905                 a++;
906                 b++;
907         }
908
909         if (isdigit(*a) && isdigit(*b)) {
910                 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
911         }
912         return *a - *b;
913 }
914
915 static struct interface *add_interface(char *name)
916 {
917         struct interface *ife, **nextp, *new;
918
919         for (ife = int_last; ife; ife = ife->prev) {
920                 int n = nstrcmp(ife->name, name);
921
922                 if (n == 0)
923                         return ife;
924                 if (n < 0)
925                         break;
926         }
927         new(new);
928         safe_strncpy(new->name, name, IFNAMSIZ);
929         nextp = ife ? &ife->next : &int_list;
930         new->prev = ife;
931         new->next = *nextp;
932         if (new->next)
933                 new->next->prev = new;
934         else
935                 int_last = new;
936         *nextp = new;
937         return new;
938 }
939
940
941 static int if_readconf(void)
942 {
943         int numreqs = 30;
944         struct ifconf ifc;
945         struct ifreq *ifr;
946         int n, err = -1;
947         int skfd2;
948
949         /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
950            (as of 2.1.128) */
951         skfd2 = get_socket_for_af(AF_INET);
952         if (skfd2 < 0) {
953                 bb_perror_msg(("warning: no inet socket available"));
954                 /* Try to soldier on with whatever socket we can get hold of.  */
955                 skfd2 = sockets_open(0);
956                 if (skfd2 < 0)
957                         return -1;
958         }
959
960         ifc.ifc_buf = NULL;
961         for (;;) {
962                 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
963                 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
964
965                 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
966                         perror("SIOCGIFCONF");
967                         goto out;
968                 }
969                 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
970                         /* assume it overflowed and try again */
971                         numreqs += 10;
972                         continue;
973                 }
974                 break;
975         }
976
977         ifr = ifc.ifc_req;
978         for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
979                 add_interface(ifr->ifr_name);
980                 ifr++;
981         }
982         err = 0;
983
984   out:
985         free(ifc.ifc_buf);
986         return err;
987 }
988
989 static char *get_name(char *name, char *p)
990 {
991         while (isspace(*p))
992                 p++;
993         while (*p) {
994                 if (isspace(*p))
995                         break;
996                 if (*p == ':') {        /* could be an alias */
997                         char *dot = p, *dotname = name;
998
999                         *name++ = *p++;
1000                         while (isdigit(*p))
1001                                 *name++ = *p++;
1002                         if (*p != ':') {        /* it wasn't, backup */
1003                                 p = dot;
1004                                 name = dotname;
1005                         }
1006                         if (*p == '\0')
1007                                 return NULL;
1008                         p++;
1009                         break;
1010                 }
1011                 *name++ = *p++;
1012         }
1013         *name++ = '\0';
1014         return p;
1015 }
1016
1017 /* If scanf supports size qualifiers for %n conversions, then we can
1018  * use a modified fmt that simply stores the position in the fields
1019  * having no associated fields in the proc string.  Of course, we need
1020  * to zero them again when we're done.  But that is smaller than the
1021  * old approach of multiple scanf occurrences with large numbers of
1022  * args. */
1023
1024 /* static const char *ss_fmt[] = { */
1025 /*      "%Ln%Lu%lu%lu%lu%lu%ln%ln%Ln%Lu%lu%lu%lu%lu%lu", */
1026 /*      "%Lu%Lu%lu%lu%lu%lu%ln%ln%Lu%Lu%lu%lu%lu%lu%lu", */
1027 /*      "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu" */
1028 /* }; */
1029
1030         /* Lie about the size of the int pointed to for %n. */
1031 #if INT_MAX == LONG_MAX
1032 static const char *ss_fmt[] = {
1033         "%n%Lu%u%u%u%u%n%n%n%Lu%u%u%u%u%u",
1034         "%Lu%Lu%u%u%u%u%n%n%Lu%Lu%u%u%u%u%u",
1035         "%Lu%Lu%u%u%u%u%u%u%Lu%Lu%u%u%u%u%u%u"
1036 };
1037 #else
1038 static const char *ss_fmt[] = {
1039         "%n%Lu%lu%lu%lu%lu%n%n%n%Lu%lu%lu%lu%lu%lu",
1040         "%Lu%Lu%lu%lu%lu%lu%n%n%Lu%Lu%lu%lu%lu%lu%lu",
1041         "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu"
1042 };
1043
1044 #endif
1045
1046 static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
1047 {
1048         memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
1049
1050         sscanf(bp, ss_fmt[procnetdev_vsn],
1051                    &ife->stats.rx_bytes, /* missing for 0 */
1052                    &ife->stats.rx_packets,
1053                    &ife->stats.rx_errors,
1054                    &ife->stats.rx_dropped,
1055                    &ife->stats.rx_fifo_errors,
1056                    &ife->stats.rx_frame_errors,
1057                    &ife->stats.rx_compressed, /* missing for <= 1 */
1058                    &ife->stats.rx_multicast, /* missing for <= 1 */
1059                    &ife->stats.tx_bytes, /* missing for 0 */
1060                    &ife->stats.tx_packets,
1061                    &ife->stats.tx_errors,
1062                    &ife->stats.tx_dropped,
1063                    &ife->stats.tx_fifo_errors,
1064                    &ife->stats.collisions,
1065                    &ife->stats.tx_carrier_errors,
1066                    &ife->stats.tx_compressed /* missing for <= 1 */
1067                    );
1068
1069         if (procnetdev_vsn <= 1) {
1070                 if (procnetdev_vsn == 0) {
1071                         ife->stats.rx_bytes = 0;
1072                         ife->stats.tx_bytes = 0;
1073                 }
1074                 ife->stats.rx_multicast = 0;
1075                 ife->stats.rx_compressed = 0;
1076                 ife->stats.tx_compressed = 0;
1077         }
1078 }
1079
1080 static inline int procnetdev_version(char *buf)
1081 {
1082         if (strstr(buf, "compressed"))
1083                 return 2;
1084         if (strstr(buf, "bytes"))
1085                 return 1;
1086         return 0;
1087 }
1088
1089 static int if_readlist_proc(char *target)
1090 {
1091         static int proc_read;
1092         FILE *fh;
1093         char buf[512];
1094         struct interface *ife;
1095         int err, procnetdev_vsn;
1096
1097         if (proc_read)
1098                 return 0;
1099         if (!target)
1100                 proc_read = 1;
1101
1102         fh = fopen(_PATH_PROCNET_DEV, "r");
1103         if (!fh) {
1104                 bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
1105                 return if_readconf();
1106         }
1107         fgets(buf, sizeof buf, fh);     /* eat line */
1108         fgets(buf, sizeof buf, fh);
1109
1110         procnetdev_vsn = procnetdev_version(buf);
1111
1112         err = 0;
1113         while (fgets(buf, sizeof buf, fh)) {
1114                 char *s, name[128];
1115
1116                 s = get_name(name, buf);
1117                 ife = add_interface(name);
1118                 get_dev_fields(s, ife, procnetdev_vsn);
1119                 ife->statistics_valid = 1;
1120                 if (target && !strcmp(target, name))
1121                         break;
1122         }
1123         if (ferror(fh)) {
1124                 perror(_PATH_PROCNET_DEV);
1125                 err = -1;
1126                 proc_read = 0;
1127         }
1128         fclose(fh);
1129         return err;
1130 }
1131
1132 static int if_readlist(void)
1133 {
1134         int err = if_readlist_proc(NULL);
1135
1136         if (!err)
1137                 err = if_readconf();
1138         return err;
1139 }
1140
1141 static int for_all_interfaces(int (*doit) (struct interface *, void *),
1142                                                           void *cookie)
1143 {
1144         struct interface *ife;
1145
1146         if (!int_list && (if_readlist() < 0))
1147                 return -1;
1148         for (ife = int_list; ife; ife = ife->next) {
1149                 int err = doit(ife, cookie);
1150
1151                 if (err)
1152                         return err;
1153         }
1154         return 0;
1155 }
1156
1157 /* Support for fetching an IPX address */
1158
1159 #if HAVE_AFIPX
1160 static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
1161 {
1162         ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
1163         return ioctl(sock, SIOCGIFADDR, ifr);
1164 }
1165 #endif
1166
1167
1168 /* Fetch the interface configuration from the kernel. */
1169 static int if_fetch(struct interface *ife)
1170 {
1171         struct ifreq ifr;
1172         int fd;
1173         char *ifname = ife->name;
1174
1175         strcpy(ifr.ifr_name, ifname);
1176         if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1177                 return (-1);
1178         ife->flags = ifr.ifr_flags;
1179
1180         strcpy(ifr.ifr_name, ifname);
1181         if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1182                 memset(ife->hwaddr, 0, 32);
1183         else
1184                 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
1185
1186         ife->type = ifr.ifr_hwaddr.sa_family;
1187
1188         strcpy(ifr.ifr_name, ifname);
1189         if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1190                 ife->metric = 0;
1191         else
1192                 ife->metric = ifr.ifr_metric;
1193
1194         strcpy(ifr.ifr_name, ifname);
1195         if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1196                 ife->mtu = 0;
1197         else
1198                 ife->mtu = ifr.ifr_mtu;
1199
1200 #ifdef HAVE_HWSLIP
1201         if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1202                 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1203                 ife->type == ARPHRD_ADAPT) {
1204 #ifdef SIOCGOUTFILL
1205                 strcpy(ifr.ifr_name, ifname);
1206                 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1207                         ife->outfill = 0;
1208                 else
1209                         ife->outfill = (unsigned int) ifr.ifr_data;
1210 #endif
1211 #ifdef SIOCGKEEPALIVE
1212                 strcpy(ifr.ifr_name, ifname);
1213                 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1214                         ife->keepalive = 0;
1215                 else
1216                         ife->keepalive = (unsigned int) ifr.ifr_data;
1217 #endif
1218         }
1219 #endif
1220
1221         strcpy(ifr.ifr_name, ifname);
1222         if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1223                 memset(&ife->map, 0, sizeof(struct ifmap));
1224         else
1225                 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
1226
1227         strcpy(ifr.ifr_name, ifname);
1228         if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1229                 memset(&ife->map, 0, sizeof(struct ifmap));
1230         else
1231                 ife->map = ifr.ifr_map;
1232
1233 #ifdef HAVE_TXQUEUELEN
1234         strcpy(ifr.ifr_name, ifname);
1235         if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1236                 ife->tx_queue_len = -1; /* unknown value */
1237         else
1238                 ife->tx_queue_len = ifr.ifr_qlen;
1239 #else
1240         ife->tx_queue_len = -1; /* unknown value */
1241 #endif
1242
1243 #if HAVE_AFINET
1244         /* IPv4 address? */
1245         fd = get_socket_for_af(AF_INET);
1246         if (fd >= 0) {
1247                 strcpy(ifr.ifr_name, ifname);
1248                 ifr.ifr_addr.sa_family = AF_INET;
1249                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1250                         ife->has_ip = 1;
1251                         ife->addr = ifr.ifr_addr;
1252                         strcpy(ifr.ifr_name, ifname);
1253                         if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1254                                 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1255                         else
1256                                 ife->dstaddr = ifr.ifr_dstaddr;
1257
1258                         strcpy(ifr.ifr_name, ifname);
1259                         if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1260                                 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1261                         else
1262                                 ife->broadaddr = ifr.ifr_broadaddr;
1263
1264                         strcpy(ifr.ifr_name, ifname);
1265                         if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1266                                 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1267                         else
1268                                 ife->netmask = ifr.ifr_netmask;
1269                 } else
1270                         memset(&ife->addr, 0, sizeof(struct sockaddr));
1271         }
1272 #endif
1273
1274 #if HAVE_AFATALK
1275         /* DDP address maybe ? */
1276         fd = get_socket_for_af(AF_APPLETALK);
1277         if (fd >= 0) {
1278                 strcpy(ifr.ifr_name, ifname);
1279                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1280                         ife->ddpaddr = ifr.ifr_addr;
1281                         ife->has_ddp = 1;
1282                 }
1283         }
1284 #endif
1285
1286 #if HAVE_AFIPX
1287         /* Look for IPX addresses with all framing types */
1288         fd = get_socket_for_af(AF_IPX);
1289         if (fd >= 0) {
1290                 strcpy(ifr.ifr_name, ifname);
1291                 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
1292                         ife->has_ipx_bb = 1;
1293                         ife->ipxaddr_bb = ifr.ifr_addr;
1294                 }
1295                 strcpy(ifr.ifr_name, ifname);
1296                 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
1297                         ife->has_ipx_sn = 1;
1298                         ife->ipxaddr_sn = ifr.ifr_addr;
1299                 }
1300                 strcpy(ifr.ifr_name, ifname);
1301                 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
1302                         ife->has_ipx_e3 = 1;
1303                         ife->ipxaddr_e3 = ifr.ifr_addr;
1304                 }
1305                 strcpy(ifr.ifr_name, ifname);
1306                 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
1307                         ife->has_ipx_e2 = 1;
1308                         ife->ipxaddr_e2 = ifr.ifr_addr;
1309                 }
1310         }
1311 #endif
1312
1313 #if HAVE_AFECONET
1314         /* Econet address maybe? */
1315         fd = get_socket_for_af(AF_ECONET);
1316         if (fd >= 0) {
1317                 strcpy(ifr.ifr_name, ifname);
1318                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1319                         ife->ecaddr = ifr.ifr_addr;
1320                         ife->has_econet = 1;
1321                 }
1322         }
1323 #endif
1324
1325         return 0;
1326 }
1327
1328
1329 static int do_if_fetch(struct interface *ife)
1330 {
1331         if (if_fetch(ife) < 0) {
1332                 char *errmsg;
1333
1334                 if (errno == ENODEV) {
1335                         /* Give better error message for this case. */
1336                         errmsg = _("Device not found");
1337                 } else {
1338                         errmsg = strerror(errno);
1339                 }
1340                 bb_error_msg(_("%s: error fetching interface information: %s\n"),
1341                                 ife->name, errmsg);
1342                 return -1;
1343         }
1344         return 0;
1345 }
1346
1347 /* This structure defines hardware protocols and their handlers. */
1348 struct hwtype {
1349         const char *name;
1350         const char *title;
1351         int type;
1352         int alen;
1353         char *(*print) (unsigned char *);
1354         int (*input) (char *, struct sockaddr *);
1355         int (*activate) (int fd);
1356         int suppress_null_addr;
1357 };
1358
1359 static struct hwtype unspec_hwtype = {
1360         "unspec", "UNSPEC", -1, 0,
1361         UNSPEC_print, NULL, NULL
1362 };
1363
1364 static struct hwtype loop_hwtype = {
1365         "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1366         NULL, NULL, NULL
1367 };
1368
1369 #if HAVE_HWETHER
1370 #include <net/if_arp.h>
1371
1372 #if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
1373 #include <net/ethernet.h>
1374 #else
1375 #include <linux/if_ether.h>
1376 #endif
1377
1378 /* Display an Ethernet address in readable format. */
1379 static char *pr_ether(unsigned char *ptr)
1380 {
1381         static char buff[64];
1382
1383         snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1384                          (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1385                          (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1386                 );
1387         return (buff);
1388 }
1389
1390 #ifdef KEEP_UNUSED
1391 /* Input an Ethernet address and convert to binary. */
1392 static int in_ether(char *bufp, struct sockaddr *sap)
1393 {
1394         unsigned char *ptr;
1395         char c, *orig;
1396         int i;
1397         unsigned val;
1398
1399         sap->sa_family = ether_hwtype.type;
1400         ptr = sap->sa_data;
1401
1402         i = 0;
1403         orig = bufp;
1404         while ((*bufp != '\0') && (i < ETH_ALEN)) {
1405                 val = 0;
1406                 c = *bufp++;
1407                 if (isdigit(c))
1408                         val = c - '0';
1409                 else if (c >= 'a' && c <= 'f')
1410                         val = c - 'a' + 10;
1411                 else if (c >= 'A' && c <= 'F')
1412                         val = c - 'A' + 10;
1413                 else {
1414 #ifdef DEBUG
1415                         bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
1416 #endif
1417                         errno = EINVAL;
1418                         return (-1);
1419                 }
1420                 val <<= 4;
1421                 c = *bufp;
1422                 if (isdigit(c))
1423                         val |= c - '0';
1424                 else if (c >= 'a' && c <= 'f')
1425                         val |= c - 'a' + 10;
1426                 else if (c >= 'A' && c <= 'F')
1427                         val |= c - 'A' + 10;
1428                 else if (c == ':' || c == 0)
1429                         val >>= 4;
1430                 else {
1431 #ifdef DEBUG
1432                         bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
1433 #endif
1434                         errno = EINVAL;
1435                         return (-1);
1436                 }
1437                 if (c != 0)
1438                         bufp++;
1439                 *ptr++ = (unsigned char) (val & 0377);
1440                 i++;
1441
1442                 /* We might get a semicolon here - not required. */
1443                 if (*bufp == ':') {
1444 #ifdef DEBUG
1445                         if (i == ETH_ALEN) {
1446                                 bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
1447                         }
1448 #endif
1449                         bufp++;
1450                 }
1451         }
1452
1453 #ifdef DEBUG
1454         /* That's it.  Any trailing junk? */
1455         if ((i == ETH_ALEN) && (*bufp != '\0')) {
1456                 bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
1457                 errno = EINVAL;
1458                 return (-1);
1459         }
1460         bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
1461 #endif
1462
1463         return (0);
1464 }
1465 #endif                                                  /* KEEP_UNUSED */
1466
1467
1468 static struct hwtype ether_hwtype = {
1469         "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1470         pr_ether, NULL /* UNUSED in_ether */ , NULL
1471 };
1472
1473
1474 #endif                                                  /* HAVE_HWETHER */
1475
1476
1477 #if HAVE_HWPPP
1478
1479 #include <net/if_arp.h>
1480
1481 #ifdef KEEP_UNUSED
1482 /* Start the PPP encapsulation on the file descriptor. */
1483 static int do_ppp(int fd)
1484 {
1485         bb_error_msg(_("You cannot start PPP with this program."));
1486         return -1;
1487 }
1488 #endif                                                  /* KEEP_UNUSED */
1489
1490 static struct hwtype ppp_hwtype = {
1491         "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1492         NULL, NULL, NULL /* UNUSED do_ppp */ , 0
1493 };
1494
1495
1496 #endif                                                  /* HAVE_PPP */
1497
1498 static struct hwtype *hwtypes[] = {
1499
1500         &loop_hwtype,
1501
1502 #if HAVE_HWSLIP
1503         &slip_hwtype,
1504         &cslip_hwtype,
1505         &slip6_hwtype,
1506         &cslip6_hwtype,
1507         &adaptive_hwtype,
1508 #endif
1509 #if HAVE_HWSTRIP
1510         &strip_hwtype,
1511 #endif
1512 #if HAVE_HWASH
1513         &ash_hwtype,
1514 #endif
1515 #if HAVE_HWETHER
1516         &ether_hwtype,
1517 #endif
1518 #if HAVE_HWTR
1519         &tr_hwtype,
1520 #ifdef ARPHRD_IEEE802_TR
1521         &tr_hwtype1,
1522 #endif
1523 #endif
1524 #if HAVE_HWAX25
1525         &ax25_hwtype,
1526 #endif
1527 #if HAVE_HWNETROM
1528         &netrom_hwtype,
1529 #endif
1530 #if HAVE_HWROSE
1531         &rose_hwtype,
1532 #endif
1533 #if HAVE_HWTUNNEL
1534         &tunnel_hwtype,
1535 #endif
1536 #if HAVE_HWPPP
1537         &ppp_hwtype,
1538 #endif
1539 #if HAVE_HWHDLCLAPB
1540         &hdlc_hwtype,
1541         &lapb_hwtype,
1542 #endif
1543 #if HAVE_HWARC
1544         &arcnet_hwtype,
1545 #endif
1546 #if HAVE_HWFR
1547         &dlci_hwtype,
1548         &frad_hwtype,
1549 #endif
1550 #if HAVE_HWSIT
1551         &sit_hwtype,
1552 #endif
1553 #if HAVE_HWFDDI
1554         &fddi_hwtype,
1555 #endif
1556 #if HAVE_HWHIPPI
1557         &hippi_hwtype,
1558 #endif
1559 #if HAVE_HWIRDA
1560         &irda_hwtype,
1561 #endif
1562 #if HAVE_HWEC
1563         &ec_hwtype,
1564 #endif
1565 #if HAVE_HWX25
1566         &x25_hwtype,
1567 #endif
1568         &unspec_hwtype,
1569         NULL
1570 };
1571
1572 #ifdef KEEP_UNUSED
1573 static short sVhwinit = 0;
1574
1575 static void hwinit()
1576 {
1577         loop_hwtype.title = _("Local Loopback");
1578         unspec_hwtype.title = _("UNSPEC");
1579 #if HAVE_HWSLIP
1580         slip_hwtype.title = _("Serial Line IP");
1581         cslip_hwtype.title = _("VJ Serial Line IP");
1582         slip6_hwtype.title = _("6-bit Serial Line IP");
1583         cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1584         adaptive_hwtype.title = _("Adaptive Serial Line IP");
1585 #endif
1586 #if HAVE_HWETHER
1587         ether_hwtype.title = _("Ethernet");
1588 #endif
1589 #if HAVE_HWASH
1590         ash_hwtype.title = _("Ash");
1591 #endif
1592 #if HAVE_HWFDDI
1593         fddi_hwtype.title = _("Fiber Distributed Data Interface");
1594 #endif
1595 #if HAVE_HWHIPPI
1596         hippi_hwtype.title = _("HIPPI");
1597 #endif
1598 #if HAVE_HWAX25
1599         ax25_hwtype.title = _("AMPR AX.25");
1600 #endif
1601 #if HAVE_HWROSE
1602         rose_hwtype.title = _("AMPR ROSE");
1603 #endif
1604 #if HAVE_HWNETROM
1605         netrom_hwtype.title = _("AMPR NET/ROM");
1606 #endif
1607 #if HAVE_HWX25
1608         x25_hwtype.title = _("generic X.25");
1609 #endif
1610 #if HAVE_HWTUNNEL
1611         tunnel_hwtype.title = _("IPIP Tunnel");
1612 #endif
1613 #if HAVE_HWPPP
1614         ppp_hwtype.title = _("Point-to-Point Protocol");
1615 #endif
1616 #if HAVE_HWHDLCLAPB
1617         hdlc_hwtype.title = _("(Cisco)-HDLC");
1618         lapb_hwtype.title = _("LAPB");
1619 #endif
1620 #if HAVE_HWARC
1621         arcnet_hwtype.title = _("ARCnet");
1622 #endif
1623 #if HAVE_HWFR
1624         dlci_hwtype.title = _("Frame Relay DLCI");
1625         frad_hwtype.title = _("Frame Relay Access Device");
1626 #endif
1627 #if HAVE_HWSIT
1628         sit_hwtype.title = _("IPv6-in-IPv4");
1629 #endif
1630 #if HAVE_HWIRDA
1631         irda_hwtype.title = _("IrLAP");
1632 #endif
1633 #if HAVE_HWTR
1634         tr_hwtype.title = _("16/4 Mbps Token Ring");
1635 #ifdef ARPHRD_IEEE802_TR
1636         tr_hwtype1.title = _("16/4 Mbps Token Ring (New)");
1637 #endif
1638 #endif
1639 #if HAVE_HWEC
1640         ec_hwtype.title = _("Econet");
1641 #endif
1642         sVhwinit = 1;
1643 }
1644 #endif                                                  /* KEEP_UNUSED */
1645
1646 #ifdef IFF_PORTSEL
1647 #if 0
1648 static const char * const if_port_text[][4] = {
1649         /* Keep in step with <linux/netdevice.h> */
1650         {"unknown", NULL, NULL, NULL},
1651         {"10base2", "bnc", "coax", NULL},
1652         {"10baseT", "utp", "tpe", NULL},
1653         {"AUI", "thick", "db15", NULL},
1654         {"100baseT", NULL, NULL, NULL},
1655         {"100baseTX", NULL, NULL, NULL},
1656         {"100baseFX", NULL, NULL, NULL},
1657         {NULL, NULL, NULL, NULL},
1658 };
1659 #else
1660 static const char * const if_port_text[] = {
1661         /* Keep in step with <linux/netdevice.h> */
1662         "unknown",
1663         "10base2",
1664         "10baseT",
1665         "AUI",
1666         "100baseT",
1667         "100baseTX",
1668         "100baseFX",
1669         NULL
1670 };
1671 #endif
1672 #endif
1673
1674 /* Check our hardware type table for this type. */
1675 static struct hwtype *get_hwntype(int type)
1676 {
1677         struct hwtype **hwp;
1678
1679 #ifdef KEEP_UNUSED
1680         if (!sVhwinit)
1681                 hwinit();
1682 #endif                                                  /* KEEP_UNUSED */
1683
1684         hwp = hwtypes;
1685         while (*hwp != NULL) {
1686                 if ((*hwp)->type == type)
1687                         return (*hwp);
1688                 hwp++;
1689         }
1690         return (NULL);
1691 }
1692
1693 /* return 1 if address is all zeros */
1694 static int hw_null_address(struct hwtype *hw, void *ap)
1695 {
1696         unsigned int i;
1697         unsigned char *address = (unsigned char *) ap;
1698
1699         for (i = 0; i < hw->alen; i++)
1700                 if (address[i])
1701                         return 0;
1702         return 1;
1703 }
1704
1705 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
1706
1707 static void print_bytes_scaled(unsigned long long ull, const char *end)
1708 {
1709         unsigned long long int_part;
1710         const char *ext;
1711         unsigned int frac_part;
1712         int i;
1713
1714         frac_part = 0;
1715         ext = TRext;
1716         int_part = ull;
1717         i = 4;
1718         do {
1719 #if 0
1720                 /* This does correct rounding and is a little larger.  But it
1721                  * uses KiB as the smallest displayed unit. */
1722                 if ((int_part < (1024*1024 - 51)) || !--i) {
1723                         i = 0;
1724                         int_part += 51;         /* 1024*.05 = 51.2 */
1725                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1726                 }
1727                 int_part /= 1024;
1728                 ext += 3;       /* KiB, MiB, GiB, TiB */
1729 #else
1730                 if (int_part >= 1024) {
1731                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1732                         int_part /= 1024;
1733                         ext += 3;       /* KiB, MiB, GiB, TiB */
1734                 }
1735                 --i;
1736 #endif
1737         } while (i);
1738
1739         printf("X bytes:%Lu (%Lu.%u %sB)%s", ull, int_part, frac_part, ext, end);
1740 }
1741
1742 static const char * const ife_print_flags_strs[] = {
1743         "UP ",
1744         "BROADCAST ",
1745         "DEBUG ",
1746         "LOOPBACK ",
1747         "POINTOPOINT ",
1748         "NOTRAILERS ",
1749         "RUNNING ",
1750         "NOARP ",
1751         "PROMISC ",
1752         "ALLMULTI ",
1753         "SLAVE ",
1754         "MASTER ",
1755         "MULTICAST ",
1756 #ifdef HAVE_DYNAMIC
1757         "DYNAMIC "
1758 #endif
1759 };
1760
1761 static const unsigned short ife_print_flags_mask[] = {
1762         IFF_UP,
1763         IFF_BROADCAST,
1764         IFF_DEBUG,
1765         IFF_LOOPBACK,
1766         IFF_POINTOPOINT,
1767         IFF_NOTRAILERS,
1768         IFF_RUNNING,
1769         IFF_NOARP,
1770         IFF_PROMISC,
1771         IFF_ALLMULTI,
1772         IFF_SLAVE,
1773         IFF_MASTER,
1774         IFF_MULTICAST,
1775 #ifdef HAVE_DYNAMIC
1776         IFF_DYNAMIC
1777 #endif
1778         0
1779 };
1780
1781 static void ife_print(struct interface *ptr)
1782 {
1783         struct aftype *ap;
1784         struct hwtype *hw;
1785         int hf;
1786         int can_compress = 0;
1787
1788 #if HAVE_AFIPX
1789         static struct aftype *ipxtype = NULL;
1790 #endif
1791 #if HAVE_AFECONET
1792         static struct aftype *ectype = NULL;
1793 #endif
1794 #if HAVE_AFATALK
1795         static struct aftype *ddptype = NULL;
1796 #endif
1797 #if HAVE_AFINET6
1798         FILE *f;
1799         char addr6[40], devname[20];
1800         struct sockaddr_in6 sap;
1801         int plen, scope, dad_status, if_idx;
1802         char addr6p[8][5];
1803 #endif
1804
1805         ap = get_afntype(ptr->addr.sa_family);
1806         if (ap == NULL)
1807                 ap = get_afntype(0);
1808
1809         hf = ptr->type;
1810
1811         if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1812                 can_compress = 1;
1813
1814         hw = get_hwntype(hf);
1815         if (hw == NULL)
1816                 hw = get_hwntype(-1);
1817
1818         printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
1819         /* For some hardware types (eg Ash, ATM) we don't print the
1820            hardware address if it's null.  */
1821         if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1822                                                                 hw->suppress_null_addr)))
1823                 printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
1824 #ifdef IFF_PORTSEL
1825         if (ptr->flags & IFF_PORTSEL) {
1826                 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
1827                 if (ptr->flags & IFF_AUTOMEDIA)
1828                         printf(_("(auto)"));
1829         }
1830 #endif
1831         printf("\n");
1832
1833 #if HAVE_AFINET
1834         if (ptr->has_ip) {
1835                 printf(_("          %s addr:%s "), ap->name,
1836                            ap->sprint(&ptr->addr, 1));
1837                 if (ptr->flags & IFF_POINTOPOINT) {
1838                         printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1839                 }
1840                 if (ptr->flags & IFF_BROADCAST) {
1841                         printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1842                 }
1843                 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1844         }
1845 #endif
1846
1847 #if HAVE_AFINET6
1848
1849 #define IPV6_ADDR_ANY           0x0000U
1850
1851 #define IPV6_ADDR_UNICAST       0x0001U
1852 #define IPV6_ADDR_MULTICAST     0x0002U
1853 #define IPV6_ADDR_ANYCAST       0x0004U
1854
1855 #define IPV6_ADDR_LOOPBACK      0x0010U
1856 #define IPV6_ADDR_LINKLOCAL     0x0020U
1857 #define IPV6_ADDR_SITELOCAL     0x0040U
1858
1859 #define IPV6_ADDR_COMPATv4      0x0080U
1860
1861 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
1862
1863 #define IPV6_ADDR_MAPPED        0x1000U
1864 #define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
1865
1866         if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1867                 while (fscanf
1868                            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1869                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1870                                 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1871                                 &dad_status, devname) != EOF) {
1872                         if (!strcmp(devname, ptr->name)) {
1873                                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1874                                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1875                                                 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1876                                 inet_pton(AF_INET6, addr6,
1877                                                   (struct sockaddr *) &sap.sin6_addr);
1878                                 sap.sin6_family = AF_INET6;
1879                                 printf(_("          inet6 addr: %s/%d"),
1880                                            inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1881                                            plen);
1882                                 printf(_(" Scope:"));
1883                                 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1884                                 case 0:
1885                                         printf(_("Global"));
1886                                         break;
1887                                 case IPV6_ADDR_LINKLOCAL:
1888                                         printf(_("Link"));
1889                                         break;
1890                                 case IPV6_ADDR_SITELOCAL:
1891                                         printf(_("Site"));
1892                                         break;
1893                                 case IPV6_ADDR_COMPATv4:
1894                                         printf(_("Compat"));
1895                                         break;
1896                                 case IPV6_ADDR_LOOPBACK:
1897                                         printf(_("Host"));
1898                                         break;
1899                                 default:
1900                                         printf(_("Unknown"));
1901                                 }
1902                                 printf("\n");
1903                         }
1904                 }
1905                 fclose(f);
1906         }
1907 #endif
1908
1909 #if HAVE_AFIPX
1910         if (ipxtype == NULL)
1911                 ipxtype = get_afntype(AF_IPX);
1912
1913         if (ipxtype != NULL) {
1914                 if (ptr->has_ipx_bb)
1915                         printf(_("          IPX/Ethernet II addr:%s\n"),
1916                                    ipxtype->sprint(&ptr->ipxaddr_bb, 1));
1917                 if (ptr->has_ipx_sn)
1918                         printf(_("          IPX/Ethernet SNAP addr:%s\n"),
1919                                    ipxtype->sprint(&ptr->ipxaddr_sn, 1));
1920                 if (ptr->has_ipx_e2)
1921                         printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
1922                                    ipxtype->sprint(&ptr->ipxaddr_e2, 1));
1923                 if (ptr->has_ipx_e3)
1924                         printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
1925                                    ipxtype->sprint(&ptr->ipxaddr_e3, 1));
1926         }
1927 #endif
1928
1929 #if HAVE_AFATALK
1930         if (ddptype == NULL)
1931                 ddptype = get_afntype(AF_APPLETALK);
1932         if (ddptype != NULL) {
1933                 if (ptr->has_ddp)
1934                         printf(_("          EtherTalk Phase 2 addr:%s\n"),
1935                                    ddptype->sprint(&ptr->ddpaddr, 1));
1936         }
1937 #endif
1938
1939 #if HAVE_AFECONET
1940         if (ectype == NULL)
1941                 ectype = get_afntype(AF_ECONET);
1942         if (ectype != NULL) {
1943                 if (ptr->has_econet)
1944                         printf(_("          econet addr:%s\n"),
1945                                    ectype->sprint(&ptr->ecaddr, 1));
1946         }
1947 #endif
1948
1949         printf("          ");
1950         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1951
1952         if (ptr->flags == 0) {
1953                 printf(_("[NO FLAGS] "));
1954         } else {
1955                 int i = 0;
1956                 do {
1957                         if (ptr->flags & ife_print_flags_mask[i]) {
1958                                 printf(_(ife_print_flags_strs[i]));
1959                         }
1960                 } while (ife_print_flags_mask[++i]);
1961         }
1962
1963         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1964         printf(_(" MTU:%d  Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1965 #ifdef SIOCSKEEPALIVE
1966         if (ptr->outfill || ptr->keepalive)
1967                 printf(_("  Outfill:%d  Keepalive:%d"), ptr->outfill, ptr->keepalive);
1968 #endif
1969         printf("\n");
1970
1971         /* If needed, display the interface statistics. */
1972
1973         if (ptr->statistics_valid) {
1974                 /* XXX: statistics are currently only printed for the primary address,
1975                  *      not for the aliases, although strictly speaking they're shared
1976                  *      by all addresses.
1977                  */
1978                 printf("          ");
1979
1980                 printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
1981                            ptr->stats.rx_packets, ptr->stats.rx_errors,
1982                            ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1983                            ptr->stats.rx_frame_errors);
1984                 if (can_compress)
1985                         printf(_("             compressed:%lu\n"),
1986                                    ptr->stats.rx_compressed);
1987                 printf("          ");
1988                 printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
1989                            ptr->stats.tx_packets, ptr->stats.tx_errors,
1990                            ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1991                            ptr->stats.tx_carrier_errors);
1992                 printf(_("          collisions:%lu "), ptr->stats.collisions);
1993                 if (can_compress)
1994                         printf(_("compressed:%lu "), ptr->stats.tx_compressed);
1995                 if (ptr->tx_queue_len != -1)
1996                         printf(_("txqueuelen:%d "), ptr->tx_queue_len);
1997                 printf("\n          R");
1998                 print_bytes_scaled(ptr->stats.rx_bytes, "  T");
1999                 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
2000
2001         }
2002
2003         if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
2004                  ptr->map.base_addr)) {
2005                 printf("          ");
2006                 if (ptr->map.irq)
2007                         printf(_("Interrupt:%d "), ptr->map.irq);
2008                 if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for
2009                                                                                            I/O maps */
2010                         printf(_("Base address:0x%lx "),
2011                                    (unsigned long) ptr->map.base_addr);
2012                 if (ptr->map.mem_start) {
2013                         printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
2014                                    ptr->map.mem_end);
2015                 }
2016                 if (ptr->map.dma)
2017                         printf(_("DMA chan:%x "), ptr->map.dma);
2018                 printf("\n");
2019         }
2020         printf("\n");
2021 }
2022
2023
2024 static int do_if_print(struct interface *ife, void *cookie)
2025 {
2026         int *opt_a = (int *) cookie;
2027         int res;
2028
2029         res = do_if_fetch(ife);
2030         if (res >= 0) {
2031                 if ((ife->flags & IFF_UP) || *opt_a)
2032                         ife_print(ife);
2033         }
2034         return res;
2035 }
2036
2037 static struct interface *lookup_interface(char *name)
2038 {
2039         struct interface *ife = NULL;
2040
2041         if (if_readlist_proc(name) < 0)
2042                 return NULL;
2043         ife = add_interface(name);
2044         return ife;
2045 }
2046
2047 /* for ipv4 add/del modes */
2048 static int if_print(char *ifname)
2049 {
2050         int res;
2051
2052         if (!ifname) {
2053                 res = for_all_interfaces(do_if_print, &interface_opt_a);
2054         } else {
2055                 struct interface *ife;
2056
2057                 ife = lookup_interface(ifname);
2058                 res = do_if_fetch(ife);
2059                 if (res >= 0)
2060                         ife_print(ife);
2061         }
2062         return res;
2063 }
2064
2065 int display_interfaces(char *ifname)
2066 {
2067         int status;
2068
2069         /* Create a channel to the NET kernel. */
2070         if ((skfd = sockets_open(0)) < 0) {
2071                 bb_perror_msg_and_die("socket");
2072         }
2073
2074         /* Do we have to show the current setup? */
2075         status = if_print(ifname);
2076         close(skfd);
2077         exit(status < 0);
2078 }