summaryrefslogtreecommitdiff
path: root/networking/interface.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2005-11-22 07:52:54 +0000
committerRob Landley <rob@landley.net>2005-11-22 07:52:54 +0000
commitb4c823211d7bc2e1b05e891e58a465f26ec05ff8 (patch)
tree44cd167436aa2bb75c8653b1a55a81920f5b010f /networking/interface.c
parentfae1dc86203c0e9f66b726495815b6fdea30b5ed (diff)
downloadbusybox-w32-b4c823211d7bc2e1b05e891e58a465f26ec05ff8.tar.gz
busybox-w32-b4c823211d7bc2e1b05e891e58a465f26ec05ff8.tar.bz2
busybox-w32-b4c823211d7bc2e1b05e891e58a465f26ec05ff8.zip
Move interface.c to networking directory since it's only used by ifconfig.
Diffstat (limited to 'networking/interface.c')
-rw-r--r--networking/interface.c2093
1 files changed, 2093 insertions, 0 deletions
diff --git a/networking/interface.c b/networking/interface.c
new file mode 100644
index 000000000..ce7d67da7
--- /dev/null
+++ b/networking/interface.c
@@ -0,0 +1,2093 @@
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
101struct 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. */
137struct 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
158static int flag_unx;
159
160#ifdef HAVE_AFIPX
161static int flag_ipx;
162#endif
163#ifdef HAVE_AFX25
164static int flag_ax25;
165#endif
166#ifdef HAVE_AFATALK
167static int flag_ddp;
168#endif
169#ifdef HAVE_AFNETROM
170static int flag_netrom;
171#endif
172static int flag_inet;
173
174#ifdef HAVE_AFINET6
175static int flag_inet6;
176#endif
177#ifdef HAVE_AFECONET
178static int flag_econet;
179#endif
180#ifdef HAVE_AFX25
181static int flag_x25 = 0;
182#endif
183#ifdef HAVE_AFASH
184static int flag_ash;
185#endif
186
187
188static 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
245static char afname[256] = "";
246#endif /* KEEP_UNUSED */
247
248#if HAVE_AFUNIX
249
250/* Display a UNIX domain address. */
251static char *UNIX_print(unsigned char *ptr)
252{
253 return (ptr);
254}
255
256
257/* Display a UNIX domain address. */
258static 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
268static 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
280static void INET_reserror(char *text)
281{
282 herror(text);
283}
284
285/* Display an Internet socket address. */
286static 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. */
293static 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
308static 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
321static 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
362static 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
374static 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
397static 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
412static void INET6_reserror(char *text)
413{
414 herror(text);
415}
416
417/* Display an Internet socket address. */
418static 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. */
429static 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
442static 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
456static 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
467static 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. */
480static 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. */
498static 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(sap->sa_data));
505}
506
507static struct aftype unspec_aftype = {
508 "unspec", "UNSPEC", AF_UNSPEC, 0,
509 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
510 NULL,
511};
512
513static 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
552static short sVafinit = 0;
553
554static 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
593static 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 */
636static 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. */
673static 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. */
695static 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 */
714static 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 */
734static 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
764struct 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
793struct 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
828int interface_opt_a = 0; /* show all interfaces */
829
830#ifdef KEEP_UNUSED
831static int opt_i = 0; /* show the statistics */
832static int opt_v = 0; /* debugging output flag */
833
834static int addr_family = 0; /* currently selected AF */
835#endif /* KEEP_UNUSED */
836
837static struct interface *int_list, *int_last;
838static int skfd = -1; /* generic raw socket desc. */
839
840
841static 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
890static 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 */
904static 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
927static 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
953static 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
1001static 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 *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
1049static 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
1055static 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
1063static 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
1097static 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
1106static 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
1149static 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
1158static 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
1177static 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. */
1186static 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
1342static 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. */
1361struct hwtype {
1362 const char *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
1372static const struct hwtype unspec_hwtype = {
1373 "unspec", "UNSPEC", -1, 0,
1374 UNSPEC_print, NULL, NULL
1375};
1376
1377static 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. */
1392static 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. */
1405static 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
1481static 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. */
1496static 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
1503static 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
1511static 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
1586static short sVhwinit = 0;
1587
1588static 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
1661static 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
1673static 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. */
1688static 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 */
1707static 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
1718static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
1719
1720static 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
1755static 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
1774static 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
1794static 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(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
2037static 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
2050static 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 */
2061static 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
2078int 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}