Initial import from FreeBSD RELENG_4:
[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(__FreeBSD__) && __FreeBSD__ >= 3
62 #include <net/if_var.h>
63 #endif /* __FreeBSD__ >= 3 */
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 __P((char *, int));
106 void setifpdst __P((char *, int));
107 void setifflags __P((char *, int));
108 #ifdef SIOCDIFPHYADDR
109 void delifaddrs __P((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) __P((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 __P((int, char *[]));
133 void status __P((void));
134 void phys_status __P((int));
135 void in_status __P((int));
136 #ifdef INET6
137 void in6_status __P((int));
138 #endif
139 void ether_status __P((int));
140 void Perror __P((char *));
141 void in_getaddr __P((char *, int));
142 #ifdef INET6
143 void in6_getaddr __P((char *, int));
144 void in6_getprefix __P((char *, int));
145 #endif
146 void printb __P((char *, unsigned int, char *));
147 int prefix __P((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) __P((int));
156         void (*af_getaddr) __P((char *, int));
157         void (*af_getprefix) __P((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 __P((caddr_t, caddr_t, struct rt_addrinfo *));
176 int     ifconfig __P((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(cp, cplim, rtinfo)
191         caddr_t cp, cplim;
192         struct rt_addrinfo *rtinfo;
193 {
194         struct sockaddr *sa;
195         int i;
196
197         memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
198         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
199                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
200                         continue;
201                 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
202                 ADVANCE(cp, sa);
203         }
204 }
205
206
207 /*
208  * Grunge for new-style sysctl() decoding.. :-(
209  * Apologies to the world for committing gross things like this in 1996..
210  */
211 struct if_msghdr *ifm;
212 struct ifa_msghdr *ifam;
213 struct sockaddr_dl *sdl;
214 struct rt_addrinfo info;
215 char *buf, *lim, *next;
216
217
218 int
219 main(argc, argv)
220         int argc;
221         char *argv[];
222 {
223         int af = AF_INET;
224         struct afswtch *rafp = NULL;
225         size_t needed;
226         int mib[6];
227         int all;
228
229         if (argc < 2) {
230                 fprintf(stderr,
231                     "usage: gifconfig interface [af] [physsrc physdst]\n");
232 #ifdef SIOCDIFPHYADDR
233                 fprintf(stderr,
234                     "       gifconfig interface delete\n");
235 #endif
236                 fprintf(stderr,
237                     "       gifconfig -a\n");
238                 exit(1);
239         }
240         argc--, argv++;
241         strncpy(name, *argv, sizeof(name));
242         strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
243         argc--, argv++;
244         if (argc > 0) {
245                 for (afp = rafp = afs; rafp->af_name; rafp++)
246                         if (strcmp(rafp->af_name, *argv) == 0) {
247                                 afp = rafp; argc--; argv++;
248                                 break;
249                         }
250                 rafp = afp;
251                 af = ifr.ifr_addr.sa_family = rafp->af_af;
252         }
253
254         mib[0] = CTL_NET;
255         mib[1] = PF_ROUTE;
256         mib[2] = 0;
257         mib[3] = 0;     /* address family */
258         mib[4] = NET_RT_IFLIST;
259         mib[5] = 0;
260
261         /* if particular family specified, only ask about it */
262         if (afp) {
263                 mib[3] = afp->af_af;
264         }
265
266         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
267                 errx(1, "iflist-sysctl-estimate");
268         if ((buf = malloc(needed)) == NULL)
269                 errx(1, "malloc");
270         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
271                 errx(1, "actual retrieval of interface table");
272         lim = buf + needed;
273
274         all = 0;
275         if (strcmp(name, "-a") == 0)
276                 all = 1;        /* All interfaces */
277         else if (strcmp(name, "-au") == 0)
278                 all = 2;        /* All IFF_UPinterfaces */
279         else if (strcmp(name, "-ad") == 0)
280                 all = 3;        /* All !IFF_UP interfaces */
281
282         for (next = buf; next < lim; next += ifm->ifm_msglen) {
283
284                 ifm = (struct if_msghdr *)next;
285
286                 /* XXX: Swallow up leftover NEWADDR messages */
287                 if (ifm->ifm_type == RTM_NEWADDR)
288                         continue;
289
290                 if (ifm->ifm_type == RTM_IFINFO) {
291                         sdl = (struct sockaddr_dl *)(ifm + 1);
292                         flags = ifm->ifm_flags;
293                 } else {
294                         errx(1, "out of sync parsing NET_RT_IFLIST");
295                 }
296
297                 switch(all) {
298                 case -1:
299                 case 0:
300                         if (strlen(name) != sdl->sdl_nlen)
301                                 continue; /* not same len */
302                         if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
303                                 continue; /* not same name */
304                         break;
305                 case 1:
306                         break;  /* always do it */
307                 case 2:
308                         if ((flags & IFF_UP) == 0)
309                                 continue; /* not up */
310                         break;
311                 case 3:
312                         if (flags & IFF_UP)
313                                 continue; /* not down */
314                         break;
315                 }
316
317                 /*
318                  * Let's just do it for gif only
319                  */
320                 if (sdl->sdl_type != IFT_GIF) {
321                         if (all != 0)
322                                 continue;
323
324                         fprintf(stderr, "gifconfig: %s is not gif.\n",
325                                 ifr.ifr_name);
326                         exit(1);
327                 }
328
329                 if (all > 0) {
330                         strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
331                         name[sdl->sdl_nlen] = '\0';
332                 }
333
334                 if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
335                         perror("gifconfig: socket");
336                         exit(1);
337                 }
338
339                 ifconfig(argc,argv,af,rafp);
340
341                 close(s);
342
343                 if (all == 0) {
344                         all = -1; /* flag it as 'done' */
345                         break;
346                 }
347         }
348         free(buf);
349
350         if (all == 0)
351                 errx(1, "interface %s does not exist", name);
352         
353
354         exit (0);
355 }
356
357
358 int
359 ifconfig(argc, argv, af, rafp)
360         int argc;
361         char *argv[];
362         int af;
363         struct afswtch *rafp;
364 {
365
366         af = 0;         /*fool gcc*/
367
368         strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
369 #ifdef INET6
370         strncpy(in6_ifr.ifr_name, name, sizeof in6_ifr.ifr_name);
371 #endif /* INET6 */
372
373         if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
374                 perror("ioctl (SIOCGIFMETRIC)");
375         else
376                 metric = ifr.ifr_metric;
377
378 #if defined(SIOCGIFMTU) && !defined(__OpenBSD__)
379         if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
380                 perror("ioctl (SIOCGIFMTU)");
381         else
382                 mtu = ifr.ifr_mtu;
383 #else
384         mtu = 0;
385 #endif
386
387         if (argc == 0) {
388                 status();
389                 return(0);
390         }
391
392         while (argc > 0) {
393                 register struct cmd *p;
394
395                 for (p = cmds; p->c_name; p++)
396                         if (strcmp(*argv, p->c_name) == 0)
397                                 break;
398                 if (p->c_name == 0 && setpsrc)
399                         p++;    /* got src, do dst */
400                 if (p->c_func) {
401                         if (p->c_parameter == NEXTARG) {
402                                 if (argv[1] == NULL)
403                                         errx(1, "'%s' requires argument",
404                                             p->c_name);
405                                 (*p->c_func)(argv[1], 0);
406                                 argc--, argv++;
407                         } else
408                                 (*p->c_func)(*argv, p->c_parameter);
409                 }
410                 argc--, argv++;
411         }
412         if (newaddr) {
413                 strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
414                 if (ioctl(s, rafp->af_pifaddr, rafp->af_addreq) < 0)
415                         Perror("ioctl (SIOCSIFPHYADDR)");
416         }
417         else if (setpsrc) {
418                 errx(1, "destination is not specified");
419         }
420         return(0);
421 }
422 #define PSRC    0
423 #define PDST    1
424
425 /*ARGSUSED*/
426 void
427 setifpsrc(addr, param)
428         char *addr;
429         int param;
430 {
431         param = 0;      /*fool gcc*/
432         (*afp->af_getaddr)(addr, PSRC);
433         setpsrc = 1;
434 }
435
436 /*ARGSUSED*/
437 void
438 setifpdst(addr, param)
439         char *addr;
440         int param;
441 {
442         param = 0;      /*fool gcc*/
443         (*afp->af_getaddr)(addr, PDST);
444         newaddr = 1;
445 }
446
447 void
448 setifflags(vname, value)
449         char *vname;
450         int value;
451 {
452         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
453                 Perror("ioctl (SIOCGIFFLAGS)");
454                 exit(1);
455         }
456         strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
457         flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
458
459         if (value < 0) {
460                 value = -value;
461                 flags &= ~value;
462         } else
463                 flags |= value;
464         ifr.ifr_flags = flags & 0xffff;
465         ifr.ifr_flagshigh = flags >> 16;
466         if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
467                 Perror(vname);
468 }
469
470 #ifdef SIOCDIFPHYADDR
471 /* ARGSUSED */
472 void
473 delifaddrs(vname, param)
474         char *vname;
475         int param;
476 {
477         param = 0;              /* fool gcc */
478         vname = NULL;           /* ditto */
479
480         if (ioctl(s, SIOCDIFPHYADDR, (caddr_t)&ifr) < 0)
481                 err(1, "ioctl(SIOCDIFPHYADDR)");
482 }
483 #endif
484
485 #define IFFBITS \
486 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
487 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
488
489 /*
490  * Print the status of the interface.  If an address family was
491  * specified, show it and it only; otherwise, show them all.
492  */
493 void
494 status()
495 {
496         struct afswtch *p = NULL;
497         char *mynext;
498         struct if_msghdr *myifm;
499
500         printf("%s: ", name);
501         printb("flags", flags, IFFBITS);
502         if (metric)
503                 printf(" metric %d", metric);
504         if (mtu)
505                 printf(" mtu %d", mtu);
506         putchar('\n');
507
508         /*
509          * XXX: Sigh. This is bad, I know.  At this point, we may have
510          * *zero* RTM_NEWADDR's, so we have to "feel the water" before
511          * incrementing the loop.  One day, I might feel inspired enough
512          * to get the top level loop to pass a count down here so we
513          * dont have to mess with this.  -Peter
514          */
515         myifm = ifm;
516
517         while (1) {
518
519                 mynext = next + ifm->ifm_msglen;
520
521                 if (mynext >= lim)
522                         break;
523
524                 myifm = (struct if_msghdr *)mynext;
525
526                 if (myifm->ifm_type != RTM_NEWADDR)
527                         break;
528
529                 next = mynext;
530
531                 ifm = (struct if_msghdr *)next;
532
533                 ifam = (struct ifa_msghdr *)myifm;
534                 info.rti_addrs = ifam->ifam_addrs;
535
536                 /* Expand the compacted addresses */
537                 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
538                           &info);
539
540                 if (afp) {
541                         if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
542                             afp->af_status != ether_status) {
543                                 p = afp;
544                                 if (p->af_status != ether_status)
545                                         (*p->af_status)(1);
546                         }
547                 } else for (p = afs; p->af_name; p++) {
548                         if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
549                             p->af_status != ether_status)
550                                 (*p->af_status)(0);
551                 }
552         }
553         if (afp == NULL || afp->af_status == ether_status)
554                 ether_status(0);
555         else if (afp && !p) {
556                 warnx("%s has no %s IFA address!", name, afp->af_name);
557         }
558
559         phys_status(0);
560 }
561
562 void
563 phys_status(force)
564         int force;
565 {
566         char psrcaddr[256];
567         char pdstaddr[256];
568         int flags = NI_NUMERICHOST;
569         char *af;
570 #ifndef SIOCGLIFPHYADDR
571         u_long srccmd, dstcmd;
572         struct ifreq *ifrp;
573 #ifdef INET6
574         int s6;
575 #endif
576
577         force = 0;      /*fool gcc*/
578
579         psrcaddr[0] = pdstaddr[0] = '\0';
580
581 #ifdef INET6
582         s6 = socket(AF_INET6, SOCK_DGRAM, 0);
583         if (s6 < 0) {
584                 ifrp = &ifr;
585                 srccmd = SIOCGIFPSRCADDR;
586                 dstcmd = SIOCGIFPDSTADDR;
587         } else {
588                 close(s6);
589                 srccmd = SIOCGIFPSRCADDR_IN6;
590                 dstcmd = SIOCGIFPDSTADDR_IN6;
591                 ifrp = (struct ifreq *)&in6_ifr;
592         }
593 #else /* INET6 */
594         ifrp = &ifr;
595         srccmd = SIOCGIFPSRCADDR;
596         dstcmd = SIOCGIFPDSTADDR;
597 #endif /* INET6 */
598
599         if (0 <= ioctl(s, srccmd, (caddr_t)ifrp)) {
600 #ifdef INET6
601                 if (ifrp->ifr_addr.sa_family == AF_INET6)
602                         af = "inet6";
603                 else
604                         af = "inet";
605 #else
606                 af = "inet";
607 #endif /* INET6 */
608                 if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
609                     psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0)
610                         psrcaddr[0] = '\0';
611         }
612         if (0 <= ioctl(s, dstcmd, (caddr_t)ifrp)) {
613                 if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
614                     pdstaddr, sizeof(pdstaddr), 0, 0, flags) != 0)
615                         pdstaddr[0] = '\0';
616         }
617         printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr);
618 #else
619         struct if_laddrreq iflr;
620
621         force = 0;      /*fool gcc*/
622
623         psrcaddr[0] = pdstaddr[0] = '\0';
624
625         memset(&iflr, 0, sizeof(iflr));
626         memcpy(iflr.iflr_name, ifr.ifr_name, sizeof(iflr.iflr_name));
627
628         if (0 <= ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&iflr)) {
629                 switch (iflr.addr.ss_family) {
630                 case AF_INET:
631                         af = "inet";
632                         break;
633 #ifdef INET6
634                 case AF_INET6:
635                         af = "inet6";
636                         break;
637 #endif /* INET6 */
638                 }
639                 if (getnameinfo((struct sockaddr *)&iflr.addr, iflr.addr.ss_len,
640                     psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0)
641                         psrcaddr[0] = '\0';
642                 if (getnameinfo((struct sockaddr *)&iflr.dstaddr,
643                     iflr.dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), 0, 0,
644                     flags) != 0)
645                         pdstaddr[0] = '\0';
646         }
647         printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr);
648 #endif
649 }
650
651 void
652 in_status(force)
653         int force;
654 {
655         struct sockaddr_in *sin, null_sin;
656 #if 0
657         char *inet_ntoa();
658 #endif
659         
660         memset(&null_sin, 0, sizeof(null_sin));
661
662         sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
663         if (!sin || sin->sin_family != AF_INET) {
664                 if (!force)
665                         return;
666                 /* warnx("%s has no AF_INET IFA address!", name); */
667                 sin = &null_sin;
668         }
669         printf("\tinet %s ", inet_ntoa(sin->sin_addr));
670
671         if (flags & IFF_POINTOPOINT) {
672                 /* note RTAX_BRD overlap with IFF_BROADCAST */
673                 sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
674                 if (!sin)
675                         sin = &null_sin;
676                 printf("--> %s ", inet_ntoa(sin->sin_addr));
677         }
678
679         sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
680         if (!sin)
681                 sin = &null_sin;
682         printf("netmask 0x%x ", (u_int32_t)ntohl(sin->sin_addr.s_addr));
683
684         if (flags & IFF_BROADCAST) {
685                 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
686                 sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
687                 if (sin && sin->sin_addr.s_addr != 0)
688                         printf("broadcast %s", inet_ntoa(sin->sin_addr));
689         }
690         putchar('\n');
691 }
692
693 #ifdef INET6
694 void
695 in6_status(force)
696         int force;
697 {
698         struct sockaddr_in6 *sin, null_sin;
699         char hostname[NI_MAXHOST];
700         int niflags = NI_NUMERICHOST;
701
702         memset(&null_sin, 0, sizeof(null_sin));
703 #ifdef NI_WITHSCOPEID
704         niflags |= NI_WITHSCOPEID;
705 #endif
706
707         sin = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA];
708         if (!sin || sin->sin6_family != AF_INET6) {
709                 if (!force)
710                         return;
711                 /* warnx("%s has no AF_INET6 IFA address!", name); */
712                 sin = &null_sin;
713         }
714 #ifdef __KAME__
715         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
716                 sin->sin6_scope_id =
717                         ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]);
718                 sin->sin6_addr.s6_addr[2] = 0;
719                 sin->sin6_addr.s6_addr[3] = 0;
720         }
721 #endif
722         getnameinfo((struct sockaddr *)sin, sin->sin6_len,
723                     hostname, sizeof(hostname), 0, 0, niflags);
724         printf("\tinet6 %s ", hostname);
725
726         if (flags & IFF_POINTOPOINT) {
727                 /* note RTAX_BRD overlap with IFF_BROADCAST */
728                 sin = (struct sockaddr_in6 *)info.rti_info[RTAX_BRD];
729                 /*
730                  * some of ther interfaces do not have valid destination
731                  * address.
732                  */
733                 if (sin->sin6_family == AF_INET6) {
734 #ifdef __KAME__
735                         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
736                                 sin->sin6_scope_id =
737                                         ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]);
738                                 sin->sin6_addr.s6_addr[2] = 0;
739                                 sin->sin6_addr.s6_addr[3] = 0;
740                         }
741 #endif
742                         getnameinfo((struct sockaddr *)sin, sin->sin6_len,
743                                     hostname, sizeof(hostname), 0, 0, niflags);
744                         printf("--> %s ", hostname);
745                 }
746         }
747
748         sin = (struct sockaddr_in6 *)info.rti_info[RTAX_NETMASK];
749         if (!sin)
750                 sin = &null_sin;
751         printf(" prefixlen %d ", prefix(&sin->sin6_addr,
752                 sizeof(struct in6_addr)));
753
754         putchar('\n');
755 }
756 #endif /*INET6*/
757
758 /*ARGSUSED*/
759 void
760 ether_status(dummy)
761         int dummy;
762 {
763         char *cp;
764         int n;
765
766         dummy = 0;      /*fool gcc*/
767
768         cp = (char *)LLADDR(sdl);
769         if ((n = sdl->sdl_alen) > 0) {
770                 if (sdl->sdl_type == IFT_ETHER)
771                         printf ("\tether ");
772                 else
773                         printf ("\tlladdr ");
774                 while (--n >= 0)
775                         printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
776                 putchar('\n');
777         }
778 }
779
780 void
781 Perror(cmd)
782         char *cmd;
783 {
784         switch (errno) {
785
786         case ENXIO:
787                 errx(1, "%s: no such interface", cmd);
788                 break;
789
790         case EPERM:
791                 errx(1, "%s: permission denied", cmd);
792                 break;
793
794         default:
795                 err(1, "%s", cmd);
796         }
797 }
798
799 #define SIN(x) ((struct sockaddr_in *) &(x))
800 struct sockaddr_in *sintab[] = {
801 SIN(addreq.ifra_addr), SIN(addreq.ifra_dstaddr)};
802
803 void
804 in_getaddr(s, which)
805         char *s;
806         int which;
807 {
808         register struct sockaddr_in *sin = sintab[which];
809         struct hostent *hp;
810         struct netent *np;
811
812         sin->sin_len = sizeof(*sin);
813         sin->sin_family = AF_INET;
814
815         if (inet_aton(s, &sin->sin_addr))
816                 ;
817         else if ((hp = gethostbyname(s)) != NULL)
818                 bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
819         else if ((np = getnetbyname(s)) != NULL)
820                 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
821         else
822                 errx(1, "%s: bad value", s);
823 }
824
825 #ifdef INET6
826 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
827 struct sockaddr_in6 *sin6tab[] = {
828 SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_dstaddr)};
829
830 void
831 in6_getaddr(s, which)
832         char *s;
833         int which;
834 {
835         register struct sockaddr_in6 *sin = sin6tab[which];
836
837         sin->sin6_len = sizeof(*sin);
838         sin->sin6_family = AF_INET6;
839
840         if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
841                 errx(1, "%s: bad value", s);
842 }
843
844 void
845 in6_getprefix(plen, which)
846         char *plen;
847         int which;
848 {
849         register struct sockaddr_in6 *sin = sin6tab[which];
850         register u_char *cp;
851         int len = atoi(plen);
852
853         if ((len < 0) || (len > 128))
854                 errx(1, "%s: bad value", plen);
855         sin->sin6_len = sizeof(*sin);
856         sin->sin6_family = AF_INET6;
857         if ((len == 0) || (len == 128)) {
858                 memset(&sin->sin6_addr, -1, sizeof(struct in6_addr));
859                 return;
860         }
861         for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
862                 *cp++ = -1;
863         *cp = (-1) << (8 - len);
864 }
865 #endif
866
867 /*
868  * Print a value a la the %b format of the kernel's printf
869  */
870 void
871 printb(s, v, bits)
872         char *s;
873         register unsigned int v;
874         register char *bits;
875 {
876         register int i, any = 0;
877         register char c;
878
879         if (bits && *bits == 8)
880                 printf("%s=%o", s, v & 0xffff);
881         else
882                 printf("%s=%x", s, v & 0xffff);
883         bits++;
884         if (bits) {
885                 putchar('<');
886                 while ((i = *bits++) != 0) {
887                         if ((v & (1 << (i-1))) != 0) {
888                                 if (any)
889                                         putchar(',');
890                                 any = 1;
891                                 for (; (c = *bits) > 32; bits++)
892                                         putchar(c);
893                         } else
894                                 for (; *bits > 32; bits++)
895                                         ;
896                 }
897                 putchar('>');
898         }
899 }
900
901 #ifdef INET6
902 int
903 prefix(val, size)
904         void *val;
905         int size;
906 {
907         register u_char *name = (u_char *)val;
908         register int byte, bit, plen = 0;
909
910         for (byte = 0; byte < size; byte++, plen += 8)
911                 if (name[byte] != 0xff)
912                         break;
913         if (byte == size)
914                 return (plen);
915         for (bit = 7; bit != 0; bit--, plen++)
916                 if (!(name[byte] & (1 << bit)))
917                         break;
918         for (; bit != 0; bit--)
919                 if (name[byte] & (1 << bit))
920                         return(0);
921         byte++;
922         for (; byte < size; byte++)
923                 if (name[byte])
924                         return(0);
925         return (plen);
926 }
927 #endif /*INET6*/