Merge branch 'vendor/EE'
[dragonfly.git] / usr.sbin / gifconfig / gifconfig.c
1 /*      $FreeBSD: src/usr.sbin/gifconfig/gifconfig.c,v 1.2.2.4 2002/08/30 14:23:39 sobomax Exp $        */
2 /*      $KAME: gifconfig.c,v 1.14 2001/01/01 04:04:56 jinmei Exp $      */
3
4 /*
5  * Copyright (c) 1983, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * gifconfig, derived from ifconfig
35  *
36  * @(#) Copyright (c) 1983, 1993\n\
37  *      The Regents of the University of California.  All rights reserved.\n
38  *
39  * @(#)ifconfig.c       8.2 (Berkeley) 2/16/94
40  */
41
42 /*
43  *  951109 - Andrew@pubnix.net - Changed to iterative buffer growing mechanism
44  *                               for ifconfig -a so all interfaces are queried.
45  *
46  *  960101 - peter@freebsd.org - Blow away the SIOCGIFCONF code and use
47  *                               sysctl() to get the structured interface conf
48  *                               and parse the messages in there. REALLY UGLY!
49  */
50
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 #include <sys/sysctl.h>
55
56 #include <net/if.h>
57 #if defined(__DragonFly__)
58 #include <net/if_var.h>
59 #endif /* __DragonFly__ */
60 #include <net/if_dl.h>
61 #include <net/if_types.h>
62 #include <net/route.h>
63 #include <netinet/in.h>
64 #include <netinet/in_var.h>
65 #include <arpa/inet.h>
66 #include <netdb.h>
67
68 #include <sys/protosw.h>
69
70 #include <ctype.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <unistd.h>
77 #include <nlist.h>
78 #include <kvm.h>
79 #include <fcntl.h>
80
81 struct  ifreq           ifr;
82 struct  ifaliasreq      addreq;
83 #ifdef INET6
84 struct  in6_ifreq       in6_ifr;
85 struct  in6_aliasreq    in6_addreq;
86 #endif
87
88 char    name[32];
89 int     flags;
90 int     metric;
91 int     mtu;
92 int     setpsrc = 0;
93 int     newaddr = 0;
94 int     s;
95 kvm_t   *kvmd;
96
97 #ifdef INET6
98 char ntop_buf[INET6_ADDRSTRLEN];        /*inet_ntop()*/
99 #endif
100
101 void setifpsrc(char *, int);
102 void setifpdst(char *, int);
103 void setifflags(char *, int);
104 #ifdef SIOCDIFPHYADDR
105 void delifaddrs(char *, int);
106 #endif
107
108 #define NEXTARG         0xffffff
109
110 static struct   cmd {
111         char    *c_name;
112         int     c_parameter;            /* NEXTARG means next argv */
113         void    (*c_func)(char *, int);
114 } cmds[] = {
115         { "up",         IFF_UP,         setifflags } ,
116         { "down",       -IFF_UP,        setifflags },
117 #ifdef SIOCDIFPHYADDR
118         { "delete",     0,              delifaddrs },
119 #endif
120         { 0,            0,              setifpsrc },
121         { 0,            0,              setifpdst },
122 };
123
124 /*
125  * XNS support liberally adapted from code written at the University of
126  * Maryland principally by James O'Toole and Chris Torek.
127  */
128 void status(void);
129 void phys_status(int);
130 void in_status(int);
131 #ifdef INET6
132 void in6_status(int);
133 #endif
134 void ether_status(int);
135 void Perror(char *);
136 void in_getaddr(char *, int);
137 #ifdef INET6
138 void in6_getaddr(char *, int);
139 void in6_getprefix(char *, int);
140 #endif
141 void printb(char *, unsigned int, char *);
142 int prefix(void *, int);
143
144 char ntop_buf[INET6_ADDRSTRLEN];
145
146 /* Known address families */
147 struct afswtch {
148         char *af_name;
149         short af_af;
150         void (*af_status)(int);
151         void (*af_getaddr)(char *, int);
152         void (*af_getprefix)(char *, int);
153         u_long af_pifaddr;
154         caddr_t af_addreq;
155         caddr_t af_req;
156 } afs[] = {
157 #define C(x) ((caddr_t) &x)
158         { "inet", AF_INET, in_status, in_getaddr, 0,
159              SIOCSIFPHYADDR, C(addreq), C(ifr) },
160 #ifdef INET6
161         { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
162              SIOCSIFPHYADDR_IN6, C(in6_addreq), C(in6_ifr) },
163 #endif
164         { "ether", AF_INET, ether_status, NULL, NULL }, /* XXX not real!! */
165         { 0,    0,          0,          0,      0 }
166 };
167
168 struct afswtch *afp = NULL;     /*the address family being set or asked about*/
169
170 void    rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
171 int     ifconfig(int argc, char *argv[], int af, struct afswtch *rafp);
172
173
174
175 /*
176  * Expand the compacted form of addresses as returned via the
177  * configuration read via sysctl().
178  */
179
180 #define ROUNDUP(a) \
181         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
182 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
183
184 void
185 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
186 {
187         struct sockaddr *sa;
188         int i;
189
190         memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
191         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
192                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
193                         continue;
194                 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
195                 ADVANCE(cp, sa);
196         }
197 }
198
199
200 /*
201  * Grunge for new-style sysctl() decoding.. :-(
202  * Apologies to the world for committing gross things like this in 1996..
203  */
204 struct if_msghdr *ifm;
205 struct ifa_msghdr *ifam;
206 struct sockaddr_dl *sdl;
207 struct rt_addrinfo info;
208 char *buf, *lim, *next;
209
210
211 int
212 main(int argc, char **argv)
213 {
214         int af = AF_INET;
215         struct afswtch *rafp = NULL;
216         size_t needed;
217         int mib[6];
218         int all;
219
220         if (argc < 2) {
221                 fprintf(stderr,
222                     "usage: gifconfig interface [af] [physsrc physdst]\n");
223 #ifdef SIOCDIFPHYADDR
224                 fprintf(stderr,
225                     "       gifconfig interface delete\n");
226 #endif
227                 fprintf(stderr,
228                     "       gifconfig -a\n");
229                 exit(1);
230         }
231         argc--, argv++;
232         strncpy(name, *argv, sizeof(name));
233         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
234         argc--, argv++;
235         if (argc > 0) {
236                 for (afp = rafp = afs; rafp->af_name; rafp++)
237                         if (strcmp(rafp->af_name, *argv) == 0) {
238                                 afp = rafp; argc--; argv++;
239                                 break;
240                         }
241                 rafp = afp;
242                 af = ifr.ifr_addr.sa_family = rafp->af_af;
243         }
244
245         mib[0] = CTL_NET;
246         mib[1] = PF_ROUTE;
247         mib[2] = 0;
248         mib[3] = 0;     /* address family */
249         mib[4] = NET_RT_IFLIST;
250         mib[5] = 0;
251
252         /* if particular family specified, only ask about it */
253         if (afp) {
254                 mib[3] = afp->af_af;
255         }
256
257         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
258                 errx(1, "iflist-sysctl-estimate");
259         if ((buf = malloc(needed)) == NULL)
260                 errx(1, "malloc");
261         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
262                 errx(1, "actual retrieval of interface table");
263         lim = buf + needed;
264
265         all = 0;
266         if (strcmp(name, "-a") == 0)
267                 all = 1;        /* All interfaces */
268         else if (strcmp(name, "-au") == 0)
269                 all = 2;        /* All IFF_UPinterfaces */
270         else if (strcmp(name, "-ad") == 0)
271                 all = 3;        /* All !IFF_UP interfaces */
272
273         for (next = buf; next < lim; next += ifm->ifm_msglen) {
274
275                 ifm = (struct if_msghdr *)next;
276
277                 /* XXX: Swallow up leftover NEWADDR messages */
278                 if (ifm->ifm_type == RTM_NEWADDR)
279                         continue;
280
281                 if (ifm->ifm_type == RTM_IFINFO) {
282                         sdl = (struct sockaddr_dl *)(ifm + 1);
283                         flags = ifm->ifm_flags;
284                 } else {
285                         errx(1, "out of sync parsing NET_RT_IFLIST");
286                 }
287
288                 switch(all) {
289                 case -1:
290                 case 0:
291                         if (strlen(name) != sdl->sdl_nlen)
292                                 continue; /* not same len */
293                         if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
294                                 continue; /* not same name */
295                         break;
296                 case 1:
297                         break;  /* always do it */
298                 case 2:
299                         if ((flags & IFF_UP) == 0)
300                                 continue; /* not up */
301                         break;
302                 case 3:
303                         if (flags & IFF_UP)
304                                 continue; /* not down */
305                         break;
306                 }
307
308                 /*
309                  * Let's just do it for gif only
310                  */
311                 if (sdl->sdl_type != IFT_GIF) {
312                         if (all != 0)
313                                 continue;
314
315                         fprintf(stderr, "gifconfig: %s is not gif.\n",
316                                 ifr.ifr_name);
317                         exit(1);
318                 }
319
320                 if (all > 0) {
321                         strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
322                         name[sdl->sdl_nlen] = '\0';
323                 }
324
325                 if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
326                         perror("gifconfig: socket");
327                         exit(1);
328                 }
329
330                 ifconfig(argc,argv,af,rafp);
331
332                 close(s);
333
334                 if (all == 0) {
335                         all = -1; /* flag it as 'done' */
336                         break;
337                 }
338         }
339         free(buf);
340
341         if (all == 0)
342                 errx(1, "interface %s does not exist", name);
343         
344
345         exit (0);
346 }
347
348
349 int
350 ifconfig(int argc, char **argv, int af, struct afswtch *rafp)
351 {
352
353         af = 0;         /*fool gcc*/
354
355         strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
356 #ifdef INET6
357         strncpy(in6_ifr.ifr_name, name, sizeof in6_ifr.ifr_name);
358 #endif /* INET6 */
359
360         if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
361                 perror("ioctl (SIOCGIFMETRIC)");
362         else
363                 metric = ifr.ifr_metric;
364
365 #if defined(SIOCGIFMTU) && !defined(__OpenBSD__)
366         if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
367                 perror("ioctl (SIOCGIFMTU)");
368         else
369                 mtu = ifr.ifr_mtu;
370 #else
371         mtu = 0;
372 #endif
373
374         if (argc == 0) {
375                 status();
376                 return(0);
377         }
378
379         while (argc > 0) {
380                 struct cmd *p;
381
382                 for (p = cmds; p->c_name; p++)
383                         if (strcmp(*argv, p->c_name) == 0)
384                                 break;
385                 if (p->c_name == NULL && setpsrc)
386                         p++;    /* got src, do dst */
387                 if (p->c_func) {
388                         if (p->c_parameter == NEXTARG) {
389                                 if (argv[1] == NULL)
390                                         errx(1, "'%s' requires argument",
391                                             p->c_name);
392                                 (*p->c_func)(argv[1], 0);
393                                 argc--, argv++;
394                         } else
395                                 (*p->c_func)(*argv, p->c_parameter);
396                 }
397                 argc--, argv++;
398         }
399         if (newaddr) {
400                 strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
401                 if (ioctl(s, rafp->af_pifaddr, rafp->af_addreq) < 0)
402                         Perror("ioctl (SIOCSIFPHYADDR)");
403         }
404         else if (setpsrc) {
405                 errx(1, "destination is not specified");
406         }
407         return(0);
408 }
409 #define PSRC    0
410 #define PDST    1
411
412 /*ARGSUSED*/
413 void
414 setifpsrc(char *addr, int param)
415 {
416         param = 0;      /*fool gcc*/
417         (*afp->af_getaddr)(addr, PSRC);
418         setpsrc = 1;
419 }
420
421 /*ARGSUSED*/
422 void
423 setifpdst(char *addr, int param)
424 {
425         param = 0;      /*fool gcc*/
426         (*afp->af_getaddr)(addr, PDST);
427         newaddr = 1;
428 }
429
430 void
431 setifflags(char *vname, int value)
432 {
433         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
434                 Perror("ioctl (SIOCGIFFLAGS)");
435                 exit(1);
436         }
437         strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
438         flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
439
440         if (value < 0) {
441                 value = -value;
442                 flags &= ~value;
443         } else
444                 flags |= value;
445         ifr.ifr_flags = flags & 0xffff;
446         ifr.ifr_flagshigh = flags >> 16;
447         if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
448                 Perror(vname);
449 }
450
451 #ifdef SIOCDIFPHYADDR
452 /* ARGSUSED */
453 void
454 delifaddrs(char *vname, int param)
455 {
456         param = 0;              /* fool gcc */
457         vname = NULL;           /* ditto */
458
459         if (ioctl(s, SIOCDIFPHYADDR, (caddr_t)&ifr) < 0)
460                 err(1, "ioctl(SIOCDIFPHYADDR)");
461 }
462 #endif
463
464 #define IFFBITS \
465 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
466 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
467
468 /*
469  * Print the status of the interface.  If an address family was
470  * specified, show it and it only; otherwise, show them all.
471  */
472 void
473 status(void)
474 {
475         struct afswtch *p = NULL;
476         char *mynext;
477         struct if_msghdr *myifm;
478
479         printf("%s: ", name);
480         printb("flags", flags, IFFBITS);
481         if (metric)
482                 printf(" metric %d", metric);
483         if (mtu)
484                 printf(" mtu %d", mtu);
485         putchar('\n');
486
487         /*
488          * XXX: Sigh. This is bad, I know.  At this point, we may have
489          * *zero* RTM_NEWADDR's, so we have to "feel the water" before
490          * incrementing the loop.  One day, I might feel inspired enough
491          * to get the top level loop to pass a count down here so we
492          * dont have to mess with this.  -Peter
493          */
494         myifm = ifm;
495
496         while (1) {
497
498                 mynext = next + ifm->ifm_msglen;
499
500                 if (mynext >= lim)
501                         break;
502
503                 myifm = (struct if_msghdr *)mynext;
504
505                 if (myifm->ifm_type != RTM_NEWADDR)
506                         break;
507
508                 next = mynext;
509
510                 ifm = (struct if_msghdr *)next;
511
512                 ifam = (struct ifa_msghdr *)myifm;
513                 info.rti_addrs = ifam->ifam_addrs;
514
515                 /* Expand the compacted addresses */
516                 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
517                           &info);
518
519                 if (afp) {
520                         if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
521                             afp->af_status != ether_status) {
522                                 p = afp;
523                                 if (p->af_status != ether_status)
524                                         (*p->af_status)(1);
525                         }
526                 } else for (p = afs; p->af_name; p++) {
527                         if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
528                             p->af_status != ether_status)
529                                 (*p->af_status)(0);
530                 }
531         }
532         if (afp == NULL || afp->af_status == ether_status)
533                 ether_status(0);
534         else if (afp && !p) {
535                 warnx("%s has no %s IFA address!", name, afp->af_name);
536         }
537
538         phys_status(0);
539 }
540
541 void
542 phys_status(int force)
543 {
544         char psrcaddr[256];
545         char pdstaddr[256];
546         int flags = NI_NUMERICHOST;
547         char *af;
548 #ifndef SIOCGLIFPHYADDR
549         u_long srccmd, dstcmd;
550         struct ifreq *ifrp;
551 #ifdef INET6
552         int s6;
553 #endif
554
555         force = 0;      /*fool gcc*/
556
557         psrcaddr[0] = pdstaddr[0] = '\0';
558
559 #ifdef INET6
560         s6 = socket(AF_INET6, SOCK_DGRAM, 0);
561         if (s6 < 0) {
562                 ifrp = &ifr;
563                 srccmd = SIOCGIFPSRCADDR;
564                 dstcmd = SIOCGIFPDSTADDR;
565         } else {
566                 close(s6);
567                 srccmd = SIOCGIFPSRCADDR_IN6;
568                 dstcmd = SIOCGIFPDSTADDR_IN6;
569                 ifrp = (struct ifreq *)&in6_ifr;
570         }
571 #else /* INET6 */
572         ifrp = &ifr;
573         srccmd = SIOCGIFPSRCADDR;
574         dstcmd = SIOCGIFPDSTADDR;
575 #endif /* INET6 */
576
577         if (0 <= ioctl(s, srccmd, (caddr_t)ifrp)) {
578 #ifdef INET6
579                 if (ifrp->ifr_addr.sa_family == AF_INET6)
580                         af = "inet6";
581                 else
582                         af = "inet";
583 #else
584                 af = "inet";
585 #endif /* INET6 */
586                 if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
587                     psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0)
588                         psrcaddr[0] = '\0';
589         }
590         if (0 <= ioctl(s, dstcmd, (caddr_t)ifrp)) {
591                 if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
592                     pdstaddr, sizeof(pdstaddr), 0, 0, flags) != 0)
593                         pdstaddr[0] = '\0';
594         }
595         printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr);
596 #else
597         struct if_laddrreq iflr;
598
599         force = 0;      /*fool gcc*/
600
601         psrcaddr[0] = pdstaddr[0] = '\0';
602
603         memset(&iflr, 0, sizeof(iflr));
604         memcpy(iflr.iflr_name, ifr.ifr_name, sizeof(iflr.iflr_name));
605
606         if (0 <= ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&iflr)) {
607                 switch (iflr.addr.ss_family) {
608                 case AF_INET:
609                         af = "inet";
610                         break;
611 #ifdef INET6
612                 case AF_INET6:
613                         af = "inet6";
614                         break;
615 #endif /* INET6 */
616                 }
617                 if (getnameinfo((struct sockaddr *)&iflr.addr, iflr.addr.ss_len,
618                     psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0)
619                         psrcaddr[0] = '\0';
620                 if (getnameinfo((struct sockaddr *)&iflr.dstaddr,
621                     iflr.dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), 0, 0,
622                     flags) != 0)
623                         pdstaddr[0] = '\0';
624         }
625         printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr);
626 #endif
627 }
628
629 void
630 in_status(int force)
631 {
632         struct sockaddr_in *sin, null_sin;
633 #if 0
634         char *inet_ntoa();
635 #endif
636         
637         memset(&null_sin, 0, sizeof(null_sin));
638
639         sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
640         if (!sin || sin->sin_family != AF_INET) {
641                 if (!force)
642                         return;
643                 /* warnx("%s has no AF_INET IFA address!", name); */
644                 sin = &null_sin;
645         }
646         printf("\tinet %s ", inet_ntoa(sin->sin_addr));
647
648         if (flags & IFF_POINTOPOINT) {
649                 /* note RTAX_BRD overlap with IFF_BROADCAST */
650                 sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
651                 if (!sin)
652                         sin = &null_sin;
653                 printf("--> %s ", inet_ntoa(sin->sin_addr));
654         }
655
656         sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
657         if (!sin)
658                 sin = &null_sin;
659         printf("netmask 0x%x ", (u_int32_t)ntohl(sin->sin_addr.s_addr));
660
661         if (flags & IFF_BROADCAST) {
662                 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
663                 sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
664                 if (sin && sin->sin_addr.s_addr != 0)
665                         printf("broadcast %s", inet_ntoa(sin->sin_addr));
666         }
667         putchar('\n');
668 }
669
670 #ifdef INET6
671 void
672 in6_status(int force)
673 {
674         struct sockaddr_in6 *sin, null_sin;
675         char hostname[NI_MAXHOST];
676         int niflags = NI_NUMERICHOST;
677
678         memset(&null_sin, 0, sizeof(null_sin));
679 #ifdef NI_WITHSCOPEID
680         niflags |= NI_WITHSCOPEID;
681 #endif
682
683         sin = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA];
684         if (!sin || sin->sin6_family != AF_INET6) {
685                 if (!force)
686                         return;
687                 /* warnx("%s has no AF_INET6 IFA address!", name); */
688                 sin = &null_sin;
689         }
690 #ifdef __KAME__
691         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
692                 sin->sin6_scope_id =
693                         ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]);
694                 sin->sin6_addr.s6_addr[2] = 0;
695                 sin->sin6_addr.s6_addr[3] = 0;
696         }
697 #endif
698         getnameinfo((struct sockaddr *)sin, sin->sin6_len,
699                     hostname, sizeof(hostname), 0, 0, niflags);
700         printf("\tinet6 %s ", hostname);
701
702         if (flags & IFF_POINTOPOINT) {
703                 /* note RTAX_BRD overlap with IFF_BROADCAST */
704                 sin = (struct sockaddr_in6 *)info.rti_info[RTAX_BRD];
705                 /*
706                  * some of ther interfaces do not have valid destination
707                  * address.
708                  */
709                 if (sin->sin6_family == AF_INET6) {
710 #ifdef __KAME__
711                         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
712                                 sin->sin6_scope_id =
713                                         ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]);
714                                 sin->sin6_addr.s6_addr[2] = 0;
715                                 sin->sin6_addr.s6_addr[3] = 0;
716                         }
717 #endif
718                         getnameinfo((struct sockaddr *)sin, sin->sin6_len,
719                                     hostname, sizeof(hostname), 0, 0, niflags);
720                         printf("--> %s ", hostname);
721                 }
722         }
723
724         sin = (struct sockaddr_in6 *)info.rti_info[RTAX_NETMASK];
725         if (!sin)
726                 sin = &null_sin;
727         printf(" prefixlen %d ", prefix(&sin->sin6_addr,
728                 sizeof(struct in6_addr)));
729
730         putchar('\n');
731 }
732 #endif /*INET6*/
733
734 /*ARGSUSED*/
735 void
736 ether_status(int dummy)
737 {
738         char *cp;
739         int n;
740
741         dummy = 0;      /*fool gcc*/
742
743         cp = (char *)LLADDR(sdl);
744         if ((n = sdl->sdl_alen) > 0) {
745                 if (sdl->sdl_type == IFT_ETHER)
746                         printf ("\tether ");
747                 else
748                         printf ("\tlladdr ");
749                 while (--n >= 0)
750                         printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
751                 putchar('\n');
752         }
753 }
754
755 void
756 Perror(char *cmd)
757 {
758         switch (errno) {
759
760         case ENXIO:
761                 errx(1, "%s: no such interface", cmd);
762                 break;
763
764         case EPERM:
765                 errx(1, "%s: permission denied", cmd);
766                 break;
767
768         default:
769                 err(1, "%s", cmd);
770         }
771 }
772
773 #define SIN(x) ((struct sockaddr_in *) &(x))
774 struct sockaddr_in *sintab[] = {
775 SIN(addreq.ifra_addr), SIN(addreq.ifra_dstaddr)};
776
777 void
778 in_getaddr(char *s, int which)
779 {
780         struct sockaddr_in *sin = sintab[which];
781         struct hostent *hp;
782         struct netent *np;
783
784         sin->sin_len = sizeof(*sin);
785         sin->sin_family = AF_INET;
786
787         if (inet_aton(s, &sin->sin_addr))
788                 ;
789         else if ((hp = gethostbyname(s)) != NULL)
790                 bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
791         else if ((np = getnetbyname(s)) != NULL)
792                 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
793         else
794                 errx(1, "%s: bad value", s);
795 }
796
797 #ifdef INET6
798 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
799 struct sockaddr_in6 *sin6tab[] = {
800 SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_dstaddr)};
801
802 void
803 in6_getaddr(char *s, int which)
804 {
805         struct sockaddr_in6 *sin = sin6tab[which];
806
807         sin->sin6_len = sizeof(*sin);
808         sin->sin6_family = AF_INET6;
809
810         if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
811                 errx(1, "%s: bad value", s);
812 }
813
814 void
815 in6_getprefix(char *plen, int which)
816 {
817         struct sockaddr_in6 *sin = sin6tab[which];
818         u_char *cp;
819         int len = atoi(plen);
820
821         if ((len < 0) || (len > 128))
822                 errx(1, "%s: bad value", plen);
823         sin->sin6_len = sizeof(*sin);
824         sin->sin6_family = AF_INET6;
825         if ((len == 0) || (len == 128)) {
826                 memset(&sin->sin6_addr, -1, sizeof(struct in6_addr));
827                 return;
828         }
829         for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
830                 *cp++ = -1;
831         *cp = (-1) << (8 - len);
832 }
833 #endif
834
835 /*
836  * Print a value a la the %b format of the kernel's printf
837  */
838 void
839 printb(char *s, unsigned int v, char *bits)
840 {
841         int i, any = 0;
842         char c;
843
844         if (bits && *bits == 8)
845                 printf("%s=%o", s, v & 0xffff);
846         else
847                 printf("%s=%x", s, v & 0xffff);
848         bits++;
849         if (bits) {
850                 putchar('<');
851                 while ((i = *bits++) != 0) {
852                         if ((v & (1 << (i-1))) != 0) {
853                                 if (any)
854                                         putchar(',');
855                                 any = 1;
856                                 for (; (c = *bits) > 32; bits++)
857                                         putchar(c);
858                         } else
859                                 for (; *bits > 32; bits++)
860                                         ;
861                 }
862                 putchar('>');
863         }
864 }
865
866 #ifdef INET6
867 int
868 prefix(void *val, int size)
869 {
870         u_char *name = (u_char *)val;
871         int byte, bit, plen = 0;
872
873         for (byte = 0; byte < size; byte++, plen += 8)
874                 if (name[byte] != 0xff)
875                         break;
876         if (byte == size)
877                 return (plen);
878         for (bit = 7; bit != 0; bit--, plen++)
879                 if (!(name[byte] & (1 << bit)))
880                         break;
881         for (; bit != 0; bit--)
882                 if (name[byte] & (1 << bit))
883                         return(0);
884         byte++;
885         for (; byte < size; byte++)
886                 if (name[byte])
887                         return(0);
888         return (plen);
889 }
890 #endif /*INET6*/