Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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