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