aboutsummaryrefslogtreecommitdiff
path: root/busybox/libbb/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/libbb/interface.c')
-rw-r--r--busybox/libbb/interface.c2083
1 files changed, 2083 insertions, 0 deletions
diff --git a/busybox/libbb/interface.c b/busybox/libbb/interface.c
new file mode 100644
index 000000000..fe2d0b4b2
--- /dev/null
+++ b/busybox/libbb/interface.c
@@ -0,0 +1,2083 @@
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#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. */
139struct 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
160static int flag_unx;
161
162#ifdef HAVE_AFIPX
163static int flag_ipx;
164#endif
165#ifdef HAVE_AFX25
166static int flag_ax25;
167#endif
168#ifdef HAVE_AFATALK
169static int flag_ddp;
170#endif
171#ifdef HAVE_AFNETROM
172static int flag_netrom;
173#endif
174static int flag_inet;
175
176#ifdef HAVE_AFINET6
177static int flag_inet6;
178#endif
179#ifdef HAVE_AFECONET
180static int flag_econet;
181#endif
182#ifdef HAVE_AFX25
183static int flag_x25 = 0;
184#endif
185#ifdef HAVE_AFASH
186static int flag_ash;
187#endif
188
189
190static 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
247static char afname[256] = "";
248#endif /* KEEP_UNUSED */
249
250#if HAVE_AFUNIX
251
252/* Display a UNIX domain address. */
253static char *UNIX_print(unsigned char *ptr)
254{
255 return (ptr);
256}
257
258
259/* Display a UNIX domain address. */
260static 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
270static 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
282static void INET_reserror(char *text)
283{
284 herror(text);
285}
286
287/* Display an Internet socket address. */
288static 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. */
295static 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
310static 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
323static 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
364static 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
376static 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
399static 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
414static void INET6_reserror(char *text)
415{
416 herror(text);
417}
418
419/* Display an Internet socket address. */
420static 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. */
431static 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
444static 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
458static 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
469static 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. */
482static 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. */
500static 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
509static struct aftype unspec_aftype = {
510 "unspec", "UNSPEC", AF_UNSPEC, 0,
511 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
512 NULL,
513};
514
515static 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
554static short sVafinit = 0;
555
556static 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
595static 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 */
638static 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. */
675static 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. */
697static 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 */
716static 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 */
736static 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
766struct 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
795struct 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
830int interface_opt_a = 0; /* show all interfaces */
831
832#ifdef KEEP_UNUSED
833static int opt_i = 0; /* show the statistics */
834static int opt_v = 0; /* debugging output flag */
835
836static int addr_family = 0; /* currently selected AF */
837#endif /* KEEP_UNUSED */
838
839static struct interface *int_list, *int_last;
840static int skfd = -1; /* generic raw socket desc. */
841
842
843static 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/* like strcmp(), but knows about numbers */
892static int nstrcmp(const char *a, const char *b)
893{
894 const char *a_ptr = a;
895 const char *b_ptr = b;
896
897 while (*a == *b) {
898 if (*a == '\0') {
899 return 0;
900 }
901 if (!isdigit(*a) && isdigit(*(a+1))) {
902 a_ptr = a+1;
903 b_ptr = b+1;
904 }
905 a++;
906 b++;
907 }
908
909 if (isdigit(*a) && isdigit(*b)) {
910 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
911 }
912 return *a - *b;
913}
914
915static struct interface *add_interface(char *name)
916{
917 struct interface *ife, **nextp, *new;
918
919 for (ife = int_last; ife; ife = ife->prev) {
920 int n = nstrcmp(ife->name, name);
921
922 if (n == 0)
923 return ife;
924 if (n < 0)
925 break;
926 }
927 new(new);
928 safe_strncpy(new->name, name, IFNAMSIZ);
929 nextp = ife ? &ife->next : &int_list;
930 new->prev = ife;
931 new->next = *nextp;
932 if (new->next)
933 new->next->prev = new;
934 else
935 int_last = new;
936 *nextp = new;
937 return new;
938}
939
940
941static int if_readconf(void)
942{
943 int numreqs = 30;
944 struct ifconf ifc;
945 struct ifreq *ifr;
946 int n, err = -1;
947 int skfd2;
948
949 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
950 (as of 2.1.128) */
951 skfd2 = get_socket_for_af(AF_INET);
952 if (skfd2 < 0) {
953 bb_perror_msg(("warning: no inet socket available"));
954 /* Try to soldier on with whatever socket we can get hold of. */
955 skfd2 = sockets_open(0);
956 if (skfd2 < 0)
957 return -1;
958 }
959
960 ifc.ifc_buf = NULL;
961 for (;;) {
962 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
963 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
964
965 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
966 perror("SIOCGIFCONF");
967 goto out;
968 }
969 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
970 /* assume it overflowed and try again */
971 numreqs += 10;
972 continue;
973 }
974 break;
975 }
976
977 ifr = ifc.ifc_req;
978 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
979 add_interface(ifr->ifr_name);
980 ifr++;
981 }
982 err = 0;
983
984 out:
985 free(ifc.ifc_buf);
986 return err;
987}
988
989char *get_name(char *name, char *p)
990{
991 /* Extract <name>[:<alias>] from nul-terminated p where p matches
992 <name>[:<alias>]: after leading whitespace.
993 If match is not made, set name empty and return unchanged p */
994 int namestart=0, nameend=0, aliasend;
995 while (isspace(p[namestart]))
996 namestart++;
997 nameend=namestart;
998 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
999 nameend++;
1000 if (p[nameend]==':') {
1001 aliasend=nameend+1;
1002 while (p[aliasend] && isdigit(p[aliasend]))
1003 aliasend++;
1004 if (p[aliasend]==':') {
1005 nameend=aliasend;
1006 }
1007 if ((nameend-namestart)<IFNAMSIZ) {
1008 memcpy(name,&p[namestart],nameend-namestart);
1009 name[nameend-namestart]='\0';
1010 p=&p[nameend];
1011 } else {
1012 /* Interface name too large */
1013 name[0]='\0';
1014 }
1015 } else {
1016 /* first ':' not found - return empty */
1017 name[0]='\0';
1018 }
1019 return p + 1;
1020}
1021
1022/* If scanf supports size qualifiers for %n conversions, then we can
1023 * use a modified fmt that simply stores the position in the fields
1024 * having no associated fields in the proc string. Of course, we need
1025 * to zero them again when we're done. But that is smaller than the
1026 * old approach of multiple scanf occurrences with large numbers of
1027 * args. */
1028
1029/* static const char *ss_fmt[] = { */
1030/* "%Ln%Lu%lu%lu%lu%lu%ln%ln%Ln%Lu%lu%lu%lu%lu%lu", */
1031/* "%Lu%Lu%lu%lu%lu%lu%ln%ln%Lu%Lu%lu%lu%lu%lu%lu", */
1032/* "%Lu%Lu%lu%lu%lu%lu%lu%lu%Lu%Lu%lu%lu%lu%lu%lu%lu" */
1033/* }; */
1034
1035 /* Lie about the size of the int pointed to for %n. */
1036#if INT_MAX == LONG_MAX
1037static const char *ss_fmt[] = {
1038 "%n%Lu%u%u%u%u%n%n%n%Lu%u%u%u%u%u",
1039 "%Lu%Lu%u%u%u%u%n%n%Lu%Lu%u%u%u%u%u",
1040 "%Lu%Lu%u%u%u%u%u%u%Lu%Lu%u%u%u%u%u%u"
1041};
1042#else
1043static const char *ss_fmt[] = {
1044 "%n%Lu%lu%lu%lu%lu%n%n%n%Lu%lu%lu%lu%lu%lu",
1045 "%Lu%Lu%lu%lu%lu%lu%n%n%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#endif
1050
1051static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
1052{
1053 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
1054
1055 sscanf(bp, ss_fmt[procnetdev_vsn],
1056 &ife->stats.rx_bytes, /* missing for 0 */
1057 &ife->stats.rx_packets,
1058 &ife->stats.rx_errors,
1059 &ife->stats.rx_dropped,
1060 &ife->stats.rx_fifo_errors,
1061 &ife->stats.rx_frame_errors,
1062 &ife->stats.rx_compressed, /* missing for <= 1 */
1063 &ife->stats.rx_multicast, /* missing for <= 1 */
1064 &ife->stats.tx_bytes, /* missing for 0 */
1065 &ife->stats.tx_packets,
1066 &ife->stats.tx_errors,
1067 &ife->stats.tx_dropped,
1068 &ife->stats.tx_fifo_errors,
1069 &ife->stats.collisions,
1070 &ife->stats.tx_carrier_errors,
1071 &ife->stats.tx_compressed /* missing for <= 1 */
1072 );
1073
1074 if (procnetdev_vsn <= 1) {
1075 if (procnetdev_vsn == 0) {
1076 ife->stats.rx_bytes = 0;
1077 ife->stats.tx_bytes = 0;
1078 }
1079 ife->stats.rx_multicast = 0;
1080 ife->stats.rx_compressed = 0;
1081 ife->stats.tx_compressed = 0;
1082 }
1083}
1084
1085static inline int procnetdev_version(char *buf)
1086{
1087 if (strstr(buf, "compressed"))
1088 return 2;
1089 if (strstr(buf, "bytes"))
1090 return 1;
1091 return 0;
1092}
1093
1094static int if_readlist_proc(char *target)
1095{
1096 static int proc_read;
1097 FILE *fh;
1098 char buf[512];
1099 struct interface *ife;
1100 int err, procnetdev_vsn;
1101
1102 if (proc_read)
1103 return 0;
1104 if (!target)
1105 proc_read = 1;
1106
1107 fh = fopen(_PATH_PROCNET_DEV, "r");
1108 if (!fh) {
1109 bb_perror_msg(_("Warning: cannot open %s. Limited output."), _PATH_PROCNET_DEV);
1110 return if_readconf();
1111 }
1112 fgets(buf, sizeof buf, fh); /* eat line */
1113 fgets(buf, sizeof buf, fh);
1114
1115 procnetdev_vsn = procnetdev_version(buf);
1116
1117 err = 0;
1118 while (fgets(buf, sizeof buf, fh)) {
1119 char *s, name[128];
1120
1121 s = get_name(name, buf);
1122 ife = add_interface(name);
1123 get_dev_fields(s, ife, procnetdev_vsn);
1124 ife->statistics_valid = 1;
1125 if (target && !strcmp(target, name))
1126 break;
1127 }
1128 if (ferror(fh)) {
1129 perror(_PATH_PROCNET_DEV);
1130 err = -1;
1131 proc_read = 0;
1132 }
1133 fclose(fh);
1134 return err;
1135}
1136
1137static int if_readlist(void)
1138{
1139 int err = if_readlist_proc(NULL);
1140
1141 if (!err)
1142 err = if_readconf();
1143 return err;
1144}
1145
1146static int for_all_interfaces(int (*doit) (struct interface *, void *),
1147 void *cookie)
1148{
1149 struct interface *ife;
1150
1151 if (!int_list && (if_readlist() < 0))
1152 return -1;
1153 for (ife = int_list; ife; ife = ife->next) {
1154 int err = doit(ife, cookie);
1155
1156 if (err)
1157 return err;
1158 }
1159 return 0;
1160}
1161
1162/* Support for fetching an IPX address */
1163
1164#if HAVE_AFIPX
1165static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
1166{
1167 ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
1168 return ioctl(sock, SIOCGIFADDR, ifr);
1169}
1170#endif
1171
1172
1173/* Fetch the interface configuration from the kernel. */
1174static int if_fetch(struct interface *ife)
1175{
1176 struct ifreq ifr;
1177 int fd;
1178 char *ifname = ife->name;
1179
1180 strcpy(ifr.ifr_name, ifname);
1181 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
1182 return (-1);
1183 ife->flags = ifr.ifr_flags;
1184
1185 strcpy(ifr.ifr_name, ifname);
1186 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
1187 memset(ife->hwaddr, 0, 32);
1188 else
1189 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
1190
1191 ife->type = ifr.ifr_hwaddr.sa_family;
1192
1193 strcpy(ifr.ifr_name, ifname);
1194 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
1195 ife->metric = 0;
1196 else
1197 ife->metric = ifr.ifr_metric;
1198
1199 strcpy(ifr.ifr_name, ifname);
1200 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
1201 ife->mtu = 0;
1202 else
1203 ife->mtu = ifr.ifr_mtu;
1204
1205#ifdef HAVE_HWSLIP
1206 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
1207 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
1208 ife->type == ARPHRD_ADAPT) {
1209#ifdef SIOCGOUTFILL
1210 strcpy(ifr.ifr_name, ifname);
1211 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
1212 ife->outfill = 0;
1213 else
1214 ife->outfill = (unsigned int) ifr.ifr_data;
1215#endif
1216#ifdef SIOCGKEEPALIVE
1217 strcpy(ifr.ifr_name, ifname);
1218 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
1219 ife->keepalive = 0;
1220 else
1221 ife->keepalive = (unsigned int) ifr.ifr_data;
1222#endif
1223 }
1224#endif
1225
1226 strcpy(ifr.ifr_name, ifname);
1227 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1228 memset(&ife->map, 0, sizeof(struct ifmap));
1229 else
1230 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
1231
1232 strcpy(ifr.ifr_name, ifname);
1233 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
1234 memset(&ife->map, 0, sizeof(struct ifmap));
1235 else
1236 ife->map = ifr.ifr_map;
1237
1238#ifdef HAVE_TXQUEUELEN
1239 strcpy(ifr.ifr_name, ifname);
1240 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
1241 ife->tx_queue_len = -1; /* unknown value */
1242 else
1243 ife->tx_queue_len = ifr.ifr_qlen;
1244#else
1245 ife->tx_queue_len = -1; /* unknown value */
1246#endif
1247
1248#if HAVE_AFINET
1249 /* IPv4 address? */
1250 fd = get_socket_for_af(AF_INET);
1251 if (fd >= 0) {
1252 strcpy(ifr.ifr_name, ifname);
1253 ifr.ifr_addr.sa_family = AF_INET;
1254 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1255 ife->has_ip = 1;
1256 ife->addr = ifr.ifr_addr;
1257 strcpy(ifr.ifr_name, ifname);
1258 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
1259 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
1260 else
1261 ife->dstaddr = ifr.ifr_dstaddr;
1262
1263 strcpy(ifr.ifr_name, ifname);
1264 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
1265 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
1266 else
1267 ife->broadaddr = ifr.ifr_broadaddr;
1268
1269 strcpy(ifr.ifr_name, ifname);
1270 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
1271 memset(&ife->netmask, 0, sizeof(struct sockaddr));
1272 else
1273 ife->netmask = ifr.ifr_netmask;
1274 } else
1275 memset(&ife->addr, 0, sizeof(struct sockaddr));
1276 }
1277#endif
1278
1279#if HAVE_AFATALK
1280 /* DDP address maybe ? */
1281 fd = get_socket_for_af(AF_APPLETALK);
1282 if (fd >= 0) {
1283 strcpy(ifr.ifr_name, ifname);
1284 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1285 ife->ddpaddr = ifr.ifr_addr;
1286 ife->has_ddp = 1;
1287 }
1288 }
1289#endif
1290
1291#if HAVE_AFIPX
1292 /* Look for IPX addresses with all framing types */
1293 fd = get_socket_for_af(AF_IPX);
1294 if (fd >= 0) {
1295 strcpy(ifr.ifr_name, ifname);
1296 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
1297 ife->has_ipx_bb = 1;
1298 ife->ipxaddr_bb = ifr.ifr_addr;
1299 }
1300 strcpy(ifr.ifr_name, ifname);
1301 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
1302 ife->has_ipx_sn = 1;
1303 ife->ipxaddr_sn = ifr.ifr_addr;
1304 }
1305 strcpy(ifr.ifr_name, ifname);
1306 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
1307 ife->has_ipx_e3 = 1;
1308 ife->ipxaddr_e3 = ifr.ifr_addr;
1309 }
1310 strcpy(ifr.ifr_name, ifname);
1311 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
1312 ife->has_ipx_e2 = 1;
1313 ife->ipxaddr_e2 = ifr.ifr_addr;
1314 }
1315 }
1316#endif
1317
1318#if HAVE_AFECONET
1319 /* Econet address maybe? */
1320 fd = get_socket_for_af(AF_ECONET);
1321 if (fd >= 0) {
1322 strcpy(ifr.ifr_name, ifname);
1323 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
1324 ife->ecaddr = ifr.ifr_addr;
1325 ife->has_econet = 1;
1326 }
1327 }
1328#endif
1329
1330 return 0;
1331}
1332
1333
1334static int do_if_fetch(struct interface *ife)
1335{
1336 if (if_fetch(ife) < 0) {
1337 char *errmsg;
1338
1339 if (errno == ENODEV) {
1340 /* Give better error message for this case. */
1341 errmsg = _("Device not found");
1342 } else {
1343 errmsg = strerror(errno);
1344 }
1345 bb_error_msg(_("%s: error fetching interface information: %s\n"),
1346 ife->name, errmsg);
1347 return -1;
1348 }
1349 return 0;
1350}
1351
1352/* This structure defines hardware protocols and their handlers. */
1353struct hwtype {
1354 const char *name;
1355 const char *title;
1356 int type;
1357 int alen;
1358 char *(*print) (unsigned char *);
1359 int (*input) (char *, struct sockaddr *);
1360 int (*activate) (int fd);
1361 int suppress_null_addr;
1362};
1363
1364static struct hwtype unspec_hwtype = {
1365 "unspec", "UNSPEC", -1, 0,
1366 UNSPEC_print, NULL, NULL
1367};
1368
1369static struct hwtype loop_hwtype = {
1370 "loop", "Local Loopback", ARPHRD_LOOPBACK, 0,
1371 NULL, NULL, NULL
1372};
1373
1374#if HAVE_HWETHER
1375#include <net/if_arp.h>
1376
1377#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
1378#include <net/ethernet.h>
1379#else
1380#include <linux/if_ether.h>
1381#endif
1382
1383/* Display an Ethernet address in readable format. */
1384static char *pr_ether(unsigned char *ptr)
1385{
1386 static char buff[64];
1387
1388 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
1389 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
1390 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
1391 );
1392 return (buff);
1393}
1394
1395#ifdef KEEP_UNUSED
1396/* Input an Ethernet address and convert to binary. */
1397static int in_ether(char *bufp, struct sockaddr *sap)
1398{
1399 unsigned char *ptr;
1400 char c, *orig;
1401 int i;
1402 unsigned val;
1403
1404 sap->sa_family = ether_hwtype.type;
1405 ptr = sap->sa_data;
1406
1407 i = 0;
1408 orig = bufp;
1409 while ((*bufp != '\0') && (i < ETH_ALEN)) {
1410 val = 0;
1411 c = *bufp++;
1412 if (isdigit(c))
1413 val = c - '0';
1414 else if (c >= 'a' && c <= 'f')
1415 val = c - 'a' + 10;
1416 else if (c >= 'A' && c <= 'F')
1417 val = c - 'A' + 10;
1418 else {
1419#ifdef DEBUG
1420 bb_error_msg(_("in_ether(%s): invalid ether address!\n"), orig);
1421#endif
1422 errno = EINVAL;
1423 return (-1);
1424 }
1425 val <<= 4;
1426 c = *bufp;
1427 if (isdigit(c))
1428 val |= c - '0';
1429 else if (c >= 'a' && c <= 'f')
1430 val |= c - 'a' + 10;
1431 else if (c >= 'A' && c <= 'F')
1432 val |= c - 'A' + 10;
1433 else if (c == ':' || c == 0)
1434 val >>= 4;
1435 else {
1436#ifdef DEBUG
1437 bb_error_msg(_("in_ether(%s): invalid ether address!"), orig);
1438#endif
1439 errno = EINVAL;
1440 return (-1);
1441 }
1442 if (c != 0)
1443 bufp++;
1444 *ptr++ = (unsigned char) (val & 0377);
1445 i++;
1446
1447 /* We might get a semicolon here - not required. */
1448 if (*bufp == ':') {
1449#ifdef DEBUG
1450 if (i == ETH_ALEN) {
1451 bb_error_msg(_("in_ether(%s): trailing : ignored!"), orig);
1452 }
1453#endif
1454 bufp++;
1455 }
1456 }
1457
1458#ifdef DEBUG
1459 /* That's it. Any trailing junk? */
1460 if ((i == ETH_ALEN) && (*bufp != '\0')) {
1461 bb_error_msg(_("in_ether(%s): trailing junk!"), orig);
1462 errno = EINVAL;
1463 return (-1);
1464 }
1465 bb_error_msg("in_ether(%s): %s", orig, pr_ether(sap->sa_data));
1466#endif
1467
1468 return (0);
1469}
1470#endif /* KEEP_UNUSED */
1471
1472
1473static struct hwtype ether_hwtype = {
1474 "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN,
1475 pr_ether, NULL /* UNUSED in_ether */ , NULL
1476};
1477
1478
1479#endif /* HAVE_HWETHER */
1480
1481
1482#if HAVE_HWPPP
1483
1484#include <net/if_arp.h>
1485
1486#ifdef KEEP_UNUSED
1487/* Start the PPP encapsulation on the file descriptor. */
1488static int do_ppp(int fd)
1489{
1490 bb_error_msg(_("You cannot start PPP with this program."));
1491 return -1;
1492}
1493#endif /* KEEP_UNUSED */
1494
1495static struct hwtype ppp_hwtype = {
1496 "ppp", "Point-Point Protocol", ARPHRD_PPP, 0,
1497 NULL, NULL, NULL /* UNUSED do_ppp */ , 0
1498};
1499
1500
1501#endif /* HAVE_PPP */
1502
1503static struct hwtype *hwtypes[] = {
1504
1505 &loop_hwtype,
1506
1507#if HAVE_HWSLIP
1508 &slip_hwtype,
1509 &cslip_hwtype,
1510 &slip6_hwtype,
1511 &cslip6_hwtype,
1512 &adaptive_hwtype,
1513#endif
1514#if HAVE_HWSTRIP
1515 &strip_hwtype,
1516#endif
1517#if HAVE_HWASH
1518 &ash_hwtype,
1519#endif
1520#if HAVE_HWETHER
1521 &ether_hwtype,
1522#endif
1523#if HAVE_HWTR
1524 &tr_hwtype,
1525#ifdef ARPHRD_IEEE802_TR
1526 &tr_hwtype1,
1527#endif
1528#endif
1529#if HAVE_HWAX25
1530 &ax25_hwtype,
1531#endif
1532#if HAVE_HWNETROM
1533 &netrom_hwtype,
1534#endif
1535#if HAVE_HWROSE
1536 &rose_hwtype,
1537#endif
1538#if HAVE_HWTUNNEL
1539 &tunnel_hwtype,
1540#endif
1541#if HAVE_HWPPP
1542 &ppp_hwtype,
1543#endif
1544#if HAVE_HWHDLCLAPB
1545 &hdlc_hwtype,
1546 &lapb_hwtype,
1547#endif
1548#if HAVE_HWARC
1549 &arcnet_hwtype,
1550#endif
1551#if HAVE_HWFR
1552 &dlci_hwtype,
1553 &frad_hwtype,
1554#endif
1555#if HAVE_HWSIT
1556 &sit_hwtype,
1557#endif
1558#if HAVE_HWFDDI
1559 &fddi_hwtype,
1560#endif
1561#if HAVE_HWHIPPI
1562 &hippi_hwtype,
1563#endif
1564#if HAVE_HWIRDA
1565 &irda_hwtype,
1566#endif
1567#if HAVE_HWEC
1568 &ec_hwtype,
1569#endif
1570#if HAVE_HWX25
1571 &x25_hwtype,
1572#endif
1573 &unspec_hwtype,
1574 NULL
1575};
1576
1577#ifdef KEEP_UNUSED
1578static short sVhwinit = 0;
1579
1580static void hwinit()
1581{
1582 loop_hwtype.title = _("Local Loopback");
1583 unspec_hwtype.title = _("UNSPEC");
1584#if HAVE_HWSLIP
1585 slip_hwtype.title = _("Serial Line IP");
1586 cslip_hwtype.title = _("VJ Serial Line IP");
1587 slip6_hwtype.title = _("6-bit Serial Line IP");
1588 cslip6_hwtype.title = _("VJ 6-bit Serial Line IP");
1589 adaptive_hwtype.title = _("Adaptive Serial Line IP");
1590#endif
1591#if HAVE_HWETHER
1592 ether_hwtype.title = _("Ethernet");
1593#endif
1594#if HAVE_HWASH
1595 ash_hwtype.title = _("Ash");
1596#endif
1597#if HAVE_HWFDDI
1598 fddi_hwtype.title = _("Fiber Distributed Data Interface");
1599#endif
1600#if HAVE_HWHIPPI
1601 hippi_hwtype.title = _("HIPPI");
1602#endif
1603#if HAVE_HWAX25
1604 ax25_hwtype.title = _("AMPR AX.25");
1605#endif
1606#if HAVE_HWROSE
1607 rose_hwtype.title = _("AMPR ROSE");
1608#endif
1609#if HAVE_HWNETROM
1610 netrom_hwtype.title = _("AMPR NET/ROM");
1611#endif
1612#if HAVE_HWX25
1613 x25_hwtype.title = _("generic X.25");
1614#endif
1615#if HAVE_HWTUNNEL
1616 tunnel_hwtype.title = _("IPIP Tunnel");
1617#endif
1618#if HAVE_HWPPP
1619 ppp_hwtype.title = _("Point-to-Point Protocol");
1620#endif
1621#if HAVE_HWHDLCLAPB
1622 hdlc_hwtype.title = _("(Cisco)-HDLC");
1623 lapb_hwtype.title = _("LAPB");
1624#endif
1625#if HAVE_HWARC
1626 arcnet_hwtype.title = _("ARCnet");
1627#endif
1628#if HAVE_HWFR
1629 dlci_hwtype.title = _("Frame Relay DLCI");
1630 frad_hwtype.title = _("Frame Relay Access Device");
1631#endif
1632#if HAVE_HWSIT
1633 sit_hwtype.title = _("IPv6-in-IPv4");
1634#endif
1635#if HAVE_HWIRDA
1636 irda_hwtype.title = _("IrLAP");
1637#endif
1638#if HAVE_HWTR
1639 tr_hwtype.title = _("16/4 Mbps Token Ring");
1640#ifdef ARPHRD_IEEE802_TR
1641 tr_hwtype1.title = _("16/4 Mbps Token Ring (New)");
1642#endif
1643#endif
1644#if HAVE_HWEC
1645 ec_hwtype.title = _("Econet");
1646#endif
1647 sVhwinit = 1;
1648}
1649#endif /* KEEP_UNUSED */
1650
1651#ifdef IFF_PORTSEL
1652#if 0
1653static const char * const if_port_text[][4] = {
1654 /* Keep in step with <linux/netdevice.h> */
1655 {"unknown", NULL, NULL, NULL},
1656 {"10base2", "bnc", "coax", NULL},
1657 {"10baseT", "utp", "tpe", NULL},
1658 {"AUI", "thick", "db15", NULL},
1659 {"100baseT", NULL, NULL, NULL},
1660 {"100baseTX", NULL, NULL, NULL},
1661 {"100baseFX", NULL, NULL, NULL},
1662 {NULL, NULL, NULL, NULL},
1663};
1664#else
1665static const char * const if_port_text[] = {
1666 /* Keep in step with <linux/netdevice.h> */
1667 "unknown",
1668 "10base2",
1669 "10baseT",
1670 "AUI",
1671 "100baseT",
1672 "100baseTX",
1673 "100baseFX",
1674 NULL
1675};
1676#endif
1677#endif
1678
1679/* Check our hardware type table for this type. */
1680static struct hwtype *get_hwntype(int type)
1681{
1682 struct hwtype **hwp;
1683
1684#ifdef KEEP_UNUSED
1685 if (!sVhwinit)
1686 hwinit();
1687#endif /* KEEP_UNUSED */
1688
1689 hwp = hwtypes;
1690 while (*hwp != NULL) {
1691 if ((*hwp)->type == type)
1692 return (*hwp);
1693 hwp++;
1694 }
1695 return (NULL);
1696}
1697
1698/* return 1 if address is all zeros */
1699static int hw_null_address(struct hwtype *hw, void *ap)
1700{
1701 unsigned int i;
1702 unsigned char *address = (unsigned char *) ap;
1703
1704 for (i = 0; i < hw->alen; i++)
1705 if (address[i])
1706 return 0;
1707 return 1;
1708}
1709
1710static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
1711
1712static void print_bytes_scaled(unsigned long long ull, const char *end)
1713{
1714 unsigned long long int_part;
1715 const char *ext;
1716 unsigned int frac_part;
1717 int i;
1718
1719 frac_part = 0;
1720 ext = TRext;
1721 int_part = ull;
1722 i = 4;
1723 do {
1724#if 0
1725 /* This does correct rounding and is a little larger. But it
1726 * uses KiB as the smallest displayed unit. */
1727 if ((int_part < (1024*1024 - 51)) || !--i) {
1728 i = 0;
1729 int_part += 51; /* 1024*.05 = 51.2 */
1730 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1731 }
1732 int_part /= 1024;
1733 ext += 3; /* KiB, MiB, GiB, TiB */
1734#else
1735 if (int_part >= 1024) {
1736 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
1737 int_part /= 1024;
1738 ext += 3; /* KiB, MiB, GiB, TiB */
1739 }
1740 --i;
1741#endif
1742 } while (i);
1743
1744 printf("X bytes:%Lu (%Lu.%u %sB)%s", ull, int_part, frac_part, ext, end);
1745}
1746
1747static const char * const ife_print_flags_strs[] = {
1748 "UP ",
1749 "BROADCAST ",
1750 "DEBUG ",
1751 "LOOPBACK ",
1752 "POINTOPOINT ",
1753 "NOTRAILERS ",
1754 "RUNNING ",
1755 "NOARP ",
1756 "PROMISC ",
1757 "ALLMULTI ",
1758 "SLAVE ",
1759 "MASTER ",
1760 "MULTICAST ",
1761#ifdef HAVE_DYNAMIC
1762 "DYNAMIC "
1763#endif
1764};
1765
1766static const unsigned short ife_print_flags_mask[] = {
1767 IFF_UP,
1768 IFF_BROADCAST,
1769 IFF_DEBUG,
1770 IFF_LOOPBACK,
1771 IFF_POINTOPOINT,
1772 IFF_NOTRAILERS,
1773 IFF_RUNNING,
1774 IFF_NOARP,
1775 IFF_PROMISC,
1776 IFF_ALLMULTI,
1777 IFF_SLAVE,
1778 IFF_MASTER,
1779 IFF_MULTICAST,
1780#ifdef HAVE_DYNAMIC
1781 IFF_DYNAMIC
1782#endif
1783 0
1784};
1785
1786static void ife_print(struct interface *ptr)
1787{
1788 struct aftype *ap;
1789 struct hwtype *hw;
1790 int hf;
1791 int can_compress = 0;
1792
1793#if HAVE_AFIPX
1794 static struct aftype *ipxtype = NULL;
1795#endif
1796#if HAVE_AFECONET
1797 static struct aftype *ectype = NULL;
1798#endif
1799#if HAVE_AFATALK
1800 static struct aftype *ddptype = NULL;
1801#endif
1802#if HAVE_AFINET6
1803 FILE *f;
1804 char addr6[40], devname[20];
1805 struct sockaddr_in6 sap;
1806 int plen, scope, dad_status, if_idx;
1807 char addr6p[8][5];
1808#endif
1809
1810 ap = get_afntype(ptr->addr.sa_family);
1811 if (ap == NULL)
1812 ap = get_afntype(0);
1813
1814 hf = ptr->type;
1815
1816 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
1817 can_compress = 1;
1818
1819 hw = get_hwntype(hf);
1820 if (hw == NULL)
1821 hw = get_hwntype(-1);
1822
1823 printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title));
1824 /* For some hardware types (eg Ash, ATM) we don't print the
1825 hardware address if it's null. */
1826 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
1827 hw->suppress_null_addr)))
1828 printf(_("HWaddr %s "), hw->print(ptr->hwaddr));
1829#ifdef IFF_PORTSEL
1830 if (ptr->flags & IFF_PORTSEL) {
1831 printf(_("Media:%s"), if_port_text[ptr->map.port] /* [0] */);
1832 if (ptr->flags & IFF_AUTOMEDIA)
1833 printf(_("(auto)"));
1834 }
1835#endif
1836 printf("\n");
1837
1838#if HAVE_AFINET
1839 if (ptr->has_ip) {
1840 printf(_(" %s addr:%s "), ap->name,
1841 ap->sprint(&ptr->addr, 1));
1842 if (ptr->flags & IFF_POINTOPOINT) {
1843 printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
1844 }
1845 if (ptr->flags & IFF_BROADCAST) {
1846 printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
1847 }
1848 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
1849 }
1850#endif
1851
1852#if HAVE_AFINET6
1853
1854#define IPV6_ADDR_ANY 0x0000U
1855
1856#define IPV6_ADDR_UNICAST 0x0001U
1857#define IPV6_ADDR_MULTICAST 0x0002U
1858#define IPV6_ADDR_ANYCAST 0x0004U
1859
1860#define IPV6_ADDR_LOOPBACK 0x0010U
1861#define IPV6_ADDR_LINKLOCAL 0x0020U
1862#define IPV6_ADDR_SITELOCAL 0x0040U
1863
1864#define IPV6_ADDR_COMPATv4 0x0080U
1865
1866#define IPV6_ADDR_SCOPE_MASK 0x00f0U
1867
1868#define IPV6_ADDR_MAPPED 0x1000U
1869#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1870
1871 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1872 while (fscanf
1873 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1874 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
1875 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
1876 &dad_status, devname) != EOF) {
1877 if (!strcmp(devname, ptr->name)) {
1878 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1879 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1880 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1881 inet_pton(AF_INET6, addr6,
1882 (struct sockaddr *) &sap.sin6_addr);
1883 sap.sin6_family = AF_INET6;
1884 printf(_(" inet6 addr: %s/%d"),
1885 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
1886 plen);
1887 printf(_(" Scope:"));
1888 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1889 case 0:
1890 printf(_("Global"));
1891 break;
1892 case IPV6_ADDR_LINKLOCAL:
1893 printf(_("Link"));
1894 break;
1895 case IPV6_ADDR_SITELOCAL:
1896 printf(_("Site"));
1897 break;
1898 case IPV6_ADDR_COMPATv4:
1899 printf(_("Compat"));
1900 break;
1901 case IPV6_ADDR_LOOPBACK:
1902 printf(_("Host"));
1903 break;
1904 default:
1905 printf(_("Unknown"));
1906 }
1907 printf("\n");
1908 }
1909 }
1910 fclose(f);
1911 }
1912#endif
1913
1914#if HAVE_AFIPX
1915 if (ipxtype == NULL)
1916 ipxtype = get_afntype(AF_IPX);
1917
1918 if (ipxtype != NULL) {
1919 if (ptr->has_ipx_bb)
1920 printf(_(" IPX/Ethernet II addr:%s\n"),
1921 ipxtype->sprint(&ptr->ipxaddr_bb, 1));
1922 if (ptr->has_ipx_sn)
1923 printf(_(" IPX/Ethernet SNAP addr:%s\n"),
1924 ipxtype->sprint(&ptr->ipxaddr_sn, 1));
1925 if (ptr->has_ipx_e2)
1926 printf(_(" IPX/Ethernet 802.2 addr:%s\n"),
1927 ipxtype->sprint(&ptr->ipxaddr_e2, 1));
1928 if (ptr->has_ipx_e3)
1929 printf(_(" IPX/Ethernet 802.3 addr:%s\n"),
1930 ipxtype->sprint(&ptr->ipxaddr_e3, 1));
1931 }
1932#endif
1933
1934#if HAVE_AFATALK
1935 if (ddptype == NULL)
1936 ddptype = get_afntype(AF_APPLETALK);
1937 if (ddptype != NULL) {
1938 if (ptr->has_ddp)
1939 printf(_(" EtherTalk Phase 2 addr:%s\n"),
1940 ddptype->sprint(&ptr->ddpaddr, 1));
1941 }
1942#endif
1943
1944#if HAVE_AFECONET
1945 if (ectype == NULL)
1946 ectype = get_afntype(AF_ECONET);
1947 if (ectype != NULL) {
1948 if (ptr->has_econet)
1949 printf(_(" econet addr:%s\n"),
1950 ectype->sprint(&ptr->ecaddr, 1));
1951 }
1952#endif
1953
1954 printf(" ");
1955 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1956
1957 if (ptr->flags == 0) {
1958 printf(_("[NO FLAGS] "));
1959 } else {
1960 int i = 0;
1961 do {
1962 if (ptr->flags & ife_print_flags_mask[i]) {
1963 printf(_(ife_print_flags_strs[i]));
1964 }
1965 } while (ife_print_flags_mask[++i]);
1966 }
1967
1968 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1969 printf(_(" MTU:%d Metric:%d"), ptr->mtu, ptr->metric ? ptr->metric : 1);
1970#ifdef SIOCSKEEPALIVE
1971 if (ptr->outfill || ptr->keepalive)
1972 printf(_(" Outfill:%d Keepalive:%d"), ptr->outfill, ptr->keepalive);
1973#endif
1974 printf("\n");
1975
1976 /* If needed, display the interface statistics. */
1977
1978 if (ptr->statistics_valid) {
1979 /* XXX: statistics are currently only printed for the primary address,
1980 * not for the aliases, although strictly speaking they're shared
1981 * by all addresses.
1982 */
1983 printf(" ");
1984
1985 printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
1986 ptr->stats.rx_packets, ptr->stats.rx_errors,
1987 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1988 ptr->stats.rx_frame_errors);
1989 if (can_compress)
1990 printf(_(" compressed:%lu\n"),
1991 ptr->stats.rx_compressed);
1992 printf(" ");
1993 printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
1994 ptr->stats.tx_packets, ptr->stats.tx_errors,
1995 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1996 ptr->stats.tx_carrier_errors);
1997 printf(_(" collisions:%lu "), ptr->stats.collisions);
1998 if (can_compress)
1999 printf(_("compressed:%lu "), ptr->stats.tx_compressed);
2000 if (ptr->tx_queue_len != -1)
2001 printf(_("txqueuelen:%d "), ptr->tx_queue_len);
2002 printf("\n R");
2003 print_bytes_scaled(ptr->stats.rx_bytes, " T");
2004 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
2005
2006 }
2007
2008 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
2009 ptr->map.base_addr)) {
2010 printf(" ");
2011 if (ptr->map.irq)
2012 printf(_("Interrupt:%d "), ptr->map.irq);
2013 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
2014 I/O maps */
2015 printf(_("Base address:0x%lx "),
2016 (unsigned long) ptr->map.base_addr);
2017 if (ptr->map.mem_start) {
2018 printf(_("Memory:%lx-%lx "), ptr->map.mem_start,
2019 ptr->map.mem_end);
2020 }
2021 if (ptr->map.dma)
2022 printf(_("DMA chan:%x "), ptr->map.dma);
2023 printf("\n");
2024 }
2025 printf("\n");
2026}
2027
2028
2029static int do_if_print(struct interface *ife, void *cookie)
2030{
2031 int *opt_a = (int *) cookie;
2032 int res;
2033
2034 res = do_if_fetch(ife);
2035 if (res >= 0) {
2036 if ((ife->flags & IFF_UP) || *opt_a)
2037 ife_print(ife);
2038 }
2039 return res;
2040}
2041
2042static struct interface *lookup_interface(char *name)
2043{
2044 struct interface *ife = NULL;
2045
2046 if (if_readlist_proc(name) < 0)
2047 return NULL;
2048 ife = add_interface(name);
2049 return ife;
2050}
2051
2052/* for ipv4 add/del modes */
2053static int if_print(char *ifname)
2054{
2055 int res;
2056
2057 if (!ifname) {
2058 res = for_all_interfaces(do_if_print, &interface_opt_a);
2059 } else {
2060 struct interface *ife;
2061
2062 ife = lookup_interface(ifname);
2063 res = do_if_fetch(ife);
2064 if (res >= 0)
2065 ife_print(ife);
2066 }
2067 return res;
2068}
2069
2070int display_interfaces(char *ifname)
2071{
2072 int status;
2073
2074 /* Create a channel to the NET kernel. */
2075 if ((skfd = sockets_open(0)) < 0) {
2076 bb_perror_msg_and_die("socket");
2077 }
2078
2079 /* Do we have to show the current setup? */
2080 status = if_print(ifname);
2081 close(skfd);
2082 exit(status < 0);
2083}