Add some error messages, use xmalloc instead of malloc
[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.20 2003/08/29 11:34:08 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 *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 #warning devel code
1711 static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
1712
1713 static void print_bytes_scaled(unsigned long long ull, const char *end)
1714 {
1715         unsigned long long int_part;
1716         const char *ext;
1717         unsigned int frac_part;
1718         int i;
1719
1720         frac_part = 0;
1721         ext = TRext;
1722         int_part = ull;
1723         i = 4;
1724         do {
1725 #if 0
1726                 /* This does correct rounding and is a little larger.  But it
1727                  * uses KiB as the smallest displayed unit. */
1728                 if ((int_part < (1024*1024 - 51)) || !--i) {
1729                         i = 0;
1730                         int_part += 51;         /* 1024*.05 = 51.2 */
1731                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1732                 }
1733                 int_part /= 1024;
1734                 ext += 3;       /* KiB, MiB, GiB, TiB */
1735 #else
1736                 if (int_part >= 1024) {
1737                         frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1738                         int_part /= 1024;
1739                         ext += 3;       /* KiB, MiB, GiB, TiB */
1740                 }
1741                 --i;
1742 #endif
1743         } while (i);
1744
1745         printf("X bytes:%Lu (%Lu.%u %sB)%s", ull, int_part, frac_part, ext, end);
1746 }
1747
1748 static const char * const ife_print_flags_strs[] = {
1749         "UP ",
1750         "BROADCAST ",
1751         "DEBUG ",
1752         "LOOPBACK ",
1753         "POINTOPOINT ",
1754         "NOTRAILERS ",
1755         "RUNNING ",
1756         "NOARP ",
1757         "PROMISC ",
1758         "ALLMULTI ",
1759         "SLAVE ",
1760         "MASTER ",
1761         "MULTICAST ",
1762 #ifdef HAVE_DYNAMIC
1763         "DYNAMIC "
1764 #endif
1765 };
1766
1767 static const unsigned short ife_print_flags_mask[] = {
1768         IFF_UP,
1769         IFF_BROADCAST,
1770         IFF_DEBUG,
1771         IFF_LOOPBACK,
1772         IFF_POINTOPOINT,
1773         IFF_NOTRAILERS,
1774         IFF_RUNNING,
1775         IFF_NOARP,
1776         IFF_PROMISC,
1777         IFF_ALLMULTI,
1778         IFF_SLAVE,
1779         IFF_MASTER,
1780         IFF_MULTICAST,
1781 #ifdef HAVE_DYNAMIC
1782         IFF_DYNAMIC
1783 #endif
1784         0
1785 };
1786
1787 static void ife_print(struct interface *ptr)
1788 {
1789         struct aftype *ap;
1790         struct hwtype *hw;
1791         int hf;
1792         int can_compress = 0;
1793
1794 #if HAVE_AFIPX
1795         static struct aftype *ipxtype = NULL;
1796 #endif
1797 #if HAVE_AFECONET
1798         static struct aftype *ectype = NULL;
1799 #endif
1800 #if HAVE_AFATALK
1801         static struct aftype *ddptype = NULL;
1802 #endif
1803 #if HAVE_AFINET6
1804         FILE *f;
1805         char addr6[40], devname[20];
1806         struct sockaddr_in6 sap;
1807         int plen, scope, dad_status, if_idx;
1808         char addr6p[8][5];
1809 #endif
1810
1811         ap = get_afntype(ptr->addr.sa_family);
1812         if (ap == NULL)
1813                 ap = get_afntype(0);
1814
1815         hf = ptr->type;
1816
1817         if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1818                 can_compress = 1;
1819
1820         hw = get_hwntype(hf);
1821         if (hw == NULL)
1822                 hw = get_hwntype(-1);
1823
1824         printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
1825         /* For some hardware types (eg Ash, ATM) we don't print the 
1826            hardware address if it's null.  */
1827         if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1828                                                                 hw->suppress_null_addr)))
1829                 printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
1830 #ifdef IFF_PORTSEL
1831         if (ptr->flags & IFF_PORTSEL) {
1832                 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
1833                 if (ptr->flags & IFF_AUTOMEDIA)
1834                         printf(_("(auto)"));
1835         }
1836 #endif
1837         printf("\n");
1838
1839 #if HAVE_AFINET
1840         if (ptr->has_ip) {
1841                 printf(_("          %s addr:%s "), ap->name,
1842                            ap->sprint(&ptr->addr, 1));
1843                 if (ptr->flags & IFF_POINTOPOINT) {
1844                         printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1845                 }
1846                 if (ptr->flags & IFF_BROADCAST) {
1847                         printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1848                 }
1849                 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1850         }
1851 #endif
1852
1853 #if HAVE_AFINET6
1854
1855 #define IPV6_ADDR_ANY           0x0000U
1856
1857 #define IPV6_ADDR_UNICAST       0x0001U
1858 #define IPV6_ADDR_MULTICAST     0x0002U
1859 #define IPV6_ADDR_ANYCAST       0x0004U
1860
1861 #define IPV6_ADDR_LOOPBACK      0x0010U
1862 #define IPV6_ADDR_LINKLOCAL     0x0020U
1863 #define IPV6_ADDR_SITELOCAL     0x0040U
1864
1865 #define IPV6_ADDR_COMPATv4      0x0080U
1866
1867 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
1868
1869 #define IPV6_ADDR_MAPPED        0x1000U
1870 #define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
1871
1872         if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1873                 while (fscanf
1874                            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1875                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1876                                 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1877                                 &dad_status, devname) != EOF) {
1878                         if (!strcmp(devname, ptr->name)) {
1879                                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1880                                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1881                                                 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1882                                 inet_pton(AF_INET6, addr6,
1883                                                   (struct sockaddr *) &sap.sin6_addr);
1884                                 sap.sin6_family = AF_INET6;
1885                                 printf(_("          inet6 addr: %s/%d"),
1886                                            inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1887                                            plen);
1888                                 printf(_(" Scope:"));
1889                                 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1890                                 case 0:
1891                                         printf(_("Global"));
1892                                         break;
1893                                 case IPV6_ADDR_LINKLOCAL:
1894                                         printf(_("Link"));
1895                                         break;
1896                                 case IPV6_ADDR_SITELOCAL:
1897                                         printf(_("Site"));
1898                                         break;
1899                                 case IPV6_ADDR_COMPATv4:
1900                                         printf(_("Compat"));
1901                                         break;
1902                                 case IPV6_ADDR_LOOPBACK:
1903                                         printf(_("Host"));
1904                                         break;
1905                                 default:
1906                                         printf(_("Unknown"));
1907                                 }
1908                                 printf("\n");
1909                         }
1910                 }
1911                 fclose(f);
1912         }
1913 #endif
1914
1915 #if HAVE_AFIPX
1916         if (ipxtype == NULL)
1917                 ipxtype = get_afntype(AF_IPX);
1918
1919         if (ipxtype != NULL) {
1920                 if (ptr->has_ipx_bb)
1921                         printf(_("          IPX/Ethernet II addr:%s\n"),
1922                                    ipxtype->sprint(&ptr->ipxaddr_bb, 1));
1923                 if (ptr->has_ipx_sn)
1924                         printf(_("          IPX/Ethernet SNAP addr:%s\n"),
1925                                    ipxtype->sprint(&ptr->ipxaddr_sn, 1));
1926                 if (ptr->has_ipx_e2)
1927                         printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
1928                                    ipxtype->sprint(&ptr->ipxaddr_e2, 1));
1929                 if (ptr->has_ipx_e3)
1930                         printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
1931                                    ipxtype->sprint(&ptr->ipxaddr_e3, 1));
1932         }
1933 #endif
1934
1935 #if HAVE_AFATALK
1936         if (ddptype == NULL)
1937                 ddptype = get_afntype(AF_APPLETALK);
1938         if (ddptype != NULL) {
1939                 if (ptr->has_ddp)
1940                         printf(_("          EtherTalk Phase 2 addr:%s\n"),
1941                                    ddptype->sprint(&ptr->ddpaddr, 1));
1942         }
1943 #endif
1944
1945 #if HAVE_AFECONET
1946         if (ectype == NULL)
1947                 ectype = get_afntype(AF_ECONET);
1948         if (ectype != NULL) {
1949                 if (ptr->has_econet)
1950                         printf(_("          econet addr:%s\n"),
1951                                    ectype->sprint(&ptr->ecaddr, 1));
1952         }
1953 #endif
1954
1955         printf("          ");
1956         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1957
1958         if (ptr->flags == 0) {
1959                 printf(_("[NO FLAGS] "));
1960         } else {
1961                 int i = 0;
1962                 do {
1963                         if (ptr->flags & ife_print_flags_mask[i]) {
1964                                 printf(_(ife_print_flags_strs[i]));
1965                         }
1966                 } while (ife_print_flags_mask[++i]);
1967         }
1968
1969         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1970         printf(_(" MTU:%d  Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1971 #ifdef SIOCSKEEPALIVE
1972         if (ptr->outfill || ptr->keepalive)
1973                 printf(_("  Outfill:%d  Keepalive:%d"), ptr->outfill, ptr->keepalive);
1974 #endif
1975         printf("\n");
1976
1977         /* If needed, display the interface statistics. */
1978
1979         if (ptr->statistics_valid) {
1980                 /* XXX: statistics are currently only printed for the primary address,
1981                  *      not for the aliases, although strictly speaking they're shared
1982                  *      by all addresses.
1983                  */
1984                 printf("          ");
1985
1986                 printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
1987                            ptr->stats.rx_packets, ptr->stats.rx_errors,
1988                            ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1989                            ptr->stats.rx_frame_errors);
1990                 if (can_compress)
1991                         printf(_("             compressed:%lu\n"),
1992                                    ptr->stats.rx_compressed);
1993                 printf("          ");
1994                 printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
1995                            ptr->stats.tx_packets, ptr->stats.tx_errors,
1996                            ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1997                            ptr->stats.tx_carrier_errors);
1998                 printf(_("          collisions:%lu "), ptr->stats.collisions);
1999                 if (can_compress)
2000                         printf(_("compressed:%lu "), ptr->stats.tx_compressed);
2001                 if (ptr->tx_queue_len != -1)
2002                         printf(_("txqueuelen:%d "), ptr->tx_queue_len);
2003                 printf("\n          R");
2004                 print_bytes_scaled(ptr->stats.rx_bytes, "  T");
2005                 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
2006
2007         }
2008
2009         if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
2010                  ptr->map.base_addr)) {
2011                 printf("          ");
2012                 if (ptr->map.irq)
2013                         printf(_("Interrupt:%d "), ptr->map.irq);
2014                 if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for 
2015                                                                                            I/O maps */
2016                         printf(_("Base address:0x%lx "),
2017                                    (unsigned long) ptr->map.base_addr);
2018                 if (ptr->map.mem_start) {
2019                         printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
2020                                    ptr->map.mem_end);
2021                 }
2022                 if (ptr->map.dma)
2023                         printf(_("DMA chan:%x "), ptr->map.dma);
2024                 printf("\n");
2025         }
2026         printf("\n");
2027 }
2028
2029
2030 static int do_if_print(struct interface *ife, void *cookie)
2031 {
2032         int *opt_a = (int *) cookie;
2033         int res;
2034
2035         res = do_if_fetch(ife);
2036         if (res >= 0) {
2037                 if ((ife->flags & IFF_UP) || *opt_a)
2038                         ife_print(ife);
2039         }
2040         return res;
2041 }
2042
2043 static struct interface *lookup_interface(char *name)
2044 {
2045         struct interface *ife = NULL;
2046
2047         if (if_readlist_proc(name) < 0)
2048                 return NULL;
2049         ife = add_interface(name);
2050         return ife;
2051 }
2052
2053 /* for ipv4 add/del modes */
2054 static int if_print(char *ifname)
2055 {
2056         int res;
2057
2058         if (!ifname) {
2059                 res = for_all_interfaces(do_if_print, &interface_opt_a);
2060         } else {
2061                 struct interface *ife;
2062
2063                 ife = lookup_interface(ifname);
2064                 res = do_if_fetch(ife);
2065                 if (res >= 0)
2066                         ife_print(ife);
2067         }
2068         return res;
2069 }
2070
2071 int display_interfaces(char *ifname)
2072 {
2073         int status;
2074
2075         /* Create a channel to the NET kernel. */
2076         if ((skfd = sockets_open(0)) < 0) {
2077                 bb_perror_msg_and_die("socket");
2078         }
2079
2080         /* Do we have to show the current setup? */
2081         status = if_print(ifname);
2082         close(skfd);
2083         exit(status < 0);
2084 }