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