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