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