source: MondoRescue/branches/stable/mindi-busybox/networking/interface.c@ 904

Last change on this file since 904 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 26.7 KB
RevLine 
[821]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 * Added print_bytes_scaled function to reduce code size.
8 * Added some (potentially) missing defines.
9 * Improved display support for -a and for a named interface.
10 *
11 * -----------------------------------------------------------
12 *
13 * ifconfig This file contains an implementation of the command
14 * that either displays or sets the characteristics of
15 * one or more of the system's networking interfaces.
16 *
17 * Version: $Id: interface.c,v 1.25 2004/08/26 21:45:21 andersen Exp $
18 *
19 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
20 * and others. Copyright 1993 MicroWalt Corporation
21 *
22 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
23 *
24 * Patched to support 'add' and 'del' keywords for INET(4) addresses
25 * by Mrs. Brisby <mrs.brisby@nimh.org>
26 *
27 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
28 * - gettext instead of catgets for i18n
29 * 10/1998 - Andi Kleen. Use interface list primitives.
30 * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu
31 * (default AF was wrong)
32 */
33
34#include "inet_common.h"
35#include <stdio.h>
36#include <errno.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <ctype.h>
42#include <sys/ioctl.h>
43#include <sys/types.h>
44#include <net/if.h>
45#include <net/if_arp.h>
46#include "busybox.h"
47
48#ifdef CONFIG_FEATURE_IPV6
49# define HAVE_AFINET6 1
50#else
51# undef HAVE_AFINET6
52#endif
53
54#define _PATH_PROCNET_DEV "/proc/net/dev"
55#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
56
57#if HAVE_AFINET6
58
59#ifndef _LINUX_IN6_H
60/*
61 * This is in linux/include/net/ipv6.h.
62 */
63
64struct in6_ifreq {
65 struct in6_addr ifr6_addr;
66 uint32_t ifr6_prefixlen;
67 unsigned int ifr6_ifindex;
68};
69
70#endif
71
72#endif /* HAVE_AFINET6 */
73
74/* Defines for glibc2.0 users. */
75#ifndef SIOCSIFTXQLEN
76#define SIOCSIFTXQLEN 0x8943
77#define SIOCGIFTXQLEN 0x8942
78#endif
79
80/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
81#ifndef ifr_qlen
82#define ifr_qlen ifr_ifru.ifru_mtu
83#endif
84
85#ifndef HAVE_TXQUEUELEN
86#define HAVE_TXQUEUELEN 1
87#endif
88
89#ifndef IFF_DYNAMIC
90#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
91#endif
92
93/* This structure defines protocol families and their handlers. */
94struct aftype {
95 const char *name;
96 const char *title;
97 int af;
98 int alen;
99 char *(*print) (unsigned char *);
100 char *(*sprint) (struct sockaddr *, int numeric);
101 int (*input) (int type, char *bufp, struct sockaddr *);
102 void (*herror) (char *text);
103 int (*rprint) (int options);
104 int (*rinput) (int typ, int ext, char **argv);
105
106 /* may modify src */
107 int (*getmask) (char *src, struct sockaddr * mask, char *name);
108
109 int fd;
110 char *flag_file;
111};
112
113/* Display an Internet socket address. */
114static char *INET_sprint(struct sockaddr *sap, int numeric)
115{
116 static char buff[128];
117
118 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
119 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
120
121 if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap,
122 numeric, 0xffffff00) != 0)
123 return (NULL);
124
125 return (buff);
126}
127
128static struct aftype inet_aftype = {
129 .name = "inet",
130 .title = "DARPA Internet",
131 .af = AF_INET,
132 .alen = 4,
133 .sprint = INET_sprint,
134 .fd = -1
135};
136
137#if HAVE_AFINET6
138
139/* Display an Internet socket address. */
140/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
141static char *INET6_sprint(struct sockaddr *sap, int numeric)
142{
143 static char buff[128];
144
145 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
146 return safe_strncpy(buff, "[NONE SET]", sizeof(buff));
147 if (INET6_rresolve
148 (buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
149 return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff));
150 return (buff);
151}
152
153static struct aftype inet6_aftype = {
154 .name = "inet6",
155 .title = "IPv6",
156 .af = AF_INET6,
157 .alen = sizeof(struct in6_addr),
158 .sprint = INET6_sprint,
159 .fd = -1
160};
161
162#endif /* HAVE_AFINET6 */
163
164/* Display an UNSPEC address. */
165static char *UNSPEC_print(unsigned char *ptr)
166{
167 static char buff[sizeof(struct sockaddr) * 3 + 1];
168 char *pos;
169 unsigned int i;
170
171 pos = buff;
172 for (i = 0; i < sizeof(struct sockaddr); i++) {
173 /* careful -- not every libc's sprintf returns # bytes written */
174 sprintf(pos, "%02X-", (*ptr++ & 0377));
175 pos += 3;
176 }
177 /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */
178 *--pos = '\0';
179 return (buff);
180}
181
182/* Display an UNSPEC socket address. */
183static char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
184{
185 static char buf[64];
186
187 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
188 return safe_strncpy(buf, "[NONE SET]", sizeof(buf));
189 return (UNSPEC_print((unsigned char *)sap->sa_data));
190}
191
192static struct aftype unspec_aftype = {
193 "unspec", "UNSPEC", AF_UNSPEC, 0,
194 UNSPEC_print, UNSPEC_sprint, NULL, NULL,
195 NULL,
196};
197
198static struct aftype * const aftypes[] = {
199 &inet_aftype,
200#if HAVE_AFINET6
201 &inet6_aftype,
202#endif
203 &unspec_aftype,
204 NULL
205};
206
207/* Check our protocol family table for this family. */
208static struct aftype *get_afntype(int af)
209{
210 struct aftype * const *afp;
211
212 afp = aftypes;
213 while (*afp != NULL) {
214 if ((*afp)->af == af)
215 return (*afp);
216 afp++;
217 }
218 return (NULL);
219}
220
221/* Check our protocol family table for this family and return its socket */
222static int get_socket_for_af(int af)
223{
224 struct aftype * const *afp;
225
226 afp = aftypes;
227 while (*afp != NULL) {
228 if ((*afp)->af == af)
229 return (*afp)->fd;
230 afp++;
231 }
232 return -1;
233}
234
235struct user_net_device_stats {
236 unsigned long long rx_packets; /* total packets received */
237 unsigned long long tx_packets; /* total packets transmitted */
238 unsigned long long rx_bytes; /* total bytes received */
239 unsigned long long tx_bytes; /* total bytes transmitted */
240 unsigned long rx_errors; /* bad packets received */
241 unsigned long tx_errors; /* packet transmit problems */
242 unsigned long rx_dropped; /* no space in linux buffers */
243 unsigned long tx_dropped; /* no space available in linux */
244 unsigned long rx_multicast; /* multicast packets received */
245 unsigned long rx_compressed;
246 unsigned long tx_compressed;
247 unsigned long collisions;
248
249 /* detailed rx_errors: */
250 unsigned long rx_length_errors;
251 unsigned long rx_over_errors; /* receiver ring buff overflow */
252 unsigned long rx_crc_errors; /* recved pkt with crc error */
253 unsigned long rx_frame_errors; /* recv'd frame alignment error */
254 unsigned long rx_fifo_errors; /* recv'r fifo overrun */
255 unsigned long rx_missed_errors; /* receiver missed packet */
256 /* detailed tx_errors */
257 unsigned long tx_aborted_errors;
258 unsigned long tx_carrier_errors;
259 unsigned long tx_fifo_errors;
260 unsigned long tx_heartbeat_errors;
261 unsigned long tx_window_errors;
262};
263
264struct interface {
265 struct interface *next, *prev;
266 char name[IFNAMSIZ]; /* interface name */
267 short type; /* if type */
268 short flags; /* various flags */
269 int metric; /* routing metric */
270 int mtu; /* MTU value */
271 int tx_queue_len; /* transmit queue length */
272 struct ifmap map; /* hardware setup */
273 struct sockaddr addr; /* IP address */
274 struct sockaddr dstaddr; /* P-P IP address */
275 struct sockaddr broadaddr; /* IP broadcast address */
276 struct sockaddr netmask; /* IP network mask */
277 int has_ip;
278 char hwaddr[32]; /* HW address */
279 int statistics_valid;
280 struct user_net_device_stats stats; /* statistics */
281 int keepalive; /* keepalive value for SLIP */
282 int outfill; /* outfill value for SLIP */
283};
284
285
286int interface_opt_a = 0; /* show all interfaces */
287
288static struct interface *int_list, *int_last;
289static int skfd = -1; /* generic raw socket desc. */
290
291
292static int sockets_open(int family)
293{
294 struct aftype * const *aft;
295 int sfd = -1;
296 static int force = -1;
297
298 if (force < 0) {
299 force = 0;
300 if (get_linux_version_code() < KERNEL_VERSION(2,1,0))
301 force = 1;
302 if (access("/proc/net", R_OK))
303 force = 1;
304 }
305 for (aft = aftypes; *aft; aft++) {
306 struct aftype *af = *aft;
307 int type = SOCK_DGRAM;
308
309 if (af->af == AF_UNSPEC)
310 continue;
311 if (family && family != af->af)
312 continue;
313 if (af->fd != -1) {
314 sfd = af->fd;
315 continue;
316 }
317 /* Check some /proc file first to not stress kmod */
318 if (!family && !force && af->flag_file) {
319 if (access(af->flag_file, R_OK))
320 continue;
321 }
322 af->fd = socket(af->af, type, 0);
323 if (af->fd >= 0)
324 sfd = af->fd;
325 }
326 if (sfd < 0) {
327 bb_error_msg("No usable address families found.");
328 }
329 return sfd;
330}
331
332#ifdef CONFIG_FEATURE_CLEAN_UP
333static void sockets_close(void)
334{
335 struct aftype * const *aft;
336 for (aft = aftypes; *aft != NULL; aft++) {
337 struct aftype *af = *aft;
338 if( af->fd != -1 ) {
339 close(af->fd);
340 af->fd = -1;
341 }
342 }
343}
344#endif
345
346/* like strcmp(), but knows about numbers */
347static int nstrcmp(const char *a, const char *b)
348{
349 const char *a_ptr = a;
350 const char *b_ptr = b;
351
352 while (*a == *b) {
353 if (*a == '\0') {
354 return 0;
355 }
356 if (!isdigit(*a) && isdigit(*(a+1))) {
357 a_ptr = a+1;
358 b_ptr = b+1;
359 }
360 a++;
361 b++;
362 }
363
364 if (isdigit(*a) && isdigit(*b)) {
365 return atoi(a_ptr) > atoi(b_ptr) ? 1 : -1;
366 }
367 return *a - *b;
368}
369
370static struct interface *add_interface(char *name)
371{
372 struct interface *ife, **nextp, *new;
373
374 for (ife = int_last; ife; ife = ife->prev) {
375 int n = nstrcmp(ife->name, name);
376
377 if (n == 0)
378 return ife;
379 if (n < 0)
380 break;
381 }
382
383 new = xzalloc(sizeof(*new));
384 safe_strncpy(new->name, name, IFNAMSIZ);
385 nextp = ife ? &ife->next : &int_list;
386 new->prev = ife;
387 new->next = *nextp;
388 if (new->next)
389 new->next->prev = new;
390 else
391 int_last = new;
392 *nextp = new;
393 return new;
394}
395
396
397static int if_readconf(void)
398{
399 int numreqs = 30;
400 struct ifconf ifc;
401 struct ifreq *ifr;
402 int n, err = -1;
403 int skfd2;
404
405 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
406 (as of 2.1.128) */
407 skfd2 = get_socket_for_af(AF_INET);
408 if (skfd2 < 0) {
409 bb_perror_msg(("warning: no inet socket available"));
410 /* Try to soldier on with whatever socket we can get hold of. */
411 skfd2 = sockets_open(0);
412 if (skfd2 < 0)
413 return -1;
414 }
415
416 ifc.ifc_buf = NULL;
417 for (;;) {
418 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
419 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
420
421 if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) {
422 perror("SIOCGIFCONF");
423 goto out;
424 }
425 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
426 /* assume it overflowed and try again */
427 numreqs += 10;
428 continue;
429 }
430 break;
431 }
432
433 ifr = ifc.ifc_req;
434 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
435 add_interface(ifr->ifr_name);
436 ifr++;
437 }
438 err = 0;
439
440 out:
441 free(ifc.ifc_buf);
442 return err;
443}
444
445static char *get_name(char *name, char *p)
446{
447 /* Extract <name> from nul-terminated p where p matches
448 <name>: after leading whitespace.
449 If match is not made, set name empty and return unchanged p */
450 int namestart=0, nameend=0;
451 while (isspace(p[namestart]))
452 namestart++;
453 nameend=namestart;
454 while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
455 nameend++;
456 if (p[nameend]==':') {
457 if ((nameend-namestart)<IFNAMSIZ) {
458 memcpy(name,&p[namestart],nameend-namestart);
459 name[nameend-namestart]='\0';
460 p=&p[nameend];
461 } else {
462 /* Interface name too large */
463 name[0]='\0';
464 }
465 } else {
466 /* trailing ':' not found - return empty */
467 name[0]='\0';
468 }
469 return p + 1;
470}
471
472/* If scanf supports size qualifiers for %n conversions, then we can
473 * use a modified fmt that simply stores the position in the fields
474 * having no associated fields in the proc string. Of course, we need
475 * to zero them again when we're done. But that is smaller than the
476 * old approach of multiple scanf occurrences with large numbers of
477 * args. */
478
479/* static const char * const ss_fmt[] = { */
480/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
481/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
482/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
483/* }; */
484
485 /* Lie about the size of the int pointed to for %n. */
486#if INT_MAX == LONG_MAX
487static const char * const ss_fmt[] = {
488 "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
489 "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
490 "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
491};
492#else
493static const char * const ss_fmt[] = {
494 "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
495 "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
496 "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
497};
498
499#endif
500
501static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
502{
503 memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
504
505 sscanf(bp, ss_fmt[procnetdev_vsn],
506 &ife->stats.rx_bytes, /* missing for 0 */
507 &ife->stats.rx_packets,
508 &ife->stats.rx_errors,
509 &ife->stats.rx_dropped,
510 &ife->stats.rx_fifo_errors,
511 &ife->stats.rx_frame_errors,
512 &ife->stats.rx_compressed, /* missing for <= 1 */
513 &ife->stats.rx_multicast, /* missing for <= 1 */
514 &ife->stats.tx_bytes, /* missing for 0 */
515 &ife->stats.tx_packets,
516 &ife->stats.tx_errors,
517 &ife->stats.tx_dropped,
518 &ife->stats.tx_fifo_errors,
519 &ife->stats.collisions,
520 &ife->stats.tx_carrier_errors,
521 &ife->stats.tx_compressed /* missing for <= 1 */
522 );
523
524 if (procnetdev_vsn <= 1) {
525 if (procnetdev_vsn == 0) {
526 ife->stats.rx_bytes = 0;
527 ife->stats.tx_bytes = 0;
528 }
529 ife->stats.rx_multicast = 0;
530 ife->stats.rx_compressed = 0;
531 ife->stats.tx_compressed = 0;
532 }
533}
534
535static inline int procnetdev_version(char *buf)
536{
537 if (strstr(buf, "compressed"))
538 return 2;
539 if (strstr(buf, "bytes"))
540 return 1;
541 return 0;
542}
543
544static int if_readlist_proc(char *target)
545{
546 static int proc_read;
547 FILE *fh;
548 char buf[512];
549 struct interface *ife;
550 int err, procnetdev_vsn;
551
552 if (proc_read)
553 return 0;
554 if (!target)
555 proc_read = 1;
556
557 fh = fopen(_PATH_PROCNET_DEV, "r");
558 if (!fh) {
559 bb_perror_msg("Warning: cannot open %s. Limited output.", _PATH_PROCNET_DEV);
560 return if_readconf();
561 }
562 fgets(buf, sizeof buf, fh); /* eat line */
563 fgets(buf, sizeof buf, fh);
564
565 procnetdev_vsn = procnetdev_version(buf);
566
567 err = 0;
568 while (fgets(buf, sizeof buf, fh)) {
569 char *s, name[128];
570
571 s = get_name(name, buf);
572 ife = add_interface(name);
573 get_dev_fields(s, ife, procnetdev_vsn);
574 ife->statistics_valid = 1;
575 if (target && !strcmp(target, name))
576 break;
577 }
578 if (ferror(fh)) {
579 perror(_PATH_PROCNET_DEV);
580 err = -1;
581 proc_read = 0;
582 }
583 fclose(fh);
584 return err;
585}
586
587static int if_readlist(void)
588{
589 int err = if_readlist_proc(NULL);
590
591 if (!err)
592 err = if_readconf();
593 return err;
594}
595
596static int for_all_interfaces(int (*doit) (struct interface *, void *),
597 void *cookie)
598{
599 struct interface *ife;
600
601 if (!int_list && (if_readlist() < 0))
602 return -1;
603 for (ife = int_list; ife; ife = ife->next) {
604 int err = doit(ife, cookie);
605
606 if (err)
607 return err;
608 }
609 return 0;
610}
611
612/* Fetch the interface configuration from the kernel. */
613static int if_fetch(struct interface *ife)
614{
615 struct ifreq ifr;
616 int fd;
617 char *ifname = ife->name;
618
619 strcpy(ifr.ifr_name, ifname);
620 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
621 return (-1);
622 ife->flags = ifr.ifr_flags;
623
624 strcpy(ifr.ifr_name, ifname);
625 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
626 memset(ife->hwaddr, 0, 32);
627 else
628 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
629
630 ife->type = ifr.ifr_hwaddr.sa_family;
631
632 strcpy(ifr.ifr_name, ifname);
633 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
634 ife->metric = 0;
635 else
636 ife->metric = ifr.ifr_metric;
637
638 strcpy(ifr.ifr_name, ifname);
639 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
640 ife->mtu = 0;
641 else
642 ife->mtu = ifr.ifr_mtu;
643
644#ifdef SIOCGIFMAP
645 strcpy(ifr.ifr_name, ifname);
646 if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
647 ife->map = ifr.ifr_map;
648 else
649#endif
650 memset(&ife->map, 0, sizeof(struct ifmap));
651
652#ifdef HAVE_TXQUEUELEN
653 strcpy(ifr.ifr_name, ifname);
654 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
655 ife->tx_queue_len = -1; /* unknown value */
656 else
657 ife->tx_queue_len = ifr.ifr_qlen;
658#else
659 ife->tx_queue_len = -1; /* unknown value */
660#endif
661
662 /* IPv4 address? */
663 fd = get_socket_for_af(AF_INET);
664 if (fd >= 0) {
665 strcpy(ifr.ifr_name, ifname);
666 ifr.ifr_addr.sa_family = AF_INET;
667 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
668 ife->has_ip = 1;
669 ife->addr = ifr.ifr_addr;
670 strcpy(ifr.ifr_name, ifname);
671 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
672 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
673 else
674 ife->dstaddr = ifr.ifr_dstaddr;
675
676 strcpy(ifr.ifr_name, ifname);
677 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
678 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
679 else
680 ife->broadaddr = ifr.ifr_broadaddr;
681
682 strcpy(ifr.ifr_name, ifname);
683 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
684 memset(&ife->netmask, 0, sizeof(struct sockaddr));
685 else
686 ife->netmask = ifr.ifr_netmask;
687 } else
688 memset(&ife->addr, 0, sizeof(struct sockaddr));
689 }
690
691 return 0;
692}
693
694
695static int do_if_fetch(struct interface *ife)
696{
697 if (if_fetch(ife) < 0) {
698 char *errmsg;
699
700 if (errno == ENODEV) {
701 /* Give better error message for this case. */
702 errmsg = "Device not found";
703 } else {
704 errmsg = strerror(errno);
705 }
706 bb_error_msg("%s: error fetching interface information: %s",
707 ife->name, errmsg);
708 return -1;
709 }
710 return 0;
711}
712
713/* This structure defines hardware protocols and their handlers. */
714struct hwtype {
715 const char * const name;
716 const char *title;
717 int type;
718 int alen;
719 char *(*print) (unsigned char *);
720 int (*input) (char *, struct sockaddr *);
721 int (*activate) (int fd);
722 int suppress_null_addr;
723};
724
725static const struct hwtype unspec_hwtype = {
726 .name = "unspec",
727 .title = "UNSPEC",
728 .type = -1,
729 .print = UNSPEC_print
730};
731
732static const struct hwtype loop_hwtype = {
733 .name = "loop",
734 .title = "Local Loopback",
735 .type = ARPHRD_LOOPBACK
736};
737
738#include <net/if_arp.h>
739
740#if (__GLIBC__ >=2 && __GLIBC_MINOR >= 1) || defined(_NEWLIB_VERSION)
741#include <net/ethernet.h>
742#else
743#include <linux/if_ether.h>
744#endif
745
746/* Display an Ethernet address in readable format. */
747static char *pr_ether(unsigned char *ptr)
748{
749 static char buff[64];
750
751 snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X",
752 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
753 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
754 );
755 return (buff);
756}
757
758static const struct hwtype ether_hwtype = {
759 .name = "ether",
760 .title = "Ethernet",
761 .type = ARPHRD_ETHER,
762 .alen = ETH_ALEN,
763 .print = pr_ether
764};
765
766#include <net/if_arp.h>
767
768static const struct hwtype ppp_hwtype = {
769 .name = "ppp",
770 .title = "Point-to-Point Protocol",
771 .type = ARPHRD_PPP
772};
773
774#ifdef CONFIG_FEATURE_IPV6
775static const struct hwtype sit_hwtype = {
776 .name = "sit",
777 .title = "IPv6-in-IPv4",
778 .type = ARPHRD_SIT,
779 .print = UNSPEC_print,
780 .suppress_null_addr = 1
781} ;
782#endif
783
784static const struct hwtype * const hwtypes[] = {
785 &loop_hwtype,
786 &ether_hwtype,
787 &ppp_hwtype,
788 &unspec_hwtype,
789#ifdef CONFIG_FEATURE_IPV6
790 &sit_hwtype,
791#endif
792 NULL
793};
794
795#ifdef IFF_PORTSEL
796static const char * const if_port_text[] = {
797 /* Keep in step with <linux/netdevice.h> */
798 "unknown",
799 "10base2",
800 "10baseT",
801 "AUI",
802 "100baseT",
803 "100baseTX",
804 "100baseFX",
805 NULL
806};
807#endif
808
809/* Check our hardware type table for this type. */
810static const struct hwtype *get_hwntype(int type)
811{
812 const struct hwtype * const *hwp;
813
814 hwp = hwtypes;
815 while (*hwp != NULL) {
816 if ((*hwp)->type == type)
817 return (*hwp);
818 hwp++;
819 }
820 return (NULL);
821}
822
823/* return 1 if address is all zeros */
824static int hw_null_address(const struct hwtype *hw, void *ap)
825{
826 unsigned int i;
827 unsigned char *address = (unsigned char *) ap;
828
829 for (i = 0; i < hw->alen; i++)
830 if (address[i])
831 return 0;
832 return 1;
833}
834
835static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti";
836
837static void print_bytes_scaled(unsigned long long ull, const char *end)
838{
839 unsigned long long int_part;
840 const char *ext;
841 unsigned int frac_part;
842 int i;
843
844 frac_part = 0;
845 ext = TRext;
846 int_part = ull;
847 i = 4;
848 do {
849 if (int_part >= 1024) {
850 frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
851 int_part /= 1024;
852 ext += 3; /* KiB, MiB, GiB, TiB */
853 }
854 --i;
855 } while (i);
856
857 printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
858}
859
860static const char * const ife_print_flags_strs[] = {
861 "UP ",
862 "BROADCAST ",
863 "DEBUG ",
864 "LOOPBACK ",
865 "POINTOPOINT ",
866 "NOTRAILERS ",
867 "RUNNING ",
868 "NOARP ",
869 "PROMISC ",
870 "ALLMULTI ",
871 "SLAVE ",
872 "MASTER ",
873 "MULTICAST ",
874#ifdef HAVE_DYNAMIC
875 "DYNAMIC "
876#endif
877};
878
879static const unsigned short ife_print_flags_mask[] = {
880 IFF_UP,
881 IFF_BROADCAST,
882 IFF_DEBUG,
883 IFF_LOOPBACK,
884 IFF_POINTOPOINT,
885 IFF_NOTRAILERS,
886 IFF_RUNNING,
887 IFF_NOARP,
888 IFF_PROMISC,
889 IFF_ALLMULTI,
890 IFF_SLAVE,
891 IFF_MASTER,
892 IFF_MULTICAST,
893#ifdef HAVE_DYNAMIC
894 IFF_DYNAMIC
895#endif
896 0
897};
898
899static void ife_print(struct interface *ptr)
900{
901 struct aftype *ap;
902 const struct hwtype *hw;
903 int hf;
904 int can_compress = 0;
905
906#if HAVE_AFINET6
907 FILE *f;
908 char addr6[40], devname[20];
909 struct sockaddr_in6 sap;
910 int plen, scope, dad_status, if_idx;
911 char addr6p[8][5];
912#endif
913
914 ap = get_afntype(ptr->addr.sa_family);
915 if (ap == NULL)
916 ap = get_afntype(0);
917
918 hf = ptr->type;
919
920 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
921 can_compress = 1;
922
923 hw = get_hwntype(hf);
924 if (hw == NULL)
925 hw = get_hwntype(-1);
926
927 printf("%-9.9s Link encap:%s ", ptr->name, hw->title);
928 /* For some hardware types (eg Ash, ATM) we don't print the
929 hardware address if it's null. */
930 if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
931 hw->suppress_null_addr)))
932 printf("HWaddr %s ", hw->print((unsigned char *)ptr->hwaddr));
933#ifdef IFF_PORTSEL
934 if (ptr->flags & IFF_PORTSEL) {
935 printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
936 if (ptr->flags & IFF_AUTOMEDIA)
937 printf("(auto)");
938 }
939#endif
940 printf("\n");
941
942 if (ptr->has_ip) {
943 printf(" %s addr:%s ", ap->name,
944 ap->sprint(&ptr->addr, 1));
945 if (ptr->flags & IFF_POINTOPOINT) {
946 printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
947 }
948 if (ptr->flags & IFF_BROADCAST) {
949 printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
950 }
951 printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
952 }
953
954#if HAVE_AFINET6
955
956#define IPV6_ADDR_ANY 0x0000U
957
958#define IPV6_ADDR_UNICAST 0x0001U
959#define IPV6_ADDR_MULTICAST 0x0002U
960#define IPV6_ADDR_ANYCAST 0x0004U
961
962#define IPV6_ADDR_LOOPBACK 0x0010U
963#define IPV6_ADDR_LINKLOCAL 0x0020U
964#define IPV6_ADDR_SITELOCAL 0x0040U
965
966#define IPV6_ADDR_COMPATv4 0x0080U
967
968#define IPV6_ADDR_SCOPE_MASK 0x00f0U
969
970#define IPV6_ADDR_MAPPED 0x1000U
971#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
972
973 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
974 while (fscanf
975 (f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
976 addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
977 addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
978 &dad_status, devname) != EOF) {
979 if (!strcmp(devname, ptr->name)) {
980 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
981 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
982 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
983 inet_pton(AF_INET6, addr6,
984 (struct sockaddr *) &sap.sin6_addr);
985 sap.sin6_family = AF_INET6;
986 printf(" inet6 addr: %s/%d",
987 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
988 plen);
989 printf(" Scope:");
990 switch (scope & IPV6_ADDR_SCOPE_MASK) {
991 case 0:
992 printf("Global");
993 break;
994 case IPV6_ADDR_LINKLOCAL:
995 printf("Link");
996 break;
997 case IPV6_ADDR_SITELOCAL:
998 printf("Site");
999 break;
1000 case IPV6_ADDR_COMPATv4:
1001 printf("Compat");
1002 break;
1003 case IPV6_ADDR_LOOPBACK:
1004 printf("Host");
1005 break;
1006 default:
1007 printf("Unknown");
1008 }
1009 printf("\n");
1010 }
1011 }
1012 fclose(f);
1013 }
1014#endif
1015
1016 printf(" ");
1017 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1018
1019 if (ptr->flags == 0) {
1020 printf("[NO FLAGS] ");
1021 } else {
1022 int i = 0;
1023 do {
1024 if (ptr->flags & ife_print_flags_mask[i]) {
1025 printf(ife_print_flags_strs[i]);
1026 }
1027 } while (ife_print_flags_mask[++i]);
1028 }
1029
1030 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1031 printf(" MTU:%d Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1032#ifdef SIOCSKEEPALIVE
1033 if (ptr->outfill || ptr->keepalive)
1034 printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive);
1035#endif
1036 printf("\n");
1037
1038 /* If needed, display the interface statistics. */
1039
1040 if (ptr->statistics_valid) {
1041 /* XXX: statistics are currently only printed for the primary address,
1042 * not for the aliases, although strictly speaking they're shared
1043 * by all addresses.
1044 */
1045 printf(" ");
1046
1047 printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1048 ptr->stats.rx_packets, ptr->stats.rx_errors,
1049 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1050 ptr->stats.rx_frame_errors);
1051 if (can_compress)
1052 printf(" compressed:%lu\n",
1053 ptr->stats.rx_compressed);
1054 printf(" ");
1055 printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1056 ptr->stats.tx_packets, ptr->stats.tx_errors,
1057 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1058 ptr->stats.tx_carrier_errors);
1059 printf(" collisions:%lu ", ptr->stats.collisions);
1060 if (can_compress)
1061 printf("compressed:%lu ", ptr->stats.tx_compressed);
1062 if (ptr->tx_queue_len != -1)
1063 printf("txqueuelen:%d ", ptr->tx_queue_len);
1064 printf("\n R");
1065 print_bytes_scaled(ptr->stats.rx_bytes, " T");
1066 print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1067
1068 }
1069
1070 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1071 ptr->map.base_addr)) {
1072 printf(" ");
1073 if (ptr->map.irq)
1074 printf("Interrupt:%d ", ptr->map.irq);
1075 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
1076 I/O maps */
1077 printf("Base address:0x%lx ",
1078 (unsigned long) ptr->map.base_addr);
1079 if (ptr->map.mem_start) {
1080 printf("Memory:%lx-%lx ", ptr->map.mem_start,
1081 ptr->map.mem_end);
1082 }
1083 if (ptr->map.dma)
1084 printf("DMA chan:%x ", ptr->map.dma);
1085 printf("\n");
1086 }
1087 printf("\n");
1088}
1089
1090
1091static int do_if_print(struct interface *ife, void *cookie)
1092{
1093 int *opt_a = (int *) cookie;
1094 int res;
1095
1096 res = do_if_fetch(ife);
1097 if (res >= 0) {
1098 if ((ife->flags & IFF_UP) || *opt_a)
1099 ife_print(ife);
1100 }
1101 return res;
1102}
1103
1104static struct interface *lookup_interface(char *name)
1105{
1106 struct interface *ife = NULL;
1107
1108 if (if_readlist_proc(name) < 0)
1109 return NULL;
1110 ife = add_interface(name);
1111 return ife;
1112}
1113
1114/* for ipv4 add/del modes */
1115static int if_print(char *ifname)
1116{
1117 int res;
1118
1119 if (!ifname) {
1120 res = for_all_interfaces(do_if_print, &interface_opt_a);
1121 } else {
1122 struct interface *ife;
1123
1124 ife = lookup_interface(ifname);
1125 res = do_if_fetch(ife);
1126 if (res >= 0)
1127 ife_print(ife);
1128 }
1129 return res;
1130}
1131
1132int display_interfaces(char *ifname);
1133int display_interfaces(char *ifname)
1134{
1135 int status;
1136
1137 /* Create a channel to the NET kernel. */
1138 if ((skfd = sockets_open(0)) < 0) {
1139 bb_perror_msg_and_die("socket");
1140 }
1141
1142 /* Do we have to show the current setup? */
1143 status = if_print(ifname);
1144#ifdef CONFIG_FEATURE_CLEAN_UP
1145 sockets_close();
1146#endif
1147 exit(status < 0);
1148}
Note: See TracBrowser for help on using the repository browser.