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