2f43192657c1d71153ce98b627de83e91a87d686
[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.11 2002/11/26 09:02:04 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 #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 <linux/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                                 fprintf(stderr, _("Too much address family arguments.\n"));
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                         fprintf(stderr, _("Unknown address family `%s'.\n"), 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                 fprintf(stderr,
697                                 _("Please don't supply more than one address family.\n"));
698         return (NULL);
699 }
700 #endif                                                  /* KEEP_UNUSED */
701
702 /* Check our protocol family table for this family. */
703 static struct aftype *get_afntype(int af)
704 {
705         struct aftype **afp;
706
707 #ifdef KEEP_UNUSED
708         if (!sVafinit)
709                 afinit();
710 #endif                                                  /* KEEP_UNUSED */
711
712         afp = aftypes;
713         while (*afp != NULL) {
714                 if ((*afp)->af == af)
715                         return (*afp);
716                 afp++;
717         }
718         return (NULL);
719 }
720
721 /* Check our protocol family table for this family and return its socket */
722 static int get_socket_for_af(int af)
723 {
724         struct aftype **afp;
725
726 #ifdef KEEP_UNUSED
727         if (!sVafinit)
728                 afinit();
729 #endif                                                  /* KEEP_UNUSED */
730
731         afp = aftypes;
732         while (*afp != NULL) {
733                 if ((*afp)->af == af)
734                         return (*afp)->fd;
735                 afp++;
736         }
737         return -1;
738 }
739
740 #ifdef KEEP_UNUSED
741 /* type: 0=all, 1=getroute */
742 static void print_aflist(int type)
743 {
744         int count = 0;
745         char *txt;
746         struct aftype **afp;
747
748 #ifdef KEEP_UNUSED
749         if (!sVafinit)
750                 afinit();
751 #endif                                                  /* KEEP_UNUSED */
752
753         afp = aftypes;
754         while (*afp != NULL) {
755                 if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) {
756                         afp++;
757                         continue;
758                 }
759                 if ((count % 3) == 0)
760                         fprintf(stderr, count ? "\n    " : "    ");
761                 txt = (*afp)->name;
762                 if (!txt)
763                         txt = "..";
764                 fprintf(stderr, "%s (%s) ", txt, _((*afp)->title));
765                 count++;
766                 afp++;
767         }
768         fprintf(stderr, "\n");
769 }
770 #endif                                                  /* KEEP_UNUSED */
771
772 struct user_net_device_stats {
773         unsigned long long rx_packets;  /* total packets received       */
774         unsigned long long tx_packets;  /* total packets transmitted    */
775         unsigned long long rx_bytes;    /* total bytes received         */
776         unsigned long long tx_bytes;    /* total bytes transmitted      */
777         unsigned long rx_errors;        /* bad packets received         */
778         unsigned long tx_errors;        /* packet transmit problems     */
779         unsigned long rx_dropped;       /* no space in linux buffers    */
780         unsigned long tx_dropped;       /* no space available in linux  */
781         unsigned long rx_multicast;     /* multicast packets received   */
782         unsigned long rx_compressed;
783         unsigned long tx_compressed;
784         unsigned long collisions;
785
786         /* detailed rx_errors: */
787         unsigned long rx_length_errors;
788         unsigned long rx_over_errors;   /* receiver ring buff overflow  */
789         unsigned long rx_crc_errors;    /* recved pkt with crc error    */
790         unsigned long rx_frame_errors;  /* recv'd frame alignment error */
791         unsigned long rx_fifo_errors;   /* recv'r fifo overrun          */
792         unsigned long rx_missed_errors; /* receiver missed packet     */
793         /* detailed tx_errors */
794         unsigned long tx_aborted_errors;
795         unsigned long tx_carrier_errors;
796         unsigned long tx_fifo_errors;
797         unsigned long tx_heartbeat_errors;
798         unsigned long tx_window_errors;
799 };
800
801 struct interface {
802         struct interface *next, *prev;
803         char name[IFNAMSIZ];    /* interface name        */
804         short type;                     /* if type               */
805         short flags;            /* various flags         */
806         int metric;                     /* routing metric        */
807         int mtu;                        /* MTU value             */
808         int tx_queue_len;       /* transmit queue length */
809         struct ifmap map;       /* hardware setup        */
810         struct sockaddr addr;   /* IP address            */
811         struct sockaddr dstaddr;        /* P-P IP address        */
812         struct sockaddr broadaddr;      /* IP broadcast address  */
813         struct sockaddr netmask;        /* IP network mask       */
814         struct sockaddr ipxaddr_bb;     /* IPX network address   */
815         struct sockaddr ipxaddr_sn;     /* IPX network address   */
816         struct sockaddr ipxaddr_e3;     /* IPX network address   */
817         struct sockaddr ipxaddr_e2;     /* IPX network address   */
818         struct sockaddr ddpaddr;        /* Appletalk DDP address */
819         struct sockaddr ecaddr; /* Econet address        */
820         int has_ip;
821         int has_ipx_bb;
822         int has_ipx_sn;
823         int has_ipx_e3;
824         int has_ipx_e2;
825         int has_ax25;
826         int has_ddp;
827         int has_econet;
828         char hwaddr[32];        /* HW address            */
829         int statistics_valid;
830         struct user_net_device_stats stats;     /* statistics            */
831         int keepalive;          /* keepalive value for SLIP */
832         int outfill;            /* outfill value for SLIP */
833 };
834
835
836 int interface_opt_a = 0;        /* show all interfaces          */
837
838 #ifdef KEEP_UNUSED
839 static int opt_i = 0;   /* show the statistics          */
840 static int opt_v = 0;   /* debugging output flag        */
841
842 static int addr_family = 0;     /* currently selected AF        */
843 #endif                                                  /* KEEP_UNUSED */
844
845 static struct interface *int_list, *int_last;
846 static int skfd = -1;   /* generic raw socket desc.     */
847
848
849 static int sockets_open(int family)
850 {
851         struct aftype **aft;
852         int sfd = -1;
853         static int force = -1;
854
855         if (force < 0) {
856                 force = 0;
857                 if (get_kernel_revision() < KRELEASE(2, 1, 0))
858                         force = 1;
859                 if (access("/proc/net", R_OK))
860                         force = 1;
861         }
862         for (aft = aftypes; *aft; aft++) {
863                 struct aftype *af = *aft;
864                 int type = SOCK_DGRAM;
865
866                 if (af->af == AF_UNSPEC)
867                         continue;
868                 if (family && family != af->af)
869                         continue;
870                 if (af->fd != -1) {
871                         sfd = af->fd;
872                         continue;
873                 }
874                 /* Check some /proc file first to not stress kmod */
875                 if (!family && !force && af->flag_file) {
876                         if (access(af->flag_file, R_OK))
877                                 continue;
878                 }
879 #if HAVE_AFNETROM
880                 if (af->af == AF_NETROM)
881                         type = SOCK_SEQPACKET;
882 #endif
883 #if HAVE_AFX25
884                 if (af->af == AF_X25)
885                         type = SOCK_SEQPACKET;
886 #endif
887                 af->fd = socket(af->af, type, 0);
888                 if (af->fd >= 0)
889                         sfd = af->fd;
890         }
891         if (sfd < 0)
892                 fprintf(stderr, _("No usable address families found.\n"));
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                 fprintf(stderr, _("warning: no inet socket available: %s\n"),
964                                 strerror(errno));
965                 /* Try to soldier on with whatever socket we can get hold of.  */
966                 skfd2 = sockets_open(0);
967                 if (skfd2 < 0)
968                         return -1;
969         }
970
971         ifc.ifc_buf = NULL;
972         for (;;) {
973                 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
974                 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
975
976                 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
977                         perror("SIOCGIFCONF");
978                         goto out;
979                 }
980                 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
981                         /* assume it overflowed and try again */
982                         numreqs += 10;
983                         continue;
984                 }
985                 break;
986         }
987
988         ifr = ifc.ifc_req;
989         for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
990                 add_interface(ifr->ifr_name);
991                 ifr++;
992         }
993         err = 0;
994
995   out:
996         free(ifc.ifc_buf);
997         return err;
998 }
999
1000 static char *get_name(char *name, char *p)
1001 {
1002         while (isspace(*p))
1003                 p++;
1004         while (*p) {
1005                 if (isspace(*p))
1006                         break;
1007                 if (*p == ':') {        /* could be an alias */
1008                         char *dot = p, *dotname = name;
1009
1010                         *name++ = *p++;
1011                         while (isdigit(*p))
1012                                 *name++ = *p++;
1013                         if (*p != ':') {        /* it wasn't, backup */
1014                                 p = dot;
1015                                 name = dotname;
1016                         }
1017                         if (*p == '\0')
1018                                 return NULL;
1019                         p++;
1020                         break;
1021                 }
1022                 *name++ = *p++;
1023         }
1024         *name++ = '\0';
1025         return p;
1026 }
1027
1028 static int get_dev_fields(char *bp, struct interface *ife)
1029 {
1030         switch (procnetdev_vsn) {
1031         case 3:
1032                 sscanf(bp,
1033                            "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
1034                            &ife->stats.rx_bytes,
1035                            &ife->stats.rx_packets,
1036                            &ife->stats.rx_errors,
1037                            &ife->stats.rx_dropped,
1038                            &ife->stats.rx_fifo_errors,
1039                            &ife->stats.rx_frame_errors,
1040                            &ife->stats.rx_compressed,
1041                            &ife->stats.rx_multicast,
1042                            &ife->stats.tx_bytes,
1043                            &ife->stats.tx_packets,
1044                            &ife->stats.tx_errors,
1045                            &ife->stats.tx_dropped,
1046                            &ife->stats.tx_fifo_errors,
1047                            &ife->stats.collisions,
1048                            &ife->stats.tx_carrier_errors, &ife->stats.tx_compressed);
1049                 break;
1050         case 2:
1051                 sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
1052                            &ife->stats.rx_bytes,
1053                            &ife->stats.rx_packets,
1054                            &ife->stats.rx_errors,
1055                            &ife->stats.rx_dropped,
1056                            &ife->stats.rx_fifo_errors,
1057                            &ife->stats.rx_frame_errors,
1058                            &ife->stats.tx_bytes,
1059                            &ife->stats.tx_packets,
1060                            &ife->stats.tx_errors,
1061                            &ife->stats.tx_dropped,
1062                            &ife->stats.tx_fifo_errors,
1063                            &ife->stats.collisions, &ife->stats.tx_carrier_errors);
1064                 ife->stats.rx_multicast = 0;
1065                 break;
1066         case 1:
1067                 sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
1068                            &ife->stats.rx_packets,
1069                            &ife->stats.rx_errors,
1070                            &ife->stats.rx_dropped,
1071                            &ife->stats.rx_fifo_errors,
1072                            &ife->stats.rx_frame_errors,
1073                            &ife->stats.tx_packets,
1074                            &ife->stats.tx_errors,
1075                            &ife->stats.tx_dropped,
1076                            &ife->stats.tx_fifo_errors,
1077                            &ife->stats.collisions, &ife->stats.tx_carrier_errors);
1078                 ife->stats.rx_bytes = 0;
1079                 ife->stats.tx_bytes = 0;
1080                 ife->stats.rx_multicast = 0;
1081                 break;
1082         }
1083         return 0;
1084 }
1085
1086 static inline int procnetdev_version(char *buf)
1087 {
1088         if (strstr(buf, "compressed"))
1089                 return 3;
1090         if (strstr(buf, "bytes"))
1091                 return 2;
1092         return 1;
1093 }
1094
1095 static int if_readlist_proc(char *target)
1096 {
1097         static int proc_read;
1098         FILE *fh;
1099         char buf[512];
1100         struct interface *ife;
1101         int err;
1102
1103         if (proc_read)
1104                 return 0;
1105         if (!target)
1106                 proc_read = 1;
1107
1108         fh = fopen(_PATH_PROCNET_DEV, "r");
1109         if (!fh) {
1110                 fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
1111                                 _PATH_PROCNET_DEV, strerror(errno));
1112                 return if_readconf();
1113         }
1114         fgets(buf, sizeof buf, fh);     /* eat line */
1115         fgets(buf, sizeof buf, fh);
1116
1117 #if 0                                   /* pretty, but can't cope with missing fields */
1118         fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh, "face", "",        /* parsed separately */
1119                                            "bytes", "%lu",
1120                                            "packets", "%lu",
1121                                            "errs", "%lu",
1122                                            "drop", "%lu",
1123                                            "fifo", "%lu",
1124                                            "frame", "%lu",
1125                                            "compressed", "%lu",
1126                                            "multicast", "%lu",
1127                                            "bytes", "%lu",
1128                                            "packets", "%lu",
1129                                            "errs", "%lu",
1130                                            "drop", "%lu",
1131                                            "fifo", "%lu",
1132                                            "colls", "%lu",
1133                                            "carrier", "%lu", "compressed", "%lu", NULL);
1134         if (!fmt)
1135                 return -1;
1136 #else
1137         procnetdev_vsn = procnetdev_version(buf);
1138 #endif
1139
1140         err = 0;
1141         while (fgets(buf, sizeof buf, fh)) {
1142                 char *s, name[IFNAMSIZ];
1143
1144                 s = get_name(name, buf);
1145                 ife = add_interface(name);
1146                 get_dev_fields(s, ife);
1147                 ife->statistics_valid = 1;
1148                 if (target && !strcmp(target, name))
1149                         break;
1150         }
1151         if (ferror(fh)) {
1152                 perror(_PATH_PROCNET_DEV);
1153                 err = -1;
1154                 proc_read = 0;
1155         }
1156 #if 0
1157         free(fmt);
1158 #endif
1159         fclose(fh);
1160         return err;
1161 }
1162
1163 static int if_readlist(void)
1164 {
1165         int err = if_readlist_proc(NULL);
1166
1167         if (!err)
1168                 err = if_readconf();
1169         return err;
1170 }
1171
1172 static int for_all_interfaces(int (*doit) (struct interface *, void *),
1173                                                           void *cookie)
1174 {
1175         struct interface *ife;
1176
1177         if (!int_list && (if_readlist() < 0))
1178                 return -1;
1179         for (ife = int_list; ife; ife = ife->next) {
1180                 int err = doit(ife, cookie);
1181
1182                 if (err)
1183                         return err;
1184         }
1185         return 0;
1186 }
1187
1188 /* Support for fetching an IPX address */
1189
1190 #if HAVE_AFIPX
1191 static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
1192 {
1193         ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
1194         return ioctl(sock, SIOCGIFADDR, ifr);
1195 }
1196 #endif
1197
1198
1199 /* Fetch the interface configuration from the kernel. */
1200 static int if_fetch(struct interface *ife)
1201 {
1202         struct ifreq ifr;
1203         int fd;
1204         char *ifname = ife->name;
1205
1206         strcpy(ifr.ifr_name, ifname);
1207         if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1208                 return (-1);
1209         ife->flags = ifr.ifr_flags;
1210
1211         strcpy(ifr.ifr_name, ifname);
1212         if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1213                 memset(ife->hwaddr, 0, 32);
1214         else
1215                 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
1216
1217         ife->type = ifr.ifr_hwaddr.sa_family;
1218
1219         strcpy(ifr.ifr_name, ifname);
1220         if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1221                 ife->metric = 0;
1222         else
1223                 ife->metric = ifr.ifr_metric;
1224
1225         strcpy(ifr.ifr_name, ifname);
1226         if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1227                 ife->mtu = 0;
1228         else
1229                 ife->mtu = ifr.ifr_mtu;
1230
1231 #ifdef HAVE_HWSLIP
1232         if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1233                 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1234                 ife->type == ARPHRD_ADAPT) {
1235 #ifdef SIOCGOUTFILL
1236                 strcpy(ifr.ifr_name, ifname);
1237                 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1238                         ife->outfill = 0;
1239                 else
1240                         ife->outfill = (unsigned int) ifr.ifr_data;
1241 #endif
1242 #ifdef SIOCGKEEPALIVE
1243                 strcpy(ifr.ifr_name, ifname);
1244                 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1245                         ife->keepalive = 0;
1246                 else
1247                         ife->keepalive = (unsigned int) ifr.ifr_data;
1248 #endif
1249         }
1250 #endif
1251
1252         strcpy(ifr.ifr_name, ifname);
1253         if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1254                 memset(&ife->map, 0, sizeof(struct ifmap));
1255         else
1256                 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
1257
1258         strcpy(ifr.ifr_name, ifname);
1259         if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1260                 memset(&ife->map, 0, sizeof(struct ifmap));
1261         else
1262                 ife->map = ifr.ifr_map;
1263
1264 #ifdef HAVE_TXQUEUELEN
1265         strcpy(ifr.ifr_name, ifname);
1266         if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1267                 ife->tx_queue_len = -1; /* unknown value */
1268         else
1269                 ife->tx_queue_len = ifr.ifr_qlen;
1270 #else
1271         ife->tx_queue_len = -1; /* unknown value */
1272 #endif
1273
1274 #if HAVE_AFINET
1275         /* IPv4 address? */
1276         fd = get_socket_for_af(AF_INET);
1277         if (fd >= 0) {
1278                 strcpy(ifr.ifr_name, ifname);
1279                 ifr.ifr_addr.sa_family = AF_INET;
1280                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1281                         ife->has_ip = 1;
1282                         ife->addr = ifr.ifr_addr;
1283                         strcpy(ifr.ifr_name, ifname);
1284                         if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1285                                 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1286                         else
1287                                 ife->dstaddr = ifr.ifr_dstaddr;
1288
1289                         strcpy(ifr.ifr_name, ifname);
1290                         if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1291                                 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1292                         else
1293                                 ife->broadaddr = ifr.ifr_broadaddr;
1294
1295                         strcpy(ifr.ifr_name, ifname);
1296                         if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1297                                 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1298                         else
1299                                 ife->netmask = ifr.ifr_netmask;
1300                 } else
1301                         memset(&ife->addr, 0, sizeof(struct sockaddr));
1302         }
1303 #endif
1304
1305 #if HAVE_AFATALK
1306         /* DDP address maybe ? */
1307         fd = get_socket_for_af(AF_APPLETALK);
1308         if (fd >= 0) {
1309                 strcpy(ifr.ifr_name, ifname);
1310                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1311                         ife->ddpaddr = ifr.ifr_addr;
1312                         ife->has_ddp = 1;
1313                 }
1314         }
1315 #endif
1316
1317 #if HAVE_AFIPX
1318         /* Look for IPX addresses with all framing types */
1319         fd = get_socket_for_af(AF_IPX);
1320         if (fd >= 0) {
1321                 strcpy(ifr.ifr_name, ifname);
1322                 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
1323                         ife->has_ipx_bb = 1;
1324                         ife->ipxaddr_bb = ifr.ifr_addr;
1325                 }
1326                 strcpy(ifr.ifr_name, ifname);
1327                 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
1328                         ife->has_ipx_sn = 1;
1329                         ife->ipxaddr_sn = ifr.ifr_addr;
1330                 }
1331                 strcpy(ifr.ifr_name, ifname);
1332                 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
1333                         ife->has_ipx_e3 = 1;
1334                         ife->ipxaddr_e3 = ifr.ifr_addr;
1335                 }
1336                 strcpy(ifr.ifr_name, ifname);
1337                 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
1338                         ife->has_ipx_e2 = 1;
1339                         ife->ipxaddr_e2 = ifr.ifr_addr;
1340                 }
1341         }
1342 #endif
1343
1344 #if HAVE_AFECONET
1345         /* Econet address maybe? */
1346         fd = get_socket_for_af(AF_ECONET);
1347         if (fd >= 0) {
1348                 strcpy(ifr.ifr_name, ifname);
1349                 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1350                         ife->ecaddr = ifr.ifr_addr;
1351                         ife->has_econet = 1;
1352                 }
1353         }
1354 #endif
1355
1356         return 0;
1357 }
1358
1359
1360 static int do_if_fetch(struct interface *ife)
1361 {
1362         if (if_fetch(ife) < 0) {
1363                 char *errmsg;
1364
1365                 if (errno == ENODEV) {
1366                         /* Give better error message for this case. */
1367                         errmsg = _("Device not found");
1368                 } else {
1369                         errmsg = strerror(errno);
1370                 }
1371                 fprintf(stderr, _("%s: error fetching interface information: %s\n"),
1372                                 ife->name, errmsg);
1373                 return -1;
1374         }
1375         return 0;
1376 }
1377
1378 /* This structure defines hardware protocols and their handlers. */
1379 struct hwtype {
1380         const char *name;
1381         const char *title;
1382         int type;
1383         int alen;
1384         char *(*print) (unsigned char *);
1385         int (*input) (char *, struct sockaddr *);
1386         int (*activate) (int fd);
1387         int suppress_null_addr;
1388 };
1389
1390 static struct hwtype unspec_hwtype = {
1391         "unspec", "UNSPEC", -1, 0,
1392         UNSPEC_print, NULL, NULL
1393 };
1394
1395 static struct hwtype loop_hwtype = {
1396         "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1397         NULL, NULL, NULL
1398 };
1399
1400 #if HAVE_HWETHER
1401 #include <net/if_arp.h>
1402 #include <linux/if_ether.h>
1403
1404 /* Display an Ethernet address in readable format. */
1405 static char *pr_ether(unsigned char *ptr)
1406 {
1407         static char buff[64];
1408
1409         snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1410                          (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1411                          (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1412                 );
1413         return (buff);
1414 }
1415
1416 #ifdef KEEP_UNUSED
1417 /* Input an Ethernet address and convert to binary. */
1418 static int in_ether(char *bufp, struct sockaddr *sap)
1419 {
1420         unsigned char *ptr;
1421         char c, *orig;
1422         int i;
1423         unsigned val;
1424
1425         sap->sa_family = ether_hwtype.type;
1426         ptr = sap->sa_data;
1427
1428         i = 0;
1429         orig = bufp;
1430         while ((*bufp != '\0') && (i < ETH_ALEN)) {
1431                 val = 0;
1432                 c = *bufp++;
1433                 if (isdigit(c))
1434                         val = c - '0';
1435                 else if (c >= 'a' && c <= 'f')
1436                         val = c - 'a' + 10;
1437                 else if (c >= 'A' && c <= 'F')
1438                         val = c - 'A' + 10;
1439                 else {
1440 #ifdef DEBUG
1441                         fprintf(stderr, _("in_ether(%s): invalid ether address!\n"),
1442                                         orig);
1443 #endif
1444                         errno = EINVAL;
1445                         return (-1);
1446                 }
1447                 val <<= 4;
1448                 c = *bufp;
1449                 if (isdigit(c))
1450                         val |= c - '0';
1451                 else if (c >= 'a' && c <= 'f')
1452                         val |= c - 'a' + 10;
1453                 else if (c >= 'A' && c <= 'F')
1454                         val |= c - 'A' + 10;
1455                 else if (c == ':' || c == 0)
1456                         val >>= 4;
1457                 else {
1458 #ifdef DEBUG
1459                         fprintf(stderr, _("in_ether(%s): invalid ether address!\n"),
1460                                         orig);
1461 #endif
1462                         errno = EINVAL;
1463                         return (-1);
1464                 }
1465                 if (c != 0)
1466                         bufp++;
1467                 *ptr++ = (unsigned char) (val & 0377);
1468                 i++;
1469
1470                 /* We might get a semicolon here - not required. */
1471                 if (*bufp == ':') {
1472                         if (i == ETH_ALEN) {
1473 #ifdef DEBUG
1474                                 fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"),
1475                                                 orig)
1476 #endif
1477                                         ;       /* nothing */
1478                         }
1479                         bufp++;
1480                 }
1481         }
1482
1483         /* That's it.  Any trailing junk? */
1484         if ((i == ETH_ALEN) && (*bufp != '\0')) {
1485 #ifdef DEBUG
1486                 fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig);
1487                 errno = EINVAL;
1488                 return (-1);
1489 #endif
1490         }
1491 #ifdef DEBUG
1492         fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
1493 #endif
1494
1495         return (0);
1496 }
1497 #endif                                                  /* KEEP_UNUSED */
1498
1499
1500 static struct hwtype ether_hwtype = {
1501         "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1502         pr_ether, NULL /* UNUSED in_ether */ , NULL
1503 };
1504
1505
1506 #endif                                                  /* HAVE_HWETHER */
1507
1508
1509 #if HAVE_HWPPP
1510
1511 #include <net/if_arp.h>
1512
1513 #ifdef KEEP_UNUSED
1514 /* Start the PPP encapsulation on the file descriptor. */
1515 static int do_ppp(int fd)
1516 {
1517         fprintf(stderr, _("You cannot start PPP with this program.\n"));
1518         return -1;
1519 }
1520 #endif                                                  /* KEEP_UNUSED */
1521
1522 static struct hwtype ppp_hwtype = {
1523         "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1524         NULL, NULL, NULL /* UNUSED do_ppp */ , 0
1525 };
1526
1527
1528 #endif                                                  /* HAVE_PPP */
1529
1530 static struct hwtype *hwtypes[] = {
1531
1532         &loop_hwtype,
1533
1534 #if HAVE_HWSLIP
1535         &slip_hwtype,
1536         &cslip_hwtype,
1537         &slip6_hwtype,
1538         &cslip6_hwtype,
1539         &adaptive_hwtype,
1540 #endif
1541 #if HAVE_HWSTRIP
1542         &strip_hwtype,
1543 #endif
1544 #if HAVE_HWASH
1545         &ash_hwtype,
1546 #endif
1547 #if HAVE_HWETHER
1548         &ether_hwtype,
1549 #endif
1550 #if HAVE_HWTR
1551         &tr_hwtype,
1552 #ifdef ARPHRD_IEEE802_TR
1553         &tr_hwtype1,
1554 #endif
1555 #endif
1556 #if HAVE_HWAX25
1557         &ax25_hwtype,
1558 #endif
1559 #if HAVE_HWNETROM
1560         &netrom_hwtype,
1561 #endif
1562 #if HAVE_HWROSE
1563         &rose_hwtype,
1564 #endif
1565 #if HAVE_HWTUNNEL
1566         &tunnel_hwtype,
1567 #endif
1568 #if HAVE_HWPPP
1569         &ppp_hwtype,
1570 #endif
1571 #if HAVE_HWHDLCLAPB
1572         &hdlc_hwtype,
1573         &lapb_hwtype,
1574 #endif
1575 #if HAVE_HWARC
1576         &arcnet_hwtype,
1577 #endif
1578 #if HAVE_HWFR
1579         &dlci_hwtype,
1580         &frad_hwtype,
1581 #endif
1582 #if HAVE_HWSIT
1583         &sit_hwtype,
1584 #endif
1585 #if HAVE_HWFDDI
1586         &fddi_hwtype,
1587 #endif
1588 #if HAVE_HWHIPPI
1589         &hippi_hwtype,
1590 #endif
1591 #if HAVE_HWIRDA
1592         &irda_hwtype,
1593 #endif
1594 #if HAVE_HWEC
1595         &ec_hwtype,
1596 #endif
1597 #if HAVE_HWX25
1598         &x25_hwtype,
1599 #endif
1600         &unspec_hwtype,
1601         NULL
1602 };
1603
1604 #ifdef KEEP_UNUSED
1605 static short sVhwinit = 0;
1606
1607 static void hwinit()
1608 {
1609         loop_hwtype.title = _("Local Loopback");
1610         unspec_hwtype.title = _("UNSPEC");
1611 #if HAVE_HWSLIP
1612         slip_hwtype.title = _("Serial Line IP");
1613         cslip_hwtype.title = _("VJ Serial Line IP");
1614         slip6_hwtype.title = _("6-bit Serial Line IP");
1615         cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1616         adaptive_hwtype.title = _("Adaptive Serial Line IP");
1617 #endif
1618 #if HAVE_HWETHER
1619         ether_hwtype.title = _("Ethernet");
1620 #endif
1621 #if HAVE_HWASH
1622         ash_hwtype.title = _("Ash");
1623 #endif
1624 #if HAVE_HWFDDI
1625         fddi_hwtype.title = _("Fiber Distributed Data Interface");
1626 #endif
1627 #if HAVE_HWHIPPI
1628         hippi_hwtype.title = _("HIPPI");
1629 #endif
1630 #if HAVE_HWAX25
1631         ax25_hwtype.title = _("AMPR AX.25");
1632 #endif
1633 #if HAVE_HWROSE
1634         rose_hwtype.title = _("AMPR ROSE");
1635 #endif
1636 #if HAVE_HWNETROM
1637         netrom_hwtype.title = _("AMPR NET/ROM");
1638 #endif
1639 #if HAVE_HWX25
1640         x25_hwtype.title = _("generic X.25");
1641 #endif
1642 #if HAVE_HWTUNNEL
1643         tunnel_hwtype.title = _("IPIP Tunnel");
1644 #endif
1645 #if HAVE_HWPPP
1646         ppp_hwtype.title = _("Point-to-Point Protocol");
1647 #endif
1648 #if HAVE_HWHDLCLAPB
1649         hdlc_hwtype.title = _("(Cisco)-HDLC");
1650         lapb_hwtype.title = _("LAPB");
1651 #endif
1652 #if HAVE_HWARC
1653         arcnet_hwtype.title = _("ARCnet");
1654 #endif
1655 #if HAVE_HWFR
1656         dlci_hwtype.title = _("Frame Relay DLCI");
1657         frad_hwtype.title = _("Frame Relay Access Device");
1658 #endif
1659 #if HAVE_HWSIT
1660         sit_hwtype.title = _("IPv6-in-IPv4");
1661 #endif
1662 #if HAVE_HWIRDA
1663         irda_hwtype.title = _("IrLAP");
1664 #endif
1665 #if HAVE_HWTR
1666         tr_hwtype.title = _("16/4 Mbps Token Ring");
1667 #ifdef ARPHRD_IEEE802_TR
1668         tr_hwtype1.title = _("16/4 Mbps Token Ring (New)");
1669 #endif
1670 #endif
1671 #if HAVE_HWEC
1672         ec_hwtype.title = _("Econet");
1673 #endif
1674         sVhwinit = 1;
1675 }
1676 #endif                                                  /* KEEP_UNUSED */
1677
1678 #ifdef IFF_PORTSEL
1679 static const char *if_port_text[][4] = {
1680         /* Keep in step with <linux/netdevice.h> */
1681         {"unknown", NULL, NULL, NULL},
1682         {"10base2", "bnc", "coax", NULL},
1683         {"10baseT", "utp", "tpe", NULL},
1684         {"AUI", "thick", "db15", NULL},
1685         {"100baseT", NULL, NULL, NULL},
1686         {"100baseTX", NULL, NULL, NULL},
1687         {"100baseFX", NULL, NULL, NULL},
1688         {NULL, NULL, NULL, NULL},
1689 };
1690 #endif
1691
1692 /* Check our hardware type table for this type. */
1693 static struct hwtype *get_hwntype(int type)
1694 {
1695         struct hwtype **hwp;
1696
1697 #ifdef KEEP_UNUSED
1698         if (!sVhwinit)
1699                 hwinit();
1700 #endif                                                  /* KEEP_UNUSED */
1701
1702         hwp = hwtypes;
1703         while (*hwp != NULL) {
1704                 if ((*hwp)->type == type)
1705                         return (*hwp);
1706                 hwp++;
1707         }
1708         return (NULL);
1709 }
1710
1711 /* return 1 if address is all zeros */
1712 static int hw_null_address(struct hwtype *hw, void *ap)
1713 {
1714         unsigned int i;
1715         unsigned char *address = (unsigned char *) ap;
1716
1717         for (i = 0; i < hw->alen; i++)
1718                 if (address[i])
1719                         return 0;
1720         return 1;
1721 }
1722
1723 static const char TRext[] = "\0\0k\0M";
1724
1725 static void print_bytes_scaled(unsigned long long ull, const char *end)
1726 {
1727         unsigned long long int_part;
1728         unsigned long frac_part;
1729         const char *ext;
1730         int i;
1731
1732         frac_part = 0;
1733         ext = TRext;
1734         int_part = ull;
1735         for (i = 0; i < 2; i++) {
1736                 if (int_part >= 1024) {
1737                         frac_part = ((int_part % 1024) * 10) / 1024;
1738                         int_part /= 1024;
1739                         ext += 2;       /* Kb, Mb */
1740                 }
1741         }
1742
1743         printf("X bytes:%Lu (%Lu.%lu %siB)%s", ull, int_part, frac_part, ext, end);
1744 }
1745
1746 static void ife_print(struct interface *ptr)
1747 {
1748         struct aftype *ap;
1749         struct hwtype *hw;
1750         int hf;
1751         int can_compress = 0;
1752
1753 #if HAVE_AFIPX
1754         static struct aftype *ipxtype = NULL;
1755 #endif
1756 #if HAVE_AFECONET
1757         static struct aftype *ectype = NULL;
1758 #endif
1759 #if HAVE_AFATALK
1760         static struct aftype *ddptype = NULL;
1761 #endif
1762 #if HAVE_AFINET6
1763         FILE *f;
1764         char addr6[40], devname[20];
1765         struct sockaddr_in6 sap;
1766         int plen, scope, dad_status, if_idx;
1767         char addr6p[8][5];
1768 #endif
1769
1770         ap = get_afntype(ptr->addr.sa_family);
1771         if (ap == NULL)
1772                 ap = get_afntype(0);
1773
1774         hf = ptr->type;
1775
1776         if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1777                 can_compress = 1;
1778
1779         hw = get_hwntype(hf);
1780         if (hw == NULL)
1781                 hw = get_hwntype(-1);
1782
1783         printf(_("%-9.9s Link encap:%s  "), ptr->name, _(hw->title));
1784         /* For some hardware types (eg Ash, ATM) we don't print the 
1785            hardware address if it's null.  */
1786         if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1787                                                                 hw->suppress_null_addr)))
1788                 printf(_("HWaddr %s  "), hw->print(ptr->hwaddr));
1789 #ifdef IFF_PORTSEL
1790         if (ptr->flags & IFF_PORTSEL) {
1791                 printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
1792                 if (ptr->flags & IFF_AUTOMEDIA)
1793                         printf(_("(auto)"));
1794         }
1795 #endif
1796         printf("\n");
1797
1798 #if HAVE_AFINET
1799         if (ptr->has_ip) {
1800                 printf(_("          %s addr:%s "), ap->name,
1801                            ap->sprint(&ptr->addr, 1));
1802                 if (ptr->flags & IFF_POINTOPOINT) {
1803                         printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1804                 }
1805                 if (ptr->flags & IFF_BROADCAST) {
1806                         printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1807                 }
1808                 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1809         }
1810 #endif
1811
1812 #if HAVE_AFINET6
1813
1814 #define IPV6_ADDR_ANY           0x0000U
1815
1816 #define IPV6_ADDR_UNICAST       0x0001U
1817 #define IPV6_ADDR_MULTICAST     0x0002U
1818 #define IPV6_ADDR_ANYCAST       0x0004U
1819
1820 #define IPV6_ADDR_LOOPBACK      0x0010U
1821 #define IPV6_ADDR_LINKLOCAL     0x0020U
1822 #define IPV6_ADDR_SITELOCAL     0x0040U
1823
1824 #define IPV6_ADDR_COMPATv4      0x0080U
1825
1826 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
1827
1828 #define IPV6_ADDR_MAPPED        0x1000U
1829 #define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
1830
1831         if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1832                 while (fscanf
1833                            (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1834                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1835                                 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1836                                 &dad_status, devname) != EOF) {
1837                         if (!strcmp(devname, ptr->name)) {
1838                                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1839                                                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1840                                                 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1841                                 inet_pton(AF_INET6, addr6,
1842                                                   (struct sockaddr *) &sap.sin6_addr);
1843                                 sap.sin6_family = AF_INET6;
1844                                 printf(_("          inet6 addr: %s/%d"),
1845                                            inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1846                                            plen);
1847                                 printf(_(" Scope:"));
1848                                 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1849                                 case 0:
1850                                         printf(_("Global"));
1851                                         break;
1852                                 case IPV6_ADDR_LINKLOCAL:
1853                                         printf(_("Link"));
1854                                         break;
1855                                 case IPV6_ADDR_SITELOCAL:
1856                                         printf(_("Site"));
1857                                         break;
1858                                 case IPV6_ADDR_COMPATv4:
1859                                         printf(_("Compat"));
1860                                         break;
1861                                 case IPV6_ADDR_LOOPBACK:
1862                                         printf(_("Host"));
1863                                         break;
1864                                 default:
1865                                         printf(_("Unknown"));
1866                                 }
1867                                 printf("\n");
1868                         }
1869                 }
1870                 fclose(f);
1871         }
1872 #endif
1873
1874 #if HAVE_AFIPX
1875         if (ipxtype == NULL)
1876                 ipxtype = get_afntype(AF_IPX);
1877
1878         if (ipxtype != NULL) {
1879                 if (ptr->has_ipx_bb)
1880                         printf(_("          IPX/Ethernet II addr:%s\n"),
1881                                    ipxtype->sprint(&ptr->ipxaddr_bb, 1));
1882                 if (ptr->has_ipx_sn)
1883                         printf(_("          IPX/Ethernet SNAP addr:%s\n"),
1884                                    ipxtype->sprint(&ptr->ipxaddr_sn, 1));
1885                 if (ptr->has_ipx_e2)
1886                         printf(_("          IPX/Ethernet 802.2 addr:%s\n"),
1887                                    ipxtype->sprint(&ptr->ipxaddr_e2, 1));
1888                 if (ptr->has_ipx_e3)
1889                         printf(_("          IPX/Ethernet 802.3 addr:%s\n"),
1890                                    ipxtype->sprint(&ptr->ipxaddr_e3, 1));
1891         }
1892 #endif
1893
1894 #if HAVE_AFATALK
1895         if (ddptype == NULL)
1896                 ddptype = get_afntype(AF_APPLETALK);
1897         if (ddptype != NULL) {
1898                 if (ptr->has_ddp)
1899                         printf(_("          EtherTalk Phase 2 addr:%s\n"),
1900                                    ddptype->sprint(&ptr->ddpaddr, 1));
1901         }
1902 #endif
1903
1904 #if HAVE_AFECONET
1905         if (ectype == NULL)
1906                 ectype = get_afntype(AF_ECONET);
1907         if (ectype != NULL) {
1908                 if (ptr->has_econet)
1909                         printf(_("          econet addr:%s\n"),
1910                                    ectype->sprint(&ptr->ecaddr, 1));
1911         }
1912 #endif
1913
1914         printf("          ");
1915         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1916         if (ptr->flags == 0)
1917                 printf(_("[NO FLAGS] "));
1918         if (ptr->flags & IFF_UP)
1919                 printf(_("UP "));
1920         if (ptr->flags & IFF_BROADCAST)
1921                 printf(_("BROADCAST "));
1922         if (ptr->flags & IFF_DEBUG)
1923                 printf(_("DEBUG "));
1924         if (ptr->flags & IFF_LOOPBACK)
1925                 printf(_("LOOPBACK "));
1926         if (ptr->flags & IFF_POINTOPOINT)
1927                 printf(_("POINTOPOINT "));
1928         if (ptr->flags & IFF_NOTRAILERS)
1929                 printf(_("NOTRAILERS "));
1930         if (ptr->flags & IFF_RUNNING)
1931                 printf(_("RUNNING "));
1932         if (ptr->flags & IFF_NOARP)
1933                 printf(_("NOARP "));
1934         if (ptr->flags & IFF_PROMISC)
1935                 printf(_("PROMISC "));
1936         if (ptr->flags & IFF_ALLMULTI)
1937                 printf(_("ALLMULTI "));
1938         if (ptr->flags & IFF_SLAVE)
1939                 printf(_("SLAVE "));
1940         if (ptr->flags & IFF_MASTER)
1941                 printf(_("MASTER "));
1942         if (ptr->flags & IFF_MULTICAST)
1943                 printf(_("MULTICAST "));
1944 #ifdef HAVE_DYNAMIC
1945         if (ptr->flags & IFF_DYNAMIC)
1946                 printf(_("DYNAMIC "));
1947 #endif
1948         /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1949         printf(_(" MTU:%d  Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1950 #ifdef SIOCSKEEPALIVE
1951         if (ptr->outfill || ptr->keepalive)
1952                 printf(_("  Outfill:%d  Keepalive:%d"), ptr->outfill, ptr->keepalive);
1953 #endif
1954         printf("\n");
1955
1956         /* If needed, display the interface statistics. */
1957
1958         if (ptr->statistics_valid) {
1959                 /* XXX: statistics are currently only printed for the primary address,
1960                  *      not for the aliases, although strictly speaking they're shared
1961                  *      by all addresses.
1962                  */
1963                 printf("          ");
1964
1965                 printf(_
1966                            ("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
1967                            ptr->stats.rx_packets, ptr->stats.rx_errors,
1968                            ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1969                            ptr->stats.rx_frame_errors);
1970                 if (can_compress)
1971                         printf(_("             compressed:%lu\n"),
1972                                    ptr->stats.rx_compressed);
1973                 printf("          ");
1974                 printf(_
1975                            ("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
1976                            ptr->stats.tx_packets, ptr->stats.tx_errors,
1977                            ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1978                            ptr->stats.tx_carrier_errors);
1979                 printf(_("          collisions:%lu "), ptr->stats.collisions);
1980                 if (can_compress)
1981                         printf(_("compressed:%lu "), ptr->stats.tx_compressed);
1982                 if (ptr->tx_queue_len != -1)
1983                         printf(_("txqueuelen:%d "), ptr->tx_queue_len);
1984                 printf("\n          R");
1985                 print_bytes_scaled(ptr->stats.rx_bytes, "  T");
1986                 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1987
1988         }
1989
1990         if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1991                  ptr->map.base_addr)) {
1992                 printf("          ");
1993                 if (ptr->map.irq)
1994                         printf(_("Interrupt:%d "), ptr->map.irq);
1995                 if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for 
1996                                                                                            I/O maps */
1997                         printf(_("Base address:0x%lx "),
1998                                    (unsigned long) ptr->map.base_addr);
1999                 if (ptr->map.mem_start) {
2000                         printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
2001                                    ptr->map.mem_end);
2002                 }
2003                 if (ptr->map.dma)
2004                         printf(_("DMA chan:%x "), ptr->map.dma);
2005                 printf("\n");
2006         }
2007         printf("\n");
2008 }
2009
2010
2011 static int do_if_print(struct interface *ife, void *cookie)
2012 {
2013         int *opt_a = (int *) cookie;
2014         int res;
2015
2016         res = do_if_fetch(ife);
2017         if (res >= 0) {
2018                 if ((ife->flags & IFF_UP) || *opt_a)
2019                         ife_print(ife);
2020         }
2021         return res;
2022 }
2023
2024 static struct interface *lookup_interface(char *name)
2025 {
2026         struct interface *ife = NULL;
2027
2028         if (if_readlist_proc(name) < 0)
2029                 return NULL;
2030         ife = add_interface(name);
2031         return ife;
2032 }
2033
2034 /* for ipv4 add/del modes */
2035 static int if_print(char *ifname)
2036 {
2037         int res;
2038
2039         if (!ifname) {
2040                 res = for_all_interfaces(do_if_print, &interface_opt_a);
2041         } else {
2042                 struct interface *ife;
2043
2044                 ife = lookup_interface(ifname);
2045                 res = do_if_fetch(ife);
2046                 if (res >= 0)
2047                         ife_print(ife);
2048         }
2049         return res;
2050 }
2051
2052 int display_interfaces(char *ifname)
2053 {
2054         int status;
2055
2056         /* Create a channel to the NET kernel. */
2057         if ((skfd = sockets_open(0)) < 0) {
2058                 perror_msg_and_die("socket");
2059         }
2060
2061         /* Do we have to show the current setup? */
2062         status = if_print(ifname);
2063         close(skfd);
2064         exit(status < 0);
2065 }