Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide 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 niro 532 /* 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     }