Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/networking/interface.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 29903 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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