better ioctl fallback handling for interface listing, avoids duplicate
[oss-qm-packages.git] / lib / interface.c
blob3caefe8755d4198fff3af91579bf37bf72a9083d
1 /* Code to manipulate interface information, shared between ifconfig and
2 netstat.
4 10/1998 partly rewriten by Andi Kleen to support an interface list.
5 I don't claim that the list operations are efficient @).
7 8/2000 Andi Kleen make the list operations a bit more efficient.
8 People are crazy enough to use thousands of aliases now.
10 $Id: interface.c,v 1.25 2002/12/05 21:54:50 ecki Exp $
13 #include "config.h"
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #include <netinet/in.h>
19 #include <net/if.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
27 #if HAVE_AFIPX
28 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
29 #include <netipx/ipx.h>
30 #else
31 #include "ipx.h"
32 #endif
33 #endif
35 #if HAVE_AFECONET
36 #include <neteconet/ec.h>
37 #endif
39 #ifdef HAVE_HWSLIP
40 #include <linux/if_slip.h>
41 #include <net/if_arp.h>
42 #endif
44 #include "net-support.h"
45 #include "pathnames.h"
46 #include "version.h"
47 #include "proc.h"
49 #include "interface.h"
50 #include "sockets.h"
51 #include "util.h"
52 #include "intl.h"
54 #ifdef IFF_PORTSEL
55 const char *if_port_text[][4] =
57 /* Keep in step with <linux/netdevice.h> */
58 {"unknown", NULL, NULL, NULL},
59 {"10base2", "bnc", "coax", NULL},
60 {"10baseT", "utp", "tpe", NULL},
61 {"AUI", "thick", "db15", NULL},
62 {"100baseT", NULL, NULL, NULL},
63 {"100baseTX", NULL, NULL, NULL},
64 {"100baseFX", NULL, NULL, NULL},
65 {NULL, NULL, NULL, NULL},
67 #endif
69 #define IPV6_ADDR_ANY 0x0000U
71 #define IPV6_ADDR_UNICAST 0x0001U
72 #define IPV6_ADDR_MULTICAST 0x0002U
73 #define IPV6_ADDR_ANYCAST 0x0004U
75 #define IPV6_ADDR_LOOPBACK 0x0010U
76 #define IPV6_ADDR_LINKLOCAL 0x0020U
77 #define IPV6_ADDR_SITELOCAL 0x0040U
79 #define IPV6_ADDR_COMPATv4 0x0080U
81 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
83 #define IPV6_ADDR_MAPPED 0x1000U
84 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
86 int procnetdev_vsn = 1;
88 int ife_short;
90 int if_list_all = 0; /* do we have requested the complete proc list, yet? */
92 static struct interface *int_list, *int_last;
94 static int if_readlist_proc(char *);
96 static struct interface *if_cache_add(char *name)
98 struct interface *ife, **nextp, *new;
100 if (!int_list)
101 int_last = NULL;
103 for (ife = int_last; ife; ife = ife->prev) {
104 int n = nstrcmp(ife->name, name);
105 if (n == 0)
106 return ife;
107 if (n < 0)
108 break;
110 new(new);
111 safe_strncpy(new->name, name, IFNAMSIZ);
112 nextp = ife ? &ife->next : &int_list;
113 new->prev = ife;
114 new->next = *nextp;
115 if (new->next)
116 new->next->prev = new;
117 else
118 int_last = new;
119 *nextp = new;
120 return new;
123 struct interface *lookup_interface(char *name)
125 /* if we have read all, use it */
126 if (if_list_all)
127 return if_cache_add(name);
129 /* otherwise we read a limited list */
130 if (if_readlist_proc(name) < 0)
131 return NULL;
133 return if_cache_add(name);
136 int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
138 struct interface *ife;
140 if (!int_list_all && (if_readlist() < 0))
141 return -1;
142 for (ife = int_list; ife; ife = ife->next) {
143 int err = doit(ife, cookie);
144 if (err)
145 return err;
147 return 0;
150 int if_cache_free(void)
152 struct interface *ife;
153 while ((ife = int_list) != NULL) {
154 int_list = ife->next;
155 free(ife);
157 int_last = NULL;
158 int_list_all = 0;
159 return 0;
162 static int if_readconf(void)
164 int numreqs = 30;
165 struct ifconf ifc;
166 struct ifreq *ifr;
167 int n, err = -1;
168 int skfd;
170 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
171 (as of 2.1.128) */
172 skfd = get_socket_for_af(AF_INET);
173 if (skfd < 0) {
174 fprintf(stderr, _("warning: no inet socket available: %s\n"),
175 strerror(errno));
176 /* Try to soldier on with whatever socket we can get hold of. */
177 skfd = sockets_open(0);
178 if (skfd < 0)
179 return -1;
182 ifc.ifc_buf = NULL;
183 for (;;) {
184 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
185 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
187 if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
188 perror("SIOCGIFCONF");
189 goto out;
191 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
192 /* assume it overflowed and try again */
193 numreqs *= 2;
194 continue;
196 break;
199 ifr = ifc.ifc_req;
200 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
201 if_cache_add(ifr->ifr_name);
202 ifr++;
204 err = 0;
206 out:
207 free(ifc.ifc_buf);
208 return err;
211 char *get_name(char *name, char *p)
213 while (isspace(*p))
214 p++;
215 while (*p) {
216 if (isspace(*p))
217 break;
218 if (*p == ':') { /* could be an alias */
219 char *dot = p++;
220 while (*p && isdigit(*p)) p++;
221 if (*p == ':') {
222 /* Yes it is, backup and copy it. */
223 p = dot;
224 *name++ = *p++;
225 while (*p && isdigit(*p)) {
226 *name++ = *p++;
228 } else {
229 /* No, it isn't */
230 p = dot;
232 p++;
233 break;
235 *name++ = *p++;
237 *name++ = '\0';
238 return p;
241 int procnetdev_version(char *buf)
243 if (strstr(buf, "compressed"))
244 return 3;
245 if (strstr(buf, "bytes"))
246 return 2;
247 return 1;
250 int get_dev_fields(char *bp, struct interface *ife)
252 switch (procnetdev_vsn) {
253 case 3:
254 sscanf(bp,
255 "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
256 &ife->stats.rx_bytes,
257 &ife->stats.rx_packets,
258 &ife->stats.rx_errors,
259 &ife->stats.rx_dropped,
260 &ife->stats.rx_fifo_errors,
261 &ife->stats.rx_frame_errors,
262 &ife->stats.rx_compressed,
263 &ife->stats.rx_multicast,
265 &ife->stats.tx_bytes,
266 &ife->stats.tx_packets,
267 &ife->stats.tx_errors,
268 &ife->stats.tx_dropped,
269 &ife->stats.tx_fifo_errors,
270 &ife->stats.collisions,
271 &ife->stats.tx_carrier_errors,
272 &ife->stats.tx_compressed);
273 break;
274 case 2:
275 sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
276 &ife->stats.rx_bytes,
277 &ife->stats.rx_packets,
278 &ife->stats.rx_errors,
279 &ife->stats.rx_dropped,
280 &ife->stats.rx_fifo_errors,
281 &ife->stats.rx_frame_errors,
283 &ife->stats.tx_bytes,
284 &ife->stats.tx_packets,
285 &ife->stats.tx_errors,
286 &ife->stats.tx_dropped,
287 &ife->stats.tx_fifo_errors,
288 &ife->stats.collisions,
289 &ife->stats.tx_carrier_errors);
290 ife->stats.rx_multicast = 0;
291 break;
292 case 1:
293 sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
294 &ife->stats.rx_packets,
295 &ife->stats.rx_errors,
296 &ife->stats.rx_dropped,
297 &ife->stats.rx_fifo_errors,
298 &ife->stats.rx_frame_errors,
300 &ife->stats.tx_packets,
301 &ife->stats.tx_errors,
302 &ife->stats.tx_dropped,
303 &ife->stats.tx_fifo_errors,
304 &ife->stats.collisions,
305 &ife->stats.tx_carrier_errors);
306 ife->stats.rx_bytes = 0;
307 ife->stats.tx_bytes = 0;
308 ife->stats.rx_multicast = 0;
309 break;
311 return 0;
314 static int if_readlist_proc(char *target)
316 FILE *fh;
317 char buf[512];
318 struct interface *ife;
319 int err;
321 fh = fopen(_PATH_PROCNET_DEV, "r");
322 if (!fh) {
323 fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
324 _PATH_PROCNET_DEV, strerror(errno));
325 return -2;
327 fgets(buf, sizeof buf, fh); /* eat line */
328 fgets(buf, sizeof buf, fh);
330 #if 0 /* pretty, but can't cope with missing fields */
331 fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
332 "face", "", /* parsed separately */
333 "bytes", "%lu",
334 "packets", "%lu",
335 "errs", "%lu",
336 "drop", "%lu",
337 "fifo", "%lu",
338 "frame", "%lu",
339 "compressed", "%lu",
340 "multicast", "%lu",
341 "bytes", "%lu",
342 "packets", "%lu",
343 "errs", "%lu",
344 "drop", "%lu",
345 "fifo", "%lu",
346 "colls", "%lu",
347 "carrier", "%lu",
348 "compressed", "%lu",
349 NULL);
350 if (!fmt)
351 return -1;
352 #else
353 procnetdev_vsn = procnetdev_version(buf);
354 #endif
356 err = 0;
357 while (fgets(buf, sizeof buf, fh)) {
358 char *s, name[IFNAMSIZ];
359 s = get_name(name, buf);
360 ife = if_cache_add(name);
361 get_dev_fields(s, ife);
362 ife->statistics_valid = 1;
363 if (target && !strcmp(target,name))
364 break;
366 if (ferror(fh)) {
367 perror(_PATH_PROCNET_DEV);
368 err = -1;
371 #if 0
372 free(fmt);
373 #endif
374 fclose(fh);
375 return err;
378 int if_readlist(void)
380 /* caller will/should check not to call this too often
381 * (i.e. only if int_list_all == 0
383 int err = if_readlist_proc(NULL);
385 if (err)
386 err = if_readconf();
388 if(!err)
389 if_list_all = 1;
391 return err;
394 /* Support for fetching an IPX address */
396 #if HAVE_AFIPX
397 static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
399 ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
400 return ioctl(sock, SIOCGIFADDR, ifr);
402 #endif
404 /* Fetch the interface configuration from the kernel. */
405 int if_fetch(struct interface *ife)
407 struct ifreq ifr;
408 int fd;
409 char *ifname = ife->name;
411 strcpy(ifr.ifr_name, ifname);
412 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
413 return (-1);
414 ife->flags = ifr.ifr_flags;
416 strcpy(ifr.ifr_name, ifname);
417 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
418 memset(ife->hwaddr, 0, 32);
419 else
420 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
422 ife->type = ifr.ifr_hwaddr.sa_family;
424 strcpy(ifr.ifr_name, ifname);
425 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
426 ife->metric = 0;
427 else
428 ife->metric = ifr.ifr_metric;
430 strcpy(ifr.ifr_name, ifname);
431 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
432 ife->mtu = 0;
433 else
434 ife->mtu = ifr.ifr_mtu;
436 #ifdef HAVE_HWSLIP
437 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
438 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
439 ife->type == ARPHRD_ADAPT) {
440 #ifdef SIOCGOUTFILL
441 strcpy(ifr.ifr_name, ifname);
442 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
443 ife->outfill = 0;
444 else
445 ife->outfill = (unsigned int) ifr.ifr_data;
446 #endif
447 #ifdef SIOCGKEEPALIVE
448 strcpy(ifr.ifr_name, ifname);
449 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
450 ife->keepalive = 0;
451 else
452 ife->keepalive = (unsigned int) ifr.ifr_data;
453 #endif
455 #endif
457 strcpy(ifr.ifr_name, ifname);
458 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
459 memset(&ife->map, 0, sizeof(struct ifmap));
460 else
461 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
463 strcpy(ifr.ifr_name, ifname);
464 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
465 memset(&ife->map, 0, sizeof(struct ifmap));
466 else
467 ife->map = ifr.ifr_map;
469 #ifdef HAVE_TXQUEUELEN
470 strcpy(ifr.ifr_name, ifname);
471 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
472 ife->tx_queue_len = -1; /* unknown value */
473 else
474 ife->tx_queue_len = ifr.ifr_qlen;
475 #else
476 ife->tx_queue_len = -1; /* unknown value */
477 #endif
479 #if HAVE_AFINET
480 /* IPv4 address? */
481 fd = get_socket_for_af(AF_INET);
482 if (fd >= 0) {
483 strcpy(ifr.ifr_name, ifname);
484 ifr.ifr_addr.sa_family = AF_INET;
485 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
486 ife->has_ip = 1;
487 ife->addr = ifr.ifr_addr;
488 strcpy(ifr.ifr_name, ifname);
489 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
490 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
491 else
492 ife->dstaddr = ifr.ifr_dstaddr;
494 strcpy(ifr.ifr_name, ifname);
495 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
496 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
497 else
498 ife->broadaddr = ifr.ifr_broadaddr;
500 strcpy(ifr.ifr_name, ifname);
501 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
502 memset(&ife->netmask, 0, sizeof(struct sockaddr));
503 else
504 ife->netmask = ifr.ifr_netmask;
505 } else
506 memset(&ife->addr, 0, sizeof(struct sockaddr));
508 #endif
510 #if HAVE_AFATALK
511 /* DDP address maybe ? */
512 fd = get_socket_for_af(AF_APPLETALK);
513 if (fd >= 0) {
514 strcpy(ifr.ifr_name, ifname);
515 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
516 ife->ddpaddr = ifr.ifr_addr;
517 ife->has_ddp = 1;
520 #endif
522 #if HAVE_AFIPX
523 /* Look for IPX addresses with all framing types */
524 fd = get_socket_for_af(AF_IPX);
525 if (fd >= 0) {
526 strcpy(ifr.ifr_name, ifname);
527 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
528 ife->has_ipx_bb = 1;
529 ife->ipxaddr_bb = ifr.ifr_addr;
531 strcpy(ifr.ifr_name, ifname);
532 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
533 ife->has_ipx_sn = 1;
534 ife->ipxaddr_sn = ifr.ifr_addr;
536 strcpy(ifr.ifr_name, ifname);
537 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
538 ife->has_ipx_e3 = 1;
539 ife->ipxaddr_e3 = ifr.ifr_addr;
541 strcpy(ifr.ifr_name, ifname);
542 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
543 ife->has_ipx_e2 = 1;
544 ife->ipxaddr_e2 = ifr.ifr_addr;
547 #endif
549 #if HAVE_AFECONET
550 /* Econet address maybe? */
551 fd = get_socket_for_af(AF_ECONET);
552 if (fd >= 0) {
553 strcpy(ifr.ifr_name, ifname);
554 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
555 ife->ecaddr = ifr.ifr_addr;
556 ife->has_econet = 1;
559 #endif
561 return 0;
564 int do_if_fetch(struct interface *ife)
566 if (if_fetch(ife) < 0) {
567 char *errmsg;
568 if (errno == ENODEV) {
569 /* Give better error message for this case. */
570 errmsg = _("Device not found");
571 } else {
572 errmsg = strerror(errno);
574 fprintf(stderr, _("%s: error fetching interface information: %s\n"),
575 ife->name, errmsg);
576 return -1;
578 return 0;
581 int do_if_print(struct interface *ife, void *cookie)
583 int *opt_a = (int *) cookie;
584 int res;
586 res = do_if_fetch(ife);
587 if (res >= 0) {
588 if ((ife->flags & IFF_UP) || *opt_a)
589 ife_print(ife);
591 return res;
594 void ife_print_short(struct interface *ptr)
596 printf("%-5.5s ", ptr->name);
597 printf("%5d %-2d", ptr->mtu, ptr->metric);
598 /* If needed, display the interface statistics. */
599 if (ptr->statistics_valid) {
600 printf("%9llu %6lu %6lu %-5lu",
601 ptr->stats.rx_packets, ptr->stats.rx_errors,
602 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
603 printf("%9llu %6lu %6lu %6lu ",
604 ptr->stats.tx_packets, ptr->stats.tx_errors,
605 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
606 } else {
607 printf("%-56s", _(" - no statistics available -"));
609 /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
610 if (ptr->flags == 0)
611 printf(_("[NO FLAGS]"));
612 if (ptr->flags & IFF_ALLMULTI)
613 printf("A");
614 if (ptr->flags & IFF_BROADCAST)
615 printf("B");
616 if (ptr->flags & IFF_DEBUG)
617 printf("D");
618 if (ptr->flags & IFF_LOOPBACK)
619 printf("L");
620 if (ptr->flags & IFF_MULTICAST)
621 printf("M");
622 #ifdef HAVE_DYNAMIC
623 if (ptr->flags & IFF_DYNAMIC)
624 printf("d");
625 #endif
626 if (ptr->flags & IFF_PROMISC)
627 printf("P");
628 if (ptr->flags & IFF_NOTRAILERS)
629 printf("N");
630 if (ptr->flags & IFF_NOARP)
631 printf("O");
632 if (ptr->flags & IFF_POINTOPOINT)
633 printf("P");
634 if (ptr->flags & IFF_SLAVE)
635 printf("s");
636 if (ptr->flags & IFF_MASTER)
637 printf("m");
638 if (ptr->flags & IFF_RUNNING)
639 printf("R");
640 if (ptr->flags & IFF_UP)
641 printf("U");
642 /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
643 printf("\n");
646 void ife_print_long(struct interface *ptr)
648 struct aftype *ap;
649 struct hwtype *hw;
650 int hf;
651 int can_compress = 0;
652 unsigned long long rx, tx, short_rx, short_tx;
653 const char *Rext = "b";
654 const char *Text = "b";
656 #if HAVE_AFIPX
657 static struct aftype *ipxtype = NULL;
658 #endif
659 #if HAVE_AFECONET
660 static struct aftype *ectype = NULL;
661 #endif
662 #if HAVE_AFATALK
663 static struct aftype *ddptype = NULL;
664 #endif
665 #if HAVE_AFINET6
666 FILE *f;
667 char addr6[40], devname[20];
668 struct sockaddr_in6 sap;
669 int plen, scope, dad_status, if_idx;
670 extern struct aftype inet6_aftype;
671 char addr6p[8][5];
672 #endif
674 ap = get_afntype(ptr->addr.sa_family);
675 if (ap == NULL)
676 ap = get_afntype(0);
678 hf = ptr->type;
680 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
681 can_compress = 1;
683 hw = get_hwntype(hf);
684 if (hw == NULL)
685 hw = get_hwntype(-1);
687 printf(_("%-9.9s Link encap:%s "), ptr->name, hw->title);
688 /* For some hardware types (eg Ash, ATM) we don't print the
689 hardware address if it's null. */
690 if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
691 hw->suppress_null_addr)))
692 printf(_("HWaddr %s "), hw->print(ptr->hwaddr));
693 #ifdef IFF_PORTSEL
694 if (ptr->flags & IFF_PORTSEL) {
695 printf(_("Media:%s"), if_port_text[ptr->map.port][0]);
696 if (ptr->flags & IFF_AUTOMEDIA)
697 printf(_("(auto)"));
699 #endif
700 printf("\n");
702 #if HAVE_AFINET
703 if (ptr->has_ip) {
704 printf(_(" %s addr:%s "), ap->name,
705 ap->sprint(&ptr->addr, 1));
706 if (ptr->flags & IFF_POINTOPOINT) {
707 printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1));
709 if (ptr->flags & IFF_BROADCAST) {
710 printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1));
712 printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1));
714 #endif
716 #if HAVE_AFINET6
717 /* FIXME: should be integrated into interface.c. */
719 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
720 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
721 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
722 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
723 &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
724 if (!strcmp(devname, ptr->name)) {
725 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
726 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
727 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
728 inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
729 printf(_(" inet6 addr: %s/%d"),
730 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
731 printf(_(" Scope:"));
732 switch (scope) {
733 case 0:
734 printf(_("Global"));
735 break;
736 case IPV6_ADDR_LINKLOCAL:
737 printf(_("Link"));
738 break;
739 case IPV6_ADDR_SITELOCAL:
740 printf(_("Site"));
741 break;
742 case IPV6_ADDR_COMPATv4:
743 printf(_("Compat"));
744 break;
745 case IPV6_ADDR_LOOPBACK:
746 printf(_("Host"));
747 break;
748 default:
749 printf(_("Unknown"));
751 printf("\n");
754 fclose(f);
756 #endif
758 #if HAVE_AFIPX
759 if (ipxtype == NULL)
760 ipxtype = get_afntype(AF_IPX);
762 if (ipxtype != NULL) {
763 if (ptr->has_ipx_bb)
764 printf(_(" IPX/Ethernet II addr:%s\n"),
765 ipxtype->sprint(&ptr->ipxaddr_bb, 1));
766 if (ptr->has_ipx_sn)
767 printf(_(" IPX/Ethernet SNAP addr:%s\n"),
768 ipxtype->sprint(&ptr->ipxaddr_sn, 1));
769 if (ptr->has_ipx_e2)
770 printf(_(" IPX/Ethernet 802.2 addr:%s\n"),
771 ipxtype->sprint(&ptr->ipxaddr_e2, 1));
772 if (ptr->has_ipx_e3)
773 printf(_(" IPX/Ethernet 802.3 addr:%s\n"),
774 ipxtype->sprint(&ptr->ipxaddr_e3, 1));
776 #endif
778 #if HAVE_AFATALK
779 if (ddptype == NULL)
780 ddptype = get_afntype(AF_APPLETALK);
781 if (ddptype != NULL) {
782 if (ptr->has_ddp)
783 printf(_(" EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1));
785 #endif
787 #if HAVE_AFECONET
788 if (ectype == NULL)
789 ectype = get_afntype(AF_ECONET);
790 if (ectype != NULL) {
791 if (ptr->has_econet)
792 printf(_(" econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1));
794 #endif
796 printf(" ");
797 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
798 if (ptr->flags == 0)
799 printf(_("[NO FLAGS] "));
800 if (ptr->flags & IFF_UP)
801 printf(_("UP "));
802 if (ptr->flags & IFF_BROADCAST)
803 printf(_("BROADCAST "));
804 if (ptr->flags & IFF_DEBUG)
805 printf(_("DEBUG "));
806 if (ptr->flags & IFF_LOOPBACK)
807 printf(_("LOOPBACK "));
808 if (ptr->flags & IFF_POINTOPOINT)
809 printf(_("POINTOPOINT "));
810 if (ptr->flags & IFF_NOTRAILERS)
811 printf(_("NOTRAILERS "));
812 if (ptr->flags & IFF_RUNNING)
813 printf(_("RUNNING "));
814 if (ptr->flags & IFF_NOARP)
815 printf(_("NOARP "));
816 if (ptr->flags & IFF_PROMISC)
817 printf(_("PROMISC "));
818 if (ptr->flags & IFF_ALLMULTI)
819 printf(_("ALLMULTI "));
820 if (ptr->flags & IFF_SLAVE)
821 printf(_("SLAVE "));
822 if (ptr->flags & IFF_MASTER)
823 printf(_("MASTER "));
824 if (ptr->flags & IFF_MULTICAST)
825 printf(_("MULTICAST "));
826 #ifdef HAVE_DYNAMIC
827 if (ptr->flags & IFF_DYNAMIC)
828 printf(_("DYNAMIC "));
829 #endif
830 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
831 printf(_(" MTU:%d Metric:%d"),
832 ptr->mtu, ptr->metric ? ptr->metric : 1);
833 #ifdef SIOCSKEEPALIVE
834 if (ptr->outfill || ptr->keepalive)
835 printf(_(" Outfill:%d Keepalive:%d"),
836 ptr->outfill, ptr->keepalive);
837 #endif
838 printf("\n");
840 /* If needed, display the interface statistics. */
842 if (ptr->statistics_valid) {
843 /* XXX: statistics are currently only printed for the primary address,
844 * not for the aliases, although strictly speaking they're shared
845 * by all addresses.
847 printf(" ");
849 printf(_("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"),
850 ptr->stats.rx_packets, ptr->stats.rx_errors,
851 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
852 ptr->stats.rx_frame_errors);
853 if (can_compress)
854 printf(_(" compressed:%lu\n"), ptr->stats.rx_compressed);
856 rx = ptr->stats.rx_bytes;
857 tx = ptr->stats.tx_bytes;
858 short_rx = rx * 10;
859 short_tx = tx * 10;
860 if (rx > 1125899906842624) {
861 short_rx /= 1125899906842624;
862 Rext = "PiB";
863 } else if (rx > 1099511627776) {
864 short_rx /= 1099511627776;
865 Rext = "TiB";
866 } else if (rx > 1073741824) {
867 short_rx /= 1073741824;
868 Rext = "GiB";
869 } else if (rx > 1048576) {
870 short_rx /= 1048576;
871 Rext = "MiB";
872 } else if (rx > 1024) {
873 short_rx /= 1024;
874 Rext = "KiB";
876 if (tx > 1125899906842624) {
877 short_tx /= 1125899906842624;
878 Text = "PiB";
879 } else if (tx > 1099511627776) {
880 short_tx /= 1099511627776;
881 Text = "TiB";
882 } else if (tx > 1073741824) {
883 short_tx /= 1073741824;
884 Text = "GiB";
885 } else if (tx > 1048576) {
886 short_tx /= 1048576;
887 Text = "MiB";
888 } else if (tx > 1024) {
889 short_tx /= 1024;
890 Text = "KiB";
893 printf(" ");
894 printf(_("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"),
895 ptr->stats.tx_packets, ptr->stats.tx_errors,
896 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
897 ptr->stats.tx_carrier_errors);
898 printf(_(" collisions:%lu "), ptr->stats.collisions);
899 if (can_compress)
900 printf(_("compressed:%lu "), ptr->stats.tx_compressed);
901 if (ptr->tx_queue_len != -1)
902 printf(_("txqueuelen:%d "), ptr->tx_queue_len);
903 printf("\n ");
904 printf(_("RX bytes:%llu (%lu.%lu %s) TX bytes:%llu (%lu.%lu %s)\n"),
905 rx, (unsigned long)(short_rx / 10),
906 (unsigned long)(short_rx % 10), Rext,
907 tx, (unsigned long)(short_tx / 10),
908 (unsigned long)(short_tx % 10), Text);
911 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
912 ptr->map.base_addr >= 0x100)) {
913 printf(" ");
914 if (ptr->map.irq)
915 printf(_("Interrupt:%d "), ptr->map.irq);
916 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
917 I/O maps */
918 printf(_("Base address:0x%x "), ptr->map.base_addr);
919 if (ptr->map.mem_start) {
920 printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
922 if (ptr->map.dma)
923 printf(_("DMA chan:%x "), ptr->map.dma);
924 printf("\n");
926 printf("\n");
929 void ife_print(struct interface *i)
931 if (ife_short)
932 ife_print_short(i);
933 else
934 ife_print_long(i);