xref: /openbsd/regress/sbin/ifconfig/ifaddr.c (revision bc5a8259)
1 /*	$OpenBSD: ifaddr.c,v 1.6 2021/07/12 15:09:18 beck Exp $	*/
2 
3 /*
4  * This file has been copied from ifconfig and adapted to test
5  * SIOCSIFADDR, SIOCSIFNETMASK, SIOCSIFDSTADDR, SIOCSIFBRDADDR
6  * ioctls.  Usually ifconfig uses SIOCAIFADDR and SIOCDIFADDR, but
7  * the old kernel interface has to be tested, too.
8  */
9 
10 /*
11  * Copyright (c) 1983, 1993
12  *	The Regents of the University of California.  All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to The NetBSD Foundation
44  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
45  * NASA Ames Research Center.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
57  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
58  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
60  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66  * POSSIBILITY OF SUCH DAMAGE.
67  */
68 
69 /*
70  * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
71  *
72  * Permission to use, copy, modify, and distribute this software for any
73  * purpose with or without fee is hereby granted, provided that the above
74  * copyright notice and this permission notice appear in all copies.
75  *
76  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
77  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
78  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
79  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
80  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
81  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
82  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
83  */
84 
85 #include <sys/socket.h>
86 #include <sys/ioctl.h>
87 #include <sys/time.h>
88 
89 #include <net/if.h>
90 #include <net/if_dl.h>
91 #include <net/if_media.h>
92 #include <net/if_types.h>
93 #include <netinet/in.h>
94 #include <netinet/in_var.h>
95 #include <netinet6/in6_var.h>
96 #include <netinet6/nd6.h>
97 #include <arpa/inet.h>
98 #include <netinet/ip_ipsp.h>
99 #include <netinet/if_ether.h>
100 
101 #include <netdb.h>
102 
103 #include <net/if_vlan_var.h>
104 
105 #include <ctype.h>
106 #include <err.h>
107 #include <errno.h>
108 #include <stdio.h>
109 #include <stdint.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <unistd.h>
113 #include <limits.h>
114 #include <resolv.h>
115 #include <util.h>
116 #include <ifaddrs.h>
117 
118 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
119 #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
120 
121 #define HWFEATURESBITS							\
122 	"\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4"			\
123 	"\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6"			\
124 	"\11CSUM_UDPv6\20WOL"
125 
126 struct	ifreq		ifr, ridreq;
127 struct	in_aliasreq	in_addreq;
128 struct	in6_ifreq	ifr6;
129 struct	in6_ifreq	in6_ridreq;
130 struct	in6_aliasreq	in6_addreq;
131 struct	sockaddr_in	netmask;
132 
133 char	ifname[IFNAMSIZ];
134 int	flags, xflags, setaddr, setmask, setipdst, setbroad, doalias;
135 u_long	metric, mtu;
136 int	rdomainid;
137 int	llprio;
138 int	clearaddr, sock;
139 int	newaddr = 0;
140 int	af = AF_INET;
141 int	explicit_prefix = 0;
142 int	Lflag = 1;
143 
144 int	showcapsflag;
145 
146 void	notealias(const char *, int);
147 void	setifaddr(const char *, int);
148 void	setifrtlabel(const char *, int);
149 void	setifdstaddr(const char *, int);
150 void	addaf(const char *, int);
151 void	removeaf(const char *, int);
152 void	setifbroadaddr(const char *, int);
153 void	setifnetmask(const char *, int);
154 void	setifprefixlen(const char *, int);
155 void	settunnel(const char *, const char *);
156 void	settunneladdr(const char *, int);
157 void	deletetunnel(const char *, int);
158 void	settunnelinst(const char *, int);
159 void	unsettunnelinst(const char *, int);
160 void	settunnelttl(const char *, int);
161 void	setia6flags(const char *, int);
162 void	setia6pltime(const char *, int);
163 void	setia6vltime(const char *, int);
164 void	setia6lifetime(const char *, const char *);
165 void	setia6eui64(const char *, int);
166 void	setrdomain(const char *, int);
167 void	unsetrdomain(const char *, int);
168 int	prefix(void *val, int);
169 int	printgroup(char *, int);
170 void	setifipdst(const char *, int);
171 void	setignore(const char *, int);
172 
173 int	actions;			/* Actions performed */
174 
175 #define A_SILENT	0x8000000	/* doing operation, do not print */
176 
177 #define	NEXTARG0	0xffffff
178 #define NEXTARG		0xfffffe
179 #define	NEXTARG2	0xfffffd
180 
181 const struct	cmd {
182 	char	*c_name;
183 	int	c_parameter;		/* NEXTARG means next argv */
184 	int	c_action;		/* defered action */
185 	void	(*c_func)(const char *, int);
186 	void	(*c_func2)(const char *, const char *);
187 } cmds[] = {
188 	{ "alias",	IFF_UP,		0,		notealias },
189 	{ "-alias",	-IFF_UP,	0,		notealias },
190 	{ "delete",	-IFF_UP,	0,		notealias },
191 	{ "netmask",	NEXTARG,	0,		setifnetmask },
192 	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
193 	{ "prefixlen",  NEXTARG,	0,		setifprefixlen},
194 	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
195 	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
196 	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
197 	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
198 	{ "pltime",	NEXTARG,	0,		setia6pltime },
199 	{ "vltime",	NEXTARG,	0,		setia6vltime },
200 	{ "eui64",	0,		0,		setia6eui64 },
201 #ifndef SMALL
202 	{ "rtlabel",	NEXTARG,	0,		setifrtlabel },
203 	{ "-rtlabel",	-1,		0,		setifrtlabel },
204 	{ "rdomain",	NEXTARG,	0,		setrdomain },
205 	{ "-rdomain",	0,		0,		unsetrdomain },
206 	{ "tunnel",	NEXTARG2,	0,		NULL, settunnel },
207 	{ "tunneladdr",	NEXTARG,	0,		settunneladdr },
208 	{ "-tunnel",	0,		0,		deletetunnel },
209 	/* deletetunnel is for backward compat, remove during 6.4-current */
210 	{ "deletetunnel",  0,		0,		deletetunnel },
211 	{ "tunneldomain", NEXTARG,	0,		settunnelinst },
212 	{ "-tunneldomain", 0,		0,		unsettunnelinst },
213 	{ "tunnelttl",	NEXTARG,	0,		settunnelttl },
214 	{ "-inet",	AF_INET,	0,		removeaf },
215 	{ "-inet6",	AF_INET6,	0,		removeaf },
216 	{ "ipdst",	NEXTARG,	0,		setifipdst },
217 #endif /* SMALL */
218 	{ NULL, /*src*/	0,		0,		setifaddr },
219 	{ NULL, /*dst*/	0,		0,		setifdstaddr },
220 	{ NULL, /*illegal*/0,		0,		NULL },
221 };
222 
223 #define	IFFBITS								\
224 	"\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6STATICARP"	\
225 	"\7RUNNING\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX"	\
226 	"\15LINK0\16LINK1\17LINK2\20MULTICAST"				\
227 	"\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII"	\
228 	"\30AUTOCONF4"
229 
230 int	getinfo(struct ifreq *, int);
231 void	getsock(int);
232 void	printif(char *, int);
233 void	printb(char *, unsigned int, unsigned char *);
234 void	printb_status(unsigned short, unsigned char *);
235 const char *get_linkstate(int, int);
236 void	status(int, struct sockaddr_dl *, int);
237 __dead void	usage(void);
238 const char *get_string(const char *, const char *, u_int8_t *, int *);
239 int	len_string(const u_int8_t *, int);
240 int	print_string(const u_int8_t *, int);
241 char	*sec2str(time_t);
242 
243 unsigned long get_ts_map(int, int, int);
244 
245 void	in_status(int);
246 void	in_getaddr(const char *, int);
247 void	in_getprefix(const char *, int);
248 void	in6_fillscopeid(struct sockaddr_in6 *);
249 void	in6_alias(struct in6_ifreq *);
250 void	in6_status(int);
251 void	in6_getaddr(const char *, int);
252 void	in6_getprefix(const char *, int);
253 
254 /* Known address families */
255 const struct afswtch {
256 	char *af_name;
257 	short af_af;
258 	void (*af_status)(int);
259 	void (*af_getaddr)(const char *, int);
260 	void (*af_getprefix)(const char *, int);
261 	u_long af_difaddr;
262 	u_long af_aifaddr;
263 	caddr_t af_ridreq;
264 	caddr_t af_addreq;
265 } afs[] = {
266 #define C(x) ((caddr_t) &x)
267 	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
268 	    SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) },
269 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
270 	    SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
271 	{ 0,	0,	    0,		0 }
272 };
273 
274 const struct afswtch *afp;	/*the address family being set or asked about*/
275 
276 int ifaliases = 0;
277 int aflag = 0;
278 
279 int
280 main(int argc, char *argv[])
281 {
282 	const struct afswtch *rafp = NULL;
283 	int create = 0;
284 	int i;
285 
286 	/* If no args at all, print all interfaces.  */
287 	if (argc < 2) {
288 		/* no filesystem visibility */
289 		if (unveil("/", "") == -1)
290 			err(1, "unveil /");
291 		if (unveil(NULL, NULL) == -1)
292 			err(1, "unveil");
293 		aflag = 1;
294 		printif(NULL, 0);
295 		return (0);
296 	}
297 	argc--, argv++;
298 	if (*argv[0] == '-') {
299 		int nomore = 0;
300 
301 		for (i = 1; argv[0][i]; i++) {
302 			switch (argv[0][i]) {
303 			case 'a':
304 				aflag = 1;
305 				nomore = 1;
306 				break;
307 			case 'A':
308 				aflag = 1;
309 				ifaliases = 1;
310 				nomore = 1;
311 				break;
312 			default:
313 				usage();
314 				break;
315 			}
316 		}
317 		if (nomore == 0) {
318 			argc--, argv++;
319 			if (argc < 1)
320 				usage();
321 			if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
322 				errx(1, "interface name '%s' too long", *argv);
323 		}
324 	} else if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
325 		errx(1, "interface name '%s' too long", *argv);
326 	argc--, argv++;
327 
328 	if (unveil(_PATH_RESCONF, "r") == -1)
329 		err(1, "unveil %s", _PATH_RESCONF);
330 	if (unveil(_PATH_HOSTS, "r") == -1)
331 		err(1, "unveil %s", _PATH_HOSTS);
332 	if (unveil(_PATH_SERVICES, "r") == -1)
333 		err(1, "unveil %s", _PATH_SERVICES);
334 	if (unveil(NULL, NULL) == -1)
335 		err(1, "unveil");
336 
337 	if (argc > 0) {
338 		for (afp = rafp = afs; rafp->af_name; rafp++)
339 			if (strcmp(rafp->af_name, *argv) == 0) {
340 				afp = rafp;
341 				argc--;
342 				argv++;
343 				break;
344 			}
345 		rafp = afp;
346 		af = ifr.ifr_addr.sa_family = rafp->af_af;
347 	}
348 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
349 
350 	/* initialization */
351 	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
352 	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
353 
354 	if (aflag == 0) {
355 		create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
356 		(void)getinfo(&ifr, create);
357 	}
358 
359 	if (argc != 0 && af == AF_INET6)
360 		addaf(ifname, AF_INET6);
361 
362 	while (argc > 0) {
363 		const struct cmd *p;
364 
365 		for (p = cmds; p->c_name; p++)
366 			if (strcmp(*argv, p->c_name) == 0)
367 				break;
368 		if (p->c_name == 0 && setaddr)
369 			for (i = setaddr; i > 0; i--) {
370 				p++;
371 				if (p->c_func == NULL)
372 					errx(1, "%s: bad value", *argv);
373 			}
374 		if (p->c_func || p->c_func2) {
375 			if (p->c_parameter == NEXTARG0) {
376 				const struct cmd *p0;
377 				int noarg = 1;
378 
379 				if (argv[1]) {
380 					for (p0 = cmds; p0->c_name; p0++)
381 						if (strcmp(argv[1],
382 						    p0->c_name) == 0) {
383 							noarg = 0;
384 							break;
385 						}
386 				} else
387 					noarg = 0;
388 
389 				if (noarg == 0)
390 					(*p->c_func)(NULL, 0);
391 				else
392 					goto nextarg;
393 			} else if (p->c_parameter == NEXTARG) {
394 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 				actions = actions | A_SILENT | p->c_action;
401 			} else if (p->c_parameter == NEXTARG2) {
402 				if ((argv[1] == NULL) ||
403 				    (argv[2] == NULL))
404 					errx(1, "'%s' requires 2 arguments",
405 					    p->c_name);
406 				(*p->c_func2)(argv[1], argv[2]);
407 				argc -= 2;
408 				argv += 2;
409 				actions = actions | A_SILENT | p->c_action;
410 			} else {
411 				(*p->c_func)(*argv, p->c_parameter);
412 				actions = actions | A_SILENT | p->c_action;
413 			}
414 		}
415 		argc--, argv++;
416 	}
417 
418 	if (argc == 0 && actions == 0) {
419 		printif(ifr.ifr_name, aflag ? ifaliases : 1);
420 		return (0);
421 	}
422 
423 	if (af == AF_INET6 && explicit_prefix == 0) {
424 		/*
425 		 * Aggregatable address architecture defines all prefixes
426 		 * are 64. So, it is convenient to set prefixlen to 64 if
427 		 * it is not specified. If we are setting a destination
428 		 * address on a point-to-point interface, 128 is required.
429 		 */
430 		if (setipdst && (flags & IFF_POINTOPOINT))
431 			setifprefixlen("128", 0);
432 		else
433 			setifprefixlen("64", 0);
434 		/* in6_getprefix("64", MASK) if MASK is available here... */
435 	}
436 
437 	if (doalias == 0 || (newaddr && clearaddr)) {
438 		(void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
439 		/* IPv4 only, inet6 does not have such ioctls */
440 		if (setaddr) {
441 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_addr,
442 			    in_addreq.ifra_addr.sin_len);
443 			if (ioctl(sock, SIOCSIFADDR, rafp->af_ridreq) == -1)
444 				err(1, "SIOCSIFADDR");
445 		}
446 		if (setmask) {
447 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_mask,
448 			    in_addreq.ifra_mask.sin_len);
449 			if (ioctl(sock, SIOCSIFNETMASK, rafp->af_ridreq) == -1)
450 				err(1, "SIOCSIFNETMASK");
451 		}
452 		if (setipdst) {
453 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_dstaddr,
454 			    in_addreq.ifra_dstaddr.sin_len);
455 			if (ioctl(sock, SIOCSIFDSTADDR, rafp->af_ridreq) == -1)
456 				err(1, "SIOCSIFDSTADDR");
457 		}
458 		if (setbroad) {
459 			memcpy(&ridreq.ifr_addr, &in_addreq.ifra_broadaddr,
460 			    in_addreq.ifra_broadaddr.sin_len);
461 			if (ioctl(sock, SIOCSIFBRDADDR, rafp->af_ridreq) == -1)
462 				err(1, "SIOCSIFBRDADDR");
463 		}
464 		return (0);
465 	}
466 	if (clearaddr) {
467 		(void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
468 		if (ioctl(sock, rafp->af_difaddr, rafp->af_ridreq) == -1) {
469 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
470 				/* means no previous address for interface */
471 			} else
472 				err(1, "SIOCDIFADDR");
473 		}
474 	}
475 	if (newaddr) {
476 		(void) strlcpy(rafp->af_addreq, ifname, sizeof(ifr.ifr_name));
477 		if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) == -1)
478 			err(1, "SIOCAIFADDR");
479 	}
480 	return (0);
481 }
482 
483 void
484 getsock(int naf)
485 {
486 	static int oaf = -1;
487 
488 	if (oaf == naf)
489 		return;
490 	if (oaf != -1)
491 		close(sock);
492 	sock = socket(naf, SOCK_DGRAM, 0);
493 	if (sock == -1)
494 		oaf = -1;
495 	else
496 		oaf = naf;
497 }
498 
499 int
500 getinfo(struct ifreq *ifr, int create)
501 {
502 
503 	getsock(af);
504 	if (sock == -1)
505 		err(1, "socket");
506 	if (!isdigit((unsigned char)ifname[strlen(ifname) - 1]))
507 		return (-1);	/* ignore groups here */
508 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) {
509 		int oerrno = errno;
510 
511 		if (!create)
512 			return (-1);
513 		if (ioctl(sock, SIOCIFCREATE, (caddr_t)ifr) == -1) {
514 			errno = oerrno;
515 			return (-1);
516 		}
517 		if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1)
518 			return (-1);
519 	}
520 	flags = ifr->ifr_flags & 0xffff;
521 	if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)ifr) == -1)
522 		ifr->ifr_flags = 0;
523 	xflags = ifr->ifr_flags;
524 	if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) == -1)
525 		metric = 0;
526 	else
527 		metric = ifr->ifr_metric;
528 	if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1)
529 		mtu = 0;
530 	else
531 		mtu = ifr->ifr_mtu;
532 #ifndef SMALL
533 	if (ioctl(sock, SIOCGIFRDOMAIN, (caddr_t)ifr) == -1)
534 		rdomainid = 0;
535 	else
536 		rdomainid = ifr->ifr_rdomainid;
537 #endif
538 	if (ioctl(sock, SIOCGIFLLPRIO, (caddr_t)ifr) == -1)
539 		llprio = 0;
540 	else
541 		llprio = ifr->ifr_llprio;
542 
543 	return (0);
544 }
545 
546 int
547 printgroup(char *groupname, int ifaliases)
548 {
549 	struct ifgroupreq	 ifgr;
550 	struct ifg_req		*ifg;
551 	int			 len, cnt = 0;
552 
553 	getsock(AF_INET);
554 	bzero(&ifgr, sizeof(ifgr));
555 	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
556 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
557 		if (errno == EINVAL || errno == ENOTTY ||
558 		    errno == ENOENT)
559 			return (-1);
560 		else
561 			err(1, "SIOCGIFGMEMB");
562 	}
563 
564 	len = ifgr.ifgr_len;
565 	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
566 		err(1, "printgroup");
567 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
568 		err(1, "SIOCGIFGMEMB");
569 
570 	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
571 	    ifg++) {
572 		len -= sizeof(struct ifg_req);
573 		printif(ifg->ifgrq_member, ifaliases);
574 		cnt++;
575 	}
576 	free(ifgr.ifgr_groups);
577 
578 	return (cnt);
579 }
580 
581 void
582 printif(char *name, int ifaliases)
583 {
584 	struct ifaddrs *ifap, *ifa;
585 	struct if_data *ifdata;
586 	const char *namep;
587 	char *oname = NULL;
588 	struct ifreq *ifrp;
589 	int count = 0, noinet = 1;
590 	size_t nlen = 0;
591 
592 	if (aflag)
593 		name = NULL;
594 	if (name) {
595 		if ((oname = strdup(name)) == NULL)
596 			err(1, "strdup");
597 		nlen = strlen(oname);
598 		/* is it a group? */
599 		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
600 			if (printgroup(oname, ifaliases) != -1) {
601 				free(oname);
602 				return;
603 			}
604 	}
605 
606 	if (getifaddrs(&ifap) != 0)
607 		err(1, "getifaddrs");
608 
609 	namep = NULL;
610 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
611 		if (oname) {
612 			if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
613 				/* must have exact match */
614 				if (strcmp(oname, ifa->ifa_name) != 0)
615 					continue;
616 			} else {
617 				/* partial match OK if it ends w/ digit */
618 				if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
619 				    !isdigit((unsigned char)ifa->ifa_name[nlen]))
620 					continue;
621 			}
622 		}
623 		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
624 		if (ifa->ifa_addr->sa_family == AF_INET6) {
625 			memset(&ifr6, 0, sizeof(ifr6));
626 			memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
627 			    MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
628 			ifrp = (struct ifreq *)&ifr6;
629 		} else {
630 			memset(&ifr, 0, sizeof(ifr));
631 			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
632 			    MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
633 			ifrp = &ifr;
634 		}
635 		strlcpy(ifname, ifa->ifa_name, sizeof(ifname));
636 		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
637 
638 		if (ifa->ifa_addr->sa_family == AF_LINK) {
639 			namep = ifa->ifa_name;
640 			if (getinfo(ifrp, 0) < 0)
641 				continue;
642 			ifdata = ifa->ifa_data;
643 			status(1, (struct sockaddr_dl *)ifa->ifa_addr,
644 			    ifdata->ifi_link_state);
645 			count++;
646 			noinet = 1;
647 			continue;
648 		}
649 
650 		if (!namep || !strcmp(namep, ifa->ifa_name)) {
651 			const struct afswtch *p;
652 
653 			if (ifa->ifa_addr->sa_family == AF_INET &&
654 			    ifaliases == 0 && noinet == 0)
655 				continue;
656 			if ((p = afp) != NULL) {
657 				if (ifa->ifa_addr->sa_family == p->af_af)
658 					p->af_status(1);
659 			} else {
660 				for (p = afs; p->af_name; p++) {
661 					if (ifa->ifa_addr->sa_family ==
662 					    p->af_af)
663 						p->af_status(0);
664 				}
665 			}
666 			count++;
667 			if (ifa->ifa_addr->sa_family == AF_INET)
668 				noinet = 0;
669 			continue;
670 		}
671 	}
672 	freeifaddrs(ifap);
673 	free(oname);
674 	if (count == 0) {
675 		fprintf(stderr, "%s: no such interface\n", ifname);
676 		exit(1);
677 	}
678 }
679 
680 #define RIDADDR 0
681 #define ADDR	1
682 #define MASK	2
683 #define DSTADDR	3
684 
685 /*ARGSUSED*/
686 void
687 setifaddr(const char *addr, int param)
688 {
689 	/*
690 	 * Delay the ioctl to set the interface addr until flags are all set.
691 	 * The address interpretation may depend on the flags,
692 	 * and the flags may change when the address is set.
693 	 */
694 	setaddr++;
695 	if (doalias >= 0)
696 		newaddr = 1;
697 	if (doalias == 0)
698 		clearaddr = 1;
699 	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
700 }
701 
702 #ifndef SMALL
703 void
704 setifrtlabel(const char *label, int d)
705 {
706 	if (d != 0)
707 		ifr.ifr_data = (caddr_t)(const char *)"";
708 	else
709 		ifr.ifr_data = (caddr_t)label;
710 	if (ioctl(sock, SIOCSIFRTLABEL, &ifr) == -1)
711 		warn("SIOCSIFRTLABEL");
712 }
713 #endif
714 
715 /* ARGSUSED */
716 void
717 setifnetmask(const char *addr, int ignored)
718 {
719 	setmask++;
720 	afp->af_getaddr(addr, MASK);
721 	explicit_prefix = 1;
722 }
723 
724 /* ARGSUSED */
725 void
726 setifbroadaddr(const char *addr, int ignored)
727 {
728 	setbroad++;
729 	afp->af_getaddr(addr, DSTADDR);
730 }
731 
732 /* ARGSUSED */
733 void
734 setifipdst(const char *addr, int ignored)
735 {
736 	in_getaddr(addr, DSTADDR);
737 	setipdst++;
738 	clearaddr = 0;
739 	newaddr = 0;
740 }
741 
742 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
743 /*ARGSUSED*/
744 void
745 notealias(const char *addr, int param)
746 {
747 	if (setaddr && doalias == 0 && param < 0)
748 		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
749 		    rqtosa(af_addreq)->sa_len);
750 	doalias = param;
751 	if (param < 0) {
752 		clearaddr = 1;
753 		newaddr = 0;
754 	} else
755 		clearaddr = 0;
756 }
757 
758 /*ARGSUSED*/
759 void
760 setifdstaddr(const char *addr, int param)
761 {
762 	setaddr++;
763 	setipdst++;
764 	afp->af_getaddr(addr, DSTADDR);
765 }
766 
767 void
768 addaf(const char *vname, int value)
769 {
770 	struct if_afreq	ifar;
771 
772 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
773 	ifar.ifar_af = value;
774 	if (ioctl(sock, SIOCIFAFATTACH, (caddr_t)&ifar) == -1)
775 		warn("SIOCIFAFATTACH");
776 }
777 
778 void
779 removeaf(const char *vname, int value)
780 {
781 	struct if_afreq	ifar;
782 
783 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
784 	ifar.ifar_af = value;
785 	if (ioctl(sock, SIOCIFAFDETACH, (caddr_t)&ifar) == -1)
786 		warn("SIOCIFAFDETACH");
787 }
788 
789 void
790 setia6flags(const char *vname, int value)
791 {
792 
793 	if (value < 0) {
794 		value = -value;
795 		in6_addreq.ifra_flags &= ~value;
796 	} else
797 		in6_addreq.ifra_flags |= value;
798 }
799 
800 void
801 setia6pltime(const char *val, int d)
802 {
803 
804 	setia6lifetime("pltime", val);
805 }
806 
807 void
808 setia6vltime(const char *val, int d)
809 {
810 
811 	setia6lifetime("vltime", val);
812 }
813 
814 void
815 setia6lifetime(const char *cmd, const char *val)
816 {
817 	const char *errmsg = NULL;
818 	time_t newval, t;
819 
820 	newval = strtonum(val, 0, 1000000, &errmsg);
821 	if (errmsg)
822 		errx(1, "invalid %s %s: %s", cmd, val, errmsg);
823 
824 	t = time(NULL);
825 
826 	if (afp->af_af != AF_INET6)
827 		errx(1, "%s not allowed for this address family", cmd);
828 	if (strcmp(cmd, "vltime") == 0) {
829 		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
830 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
831 	} else if (strcmp(cmd, "pltime") == 0) {
832 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
833 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
834 	}
835 }
836 
837 void
838 setia6eui64(const char *cmd, int val)
839 {
840 	struct ifaddrs *ifap, *ifa;
841 	const struct sockaddr_in6 *sin6 = NULL;
842 	const struct in6_addr *lladdr = NULL;
843 	struct in6_addr *in6;
844 
845 	if (afp->af_af != AF_INET6)
846 		errx(1, "%s not allowed for this address family", cmd);
847 
848 	addaf(ifname, AF_INET6);
849 
850 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
851 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
852 		errx(1, "interface index is already filled");
853 	if (getifaddrs(&ifap) != 0)
854 		err(1, "getifaddrs");
855 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
856 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
857 		    strcmp(ifa->ifa_name, ifname) == 0) {
858 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
859 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
860 				lladdr = &sin6->sin6_addr;
861 				break;
862 			}
863 		}
864 	}
865 	if (!lladdr)
866 		errx(1, "could not determine link local address");
867 
868 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
869 
870 	freeifaddrs(ifap);
871 }
872 
873 const char *
874 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
875 {
876 	int len = *lenp, hexstr;
877 	u_int8_t *p = buf;
878 
879 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
880 	if (hexstr)
881 		val += 2;
882 	for (;;) {
883 		if (*val == '\0')
884 			break;
885 		if (sep != NULL && strchr(sep, *val) != NULL) {
886 			val++;
887 			break;
888 		}
889 		if (hexstr) {
890 			if (!isxdigit((u_char)val[0]) ||
891 			    !isxdigit((u_char)val[1])) {
892 				warnx("bad hexadecimal digits");
893 				return NULL;
894 			}
895 		}
896 		if (p > buf + len) {
897 			if (hexstr)
898 				warnx("hexadecimal digits too long");
899 			else
900 				warnx("strings too long");
901 			return NULL;
902 		}
903 		if (hexstr) {
904 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
905 			*p++ = (tohex((u_char)val[0]) << 4) |
906 			    tohex((u_char)val[1]);
907 #undef tohex
908 			val += 2;
909 		} else {
910 			if (*val == '\\' &&
911 			    sep != NULL && strchr(sep, *(val + 1)) != NULL)
912 				val++;
913 			*p++ = *val++;
914 		}
915 	}
916 	len = p - buf;
917 	if (len < *lenp)
918 		memset(p, 0, *lenp - len);
919 	*lenp = len;
920 	return val;
921 }
922 
923 int
924 len_string(const u_int8_t *buf, int len)
925 {
926 	int i = 0, hasspc = 0;
927 
928 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
929 		for (; i < len; i++) {
930 			/* Only print 7-bit ASCII keys */
931 			if (buf[i] & 0x80 || !isprint(buf[i]))
932 				break;
933 			if (isspace(buf[i]))
934 				hasspc++;
935 		}
936 	}
937 	if (i == len) {
938 		if (hasspc || len == 0)
939 			return len + 2;
940 		else
941 			return len;
942 	} else
943 		return (len * 2) + 2;
944 }
945 
946 int
947 print_string(const u_int8_t *buf, int len)
948 {
949 	int i = 0, hasspc = 0;
950 
951 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
952 		for (; i < len; i++) {
953 			/* Only print 7-bit ASCII keys */
954 			if (buf[i] & 0x80 || !isprint(buf[i]))
955 				break;
956 			if (isspace(buf[i]))
957 				hasspc++;
958 		}
959 	}
960 	if (i == len) {
961 		if (hasspc || len == 0) {
962 			printf("\"%.*s\"", len, buf);
963 			return len + 2;
964 		} else {
965 			printf("%.*s", len, buf);
966 			return len;
967 		}
968 	} else {
969 		printf("0x");
970 		for (i = 0; i < len; i++)
971 			printf("%02x", buf[i]);
972 		return (len * 2) + 2;
973 	}
974 }
975 
976 static void
977 print_tunnel(const struct if_laddrreq *req)
978 {
979 	char psrcaddr[NI_MAXHOST];
980 	char pdstaddr[NI_MAXHOST];
981 	const char *ver = "";
982 	const int niflag = NI_NUMERICHOST;
983 
984 	if (req == NULL) {
985 		printf("(unset)");
986 		return;
987 	}
988 
989 	psrcaddr[0] = pdstaddr[0] = '\0';
990 
991 	if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len,
992 	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
993 		strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
994 	if (req->addr.ss_family == AF_INET6)
995 		ver = "6";
996 
997 	printf("inet%s %s", ver, psrcaddr);
998 
999 	if (req->dstaddr.ss_family != AF_UNSPEC) {
1000 		in_port_t dstport = 0;
1001 		const struct sockaddr_in *sin;
1002 		const struct sockaddr_in6 *sin6;
1003 
1004 		if (getnameinfo((struct sockaddr *)&req->dstaddr,
1005 		    req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr),
1006 		    0, 0, niflag) != 0)
1007 			strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
1008 
1009 		printf(" -> %s", pdstaddr);
1010 
1011 		switch (req->dstaddr.ss_family) {
1012 		case AF_INET:
1013 			sin = (const struct sockaddr_in *)&req->dstaddr;
1014 			dstport = sin->sin_port;
1015 			break;
1016 		case AF_INET6:
1017 			sin6 = (const struct sockaddr_in6 *)&req->dstaddr;
1018 			dstport = sin6->sin6_port;
1019 			break;
1020 		}
1021 
1022 		if (dstport)
1023 			printf(":%u", ntohs(dstport));
1024 	}
1025 }
1026 
1027 /* ARGSUSED */
1028 static void
1029 phys_status(int force)
1030 {
1031 	struct if_laddrreq req;
1032 	struct if_laddrreq *r = &req;
1033 
1034 	memset(&req, 0, sizeof(req));
1035 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1036 	if (ioctl(sock, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) {
1037 		if (errno != EADDRNOTAVAIL)
1038 			return;
1039 
1040 		r = NULL;
1041 	}
1042 
1043 	printf("\ttunnel: ");
1044 	print_tunnel(r);
1045 
1046 	if (ioctl(sock, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) {
1047 		if (ifr.ifr_ttl == -1)
1048 			printf(" ttl copy");
1049 		else if (ifr.ifr_ttl > 0)
1050 			printf(" ttl %d", ifr.ifr_ttl);
1051 	}
1052 
1053 	if (ioctl(sock, SIOCGLIFPHYDF, (caddr_t)&ifr) == 0)
1054 		printf(" %s", ifr.ifr_df ? "df" : "nodf");
1055 
1056 #ifndef SMALL
1057 	if (ioctl(sock, SIOCGLIFPHYECN, (caddr_t)&ifr) == 0)
1058 		printf(" %s", ifr.ifr_metric ? "ecn" : "noecn");
1059 
1060 	if (ioctl(sock, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
1061 	    (rdomainid != 0 || ifr.ifr_rdomainid != 0))
1062 		printf(" rdomain %d", ifr.ifr_rdomainid);
1063 #endif
1064 	printf("\n");
1065 }
1066 
1067 #ifndef SMALL
1068 const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1069 
1070 const struct ifmedia_status_description ifm_status_descriptions[] =
1071 	IFM_STATUS_DESCRIPTIONS;
1072 #endif
1073 
1074 const struct if_status_description if_status_descriptions[] =
1075 	LINK_STATE_DESCRIPTIONS;
1076 
1077 const char *
1078 get_linkstate(int mt, int link_state)
1079 {
1080 	const struct if_status_description *p;
1081 	static char buf[8];
1082 
1083 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1084 		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
1085 			return (p->ifs_string);
1086 	}
1087 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1088 	return buf;
1089 }
1090 
1091 /*
1092  * Print the status of the interface.  If an address family was
1093  * specified, show it and it only; otherwise, show them all.
1094  */
1095 void
1096 status(int link, struct sockaddr_dl *sdl, int ls)
1097 {
1098 	const struct afswtch *p = afp;
1099 	struct ifmediareq ifmr;
1100 #ifndef SMALL
1101 	struct ifreq ifrdesc;
1102 	char ifdescr[IFDESCRSIZE];
1103 #endif
1104 	uint64_t *media_list;
1105 	char sep;
1106 
1107 
1108 	printf("%s: ", ifname);
1109 	printb("flags", flags | (xflags << 16), IFFBITS);
1110 	if (rdomainid)
1111 		printf(" rdomain %d", rdomainid);
1112 	if (metric)
1113 		printf(" metric %lu", metric);
1114 	if (mtu)
1115 		printf(" mtu %lu", mtu);
1116 	putchar('\n');
1117 	if (sdl != NULL && sdl->sdl_alen &&
1118 	    (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
1119 		(void)printf("\tlladdr %s\n", ether_ntoa(
1120 		    (struct ether_addr *)LLADDR(sdl)));
1121 
1122 	sep = '\t';
1123 #ifndef SMALL
1124 	(void) memset(&ifrdesc, 0, sizeof(ifrdesc));
1125 	(void) strlcpy(ifrdesc.ifr_name, ifname, sizeof(ifrdesc.ifr_name));
1126 	ifrdesc.ifr_data = (caddr_t)&ifdescr;
1127 	if (ioctl(sock, SIOCGIFDESCR, &ifrdesc) == 0 &&
1128 	    strlen(ifrdesc.ifr_data))
1129 		printf("\tdescription: %s\n", ifrdesc.ifr_data);
1130 
1131 	if (sdl != NULL) {
1132 		printf("%cindex %u", sep, sdl->sdl_index);
1133 		sep = ' ';
1134 	}
1135 	if (ioctl(sock, SIOCGIFPRIORITY, &ifrdesc) == 0) {
1136 		printf("%cpriority %d", sep, ifrdesc.ifr_metric);
1137 		sep = ' ';
1138 	}
1139 #endif
1140 	printf("%cllprio %d\n", sep, llprio);
1141 
1142 	(void) memset(&ifmr, 0, sizeof(ifmr));
1143 	(void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
1144 
1145 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
1146 		/*
1147 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1148 		 */
1149 		if (ls != LINK_STATE_UNKNOWN)
1150 			printf("\tstatus: %s\n",
1151 			    get_linkstate(sdl->sdl_type, ls));
1152 		goto proto_status;
1153 	}
1154 
1155 	if (ifmr.ifm_count == 0) {
1156 		warnx("%s: no media types?", ifname);
1157 		goto proto_status;
1158 	}
1159 
1160 	media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
1161 	if (media_list == NULL)
1162 		err(1, "calloc");
1163 	ifmr.ifm_ulist = media_list;
1164 
1165 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1)
1166 		err(1, "SIOCGIFMEDIA");
1167 
1168 #ifdef SMALL
1169 	printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
1170 #else
1171 	if (ifmr.ifm_status & IFM_AVALID) {
1172 		const struct ifmedia_status_description *ifms;
1173 		int bitno, found = 0;
1174 
1175 		printf("\tstatus: ");
1176 		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1177 			for (ifms = ifm_status_descriptions;
1178 			    ifms->ifms_valid != 0; ifms++) {
1179 				if (ifms->ifms_type !=
1180 				    IFM_TYPE(ifmr.ifm_current) ||
1181 				    ifms->ifms_valid !=
1182 				    ifm_status_valid_list[bitno])
1183 					continue;
1184 				printf("%s%s", found ? ", " : "",
1185 				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1186 				found = 1;
1187 
1188 				/*
1189 				 * For each valid indicator bit, there's
1190 				 * only one entry for each media type, so
1191 				 * terminate the inner loop now.
1192 				 */
1193 				break;
1194 			}
1195 		}
1196 
1197 		if (found == 0)
1198 			printf("unknown");
1199 		putchar('\n');
1200 	}
1201 
1202 #endif
1203 	free(media_list);
1204 
1205  proto_status:
1206 	if (link == 0) {
1207 		if ((p = afp) != NULL) {
1208 			p->af_status(1);
1209 		} else for (p = afs; p->af_name; p++) {
1210 			ifr.ifr_addr.sa_family = p->af_af;
1211 			p->af_status(0);
1212 		}
1213 	}
1214 
1215 	phys_status(0);
1216 }
1217 
1218 /* ARGSUSED */
1219 void
1220 in_status(int force)
1221 {
1222 	struct sockaddr_in *sin, sin2;
1223 
1224 	getsock(AF_INET);
1225 	if (sock == -1) {
1226 		if (errno == EPROTONOSUPPORT)
1227 			return;
1228 		err(1, "socket");
1229 	}
1230 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1231 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1232 
1233 	/*
1234 	 * We keep the interface address and reset it before each
1235 	 * ioctl() so we can get ifaliases information (as opposed
1236 	 * to the primary interface netmask/dstaddr/broadaddr, if
1237 	 * the ifr_addr field is zero).
1238 	 */
1239 	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
1240 
1241 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1242 	if (ioctl(sock, SIOCGIFADDR, (caddr_t)&ifr) == -1) {
1243 		warn("SIOCGIFADDR");
1244 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1245 	}
1246 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1247 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1248 	printf("\tinet %s", inet_ntoa(sin->sin_addr));
1249 	memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1250 	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) == -1) {
1251 		if (errno != EADDRNOTAVAIL)
1252 			warn("SIOCGIFNETMASK");
1253 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1254 	} else
1255 		netmask.sin_addr =
1256 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1257 	if (flags & IFF_POINTOPOINT) {
1258 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1259 		if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) {
1260 			if (errno == EADDRNOTAVAIL)
1261 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1262 			else
1263 			    warn("SIOCGIFDSTADDR");
1264 		}
1265 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1266 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1267 		printf(" --> %s", inet_ntoa(sin->sin_addr));
1268 	}
1269 	printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
1270 	if (flags & IFF_BROADCAST) {
1271 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1272 		if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) == -1) {
1273 			if (errno == EADDRNOTAVAIL)
1274 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1275 			else
1276 			    warn("SIOCGIFBRDADDR");
1277 		}
1278 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1279 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
1280 		if (sin->sin_addr.s_addr != 0)
1281 			printf(" broadcast %s", inet_ntoa(sin->sin_addr));
1282 	}
1283 	putchar('\n');
1284 }
1285 
1286 /* ARGSUSED */
1287 void
1288 setifprefixlen(const char *addr, int d)
1289 {
1290 	setmask++;
1291 	if (afp->af_getprefix)
1292 		afp->af_getprefix(addr, MASK);
1293 	explicit_prefix = 1;
1294 }
1295 
1296 void
1297 in6_fillscopeid(struct sockaddr_in6 *sin6)
1298 {
1299 #ifdef __KAME__
1300 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1301 		sin6->sin6_scope_id =
1302 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1303 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1304 	}
1305 #endif /* __KAME__ */
1306 }
1307 
1308 /* XXX not really an alias */
1309 void
1310 in6_alias(struct in6_ifreq *creq)
1311 {
1312 	struct sockaddr_in6 *sin6;
1313 	struct	in6_ifreq ifr6;		/* shadows file static variable */
1314 	u_int32_t scopeid;
1315 	char hbuf[NI_MAXHOST];
1316 	const int niflag = NI_NUMERICHOST;
1317 
1318 	/* Get the non-alias address for this interface. */
1319 	getsock(AF_INET6);
1320 	if (sock == -1) {
1321 		if (errno == EPROTONOSUPPORT)
1322 			return;
1323 		err(1, "socket");
1324 	}
1325 
1326 	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
1327 
1328 	in6_fillscopeid(sin6);
1329 	scopeid = sin6->sin6_scope_id;
1330 	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1331 	    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1332 		strlcpy(hbuf, "", sizeof hbuf);
1333 	printf("\tinet6 %s", hbuf);
1334 
1335 	if (flags & IFF_POINTOPOINT) {
1336 		(void) memset(&ifr6, 0, sizeof(ifr6));
1337 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1338 		ifr6.ifr_addr = creq->ifr_addr;
1339 		if (ioctl(sock, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) {
1340 			if (errno != EADDRNOTAVAIL)
1341 				warn("SIOCGIFDSTADDR_IN6");
1342 			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
1343 			ifr6.ifr_addr.sin6_family = AF_INET6;
1344 			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1345 		}
1346 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1347 		in6_fillscopeid(sin6);
1348 		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1349 		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1350 			strlcpy(hbuf, "", sizeof hbuf);
1351 		printf(" -> %s", hbuf);
1352 	}
1353 
1354 	(void) memset(&ifr6, 0, sizeof(ifr6));
1355 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1356 	ifr6.ifr_addr = creq->ifr_addr;
1357 	if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) {
1358 		if (errno != EADDRNOTAVAIL)
1359 			warn("SIOCGIFNETMASK_IN6");
1360 	} else {
1361 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1362 		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
1363 		    sizeof(struct in6_addr)));
1364 	}
1365 
1366 	(void) memset(&ifr6, 0, sizeof(ifr6));
1367 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1368 	ifr6.ifr_addr = creq->ifr_addr;
1369 	if (ioctl(sock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) {
1370 		if (errno != EADDRNOTAVAIL)
1371 			warn("SIOCGIFAFLAG_IN6");
1372 	} else {
1373 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
1374 			printf(" anycast");
1375 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
1376 			printf(" tentative");
1377 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
1378 			printf(" duplicated");
1379 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
1380 			printf(" detached");
1381 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
1382 			printf(" deprecated");
1383 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
1384 			printf(" autoconf");
1385 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY)
1386 			printf(" autoconfprivacy");
1387 	}
1388 
1389 	if (scopeid)
1390 		printf(" scopeid 0x%x", scopeid);
1391 
1392 	if (Lflag) {
1393 		struct in6_addrlifetime *lifetime;
1394 
1395 		(void) memset(&ifr6, 0, sizeof(ifr6));
1396 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
1397 		ifr6.ifr_addr = creq->ifr_addr;
1398 		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
1399 		if (ioctl(sock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) {
1400 			if (errno != EADDRNOTAVAIL)
1401 				warn("SIOCGIFALIFETIME_IN6");
1402 		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
1403 			time_t t = time(NULL);
1404 
1405 			printf(" pltime ");
1406 			if (lifetime->ia6t_preferred) {
1407 				printf("%s", lifetime->ia6t_preferred < t
1408 				    ? "0" :
1409 				    sec2str(lifetime->ia6t_preferred - t));
1410 			} else
1411 				printf("infty");
1412 
1413 			printf(" vltime ");
1414 			if (lifetime->ia6t_expire) {
1415 				printf("%s", lifetime->ia6t_expire < t
1416 				    ? "0"
1417 				    : sec2str(lifetime->ia6t_expire - t));
1418 			} else
1419 				printf("infty");
1420 		}
1421 	}
1422 
1423 	printf("\n");
1424 }
1425 
1426 void
1427 in6_status(int force)
1428 {
1429 	in6_alias((struct in6_ifreq *)&ifr6);
1430 }
1431 
1432 #ifndef SMALL
1433 void
1434 settunnel(const char *src, const char *dst)
1435 {
1436 	char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport;
1437 	const char *dstip;
1438 	struct addrinfo *srcres, *dstres;
1439 	int ecode;
1440 	struct if_laddrreq req;
1441 
1442 	if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) {
1443 		/* no port or IPv6 */
1444 		dstip = dst;
1445 		dstport = NULL;
1446 	} else {
1447 		if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf))
1448 			errx(1, "%s bad value", dst);
1449 		dstport = strchr(buf, ':');
1450 		*dstport++ = '\0';
1451 		dstip = buf;
1452 	}
1453 
1454 	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
1455 		errx(1, "error in parsing address string: %s",
1456 		    gai_strerror(ecode));
1457 
1458 	if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0)
1459 		errx(1, "error in parsing address string: %s",
1460 		    gai_strerror(ecode));
1461 
1462 	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
1463 		errx(1,
1464 		    "source and destination address families do not match");
1465 
1466 	memset(&req, 0, sizeof(req));
1467 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1468 	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
1469 	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
1470 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
1471 		warn("SIOCSLIFPHYADDR");
1472 
1473 	freeaddrinfo(srcres);
1474 	freeaddrinfo(dstres);
1475 }
1476 
1477 void
1478 settunneladdr(const char *addr, int ignored)
1479 {
1480 	struct addrinfo hints, *res;
1481 	struct if_laddrreq req;
1482 	ssize_t len;
1483 	int rv;
1484 
1485 	memset(&hints, 0, sizeof(hints));
1486 	hints.ai_family = AF_UNSPEC;
1487 	hints.ai_socktype = SOCK_DGRAM;
1488 	hints.ai_protocol = 0;
1489 	hints.ai_flags = AI_PASSIVE;
1490 
1491 	rv = getaddrinfo(addr, NULL, &hints, &res);
1492 	if (rv != 0)
1493 		errx(1, "tunneladdr %s: %s", addr, gai_strerror(rv));
1494 
1495 	memset(&req, 0, sizeof(req));
1496 	len = strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
1497 	if (len >= sizeof(req.iflr_name))
1498 		errx(1, "%s: Interface name too long", ifname);
1499 
1500 	memcpy(&req.addr, res->ai_addr, res->ai_addrlen);
1501 
1502 	req.dstaddr.ss_len = 2;
1503 	req.dstaddr.ss_family = AF_UNSPEC;
1504 
1505 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
1506 		warn("tunneladdr %s", addr);
1507 
1508 	freeaddrinfo(res);
1509 }
1510 
1511 /* ARGSUSED */
1512 void
1513 deletetunnel(const char *ignored, int alsoignored)
1514 {
1515 	if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1)
1516 		warn("SIOCDIFPHYADDR");
1517 }
1518 
1519 void
1520 settunnelinst(const char *id, int param)
1521 {
1522 	const char *errmsg = NULL;
1523 	int rdomainid;
1524 
1525 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
1526 	if (errmsg)
1527 		errx(1, "rdomain %s: %s", id, errmsg);
1528 
1529 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1530 	ifr.ifr_rdomainid = rdomainid;
1531 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
1532 		warn("SIOCSLIFPHYRTABLE");
1533 }
1534 
1535 void
1536 unsettunnelinst(const char *ignored, int alsoignored)
1537 {
1538 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1539 	ifr.ifr_rdomainid = 0;
1540 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
1541 		warn("SIOCSLIFPHYRTABLE");
1542 }
1543 
1544 void
1545 settunnelttl(const char *id, int param)
1546 {
1547 	const char *errmsg = NULL;
1548 	int ttl;
1549 
1550 	if (strcmp(id, "copy") == 0)
1551 		ttl = -1;
1552 	else {
1553 		ttl = strtonum(id, 0, 0xff, &errmsg);
1554 		if (errmsg)
1555 			errx(1, "tunnelttl %s: %s", id, errmsg);
1556 	}
1557 
1558 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1559 	ifr.ifr_ttl = ttl;
1560 	if (ioctl(sock, SIOCSLIFPHYTTL, (caddr_t)&ifr) == -1)
1561 		warn("SIOCSLIFPHYTTL");
1562 }
1563 
1564 void
1565 utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
1566 {
1567 	uint16_t c;
1568 
1569 	while (outlen > 0) {
1570 		c = inlen > 0 ? letoh16(*in) : 0;
1571 		if (c == 0 || --outlen == 0) {
1572 			/* always NUL terminate result */
1573 			*out = '\0';
1574 			break;
1575 		}
1576 		*out++ = isascii(c) ? (char)c : '?';
1577 		in++;
1578 		inlen--;
1579 	}
1580 }
1581 
1582 int
1583 char_to_utf16(const char *in, uint16_t *out, size_t outlen)
1584 {
1585 	int	 n = 0;
1586 	uint16_t c;
1587 
1588 	for (;;) {
1589 		c = *in++;
1590 
1591 		if (c == '\0') {
1592 			/*
1593 			 * NUL termination is not required, but zero out the
1594 			 * residual buffer
1595 			 */
1596 			memset(out, 0, outlen);
1597 			return n;
1598 		}
1599 		if (outlen < sizeof (*out))
1600 			return -1;
1601 
1602 		*out++ = htole16(c);
1603 		n += sizeof (*out);
1604 		outlen -= sizeof (*out);
1605 	}
1606 }
1607 
1608 #endif
1609 
1610 #define SIN(x) ((struct sockaddr_in *) &(x))
1611 struct sockaddr_in *sintab[] = {
1612 SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
1613 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
1614 
1615 void
1616 in_getaddr(const char *s, int which)
1617 {
1618 	struct sockaddr_in *sin = sintab[which], tsin;
1619 	struct hostent *hp;
1620 	int bits, l;
1621 	char p[3];
1622 
1623 	bzero(&tsin, sizeof(tsin));
1624 	sin->sin_len = sizeof(*sin);
1625 	if (which != MASK)
1626 		sin->sin_family = AF_INET;
1627 
1628 	if (which == ADDR && strrchr(s, '/') != NULL &&
1629 	    (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
1630 	    sizeof(tsin.sin_addr))) != -1) {
1631 		l = snprintf(p, sizeof(p), "%d", bits);
1632 		if (l < 0 || l >= sizeof(p))
1633 			errx(1, "%d: bad prefixlen", bits);
1634 		setmask++;
1635 		in_getprefix(p, MASK);
1636 		memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
1637 	} else if (inet_aton(s, &sin->sin_addr) == 0) {
1638 		if ((hp = gethostbyname(s)))
1639 			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1640 		else
1641 			errx(1, "%s: bad value", s);
1642 	}
1643 }
1644 
1645 /* ARGSUSED */
1646 void
1647 in_getprefix(const char *plen, int which)
1648 {
1649 	struct sockaddr_in *sin = sintab[which];
1650 	const char *errmsg = NULL;
1651 	u_char *cp;
1652 	int len;
1653 
1654 	len = strtonum(plen, 0, 32, &errmsg);
1655 	if (errmsg)
1656 		errx(1, "prefix %s: %s", plen, errmsg);
1657 
1658 	sin->sin_len = sizeof(*sin);
1659 	if (which != MASK)
1660 		sin->sin_family = AF_INET;
1661 	if ((len == 0) || (len == 32)) {
1662 		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
1663 		return;
1664 	}
1665 	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
1666 	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
1667 		*cp++ = 0xff;
1668 	if (len)
1669 		*cp = 0xff << (8 - len);
1670 }
1671 
1672 /*
1673  * Print a value a la the %b format of the kernel's printf
1674  */
1675 void
1676 printb(char *s, unsigned int v, unsigned char *bits)
1677 {
1678 	int i, any = 0;
1679 	unsigned char c;
1680 
1681 	if (bits && *bits == 8)
1682 		printf("%s=%o", s, v);
1683 	else
1684 		printf("%s=%x", s, v);
1685 
1686 	if (bits) {
1687 		bits++;
1688 		putchar('<');
1689 		while ((i = *bits++)) {
1690 			if (v & (1 << (i-1))) {
1691 				if (any)
1692 					putchar(',');
1693 				any = 1;
1694 				for (; (c = *bits) > 32; bits++)
1695 					putchar(c);
1696 			} else
1697 				for (; *bits > 32; bits++)
1698 					;
1699 		}
1700 		putchar('>');
1701 	}
1702 }
1703 
1704 /*
1705  * A simple version of printb for status output
1706  */
1707 void
1708 printb_status(unsigned short v, unsigned char *bits)
1709 {
1710 	int i, any = 0;
1711 	unsigned char c;
1712 
1713 	if (bits) {
1714 		bits++;
1715 		while ((i = *bits++)) {
1716 			if (v & (1 << (i-1))) {
1717 				if (any)
1718 					putchar(',');
1719 				any = 1;
1720 				for (; (c = *bits) > 32; bits++)
1721 					putchar(tolower(c));
1722 			} else
1723 				for (; *bits > 32; bits++)
1724 					;
1725 		}
1726 	}
1727 }
1728 
1729 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
1730 struct sockaddr_in6 *sin6tab[] = {
1731 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
1732 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
1733 
1734 void
1735 in6_getaddr(const char *s, int which)
1736 {
1737 	struct sockaddr_in6 *sin6 = sin6tab[which];
1738 	struct addrinfo hints, *res;
1739 	char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
1740 	int error;
1741 
1742 	memset(&hints, 0, sizeof(hints));
1743 	hints.ai_family = AF_INET6;
1744 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
1745 
1746 	if (which == ADDR && strchr(s, '/') != NULL) {
1747 		if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1748 			errx(1, "%s: bad value", s);
1749 		pfxlen = strchr(buf, '/');
1750 		*pfxlen++ = '\0';
1751 		s = buf;
1752 		setmask++;
1753 		in6_getprefix(pfxlen, MASK);
1754 		explicit_prefix = 1;
1755 	}
1756 
1757 	error = getaddrinfo(s, "0", &hints, &res);
1758 	if (error)
1759 		errx(1, "%s: %s", s, gai_strerror(error));
1760 	memcpy(sin6, res->ai_addr, res->ai_addrlen);
1761 #ifdef __KAME__
1762 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
1763 	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
1764 	    sin6->sin6_scope_id) {
1765 		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
1766 		    htons(sin6->sin6_scope_id & 0xffff);
1767 		sin6->sin6_scope_id = 0;
1768 	}
1769 #endif /* __KAME__ */
1770 	freeaddrinfo(res);
1771 }
1772 
1773 void
1774 in6_getprefix(const char *plen, int which)
1775 {
1776 	struct sockaddr_in6 *sin6 = sin6tab[which];
1777 	const char *errmsg = NULL;
1778 	u_char *cp;
1779 	int len;
1780 
1781 	len = strtonum(plen, 0, 128, &errmsg);
1782 	if (errmsg)
1783 		errx(1, "prefix %s: %s", plen, errmsg);
1784 
1785 	sin6->sin6_len = sizeof(*sin6);
1786 	if (which != MASK)
1787 		sin6->sin6_family = AF_INET6;
1788 	if ((len == 0) || (len == 128)) {
1789 		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
1790 		return;
1791 	}
1792 	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
1793 	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
1794 		*cp++ = 0xff;
1795 	if (len)
1796 		*cp = 0xff << (8 - len);
1797 }
1798 
1799 int
1800 prefix(void *val, int size)
1801 {
1802 	u_char *nam = (u_char *)val;
1803 	int byte, bit, plen = 0;
1804 
1805 	for (byte = 0; byte < size; byte++, plen += 8)
1806 		if (nam[byte] != 0xff)
1807 			break;
1808 	if (byte == size)
1809 		return (plen);
1810 	for (bit = 7; bit != 0; bit--, plen++)
1811 		if (!(nam[byte] & (1 << bit)))
1812 			break;
1813 	for (; bit != 0; bit--)
1814 		if (nam[byte] & (1 << bit))
1815 			return (0);
1816 	byte++;
1817 	for (; byte < size; byte++)
1818 		if (nam[byte])
1819 			return (0);
1820 	return (plen);
1821 }
1822 
1823 /* Print usage and exit  */
1824 __dead void
1825 usage(void)
1826 {
1827 	fprintf(stderr,
1828 	    "usage: ifaddr interface [address_family] "
1829 	    "[address [dest_address]]\n"
1830 	    "\t\t[parameters]\n");
1831 	exit(1);
1832 }
1833 
1834 #ifndef SMALL
1835 void
1836 printifhwfeatures(const char *unused, int show)
1837 {
1838 	struct if_data ifrdat;
1839 
1840 	if (!show) {
1841 		if (showcapsflag)
1842 			usage();
1843 		showcapsflag = 1;
1844 		return;
1845 	}
1846 	bzero(&ifrdat, sizeof(ifrdat));
1847 	ifr.ifr_data = (caddr_t)&ifrdat;
1848 	if (ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr) == -1)
1849 		err(1, "SIOCGIFDATA");
1850 	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
1851 
1852 	if (ioctl(sock, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
1853 		if (ifr.ifr_hardmtu)
1854 			printf(" hardmtu %u", ifr.ifr_hardmtu);
1855 	}
1856 	putchar('\n');
1857 }
1858 #endif
1859 
1860 char *
1861 sec2str(time_t total)
1862 {
1863 	static char result[256];
1864 	char *p = result;
1865 	char *end = &result[sizeof(result)];
1866 
1867 	snprintf(p, end - p, "%lld", (long long)total);
1868 	return (result);
1869 }
1870 
1871 #ifndef SMALL
1872 void
1873 setrdomain(const char *id, int param)
1874 {
1875 	const char *errmsg = NULL;
1876 	int rdomainid;
1877 
1878 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
1879 	if (errmsg)
1880 		errx(1, "rdomain %s: %s", id, errmsg);
1881 
1882 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1883 	ifr.ifr_rdomainid = rdomainid;
1884 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
1885 		warn("SIOCSIFRDOMAIN");
1886 }
1887 
1888 void
1889 unsetrdomain(const char *ignored, int alsoignored)
1890 {
1891 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1892 	ifr.ifr_rdomainid = 0;
1893 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
1894 		warn("SIOCSIFRDOMAIN");
1895 }
1896 #endif
1897 
1898 #ifdef SMALL
1899 void
1900 setignore(const char *id, int param)
1901 {
1902 	/* just digest the command */
1903 }
1904 #endif
1905