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