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