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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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