added 'ull' prefix to unsigned long long constants to make gcc 3.3 happy
[oss-qm-packages.git] / lib / interface.c
blob913cca2fa5e00a018bc2819381c311ff806d4484
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.28 2003/05/29 02:09:14 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>
26 #include <string.h>
28 #if HAVE_AFIPX
29 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
30 #include <netipx/ipx.h>
31 #else
32 #include "ipx.h"
33 #endif
34 #endif
36 #if HAVE_AFECONET
37 #include <neteconet/ec.h>
38 #endif
40 #ifdef HAVE_HWSLIP
41 #include <linux/if_slip.h>
42 #include <net/if_arp.h>
43 #endif
45 #include "net-support.h"
46 #include "pathnames.h"
47 #include "version.h"
48 #include "proc.h"
50 #include "interface.h"
51 #include "sockets.h"
52 #include "util.h"
53 #include "intl.h"
55 #ifdef IFF_PORTSEL
56 const char *if_port_text[][4] =
58 /* Keep in step with <linux/netdevice.h> */
59 {"unknown", NULL, NULL, NULL},
60 {"10base2", "bnc", "coax", NULL},
61 {"10baseT", "utp", "tpe", NULL},
62 {"AUI", "thick", "db15", NULL},
63 {"100baseT", NULL, NULL, NULL},
64 {"100baseTX", NULL, NULL, NULL},
65 {"100baseFX", NULL, NULL, NULL},
66 {NULL, NULL, NULL, NULL},
68 #endif
70 #define IPV6_ADDR_ANY 0x0000U
72 #define IPV6_ADDR_UNICAST 0x0001U
73 #define IPV6_ADDR_MULTICAST 0x0002U
74 #define IPV6_ADDR_ANYCAST 0x0004U
76 #define IPV6_ADDR_LOOPBACK 0x0010U
77 #define IPV6_ADDR_LINKLOCAL 0x0020U
78 #define IPV6_ADDR_SITELOCAL 0x0040U
80 #define IPV6_ADDR_COMPATv4 0x0080U
82 #define IPV6_ADDR_SCOPE_MASK 0x00f0U
84 #define IPV6_ADDR_MAPPED 0x1000U
85 #define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
87 int procnetdev_vsn = 1;
89 int ife_short;
91 int if_list_all = 0; /* do we have requested the complete proc list, yet? */
93 static struct interface *int_list, *int_last;
95 static int if_readlist_proc(char *);
97 static struct interface *if_cache_add(char *name)
99 struct interface *ife, **nextp, *new;
101 if (!int_list)
102 int_last = NULL;
104 /* the cache is sorted, so if we hit a smaller if, exit */
105 for (ife = int_last; ife; ife = ife->prev) {
106 int n = nstrcmp(ife->name, name);
107 if (n == 0)
108 return ife;
109 if (n < 0)
110 break;
112 new(new);
113 safe_strncpy(new->name, name, IFNAMSIZ);
114 nextp = ife ? &ife->next : &int_list; // keep sorting
115 new->prev = ife;
116 new->next = *nextp;
117 if (new->next)
118 new->next->prev = new;
119 else
120 int_last = new;
121 *nextp = new;
122 return new;
125 struct interface *lookup_interface(char *name)
127 /* if we have read all, use it */
128 if (if_list_all)
129 return if_cache_add(name);
131 /* otherwise we read a limited list */
132 if (if_readlist_proc(name) < 0)
133 return NULL;
135 return if_cache_add(name);
138 int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
140 struct interface *ife;
142 if (!if_list_all && (if_readlist() < 0))
143 return -1;
144 for (ife = int_list; ife; ife = ife->next) {
145 int err = doit(ife, cookie);
146 if (err)
147 return err;
149 return 0;
152 int if_cache_free(void)
154 struct interface *ife;
155 while ((ife = int_list) != NULL) {
156 int_list = ife->next;
157 free(ife);
159 int_last = NULL;
160 if_list_all = 0;
161 return 0;
164 static int if_readconf(void)
166 int numreqs = 30;
167 struct ifconf ifc;
168 struct ifreq *ifr;
169 int n, err = -1;
170 int skfd;
172 /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
173 (as of 2.1.128) */
174 skfd = get_socket_for_af(AF_INET);
175 if (skfd < 0) {
176 fprintf(stderr, _("warning: no inet socket available: %s\n"),
177 strerror(errno));
178 /* Try to soldier on with whatever socket we can get hold of. */
179 skfd = sockets_open(0);
180 if (skfd < 0)
181 return -1;
184 ifc.ifc_buf = NULL;
185 for (;;) {
186 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
187 ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
189 if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
190 perror("SIOCGIFCONF");
191 goto out;
193 if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
194 /* assume it overflowed and try again */
195 numreqs *= 2;
196 continue;
198 break;
201 ifr = ifc.ifc_req;
202 for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
203 if_cache_add(ifr->ifr_name);
204 ifr++;
206 err = 0;
208 out:
209 free(ifc.ifc_buf);
210 return err;
213 char *get_name(char *name, char *p)
215 while (isspace(*p))
216 p++;
217 while (*p) {
218 if (isspace(*p))
219 break;
220 if (*p == ':') { /* could be an alias */
221 char *dot = p++;
222 while (*p && isdigit(*p)) p++;
223 if (*p == ':') {
224 /* Yes it is, backup and copy it. */
225 p = dot;
226 *name++ = *p++;
227 while (*p && isdigit(*p)) {
228 *name++ = *p++;
230 } else {
231 /* No, it isn't */
232 p = dot;
234 p++;
235 break;
237 *name++ = *p++;
239 *name++ = '\0';
240 return p;
243 int procnetdev_version(char *buf)
245 if (strstr(buf, "compressed"))
246 return 3;
247 if (strstr(buf, "bytes"))
248 return 2;
249 return 1;
252 int get_dev_fields(char *bp, struct interface *ife)
254 switch (procnetdev_vsn) {
255 case 3:
256 sscanf(bp,
257 "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu",
258 &ife->stats.rx_bytes,
259 &ife->stats.rx_packets,
260 &ife->stats.rx_errors,
261 &ife->stats.rx_dropped,
262 &ife->stats.rx_fifo_errors,
263 &ife->stats.rx_frame_errors,
264 &ife->stats.rx_compressed,
265 &ife->stats.rx_multicast,
267 &ife->stats.tx_bytes,
268 &ife->stats.tx_packets,
269 &ife->stats.tx_errors,
270 &ife->stats.tx_dropped,
271 &ife->stats.tx_fifo_errors,
272 &ife->stats.collisions,
273 &ife->stats.tx_carrier_errors,
274 &ife->stats.tx_compressed);
275 break;
276 case 2:
277 sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu",
278 &ife->stats.rx_bytes,
279 &ife->stats.rx_packets,
280 &ife->stats.rx_errors,
281 &ife->stats.rx_dropped,
282 &ife->stats.rx_fifo_errors,
283 &ife->stats.rx_frame_errors,
285 &ife->stats.tx_bytes,
286 &ife->stats.tx_packets,
287 &ife->stats.tx_errors,
288 &ife->stats.tx_dropped,
289 &ife->stats.tx_fifo_errors,
290 &ife->stats.collisions,
291 &ife->stats.tx_carrier_errors);
292 ife->stats.rx_multicast = 0;
293 break;
294 case 1:
295 sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu",
296 &ife->stats.rx_packets,
297 &ife->stats.rx_errors,
298 &ife->stats.rx_dropped,
299 &ife->stats.rx_fifo_errors,
300 &ife->stats.rx_frame_errors,
302 &ife->stats.tx_packets,
303 &ife->stats.tx_errors,
304 &ife->stats.tx_dropped,
305 &ife->stats.tx_fifo_errors,
306 &ife->stats.collisions,
307 &ife->stats.tx_carrier_errors);
308 ife->stats.rx_bytes = 0;
309 ife->stats.tx_bytes = 0;
310 ife->stats.rx_multicast = 0;
311 break;
313 return 0;
316 static int if_readlist_proc(char *target)
318 FILE *fh;
319 char buf[512];
320 struct interface *ife;
321 int err;
323 fh = fopen(_PATH_PROCNET_DEV, "r");
324 if (!fh) {
325 fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"),
326 _PATH_PROCNET_DEV, strerror(errno));
327 return -2;
329 fgets(buf, sizeof buf, fh); /* eat line */
330 fgets(buf, sizeof buf, fh);
332 #if 0 /* pretty, but can't cope with missing fields */
333 fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh,
334 "face", "", /* parsed separately */
335 "bytes", "%lu",
336 "packets", "%lu",
337 "errs", "%lu",
338 "drop", "%lu",
339 "fifo", "%lu",
340 "frame", "%lu",
341 "compressed", "%lu",
342 "multicast", "%lu",
343 "bytes", "%lu",
344 "packets", "%lu",
345 "errs", "%lu",
346 "drop", "%lu",
347 "fifo", "%lu",
348 "colls", "%lu",
349 "carrier", "%lu",
350 "compressed", "%lu",
351 NULL);
352 if (!fmt)
353 return -1;
354 #else
355 procnetdev_vsn = procnetdev_version(buf);
356 #endif
358 err = 0;
359 while (fgets(buf, sizeof buf, fh)) {
360 char *s, name[IFNAMSIZ];
361 s = get_name(name, buf);
362 ife = if_cache_add(name);
363 get_dev_fields(s, ife);
364 ife->statistics_valid = 1;
365 if (target && !strcmp(target,name))
366 break;
368 if (ferror(fh)) {
369 perror(_PATH_PROCNET_DEV);
370 err = -1;
373 #if 0
374 free(fmt);
375 #endif
376 fclose(fh);
377 return err;
380 int if_readlist(void)
382 /* caller will/should check not to call this too often
383 * (i.e. only if if_list_all == 0
385 int err = if_readlist_proc(NULL);
387 if (err)
388 err = if_readconf();
390 if(!err)
391 if_list_all = 1;
393 return err;
396 /* Support for fetching an IPX address */
398 #if HAVE_AFIPX
399 static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
401 ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
402 return ioctl(sock, SIOCGIFADDR, ifr);
404 #endif
406 /* Fetch the interface configuration from the kernel. */
407 int if_fetch(struct interface *ife)
409 struct ifreq ifr;
410 int fd;
411 char *ifname = ife->name;
413 strcpy(ifr.ifr_name, ifname);
414 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
415 return (-1);
416 ife->flags = ifr.ifr_flags;
418 strcpy(ifr.ifr_name, ifname);
419 if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
420 memset(ife->hwaddr, 0, 32);
421 else
422 memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
424 ife->type = ifr.ifr_hwaddr.sa_family;
426 strcpy(ifr.ifr_name, ifname);
427 if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
428 ife->metric = 0;
429 else
430 ife->metric = ifr.ifr_metric;
432 strcpy(ifr.ifr_name, ifname);
433 if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
434 ife->mtu = 0;
435 else
436 ife->mtu = ifr.ifr_mtu;
438 #ifdef HAVE_HWSLIP
439 if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
440 ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
441 ife->type == ARPHRD_ADAPT) {
442 #ifdef SIOCGOUTFILL
443 strcpy(ifr.ifr_name, ifname);
444 if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
445 ife->outfill = 0;
446 else
447 ife->outfill = (unsigned int) ifr.ifr_data;
448 #endif
449 #ifdef SIOCGKEEPALIVE
450 strcpy(ifr.ifr_name, ifname);
451 if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
452 ife->keepalive = 0;
453 else
454 ife->keepalive = (unsigned int) ifr.ifr_data;
455 #endif
457 #endif
459 strcpy(ifr.ifr_name, ifname);
460 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
461 memset(&ife->map, 0, sizeof(struct ifmap));
462 else
463 memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
465 strcpy(ifr.ifr_name, ifname);
466 if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
467 memset(&ife->map, 0, sizeof(struct ifmap));
468 else
469 ife->map = ifr.ifr_map;
471 #ifdef HAVE_TXQUEUELEN
472 strcpy(ifr.ifr_name, ifname);
473 if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
474 ife->tx_queue_len = -1; /* unknown value */
475 else
476 ife->tx_queue_len = ifr.ifr_qlen;
477 #else
478 ife->tx_queue_len = -1; /* unknown value */
479 #endif
481 #if HAVE_AFINET
482 /* IPv4 address? */
483 fd = get_socket_for_af(AF_INET);
484 if (fd >= 0) {
485 strcpy(ifr.ifr_name, ifname);
486 ifr.ifr_addr.sa_family = AF_INET;
487 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
488 ife->has_ip = 1;
489 ife->addr = ifr.ifr_addr;
490 strcpy(ifr.ifr_name, ifname);
491 if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
492 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
493 else
494 ife->dstaddr = ifr.ifr_dstaddr;
496 strcpy(ifr.ifr_name, ifname);
497 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
498 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
499 else
500 ife->broadaddr = ifr.ifr_broadaddr;
502 strcpy(ifr.ifr_name, ifname);
503 if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
504 memset(&ife->netmask, 0, sizeof(struct sockaddr));
505 else
506 ife->netmask = ifr.ifr_netmask;
507 } else
508 memset(&ife->addr, 0, sizeof(struct sockaddr));
510 #endif
512 #if HAVE_AFATALK
513 /* DDP address maybe ? */
514 fd = get_socket_for_af(AF_APPLETALK);
515 if (fd >= 0) {
516 strcpy(ifr.ifr_name, ifname);
517 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
518 ife->ddpaddr = ifr.ifr_addr;
519 ife->has_ddp = 1;
522 #endif
524 #if HAVE_AFIPX
525 /* Look for IPX addresses with all framing types */
526 fd = get_socket_for_af(AF_IPX);
527 if (fd >= 0) {
528 strcpy(ifr.ifr_name, ifname);
529 if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
530 ife->has_ipx_bb = 1;
531 ife->ipxaddr_bb = ifr.ifr_addr;
533 strcpy(ifr.ifr_name, ifname);
534 if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
535 ife->has_ipx_sn = 1;
536 ife->ipxaddr_sn = ifr.ifr_addr;
538 strcpy(ifr.ifr_name, ifname);
539 if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
540 ife->has_ipx_e3 = 1;
541 ife->ipxaddr_e3 = ifr.ifr_addr;
543 strcpy(ifr.ifr_name, ifname);
544 if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
545 ife->has_ipx_e2 = 1;
546 ife->ipxaddr_e2 = ifr.ifr_addr;
549 #endif
551 #if HAVE_AFECONET
552 /* Econet address maybe? */
553 fd = get_socket_for_af(AF_ECONET);
554 if (fd >= 0) {
555 strcpy(ifr.ifr_name, ifname);
556 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
557 ife->ecaddr = ifr.ifr_addr;
558 ife->has_econet = 1;
561 #endif
563 return 0;
566 int do_if_fetch(struct interface *ife)
568 if (if_fetch(ife) < 0) {
569 char *errmsg;
570 if (errno == ENODEV) {
571 /* Give better error message for this case. */
572 errmsg = _("Device not found");
573 } else {
574 errmsg = strerror(errno);
576 fprintf(stderr, _("%s: error fetching interface information: %s\n"),
577 ife->name, errmsg);
578 return -1;
580 return 0;
583 int do_if_print(struct interface *ife, void *cookie)
585 int *opt_a = (int *) cookie;
586 int res;
588 res = do_if_fetch(ife);
589 if (res >= 0) {
590 if ((ife->flags & IFF_UP) || *opt_a)
591 ife_print(ife);
593 return res;
596 void ife_print_short(struct interface *ptr)
598 printf("%-5.5s ", ptr->name);
599 printf("%5d %-2d ", ptr->mtu, ptr->metric);
600 /* If needed, display the interface statistics. */
601 if (ptr->statistics_valid) {
602 printf("%8llu %6lu %6lu %-6lu ",
603 ptr->stats.rx_packets, ptr->stats.rx_errors,
604 ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
605 printf("%8llu %6lu %6lu %6lu ",
606 ptr->stats.tx_packets, ptr->stats.tx_errors,
607 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
608 } else {
609 printf("%-56s", _(" - no statistics available -"));
611 /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
612 if (ptr->flags == 0)
613 printf(_("[NO FLAGS]"));
614 if (ptr->flags & IFF_ALLMULTI)
615 printf("A");
616 if (ptr->flags & IFF_BROADCAST)
617 printf("B");
618 if (ptr->flags & IFF_DEBUG)
619 printf("D");
620 if (ptr->flags & IFF_LOOPBACK)
621 printf("L");
622 if (ptr->flags & IFF_MULTICAST)
623 printf("M");
624 #ifdef HAVE_DYNAMIC
625 if (ptr->flags & IFF_DYNAMIC)
626 printf("d");
627 #endif
628 if (ptr->flags & IFF_PROMISC)
629 printf("P");
630 if (ptr->flags & IFF_NOTRAILERS)
631 printf("N");
632 if (ptr->flags & IFF_NOARP)
633 printf("O");
634 if (ptr->flags & IFF_POINTOPOINT)
635 printf("P");
636 if (ptr->flags & IFF_SLAVE)
637 printf("s");
638 if (ptr->flags & IFF_MASTER)
639 printf("m");
640 if (ptr->flags & IFF_RUNNING)
641 printf("R");
642 if (ptr->flags & IFF_UP)
643 printf("U");
644 /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
645 printf("\n");
648 void ife_print_long(struct interface *ptr)
650 struct aftype *ap;
651 struct hwtype *hw;
652 int hf;
653 int can_compress = 0;
654 unsigned long long rx, tx, short_rx, short_tx;
655 const char *Rext = "b";
656 const char *Text = "b";
657 static char flags[200];
659 #if HAVE_AFIPX
660 static struct aftype *ipxtype = NULL;
661 #endif
662 #if HAVE_AFECONET
663 static struct aftype *ectype = NULL;
664 #endif
665 #if HAVE_AFATALK
666 static struct aftype *ddptype = NULL;
667 #endif
668 #if HAVE_AFINET6
669 FILE *f;
670 char addr6[40], devname[20];
671 struct sockaddr_in6 sap;
672 int plen, scope, dad_status, if_idx;
673 extern struct aftype inet6_aftype;
674 char addr6p[8][5];
675 #endif
677 ap = get_afntype(ptr->addr.sa_family);
678 if (ap == NULL)
679 ap = get_afntype(0);
681 hf = ptr->type;
683 if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
684 can_compress = 1;
686 hw = get_hwntype(hf);
687 if (hw == NULL)
688 hw = get_hwntype(-1);
690 sprintf(flags, "flags=%d<", ptr->flags);
691 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
692 if (ptr->flags == 0)
693 strcat(flags,">");
694 if (ptr->flags & IFF_UP)
695 strcat(flags,_("UP,"));
696 if (ptr->flags & IFF_BROADCAST)
697 strcat(flags,_("BROADCAST,"));
698 if (ptr->flags & IFF_DEBUG)
699 strcat(flags,_("DEBUG,"));
700 if (ptr->flags & IFF_LOOPBACK)
701 strcat(flags,_("LOOPBACK,"));
702 if (ptr->flags & IFF_POINTOPOINT)
703 strcat(flags,_("POINTOPOINT,"));
704 if (ptr->flags & IFF_NOTRAILERS)
705 strcat(flags,_("NOTRAILERS,"));
706 if (ptr->flags & IFF_RUNNING)
707 strcat(flags,_("RUNNING,"));
708 if (ptr->flags & IFF_NOARP)
709 strcat(flags,_("NOARP,"));
710 if (ptr->flags & IFF_PROMISC)
711 strcat(flags,_("PROMISC,"));
712 if (ptr->flags & IFF_ALLMULTI)
713 strcat(flags,_("ALLMULTI,"));
714 if (ptr->flags & IFF_SLAVE)
715 strcat(flags,_("SLAVE,"));
716 if (ptr->flags & IFF_MASTER)
717 strcat(flags,_("MASTER,"));
718 if (ptr->flags & IFF_MULTICAST)
719 strcat(flags,_("MULTICAST,"));
720 #ifdef HAVE_DYNAMIC
721 if (ptr->flags & IFF_DYNAMIC)
722 strcat(flags,_("DYNAMIC,"));
723 #endif
724 /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
725 if (flags[strlen(flags)-1] == ',')
726 flags[strlen(flags)-1] = '>';
727 else
728 flags[strlen(flags)-1] = 0;
731 printf(_("%s: %s mtu %d metric %d"),
732 ptr->name, flags, ptr->mtu, ptr->metric ? ptr->metric : 1);
733 #ifdef SIOCSKEEPALIVE
734 if (ptr->outfill || ptr->keepalive)
735 printf(_(" outfill %d keepalive %d"),
736 ptr->outfill, ptr->keepalive);
737 #endif
738 printf("\n");
742 #if HAVE_AFINET
743 if (ptr->has_ip) {
744 printf(_(" %s %s"), ap->name,
745 ap->sprint(&ptr->addr, 1));
746 printf(_(" netmask %s"), ap->sprint(&ptr->netmask, 1));
747 if (ptr->flags & IFF_BROADCAST) {
748 printf(_(" broadcast %s"), ap->sprint(&ptr->broadaddr, 1));
750 if (ptr->flags & IFF_POINTOPOINT) {
751 printf(_(" destination %s"), ap->sprint(&ptr->dstaddr, 1));
753 printf("\n");
755 #endif
757 #if HAVE_AFINET6
758 /* FIXME: should be integrated into interface.c. */
760 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
761 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
762 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
763 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
764 &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
765 if (!strcmp(devname, ptr->name)) {
766 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
767 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
768 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
769 inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
770 printf(_(" %s %s prefixlen %d"),
771 inet6_aftype.name,
772 inet6_aftype.sprint((struct sockaddr *) &sap, 1),
773 plen);
774 printf(_(" scopeid 0x%x"), scope);
776 flags[0] = '<'; flags[1] = 0;
777 if (scope & IPV6_ADDR_COMPATv4) {
778 strcat(flags, _("compat,"));
779 scope -= IPV6_ADDR_COMPATv4;
781 if (scope == 0)
782 strcat(flags, _("global,"));
783 if (scope & IPV6_ADDR_LINKLOCAL)
784 strcat(flags, _("link,"));
785 if (scope & IPV6_ADDR_SITELOCAL)
786 strcat(flags, _("site,"));
787 if (scope & IPV6_ADDR_LOOPBACK)
788 strcat(flags, _("host,"));
789 if (flags[strlen(flags)-1] == ',')
790 flags[strlen(flags)-1] = '>';
791 else
792 flags[strlen(flags)-1] = 0;
793 printf("%s\n", flags);
796 fclose(f);
798 #endif
800 #if HAVE_AFIPX
801 if (ipxtype == NULL)
802 ipxtype = get_afntype(AF_IPX);
804 if (ipxtype != NULL) {
805 if (ptr->has_ipx_bb)
806 printf(_(" %s Ethernet-II %s\n"),
807 ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_bb, 1));
808 if (ptr->has_ipx_sn)
809 printf(_(" %s Ethernet-SNAP %s\n"),
810 ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_sn, 1));
811 if (ptr->has_ipx_e2)
812 printf(_(" %s Ethernet802.2 %s\n"),
813 ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e2, 1));
814 if (ptr->has_ipx_e3)
815 printf(_(" %s Ethernet802.3 %s\n"),
816 ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e3, 1));
818 #endif
820 #if HAVE_AFATALK
821 if (ddptype == NULL)
822 ddptype = get_afntype(AF_APPLETALK);
823 if (ddptype != NULL) {
824 if (ptr->has_ddp)
825 printf(_(" %s %s\n"), ddptype->name, ddptype->sprint(&ptr->ddpaddr, 1));
827 #endif
829 #if HAVE_AFECONET
830 if (ectype == NULL)
831 ectype = get_afntype(AF_ECONET);
832 if (ectype != NULL) {
833 if (ptr->has_econet)
834 printf(_(" %s %s\n"), ectype->name, ectype->sprint(&ptr->ecaddr, 1));
836 #endif
838 /* For some hardware types (eg Ash, ATM) we don't print the
839 hardware address if it's null. */
840 if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
841 hw->suppress_null_addr)))
842 printf(_(" %s %s"), hw->name, hw->print(ptr->hwaddr));
843 else
844 printf(_(" %s"), hw->name);
845 if (ptr->tx_queue_len != -1)
846 printf(_(" txqueuelen %d"), ptr->tx_queue_len);
847 printf(" (%s)\n", hw->title);
849 #ifdef IFF_PORTSEL
850 if (ptr->flags & IFF_PORTSEL) {
851 printf(_(" media %s"), if_port_text[ptr->map.port][0]);
852 if (ptr->flags & IFF_AUTOMEDIA)
853 printf(_("autoselect"));
854 printf("\n");
856 #endif
859 /* If needed, display the interface statistics. */
861 if (ptr->statistics_valid) {
862 /* XXX: statistics are currently only printed for the primary address,
863 * not for the aliases, although strictly speaking they're shared
864 * by all addresses.
866 rx = ptr->stats.rx_bytes;
867 short_rx = rx * 10;
868 if (rx > 1125899906842624ull) {
869 short_rx /= 1125899906842624ull;
870 Rext = "PiB";
871 } else if (rx > 1099511627776ull) {
872 short_rx /= 1099511627776ull;
873 Rext = "TiB";
874 } else if (rx > 1073741824ull) {
875 short_rx /= 1073741824ull;
876 Rext = "GiB";
877 } else if (rx > 1048576) {
878 short_rx /= 1048576;
879 Rext = "MiB";
880 } else if (rx > 1024) {
881 short_rx /= 1024;
882 Rext = "KiB";
884 tx = ptr->stats.tx_bytes;
885 short_tx = tx * 10;
886 if (tx > 1125899906842624ull) {
887 short_tx /= 1125899906842624ull;
888 Text = "PiB";
889 } else if (tx > 1099511627776ull) {
890 short_tx /= 1099511627776ull;
891 Text = "TiB";
892 } else if (tx > 1073741824ull) {
893 short_tx /= 1073741824ull;
894 Text = "GiB";
895 } else if (tx > 1048576) {
896 short_tx /= 1048576;
897 Text = "MiB";
898 } else if (tx > 1024) {
899 short_tx /= 1024;
900 Text = "KiB";
903 printf(" ");
904 printf(_("RX packets %llu bytes %llu (%lu.%lu %s)\n"),
905 ptr->stats.rx_packets,
906 rx, (unsigned long)(short_rx / 10),
907 (unsigned long)(short_rx % 10), Rext);
908 if (can_compress) {
909 printf(" ");
910 printf(_("RX compressed:%lu\n"), ptr->stats.rx_compressed);
912 printf(" ");
913 printf(_("RX errors %lu dropped %lu overruns %lu frame %lu\n"),
914 ptr->stats.rx_errors, ptr->stats.rx_dropped,
915 ptr->stats.rx_fifo_errors, ptr->stats.rx_frame_errors);
918 printf(" ");
919 printf(_("TX packets %llu bytes %llu (%lu.%lu %s)\n"),
920 ptr->stats.tx_packets,
921 tx, (unsigned long)(short_tx / 10),
922 (unsigned long)(short_tx % 10), Text);
923 if (can_compress) {
924 printf(" ");
925 printf(_("TX compressed %lu\n"), ptr->stats.tx_compressed);
927 printf(" ");
928 printf(_("TX errors %lu dropped %lu overruns %lu carrier %lu collisions %lu\n"),
929 ptr->stats.tx_errors,
930 ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
931 ptr->stats.tx_carrier_errors, ptr->stats.collisions);
934 if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
935 ptr->map.base_addr >= 0x100)) {
936 printf(" device ");
937 if (ptr->map.irq)
938 printf(_("interrupt %d "), ptr->map.irq);
939 if (ptr->map.base_addr >= 0x100) /* Only print devices using it for
940 I/O maps */
941 printf(_("base 0x%x "), ptr->map.base_addr);
942 if (ptr->map.mem_start) {
943 printf(_("memory 0x%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end);
945 if (ptr->map.dma)
946 printf(_(" dma 0x%x"), ptr->map.dma);
947 printf("\n");
949 printf("\n");
952 void ife_print(struct interface *i)
954 if (ife_short)
955 ife_print_short(i);
956 else
957 ife_print_long(i);