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