xref: /dragonfly/usr.sbin/gifconfig/gifconfig.c (revision ae071d8d)
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*/
891