enable -fno-strict-aliasing until the code base gets a hefty clean up to fix all...
[platform/upstream/net-tools.git] / lib / interface.c
1 /* Code to manipulate interface information, shared between ifconfig and
2    netstat. 
3
4    10/1998 partly rewriten by Andi Kleen to support an interface list.   
5    I don't claim that the list operations are efficient @).  
6
7    8/2000  Andi Kleen make the list operations a bit more efficient.
8    People are crazy enough to use thousands of aliases now.
9
10    $Id: interface.c,v 1.31 2009/07/08 00:24:03 ecki Exp $
11  */
12
13 #include "config.h"
14
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>
27
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
35
36 #if HAVE_AFECONET
37 #include <neteconet/ec.h>
38 #endif
39
40 #ifdef HAVE_HWSLIP
41 #include <linux/if_slip.h>
42 #include <net/if_arp.h>
43 #endif
44
45 #include "net-support.h"
46 #include "pathnames.h"
47 #include "version.h"
48 #include "proc.h"
49
50 #include "interface.h"
51 #include "sockets.h"
52 #include "util.h"
53 #include "intl.h"
54
55 #ifdef IFF_PORTSEL
56 const char *if_port_text[][4] =
57 {
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},
67 };
68 #endif
69
70 #define IPV6_ADDR_ANY           0x0000U
71
72 #define IPV6_ADDR_UNICAST       0x0001U
73 #define IPV6_ADDR_MULTICAST     0x0002U
74 #define IPV6_ADDR_ANYCAST       0x0004U
75
76 #define IPV6_ADDR_LOOPBACK      0x0010U
77 #define IPV6_ADDR_LINKLOCAL     0x0020U
78 #define IPV6_ADDR_SITELOCAL     0x0040U
79
80 #define IPV6_ADDR_COMPATv4      0x0080U
81
82 #define IPV6_ADDR_SCOPE_MASK    0x00f0U
83
84 #define IPV6_ADDR_MAPPED        0x1000U
85 #define IPV6_ADDR_RESERVED      0x2000U         /* reserved address space */
86
87 int procnetdev_vsn = 1;
88
89 int ife_short;
90
91 int if_list_all = 0;    /* do we have requested the complete proc list, yet? */
92
93 static struct interface *int_list, *int_last;
94
95 static int if_readlist_proc(char *);
96
97 static struct interface *if_cache_add(char *name)
98 {
99     struct interface *ife, **nextp, *new;
100
101     if (!int_list)
102         int_last = NULL;
103
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; 
111     }
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; 
123 }
124
125 struct interface *lookup_interface(char *name)
126 {
127    /* if we have read all, use it */
128    if (if_list_all)
129         return if_cache_add(name);
130
131    /* otherwise we read a limited list */
132    if (if_readlist_proc(name) < 0)
133         return NULL;
134  
135    return if_cache_add(name);
136 }
137
138 int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
139 {
140     struct interface *ife;
141
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;
148     }
149     return 0;
150 }
151
152 int if_cache_free(void)
153 {
154     struct interface *ife;
155     while ((ife = int_list) != NULL) {
156         int_list = ife->next;
157         free(ife);
158     }
159     int_last = NULL;
160     if_list_all = 0;
161     return 0;
162 }
163
164 static int if_readconf(void)
165 {
166     int numreqs = 30;
167     struct ifconf ifc;
168     struct ifreq *ifr;
169     int n, err = -1;
170     int skfd;
171
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;
182     }
183
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);
188
189         if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
190             perror("SIOCGIFCONF");
191             goto out;
192         }
193         if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
194             /* assume it overflowed and try again */
195             numreqs *= 2;
196             continue;
197         }
198         break;
199     }
200
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++;
205     }
206     err = 0;
207
208 out:
209     free(ifc.ifc_buf);
210     return err;
211 }
212
213 char *get_name(char *name, char *p)
214 {
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++;
229                         }
230                 } else {
231                         /* No, it isn't */
232                         p = dot;
233             }
234             p++;
235             break;
236         }
237         *name++ = *p++;
238     }
239     *name++ = '\0';
240     return p;
241 }
242
243 int procnetdev_version(char *buf)
244 {
245     if (strstr(buf, "compressed"))
246         return 3;
247     if (strstr(buf, "bytes"))
248         return 2;
249     return 1;
250 }
251
252 int get_dev_fields(char *bp, struct interface *ife)
253 {
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,
266
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,
284
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,
301
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;
312     }
313     return 0;
314 }
315
316 static int if_readlist_proc(char *target)
317 {
318     FILE *fh;
319     char buf[512];
320     struct interface *ife;
321     int err;
322
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;
328         }       
329     fgets(buf, sizeof buf, fh); /* eat line */
330     fgets(buf, sizeof buf, fh);
331
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
357
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;
367     }
368     if (ferror(fh)) {
369         perror(_PATH_PROCNET_DEV);
370         err = -1;
371     }
372
373 #if 0
374     free(fmt);
375 #endif
376     fclose(fh);
377     return err;
378 }
379
380 int if_readlist(void) 
381
382     /* caller will/should check not to call this too often 
383      *   (i.e. only if if_list_all == 0 
384      */
385     int err = 0;
386
387     err |= if_readlist_proc(NULL); 
388     err |= if_readconf();
389
390     if_list_all = 1;
391
392     return err;
393
394
395 /* Support for fetching an IPX address */
396
397 #if HAVE_AFIPX
398 static int ipx_getaddr(int sock, int ft, struct ifreq *ifr)
399 {
400     ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft;
401     return ioctl(sock, SIOCGIFADDR, ifr);
402 }
403 #endif
404
405 /* Fetch the interface configuration from the kernel. */
406 int if_fetch(struct interface *ife)
407 {
408     struct ifreq ifr;
409     int fd;
410     char *ifname = ife->name; 
411
412     strcpy(ifr.ifr_name, ifname);
413     if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
414         return (-1);
415     ife->flags = ifr.ifr_flags;
416
417     strcpy(ifr.ifr_name, ifname);
418     if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
419         memset(ife->hwaddr, 0, 32);
420     else
421         memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
422
423     ife->type = ifr.ifr_hwaddr.sa_family;
424
425     strcpy(ifr.ifr_name, ifname);
426     if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
427         ife->metric = 0;
428     else
429         ife->metric = ifr.ifr_metric;
430
431     strcpy(ifr.ifr_name, ifname);
432     if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
433         ife->mtu = 0;
434     else
435         ife->mtu = ifr.ifr_mtu;
436
437 #ifdef HAVE_HWSLIP
438     if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
439         ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
440         ife->type == ARPHRD_ADAPT) {
441 #ifdef SIOCGOUTFILL
442         strcpy(ifr.ifr_name, ifname);
443         if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
444             ife->outfill = 0;
445         else
446             ife->outfill = (unsigned int) ifr.ifr_data;
447 #endif
448 #ifdef SIOCGKEEPALIVE
449         strcpy(ifr.ifr_name, ifname);
450         if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
451             ife->keepalive = 0;
452         else
453             ife->keepalive = (unsigned int) ifr.ifr_data;
454 #endif
455     }
456 #endif
457
458     strcpy(ifr.ifr_name, ifname);
459     if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
460         memset(&ife->map, 0, sizeof(struct ifmap));
461     else
462         memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));
463
464     strcpy(ifr.ifr_name, ifname);
465     if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
466         memset(&ife->map, 0, sizeof(struct ifmap));
467     else
468         ife->map = ifr.ifr_map;
469
470 #ifdef HAVE_TXQUEUELEN
471     strcpy(ifr.ifr_name, ifname);
472     if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
473         ife->tx_queue_len = -1; /* unknown value */
474     else
475         ife->tx_queue_len = ifr.ifr_qlen;
476 #else
477     ife->tx_queue_len = -1;     /* unknown value */
478 #endif
479
480 #if HAVE_AFINET
481     /* IPv4 address? */
482     fd = get_socket_for_af(AF_INET);
483     if (fd >= 0) {
484         strcpy(ifr.ifr_name, ifname);
485         ifr.ifr_addr.sa_family = AF_INET;
486         if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
487             ife->has_ip = 1;
488             ife->addr = ifr.ifr_addr;
489             strcpy(ifr.ifr_name, ifname);
490             if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
491                 memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
492             else
493                 ife->dstaddr = ifr.ifr_dstaddr;
494
495             strcpy(ifr.ifr_name, ifname);
496             if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
497                 memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
498             else
499                 ife->broadaddr = ifr.ifr_broadaddr;
500
501             strcpy(ifr.ifr_name, ifname);
502             if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
503                 memset(&ife->netmask, 0, sizeof(struct sockaddr));
504             else
505                 ife->netmask = ifr.ifr_netmask;
506         } else
507             memset(&ife->addr, 0, sizeof(struct sockaddr));
508     }
509 #endif
510
511 #if HAVE_AFATALK
512     /* DDP address maybe ? */
513     fd = get_socket_for_af(AF_APPLETALK);
514     if (fd >= 0) {
515         strcpy(ifr.ifr_name, ifname);
516         if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
517             ife->ddpaddr = ifr.ifr_addr;
518             ife->has_ddp = 1;
519         }
520     }
521 #endif
522
523 #if HAVE_AFIPX
524     /* Look for IPX addresses with all framing types */
525     fd = get_socket_for_af(AF_IPX);
526     if (fd >= 0) {
527         strcpy(ifr.ifr_name, ifname);
528         if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
529             ife->has_ipx_bb = 1;
530             ife->ipxaddr_bb = ifr.ifr_addr;
531         }
532         strcpy(ifr.ifr_name, ifname);
533         if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
534             ife->has_ipx_sn = 1;
535             ife->ipxaddr_sn = ifr.ifr_addr;
536         }
537         strcpy(ifr.ifr_name, ifname);
538         if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
539             ife->has_ipx_e3 = 1;
540             ife->ipxaddr_e3 = ifr.ifr_addr;
541         }
542         strcpy(ifr.ifr_name, ifname);
543         if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
544             ife->has_ipx_e2 = 1;
545             ife->ipxaddr_e2 = ifr.ifr_addr;
546         }
547     }
548 #endif
549
550 #if HAVE_AFECONET
551     /* Econet address maybe? */
552     fd = get_socket_for_af(AF_ECONET);
553     if (fd >= 0) {
554         strcpy(ifr.ifr_name, ifname);
555         if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
556             ife->ecaddr = ifr.ifr_addr;
557             ife->has_econet = 1;
558         }
559     }
560 #endif
561
562     return 0;
563 }
564
565 int do_if_fetch(struct interface *ife)
566
567     if (if_fetch(ife) < 0) {
568         char *errmsg; 
569         if (errno == ENODEV) { 
570             /* Give better error message for this case. */ 
571             errmsg = _("Device not found"); 
572         } else { 
573             errmsg = strerror(errno); 
574         }
575         fprintf(stderr, _("%s: error fetching interface information: %s\n"),
576                 ife->name, errmsg);
577         return -1;
578     }
579     return 0; 
580 }
581
582 int do_if_print(struct interface *ife, void *cookie)
583 {
584     int *opt_a = (int *) cookie;
585     int res; 
586
587     res = do_if_fetch(ife); 
588     if (res >= 0) {   
589         if ((ife->flags & IFF_UP) || *opt_a)
590             ife_print(ife);
591     }
592     return res;
593 }
594
595 void ife_print_short(struct interface *ptr)
596 {
597     printf("%-5.5s ", ptr->name);
598     printf("%5d %-2d ", ptr->mtu, ptr->metric);
599     /* If needed, display the interface statistics. */
600     if (ptr->statistics_valid) {
601         printf("%8llu %6lu %6lu %-6lu ",
602                ptr->stats.rx_packets, ptr->stats.rx_errors,
603                ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
604         printf("%8llu %6lu %6lu %6lu ",
605                ptr->stats.tx_packets, ptr->stats.tx_errors,
606                ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
607     } else {
608         printf("%-56s", _("     - no statistics available -"));
609     }
610     /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
611     if (ptr->flags == 0)
612         printf(_("[NO FLAGS]"));
613     if (ptr->flags & IFF_ALLMULTI)
614         printf("A");
615     if (ptr->flags & IFF_BROADCAST)
616         printf("B");
617     if (ptr->flags & IFF_DEBUG)
618         printf("D");
619     if (ptr->flags & IFF_LOOPBACK)
620         printf("L");
621     if (ptr->flags & IFF_MULTICAST)
622         printf("M");
623 #ifdef HAVE_DYNAMIC
624     if (ptr->flags & IFF_DYNAMIC)
625         printf("d");
626 #endif
627     if (ptr->flags & IFF_PROMISC)
628         printf("P");
629     if (ptr->flags & IFF_NOTRAILERS)
630         printf("N");
631     if (ptr->flags & IFF_NOARP)
632         printf("O");
633     if (ptr->flags & IFF_POINTOPOINT)
634         printf("P");
635     if (ptr->flags & IFF_SLAVE)
636         printf("s");
637     if (ptr->flags & IFF_MASTER)
638         printf("m");
639     if (ptr->flags & IFF_RUNNING)
640         printf("R");
641     if (ptr->flags & IFF_UP)
642         printf("U");
643     /* DONT FORGET TO ADD THE FLAGS IN ife_print_long, too */
644     printf("\n");
645 }
646
647 void ife_print_long(struct interface *ptr)
648 {
649     struct aftype *ap;
650     struct hwtype *hw;
651     int hf;
652     int can_compress = 0;
653     unsigned long long rx, tx, short_rx, short_tx;
654     const char *Rext = "B";
655     const char *Text = "B";
656     static char flags[200];
657     
658 #if HAVE_AFIPX
659     static struct aftype *ipxtype = NULL;
660 #endif
661 #if HAVE_AFECONET
662     static struct aftype *ectype = NULL;
663 #endif
664 #if HAVE_AFATALK
665     static struct aftype *ddptype = NULL;
666 #endif
667 #if HAVE_AFINET6
668     FILE *f;
669     char addr6[40], devname[21];
670     struct sockaddr_in6 sap;
671     int plen, scope, dad_status, if_idx;
672     extern struct aftype inet6_aftype;
673     char addr6p[8][5];
674 #endif
675
676     ap = get_afntype(ptr->addr.sa_family);
677     if (ap == NULL)
678         ap = get_afntype(0);
679
680     hf = ptr->type;
681
682     if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
683         can_compress = 1;
684
685     hw = get_hwntype(hf);
686     if (hw == NULL)
687         hw = get_hwntype(-1);
688
689     sprintf(flags, "flags=%d<", ptr->flags);
690     /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
691     if (ptr->flags == 0)
692         strcat(flags,">");
693     if (ptr->flags & IFF_UP)
694         strcat(flags,_("UP,"));
695     if (ptr->flags & IFF_BROADCAST)
696         strcat(flags,_("BROADCAST,"));
697     if (ptr->flags & IFF_DEBUG)
698         strcat(flags,_("DEBUG,"));
699     if (ptr->flags & IFF_LOOPBACK)
700         strcat(flags,_("LOOPBACK,"));
701     if (ptr->flags & IFF_POINTOPOINT)
702         strcat(flags,_("POINTOPOINT,"));
703     if (ptr->flags & IFF_NOTRAILERS)
704         strcat(flags,_("NOTRAILERS,"));
705     if (ptr->flags & IFF_RUNNING)
706         strcat(flags,_("RUNNING,"));
707     if (ptr->flags & IFF_NOARP)
708         strcat(flags,_("NOARP,"));
709     if (ptr->flags & IFF_PROMISC)
710         strcat(flags,_("PROMISC,"));
711     if (ptr->flags & IFF_ALLMULTI)
712         strcat(flags,_("ALLMULTI,"));
713     if (ptr->flags & IFF_SLAVE)
714         strcat(flags,_("SLAVE,"));
715     if (ptr->flags & IFF_MASTER)
716         strcat(flags,_("MASTER,"));
717     if (ptr->flags & IFF_MULTICAST)
718         strcat(flags,_("MULTICAST,"));
719 #ifdef HAVE_DYNAMIC
720     if (ptr->flags & IFF_DYNAMIC)
721         strcat(flags,_("DYNAMIC,"));
722 #endif
723     /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
724     if (flags[strlen(flags)-1] == ',')
725       flags[strlen(flags)-1] = '>';
726     else
727       flags[strlen(flags)-1] = 0;
728       
729
730     printf(_("%s: %s  mtu %d  metric %d"),
731            ptr->name, flags, ptr->mtu, ptr->metric ? ptr->metric : 1);
732 #ifdef SIOCSKEEPALIVE
733     if (ptr->outfill || ptr->keepalive)
734         printf(_("  outfill %d  keepalive %d"),
735                ptr->outfill, ptr->keepalive);
736 #endif
737     printf("\n");
738
739
740
741 #if HAVE_AFINET
742     if (ptr->has_ip) {
743         printf(_("        %s %s"), ap->name,
744                ap->sprint(&ptr->addr, 1));
745         printf(_("  netmask %s"), ap->sprint(&ptr->netmask, 1));
746         if (ptr->flags & IFF_BROADCAST) {
747             printf(_("  broadcast %s"), ap->sprint(&ptr->broadaddr, 1));
748         }
749         if (ptr->flags & IFF_POINTOPOINT) {
750             printf(_("  destination %s"), ap->sprint(&ptr->dstaddr, 1));
751         }
752         printf("\n");
753     }
754 #endif
755
756 #if HAVE_AFINET6
757     /* FIXME: should be integrated into interface.c.   */
758
759     if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
760         while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
761                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
762                       addr6p[4], addr6p[5], addr6p[6], addr6p[7],
763                   &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
764             if (!strcmp(devname, ptr->name)) {
765                 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
766                         addr6p[0], addr6p[1], addr6p[2], addr6p[3],
767                         addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
768                 inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
769                 printf(_("        %s %s  prefixlen %d"),
770                         inet6_aftype.name, 
771                         inet6_aftype.sprint((struct sockaddr *) &sap, 1), 
772                         plen);
773                 printf(_("  scopeid 0x%x"), scope);
774
775                 flags[0] = '<'; flags[1] = 0;
776                 if (scope & IPV6_ADDR_COMPATv4) {
777                         strcat(flags, _("compat,"));
778                         scope -= IPV6_ADDR_COMPATv4;
779                 }
780                 if (scope == 0)
781                         strcat(flags, _("global,"));
782                 if (scope & IPV6_ADDR_LINKLOCAL)
783                         strcat(flags, _("link,"));
784                 if (scope & IPV6_ADDR_SITELOCAL)
785                         strcat(flags, _("site,"));
786                 if (scope & IPV6_ADDR_LOOPBACK)
787                         strcat(flags, _("host,"));
788                 if (flags[strlen(flags)-1] == ',')
789                         flags[strlen(flags)-1] = '>';
790                 else
791                         flags[strlen(flags)-1] = 0;
792                 printf("%s\n", flags);
793             }
794         }
795         fclose(f);
796     }
797 #endif
798
799 #if HAVE_AFIPX
800     if (ipxtype == NULL)
801         ipxtype = get_afntype(AF_IPX);
802
803     if (ipxtype != NULL) {
804         if (ptr->has_ipx_bb)
805             printf(_("        %s Ethernet-II   %s\n"),
806                    ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_bb, 1));
807         if (ptr->has_ipx_sn)
808             printf(_("        %s Ethernet-SNAP %s\n"),
809                    ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_sn, 1));
810         if (ptr->has_ipx_e2)
811             printf(_("        %s Ethernet802.2 %s\n"),
812                    ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e2, 1));
813         if (ptr->has_ipx_e3)
814             printf(_("        %s Ethernet802.3 %s\n"),
815                    ipxtype->name, ipxtype->sprint(&ptr->ipxaddr_e3, 1));
816     }
817 #endif
818
819 #if HAVE_AFATALK
820     if (ddptype == NULL)
821         ddptype = get_afntype(AF_APPLETALK);
822     if (ddptype != NULL) {
823         if (ptr->has_ddp)
824             printf(_("        %s %s\n"), ddptype->name, ddptype->sprint(&ptr->ddpaddr, 1));
825     }
826 #endif
827
828 #if HAVE_AFECONET
829     if (ectype == NULL)
830         ectype = get_afntype(AF_ECONET);
831     if (ectype != NULL) {
832         if (ptr->has_econet)
833             printf(_("        %s %s\n"), ectype->name, ectype->sprint(&ptr->ecaddr, 1));
834     }
835 #endif
836
837     /* For some hardware types (eg Ash, ATM) we don't print the 
838        hardware address if it's null.  */
839     if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) &&
840                                   hw->suppress_null_addr)))
841         printf(_("        %s %s"), hw->name, hw->print(ptr->hwaddr));
842     else
843         printf(_("        %s"), hw->name);
844     if (ptr->tx_queue_len != -1)
845         printf(_("  txqueuelen %d"), ptr->tx_queue_len);
846     printf("  (%s)\n", hw->title);
847
848 #ifdef IFF_PORTSEL
849     if (ptr->flags & IFF_PORTSEL) {
850         printf(_("        media %s"), if_port_text[ptr->map.port][0]);
851         if (ptr->flags & IFF_AUTOMEDIA)
852             printf(_("autoselect"));
853         printf("\n");
854     }
855 #endif
856
857
858     /* If needed, display the interface statistics. */
859
860     if (ptr->statistics_valid) {
861         /* XXX: statistics are currently only printed for the primary address,
862          *      not for the aliases, although strictly speaking they're shared
863          *      by all addresses.
864          */
865         rx = ptr->stats.rx_bytes;  
866         short_rx = rx * 10;  
867         if (rx > 1125899906842624ull) {
868             short_rx /= 1125899906842624ull;
869             Rext = "PiB";
870         } else if (rx > 1099511627776ull) {
871             short_rx /= 1099511627776ull;
872             Rext = "TiB";
873         } else if (rx > 1073741824ull) {
874             short_rx /= 1073741824ull;
875             Rext = "GiB";
876         } else if (rx > 1048576) {
877             short_rx /= 1048576;
878             Rext = "MiB";
879         } else if (rx > 1024) {
880             short_rx /= 1024;
881             Rext = "KiB";
882         }
883         tx = ptr->stats.tx_bytes;
884         short_tx = tx * 10;
885         if (tx > 1125899906842624ull) {
886             short_tx /= 1125899906842624ull;
887             Text = "PiB";
888         } else  if (tx > 1099511627776ull) {
889             short_tx /= 1099511627776ull;
890             Text = "TiB";
891         } else if (tx > 1073741824ull) {
892             short_tx /= 1073741824ull;
893             Text = "GiB";
894         } else if (tx > 1048576) {
895             short_tx /= 1048576;
896             Text = "MiB";
897         } else if (tx > 1024) {
898             short_tx /= 1024;
899             Text = "KiB";
900         }
901
902         printf("        ");
903         printf(_("RX packets %llu  bytes %llu (%lu.%lu %s)\n"), 
904                 ptr->stats.rx_packets, 
905                rx, (unsigned long)(short_rx / 10), 
906                (unsigned long)(short_rx % 10), Rext);
907         if (can_compress) {
908             printf("        ");
909             printf(_("RX compressed:%lu\n"), ptr->stats.rx_compressed);
910         }
911         printf("        ");
912         printf(_("RX errors %lu  dropped %lu  overruns %lu  frame %lu\n"),
913                ptr->stats.rx_errors, ptr->stats.rx_dropped, 
914                ptr->stats.rx_fifo_errors, ptr->stats.rx_frame_errors);
915
916
917         printf("        ");
918         printf(_("TX packets %llu  bytes %llu (%lu.%lu %s)\n"),
919                 ptr->stats.tx_packets, 
920                 tx, (unsigned long)(short_tx / 10), 
921                 (unsigned long)(short_tx % 10), Text);
922         if (can_compress) {
923             printf("        ");
924             printf(_("TX compressed %lu\n"), ptr->stats.tx_compressed);
925         }
926         printf("        ");
927         printf(_("TX errors %lu  dropped %lu overruns %lu  carrier %lu  collisions %lu\n"),
928                ptr->stats.tx_errors,
929                ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
930                ptr->stats.tx_carrier_errors, ptr->stats.collisions);
931     }
932
933     if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
934          ptr->map.base_addr >= 0x100)) {
935         printf("        device ");
936         if (ptr->map.irq)
937             printf(_("interrupt %d  "), ptr->map.irq);
938         if (ptr->map.base_addr >= 0x100)        /* Only print devices using it for 
939                                                    I/O maps */
940             printf(_("base 0x%x  "), ptr->map.base_addr);
941         if (ptr->map.mem_start) {
942             printf(_("memory 0x%lx-%lx  "), ptr->map.mem_start, ptr->map.mem_end);
943         }
944         if (ptr->map.dma)
945             printf(_("  dma 0x%x"), ptr->map.dma);
946         printf("\n");
947     }
948     printf("\n");
949 }
950
951 void ife_print(struct interface *i)
952 {
953     if (ife_short)
954         ife_print_short(i);
955     else
956         ife_print_long(i);
957 }