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