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