xref: /openbsd/sbin/ifconfig/ifconfig.c (revision 5a38ef86)
1 /*	$OpenBSD: ifconfig.c,v 1.451 2021/11/23 19:13:45 kn Exp $	*/
2 /*	$NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*-
34  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to The NetBSD Foundation
38  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
39  * NASA Ames Research Center.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60  * POSSIBILITY OF SUCH DAMAGE.
61  */
62 
63 #include <sys/socket.h>
64 #include <sys/ioctl.h>
65 #include <sys/time.h>
66 
67 #include <net/if.h>
68 #include <net/if_dl.h>
69 #include <net/if_media.h>
70 #include <net/if_types.h>
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
73 #include <netinet6/in6_var.h>
74 #include <netinet6/nd6.h>
75 #include <arpa/inet.h>
76 #include <netinet/ip_ipsp.h>
77 #include <netinet/if_ether.h>
78 #include <net80211/ieee80211.h>
79 #include <net80211/ieee80211_ioctl.h>
80 #include <net/pfvar.h>
81 #include <net/if_pfsync.h>
82 #include <net/if_pflow.h>
83 #include <net/if_pppoe.h>
84 #include <net/if_trunk.h>
85 #include <net/if_wg.h>
86 #include <net/trunklacp.h>
87 #include <net/if_sppp.h>
88 #include <net/ppp_defs.h>
89 
90 #include <netinet/ip_carp.h>
91 
92 #include <netdb.h>
93 
94 #include <net/if_vlan_var.h>
95 
96 #include <netmpls/mpls.h>
97 
98 #include <ctype.h>
99 #include <err.h>
100 #include <errno.h>
101 #include <stdio.h>
102 #include <stdint.h>
103 #include <stdlib.h>
104 #include <stddef.h>
105 #include <string.h>
106 #include <unistd.h>
107 #include <limits.h>
108 #include <resolv.h>
109 #include <util.h>
110 #include <ifaddrs.h>
111 
112 #ifndef SMALL
113 #include <dev/usb/mbim.h>
114 #include <dev/usb/if_umb.h>
115 #endif /* SMALL */
116 
117 #include "ifconfig.h"
118 
119 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
120 #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
121 
122 #define HWFEATURESBITS							\
123 	"\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4"			\
124 	"\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6"			\
125 	"\11CSUM_UDPv6\20WOL"
126 
127 struct ifencap {
128 	unsigned int	 ife_flags;
129 #define IFE_VNETID_MASK		0xf
130 #define IFE_VNETID_NOPE		0x0
131 #define IFE_VNETID_NONE		0x1
132 #define IFE_VNETID_ANY		0x2
133 #define IFE_VNETID_SET		0x3
134 	int64_t		 ife_vnetid;
135 #define IFE_VNETFLOWID		0x10
136 
137 #define IFE_PARENT_MASK		0xf00
138 #define IFE_PARENT_NOPE		0x000
139 #define IFE_PARENT_NONE		0x100
140 #define IFE_PARENT_SET		0x200
141 	char		ife_parent[IFNAMSIZ];
142 
143 #define IFE_TXHPRIO_SET		0x1000
144 	int		ife_txhprio;
145 #define IFE_RXHPRIO_SET		0x2000
146 	int		ife_rxhprio;
147 };
148 
149 struct	ifreq		ifr, ridreq;
150 struct	in_aliasreq	in_addreq;
151 struct	in6_ifreq	ifr6;
152 struct	in6_ifreq	in6_ridreq;
153 struct	in6_aliasreq	in6_addreq;
154 struct	sockaddr_in	netmask;
155 
156 #ifndef SMALL
157 struct	ifaliasreq	addreq;
158 
159 int	wconfig = 0;
160 int	wcwconfig = 0;
161 int	rdomainid;
162 #endif /* SMALL */
163 
164 char	ifname[IFNAMSIZ];
165 int	flags, xflags, setaddr, setipdst, doalias;
166 u_long	metric, mtu;
167 int	llprio;
168 int	clearaddr, sock;
169 int	newaddr = 0;
170 int	af = AF_INET;
171 int	explicit_prefix = 0;
172 int	Lflag = 1;
173 int	show_join = 0;
174 
175 int	showmediaflag;
176 int	showcapsflag;
177 int	shownet80211chans;
178 int	shownet80211nodes;
179 int	showclasses;
180 int	showtransceiver;
181 
182 struct	ifencap;
183 
184 struct ieee80211_join join;
185 
186 const	char *lacpmodeactive = "active";
187 const	char *lacpmodepassive = "passive";
188 const	char *lacptimeoutfast = "fast";
189 const	char *lacptimeoutslow = "slow";
190 
191 void	notealias(const char *, int);
192 void	setifaddr(const char *, int);
193 void	setiflladdr(const char *, int);
194 void	setifdstaddr(const char *, int);
195 void	setifflags(const char *, int);
196 void	setifxflags(const char *, int);
197 void	addaf(const char *, int);
198 void	removeaf(const char *, int);
199 void	setifbroadaddr(const char *, int);
200 void	setifmtu(const char *, int);
201 void	setifllprio(const char *, int);
202 void	setifnwid(const char *, int);
203 void	setifjoin(const char *, int);
204 void	delifjoin(const char *, int);
205 void	delifjoinlist(const char *, int);
206 void	showjoin(const char *, int);
207 void	setifbssid(const char *, int);
208 void	setifnwkey(const char *, int);
209 void	setifwpa(const char *, int);
210 void	setifwpaprotos(const char *, int);
211 void	setifwpaakms(const char *, int);
212 void	setifwpaciphers(const char *, int);
213 void	setifwpagroupcipher(const char *, int);
214 void	setifwpakey(const char *, int);
215 void	setifchan(const char *, int);
216 void	setifscan(const char *, int);
217 void	setifnwflag(const char *, int);
218 void	unsetifnwflag(const char *, int);
219 void	setifnetmask(const char *, int);
220 void	setifprefixlen(const char *, int);
221 void	setvnetid(const char *, int);
222 void	delvnetid(const char *, int);
223 void	getvnetid(struct ifencap *);
224 void	setifparent(const char *, int);
225 void	delifparent(const char *, int);
226 void	getifparent(struct ifencap *);
227 void	getencap(void);
228 void	setia6flags(const char *, int);
229 void	setia6pltime(const char *, int);
230 void	setia6vltime(const char *, int);
231 void	setia6lifetime(const char *, const char *);
232 void	setia6eui64(const char *, int);
233 void	setmedia(const char *, int);
234 void	setmediaopt(const char *, int);
235 void	setmediamode(const char *, int);
236 void	unsetmediamode(const char *, int);
237 void	clone_create(const char *, int);
238 void	clone_destroy(const char *, int);
239 void	unsetmediaopt(const char *, int);
240 void	setmediainst(const char *, int);
241 int	prefix(void *val, int);
242 void	getifgroups(void);
243 void	setifgroup(const char *, int);
244 void	unsetifgroup(const char *, int);
245 void	setgroupattribs(char *, int, char *[]);
246 int	printgroup(char *, int);
247 void	setautoconf(const char *, int);
248 void	settemporary(const char *, int);
249 void	settrunkport(const char *, int);
250 void	unsettrunkport(const char *, int);
251 void	settrunkproto(const char *, int);
252 void	settrunklacpmode(const char *, int);
253 void	settrunklacptimeout(const char *, int);
254 void	trunk_status(void);
255 void	list_cloners(void);
256 
257 #ifndef SMALL
258 void	setifrtlabel(const char *, int);
259 void	setrdomain(const char *, int);
260 void	unsetrdomain(const char *, int);
261 void	setkeepalive(const char *, const char *);
262 void	unsetkeepalive(const char *, int);
263 void	carp_status(void);
264 void	setcarp_advbase(const char *,int);
265 void	setcarp_advskew(const char *, int);
266 void	setcarppeer(const char *, int);
267 void	unsetcarppeer(const char *, int);
268 void	setcarp_passwd(const char *, int);
269 void	setcarp_vhid(const char *, int);
270 void	setcarp_state(const char *, int);
271 void	setcarpdev(const char *, int);
272 void	setcarp_nodes(const char *, int);
273 void	setcarp_balancing(const char *, int);
274 void	setpfsync_syncdev(const char *, int);
275 void	setpfsync_maxupd(const char *, int);
276 void	unsetpfsync_syncdev(const char *, int);
277 void	setpfsync_syncpeer(const char *, int);
278 void	unsetpfsync_syncpeer(const char *, int);
279 void	setpfsync_defer(const char *, int);
280 void	pfsync_status(void);
281 void	setvnetflowid(const char *, int);
282 void	delvnetflowid(const char *, int);
283 void	getvnetflowid(struct ifencap *);
284 void	gettxprio(struct ifencap *);
285 void	settxprio(const char *, int);
286 void	getrxprio(struct ifencap *);
287 void	setrxprio(const char *, int);
288 void	setmplslabel(const char *, int);
289 void	unsetmplslabel(const char *, int);
290 void	setpwe3cw(const char *, int);
291 void	unsetpwe3cw(const char *, int);
292 void	setpwe3fat(const char *, int);
293 void	unsetpwe3fat(const char *, int);
294 void	setpwe3neighbor(const char *, const char *);
295 void	unsetpwe3neighbor(const char *, int);
296 void	mpls_status(void);
297 void	settunnel(const char *, const char *);
298 void	settunneladdr(const char *, int);
299 void	deletetunnel(const char *, int);
300 void	settunnelinst(const char *, int);
301 void	unsettunnelinst(const char *, int);
302 void	settunnelttl(const char *, int);
303 void	settunneldf(const char *, int);
304 void	settunnelnodf(const char *, int);
305 void	settunnelecn(const char *, int);
306 void	settunnelnoecn(const char *, int);
307 void	setpppoe_dev(const char *,int);
308 void	setpppoe_svc(const char *,int);
309 void	setpppoe_ac(const char *,int);
310 void	pppoe_status(void);
311 void	setspppproto(const char *, int);
312 void	setspppname(const char *, int);
313 void	setspppkey(const char *, int);
314 void	setsppppeerproto(const char *, int);
315 void	setsppppeername(const char *, int);
316 void	setsppppeerkey(const char *, int);
317 void	setsppppeerflag(const char *, int);
318 void	unsetsppppeerflag(const char *, int);
319 void	sppp_status(void);
320 void	sppp_printproto(const char *, struct sauthreq *);
321 void	setifpriority(const char *, int);
322 void	setifpowersave(const char *, int);
323 void	setifmetric(const char *, int);
324 void	pflow_status(void);
325 void	pflow_addr(const char*, struct sockaddr_storage *);
326 void	setpflow_sender(const char *, int);
327 void	unsetpflow_sender(const char *, int);
328 void	setpflow_receiver(const char *, int);
329 void	unsetpflow_receiver(const char *, int);
330 void	setpflowproto(const char *, int);
331 void	setifipdst(const char *, int);
332 void	setifdesc(const char *, int);
333 void	unsetifdesc(const char *, int);
334 void	printifhwfeatures(const char *, int);
335 void	setpair(const char *, int);
336 void	unsetpair(const char *, int);
337 void	umb_status(void);
338 void	umb_printclasses(char *, int);
339 int	umb_parse_classes(const char *);
340 void	umb_setpin(const char *, int);
341 void	umb_chgpin(const char *, const char *);
342 void	umb_puk(const char *, const char *);
343 void	umb_pinop(int, int, const char *, const char *);
344 void	umb_apn(const char *, int);
345 void	umb_setclass(const char *, int);
346 void	umb_roaming(const char *, int);
347 void	utf16_to_char(uint16_t *, int, char *, size_t);
348 int	char_to_utf16(const char *, uint16_t *, size_t);
349 void	transceiver(const char *, int);
350 void	transceiverdump(const char *, int);
351 
352 /* WG */
353 void	setwgpeer(const char *, int);
354 void	setwgpeerep(const char *, const char *);
355 void	setwgpeeraip(const char *, int);
356 void	setwgpeerpsk(const char *, int);
357 void	setwgpeerpka(const char *, int);
358 void	setwgport(const char *, int);
359 void	setwgkey(const char *, int);
360 void	setwgrtable(const char *, int);
361 
362 void	unsetwgpeer(const char *, int);
363 void	unsetwgpeerpsk(const char *, int);
364 void	unsetwgpeerall(const char *, int);
365 
366 void	wg_status();
367 #else
368 void	setignore(const char *, int);
369 #endif
370 
371 /*
372  * Media stuff.  Whenever a media command is first performed, the
373  * currently select media is grabbed for this interface.  If `media'
374  * is given, the current media word is modified.  `mediaopt' commands
375  * only modify the set and clear words.  They then operate on the
376  * current media word later.
377  */
378 uint64_t	media_current;
379 uint64_t	mediaopt_set;
380 uint64_t	mediaopt_clear;
381 
382 int	actions;			/* Actions performed */
383 
384 #define	A_MEDIA		0x0001		/* media command */
385 #define	A_MEDIAOPTSET	0x0002		/* mediaopt command */
386 #define	A_MEDIAOPTCLR	0x0004		/* -mediaopt command */
387 #define	A_MEDIAOPT	(A_MEDIAOPTSET|A_MEDIAOPTCLR)
388 #define	A_MEDIAINST	0x0008		/* instance or inst command */
389 #define	A_MEDIAMODE	0x0010		/* mode command */
390 #define	A_JOIN		0x0020		/* join */
391 #define	A_WIREGUARD	0x0040		/* any WireGuard command */
392 #define A_SILENT	0x8000000	/* doing operation, do not print */
393 
394 #define	NEXTARG0	0xffffff
395 #define NEXTARG		0xfffffe
396 #define	NEXTARG2	0xfffffd
397 
398 const struct	cmd {
399 	char	*c_name;
400 	int	c_parameter;		/* NEXTARG means next argv */
401 	int	c_action;		/* defered action */
402 	void	(*c_func)(const char *, int);
403 	void	(*c_func2)(const char *, const char *);
404 } cmds[] = {
405 	{ "up",		IFF_UP,		0,		setifflags } ,
406 	{ "down",	-IFF_UP,	0,		setifflags },
407 	{ "arp",	-IFF_NOARP,	0,		setifflags },
408 	{ "-arp",	IFF_NOARP,	0,		setifflags },
409 	{ "debug",	IFF_DEBUG,	0,		setifflags },
410 	{ "-debug",	-IFF_DEBUG,	0,		setifflags },
411 	{ "alias",	IFF_UP,		0,		notealias },
412 	{ "-alias",	-IFF_UP,	0,		notealias },
413 	{ "delete",	-IFF_UP,	0,		notealias },
414 	{ "netmask",	NEXTARG,	0,		setifnetmask },
415 	{ "mtu",	NEXTARG,	0,		setifmtu },
416 	{ "nwid",	NEXTARG,	0,		setifnwid },
417 	{ "-nwid",	-1,		0,		setifnwid },
418 	{ "join",	NEXTARG,	0,		setifjoin },
419 	{ "-join",	NEXTARG,	0,		delifjoin },
420 	{ "joinlist",	NEXTARG0,	0,		showjoin },
421 	{ "-joinlist",	-1,		0,		delifjoinlist },
422 	{ "bssid",	NEXTARG,	0,		setifbssid },
423 	{ "-bssid",	-1,		0,		setifbssid },
424 	{ "nwkey",	NEXTARG,	0,		setifnwkey },
425 	{ "-nwkey",	-1,		0,		setifnwkey },
426 	{ "wpa",	1,		0,		setifwpa },
427 	{ "-wpa",	0,		0,		setifwpa },
428 	{ "wpaakms",	NEXTARG,	0,		setifwpaakms },
429 	{ "wpaciphers",	NEXTARG,	0,		setifwpaciphers },
430 	{ "wpagroupcipher", NEXTARG,	0,		setifwpagroupcipher },
431 	{ "wpaprotos",	NEXTARG,	0,		setifwpaprotos },
432 	{ "wpakey",	NEXTARG,	0,		setifwpakey },
433 	{ "-wpakey",	-1,		0,		setifwpakey },
434 	{ "chan",	NEXTARG0,	0,		setifchan },
435 	{ "-chan",	-1,		0,		setifchan },
436 	{ "scan",	NEXTARG0,	0,		setifscan },
437 	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
438 	{ "prefixlen",  NEXTARG,	0,		setifprefixlen},
439 	{ "vnetid",	NEXTARG,	0,		setvnetid },
440 	{ "-vnetid",	0,		0,		delvnetid },
441 	{ "parent",	NEXTARG,	0,		setifparent },
442 	{ "-parent",	1,		0,		delifparent },
443 	{ "vlan",	NEXTARG,	0,		setvnetid },
444 	{ "-vlan",	0,		0,		delvnetid },
445 	{ "vlandev",	NEXTARG,	0,		setifparent },
446 	{ "-vlandev",	1,		0,		delifparent },
447 	{ "group",	NEXTARG,	0,		setifgroup },
448 	{ "-group",	NEXTARG,	0,		unsetifgroup },
449 	{ "autoconf",	1,		0,		setautoconf },
450 	{ "-autoconf",	-1,		0,		setautoconf },
451 	{ "trunkport",	NEXTARG,	0,		settrunkport },
452 	{ "-trunkport",	NEXTARG,	0,		unsettrunkport },
453 	{ "trunkproto",	NEXTARG,	0,		settrunkproto },
454 	{ "lacpmode",	NEXTARG,	0,		settrunklacpmode },
455 	{ "lacptimeout", NEXTARG,	0,		settrunklacptimeout },
456 	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
457 	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
458 	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
459 	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
460 	{ "pltime",	NEXTARG,	0,		setia6pltime },
461 	{ "vltime",	NEXTARG,	0,		setia6vltime },
462 	{ "eui64",	0,		0,		setia6eui64 },
463 	{ "temporary",	1,		0,		settemporary },
464 	{ "-temporary",	-1,		0,		settemporary },
465 	{ "soii",	-IFXF_INET6_NOSOII,	0,	setifxflags },
466 	{ "-soii",	IFXF_INET6_NOSOII,	0,	setifxflags },
467 	{ "monitor",	IFXF_MONITOR,	0,		setifxflags },
468 	{ "-monitor",	-IFXF_MONITOR,	0,		setifxflags },
469 #ifndef SMALL
470 	{ "hwfeatures", NEXTARG0,	0,		printifhwfeatures },
471 	{ "metric",	NEXTARG,	0,		setifmetric },
472 	{ "powersave",	NEXTARG0,	0,		setifpowersave },
473 	{ "-powersave",	-1,		0,		setifpowersave },
474 	{ "priority",	NEXTARG,	0,		setifpriority },
475 	{ "rtlabel",	NEXTARG,	0,		setifrtlabel },
476 	{ "-rtlabel",	-1,		0,		setifrtlabel },
477 	{ "rdomain",	NEXTARG,	0,		setrdomain },
478 	{ "-rdomain",	0,		0,		unsetrdomain },
479 	{ "staticarp",	IFF_STATICARP,	0,		setifflags },
480 	{ "-staticarp",	-IFF_STATICARP,	0,		setifflags },
481 	{ "mpls",	IFXF_MPLS,	0,		setifxflags },
482 	{ "-mpls",	-IFXF_MPLS,	0,		setifxflags },
483 	{ "mplslabel",	NEXTARG,	0,		setmplslabel },
484 	{ "-mplslabel",	0,		0,		unsetmplslabel },
485 	{ "pwecw",	0,		0,		setpwe3cw },
486 	{ "-pwecw",	0,		0,		unsetpwe3cw },
487 	{ "pwefat",	0,		0,		setpwe3fat },
488 	{ "-pwefat",	0,		0,		unsetpwe3fat },
489 	{ "pweneighbor", NEXTARG2,	0,		NULL, setpwe3neighbor },
490 	{ "-pweneighbor", 0,		0,		unsetpwe3neighbor },
491 	{ "advbase",	NEXTARG,	0,		setcarp_advbase },
492 	{ "advskew",	NEXTARG,	0,		setcarp_advskew },
493 	{ "carppeer",	NEXTARG,	0,		setcarppeer },
494 	{ "-carppeer",	1,		0,		unsetcarppeer },
495 	{ "pass",	NEXTARG,	0,		setcarp_passwd },
496 	{ "vhid",	NEXTARG,	0,		setcarp_vhid },
497 	{ "state",	NEXTARG,	0,		setcarp_state },
498 	{ "carpdev",	NEXTARG,	0,		setcarpdev },
499 	{ "carpnodes",	NEXTARG,	0,		setcarp_nodes },
500 	{ "balancing",	NEXTARG,	0,		setcarp_balancing },
501 	{ "syncdev",	NEXTARG,	0,		setpfsync_syncdev },
502 	{ "-syncdev",	1,		0,		unsetpfsync_syncdev },
503 	{ "syncif",	NEXTARG,	0,		setpfsync_syncdev },
504 	{ "-syncif",	1,		0,		unsetpfsync_syncdev },
505 	{ "syncpeer",	NEXTARG,	0,		setpfsync_syncpeer },
506 	{ "-syncpeer",	1,		0,		unsetpfsync_syncpeer },
507 	{ "maxupd",	NEXTARG,	0,		setpfsync_maxupd },
508 	{ "defer",	1,		0,		setpfsync_defer },
509 	{ "-defer",	0,		0,		setpfsync_defer },
510 	{ "tunnel",	NEXTARG2,	0,		NULL, settunnel },
511 	{ "tunneladdr",	NEXTARG,	0,		settunneladdr },
512 	{ "-tunnel",	0,		0,		deletetunnel },
513 	{ "tunneldomain", NEXTARG,	0,		settunnelinst },
514 	{ "-tunneldomain", 0,		0,		unsettunnelinst },
515 	{ "tunnelttl",	NEXTARG,	0,		settunnelttl },
516 	{ "tunneldf",	0,		0,		settunneldf },
517 	{ "-tunneldf",	0,		0,		settunnelnodf },
518 	{ "tunnelecn",	0,		0,		settunnelecn },
519 	{ "-tunnelecn",	0,		0,		settunnelnoecn },
520 	{ "vnetflowid",	0,		0,		setvnetflowid },
521 	{ "-vnetflowid", 0,		0,		delvnetflowid },
522 	{ "txprio",	NEXTARG,	0,		settxprio },
523 	{ "rxprio",	NEXTARG,	0,		setrxprio },
524 	{ "pppoedev",	NEXTARG,	0,		setpppoe_dev },
525 	{ "pppoesvc",	NEXTARG,	0,		setpppoe_svc },
526 	{ "-pppoesvc",	1,		0,		setpppoe_svc },
527 	{ "pppoeac",	NEXTARG,	0,		setpppoe_ac },
528 	{ "-pppoeac",	1,		0,		setpppoe_ac },
529 	{ "authproto",	NEXTARG,	0,		setspppproto },
530 	{ "authname",	NEXTARG,	0,		setspppname },
531 	{ "authkey",	NEXTARG,	0,		setspppkey },
532 	{ "peerproto",	NEXTARG,	0,		setsppppeerproto },
533 	{ "peername",	NEXTARG,	0,		setsppppeername },
534 	{ "peerkey",	NEXTARG,	0,		setsppppeerkey },
535 	{ "peerflag",	NEXTARG,	0,		setsppppeerflag },
536 	{ "-peerflag",	NEXTARG,	0,		unsetsppppeerflag },
537 	{ "nwflag",	NEXTARG,	0,		setifnwflag },
538 	{ "-nwflag",	NEXTARG,	0,		unsetifnwflag },
539 	{ "flowsrc",	NEXTARG,	0,		setpflow_sender },
540 	{ "-flowsrc",	1,		0,		unsetpflow_sender },
541 	{ "flowdst",	NEXTARG,	0,		setpflow_receiver },
542 	{ "-flowdst", 1,		0,		unsetpflow_receiver },
543 	{ "pflowproto", NEXTARG,	0,		setpflowproto },
544 	{ "-inet",	AF_INET,	0,		removeaf },
545 	{ "-inet6",	AF_INET6,	0,		removeaf },
546 	{ "keepalive",	NEXTARG2,	0,		NULL, setkeepalive },
547 	{ "-keepalive",	1,		0,		unsetkeepalive },
548 	{ "add",	NEXTARG,	0,		bridge_add },
549 	{ "del",	NEXTARG,	0,		bridge_delete },
550 	{ "addspan",	NEXTARG,	0,		bridge_addspan },
551 	{ "delspan",	NEXTARG,	0,		bridge_delspan },
552 	{ "discover",	NEXTARG,	0,		setdiscover },
553 	{ "-discover",	NEXTARG,	0,		unsetdiscover },
554 	{ "blocknonip", NEXTARG,	0,		setblocknonip },
555 	{ "-blocknonip",NEXTARG,	0,		unsetblocknonip },
556 	{ "learn",	NEXTARG,	0,		setlearn },
557 	{ "-learn",	NEXTARG,	0,		unsetlearn },
558 	{ "stp",	NEXTARG,	0,		setstp },
559 	{ "-stp",	NEXTARG,	0,		unsetstp },
560 	{ "edge",	NEXTARG,	0,		setedge },
561 	{ "-edge",	NEXTARG,	0,		unsetedge },
562 	{ "autoedge",	NEXTARG,	0,		setautoedge },
563 	{ "-autoedge",	NEXTARG,	0,		unsetautoedge },
564 	{ "protected",	NEXTARG2,	0,		NULL, bridge_protect },
565 	{ "-protected",	NEXTARG,	0,		bridge_unprotect },
566 	{ "ptp",	NEXTARG,	0,		setptp },
567 	{ "-ptp",	NEXTARG,	0,		unsetptp },
568 	{ "autoptp",	NEXTARG,	0,		setautoptp },
569 	{ "-autoptp",	NEXTARG,	0,		unsetautoptp },
570 	{ "flush",	0,		0,		bridge_flush },
571 	{ "flushall",	0,		0,		bridge_flushall },
572 	{ "static",	NEXTARG2,	0,		NULL, bridge_addaddr },
573 	{ "deladdr",	NEXTARG,	0,		bridge_deladdr },
574 	{ "maxaddr",	NEXTARG,	0,		bridge_maxaddr },
575 	{ "addr",	0,		0,		bridge_addrs },
576 	{ "hellotime",	NEXTARG,	0,		bridge_hellotime },
577 	{ "fwddelay",	NEXTARG,	0,		bridge_fwddelay },
578 	{ "maxage",	NEXTARG,	0,		bridge_maxage },
579 	{ "proto",	NEXTARG,	0,		bridge_proto },
580 	{ "ifpriority",	NEXTARG2,	0,		NULL, bridge_ifprio },
581 	{ "ifcost",	NEXTARG2,	0,		NULL, bridge_ifcost },
582 	{ "-ifcost",	NEXTARG,	0,		bridge_noifcost },
583 	{ "timeout",	NEXTARG,	0,		bridge_timeout },
584 	{ "holdcnt",	NEXTARG,	0,		bridge_holdcnt },
585 	{ "spanpriority", NEXTARG,	0,		bridge_priority },
586 	{ "ipdst",	NEXTARG,	0,		setifipdst },
587 #if 0
588 	/* XXX `rule` special-cased below */
589 	{ "rule",	0,		0,		bridge_rule },
590 #endif
591 	{ "rules",	NEXTARG,	0,		bridge_rules },
592 	{ "rulefile",	NEXTARG,	0,		bridge_rulefile },
593 	{ "flushrule",	NEXTARG,	0,		bridge_flushrule },
594 	{ "description", NEXTARG,	0,		setifdesc },
595 	{ "descr",	NEXTARG,	0,		setifdesc },
596 	{ "-description", 1,		0,		unsetifdesc },
597 	{ "-descr",	1,		0,		unsetifdesc },
598 	{ "wol",	IFXF_WOL,	0,		setifxflags },
599 	{ "-wol",	-IFXF_WOL,	0,		setifxflags },
600 	{ "pin",	NEXTARG,	0,		umb_setpin },
601 	{ "chgpin",	NEXTARG2,	0,		NULL, umb_chgpin },
602 	{ "puk",	NEXTARG2,	0,		NULL, umb_puk },
603 	{ "apn",	NEXTARG,	0,		umb_apn },
604 	{ "-apn",	-1,		0,		umb_apn },
605 	{ "class",	NEXTARG0,	0,		umb_setclass },
606 	{ "-class",	-1,		0,		umb_setclass },
607 	{ "roaming",	1,		0,		umb_roaming },
608 	{ "-roaming",	0,		0,		umb_roaming },
609 	{ "patch",	NEXTARG,	0,		setpair },
610 	{ "-patch",	1,		0,		unsetpair },
611 	{ "addlocal",	NEXTARG,	0,		addlocal },
612 	{ "transceiver", NEXTARG0,	0,		transceiver },
613 	{ "sff",	NEXTARG0,	0,		transceiver },
614 	{ "sffdump",	0,		0,		transceiverdump },
615 
616 	{ "wgpeer",	NEXTARG,	A_WIREGUARD,	setwgpeer},
617 	{ "wgendpoint",	NEXTARG2,	A_WIREGUARD,	NULL,	setwgpeerep},
618 	{ "wgaip",	NEXTARG,	A_WIREGUARD,	setwgpeeraip},
619 	{ "wgpsk",	NEXTARG,	A_WIREGUARD,	setwgpeerpsk},
620 	{ "wgpka",	NEXTARG,	A_WIREGUARD,	setwgpeerpka},
621 	{ "wgport",	NEXTARG,	A_WIREGUARD,	setwgport},
622 	{ "wgkey",	NEXTARG,	A_WIREGUARD,	setwgkey},
623 	{ "wgrtable",	NEXTARG,	A_WIREGUARD,	setwgrtable},
624 	{ "-wgpeer",	NEXTARG,	A_WIREGUARD,	unsetwgpeer},
625 	{ "-wgpsk",	0,		A_WIREGUARD,	unsetwgpeerpsk},
626 	{ "-wgpeerall",	0,		A_WIREGUARD,	unsetwgpeerall},
627 
628 #else /* SMALL */
629 	{ "powersave",	NEXTARG0,	0,		setignore },
630 	{ "priority",	NEXTARG,	0,		setignore },
631 	{ "rtlabel",	NEXTARG,	0,		setignore },
632 	{ "mpls",	IFXF_MPLS,	0,		setignore },
633 	{ "nwflag",	NEXTARG,	0,		setignore },
634 	{ "rdomain",	NEXTARG,	0,		setignore },
635 	{ "-inet",	AF_INET,	0,		removeaf },
636 	{ "-inet6",	AF_INET6,	0,		removeaf },
637 	{ "description", NEXTARG,	0,		setignore },
638 	{ "descr",	NEXTARG,	0,		setignore },
639 	{ "wol",	IFXF_WOL,	0,		setignore },
640 	{ "-wol",	-IFXF_WOL,	0,		setignore },
641 #endif /* SMALL */
642 #if 0
643 	/* XXX `create' special-cased below */
644 	{ "create",	0,		0,		clone_create } ,
645 #endif
646 	{ "destroy",	0,		0,		clone_destroy } ,
647 	{ "link0",	IFF_LINK0,	0,		setifflags } ,
648 	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
649 	{ "link1",	IFF_LINK1,	0,		setifflags } ,
650 	{ "-link1",	-IFF_LINK1,	0,		setifflags } ,
651 	{ "link2",	IFF_LINK2,	0,		setifflags } ,
652 	{ "-link2",	-IFF_LINK2,	0,		setifflags } ,
653 	{ "media",	NEXTARG0,	A_MEDIA,	setmedia },
654 	{ "mediaopt",	NEXTARG,	A_MEDIAOPTSET,	setmediaopt },
655 	{ "-mediaopt",	NEXTARG,	A_MEDIAOPTCLR,	unsetmediaopt },
656 	{ "mode",	NEXTARG,	A_MEDIAMODE,	setmediamode },
657 	{ "-mode",	0,		A_MEDIAMODE,	unsetmediamode },
658 	{ "instance",	NEXTARG,	A_MEDIAINST,	setmediainst },
659 	{ "inst",	NEXTARG,	A_MEDIAINST,	setmediainst },
660 	{ "lladdr",	NEXTARG,	0,		setiflladdr },
661 	{ "llprio",	NEXTARG,	0,		setifllprio },
662 	{ NULL, /*src*/	0,		0,		setifaddr },
663 	{ NULL, /*dst*/	0,		0,		setifdstaddr },
664 	{ NULL, /*illegal*/0,		0,		NULL },
665 };
666 
667 #define	IFFBITS								\
668 	"\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6STATICARP"	\
669 	"\7RUNNING\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX"	\
670 	"\15LINK0\16LINK1\17LINK2\20MULTICAST"				\
671 	"\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII"	\
672 	"\30AUTOCONF4" "\31MONITOR"
673 
674 int	getinfo(struct ifreq *, int);
675 void	getsock(int);
676 void	printgroupattribs(char *);
677 void	printif(char *, int);
678 void	printb_status(unsigned short, unsigned char *);
679 const char *get_linkstate(int, int);
680 void	status(int, struct sockaddr_dl *, int);
681 __dead void	usage(void);
682 const char *get_string(const char *, const char *, u_int8_t *, int *);
683 int	len_string(const u_int8_t *, int);
684 int	print_string(const u_int8_t *, int);
685 char	*sec2str(time_t);
686 
687 const char *get_media_type_string(uint64_t);
688 const char *get_media_subtype_string(uint64_t);
689 uint64_t	get_media_mode(uint64_t, const char *);
690 uint64_t	get_media_subtype(uint64_t, const char *);
691 uint64_t	get_media_options(uint64_t, const char *);
692 uint64_t	lookup_media_word(const struct ifmedia_description *, uint64_t,
693 	    const char *);
694 void	print_media_word(uint64_t, int, int);
695 void	process_media_commands(void);
696 void	init_current_media(void);
697 
698 void	process_join_commands(void);
699 
700 void	process_wg_commands(void);
701 
702 unsigned long get_ts_map(int, int, int);
703 
704 void	in_status(int);
705 void	in_getaddr(const char *, int);
706 void	in_getprefix(const char *, int);
707 void	in6_fillscopeid(struct sockaddr_in6 *);
708 void	in6_alias(struct in6_ifreq *);
709 void	in6_status(int);
710 void	in6_getaddr(const char *, int);
711 void	in6_getprefix(const char *, int);
712 void	ieee80211_status(void);
713 void	join_status(void);
714 void	ieee80211_listchans(void);
715 void	ieee80211_listnodes(void);
716 void	ieee80211_printnode(struct ieee80211_nodereq *);
717 u_int	getwpacipher(const char *);
718 void	print_cipherset(u_int32_t);
719 
720 void	spppauthinfo(struct sauthreq *, int);
721 void	spppdnsinfo(struct sdnsreq *);
722 
723 /* Known address families */
724 const struct afswtch {
725 	char *af_name;
726 	short af_af;
727 	void (*af_status)(int);
728 	void (*af_getaddr)(const char *, int);
729 	void (*af_getprefix)(const char *, int);
730 	u_long af_difaddr;
731 	u_long af_aifaddr;
732 	caddr_t af_ridreq;
733 	caddr_t af_addreq;
734 } afs[] = {
735 #define C(x) ((caddr_t) &x)
736 	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
737 	    SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) },
738 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
739 	    SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
740 	{ 0,	0,	    0,		0 }
741 };
742 
743 const struct afswtch *afp;	/*the address family being set or asked about*/
744 
745 char joinname[IEEE80211_NWID_LEN];
746 size_t joinlen;
747 char nwidname[IEEE80211_NWID_LEN];
748 size_t nwidlen;
749 
750 int ifaliases = 0;
751 int aflag = 0;
752 
753 int
754 main(int argc, char *argv[])
755 {
756 	const struct afswtch *rafp = NULL;
757 	int create = 0;
758 	int Cflag = 0;
759 	int gflag = 0;
760 	int found_rulefile = 0;
761 	int i;
762 
763 	/* If no args at all, print all interfaces.  */
764 	if (argc < 2) {
765 		/* no filesystem visibility */
766 		if (unveil("/", "") == -1)
767 			err(1, "unveil /");
768 		if (unveil(NULL, NULL) == -1)
769 			err(1, "unveil");
770 		aflag = 1;
771 		printif(NULL, 0);
772 		return (0);
773 	}
774 	argc--, argv++;
775 	if (*argv[0] == '-') {
776 		int nomore = 0;
777 
778 		for (i = 1; argv[0][i]; i++) {
779 			switch (argv[0][i]) {
780 			case 'a':
781 				aflag = 1;
782 				nomore = 1;
783 				break;
784 			case 'A':
785 				aflag = 1;
786 				ifaliases = 1;
787 				nomore = 1;
788 				break;
789 			case 'g':
790 				gflag = 1;
791 				break;
792 			case 'C':
793 				Cflag = 1;
794 				nomore = 1;
795 				break;
796 			default:
797 				usage();
798 				break;
799 			}
800 		}
801 		if (nomore == 0) {
802 			argc--, argv++;
803 			if (argc < 1)
804 				usage();
805 			if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
806 				errx(1, "interface name '%s' too long", *argv);
807 		}
808 	} else if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
809 		errx(1, "interface name '%s' too long", *argv);
810 	argc--, argv++;
811 
812 	for (i = 0; i < argc; i++) {
813 		if (strcmp(argv[i], "rulefile") == 0) {
814 			found_rulefile = 1;
815 			break;
816 		}
817 	}
818 
819 	if (!found_rulefile) {
820 		if (unveil(_PATH_RESCONF, "r") == -1)
821 			err(1, "unveil %s", _PATH_RESCONF);
822 		if (unveil(_PATH_HOSTS, "r") == -1)
823 			err(1, "unveil %s", _PATH_HOSTS);
824 		if (unveil(_PATH_SERVICES, "r") == -1)
825 			err(1, "unveil %s", _PATH_SERVICES);
826 		if (unveil(NULL, NULL) == -1)
827 			err(1, "unveil");
828 	}
829 
830 	if (argc > 0) {
831 		for (afp = rafp = afs; rafp->af_name; rafp++)
832 			if (strcmp(rafp->af_name, *argv) == 0) {
833 				afp = rafp;
834 				argc--;
835 				argv++;
836 				break;
837 			}
838 		rafp = afp;
839 		af = ifr.ifr_addr.sa_family = rafp->af_af;
840 	}
841 	if (Cflag) {
842 		if (argc > 0 || aflag)
843 			usage();
844 		list_cloners();
845 		return (0);
846 	}
847 	if (gflag) {
848 		if (argc == 0)
849 			printgroupattribs(ifname);
850 		else
851 			setgroupattribs(ifname, argc, argv);
852 		return (0);
853 	}
854 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
855 
856 	/* initialization */
857 	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
858 	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
859 
860 	/*
861 	 * NOTE:  We must special-case the `create' command right
862 	 * here as we would otherwise fail in getinfo().
863 	 */
864 	if (argc > 0 && strcmp(argv[0], "create") == 0) {
865 		clone_create(argv[0], 0);
866 		argc--, argv++;
867 		if (argc == 0)
868 			return (0);
869 	}
870 	if (aflag == 0) {
871 		create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
872 		(void)getinfo(&ifr, create);
873 	}
874 
875 	if (argc != 0 && af == AF_INET6)
876 		addaf(ifname, AF_INET6);
877 
878 	while (argc > 0) {
879 		const struct cmd *p;
880 
881 		for (p = cmds; p->c_name; p++)
882 			if (strcmp(*argv, p->c_name) == 0)
883 				break;
884 #ifndef SMALL
885 		if (strcmp(*argv, "rule") == 0) {
886 			argc--, argv++;
887 			return bridge_rule(argc, argv, -1);
888 		}
889 #endif
890 		if (p->c_name == 0 && setaddr)
891 			for (i = setaddr; i > 0; i--) {
892 				p++;
893 				if (p->c_func == NULL)
894 					errx(1, "%s: bad value", *argv);
895 			}
896 		if (p->c_func || p->c_func2) {
897 			if (p->c_parameter == NEXTARG0) {
898 				const struct cmd *p0;
899 				int noarg = 1;
900 
901 				if (argv[1]) {
902 					for (p0 = cmds; p0->c_name; p0++)
903 						if (strcmp(argv[1],
904 						    p0->c_name) == 0) {
905 							noarg = 0;
906 							break;
907 						}
908 				} else
909 					noarg = 0;
910 
911 				if (noarg == 0)
912 					(*p->c_func)(NULL, 0);
913 				else
914 					goto nextarg;
915 			} else if (p->c_parameter == NEXTARG) {
916 nextarg:
917 				if (argv[1] == NULL)
918 					errx(1, "'%s' requires argument",
919 					    p->c_name);
920 				(*p->c_func)(argv[1], 0);
921 				argc--, argv++;
922 				actions = actions | A_SILENT | p->c_action;
923 			} else if (p->c_parameter == NEXTARG2) {
924 				if ((argv[1] == NULL) ||
925 				    (argv[2] == NULL))
926 					errx(1, "'%s' requires 2 arguments",
927 					    p->c_name);
928 				(*p->c_func2)(argv[1], argv[2]);
929 				argc -= 2;
930 				argv += 2;
931 				actions = actions | A_SILENT | p->c_action;
932 			} else {
933 				(*p->c_func)(*argv, p->c_parameter);
934 				actions = actions | A_SILENT | p->c_action;
935 			}
936 		}
937 		argc--, argv++;
938 	}
939 
940 	if (argc == 0 && actions == 0) {
941 		printif(ifr.ifr_name, aflag ? ifaliases : 1);
942 		return (0);
943 	}
944 
945 #ifndef SMALL
946 	process_wg_commands();
947 #endif
948 
949 	process_join_commands();
950 
951 	/* Process any media commands that may have been issued. */
952 	process_media_commands();
953 
954 	if (af == AF_INET6 && explicit_prefix == 0) {
955 		/*
956 		 * Aggregatable address architecture defines all prefixes
957 		 * are 64. So, it is convenient to set prefixlen to 64 if
958 		 * it is not specified. If we are setting a destination
959 		 * address on a point-to-point interface, 128 is required.
960 		 */
961 		if (setipdst && (flags & IFF_POINTOPOINT))
962 			setifprefixlen("128", 0);
963 		else
964 			setifprefixlen("64", 0);
965 		/* in6_getprefix("64", MASK) if MASK is available here... */
966 	}
967 
968 	if (clearaddr) {
969 		(void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
970 		if (ioctl(sock, rafp->af_difaddr, rafp->af_ridreq) == -1) {
971 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
972 				/* means no previous address for interface */
973 			} else
974 				err(1, "SIOCDIFADDR");
975 		}
976 	}
977 	if (newaddr) {
978 		(void) strlcpy(rafp->af_addreq, ifname, sizeof(ifr.ifr_name));
979 		if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) == -1)
980 			err(1, "SIOCAIFADDR");
981 	}
982 	return (0);
983 }
984 
985 void
986 getsock(int naf)
987 {
988 	static int oaf = -1;
989 
990 	if (oaf == naf)
991 		return;
992 	if (oaf != -1)
993 		close(sock);
994 	sock = socket(naf, SOCK_DGRAM, 0);
995 	if (sock == -1)
996 		oaf = -1;
997 	else
998 		oaf = naf;
999 }
1000 
1001 int
1002 getinfo(struct ifreq *ifr, int create)
1003 {
1004 
1005 	getsock(af);
1006 	if (sock == -1)
1007 		err(1, "socket");
1008 	if (!isdigit((unsigned char)ifname[strlen(ifname) - 1]))
1009 		return (-1);	/* ignore groups here */
1010 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) {
1011 		int oerrno = errno;
1012 
1013 		if (!create)
1014 			return (-1);
1015 		if (ioctl(sock, SIOCIFCREATE, (caddr_t)ifr) == -1) {
1016 			errno = oerrno;
1017 			return (-1);
1018 		}
1019 		if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1)
1020 			return (-1);
1021 	}
1022 	flags = ifr->ifr_flags & 0xffff;
1023 	if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)ifr) == -1)
1024 		ifr->ifr_flags = 0;
1025 	xflags = ifr->ifr_flags;
1026 	if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) == -1)
1027 		metric = 0;
1028 	else
1029 		metric = ifr->ifr_metric;
1030 #ifdef SMALL
1031 	if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1)
1032 #else
1033 	if (is_bridge() || ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1)
1034 #endif
1035 		mtu = 0;
1036 	else
1037 		mtu = ifr->ifr_mtu;
1038 #ifndef SMALL
1039 	if (ioctl(sock, SIOCGIFRDOMAIN, (caddr_t)ifr) == -1)
1040 		rdomainid = 0;
1041 	else
1042 		rdomainid = ifr->ifr_rdomainid;
1043 #endif
1044 	if (ioctl(sock, SIOCGIFLLPRIO, (caddr_t)ifr) == -1)
1045 		llprio = 0;
1046 	else
1047 		llprio = ifr->ifr_llprio;
1048 
1049 	return (0);
1050 }
1051 
1052 int
1053 printgroup(char *groupname, int ifaliases)
1054 {
1055 	struct ifgroupreq	 ifgr;
1056 	struct ifg_req		*ifg;
1057 	int			 len, cnt = 0;
1058 
1059 	getsock(AF_INET);
1060 	bzero(&ifgr, sizeof(ifgr));
1061 	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1062 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
1063 		if (errno == EINVAL || errno == ENOTTY ||
1064 		    errno == ENOENT)
1065 			return (-1);
1066 		else
1067 			err(1, "SIOCGIFGMEMB");
1068 	}
1069 
1070 	len = ifgr.ifgr_len;
1071 	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
1072 		err(1, "printgroup");
1073 	if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
1074 		err(1, "SIOCGIFGMEMB");
1075 
1076 	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
1077 	    ifg++) {
1078 		len -= sizeof(struct ifg_req);
1079 		printif(ifg->ifgrq_member, ifaliases);
1080 		cnt++;
1081 	}
1082 	free(ifgr.ifgr_groups);
1083 
1084 	return (cnt);
1085 }
1086 
1087 void
1088 printgroupattribs(char *groupname)
1089 {
1090 	struct ifgroupreq	 ifgr;
1091 
1092 	getsock(AF_INET);
1093 	bzero(&ifgr, sizeof(ifgr));
1094 	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1095 	if (ioctl(sock, SIOCGIFGATTR, (caddr_t)&ifgr) == -1)
1096 		err(1, "SIOCGIFGATTR");
1097 
1098 	printf("%s:", groupname);
1099 	printf(" carp demote count %d", ifgr.ifgr_attrib.ifg_carp_demoted);
1100 	printf("\n");
1101 }
1102 
1103 void
1104 setgroupattribs(char *groupname, int argc, char *argv[])
1105 {
1106 	const char *errstr;
1107 	char *p = argv[0];
1108 	int neg = 1;
1109 
1110 	struct ifgroupreq	 ifgr;
1111 
1112 	getsock(AF_INET);
1113 	bzero(&ifgr, sizeof(ifgr));
1114 	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1115 
1116 	if (argc > 1) {
1117 		neg = strtonum(argv[1], 0, 128, &errstr);
1118 		if (errstr)
1119 			errx(1, "invalid carp demotion: %s", errstr);
1120 	}
1121 
1122 	if (p[0] == '-') {
1123 		neg = neg * -1;
1124 		p++;
1125 	}
1126 	if (!strcmp(p, "carpdemote"))
1127 		ifgr.ifgr_attrib.ifg_carp_demoted = neg;
1128 	else
1129 		usage();
1130 
1131 	if (ioctl(sock, SIOCSIFGATTR, (caddr_t)&ifgr) == -1)
1132 		err(1, "SIOCSIFGATTR");
1133 }
1134 
1135 void
1136 printif(char *name, int ifaliases)
1137 {
1138 	struct ifaddrs *ifap, *ifa;
1139 	struct if_data *ifdata;
1140 	const char *namep;
1141 	char *oname = NULL;
1142 	struct ifreq *ifrp;
1143 	int count = 0, noinet = 1;
1144 	size_t nlen = 0;
1145 
1146 	if (aflag)
1147 		name = NULL;
1148 	if (name) {
1149 		if ((oname = strdup(name)) == NULL)
1150 			err(1, "strdup");
1151 		nlen = strlen(oname);
1152 		/* is it a group? */
1153 		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
1154 			if (printgroup(oname, ifaliases) != -1) {
1155 				free(oname);
1156 				return;
1157 			}
1158 	}
1159 
1160 	if (getifaddrs(&ifap) != 0)
1161 		err(1, "getifaddrs");
1162 
1163 	namep = NULL;
1164 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1165 		if (oname) {
1166 			if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
1167 				/* must have exact match */
1168 				if (strcmp(oname, ifa->ifa_name) != 0)
1169 					continue;
1170 			} else {
1171 				/* partial match OK if it ends w/ digit */
1172 				if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
1173 				    !isdigit((unsigned char)ifa->ifa_name[nlen]))
1174 					continue;
1175 			}
1176 		}
1177 		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
1178 		if (ifa->ifa_addr != NULL &&
1179 		    ifa->ifa_addr->sa_family == AF_INET6) {
1180 			memset(&ifr6, 0, sizeof(ifr6));
1181 			memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
1182 			    MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
1183 			ifrp = (struct ifreq *)&ifr6;
1184 		} else if (ifa->ifa_addr != NULL) {
1185 			memset(&ifr, 0, sizeof(ifr));
1186 			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
1187 			    MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
1188 			ifrp = &ifr;
1189 		}
1190 		strlcpy(ifname, ifa->ifa_name, sizeof(ifname));
1191 		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
1192 
1193 		if (ifa->ifa_addr != NULL &&
1194 		    ifa->ifa_addr->sa_family == AF_LINK) {
1195 			namep = ifa->ifa_name;
1196 			if (getinfo(ifrp, 0) < 0)
1197 				continue;
1198 			ifdata = ifa->ifa_data;
1199 			status(1, (struct sockaddr_dl *)ifa->ifa_addr,
1200 			    ifdata->ifi_link_state);
1201 			count++;
1202 			noinet = 1;
1203 			continue;
1204 		}
1205 
1206 		if (!namep || !strcmp(namep, ifa->ifa_name)) {
1207 			const struct afswtch *p;
1208 
1209 			if (ifa->ifa_addr == NULL ||
1210 			    (ifa->ifa_addr->sa_family == AF_INET &&
1211 			    ifaliases == 0 && noinet == 0))
1212 				continue;
1213 			if ((p = afp) != NULL) {
1214 				if (ifa->ifa_addr->sa_family == p->af_af)
1215 					p->af_status(1);
1216 			} else {
1217 				for (p = afs; p->af_name; p++) {
1218 					if (ifa->ifa_addr->sa_family ==
1219 					    p->af_af)
1220 						p->af_status(0);
1221 				}
1222 			}
1223 			count++;
1224 			if (ifa->ifa_addr->sa_family == AF_INET)
1225 				noinet = 0;
1226 			continue;
1227 		}
1228 	}
1229 	freeifaddrs(ifap);
1230 	free(oname);
1231 	if (count == 0) {
1232 		fprintf(stderr, "%s: no such interface\n", ifname);
1233 		exit(1);
1234 	}
1235 }
1236 
1237 /*ARGSUSED*/
1238 void
1239 clone_create(const char *addr, int param)
1240 {
1241 
1242 	/* We're called early... */
1243 	getsock(AF_INET);
1244 
1245 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1246 	if (ioctl(sock, SIOCIFCREATE, &ifr) == -1)
1247 		err(1, "SIOCIFCREATE");
1248 }
1249 
1250 /*ARGSUSED*/
1251 void
1252 clone_destroy(const char *addr, int param)
1253 {
1254 
1255 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1256 	if (ioctl(sock, SIOCIFDESTROY, &ifr) == -1)
1257 		err(1, "SIOCIFDESTROY");
1258 }
1259 
1260 void
1261 list_cloners(void)
1262 {
1263 	struct if_clonereq ifcr;
1264 	char *cp, *buf;
1265 	int idx;
1266 
1267 	memset(&ifcr, 0, sizeof(ifcr));
1268 
1269 	getsock(AF_INET);
1270 
1271 	if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
1272 		err(1, "SIOCIFGCLONERS for count");
1273 
1274 	buf = calloc(ifcr.ifcr_total, IFNAMSIZ);
1275 	if (buf == NULL)
1276 		err(1, "unable to allocate cloner name buffer");
1277 
1278 	ifcr.ifcr_count = ifcr.ifcr_total;
1279 	ifcr.ifcr_buffer = buf;
1280 
1281 	if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
1282 		err(1, "SIOCIFGCLONERS for names");
1283 
1284 	/*
1285 	 * In case some disappeared in the mean time, clamp it down.
1286 	 */
1287 	if (ifcr.ifcr_count > ifcr.ifcr_total)
1288 		ifcr.ifcr_count = ifcr.ifcr_total;
1289 
1290 	qsort(buf, ifcr.ifcr_count, IFNAMSIZ,
1291 	    (int(*)(const void *, const void *))strcmp);
1292 
1293 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
1294 		if (idx > 0)
1295 			putchar(' ');
1296 		printf("%s", cp);
1297 	}
1298 
1299 	putchar('\n');
1300 	free(buf);
1301 }
1302 
1303 #define RIDADDR 0
1304 #define ADDR	1
1305 #define MASK	2
1306 #define DSTADDR	3
1307 
1308 /*ARGSUSED*/
1309 void
1310 setifaddr(const char *addr, int param)
1311 {
1312 	/*
1313 	 * Delay the ioctl to set the interface addr until flags are all set.
1314 	 * The address interpretation may depend on the flags,
1315 	 * and the flags may change when the address is set.
1316 	 */
1317 	setaddr++;
1318 	if (doalias >= 0)
1319 		newaddr = 1;
1320 	if (doalias == 0)
1321 		clearaddr = 1;
1322 	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
1323 }
1324 
1325 #ifndef SMALL
1326 void
1327 setifrtlabel(const char *label, int d)
1328 {
1329 	if (d != 0)
1330 		ifr.ifr_data = (caddr_t)(const char *)"";
1331 	else
1332 		ifr.ifr_data = (caddr_t)label;
1333 	if (ioctl(sock, SIOCSIFRTLABEL, &ifr) == -1)
1334 		warn("SIOCSIFRTLABEL");
1335 }
1336 #endif
1337 
1338 /* ARGSUSED */
1339 void
1340 setifnetmask(const char *addr, int ignored)
1341 {
1342 	afp->af_getaddr(addr, MASK);
1343 	explicit_prefix = 1;
1344 }
1345 
1346 /* ARGSUSED */
1347 void
1348 setifbroadaddr(const char *addr, int ignored)
1349 {
1350 	afp->af_getaddr(addr, DSTADDR);
1351 }
1352 
1353 #ifndef SMALL
1354 /* ARGSUSED */
1355 void
1356 setifdesc(const char *val, int ignored)
1357 {
1358 	ifr.ifr_data = (caddr_t)val;
1359 	if (ioctl(sock, SIOCSIFDESCR, &ifr) == -1)
1360 		warn("SIOCSIFDESCR");
1361 }
1362 
1363 /* ARGSUSED */
1364 void
1365 unsetifdesc(const char *noval, int ignored)
1366 {
1367 	ifr.ifr_data = (caddr_t)(const char *)"";
1368 	if (ioctl(sock, SIOCSIFDESCR, &ifr) == -1)
1369 		warn("SIOCSIFDESCR");
1370 }
1371 
1372 /* ARGSUSED */
1373 void
1374 setifipdst(const char *addr, int ignored)
1375 {
1376 	in_getaddr(addr, DSTADDR);
1377 	setipdst++;
1378 	clearaddr = 0;
1379 	newaddr = 0;
1380 }
1381 #endif
1382 
1383 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1384 /*ARGSUSED*/
1385 void
1386 notealias(const char *addr, int param)
1387 {
1388 	if (setaddr && doalias == 0 && param < 0)
1389 		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1390 		    rqtosa(af_addreq)->sa_len);
1391 	doalias = param;
1392 	if (param < 0) {
1393 		clearaddr = 1;
1394 		newaddr = 0;
1395 	} else
1396 		clearaddr = 0;
1397 }
1398 
1399 /*ARGSUSED*/
1400 void
1401 setifdstaddr(const char *addr, int param)
1402 {
1403 	setaddr++;
1404 	setipdst++;
1405 	afp->af_getaddr(addr, DSTADDR);
1406 }
1407 
1408 /*
1409  * Note: doing an SIOCGIFFLAGS scribbles on the union portion
1410  * of the ifreq structure, which may confuse other parts of ifconfig.
1411  * Make a private copy so we can avoid that.
1412  */
1413 /* ARGSUSED */
1414 void
1415 setifflags(const char *vname, int value)
1416 {
1417 	struct ifreq my_ifr;
1418 
1419 	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1420 
1421 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&my_ifr) == -1)
1422 		err(1, "SIOCGIFFLAGS");
1423 	(void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name));
1424 	flags = my_ifr.ifr_flags;
1425 
1426 	if (value < 0) {
1427 		value = -value;
1428 		flags &= ~value;
1429 	} else
1430 		flags |= value;
1431 	my_ifr.ifr_flags = flags;
1432 	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&my_ifr) == -1)
1433 		err(1, "SIOCSIFFLAGS");
1434 }
1435 
1436 /* ARGSUSED */
1437 void
1438 setifxflags(const char *vname, int value)
1439 {
1440 	struct ifreq my_ifr;
1441 
1442 	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1443 
1444 	if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)&my_ifr) == -1)
1445 		warn("SIOCGIFXFLAGS");
1446 	(void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name));
1447 	xflags = my_ifr.ifr_flags;
1448 
1449 	if (value < 0) {
1450 		value = -value;
1451 		xflags &= ~value;
1452 	} else
1453 		xflags |= value;
1454 	my_ifr.ifr_flags = xflags;
1455 	if (ioctl(sock, SIOCSIFXFLAGS, (caddr_t)&my_ifr) == -1)
1456 		warn("SIOCSIFXFLAGS");
1457 }
1458 
1459 void
1460 addaf(const char *vname, int value)
1461 {
1462 	struct if_afreq	ifar;
1463 
1464 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
1465 	ifar.ifar_af = value;
1466 	if (ioctl(sock, SIOCIFAFATTACH, (caddr_t)&ifar) == -1)
1467 		warn("SIOCIFAFATTACH");
1468 }
1469 
1470 void
1471 removeaf(const char *vname, int value)
1472 {
1473 	struct if_afreq	ifar;
1474 
1475 	strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
1476 	ifar.ifar_af = value;
1477 	if (ioctl(sock, SIOCIFAFDETACH, (caddr_t)&ifar) == -1)
1478 		warn("SIOCIFAFDETACH");
1479 }
1480 
1481 void
1482 setia6flags(const char *vname, int value)
1483 {
1484 
1485 	if (value < 0) {
1486 		value = -value;
1487 		in6_addreq.ifra_flags &= ~value;
1488 	} else
1489 		in6_addreq.ifra_flags |= value;
1490 }
1491 
1492 void
1493 setia6pltime(const char *val, int d)
1494 {
1495 
1496 	setia6lifetime("pltime", val);
1497 }
1498 
1499 void
1500 setia6vltime(const char *val, int d)
1501 {
1502 
1503 	setia6lifetime("vltime", val);
1504 }
1505 
1506 void
1507 setia6lifetime(const char *cmd, const char *val)
1508 {
1509 	const char *errmsg = NULL;
1510 	time_t newval, t;
1511 
1512 	newval = strtonum(val, 0, 1000000, &errmsg);
1513 	if (errmsg)
1514 		errx(1, "invalid %s %s: %s", cmd, val, errmsg);
1515 
1516 	t = time(NULL);
1517 
1518 	if (afp->af_af != AF_INET6)
1519 		errx(1, "%s not allowed for this address family", cmd);
1520 	if (strcmp(cmd, "vltime") == 0) {
1521 		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1522 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1523 	} else if (strcmp(cmd, "pltime") == 0) {
1524 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1525 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1526 	}
1527 }
1528 
1529 void
1530 setia6eui64(const char *cmd, int val)
1531 {
1532 	struct ifaddrs *ifap, *ifa;
1533 	const struct sockaddr_in6 *sin6 = NULL;
1534 	const struct in6_addr *lladdr = NULL;
1535 	struct in6_addr *in6;
1536 
1537 	if (afp->af_af != AF_INET6)
1538 		errx(1, "%s not allowed for this address family", cmd);
1539 
1540 	addaf(ifname, AF_INET6);
1541 
1542 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1543 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1544 		errx(1, "interface index is already filled");
1545 	if (getifaddrs(&ifap) != 0)
1546 		err(1, "getifaddrs");
1547 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1548 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1549 		    strcmp(ifa->ifa_name, ifname) == 0) {
1550 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1551 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1552 				lladdr = &sin6->sin6_addr;
1553 				break;
1554 			}
1555 		}
1556 	}
1557 	if (!lladdr)
1558 		errx(1, "could not determine link local address");
1559 
1560 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1561 
1562 	freeifaddrs(ifap);
1563 }
1564 
1565 void
1566 setautoconf(const char *cmd, int val)
1567 {
1568 	switch (afp->af_af) {
1569 	case AF_INET:
1570 		setifxflags("inet", val * IFXF_AUTOCONF4);
1571 		break;
1572 	case AF_INET6:
1573 		if (val > 0)
1574 			setifxflags("inet6", (IFXF_AUTOCONF6 |
1575 			    IFXF_AUTOCONF6TEMP));
1576 		else
1577 			setifxflags("inet6", -IFXF_AUTOCONF6);
1578 		break;
1579 	default:
1580 		errx(1, "autoconf not allowed for this address family");
1581 	}
1582 }
1583 
1584 void
1585 settemporary(const char *cmd, int val)
1586 {
1587 	switch (afp->af_af) {
1588 	case AF_INET6:
1589 		setifxflags("inet6", val * IFXF_AUTOCONF6TEMP);
1590 		break;
1591 	default:
1592 		errx(1, "temporary not allowed for this address family");
1593 	}
1594 }
1595 
1596 #ifndef SMALL
1597 /* ARGSUSED */
1598 void
1599 setifmetric(const char *val, int ignored)
1600 {
1601 	const char *errmsg = NULL;
1602 
1603 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1604 
1605 	ifr.ifr_metric = strtonum(val, 0, INT_MAX, &errmsg);
1606 	if (errmsg)
1607 		errx(1, "metric %s: %s", val, errmsg);
1608 	if (ioctl(sock, SIOCSIFMETRIC, (caddr_t)&ifr) == -1)
1609 		warn("SIOCSIFMETRIC");
1610 }
1611 #endif
1612 
1613 /* ARGSUSED */
1614 void
1615 setifmtu(const char *val, int d)
1616 {
1617 	const char *errmsg = NULL;
1618 
1619 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1620 
1621 	ifr.ifr_mtu = strtonum(val, 0, INT_MAX, &errmsg);
1622 	if (errmsg)
1623 		errx(1, "mtu %s: %s", val, errmsg);
1624 	if (ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr) == -1)
1625 		warn("SIOCSIFMTU");
1626 }
1627 
1628 /* ARGSUSED */
1629 void
1630 setifllprio(const char *val, int d)
1631 {
1632 	const char *errmsg = NULL;
1633 
1634 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1635 
1636 	ifr.ifr_llprio = strtonum(val, 0, UCHAR_MAX, &errmsg);
1637 	if (errmsg)
1638 		errx(1, "llprio %s: %s", val, errmsg);
1639 	if (ioctl(sock, SIOCSIFLLPRIO, (caddr_t)&ifr) == -1)
1640 		warn("SIOCSIFLLPRIO");
1641 }
1642 
1643 /* ARGSUSED */
1644 void
1645 setifgroup(const char *group_name, int dummy)
1646 {
1647 	struct ifgroupreq ifgr;
1648 	size_t namelen;
1649 
1650 	memset(&ifgr, 0, sizeof(ifgr));
1651 	strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
1652 
1653 	namelen = strlen(group_name);
1654 	if (namelen == 0)
1655 		errx(1, "setifgroup: group name empty");
1656 	if (namelen >= IFNAMSIZ)
1657 		errx(1, "setifgroup: group name too long");
1658 	if (isdigit((unsigned char)group_name[namelen - 1]))
1659 		errx(1, "setifgroup: group names may not end in a digit");
1660 
1661 	strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ);
1662 	if (ioctl(sock, SIOCAIFGROUP, (caddr_t)&ifgr) == -1) {
1663 		if (errno != EEXIST)
1664 			err(1," SIOCAIFGROUP");
1665 	}
1666 }
1667 
1668 /* ARGSUSED */
1669 void
1670 unsetifgroup(const char *group_name, int dummy)
1671 {
1672 	struct ifgroupreq ifgr;
1673 
1674 	memset(&ifgr, 0, sizeof(ifgr));
1675 	strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
1676 
1677 	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1678 		errx(1, "unsetifgroup: group name too long");
1679 	if (ioctl(sock, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
1680 		err(1, "SIOCDIFGROUP");
1681 }
1682 
1683 const char *
1684 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1685 {
1686 	int len = *lenp, hexstr;
1687 	u_int8_t *p = buf;
1688 
1689 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1690 	if (hexstr)
1691 		val += 2;
1692 	for (;;) {
1693 		if (*val == '\0')
1694 			break;
1695 		if (sep != NULL && strchr(sep, *val) != NULL) {
1696 			val++;
1697 			break;
1698 		}
1699 		if (hexstr) {
1700 			if (!isxdigit((u_char)val[0]) ||
1701 			    !isxdigit((u_char)val[1])) {
1702 				warnx("bad hexadecimal digits");
1703 				return NULL;
1704 			}
1705 		}
1706 		if (p > buf + len) {
1707 			if (hexstr)
1708 				warnx("hexadecimal digits too long");
1709 			else
1710 				warnx("strings too long");
1711 			return NULL;
1712 		}
1713 		if (hexstr) {
1714 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1715 			*p++ = (tohex((u_char)val[0]) << 4) |
1716 			    tohex((u_char)val[1]);
1717 #undef tohex
1718 			val += 2;
1719 		} else {
1720 			if (*val == '\\' &&
1721 			    sep != NULL && strchr(sep, *(val + 1)) != NULL)
1722 				val++;
1723 			*p++ = *val++;
1724 		}
1725 	}
1726 	len = p - buf;
1727 	if (len < *lenp)
1728 		memset(p, 0, *lenp - len);
1729 	*lenp = len;
1730 	return val;
1731 }
1732 
1733 int
1734 len_string(const u_int8_t *buf, int len)
1735 {
1736 	int i = 0, hasspc = 0;
1737 
1738 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1739 		for (; i < len; i++) {
1740 			/* Only print 7-bit ASCII keys */
1741 			if (buf[i] & 0x80 || !isprint(buf[i]))
1742 				break;
1743 			if (isspace(buf[i]))
1744 				hasspc++;
1745 		}
1746 	}
1747 	if (i == len) {
1748 		if (hasspc || len == 0)
1749 			return len + 2;
1750 		else
1751 			return len;
1752 	} else
1753 		return (len * 2) + 2;
1754 }
1755 
1756 int
1757 print_string(const u_int8_t *buf, int len)
1758 {
1759 	int i = 0, hasspc = 0;
1760 
1761 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1762 		for (; i < len; i++) {
1763 			/* Only print 7-bit ASCII keys */
1764 			if (buf[i] & 0x80 || !isprint(buf[i]))
1765 				break;
1766 			if (isspace(buf[i]))
1767 				hasspc++;
1768 		}
1769 	}
1770 	if (i == len) {
1771 		if (hasspc || len == 0) {
1772 			printf("\"%.*s\"", len, buf);
1773 			return len + 2;
1774 		} else {
1775 			printf("%.*s", len, buf);
1776 			return len;
1777 		}
1778 	} else {
1779 		printf("0x");
1780 		for (i = 0; i < len; i++)
1781 			printf("%02x", buf[i]);
1782 		return (len * 2) + 2;
1783 	}
1784 }
1785 
1786 void
1787 setifnwid(const char *val, int d)
1788 {
1789 	struct ieee80211_nwid nwid;
1790 	int len;
1791 
1792 	if (joinlen != 0) {
1793 		errx(1, "nwid and join may not be used at the same time");
1794 	}
1795 
1796 	if (nwidlen != 0) {
1797 		errx(1, "nwid may not be specified twice");
1798 	}
1799 
1800 	if (d != 0) {
1801 		/* no network id is especially desired */
1802 		memset(&nwid, 0, sizeof(nwid));
1803 		len = 0;
1804 	} else {
1805 		len = sizeof(nwid.i_nwid);
1806 		if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1807 			return;
1808 	}
1809 	nwidlen = nwid.i_len = len;
1810 	(void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1811 	memcpy(nwidname, nwid.i_nwid, len);
1812 	ifr.ifr_data = (caddr_t)&nwid;
1813 	if (ioctl(sock, SIOCS80211NWID, (caddr_t)&ifr) == -1)
1814 		warn("SIOCS80211NWID");
1815 }
1816 
1817 
1818 void
1819 process_join_commands(void)
1820 {
1821 	if (!(actions & A_JOIN))
1822 		return;
1823 
1824 	ifr.ifr_data = (caddr_t)&join;
1825 	if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1826 		err(1, "SIOCS80211JOIN");
1827 }
1828 
1829 void
1830 setifjoin(const char *val, int d)
1831 {
1832 	int len;
1833 
1834 	if (nwidlen != 0) {
1835 		errx(1, "nwid and join may not be used at the same time");
1836 	}
1837 
1838 	if (joinlen != 0) {
1839 		errx(1, "join may not be specified twice");
1840 	}
1841 
1842 	if (d != 0) {
1843 		/* no network id is especially desired */
1844 		memset(&join, 0, sizeof(join));
1845 		len = 0;
1846 	} else {
1847 		len = sizeof(join.i_nwid);
1848 		if (get_string(val, NULL, join.i_nwid, &len) == NULL)
1849 			return;
1850 		if (len == 0)
1851 			join.i_flags |= IEEE80211_JOIN_ANY;
1852 	}
1853 	joinlen = join.i_len = len;
1854 	(void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1855 	memcpy(joinname, join.i_nwid, len);
1856 
1857 	actions |= A_JOIN;
1858 }
1859 
1860 void
1861 delifjoin(const char *val, int d)
1862 {
1863 	struct ieee80211_join join;
1864 	int len;
1865 
1866 	memset(&join, 0, sizeof(join));
1867 	len = 0;
1868 	join.i_flags |= IEEE80211_JOIN_DEL;
1869 
1870 	if (d == -1) {
1871 		ifr.ifr_data = (caddr_t)&join;
1872 		if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1873 			err(1, "SIOCS80211JOIN");
1874 	}
1875 
1876 	len = sizeof(join.i_nwid);
1877 	if (get_string(val, NULL, join.i_nwid, &len) == NULL)
1878 		return;
1879 	join.i_len = len;
1880 	if (len == 0)
1881 		join.i_flags |= IEEE80211_JOIN_ANY;
1882 	(void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1883 	ifr.ifr_data = (caddr_t)&join;
1884 	if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1885 		err(1, "SIOCS80211JOIN");
1886 }
1887 
1888 void
1889 delifjoinlist(const char *val, int d)
1890 {
1891 	struct ieee80211_join join;
1892 	int len;
1893 
1894 	memset(&join, 0, sizeof(join));
1895 	len = 0;
1896 	join.i_flags |= (IEEE80211_JOIN_DEL | IEEE80211_JOIN_DEL_ALL);
1897 
1898 	if (d == -1) {
1899 		ifr.ifr_data = (caddr_t)&join;
1900 		if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1901 			err(1, "SIOCS80211JOIN");
1902 		return;
1903 	}
1904 
1905 	ifr.ifr_data = (caddr_t)&join;
1906 	if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1907 		err(1, "SIOCS80211JOIN");
1908 }
1909 
1910 void
1911 setifbssid(const char *val, int d)
1912 {
1913 
1914 	struct ieee80211_bssid bssid;
1915 	struct ether_addr *ea;
1916 
1917 	if (d != 0) {
1918 		/* no BSSID is especially desired */
1919 		memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1920 	} else {
1921 		ea = ether_aton((char*)val);
1922 		if (ea == NULL) {
1923 			warnx("malformed BSSID: %s", val);
1924 			return;
1925 		}
1926 		memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1927 		    sizeof(bssid.i_bssid));
1928 	}
1929 	strlcpy(bssid.i_name, ifname, sizeof(bssid.i_name));
1930 	if (ioctl(sock, SIOCS80211BSSID, &bssid) == -1)
1931 		warn("SIOCS80211BSSID");
1932 }
1933 
1934 void
1935 setifnwkey(const char *val, int d)
1936 {
1937 	int i, len;
1938 	struct ieee80211_nwkey nwkey;
1939 	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1940 
1941 	bzero(&nwkey, sizeof(nwkey));
1942 	bzero(&keybuf, sizeof(keybuf));
1943 
1944 	nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1945 	nwkey.i_defkid = 1;
1946 	if (d == -1) {
1947 		/* disable WEP encryption */
1948 		nwkey.i_wepon = IEEE80211_NWKEY_OPEN;
1949 		i = 0;
1950 	} else if (strcasecmp("persist", val) == 0) {
1951 		/* use all values from persistent memory */
1952 		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1953 		nwkey.i_defkid = 0;
1954 		for (i = 0; i < IEEE80211_WEP_NKID; i++)
1955 			nwkey.i_key[i].i_keylen = -1;
1956 	} else if (strncasecmp("persist:", val, 8) == 0) {
1957 		val += 8;
1958 		/* program keys in persistent memory */
1959 		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1960 		goto set_nwkey;
1961 	} else {
1962  set_nwkey:
1963 		if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1964 			/* specifying a full set of four keys */
1965 			nwkey.i_defkid = val[0] - '0';
1966 			val += 2;
1967 			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1968 				len = sizeof(keybuf[i]);
1969 				val = get_string(val, ",", keybuf[i], &len);
1970 				if (val == NULL)
1971 					return;
1972 				nwkey.i_key[i].i_keylen = len;
1973 				nwkey.i_key[i].i_keydat = keybuf[i];
1974 			}
1975 			if (*val != '\0') {
1976 				warnx("SIOCS80211NWKEY: too many keys.");
1977 				return;
1978 			}
1979 		} else {
1980 			/*
1981 			 * length of each key must be either a 5
1982 			 * character ASCII string or 10 hex digits for
1983 			 * 40 bit encryption, or 13 character ASCII
1984 			 * string or 26 hex digits for 128 bit
1985 			 * encryption.
1986 			 */
1987 			int j;
1988 			char *tmp = NULL;
1989 			size_t vlen = strlen(val);
1990 			switch(vlen) {
1991 			case 10:
1992 			case 26:
1993 				/* 0x must be missing for these lengths */
1994 				j = asprintf(&tmp, "0x%s", val);
1995 				if (j == -1) {
1996 					warnx("malloc failed");
1997 					return;
1998 				}
1999 				val = tmp;
2000 				break;
2001 			case 12:
2002 			case 28:
2003 			case 5:
2004 			case 13:
2005 				/* 0xkey or string case - all is ok */
2006 				break;
2007 			default:
2008 				warnx("Invalid WEP key length");
2009 				return;
2010 			}
2011 			len = sizeof(keybuf[0]);
2012 			val = get_string(val, NULL, keybuf[0], &len);
2013 			free(tmp);
2014 			if (val == NULL)
2015 				return;
2016 			nwkey.i_key[0].i_keylen = len;
2017 			nwkey.i_key[0].i_keydat = keybuf[0];
2018 			i = 1;
2019 		}
2020 	}
2021 	(void)strlcpy(nwkey.i_name, ifname, sizeof(nwkey.i_name));
2022 
2023 	if (actions & A_JOIN) {
2024 		memcpy(&join.i_nwkey, &nwkey, sizeof(join.i_nwkey));
2025 		join.i_flags |= IEEE80211_JOIN_NWKEY;
2026 		return;
2027 	}
2028 
2029 	if (ioctl(sock, SIOCS80211NWKEY, (caddr_t)&nwkey) == -1)
2030 		err(1, "SIOCS80211NWKEY");
2031 }
2032 
2033 /* ARGSUSED */
2034 void
2035 setifwpa(const char *val, int d)
2036 {
2037 	struct ieee80211_wpaparams wpa;
2038 
2039 	memset(&wpa, 0, sizeof(wpa));
2040 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2041 	/* Don't read current values. The kernel will set defaults. */
2042 	wpa.i_enabled = d;
2043 
2044 	if (actions & A_JOIN) {
2045 		join.i_wpaparams.i_enabled = d;
2046 		join.i_flags |= IEEE80211_JOIN_WPA;
2047 		return;
2048 	}
2049 
2050 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2051 		err(1, "SIOCS80211WPAPARMS");
2052 }
2053 
2054 /* ARGSUSED */
2055 void
2056 setifwpaprotos(const char *val, int d)
2057 {
2058 	struct ieee80211_wpaparams wpa;
2059 	char *optlist, *str;
2060 	u_int rval = 0;
2061 
2062 	if ((optlist = strdup(val)) == NULL)
2063 		err(1, "strdup");
2064 	str = strtok(optlist, ",");
2065 	while (str != NULL) {
2066 		if (strcasecmp(str, "wpa1") == 0)
2067 			rval |= IEEE80211_WPA_PROTO_WPA1;
2068 		else if (strcasecmp(str, "wpa2") == 0)
2069 			rval |= IEEE80211_WPA_PROTO_WPA2;
2070 		else
2071 			errx(1, "wpaprotos: unknown protocol: %s", str);
2072 		str = strtok(NULL, ",");
2073 	}
2074 	free(optlist);
2075 
2076 	if (actions & A_JOIN) {
2077 		join.i_wpaparams.i_protos = rval;
2078 		join.i_flags |= IEEE80211_JOIN_WPA;
2079 		return;
2080 	}
2081 
2082 	memset(&wpa, 0, sizeof(wpa));
2083 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2084 	if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2085 		err(1, "SIOCG80211WPAPARMS");
2086 	wpa.i_protos = rval;
2087 	/* Let the kernel set up the appropriate default ciphers. */
2088 	wpa.i_ciphers = 0;
2089 	wpa.i_groupcipher = 0;
2090 
2091 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2092 		err(1, "SIOCS80211WPAPARMS");
2093 }
2094 
2095 /* ARGSUSED */
2096 void
2097 setifwpaakms(const char *val, int d)
2098 {
2099 	struct ieee80211_wpaparams wpa;
2100 	char *optlist, *str;
2101 	u_int rval = 0;
2102 
2103 	if ((optlist = strdup(val)) == NULL)
2104 		err(1, "strdup");
2105 	str = strtok(optlist, ",");
2106 	while (str != NULL) {
2107 		if (strcasecmp(str, "psk") == 0)
2108 			rval |= IEEE80211_WPA_AKM_PSK;
2109 		else if (strcasecmp(str, "802.1x") == 0)
2110 			rval |= IEEE80211_WPA_AKM_8021X;
2111 		else
2112 			errx(1, "wpaakms: unknown akm: %s", str);
2113 		str = strtok(NULL, ",");
2114 	}
2115 	free(optlist);
2116 
2117 	if (actions & A_JOIN) {
2118 		join.i_wpaparams.i_akms = rval;
2119 		join.i_wpaparams.i_enabled =
2120 		    ((rval & IEEE80211_WPA_AKM_8021X) != 0);
2121 		join.i_flags |= IEEE80211_JOIN_WPA;
2122 		return;
2123 	}
2124 
2125 	memset(&wpa, 0, sizeof(wpa));
2126 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2127 	if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2128 		err(1, "SIOCG80211WPAPARMS");
2129 	wpa.i_akms = rval;
2130 	/* Enable WPA for 802.1x here. PSK case is handled in setifwpakey(). */
2131 	wpa.i_enabled = ((rval & IEEE80211_WPA_AKM_8021X) != 0);
2132 
2133 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2134 		err(1, "SIOCS80211WPAPARMS");
2135 }
2136 
2137 static const struct {
2138 	const char	*name;
2139 	u_int		cipher;
2140 } ciphers[] = {
2141 	{ "usegroup",	IEEE80211_WPA_CIPHER_USEGROUP },
2142 	{ "wep40",	IEEE80211_WPA_CIPHER_WEP40 },
2143 	{ "tkip",	IEEE80211_WPA_CIPHER_TKIP },
2144 	{ "ccmp",	IEEE80211_WPA_CIPHER_CCMP },
2145 	{ "wep104",	IEEE80211_WPA_CIPHER_WEP104 }
2146 };
2147 
2148 u_int
2149 getwpacipher(const char *name)
2150 {
2151 	int i;
2152 
2153 	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++)
2154 		if (strcasecmp(name, ciphers[i].name) == 0)
2155 			return ciphers[i].cipher;
2156 	return IEEE80211_WPA_CIPHER_NONE;
2157 }
2158 
2159 /* ARGSUSED */
2160 void
2161 setifwpaciphers(const char *val, int d)
2162 {
2163 	struct ieee80211_wpaparams wpa;
2164 	char *optlist, *str;
2165 	u_int rval = 0;
2166 
2167 	if ((optlist = strdup(val)) == NULL)
2168 		err(1, "strdup");
2169 	str = strtok(optlist, ",");
2170 	while (str != NULL) {
2171 		u_int cipher = getwpacipher(str);
2172 		if (cipher == IEEE80211_WPA_CIPHER_NONE)
2173 			errx(1, "wpaciphers: unknown cipher: %s", str);
2174 
2175 		rval |= cipher;
2176 		str = strtok(NULL, ",");
2177 	}
2178 	free(optlist);
2179 
2180 	if (actions & A_JOIN) {
2181 		join.i_wpaparams.i_ciphers = rval;
2182 		join.i_flags |= IEEE80211_JOIN_WPA;
2183 		return;
2184 	}
2185 
2186 	memset(&wpa, 0, sizeof(wpa));
2187 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2188 	if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2189 		err(1, "SIOCG80211WPAPARMS");
2190 	wpa.i_ciphers = rval;
2191 
2192 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2193 		err(1, "SIOCS80211WPAPARMS");
2194 }
2195 
2196 /* ARGSUSED */
2197 void
2198 setifwpagroupcipher(const char *val, int d)
2199 {
2200 	struct ieee80211_wpaparams wpa;
2201 	u_int cipher;
2202 
2203 	cipher = getwpacipher(val);
2204 	if (cipher == IEEE80211_WPA_CIPHER_NONE)
2205 		errx(1, "wpagroupcipher: unknown cipher: %s", val);
2206 
2207 	memset(&wpa, 0, sizeof(wpa));
2208 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2209 	if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2210 		err(1, "SIOCG80211WPAPARMS");
2211 	wpa.i_groupcipher = cipher;
2212 
2213 	if (actions & A_JOIN) {
2214 		join.i_wpaparams.i_groupcipher = cipher;
2215 		join.i_flags |= IEEE80211_JOIN_WPA;
2216 		return;
2217 	}
2218 
2219 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2220 		err(1, "SIOCS80211WPAPARMS");
2221 }
2222 
2223 void
2224 setifwpakey(const char *val, int d)
2225 {
2226 	struct ieee80211_wpaparams wpa;
2227 	struct ieee80211_wpapsk psk;
2228 	struct ieee80211_nwid nwid;
2229 	int passlen;
2230 
2231 	memset(&psk, 0, sizeof(psk));
2232 	if (d != -1) {
2233 		memset(&ifr, 0, sizeof(ifr));
2234 		ifr.ifr_data = (caddr_t)&nwid;
2235 		strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2236 
2237 		/* Use the value specified in 'join' or 'nwid' */
2238 		if (joinlen != 0) {
2239 			memcpy(nwid.i_nwid, joinname, joinlen);
2240 			nwid.i_len = joinlen;
2241 		} else if (nwidlen != 0) {
2242 			memcpy(nwid.i_nwid, nwidname, nwidlen);
2243 			nwid.i_len = nwidlen;
2244 		} else {
2245 			warnx("no nwid or join command, guessing nwid to use");
2246 
2247 			if (ioctl(sock, SIOCG80211NWID, (caddr_t)&ifr) == -1)
2248 				err(1, "SIOCG80211NWID");
2249 		}
2250 
2251 		passlen = strlen(val);
2252 		if (passlen == 2 + 2 * sizeof(psk.i_psk) &&
2253 		    val[0] == '0' && val[1] == 'x') {
2254 			/* Parse a WPA hex key (must be full-length) */
2255 			passlen = sizeof(psk.i_psk);
2256 			val = get_string(val, NULL, psk.i_psk, &passlen);
2257 			if (val == NULL || passlen != sizeof(psk.i_psk))
2258 				errx(1, "wpakey: invalid pre-shared key");
2259 		} else {
2260 			/* Parse a WPA passphrase */
2261 			if (passlen < 8 || passlen > 63)
2262 				errx(1, "wpakey: passphrase must be between "
2263 				    "8 and 63 characters");
2264 			if (nwid.i_len == 0)
2265 				errx(1, "wpakey: nwid not set");
2266 			if (pkcs5_pbkdf2(val, passlen, nwid.i_nwid, nwid.i_len,
2267 			    psk.i_psk, sizeof(psk.i_psk), 4096) != 0)
2268 				errx(1, "wpakey: passphrase hashing failed");
2269 		}
2270 		psk.i_enabled = 1;
2271 	} else
2272 		psk.i_enabled = 0;
2273 
2274 	(void)strlcpy(psk.i_name, ifname, sizeof(psk.i_name));
2275 
2276 	if (actions & A_JOIN) {
2277 		memcpy(&join.i_wpapsk, &psk, sizeof(join.i_wpapsk));
2278 		join.i_flags |= IEEE80211_JOIN_WPAPSK;
2279 		if (!join.i_wpaparams.i_enabled)
2280 			setifwpa(NULL, join.i_wpapsk.i_enabled);
2281 		return;
2282 	}
2283 
2284 	if (ioctl(sock, SIOCS80211WPAPSK, (caddr_t)&psk) == -1)
2285 		err(1, "SIOCS80211WPAPSK");
2286 
2287 	/* And ... automatically enable or disable WPA */
2288 	memset(&wpa, 0, sizeof(wpa));
2289 	(void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2290 	if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2291 		err(1, "SIOCG80211WPAPARMS");
2292 	wpa.i_enabled = psk.i_enabled;
2293 	if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2294 		err(1, "SIOCS80211WPAPARMS");
2295 }
2296 
2297 void
2298 setifchan(const char *val, int d)
2299 {
2300 	struct ieee80211chanreq channel;
2301 	const char *errstr;
2302 	int chan;
2303 
2304 	if (val == NULL) {
2305 		if (shownet80211chans || shownet80211nodes)
2306 			usage();
2307 		shownet80211chans = 1;
2308 		return;
2309 	}
2310 	if (d != 0)
2311 		chan = IEEE80211_CHAN_ANY;
2312 	else {
2313 		chan = strtonum(val, 1, 256, &errstr);
2314 		if (errstr) {
2315 			warnx("invalid channel %s: %s", val, errstr);
2316 			return;
2317 		}
2318 	}
2319 
2320 	strlcpy(channel.i_name, ifname, sizeof(channel.i_name));
2321 	channel.i_channel = (u_int16_t)chan;
2322 	if (ioctl(sock, SIOCS80211CHANNEL, (caddr_t)&channel) == -1)
2323 		warn("SIOCS80211CHANNEL");
2324 }
2325 
2326 /* ARGSUSED */
2327 void
2328 setifscan(const char *val, int d)
2329 {
2330 	if (shownet80211chans || shownet80211nodes)
2331 		usage();
2332 	shownet80211nodes = 1;
2333 }
2334 
2335 #ifndef SMALL
2336 
2337 void
2338 setifnwflag(const char *val, int d)
2339 {
2340 	static const struct ieee80211_flags nwflags[] = IEEE80211_FLAGS;
2341 	u_int i, flag = 0;
2342 
2343 	for (i = 0; i < (sizeof(nwflags) / sizeof(nwflags[0])); i++) {
2344 		if (strcmp(val, nwflags[i].f_name) == 0) {
2345 			flag = nwflags[i].f_flag;
2346 			break;
2347 		}
2348 	}
2349 	if (flag == 0)
2350 		errx(1, "Invalid nwflag: %s", val);
2351 
2352 	if (ioctl(sock, SIOCG80211FLAGS, (caddr_t)&ifr) != 0)
2353 		err(1, "SIOCG80211FLAGS");
2354 
2355 	if (d)
2356 		ifr.ifr_flags &= ~flag;
2357 	else
2358 		ifr.ifr_flags |= flag;
2359 
2360 	if (ioctl(sock, SIOCS80211FLAGS, (caddr_t)&ifr) != 0)
2361 		err(1, "SIOCS80211FLAGS");
2362 }
2363 
2364 void
2365 unsetifnwflag(const char *val, int d)
2366 {
2367 	setifnwflag(val, 1);
2368 }
2369 
2370 /* ARGSUSED */
2371 void
2372 setifpowersave(const char *val, int d)
2373 {
2374 	struct ieee80211_power power;
2375 	const char *errmsg = NULL;
2376 
2377 	(void)strlcpy(power.i_name, ifname, sizeof(power.i_name));
2378 	if (ioctl(sock, SIOCG80211POWER, (caddr_t)&power) == -1) {
2379 		warn("SIOCG80211POWER");
2380 		return;
2381 	}
2382 
2383 	if (d != -1 && val != NULL) {
2384 		power.i_maxsleep = strtonum(val, 0, INT_MAX, &errmsg);
2385 		if (errmsg)
2386 			errx(1, "powersave %s: %s", val, errmsg);
2387 	}
2388 
2389 	power.i_enabled = d == -1 ? 0 : 1;
2390 	if (ioctl(sock, SIOCS80211POWER, (caddr_t)&power) == -1)
2391 		warn("SIOCS80211POWER");
2392 }
2393 #endif
2394 
2395 void
2396 print_cipherset(u_int32_t cipherset)
2397 {
2398 	const char *sep = "";
2399 	int i;
2400 
2401 	if (cipherset == IEEE80211_WPA_CIPHER_NONE) {
2402 		printf("none");
2403 		return;
2404 	}
2405 	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++) {
2406 		if (cipherset & ciphers[i].cipher) {
2407 			printf("%s%s", sep, ciphers[i].name);
2408 			sep = ",";
2409 		}
2410 	}
2411 }
2412 
2413 static void
2414 print_assoc_failures(uint32_t assoc_fail)
2415 {
2416 	/* Filter out the most obvious failure cases. */
2417 	assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_ESSID;
2418 	if (assoc_fail & IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY)
2419 		assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_WPA_PROTO;
2420 	assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY;
2421 
2422 	if (assoc_fail == 0)
2423 		return;
2424 
2425 	printb_status(assoc_fail, IEEE80211_NODEREQ_ASSOCFAIL_BITS);
2426 }
2427 
2428 void
2429 ieee80211_status(void)
2430 {
2431 	int len, inwid, ijoin, inwkey, ipsk, ichan, ipwr;
2432 	int ibssid, iwpa, assocfail = 0;
2433 	struct ieee80211_nwid nwid;
2434 	struct ieee80211_join join;
2435 	struct ieee80211_nwkey nwkey;
2436 	struct ieee80211_wpapsk psk;
2437 	struct ieee80211_power power;
2438 	struct ieee80211chanreq channel;
2439 	struct ieee80211_bssid bssid;
2440 	struct ieee80211_wpaparams wpa;
2441 	struct ieee80211_nodereq nr;
2442 	u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
2443 	struct ether_addr ea;
2444 
2445 	/* get current status via ioctls */
2446 	memset(&ifr, 0, sizeof(ifr));
2447 	ifr.ifr_data = (caddr_t)&nwid;
2448 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2449 	inwid = ioctl(sock, SIOCG80211NWID, (caddr_t)&ifr);
2450 
2451 	ifr.ifr_data = (caddr_t)&join;
2452 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2453 	ijoin = ioctl(sock, SIOCG80211JOIN, (caddr_t)&ifr);
2454 
2455 	memset(&nwkey, 0, sizeof(nwkey));
2456 	strlcpy(nwkey.i_name, ifname, sizeof(nwkey.i_name));
2457 	inwkey = ioctl(sock, SIOCG80211NWKEY, (caddr_t)&nwkey);
2458 
2459 	memset(&psk, 0, sizeof(psk));
2460 	strlcpy(psk.i_name, ifname, sizeof(psk.i_name));
2461 	ipsk = ioctl(sock, SIOCG80211WPAPSK, (caddr_t)&psk);
2462 
2463 	memset(&power, 0, sizeof(power));
2464 	strlcpy(power.i_name, ifname, sizeof(power.i_name));
2465 	ipwr = ioctl(sock, SIOCG80211POWER, &power);
2466 
2467 	memset(&channel, 0, sizeof(channel));
2468 	strlcpy(channel.i_name, ifname, sizeof(channel.i_name));
2469 	ichan = ioctl(sock, SIOCG80211CHANNEL, (caddr_t)&channel);
2470 
2471 	memset(&bssid, 0, sizeof(bssid));
2472 	strlcpy(bssid.i_name, ifname, sizeof(bssid.i_name));
2473 	ibssid = ioctl(sock, SIOCG80211BSSID, &bssid);
2474 
2475 	memset(&wpa, 0, sizeof(wpa));
2476 	strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2477 	iwpa = ioctl(sock, SIOCG80211WPAPARMS, &wpa);
2478 
2479 	/* check if any ieee80211 option is active */
2480 	if (inwid == 0 || ijoin == 0 || inwkey == 0 || ipsk == 0 ||
2481 	    ipwr == 0 || ichan == 0 || ibssid == 0 || iwpa == 0)
2482 		fputs("\tieee80211:", stdout);
2483 	else
2484 		return;
2485 
2486 	if (inwid == 0) {
2487 		/* nwid.i_nwid is not NUL terminated. */
2488 		len = nwid.i_len;
2489 		if (len > IEEE80211_NWID_LEN)
2490 			len = IEEE80211_NWID_LEN;
2491 		if (ijoin == 0 && join.i_flags & IEEE80211_JOIN_FOUND)
2492 			fputs(" join ", stdout);
2493 		else
2494 			fputs(" nwid ", stdout);
2495 		print_string(nwid.i_nwid, len);
2496 	}
2497 
2498 	if (ichan == 0 && channel.i_channel != 0 &&
2499 	    channel.i_channel != IEEE80211_CHAN_ANY)
2500 		printf(" chan %u", channel.i_channel);
2501 
2502 	memset(&zero_bssid, 0, sizeof(zero_bssid));
2503 	if (ibssid == 0 &&
2504 	    memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
2505 		memcpy(&ea.ether_addr_octet, bssid.i_bssid,
2506 		    sizeof(ea.ether_addr_octet));
2507 		printf(" bssid %s", ether_ntoa(&ea));
2508 
2509 		bzero(&nr, sizeof(nr));
2510 		bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
2511 		strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
2512 		if (ioctl(sock, SIOCG80211NODE, &nr) == 0) {
2513 			if (nr.nr_rssi) {
2514 				if (nr.nr_max_rssi)
2515 					printf(" %u%%",
2516 					    IEEE80211_NODEREQ_RSSI(&nr));
2517 				else
2518 					printf(" %ddBm", nr.nr_rssi);
2519 			}
2520 			assocfail = nr.nr_assoc_fail;
2521 		}
2522 	}
2523 
2524 	if (inwkey == 0 && nwkey.i_wepon > IEEE80211_NWKEY_OPEN)
2525 		fputs(" nwkey", stdout);
2526 
2527 	if (ipsk == 0 && psk.i_enabled)
2528 		fputs(" wpakey", stdout);
2529 	if (iwpa == 0 && wpa.i_enabled) {
2530 		const char *sep;
2531 
2532 		fputs(" wpaprotos ", stdout); sep = "";
2533 		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1) {
2534 			fputs("wpa1", stdout);
2535 			sep = ",";
2536 		}
2537 		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
2538 			printf("%swpa2", sep);
2539 
2540 		fputs(" wpaakms ", stdout); sep = "";
2541 		if (wpa.i_akms & IEEE80211_WPA_AKM_PSK) {
2542 			fputs("psk", stdout);
2543 			sep = ",";
2544 		}
2545 		if (wpa.i_akms & IEEE80211_WPA_AKM_8021X)
2546 			printf("%s802.1x", sep);
2547 
2548 		fputs(" wpaciphers ", stdout);
2549 		print_cipherset(wpa.i_ciphers);
2550 
2551 		fputs(" wpagroupcipher ", stdout);
2552 		print_cipherset(wpa.i_groupcipher);
2553 	}
2554 
2555 	if (ipwr == 0 && power.i_enabled)
2556 		printf(" powersave on (%dms sleep)", power.i_maxsleep);
2557 
2558 	if (ioctl(sock, SIOCG80211FLAGS, (caddr_t)&ifr) == 0 &&
2559 	    ifr.ifr_flags) {
2560 		putchar(' ');
2561 		printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
2562 	}
2563 
2564 	if (assocfail) {
2565 		putchar(' ');
2566 		print_assoc_failures(assocfail);
2567 	}
2568 	putchar('\n');
2569 	if (show_join)
2570 		join_status();
2571 	if (shownet80211chans)
2572 		ieee80211_listchans();
2573 	else if (shownet80211nodes)
2574 		ieee80211_listnodes();
2575 }
2576 
2577 void
2578 showjoin(const char *cmd, int val)
2579 {
2580 	show_join = 1;
2581 	return;
2582 }
2583 
2584 void
2585 join_status(void)
2586 {
2587 	struct ieee80211_joinreq_all ja;
2588 	struct ieee80211_join *jn = NULL;
2589 	struct ieee80211_wpaparams *wpa;
2590 	int jsz = 100;
2591 	int ojsz;
2592 	int i;
2593 	int r;
2594 	int maxlen, len;
2595 
2596 	bzero(&ja, sizeof(ja));
2597 	jn = recallocarray(NULL, 0, jsz, sizeof(*jn));
2598 	if (jn == NULL)
2599 		err(1, "recallocarray");
2600 	ojsz = jsz;
2601 	while (1) {
2602 		ja.ja_node = jn;
2603 		ja.ja_size = jsz * sizeof(*jn);
2604 		strlcpy(ja.ja_ifname, ifname, sizeof(ja.ja_ifname));
2605 
2606 		if ((r = ioctl(sock, SIOCG80211JOINALL, &ja)) != 0) {
2607 			if (errno == E2BIG) {
2608 				jsz += 100;
2609 				jn = recallocarray(jn, ojsz, jsz, sizeof(*jn));
2610 				if (jn == NULL)
2611 					err(1, "recallocarray");
2612 				ojsz = jsz;
2613 				continue;
2614 			} else if (errno != ENOENT)
2615 				warn("SIOCG80211JOINALL");
2616 			return;
2617 		}
2618 		break;
2619 	}
2620 
2621 	if (!ja.ja_nodes)
2622 		return;
2623 
2624 	maxlen = 0;
2625 	for (i = 0; i < ja.ja_nodes; i++) {
2626 		len = len_string(jn[i].i_nwid, jn[i].i_len);
2627 		if (len > maxlen)
2628 			maxlen = len;
2629 	}
2630 
2631 	for (i = 0; i < ja.ja_nodes; i++) {
2632 		printf("\t      ");
2633 		if (jn[i].i_len > IEEE80211_NWID_LEN)
2634 			jn[i].i_len = IEEE80211_NWID_LEN;
2635 		len = print_string(jn[i].i_nwid, jn[i].i_len);
2636 		printf("%-*s", maxlen - len, "");
2637 		if (jn[i].i_flags) {
2638 			const char *sep;
2639 			printf(" ");
2640 
2641 			if (jn[i].i_flags & IEEE80211_JOIN_NWKEY)
2642 				printf("nwkey");
2643 
2644 			if (jn[i].i_flags & IEEE80211_JOIN_WPA) {
2645 				wpa = &jn[i].i_wpaparams;
2646 
2647 				printf("wpaprotos "); sep = "";
2648 				if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1) {
2649 					printf("wpa1");
2650 					sep = ",";
2651 				}
2652 				if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
2653 					printf("%swpa2", sep);
2654 
2655 				printf(" wpaakms "); sep = "";
2656 				if (wpa->i_akms & IEEE80211_WPA_AKM_PSK) {
2657 					printf("psk");
2658 					sep = ",";
2659 				}
2660 				if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
2661 					printf("%s802.1x", sep);
2662 
2663 				printf(" wpaciphers ");
2664 				print_cipherset(wpa->i_ciphers);
2665 
2666 				printf(" wpagroupcipher ");
2667 				print_cipherset(wpa->i_groupcipher);
2668 			}
2669 		}
2670 		putchar('\n');
2671 	}
2672 }
2673 
2674 void
2675 ieee80211_listchans(void)
2676 {
2677 	static struct ieee80211_channel chans[256+1];
2678 	struct ieee80211_chanreq_all ca;
2679 	int i;
2680 
2681 	bzero(&ca, sizeof(ca));
2682 	bzero(chans, sizeof(chans));
2683 	ca.i_chans = chans;
2684 	strlcpy(ca.i_name, ifname, sizeof(ca.i_name));
2685 
2686 	if (ioctl(sock, SIOCG80211ALLCHANS, &ca) != 0) {
2687 		warn("SIOCG80211ALLCHANS");
2688 		return;
2689 	}
2690 	printf("\t\t%4s  %-8s  %s\n", "chan", "freq", "properties");
2691 	for (i = 1; i <= 256; i++) {
2692 		if (chans[i].ic_flags == 0)
2693 			continue;
2694 		printf("\t\t%4d  %4d MHz  ", i, chans[i].ic_freq);
2695 		if (chans[i].ic_flags & IEEE80211_CHAN_PASSIVE)
2696 			printf("passive scan");
2697 		else
2698 			putchar('-');
2699 		putchar('\n');
2700 	}
2701 }
2702 
2703 /*
2704  * Returns an integer less than, equal to, or greater than zero if nr1's
2705  * RSSI is respectively greater than, equal to, or less than nr2's RSSI.
2706  */
2707 static int
2708 rssicmp(const void *nr1, const void *nr2)
2709 {
2710 	const struct ieee80211_nodereq *x = nr1, *y = nr2;
2711 	return y->nr_rssi < x->nr_rssi ? -1 : y->nr_rssi > x->nr_rssi;
2712 }
2713 
2714 void
2715 ieee80211_listnodes(void)
2716 {
2717 	struct ieee80211_nodereq_all na;
2718 	struct ieee80211_nodereq nr[512];
2719 	struct ifreq ifr;
2720 	int i;
2721 
2722 	if ((flags & IFF_UP) == 0) {
2723 		printf("\t\tcannot scan, interface is down\n");
2724 		return;
2725 	}
2726 
2727 	bzero(&ifr, sizeof(ifr));
2728 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2729 
2730 	if (ioctl(sock, SIOCS80211SCAN, (caddr_t)&ifr) != 0) {
2731 		if (errno == EPERM)
2732 			printf("\t\tno permission to scan\n");
2733 		return;
2734 	}
2735 
2736 	bzero(&na, sizeof(na));
2737 	bzero(&nr, sizeof(nr));
2738 	na.na_node = nr;
2739 	na.na_size = sizeof(nr);
2740 	strlcpy(na.na_ifname, ifname, sizeof(na.na_ifname));
2741 
2742 	if (ioctl(sock, SIOCG80211ALLNODES, &na) != 0) {
2743 		warn("SIOCG80211ALLNODES");
2744 		return;
2745 	}
2746 
2747 	if (!na.na_nodes)
2748 		printf("\t\tnone\n");
2749 	else
2750 		qsort(nr, na.na_nodes, sizeof(*nr), rssicmp);
2751 
2752 	for (i = 0; i < na.na_nodes; i++) {
2753 		printf("\t\t");
2754 		ieee80211_printnode(&nr[i]);
2755 		putchar('\n');
2756 	}
2757 }
2758 
2759 void
2760 ieee80211_printnode(struct ieee80211_nodereq *nr)
2761 {
2762 	int len, i;
2763 
2764 	if (nr->nr_flags & IEEE80211_NODEREQ_AP ||
2765 	    nr->nr_capinfo & IEEE80211_CAPINFO_IBSS) {
2766 		len = nr->nr_nwid_len;
2767 		if (len > IEEE80211_NWID_LEN)
2768 			len = IEEE80211_NWID_LEN;
2769 		printf("nwid ");
2770 		print_string(nr->nr_nwid, len);
2771 		putchar(' ');
2772 
2773 		printf("chan %u ", nr->nr_channel);
2774 
2775 		printf("bssid %s ",
2776 		    ether_ntoa((struct ether_addr*)nr->nr_bssid));
2777 	}
2778 
2779 	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2780 		printf("lladdr %s ",
2781 		    ether_ntoa((struct ether_addr*)nr->nr_macaddr));
2782 
2783 	if (nr->nr_max_rssi)
2784 		printf("%u%% ", IEEE80211_NODEREQ_RSSI(nr));
2785 	else
2786 		printf("%ddBm ", nr->nr_rssi);
2787 
2788 	if (nr->nr_pwrsave)
2789 		printf("powersave ");
2790 	/*
2791 	 * Print our current Tx rate for associated nodes.
2792 	 * Print the fastest supported rate for APs.
2793 	 */
2794 	if ((nr->nr_flags & (IEEE80211_NODEREQ_AP)) == 0) {
2795 		if (nr->nr_flags & IEEE80211_NODEREQ_VHT) {
2796 			printf("VHT-MCS%d/%dSS", nr->nr_txmcs, nr->nr_vht_ss);
2797 		} else if (nr->nr_flags & IEEE80211_NODEREQ_HT) {
2798 			printf("HT-MCS%d ", nr->nr_txmcs);
2799 		} else if (nr->nr_nrates) {
2800 			printf("%uM ",
2801 			    (nr->nr_rates[nr->nr_txrate] & IEEE80211_RATE_VAL)
2802 			    / 2);
2803 		}
2804 	} else if (nr->nr_max_rxrate) {
2805 		printf("%uM HT ", nr->nr_max_rxrate);
2806 	} else if (nr->nr_rxmcs[0] != 0) {
2807 		for (i = IEEE80211_HT_NUM_MCS - 1; i >= 0; i--) {
2808 			if (nr->nr_rxmcs[i / 8] & (1 << (i / 10)))
2809 				break;
2810 		}
2811 		printf("HT-MCS%d ", i);
2812 	} else if (nr->nr_nrates) {
2813 		printf("%uM ",
2814 		    (nr->nr_rates[nr->nr_nrates - 1] & IEEE80211_RATE_VAL) / 2);
2815 	}
2816 	/* ESS is the default, skip it */
2817 	nr->nr_capinfo &= ~IEEE80211_CAPINFO_ESS;
2818 	if (nr->nr_capinfo) {
2819 		printb_status(nr->nr_capinfo, IEEE80211_CAPINFO_BITS);
2820 		if (nr->nr_capinfo & IEEE80211_CAPINFO_PRIVACY) {
2821 			if (nr->nr_rsnprotos) {
2822 				if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA2)
2823 					fputs(",wpa2", stdout);
2824 				if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA1)
2825 					fputs(",wpa1", stdout);
2826 			} else
2827 				fputs(",wep", stdout);
2828 
2829 			if (nr->nr_rsnakms & IEEE80211_WPA_AKM_8021X ||
2830 			    nr->nr_rsnakms & IEEE80211_WPA_AKM_SHA256_8021X)
2831 				fputs(",802.1x", stdout);
2832 		}
2833 		putchar(' ');
2834 	}
2835 
2836 	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2837 		printb_status(IEEE80211_NODEREQ_STATE(nr->nr_state),
2838 		    IEEE80211_NODEREQ_STATE_BITS);
2839 	else if (nr->nr_assoc_fail)
2840 		print_assoc_failures(nr->nr_assoc_fail);
2841 }
2842 
2843 void
2844 init_current_media(void)
2845 {
2846 	struct ifmediareq ifmr;
2847 
2848 	/*
2849 	 * If we have not yet done so, grab the currently-selected
2850 	 * media.
2851 	 */
2852 	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2853 		(void) memset(&ifmr, 0, sizeof(ifmr));
2854 		(void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
2855 
2856 		if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
2857 			/*
2858 			 * If we get E2BIG, the kernel is telling us
2859 			 * that there are more, so we can ignore it.
2860 			 */
2861 			if (errno != E2BIG)
2862 				err(1, "SIOCGIFMEDIA");
2863 		}
2864 
2865 		media_current = ifmr.ifm_current;
2866 	}
2867 
2868 	/* Sanity. */
2869 	if (IFM_TYPE(media_current) == 0)
2870 		errx(1, "%s: no link type?", ifname);
2871 }
2872 
2873 void
2874 process_media_commands(void)
2875 {
2876 
2877 	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2878 		/* Nothing to do. */
2879 		return;
2880 	}
2881 
2882 	/*
2883 	 * Media already set up, and commands sanity-checked.  Set/clear
2884 	 * any options, and we're ready to go.
2885 	 */
2886 	media_current |= mediaopt_set;
2887 	media_current &= ~mediaopt_clear;
2888 
2889 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2890 	ifr.ifr_media = media_current;
2891 
2892 	if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1)
2893 		err(1, "SIOCSIFMEDIA");
2894 }
2895 
2896 /* ARGSUSED */
2897 void
2898 setmedia(const char *val, int d)
2899 {
2900 	uint64_t type, subtype, inst;
2901 
2902 	if (val == NULL) {
2903 		if (showmediaflag)
2904 			usage();
2905 		showmediaflag = 1;
2906 		return;
2907 	}
2908 
2909 	init_current_media();
2910 
2911 	/* Only one media command may be given. */
2912 	if (actions & A_MEDIA)
2913 		errx(1, "only one `media' command may be issued");
2914 
2915 	/* Must not come after mode commands */
2916 	if (actions & A_MEDIAMODE)
2917 		errx(1, "may not issue `media' after `mode' commands");
2918 
2919 	/* Must not come after mediaopt commands */
2920 	if (actions & A_MEDIAOPT)
2921 		errx(1, "may not issue `media' after `mediaopt' commands");
2922 
2923 	/*
2924 	 * No need to check if `instance' has been issued; setmediainst()
2925 	 * craps out if `media' has not been specified.
2926 	 */
2927 
2928 	type = IFM_TYPE(media_current);
2929 	inst = IFM_INST(media_current);
2930 
2931 	/* Look up the subtype. */
2932 	subtype = get_media_subtype(type, val);
2933 
2934 	/* Build the new current media word. */
2935 	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
2936 
2937 	/* Media will be set after other processing is complete. */
2938 }
2939 
2940 /* ARGSUSED */
2941 void
2942 setmediamode(const char *val, int d)
2943 {
2944 	uint64_t type, subtype, options, inst, mode;
2945 
2946 	init_current_media();
2947 
2948 	/* Can only issue `mode' once. */
2949 	if (actions & A_MEDIAMODE)
2950 		errx(1, "only one `mode' command may be issued");
2951 
2952 	type = IFM_TYPE(media_current);
2953 	subtype = IFM_SUBTYPE(media_current);
2954 	options = IFM_OPTIONS(media_current);
2955 	inst = IFM_INST(media_current);
2956 
2957 	if ((mode = get_media_mode(type, val)) == -1)
2958 		errx(1, "invalid media mode: %s", val);
2959 	media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
2960 	/* Media will be set after other processing is complete. */
2961 }
2962 
2963 void
2964 unsetmediamode(const char *val, int d)
2965 {
2966 	uint64_t type, subtype, options, inst;
2967 
2968 	init_current_media();
2969 
2970 	/* Can only issue `mode' once. */
2971 	if (actions & A_MEDIAMODE)
2972 		errx(1, "only one `mode' command may be issued");
2973 
2974 	type = IFM_TYPE(media_current);
2975 	subtype = IFM_SUBTYPE(media_current);
2976 	options = IFM_OPTIONS(media_current);
2977 	inst = IFM_INST(media_current);
2978 
2979 	media_current = IFM_MAKEWORD(type, subtype, options, inst) |
2980 	    (IFM_AUTO << IFM_MSHIFT);
2981 	/* Media will be set after other processing is complete. */
2982 }
2983 
2984 void
2985 setmediaopt(const char *val, int d)
2986 {
2987 
2988 	init_current_media();
2989 
2990 	/* Can only issue `mediaopt' once. */
2991 	if (actions & A_MEDIAOPTSET)
2992 		errx(1, "only one `mediaopt' command may be issued");
2993 
2994 	/* Can't issue `mediaopt' if `instance' has already been issued. */
2995 	if (actions & A_MEDIAINST)
2996 		errx(1, "may not issue `mediaopt' after `instance'");
2997 
2998 	mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
2999 
3000 	/* Media will be set after other processing is complete. */
3001 }
3002 
3003 /* ARGSUSED */
3004 void
3005 unsetmediaopt(const char *val, int d)
3006 {
3007 
3008 	init_current_media();
3009 
3010 	/* Can only issue `-mediaopt' once. */
3011 	if (actions & A_MEDIAOPTCLR)
3012 		errx(1, "only one `-mediaopt' command may be issued");
3013 
3014 	/* May not issue `media' and `-mediaopt'. */
3015 	if (actions & A_MEDIA)
3016 		errx(1, "may not issue both `media' and `-mediaopt'");
3017 
3018 	/*
3019 	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
3020 	 * implicitly checks for A_MEDIAINST.
3021 	 */
3022 
3023 	mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
3024 
3025 	/* Media will be set after other processing is complete. */
3026 }
3027 
3028 /* ARGSUSED */
3029 void
3030 setmediainst(const char *val, int d)
3031 {
3032 	uint64_t type, subtype, options, inst;
3033 	const char *errmsg = NULL;
3034 
3035 	init_current_media();
3036 
3037 	/* Can only issue `instance' once. */
3038 	if (actions & A_MEDIAINST)
3039 		errx(1, "only one `instance' command may be issued");
3040 
3041 	/* Must have already specified `media' */
3042 	if ((actions & A_MEDIA) == 0)
3043 		errx(1, "must specify `media' before `instance'");
3044 
3045 	type = IFM_TYPE(media_current);
3046 	subtype = IFM_SUBTYPE(media_current);
3047 	options = IFM_OPTIONS(media_current);
3048 
3049 	inst = strtonum(val, 0, IFM_INST_MAX, &errmsg);
3050 	if (errmsg)
3051 		errx(1, "media instance %s: %s", val, errmsg);
3052 
3053 	media_current = IFM_MAKEWORD(type, subtype, options, inst);
3054 
3055 	/* Media will be set after other processing is complete. */
3056 }
3057 
3058 
3059 const struct ifmedia_description ifm_type_descriptions[] =
3060     IFM_TYPE_DESCRIPTIONS;
3061 
3062 const struct ifmedia_description ifm_subtype_descriptions[] =
3063     IFM_SUBTYPE_DESCRIPTIONS;
3064 
3065 struct ifmedia_description ifm_mode_descriptions[] =
3066     IFM_MODE_DESCRIPTIONS;
3067 
3068 const struct ifmedia_description ifm_option_descriptions[] =
3069     IFM_OPTION_DESCRIPTIONS;
3070 
3071 const char *
3072 get_media_type_string(uint64_t mword)
3073 {
3074 	const struct ifmedia_description *desc;
3075 
3076 	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
3077 	    desc++) {
3078 		if (IFM_TYPE(mword) == desc->ifmt_word)
3079 			return (desc->ifmt_string);
3080 	}
3081 	return ("<unknown type>");
3082 }
3083 
3084 const char *
3085 get_media_subtype_string(uint64_t mword)
3086 {
3087 	const struct ifmedia_description *desc;
3088 
3089 	for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
3090 	    desc++) {
3091 		if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
3092 		    IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
3093 			return (desc->ifmt_string);
3094 	}
3095 	return ("<unknown subtype>");
3096 }
3097 
3098 uint64_t
3099 get_media_subtype(uint64_t type, const char *val)
3100 {
3101 	uint64_t rval;
3102 
3103 	rval = lookup_media_word(ifm_subtype_descriptions, type, val);
3104 	if (rval == -1)
3105 		errx(1, "unknown %s media subtype: %s",
3106 		    get_media_type_string(type), val);
3107 
3108 	return (rval);
3109 }
3110 
3111 uint64_t
3112 get_media_mode(uint64_t type, const char *val)
3113 {
3114 	uint64_t rval;
3115 
3116 	rval = lookup_media_word(ifm_mode_descriptions, type, val);
3117 	if (rval == -1)
3118 		errx(1, "unknown %s media mode: %s",
3119 		    get_media_type_string(type), val);
3120 	return (rval);
3121 }
3122 
3123 uint64_t
3124 get_media_options(uint64_t type, const char *val)
3125 {
3126 	char *optlist, *str;
3127 	uint64_t option, rval = 0;
3128 
3129 	/* We muck with the string, so copy it. */
3130 	optlist = strdup(val);
3131 	if (optlist == NULL)
3132 		err(1, "strdup");
3133 	str = optlist;
3134 
3135 	/*
3136 	 * Look up the options in the user-provided comma-separated list.
3137 	 */
3138 	for (; (str = strtok(str, ",")) != NULL; str = NULL) {
3139 		option = lookup_media_word(ifm_option_descriptions, type, str);
3140 		if (option == -1)
3141 			errx(1, "unknown %s media option: %s",
3142 			    get_media_type_string(type), str);
3143 		rval |= IFM_OPTIONS(option);
3144 	}
3145 
3146 	free(optlist);
3147 	return (rval);
3148 }
3149 
3150 uint64_t
3151 lookup_media_word(const struct ifmedia_description *desc, uint64_t type,
3152     const char *val)
3153 {
3154 
3155 	for (; desc->ifmt_string != NULL; desc++) {
3156 		if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
3157 		    strcasecmp(desc->ifmt_string, val) == 0)
3158 			return (desc->ifmt_word);
3159 	}
3160 	return (-1);
3161 }
3162 
3163 void
3164 print_media_word(uint64_t ifmw, int print_type, int as_syntax)
3165 {
3166 	const struct ifmedia_description *desc;
3167 	uint64_t seen_option = 0;
3168 
3169 	if (print_type)
3170 		printf("%s ", get_media_type_string(ifmw));
3171 	printf("%s%s", as_syntax ? "media " : "",
3172 	    get_media_subtype_string(ifmw));
3173 
3174 	/* Find mode. */
3175 	if (IFM_MODE(ifmw) != 0) {
3176 		for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL;
3177 		    desc++) {
3178 			if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
3179 			    IFM_MODE(ifmw) == IFM_MODE(desc->ifmt_word)) {
3180 				printf(" mode %s", desc->ifmt_string);
3181 				break;
3182 			}
3183 		}
3184 	}
3185 
3186 	/* Find options. */
3187 	for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
3188 	    desc++) {
3189 		if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
3190 		    (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
3191 		    (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
3192 			if (seen_option == 0)
3193 				printf(" %s", as_syntax ? "mediaopt " : "");
3194 			printf("%s%s", seen_option ? "," : "",
3195 			    desc->ifmt_string);
3196 			seen_option |= IFM_OPTIONS(desc->ifmt_word);
3197 		}
3198 	}
3199 	if (IFM_INST(ifmw) != 0)
3200 		printf(" instance %lld", IFM_INST(ifmw));
3201 }
3202 
3203 static void
3204 print_tunnel(const struct if_laddrreq *req)
3205 {
3206 	char psrcaddr[NI_MAXHOST];
3207 	char pdstaddr[NI_MAXHOST];
3208 	const char *ver = "";
3209 	const int niflag = NI_NUMERICHOST;
3210 
3211 	if (req == NULL) {
3212 		printf("(unset)");
3213 		return;
3214 	}
3215 
3216 	psrcaddr[0] = pdstaddr[0] = '\0';
3217 
3218 	if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len,
3219 	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
3220 		strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
3221 	if (req->addr.ss_family == AF_INET6)
3222 		ver = "6";
3223 
3224 	printf("inet%s %s", ver, psrcaddr);
3225 
3226 	if (req->dstaddr.ss_family != AF_UNSPEC) {
3227 		in_port_t dstport = 0;
3228 		const struct sockaddr_in *sin;
3229 		const struct sockaddr_in6 *sin6;
3230 
3231 		if (getnameinfo((struct sockaddr *)&req->dstaddr,
3232 		    req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr),
3233 		    0, 0, niflag) != 0)
3234 			strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
3235 
3236 		printf(" --> %s", pdstaddr);
3237 
3238 		switch (req->dstaddr.ss_family) {
3239 		case AF_INET:
3240 			sin = (const struct sockaddr_in *)&req->dstaddr;
3241 			dstport = sin->sin_port;
3242 			break;
3243 		case AF_INET6:
3244 			sin6 = (const struct sockaddr_in6 *)&req->dstaddr;
3245 			dstport = sin6->sin6_port;
3246 			break;
3247 		}
3248 
3249 		if (dstport)
3250 			printf(":%u", ntohs(dstport));
3251 	}
3252 }
3253 
3254 /* ARGSUSED */
3255 static void
3256 phys_status(int force)
3257 {
3258 	struct if_laddrreq req;
3259 	struct if_laddrreq *r = &req;
3260 
3261 	memset(&req, 0, sizeof(req));
3262 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3263 	if (ioctl(sock, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) {
3264 		if (errno != EADDRNOTAVAIL)
3265 			return;
3266 
3267 		r = NULL;
3268 	}
3269 
3270 	printf("\ttunnel: ");
3271 	print_tunnel(r);
3272 
3273 	if (ioctl(sock, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) {
3274 		if (ifr.ifr_ttl == -1)
3275 			printf(" ttl copy");
3276 		else if (ifr.ifr_ttl > 0)
3277 			printf(" ttl %d", ifr.ifr_ttl);
3278 	}
3279 
3280 	if (ioctl(sock, SIOCGLIFPHYDF, (caddr_t)&ifr) == 0)
3281 		printf(" %s", ifr.ifr_df ? "df" : "nodf");
3282 
3283 #ifndef SMALL
3284 	if (ioctl(sock, SIOCGLIFPHYECN, (caddr_t)&ifr) == 0)
3285 		printf(" %s", ifr.ifr_metric ? "ecn" : "noecn");
3286 
3287 	if (ioctl(sock, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
3288 	    (rdomainid != 0 || ifr.ifr_rdomainid != 0))
3289 		printf(" rdomain %d", ifr.ifr_rdomainid);
3290 #endif
3291 	printf("\n");
3292 }
3293 
3294 #ifndef SMALL
3295 const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
3296 
3297 const struct ifmedia_status_description ifm_status_descriptions[] =
3298 	IFM_STATUS_DESCRIPTIONS;
3299 #endif
3300 
3301 const struct if_status_description if_status_descriptions[] =
3302 	LINK_STATE_DESCRIPTIONS;
3303 
3304 const char *
3305 get_linkstate(int mt, int link_state)
3306 {
3307 	const struct if_status_description *p;
3308 	static char buf[8];
3309 
3310 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
3311 		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
3312 			return (p->ifs_string);
3313 	}
3314 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
3315 	return buf;
3316 }
3317 
3318 /*
3319  * Print the status of the interface.  If an address family was
3320  * specified, show it and it only; otherwise, show them all.
3321  */
3322 void
3323 status(int link, struct sockaddr_dl *sdl, int ls)
3324 {
3325 	const struct afswtch *p = afp;
3326 	struct ifmediareq ifmr;
3327 #ifndef SMALL
3328 	struct ifreq ifrdesc;
3329 	struct ifkalivereq ikardesc;
3330 	char ifdescr[IFDESCRSIZE];
3331 	char pifname[IF_NAMESIZE];
3332 #endif
3333 	uint64_t *media_list;
3334 	int i;
3335 	char sep;
3336 
3337 
3338 	printf("%s: ", ifname);
3339 	printb("flags", flags | (xflags << 16), IFFBITS);
3340 #ifndef SMALL
3341 	if (rdomainid)
3342 		printf(" rdomain %d", rdomainid);
3343 #endif
3344 	if (metric)
3345 		printf(" metric %lu", metric);
3346 	if (mtu)
3347 		printf(" mtu %lu", mtu);
3348 	putchar('\n');
3349 #ifndef SMALL
3350 	if (showcapsflag)
3351 		printifhwfeatures(NULL, 1);
3352 #endif
3353 	if (sdl != NULL && sdl->sdl_alen &&
3354 	    (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
3355 		(void)printf("\tlladdr %s\n", ether_ntoa(
3356 		    (struct ether_addr *)LLADDR(sdl)));
3357 
3358 	sep = '\t';
3359 #ifndef SMALL
3360 	(void) memset(&ifrdesc, 0, sizeof(ifrdesc));
3361 	(void) strlcpy(ifrdesc.ifr_name, ifname, sizeof(ifrdesc.ifr_name));
3362 	ifrdesc.ifr_data = (caddr_t)&ifdescr;
3363 	if (ioctl(sock, SIOCGIFDESCR, &ifrdesc) == 0 &&
3364 	    strlen(ifrdesc.ifr_data))
3365 		printf("\tdescription: %s\n", ifrdesc.ifr_data);
3366 
3367 	if (sdl != NULL) {
3368 		printf("%cindex %u", sep, sdl->sdl_index);
3369 		sep = ' ';
3370 	}
3371 	if (!is_bridge() && ioctl(sock, SIOCGIFPRIORITY, &ifrdesc) == 0) {
3372 		printf("%cpriority %d", sep, ifrdesc.ifr_metric);
3373 		sep = ' ';
3374 	}
3375 #endif
3376 	printf("%cllprio %d\n", sep, llprio);
3377 
3378 #ifndef SMALL
3379 	(void) memset(&ikardesc, 0, sizeof(ikardesc));
3380 	(void) strlcpy(ikardesc.ikar_name, ifname, sizeof(ikardesc.ikar_name));
3381 	if (ioctl(sock, SIOCGETKALIVE, &ikardesc) == 0 &&
3382 	    (ikardesc.ikar_timeo != 0 || ikardesc.ikar_cnt != 0))
3383 		printf("\tkeepalive: timeout %d count %d\n",
3384 		    ikardesc.ikar_timeo, ikardesc.ikar_cnt);
3385 	if (ioctl(sock, SIOCGIFPAIR, &ifrdesc) == 0 && ifrdesc.ifr_index != 0 &&
3386 	    if_indextoname(ifrdesc.ifr_index, pifname) != NULL)
3387 		printf("\tpatch: %s\n", pifname);
3388 #endif
3389 	getencap();
3390 #ifndef SMALL
3391 	carp_status();
3392 	pfsync_status();
3393 	pppoe_status();
3394 	sppp_status();
3395 	mpls_status();
3396 	pflow_status();
3397 	umb_status();
3398 	wg_status();
3399 #endif
3400 	trunk_status();
3401 	getifgroups();
3402 
3403 	(void) memset(&ifmr, 0, sizeof(ifmr));
3404 	(void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
3405 
3406 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
3407 		/*
3408 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
3409 		 */
3410 		if (ls != LINK_STATE_UNKNOWN)
3411 			printf("\tstatus: %s\n",
3412 			    get_linkstate(sdl->sdl_type, ls));
3413 		goto proto_status;
3414 	}
3415 
3416 	if (ifmr.ifm_count == 0) {
3417 		warnx("%s: no media types?", ifname);
3418 		goto proto_status;
3419 	}
3420 
3421 	media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
3422 	if (media_list == NULL)
3423 		err(1, "calloc");
3424 	ifmr.ifm_ulist = media_list;
3425 
3426 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1)
3427 		err(1, "SIOCGIFMEDIA");
3428 
3429 	printf("\tmedia: ");
3430 	print_media_word(ifmr.ifm_current, 1, 0);
3431 	if (ifmr.ifm_active != ifmr.ifm_current) {
3432 		putchar(' ');
3433 		putchar('(');
3434 		print_media_word(ifmr.ifm_active, 0, 0);
3435 		putchar(')');
3436 	}
3437 	putchar('\n');
3438 
3439 #ifdef SMALL
3440 	printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
3441 #else
3442 	if (ifmr.ifm_status & IFM_AVALID) {
3443 		const struct ifmedia_status_description *ifms;
3444 		int bitno, found = 0;
3445 
3446 		printf("\tstatus: ");
3447 		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
3448 			for (ifms = ifm_status_descriptions;
3449 			    ifms->ifms_valid != 0; ifms++) {
3450 				if (ifms->ifms_type !=
3451 				    IFM_TYPE(ifmr.ifm_current) ||
3452 				    ifms->ifms_valid !=
3453 				    ifm_status_valid_list[bitno])
3454 					continue;
3455 				printf("%s%s", found ? ", " : "",
3456 				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
3457 				found = 1;
3458 
3459 				/*
3460 				 * For each valid indicator bit, there's
3461 				 * only one entry for each media type, so
3462 				 * terminate the inner loop now.
3463 				 */
3464 				break;
3465 			}
3466 		}
3467 
3468 		if (found == 0)
3469 			printf("unknown");
3470 		putchar('\n');
3471 	}
3472 
3473 	if (showtransceiver) {
3474 		if (if_sff_info(0) == -1)
3475 			if (!aflag && errno != EPERM && errno != ENOTTY)
3476 				warn("%s transceiver", ifname);
3477 	}
3478 #endif
3479 	ieee80211_status();
3480 
3481 	if (showmediaflag) {
3482 		uint64_t type;
3483 		int printed_type = 0;
3484 
3485 		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
3486 			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
3487 				if (IFM_TYPE(media_list[i]) == type) {
3488 
3489 					/*
3490 					 * Don't advertise media with fixed
3491 					 * data rates for wireless interfaces.
3492 					 * Normal people don't need these.
3493 					 */
3494 					if (type == IFM_IEEE80211 &&
3495 					    (media_list[i] & IFM_TMASK) !=
3496 					    IFM_AUTO)
3497 						continue;
3498 
3499 					if (printed_type == 0) {
3500 					    printf("\tsupported media:\n");
3501 					    printed_type = 1;
3502 					}
3503 					printf("\t\t");
3504 					print_media_word(media_list[i], 0, 1);
3505 					printf("\n");
3506 				}
3507 			}
3508 		}
3509 	}
3510 
3511 	free(media_list);
3512 
3513  proto_status:
3514 	if (link == 0) {
3515 		if ((p = afp) != NULL) {
3516 			p->af_status(1);
3517 		} else for (p = afs; p->af_name; p++) {
3518 			ifr.ifr_addr.sa_family = p->af_af;
3519 			p->af_status(0);
3520 		}
3521 	}
3522 
3523 	phys_status(0);
3524 #ifndef SMALL
3525 	bridge_status();
3526 #endif
3527 }
3528 
3529 /* ARGSUSED */
3530 void
3531 in_status(int force)
3532 {
3533 	struct sockaddr_in *sin, sin2;
3534 
3535 	getsock(AF_INET);
3536 	if (sock == -1) {
3537 		if (errno == EPROTONOSUPPORT)
3538 			return;
3539 		err(1, "socket");
3540 	}
3541 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3542 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
3543 
3544 	/*
3545 	 * We keep the interface address and reset it before each
3546 	 * ioctl() so we can get ifaliases information (as opposed
3547 	 * to the primary interface netmask/dstaddr/broadaddr, if
3548 	 * the ifr_addr field is zero).
3549 	 */
3550 	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
3551 
3552 	printf("\tinet %s", inet_ntoa(sin->sin_addr));
3553 	(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3554 	if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) == -1) {
3555 		if (errno != EADDRNOTAVAIL)
3556 			warn("SIOCGIFNETMASK");
3557 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3558 	} else
3559 		netmask.sin_addr =
3560 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
3561 	if (flags & IFF_POINTOPOINT) {
3562 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3563 		if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) {
3564 			if (errno == EADDRNOTAVAIL)
3565 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3566 			else
3567 			    warn("SIOCGIFDSTADDR");
3568 		}
3569 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3570 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
3571 		printf(" --> %s", inet_ntoa(sin->sin_addr));
3572 	}
3573 	printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
3574 	if (flags & IFF_BROADCAST) {
3575 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3576 		if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) == -1) {
3577 			if (errno == EADDRNOTAVAIL)
3578 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3579 			else
3580 			    warn("SIOCGIFBRDADDR");
3581 		}
3582 		(void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3583 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
3584 		if (sin->sin_addr.s_addr != 0)
3585 			printf(" broadcast %s", inet_ntoa(sin->sin_addr));
3586 	}
3587 	putchar('\n');
3588 }
3589 
3590 /* ARGSUSED */
3591 void
3592 setifprefixlen(const char *addr, int d)
3593 {
3594 	if (afp->af_getprefix)
3595 		afp->af_getprefix(addr, MASK);
3596 	explicit_prefix = 1;
3597 }
3598 
3599 void
3600 in6_fillscopeid(struct sockaddr_in6 *sin6)
3601 {
3602 #ifdef __KAME__
3603 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
3604 	    sin6->sin6_scope_id == 0) {
3605 		sin6->sin6_scope_id =
3606 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3607 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
3608 	}
3609 #endif /* __KAME__ */
3610 }
3611 
3612 /* XXX not really an alias */
3613 void
3614 in6_alias(struct in6_ifreq *creq)
3615 {
3616 	struct sockaddr_in6 *sin6;
3617 	struct	in6_ifreq ifr6;		/* shadows file static variable */
3618 	u_int32_t scopeid;
3619 	char hbuf[NI_MAXHOST];
3620 	const int niflag = NI_NUMERICHOST;
3621 
3622 	/* Get the non-alias address for this interface. */
3623 	getsock(AF_INET6);
3624 	if (sock == -1) {
3625 		if (errno == EPROTONOSUPPORT)
3626 			return;
3627 		err(1, "socket");
3628 	}
3629 
3630 	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
3631 
3632 	in6_fillscopeid(sin6);
3633 	scopeid = sin6->sin6_scope_id;
3634 	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3635 	    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3636 		strlcpy(hbuf, "", sizeof hbuf);
3637 	printf("\tinet6 %s", hbuf);
3638 
3639 	if (flags & IFF_POINTOPOINT) {
3640 		(void) memset(&ifr6, 0, sizeof(ifr6));
3641 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3642 		ifr6.ifr_addr = creq->ifr_addr;
3643 		if (ioctl(sock, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) {
3644 			if (errno != EADDRNOTAVAIL)
3645 				warn("SIOCGIFDSTADDR_IN6");
3646 			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
3647 			ifr6.ifr_addr.sin6_family = AF_INET6;
3648 			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
3649 		}
3650 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3651 		in6_fillscopeid(sin6);
3652 		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3653 		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3654 			strlcpy(hbuf, "", sizeof hbuf);
3655 		printf(" --> %s", hbuf);
3656 	}
3657 
3658 	(void) memset(&ifr6, 0, sizeof(ifr6));
3659 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3660 	ifr6.ifr_addr = creq->ifr_addr;
3661 	if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) {
3662 		if (errno != EADDRNOTAVAIL)
3663 			warn("SIOCGIFNETMASK_IN6");
3664 	} else {
3665 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3666 		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
3667 		    sizeof(struct in6_addr)));
3668 	}
3669 
3670 	(void) memset(&ifr6, 0, sizeof(ifr6));
3671 	(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3672 	ifr6.ifr_addr = creq->ifr_addr;
3673 	if (ioctl(sock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) {
3674 		if (errno != EADDRNOTAVAIL)
3675 			warn("SIOCGIFAFLAG_IN6");
3676 	} else {
3677 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
3678 			printf(" anycast");
3679 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
3680 			printf(" tentative");
3681 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
3682 			printf(" duplicated");
3683 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
3684 			printf(" detached");
3685 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
3686 			printf(" deprecated");
3687 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
3688 			printf(" autoconf");
3689 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY)
3690 			printf(" temporary");
3691 	}
3692 
3693 	if (scopeid)
3694 		printf(" scopeid 0x%x", scopeid);
3695 
3696 	if (Lflag) {
3697 		struct in6_addrlifetime *lifetime;
3698 
3699 		(void) memset(&ifr6, 0, sizeof(ifr6));
3700 		(void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3701 		ifr6.ifr_addr = creq->ifr_addr;
3702 		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
3703 		if (ioctl(sock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) {
3704 			if (errno != EADDRNOTAVAIL)
3705 				warn("SIOCGIFALIFETIME_IN6");
3706 		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
3707 			time_t t = time(NULL);
3708 
3709 			printf(" pltime ");
3710 			if (lifetime->ia6t_preferred) {
3711 				printf("%s", lifetime->ia6t_preferred < t
3712 				    ? "0" :
3713 				    sec2str(lifetime->ia6t_preferred - t));
3714 			} else
3715 				printf("infty");
3716 
3717 			printf(" vltime ");
3718 			if (lifetime->ia6t_expire) {
3719 				printf("%s", lifetime->ia6t_expire < t
3720 				    ? "0"
3721 				    : sec2str(lifetime->ia6t_expire - t));
3722 			} else
3723 				printf("infty");
3724 		}
3725 	}
3726 
3727 	printf("\n");
3728 }
3729 
3730 void
3731 in6_status(int force)
3732 {
3733 	in6_alias((struct in6_ifreq *)&ifr6);
3734 }
3735 
3736 #ifndef SMALL
3737 void
3738 settunnel(const char *src, const char *dst)
3739 {
3740 	char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport;
3741 	const char *dstip;
3742 	struct addrinfo *srcres, *dstres;
3743 	int ecode;
3744 	struct if_laddrreq req;
3745 
3746 	if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) {
3747 		/* no port or IPv6 */
3748 		dstip = dst;
3749 		dstport = NULL;
3750 	} else {
3751 		if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf))
3752 			errx(1, "%s bad value", dst);
3753 		dstport = strchr(buf, ':');
3754 		*dstport++ = '\0';
3755 		dstip = buf;
3756 	}
3757 
3758 	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
3759 		errx(1, "error in parsing address string: %s",
3760 		    gai_strerror(ecode));
3761 
3762 	if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0)
3763 		errx(1, "error in parsing address string: %s",
3764 		    gai_strerror(ecode));
3765 
3766 	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
3767 		errx(1,
3768 		    "source and destination address families do not match");
3769 
3770 	memset(&req, 0, sizeof(req));
3771 	(void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3772 	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
3773 	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
3774 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
3775 		warn("SIOCSLIFPHYADDR");
3776 
3777 	freeaddrinfo(srcres);
3778 	freeaddrinfo(dstres);
3779 }
3780 
3781 void
3782 settunneladdr(const char *addr, int ignored)
3783 {
3784 	struct addrinfo hints, *res;
3785 	struct if_laddrreq req;
3786 	ssize_t len;
3787 	int rv;
3788 
3789 	memset(&hints, 0, sizeof(hints));
3790 	hints.ai_family = AF_UNSPEC;
3791 	hints.ai_socktype = SOCK_DGRAM;
3792 	hints.ai_protocol = 0;
3793 	hints.ai_flags = AI_PASSIVE;
3794 
3795 	rv = getaddrinfo(addr, NULL, &hints, &res);
3796 	if (rv != 0)
3797 		errx(1, "tunneladdr %s: %s", addr, gai_strerror(rv));
3798 
3799 	memset(&req, 0, sizeof(req));
3800 	len = strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3801 	if (len >= sizeof(req.iflr_name))
3802 		errx(1, "%s: Interface name too long", ifname);
3803 
3804 	memcpy(&req.addr, res->ai_addr, res->ai_addrlen);
3805 
3806 	req.dstaddr.ss_len = 2;
3807 	req.dstaddr.ss_family = AF_UNSPEC;
3808 
3809 	if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
3810 		warn("tunneladdr %s", addr);
3811 
3812 	freeaddrinfo(res);
3813 }
3814 
3815 /* ARGSUSED */
3816 void
3817 deletetunnel(const char *ignored, int alsoignored)
3818 {
3819 	if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1)
3820 		warn("SIOCDIFPHYADDR");
3821 }
3822 
3823 void
3824 settunnelinst(const char *id, int param)
3825 {
3826 	const char *errmsg = NULL;
3827 	int rdomainid;
3828 
3829 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
3830 	if (errmsg)
3831 		errx(1, "rdomain %s: %s", id, errmsg);
3832 
3833 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3834 	ifr.ifr_rdomainid = rdomainid;
3835 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
3836 		warn("SIOCSLIFPHYRTABLE");
3837 }
3838 
3839 void
3840 unsettunnelinst(const char *ignored, int alsoignored)
3841 {
3842 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3843 	ifr.ifr_rdomainid = 0;
3844 	if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
3845 		warn("SIOCSLIFPHYRTABLE");
3846 }
3847 
3848 void
3849 settunnelttl(const char *id, int param)
3850 {
3851 	const char *errmsg = NULL;
3852 	int ttl;
3853 
3854 	if (strcmp(id, "copy") == 0)
3855 		ttl = -1;
3856 	else {
3857 		ttl = strtonum(id, 0, 0xff, &errmsg);
3858 		if (errmsg)
3859 			errx(1, "tunnelttl %s: %s", id, errmsg);
3860 	}
3861 
3862 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3863 	ifr.ifr_ttl = ttl;
3864 	if (ioctl(sock, SIOCSLIFPHYTTL, (caddr_t)&ifr) == -1)
3865 		warn("SIOCSLIFPHYTTL");
3866 }
3867 
3868 void
3869 settunneldf(const char *ignored, int alsoignored)
3870 {
3871 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3872 	ifr.ifr_df = 1;
3873 	if (ioctl(sock, SIOCSLIFPHYDF, (caddr_t)&ifr) == -1)
3874 		warn("SIOCSLIFPHYDF");
3875 }
3876 
3877 void
3878 settunnelnodf(const char *ignored, int alsoignored)
3879 {
3880 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3881 	ifr.ifr_df = 0;
3882 	if (ioctl(sock, SIOCSLIFPHYDF, (caddr_t)&ifr) == -1)
3883 		warn("SIOCSLIFPHYDF");
3884 }
3885 
3886 void
3887 settunnelecn(const char *ignored, int alsoignored)
3888 {
3889 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3890 	ifr.ifr_metric = 1;
3891 	if (ioctl(sock, SIOCSLIFPHYECN, (caddr_t)&ifr) == -1)
3892 		warn("SIOCSLIFPHYECN");
3893 }
3894 
3895 void
3896 settunnelnoecn(const char *ignored, int alsoignored)
3897 {
3898 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3899 	ifr.ifr_metric = 0;
3900 	if (ioctl(sock, SIOCSLIFPHYECN, (caddr_t)&ifr) == -1)
3901 		warn("SIOCSLIFPHYECN");
3902 }
3903 
3904 void
3905 setvnetflowid(const char *ignored, int alsoignored)
3906 {
3907 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
3908 	    sizeof(ifr.ifr_name))
3909 		errx(1, "vnetflowid: name is too long");
3910 
3911 	ifr.ifr_vnetid = 1;
3912 	if (ioctl(sock, SIOCSVNETFLOWID, &ifr) == -1)
3913 		warn("SIOCSVNETFLOWID");
3914 }
3915 
3916 void
3917 delvnetflowid(const char *ignored, int alsoignored)
3918 {
3919 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
3920 	    sizeof(ifr.ifr_name))
3921 		errx(1, "vnetflowid: name is too long");
3922 
3923 	ifr.ifr_vnetid = 0;
3924 	if (ioctl(sock, SIOCSVNETFLOWID, &ifr) == -1)
3925 		warn("SIOCSVNETFLOWID");
3926 }
3927 
3928 static void
3929 pwe3_neighbor(void)
3930 {
3931 	const char *prefix = "pwe3 remote label";
3932 	struct if_laddrreq req;
3933 	char hbuf[NI_MAXHOST];
3934 	struct sockaddr_mpls *smpls;
3935 	int error;
3936 
3937 	memset(&req, 0, sizeof(req));
3938 	if (strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)) >=
3939 	    sizeof(req.iflr_name))
3940 		errx(1, "pwe3 neighbor: name is too long");
3941 
3942 	if (ioctl(sock, SIOCGPWE3NEIGHBOR, &req) == -1) {
3943 		if (errno != EADDRNOTAVAIL)
3944 			return;
3945 
3946 		printf(" %s (unset)", prefix);
3947 		return;
3948 	}
3949 
3950 	if (req.dstaddr.ss_family != AF_MPLS) {
3951 		warnc(EPFNOSUPPORT, "pwe3 neighbor");
3952 		return;
3953 	}
3954 	smpls = (struct sockaddr_mpls *)&req.dstaddr;
3955 
3956 	error = getnameinfo((struct sockaddr *)&req.addr, sizeof(req.addr),
3957 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
3958 	if (error != 0) {
3959 		warnx("%s: %s", prefix, gai_strerror(error));
3960 		return;
3961 	}
3962 
3963 	printf(" %s %u on %s", prefix, smpls->smpls_label, hbuf);
3964 }
3965 
3966 static void
3967 pwe3_cword(void)
3968 {
3969 	struct ifreq req;
3970 
3971 	memset(&req, 0, sizeof(req));
3972 	if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
3973 	    sizeof(req.ifr_name))
3974 		errx(1, "pwe3 control word: name is too long");
3975 
3976 	if (ioctl(sock, SIOCGPWE3CTRLWORD, &req) == -1) {
3977 		return;
3978 	}
3979 
3980 	printf(" %s", req.ifr_pwe3 ? "cw" : "nocw");
3981 }
3982 
3983 static void
3984 pwe3_fword(void)
3985 {
3986 	struct ifreq req;
3987 
3988 	memset(&req, 0, sizeof(req));
3989 	if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
3990 	    sizeof(req.ifr_name))
3991 		errx(1, "pwe3 control word: name is too long");
3992 
3993 	if (ioctl(sock, SIOCGPWE3FAT, &req) == -1)
3994 		return;
3995 
3996 	printf(" %s", req.ifr_pwe3 ? "fat" : "nofat");
3997 }
3998 
3999 void
4000 mpls_status(void)
4001 {
4002 	struct shim_hdr	shim;
4003 
4004 	bzero(&shim, sizeof(shim));
4005 	ifr.ifr_data = (caddr_t)&shim;
4006 
4007 	if (ioctl(sock, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
4008 		if (errno != EADDRNOTAVAIL)
4009 			return;
4010 
4011 		printf("\tmpls: label (unset)");
4012 	} else
4013 		printf("\tmpls: label %u", shim.shim_label);
4014 
4015 	pwe3_neighbor();
4016 	pwe3_cword();
4017 	pwe3_fword();
4018 
4019 	printf("\n");
4020 }
4021 
4022 /* ARGSUSED */
4023 void
4024 setmplslabel(const char *val, int d)
4025 {
4026 	struct shim_hdr	 shim;
4027 	const char	*estr;
4028 
4029 	bzero(&shim, sizeof(shim));
4030 	ifr.ifr_data = (caddr_t)&shim;
4031 	shim.shim_label = strtonum(val, 0, MPLS_LABEL_MAX, &estr);
4032 
4033 	if (estr)
4034 		errx(1, "mpls label %s is %s", val, estr);
4035 	if (ioctl(sock, SIOCSETLABEL, (caddr_t)&ifr) == -1)
4036 		warn("SIOCSETLABEL");
4037 }
4038 
4039 void
4040 unsetmplslabel(const char *val, int d)
4041 {
4042 	struct ifreq req;
4043 
4044 	memset(&req, 0, sizeof(req));
4045 	if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4046 	    sizeof(req.ifr_name))
4047 		errx(1, "interface name is too long");
4048 
4049 	if (ioctl(sock, SIOCDELLABEL, (caddr_t)&ifr) == -1)
4050 		warn("-mplslabel");
4051 }
4052 
4053 static void
4054 setpwe3(unsigned long cmd, const char *cmdname, int value)
4055 {
4056 	struct ifreq req;
4057 
4058 	memset(&req, 0, sizeof(req));
4059 	if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4060 	    sizeof(req.ifr_name))
4061 		errx(1, "interface name is too long");
4062 
4063 	req.ifr_pwe3 = value;
4064 
4065 	if (ioctl(sock, cmd, &req) == -1)
4066 		warn("%s", cmdname);
4067 }
4068 
4069 void
4070 setpwe3cw(const char *val, int d)
4071 {
4072 	setpwe3(SIOCSPWE3CTRLWORD, "pwecw", 1);
4073 }
4074 
4075 void
4076 unsetpwe3cw(const char *val, int d)
4077 {
4078 	setpwe3(SIOCSPWE3CTRLWORD, "-pwecw", 0);
4079 }
4080 
4081 void
4082 setpwe3fat(const char *val, int d)
4083 {
4084 	setpwe3(SIOCSPWE3FAT, "pwefat", 1);
4085 }
4086 
4087 void
4088 unsetpwe3fat(const char *val, int d)
4089 {
4090 	setpwe3(SIOCSPWE3FAT, "-pwefat", 0);
4091 }
4092 
4093 void
4094 setpwe3neighbor(const char *label, const char *neighbor)
4095 {
4096 	struct if_laddrreq req;
4097 	struct addrinfo hints, *res;
4098 	struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req.dstaddr;
4099 	const char *errstr;
4100 	int error;
4101 
4102 	memset(&req, 0, sizeof(req));
4103 	if (strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)) >=
4104 	    sizeof(req.iflr_name))
4105 		errx(1, "interface name is too long");
4106 
4107 	memset(&hints, 0, sizeof(hints));
4108 	hints.ai_family = AF_UNSPEC;
4109 	hints.ai_socktype = SOCK_DGRAM;
4110 	error = getaddrinfo(neighbor, NULL, &hints, &res);
4111 	if (error != 0)
4112 		errx(1, "pweneighbor %s: %s", neighbor, gai_strerror(error));
4113 
4114 	smpls->smpls_len = sizeof(*smpls);
4115 	smpls->smpls_family = AF_MPLS;
4116 	smpls->smpls_label = strtonum(label,
4117 	    (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
4118 	if (errstr != NULL)
4119 		errx(1, "pweneighbor: invalid label: %s", errstr);
4120 
4121 
4122 	if (res->ai_addrlen > sizeof(req.addr))
4123 		errx(1, "pweneighbors: unexpected socklen");
4124 
4125 	memcpy(&req.addr, res->ai_addr, res->ai_addrlen);
4126 
4127 	freeaddrinfo(res);
4128 
4129 	if (ioctl(sock, SIOCSPWE3NEIGHBOR, &req) == -1)
4130 		warn("pweneighbor");
4131 }
4132 
4133 void
4134 unsetpwe3neighbor(const char *val, int d)
4135 {
4136 	struct ifreq req;
4137 
4138 	memset(&req, 0, sizeof(req));
4139 	if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4140 	    sizeof(req.ifr_name))
4141 		errx(1, "interface name is too long");
4142 
4143 	if (ioctl(sock, SIOCDPWE3NEIGHBOR, &req) == -1)
4144 		warn("-pweneighbor");
4145 }
4146 
4147 void
4148 transceiver(const char *value, int d)
4149 {
4150 	showtransceiver = 1;
4151 }
4152 
4153 void
4154 transceiverdump(const char *value, int d)
4155 {
4156 	if (if_sff_info(1) == -1)
4157 		err(1, "%s transceiver", ifname);
4158 }
4159 #endif /* SMALL */
4160 
4161 void
4162 getvnetflowid(struct ifencap *ife)
4163 {
4164 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4165 	    sizeof(ifr.ifr_name))
4166 		errx(1, "vnetflowid: name is too long");
4167 
4168 	if (ioctl(sock, SIOCGVNETFLOWID, &ifr) == -1)
4169 		return;
4170 
4171 	if (ifr.ifr_vnetid)
4172 		ife->ife_flags |= IFE_VNETFLOWID;
4173 }
4174 
4175 void
4176 setvnetid(const char *id, int param)
4177 {
4178 	const char *errmsg = NULL;
4179 	int64_t vnetid;
4180 
4181 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
4182 
4183 	if (strcasecmp("any", id) == 0)
4184 		vnetid = -1;
4185 	else {
4186 		vnetid = strtonum(id, 0, INT64_MAX, &errmsg);
4187 		if (errmsg)
4188 			errx(1, "vnetid %s: %s", id, errmsg);
4189 	}
4190 
4191 	ifr.ifr_vnetid = vnetid;
4192 	if (ioctl(sock, SIOCSVNETID, (caddr_t)&ifr) == -1)
4193 		warn("SIOCSVNETID");
4194 }
4195 
4196 /* ARGSUSED */
4197 void
4198 delvnetid(const char *ignored, int alsoignored)
4199 {
4200 	if (ioctl(sock, SIOCDVNETID, &ifr) == -1)
4201 		warn("SIOCDVNETID");
4202 }
4203 
4204 void
4205 getvnetid(struct ifencap *ife)
4206 {
4207 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4208 	    sizeof(ifr.ifr_name))
4209 		errx(1, "vnetid: name is too long");
4210 
4211 	if (ioctl(sock, SIOCGVNETID, &ifr) == -1) {
4212 		if (errno != EADDRNOTAVAIL)
4213 			return;
4214 
4215 		ife->ife_flags |= IFE_VNETID_NONE;
4216 		return;
4217 	}
4218 
4219 	if (ifr.ifr_vnetid < 0) {
4220 		ife->ife_flags |= IFE_VNETID_ANY;
4221 		return;
4222 	}
4223 
4224 	ife->ife_flags |= IFE_VNETID_SET;
4225 	ife->ife_vnetid = ifr.ifr_vnetid;
4226 }
4227 
4228 void
4229 setifparent(const char *id, int param)
4230 {
4231 	struct if_parent ifp;
4232 
4233 	if (strlcpy(ifp.ifp_name, ifname, sizeof(ifp.ifp_name)) >=
4234 	    sizeof(ifp.ifp_name))
4235 		errx(1, "parent: name too long");
4236 
4237 	if (strlcpy(ifp.ifp_parent, id, sizeof(ifp.ifp_parent)) >=
4238 	    sizeof(ifp.ifp_parent))
4239 		errx(1, "parent: parent too long");
4240 
4241 	if (ioctl(sock, SIOCSIFPARENT, (caddr_t)&ifp) == -1)
4242 		warn("SIOCSIFPARENT");
4243 }
4244 
4245 /* ARGSUSED */
4246 void
4247 delifparent(const char *ignored, int alsoignored)
4248 {
4249 	if (ioctl(sock, SIOCDIFPARENT, &ifr) == -1)
4250 		warn("SIOCDIFPARENT");
4251 }
4252 
4253 void
4254 getifparent(struct ifencap *ife)
4255 {
4256 	struct if_parent ifp;
4257 
4258 	memset(&ifp, 0, sizeof(ifp));
4259 	if (strlcpy(ifp.ifp_name, ifname, sizeof(ifp.ifp_name)) >=
4260 	    sizeof(ifp.ifp_name))
4261 		errx(1, "parent: name too long");
4262 
4263 	if (ioctl(sock, SIOCGIFPARENT, (caddr_t)&ifp) == -1) {
4264 		if (errno != EADDRNOTAVAIL)
4265 			return;
4266 
4267 		ife->ife_flags |= IFE_PARENT_NONE;
4268 	} else {
4269 		memcpy(ife->ife_parent, ifp.ifp_parent,
4270 		    sizeof(ife->ife_parent));
4271 		ife->ife_flags |= IFE_PARENT_SET;
4272 	}
4273 }
4274 
4275 #ifndef SMALL
4276 void
4277 gettxprio(struct ifencap *ife)
4278 {
4279 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4280 	    sizeof(ifr.ifr_name))
4281 		errx(1, "hdr prio: name is too long");
4282 
4283 	if (ioctl(sock, SIOCGTXHPRIO, (caddr_t)&ifr) == -1)
4284 		return;
4285 
4286 	ife->ife_flags |= IFE_TXHPRIO_SET;
4287 	ife->ife_txhprio = ifr.ifr_hdrprio;
4288 }
4289 
4290 void
4291 settxprio(const char *val, int d)
4292 {
4293 	const char *errmsg = NULL;
4294 
4295 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4296 	    sizeof(ifr.ifr_name))
4297 		errx(1, "tx prio: name is too long");
4298 
4299 	if (strcmp(val, "packet") == 0)
4300 		ifr.ifr_hdrprio = IF_HDRPRIO_PACKET;
4301 	else if (strcmp(val, "payload") == 0)
4302 		ifr.ifr_hdrprio = IF_HDRPRIO_PAYLOAD;
4303 	else {
4304 		ifr.ifr_hdrprio = strtonum(val,
4305 		    IF_HDRPRIO_MIN, IF_HDRPRIO_MAX, &errmsg);
4306 		if (errmsg)
4307 			errx(1, "tx prio %s: %s", val, errmsg);
4308 	}
4309 
4310 	if (ioctl(sock, SIOCSTXHPRIO, (caddr_t)&ifr) == -1)
4311 		warn("SIOCSTXHPRIO");
4312 }
4313 
4314 void
4315 getrxprio(struct ifencap *ife)
4316 {
4317 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4318 	    sizeof(ifr.ifr_name))
4319 		errx(1, "hdr prio: name is too long");
4320 
4321 	if (ioctl(sock, SIOCGRXHPRIO, (caddr_t)&ifr) == -1)
4322 		return;
4323 
4324 	ife->ife_flags |= IFE_RXHPRIO_SET;
4325 	ife->ife_rxhprio = ifr.ifr_hdrprio;
4326 }
4327 
4328 void
4329 setrxprio(const char *val, int d)
4330 {
4331 	const char *errmsg = NULL;
4332 
4333 	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4334 	    sizeof(ifr.ifr_name))
4335 		errx(1, "rx prio: name is too long");
4336 
4337 	if (strcmp(val, "packet") == 0)
4338 		ifr.ifr_hdrprio = IF_HDRPRIO_PACKET;
4339 	else if (strcmp(val, "payload") == 0)
4340 		ifr.ifr_hdrprio = IF_HDRPRIO_PAYLOAD;
4341 	else if (strcmp(val, "outer") == 0)
4342 		ifr.ifr_hdrprio = IF_HDRPRIO_OUTER;
4343 	else {
4344 		ifr.ifr_hdrprio = strtonum(val,
4345 		    IF_HDRPRIO_MIN, IF_HDRPRIO_MAX, &errmsg);
4346 		if (errmsg)
4347 			errx(1, "rx prio %s: %s", val, errmsg);
4348 	}
4349 
4350 	if (ioctl(sock, SIOCSRXHPRIO, (caddr_t)&ifr) == -1)
4351 		warn("SIOCSRXHPRIO");
4352 }
4353 #endif
4354 
4355 void
4356 getencap(void)
4357 {
4358 	struct ifencap ife = { .ife_flags = 0 };
4359 
4360 	getvnetid(&ife);
4361 	getvnetflowid(&ife);
4362 	getifparent(&ife);
4363 #ifndef SMALL
4364 	gettxprio(&ife);
4365 	getrxprio(&ife);
4366 #endif
4367 
4368 	if (ife.ife_flags == 0)
4369 		return;
4370 
4371 	printf("\tencap:");
4372 
4373 	switch (ife.ife_flags & IFE_VNETID_MASK) {
4374 	case IFE_VNETID_NONE:
4375 		printf(" vnetid none");
4376 		break;
4377 	case IFE_VNETID_ANY:
4378 		printf(" vnetid any");
4379 		break;
4380 	case IFE_VNETID_SET:
4381 		printf(" vnetid %lld", ife.ife_vnetid);
4382 		if (ife.ife_flags & IFE_VNETFLOWID)
4383 			printf("+");
4384 		break;
4385 	}
4386 
4387 	switch (ife.ife_flags & IFE_PARENT_MASK) {
4388 	case IFE_PARENT_NONE:
4389 		printf(" parent none");
4390 		break;
4391 	case IFE_PARENT_SET:
4392 		printf(" parent %s", ife.ife_parent);
4393 		break;
4394 	}
4395 
4396 #ifndef SMALL
4397 	if (ife.ife_flags & IFE_TXHPRIO_SET) {
4398 		printf(" txprio ");
4399 		switch (ife.ife_txhprio) {
4400 		case IF_HDRPRIO_PACKET:
4401 			printf("packet");
4402 			break;
4403 		case IF_HDRPRIO_PAYLOAD:
4404 			printf("payload");
4405 			break;
4406 		default:
4407 			printf("%d", ife.ife_txhprio);
4408 			break;
4409 		}
4410 	}
4411 
4412 	if (ife.ife_flags & IFE_RXHPRIO_SET) {
4413 		printf(" rxprio ");
4414 		switch (ife.ife_rxhprio) {
4415 		case IF_HDRPRIO_PACKET:
4416 			printf("packet");
4417 			break;
4418 		case IF_HDRPRIO_PAYLOAD:
4419 			printf("payload");
4420 			break;
4421 		case IF_HDRPRIO_OUTER:
4422 			printf("outer");
4423 			break;
4424 		default:
4425 			printf("%d", ife.ife_rxhprio);
4426 			break;
4427 		}
4428 	}
4429 #endif
4430 
4431 	printf("\n");
4432 }
4433 
4434 void
4435 settrunkport(const char *val, int d)
4436 {
4437 	struct trunk_reqport rp;
4438 
4439 	bzero(&rp, sizeof(rp));
4440 	strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4441 	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
4442 
4443 	if (ioctl(sock, SIOCSTRUNKPORT, &rp) == -1)
4444 		err(1, "SIOCSTRUNKPORT");
4445 }
4446 
4447 void
4448 unsettrunkport(const char *val, int d)
4449 {
4450 	struct trunk_reqport rp;
4451 
4452 	bzero(&rp, sizeof(rp));
4453 	strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4454 	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
4455 
4456 	if (ioctl(sock, SIOCSTRUNKDELPORT, &rp) == -1)
4457 		err(1, "SIOCSTRUNKDELPORT");
4458 }
4459 
4460 void
4461 settrunkproto(const char *val, int d)
4462 {
4463 	struct trunk_protos tpr[] = TRUNK_PROTOS;
4464 	struct trunk_reqall ra;
4465 	int i;
4466 
4467 	bzero(&ra, sizeof(ra));
4468 	ra.ra_proto = TRUNK_PROTO_MAX;
4469 
4470 	for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
4471 		if (strcmp(val, tpr[i].tpr_name) == 0) {
4472 			ra.ra_proto = tpr[i].tpr_proto;
4473 			break;
4474 		}
4475 	}
4476 	if (ra.ra_proto == TRUNK_PROTO_MAX)
4477 		errx(1, "Invalid trunk protocol: %s", val);
4478 
4479 	strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4480 	if (ioctl(sock, SIOCSTRUNK, &ra) != 0)
4481 		err(1, "SIOCSTRUNK");
4482 }
4483 
4484 void
4485 settrunklacpmode(const char *val, int d)
4486 {
4487 	struct trunk_reqall ra;
4488 	struct trunk_opts tops;
4489 
4490 	bzero(&ra, sizeof(ra));
4491 	strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4492 
4493 	if (ioctl(sock, SIOCGTRUNK, &ra) != 0)
4494 		err(1, "SIOCGTRUNK");
4495 
4496 	if (ra.ra_proto != TRUNK_PROTO_LACP)
4497 		errx(1, "Invalid option for trunk: %s", ifname);
4498 
4499 	if (strcmp(val, lacpmodeactive) != 0 &&
4500 	    strcmp(val, lacpmodepassive) != 0)
4501 		errx(1, "Invalid lacpmode option for trunk: %s", ifname);
4502 
4503 	bzero(&tops, sizeof(tops));
4504 	strlcpy(tops.to_ifname, ifname, sizeof(tops.to_ifname));
4505 	tops.to_proto = TRUNK_PROTO_LACP;
4506 	tops.to_opts |= TRUNK_OPT_LACP_MODE;
4507 
4508 	if (strcmp(val, lacpmodeactive) == 0)
4509 		tops.to_lacpopts.lacp_mode = 1;
4510 	else
4511 		tops.to_lacpopts.lacp_mode = 0;
4512 
4513 	if (ioctl(sock, SIOCSTRUNKOPTS, &tops) != 0)
4514 		err(1, "SIOCSTRUNKOPTS");
4515 }
4516 
4517 void
4518 settrunklacptimeout(const char *val, int d)
4519 {
4520 	struct trunk_reqall ra;
4521 	struct trunk_opts tops;
4522 
4523 	bzero(&ra, sizeof(ra));
4524 	strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4525 
4526 	if (ioctl(sock, SIOCGTRUNK, &ra) != 0)
4527 		err(1, "SIOCGTRUNK");
4528 
4529 	if (ra.ra_proto != TRUNK_PROTO_LACP)
4530 		errx(1, "Invalid option for trunk: %s", ifname);
4531 
4532 	if (strcmp(val, lacptimeoutfast) != 0 &&
4533 	    strcmp(val, lacptimeoutslow) != 0)
4534 		errx(1, "Invalid lacptimeout option for trunk: %s", ifname);
4535 
4536 	bzero(&tops, sizeof(tops));
4537 	strlcpy(tops.to_ifname, ifname, sizeof(tops.to_ifname));
4538 	tops.to_proto = TRUNK_PROTO_LACP;
4539 	tops.to_opts |= TRUNK_OPT_LACP_TIMEOUT;
4540 
4541 	if (strcmp(val, lacptimeoutfast) == 0)
4542 		tops.to_lacpopts.lacp_timeout = 1;
4543 	else
4544 		tops.to_lacpopts.lacp_timeout = 0;
4545 
4546 	if (ioctl(sock, SIOCSTRUNKOPTS, &tops) != 0)
4547 		err(1, "SIOCSTRUNKOPTS");
4548 }
4549 
4550 void
4551 trunk_status(void)
4552 {
4553 	struct trunk_protos tpr[] = TRUNK_PROTOS;
4554 	struct trunk_reqport rp, rpbuf[TRUNK_MAX_PORTS];
4555 	struct trunk_reqall ra;
4556 	struct lacp_opreq *lp;
4557 	const char *proto = "<unknown>";
4558 	int i, isport = 0;
4559 
4560 	bzero(&rp, sizeof(rp));
4561 	bzero(&ra, sizeof(ra));
4562 
4563 	strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4564 	strlcpy(rp.rp_portname, ifname, sizeof(rp.rp_portname));
4565 
4566 	if (ioctl(sock, SIOCGTRUNKPORT, &rp) == 0)
4567 		isport = 1;
4568 
4569 	strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4570 	ra.ra_size = sizeof(rpbuf);
4571 	ra.ra_port = rpbuf;
4572 
4573 	if (ioctl(sock, SIOCGTRUNK, &ra) == 0) {
4574 		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
4575 
4576 		for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
4577 			if (ra.ra_proto == tpr[i].tpr_proto) {
4578 				proto = tpr[i].tpr_name;
4579 				break;
4580 			}
4581 		}
4582 
4583 		printf("\ttrunk: trunkproto %s", proto);
4584 		if (isport)
4585 			printf(" trunkdev %s", rp.rp_ifname);
4586 		putchar('\n');
4587 		if (ra.ra_proto == TRUNK_PROTO_LACP) {
4588 			char *act_mac = strdup(
4589 			    ether_ntoa((struct ether_addr*)lp->actor_mac));
4590 			if (act_mac == NULL)
4591 				err(1, "strdup");
4592 			printf("\ttrunk id: [(%04X,%s,%04X,%04X,%04X),\n"
4593 			    "\t\t (%04X,%s,%04X,%04X,%04X)]\n",
4594 			    lp->actor_prio, act_mac,
4595 			    lp->actor_key, lp->actor_portprio, lp->actor_portno,
4596 			    lp->partner_prio,
4597 			    ether_ntoa((struct ether_addr*)lp->partner_mac),
4598 			    lp->partner_key, lp->partner_portprio,
4599 			    lp->partner_portno);
4600 			free(act_mac);
4601 		}
4602 
4603 		for (i = 0; i < ra.ra_ports; i++) {
4604 			lp = (struct lacp_opreq *)&(rpbuf[i].rp_lacpreq);
4605 			if (ra.ra_proto == TRUNK_PROTO_LACP) {
4606 				printf("\t\t%s lacp actor "
4607 				    "system pri 0x%x mac %s, key 0x%x, "
4608 				    "port pri 0x%x number 0x%x\n",
4609 				    rpbuf[i].rp_portname,
4610 				    lp->actor_prio,
4611 				    ether_ntoa((struct ether_addr*)
4612 				     lp->actor_mac),
4613 				    lp->actor_key,
4614 				    lp->actor_portprio, lp->actor_portno);
4615 				printf("\t\t%s lacp actor state ",
4616 				    rpbuf[i].rp_portname);
4617 				printb_status(lp->actor_state,
4618 				    LACP_STATE_BITS);
4619 				putchar('\n');
4620 
4621 				printf("\t\t%s lacp partner "
4622 				    "system pri 0x%x mac %s, key 0x%x, "
4623 				    "port pri 0x%x number 0x%x\n",
4624 				    rpbuf[i].rp_portname,
4625 				    lp->partner_prio,
4626 				    ether_ntoa((struct ether_addr*)
4627 				     lp->partner_mac),
4628 				    lp->partner_key,
4629 				    lp->partner_portprio, lp->partner_portno);
4630 				printf("\t\t%s lacp partner state ",
4631 				    rpbuf[i].rp_portname);
4632 				printb_status(lp->partner_state,
4633 				    LACP_STATE_BITS);
4634 				putchar('\n');
4635 			}
4636 
4637 			printf("\t\t%s port ", rpbuf[i].rp_portname);
4638 			printb_status(rpbuf[i].rp_flags, TRUNK_PORT_BITS);
4639 			putchar('\n');
4640 		}
4641 
4642 		if (showmediaflag) {
4643 			printf("\tsupported trunk protocols:\n");
4644 			for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++)
4645 				printf("\t\ttrunkproto %s\n", tpr[i].tpr_name);
4646 		}
4647 	} else if (isport)
4648 		printf("\ttrunk: trunkdev %s\n", rp.rp_ifname);
4649 }
4650 
4651 #ifndef SMALL
4652 static const char *carp_states[] = { CARP_STATES };
4653 static const char *carp_bal_modes[] = { CARP_BAL_MODES };
4654 
4655 void
4656 carp_status(void)
4657 {
4658 	const char *state, *balmode;
4659 	struct carpreq carpr;
4660 	char peer[32];
4661 	int i;
4662 
4663 	memset((char *)&carpr, 0, sizeof(struct carpreq));
4664 	ifr.ifr_data = (caddr_t)&carpr;
4665 
4666 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4667 		return;
4668 
4669 	if (carpr.carpr_vhids[0] == 0)
4670 		return;
4671 
4672 	if (carpr.carpr_balancing > CARP_BAL_MAXID)
4673 		balmode = "<UNKNOWN>";
4674 	else
4675 		balmode = carp_bal_modes[carpr.carpr_balancing];
4676 
4677 	if (carpr.carpr_peer.s_addr != htonl(INADDR_CARP_GROUP))
4678 		snprintf(peer, sizeof(peer),
4679 		    " carppeer %s", inet_ntoa(carpr.carpr_peer));
4680 	else
4681 		peer[0] = '\0';
4682 
4683 	for (i = 0; carpr.carpr_vhids[i]; i++) {
4684 		if (carpr.carpr_states[i] > CARP_MAXSTATE)
4685 			state = "<UNKNOWN>";
4686 		else
4687 			state = carp_states[carpr.carpr_states[i]];
4688 		if (carpr.carpr_vhids[1] == 0) {
4689 			printf("\tcarp: %s carpdev %s vhid %u advbase %d "
4690 			    "advskew %u%s\n", state,
4691 			    carpr.carpr_carpdev[0] != '\0' ?
4692 			    carpr.carpr_carpdev : "none", carpr.carpr_vhids[0],
4693 			    carpr.carpr_advbase, carpr.carpr_advskews[0],
4694 			    peer);
4695 		} else {
4696 			if (i == 0) {
4697 				printf("\tcarp: carpdev %s advbase %d"
4698 				    " balancing %s%s\n",
4699 				    carpr.carpr_carpdev[0] != '\0' ?
4700 				    carpr.carpr_carpdev : "none",
4701 				    carpr.carpr_advbase, balmode, peer);
4702 			}
4703 			printf("\t\tstate %s vhid %u advskew %u\n", state,
4704 			    carpr.carpr_vhids[i], carpr.carpr_advskews[i]);
4705 		}
4706 	}
4707 }
4708 
4709 /* ARGSUSED */
4710 void
4711 setcarp_passwd(const char *val, int d)
4712 {
4713 	struct carpreq carpr;
4714 
4715 	bzero(&carpr, sizeof(struct carpreq));
4716 	ifr.ifr_data = (caddr_t)&carpr;
4717 
4718 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4719 		err(1, "SIOCGVH");
4720 
4721 	bzero(carpr.carpr_key, CARP_KEY_LEN);
4722 	strlcpy((char *)carpr.carpr_key, val, CARP_KEY_LEN);
4723 
4724 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4725 		err(1, "SIOCSVH");
4726 }
4727 
4728 /* ARGSUSED */
4729 void
4730 setcarp_vhid(const char *val, int d)
4731 {
4732 	const char *errmsg = NULL;
4733 	struct carpreq carpr;
4734 	int vhid;
4735 
4736 	vhid = strtonum(val, 1, 255, &errmsg);
4737 	if (errmsg)
4738 		errx(1, "vhid %s: %s", val, errmsg);
4739 
4740 	bzero(&carpr, sizeof(struct carpreq));
4741 	ifr.ifr_data = (caddr_t)&carpr;
4742 
4743 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4744 		err(1, "SIOCGVH");
4745 
4746 	carpr.carpr_vhids[0] = vhid;
4747 	carpr.carpr_vhids[1] = 0;
4748 
4749 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4750 		err(1, "SIOCSVH");
4751 }
4752 
4753 /* ARGSUSED */
4754 void
4755 setcarp_advskew(const char *val, int d)
4756 {
4757 	const char *errmsg = NULL;
4758 	struct carpreq carpr;
4759 	int advskew;
4760 
4761 	advskew = strtonum(val, 0, 254, &errmsg);
4762 	if (errmsg)
4763 		errx(1, "advskew %s: %s", val, errmsg);
4764 
4765 	bzero(&carpr, sizeof(struct carpreq));
4766 	ifr.ifr_data = (caddr_t)&carpr;
4767 
4768 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4769 		err(1, "SIOCGVH");
4770 
4771 	carpr.carpr_advskews[0] = advskew;
4772 
4773 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4774 		err(1, "SIOCSVH");
4775 }
4776 
4777 /* ARGSUSED */
4778 void
4779 setcarp_advbase(const char *val, int d)
4780 {
4781 	const char *errmsg = NULL;
4782 	struct carpreq carpr;
4783 	int advbase;
4784 
4785 	advbase = strtonum(val, 0, 254, &errmsg);
4786 	if (errmsg)
4787 		errx(1, "advbase %s: %s", val, errmsg);
4788 
4789 	bzero(&carpr, sizeof(struct carpreq));
4790 	ifr.ifr_data = (caddr_t)&carpr;
4791 
4792 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4793 		err(1, "SIOCGVH");
4794 
4795 	carpr.carpr_advbase = advbase;
4796 
4797 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4798 		err(1, "SIOCSVH");
4799 }
4800 
4801 /* ARGSUSED */
4802 void
4803 setcarppeer(const char *val, int d)
4804 {
4805 	struct carpreq carpr;
4806 	struct addrinfo hints, *peerres;
4807 	int ecode;
4808 
4809 	bzero(&carpr, sizeof(struct carpreq));
4810 	ifr.ifr_data = (caddr_t)&carpr;
4811 
4812 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4813 		err(1, "SIOCGVH");
4814 
4815 	bzero(&hints, sizeof(hints));
4816 	hints.ai_family = AF_INET;
4817 	hints.ai_socktype = SOCK_DGRAM;
4818 
4819 	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4820 		errx(1, "error in parsing address string: %s",
4821 		    gai_strerror(ecode));
4822 
4823 	if (peerres->ai_addr->sa_family != AF_INET)
4824 		errx(1, "only IPv4 addresses supported for the carppeer");
4825 
4826 	carpr.carpr_peer.s_addr = ((struct sockaddr_in *)
4827 	    peerres->ai_addr)->sin_addr.s_addr;
4828 
4829 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4830 		err(1, "SIOCSVH");
4831 
4832 	freeaddrinfo(peerres);
4833 }
4834 
4835 void
4836 unsetcarppeer(const char *val, int d)
4837 {
4838 	struct carpreq carpr;
4839 
4840 	bzero(&carpr, sizeof(struct carpreq));
4841 	ifr.ifr_data = (caddr_t)&carpr;
4842 
4843 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4844 		err(1, "SIOCGVH");
4845 
4846 	bzero(&carpr.carpr_peer, sizeof(carpr.carpr_peer));
4847 
4848 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4849 		err(1, "SIOCSVH");
4850 }
4851 
4852 /* ARGSUSED */
4853 void
4854 setcarp_state(const char *val, int d)
4855 {
4856 	struct carpreq carpr;
4857 	int i;
4858 
4859 	bzero(&carpr, sizeof(struct carpreq));
4860 	ifr.ifr_data = (caddr_t)&carpr;
4861 
4862 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4863 		err(1, "SIOCGVH");
4864 
4865 	for (i = 0; i <= CARP_MAXSTATE; i++) {
4866 		if (!strcasecmp(val, carp_states[i])) {
4867 			carpr.carpr_state = i;
4868 			break;
4869 		}
4870 	}
4871 
4872 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4873 		err(1, "SIOCSVH");
4874 }
4875 
4876 /* ARGSUSED */
4877 void
4878 setcarpdev(const char *val, int d)
4879 {
4880 	struct carpreq carpr;
4881 
4882 	bzero(&carpr, sizeof(struct carpreq));
4883 	ifr.ifr_data = (caddr_t)&carpr;
4884 
4885 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4886 		err(1, "SIOCGVH");
4887 
4888 	strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
4889 
4890 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4891 		err(1, "SIOCSVH");
4892 }
4893 
4894 void
4895 setcarp_nodes(const char *val, int d)
4896 {
4897 	char *optlist, *str;
4898 	int i;
4899 	struct carpreq carpr;
4900 
4901 	bzero(&carpr, sizeof(struct carpreq));
4902 	ifr.ifr_data = (caddr_t)&carpr;
4903 
4904 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4905 		err(1, "SIOCGVH");
4906 
4907 	bzero(carpr.carpr_vhids, sizeof(carpr.carpr_vhids));
4908 	bzero(carpr.carpr_advskews, sizeof(carpr.carpr_advskews));
4909 
4910 	optlist = strdup(val);
4911 	if (optlist == NULL)
4912 		err(1, "strdup");
4913 
4914 	str = strtok(optlist, ",");
4915 	for (i = 0; str != NULL; i++) {
4916 		u_int vhid, advskew;
4917 
4918 		if (i >= CARP_MAXNODES)
4919 			errx(1, "too many carp nodes");
4920 		if (sscanf(str, "%u:%u", &vhid, &advskew) != 2) {
4921 			errx(1, "non parsable arg: %s", str);
4922 		}
4923 		if (vhid > 255)
4924 			errx(1, "vhid %u: value too large", vhid);
4925 		if (advskew >= 255)
4926 			errx(1, "advskew %u: value too large", advskew);
4927 
4928 		carpr.carpr_vhids[i] = vhid;
4929 		carpr.carpr_advskews[i] = advskew;
4930 		str = strtok(NULL, ",");
4931 	}
4932 	free(optlist);
4933 
4934 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4935 		err(1, "SIOCSVH");
4936 }
4937 
4938 void
4939 setcarp_balancing(const char *val, int d)
4940 {
4941 	int i;
4942 	struct carpreq carpr;
4943 
4944 	bzero(&carpr, sizeof(struct carpreq));
4945 	ifr.ifr_data = (caddr_t)&carpr;
4946 
4947 	if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4948 		err(1, "SIOCGVH");
4949 
4950 	for (i = 0; i <= CARP_BAL_MAXID; i++)
4951 		if (!strcasecmp(val, carp_bal_modes[i]))
4952 			break;
4953 
4954 	if (i > CARP_BAL_MAXID)
4955 		errx(1, "balancing %s: unknown mode", val);
4956 
4957 	carpr.carpr_balancing = i;
4958 
4959 	if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4960 		err(1, "SIOCSVH");
4961 }
4962 
4963 void
4964 setpfsync_syncdev(const char *val, int d)
4965 {
4966 	struct pfsyncreq preq;
4967 
4968 	bzero(&preq, sizeof(struct pfsyncreq));
4969 	ifr.ifr_data = (caddr_t)&preq;
4970 
4971 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4972 		err(1, "SIOCGETPFSYNC");
4973 
4974 	strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
4975 
4976 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4977 		err(1, "SIOCSETPFSYNC");
4978 }
4979 
4980 /* ARGSUSED */
4981 void
4982 unsetpfsync_syncdev(const char *val, int d)
4983 {
4984 	struct pfsyncreq preq;
4985 
4986 	bzero(&preq, sizeof(struct pfsyncreq));
4987 	ifr.ifr_data = (caddr_t)&preq;
4988 
4989 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4990 		err(1, "SIOCGETPFSYNC");
4991 
4992 	bzero(&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
4993 
4994 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4995 		err(1, "SIOCSETPFSYNC");
4996 }
4997 
4998 /* ARGSUSED */
4999 void
5000 setpfsync_syncpeer(const char *val, int d)
5001 {
5002 	struct pfsyncreq preq;
5003 	struct addrinfo hints, *peerres;
5004 	int ecode;
5005 
5006 	bzero(&preq, sizeof(struct pfsyncreq));
5007 	ifr.ifr_data = (caddr_t)&preq;
5008 
5009 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5010 		err(1, "SIOCGETPFSYNC");
5011 
5012 	memset(&hints, 0, sizeof(hints));
5013 	hints.ai_family = AF_INET;
5014 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
5015 
5016 	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
5017 		errx(1, "error in parsing address string: %s",
5018 		    gai_strerror(ecode));
5019 
5020 	if (peerres->ai_addr->sa_family != AF_INET)
5021 		errx(1, "only IPv4 addresses supported for the syncpeer");
5022 
5023 	preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
5024 	    peerres->ai_addr)->sin_addr.s_addr;
5025 
5026 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5027 		err(1, "SIOCSETPFSYNC");
5028 
5029 	freeaddrinfo(peerres);
5030 }
5031 
5032 /* ARGSUSED */
5033 void
5034 unsetpfsync_syncpeer(const char *val, int d)
5035 {
5036 	struct pfsyncreq preq;
5037 
5038 	bzero(&preq, sizeof(struct pfsyncreq));
5039 	ifr.ifr_data = (caddr_t)&preq;
5040 
5041 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5042 		err(1, "SIOCGETPFSYNC");
5043 
5044 	preq.pfsyncr_syncpeer.s_addr = 0;
5045 
5046 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5047 		err(1, "SIOCSETPFSYNC");
5048 }
5049 
5050 /* ARGSUSED */
5051 void
5052 setpfsync_maxupd(const char *val, int d)
5053 {
5054 	const char *errmsg = NULL;
5055 	struct pfsyncreq preq;
5056 	int maxupdates;
5057 
5058 	maxupdates = strtonum(val, 0, 255, &errmsg);
5059 	if (errmsg)
5060 		errx(1, "maxupd %s: %s", val, errmsg);
5061 
5062 	bzero(&preq, sizeof(struct pfsyncreq));
5063 	ifr.ifr_data = (caddr_t)&preq;
5064 
5065 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5066 		err(1, "SIOCGETPFSYNC");
5067 
5068 	preq.pfsyncr_maxupdates = maxupdates;
5069 
5070 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5071 		err(1, "SIOCSETPFSYNC");
5072 }
5073 
5074 void
5075 setpfsync_defer(const char *val, int d)
5076 {
5077 	struct pfsyncreq preq;
5078 
5079 	bzero(&preq, sizeof(struct pfsyncreq));
5080 	ifr.ifr_data = (caddr_t)&preq;
5081 
5082 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5083 		err(1, "SIOCGETPFSYNC");
5084 
5085 	preq.pfsyncr_defer = d;
5086 	if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5087 		err(1, "SIOCSETPFSYNC");
5088 }
5089 
5090 void
5091 pfsync_status(void)
5092 {
5093 	struct pfsyncreq preq;
5094 
5095 	bzero(&preq, sizeof(struct pfsyncreq));
5096 	ifr.ifr_data = (caddr_t)&preq;
5097 
5098 	if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5099 		return;
5100 
5101 	if (preq.pfsyncr_syncdev[0] != '\0') {
5102 		printf("\tpfsync: syncdev: %s ", preq.pfsyncr_syncdev);
5103 		if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
5104 			printf("syncpeer: %s ",
5105 			    inet_ntoa(preq.pfsyncr_syncpeer));
5106 		printf("maxupd: %d ", preq.pfsyncr_maxupdates);
5107 		printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
5108 	}
5109 }
5110 
5111 void
5112 pflow_status(void)
5113 {
5114 	struct pflowreq		 preq;
5115 	struct sockaddr_in	*sin;
5116 	struct sockaddr_in6	*sin6;
5117 	int			 error;
5118 	char			 buf[INET6_ADDRSTRLEN];
5119 
5120 	bzero(&preq, sizeof(struct pflowreq));
5121 	ifr.ifr_data = (caddr_t)&preq;
5122 
5123 	if (ioctl(sock, SIOCGETPFLOW, (caddr_t)&ifr) == -1)
5124 		 return;
5125 
5126 	if (preq.flowsrc.ss_family == AF_INET || preq.flowsrc.ss_family ==
5127 	    AF_INET6) {
5128 		error = getnameinfo((struct sockaddr*)&preq.flowsrc,
5129 		    preq.flowsrc.ss_len, buf, sizeof(buf), NULL, 0,
5130 		    NI_NUMERICHOST);
5131 		if (error)
5132 			err(1, "sender: %s", gai_strerror(error));
5133 	}
5134 
5135 	printf("\tpflow: ");
5136 	switch (preq.flowsrc.ss_family) {
5137 	case AF_INET:
5138 		sin = (struct sockaddr_in*) &preq.flowsrc;
5139 		if (sin->sin_addr.s_addr != INADDR_ANY) {
5140 			printf("sender: %s", buf);
5141 			if (sin->sin_port != 0)
5142 				printf(":%u", ntohs(sin->sin_port));
5143 			printf(" ");
5144 		}
5145 		break;
5146 	case AF_INET6:
5147 		sin6 = (struct sockaddr_in6*) &preq.flowsrc;
5148 		if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5149 			printf("sender: [%s]", buf);
5150 			if (sin6->sin6_port != 0)
5151 				printf(":%u", ntohs(sin6->sin6_port));
5152 			printf(" ");
5153 		}
5154 	default:
5155 		break;
5156 	}
5157 	if (preq.flowdst.ss_family == AF_INET || preq.flowdst.ss_family ==
5158 	    AF_INET6) {
5159 		error = getnameinfo((struct sockaddr*)&preq.flowdst,
5160 		    preq.flowdst.ss_len, buf, sizeof(buf), NULL, 0,
5161 		    NI_NUMERICHOST);
5162 		if (error)
5163 			err(1, "receiver: %s", gai_strerror(error));
5164 	}
5165 	switch (preq.flowdst.ss_family) {
5166 	case AF_INET:
5167 		sin = (struct sockaddr_in*)&preq.flowdst;
5168 		printf("receiver: %s:", sin->sin_addr.s_addr != INADDR_ANY ?
5169 		    buf : "INVALID");
5170 		if (sin->sin_port == 0)
5171 			printf("%s ", "INVALID");
5172 		else
5173 			printf("%u ", ntohs(sin->sin_port));
5174 		break;
5175 	case AF_INET6:
5176 		sin6 = (struct sockaddr_in6*) &preq.flowdst;
5177 		printf("receiver: [%s]:",
5178 		    !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ? buf :
5179 		    "INVALID");
5180 		if (sin6->sin6_port == 0)
5181 			printf("%s ", "INVALID");
5182 		else
5183 			printf("%u ", ntohs(sin6->sin6_port));
5184 		break;
5185 	default:
5186 		printf("receiver: INVALID:INVALID ");
5187 		break;
5188 	}
5189 	printf("version: %d\n", preq.version);
5190 }
5191 
5192 void
5193 pflow_addr(const char *val, struct sockaddr_storage *ss) {
5194 	struct addrinfo hints, *res0;
5195 	int error, flag;
5196 	char *cp, *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
5197 
5198 	if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
5199 		errx(1, "%s bad value", val);
5200 
5201 	port = NULL;
5202 	cp = buf;
5203 	if (*cp == '[')
5204 		flag = 1;
5205 	else
5206 		flag = 0;
5207 
5208 	for(; *cp; ++cp) {
5209 		if (*cp == ']' && *(cp + 1) == ':' && flag) {
5210 			*cp = '\0';
5211 			*(cp + 1) = '\0';
5212 			port = cp + 2;
5213 			break;
5214 		}
5215 		if (*cp == ']' && *(cp + 1) == '\0' && flag) {
5216 			*cp = '\0';
5217 			port = NULL;
5218 			break;
5219 		}
5220 		if (*cp == ':' && !flag) {
5221 			*cp = '\0';
5222 			port = cp + 1;
5223 			break;
5224 		}
5225 	}
5226 
5227 	ip = buf;
5228 	if (flag)
5229 		ip++;
5230 
5231 	bzero(&hints, sizeof(hints));
5232 	hints.ai_family = AF_UNSPEC;
5233 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
5234 	hints.ai_flags = AI_NUMERICHOST;
5235 
5236 	if ((error = getaddrinfo(ip, port, &hints, &res0)) != 0)
5237 		errx(1, "error in parsing address string: %s",
5238 		    gai_strerror(error));
5239 
5240 	memcpy(ss, res0->ai_addr, res0->ai_addr->sa_len);
5241 	freeaddrinfo(res0);
5242 }
5243 
5244 void
5245 setpflow_sender(const char *val, int d)
5246 {
5247 	struct pflowreq preq;
5248 
5249 	bzero(&preq, sizeof(struct pflowreq));
5250 	ifr.ifr_data = (caddr_t)&preq;
5251 	preq.addrmask |= PFLOW_MASK_SRCIP;
5252 	pflow_addr(val, &preq.flowsrc);
5253 
5254 	if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5255 		err(1, "SIOCSETPFLOW");
5256 }
5257 
5258 void
5259 unsetpflow_sender(const char *val, int d)
5260 {
5261 	struct pflowreq preq;
5262 
5263 	bzero(&preq, sizeof(struct pflowreq));
5264 	preq.addrmask |= PFLOW_MASK_SRCIP;
5265 	ifr.ifr_data = (caddr_t)&preq;
5266 	if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5267 		err(1, "SIOCSETPFLOW");
5268 }
5269 
5270 void
5271 setpflow_receiver(const char *val, int d)
5272 {
5273 	struct pflowreq preq;
5274 
5275 	bzero(&preq, sizeof(struct pflowreq));
5276 	ifr.ifr_data = (caddr_t)&preq;
5277 	preq.addrmask |= PFLOW_MASK_DSTIP;
5278 	pflow_addr(val, &preq.flowdst);
5279 
5280 	if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5281 		err(1, "SIOCSETPFLOW");
5282 }
5283 
5284 void
5285 unsetpflow_receiver(const char *val, int d)
5286 {
5287 	struct pflowreq preq;
5288 
5289 	bzero(&preq, sizeof(struct pflowreq));
5290 	ifr.ifr_data = (caddr_t)&preq;
5291 	preq.addrmask |= PFLOW_MASK_DSTIP;
5292 	if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5293 		err(1, "SIOCSETPFLOW");
5294 }
5295 
5296 /* PFLOWPROTO XXX */
5297 void
5298 setpflowproto(const char *val, int d)
5299 {
5300 	struct pflow_protos ppr[] = PFLOW_PROTOS;
5301 	struct pflowreq preq;
5302 	int i;
5303 
5304 	bzero(&preq, sizeof(preq));
5305 	preq.version = PFLOW_PROTO_MAX;
5306 
5307 	for (i = 0; i < (sizeof(ppr) / sizeof(ppr[0])); i++) {
5308 		if (strcmp(val, ppr[i].ppr_name) == 0) {
5309 			preq.version = ppr[i].ppr_proto;
5310 			break;
5311 		}
5312 	}
5313 	if (preq.version == PFLOW_PROTO_MAX)
5314 		errx(1, "Invalid pflow protocol: %s", val);
5315 
5316 	preq.addrmask |= PFLOW_MASK_VERSION;
5317 
5318 	ifr.ifr_data = (caddr_t)&preq;
5319 
5320 	if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5321 		err(1, "SIOCSETPFLOW");
5322 }
5323 
5324 void
5325 pppoe_status(void)
5326 {
5327 	struct pppoediscparms parms;
5328 	struct pppoeconnectionstate state;
5329 
5330 	memset(&state, 0, sizeof(state));
5331 
5332 	strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5333 	if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5334 		return;
5335 
5336 	printf("\tdev: %s ", parms.eth_ifname);
5337 
5338 	if (*parms.ac_name)
5339 		printf("ac: %s ", parms.ac_name);
5340 	if (*parms.service_name)
5341 		printf("svc: %s ", parms.service_name);
5342 
5343 	strlcpy(state.ifname, ifname, sizeof(state.ifname));
5344 	if (ioctl(sock, PPPOEGETSESSION, &state) == -1)
5345 		err(1, "PPPOEGETSESSION");
5346 
5347 	printf("state: ");
5348 	switch (state.state) {
5349 	case PPPOE_STATE_INITIAL:
5350 		printf("initial"); break;
5351 	case PPPOE_STATE_PADI_SENT:
5352 		printf("PADI sent"); break;
5353 	case PPPOE_STATE_PADR_SENT:
5354 		printf("PADR sent"); break;
5355 	case PPPOE_STATE_SESSION:
5356 		printf("session"); break;
5357 	case PPPOE_STATE_CLOSING:
5358 		printf("closing"); break;
5359 	}
5360 	printf("\n\tsid: 0x%x", state.session_id);
5361 	printf(" PADI retries: %d", state.padi_retry_no);
5362 	printf(" PADR retries: %d", state.padr_retry_no);
5363 
5364 	if (state.state == PPPOE_STATE_SESSION) {
5365 		struct timespec temp_time;
5366 		time_t diff_time, day = 0;
5367 		unsigned int hour = 0, min = 0, sec = 0;
5368 
5369 		if (state.session_time.tv_sec != 0) {
5370 			if (clock_gettime(CLOCK_BOOTTIME, &temp_time) == -1)
5371 				goto notime;
5372 			diff_time = temp_time.tv_sec -
5373 			    state.session_time.tv_sec;
5374 
5375 			day = diff_time / (60 * 60 * 24);
5376 			diff_time %= (60 * 60 * 24);
5377 
5378 			hour = diff_time / (60 * 60);
5379 			diff_time %= (60 * 60);
5380 
5381 			min = diff_time / 60;
5382 			diff_time %= 60;
5383 
5384 			sec = diff_time;
5385 		}
5386 		printf(" time: ");
5387 		if (day != 0)
5388 			printf("%lldd ", (long long)day);
5389 		printf("%02u:%02u:%02u", hour, min, sec);
5390 	}
5391 notime:
5392 	putchar('\n');
5393 }
5394 
5395 /* ARGSUSED */
5396 void
5397 setpppoe_dev(const char *val, int d)
5398 {
5399 	struct pppoediscparms parms;
5400 
5401 	strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5402 	if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5403 		return;
5404 
5405 	strlcpy(parms.eth_ifname, val, sizeof(parms.eth_ifname));
5406 
5407 	if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5408 		err(1, "PPPOESETPARMS");
5409 }
5410 
5411 /* ARGSUSED */
5412 void
5413 setpppoe_svc(const char *val, int d)
5414 {
5415 	struct pppoediscparms parms;
5416 
5417 	strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5418 	if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5419 		return;
5420 
5421 	if (d == 0)
5422 		strlcpy(parms.service_name, val, sizeof(parms.service_name));
5423 	else
5424 		memset(parms.service_name, 0, sizeof(parms.service_name));
5425 
5426 	if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5427 		err(1, "PPPOESETPARMS");
5428 }
5429 
5430 /* ARGSUSED */
5431 void
5432 setpppoe_ac(const char *val, int d)
5433 {
5434 	struct pppoediscparms parms;
5435 
5436 	strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5437 	if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5438 		return;
5439 
5440 	if (d == 0)
5441 		strlcpy(parms.ac_name, val, sizeof(parms.ac_name));
5442 	else
5443 		memset(parms.ac_name, 0, sizeof(parms.ac_name));
5444 
5445 	if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5446 		err(1, "PPPOESETPARMS");
5447 }
5448 
5449 void
5450 spppauthinfo(struct sauthreq *spa, int d)
5451 {
5452 	bzero(spa, sizeof(struct sauthreq));
5453 
5454 	ifr.ifr_data = (caddr_t)spa;
5455 	spa->cmd = d == 0 ? SPPPIOGMAUTH : SPPPIOGHAUTH;
5456 	if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1)
5457 		err(1, "SIOCGSPPPPARAMS(SPPPIOGXAUTH)");
5458 }
5459 
5460 void
5461 spppdnsinfo(struct sdnsreq *spd)
5462 {
5463 	memset(spd, 0, sizeof(*spd));
5464 
5465 	ifr.ifr_data = (caddr_t)spd;
5466 	spd->cmd = SPPPIOGDNS;
5467 	if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1)
5468 		err(1, "SIOCGSPPPPARAMS(SPPPIOGDNS)");
5469 }
5470 
5471 void
5472 setspppproto(const char *val, int d)
5473 {
5474 	struct sauthreq spa;
5475 
5476 	spppauthinfo(&spa, d);
5477 
5478 	if (strcmp(val, "pap") == 0)
5479 		spa.proto = PPP_PAP;
5480 	else if (strcmp(val, "chap") == 0)
5481 		spa.proto = PPP_CHAP;
5482 	else if (strcmp(val, "none") == 0)
5483 		spa.proto = 0;
5484 	else
5485 		errx(1, "setpppproto");
5486 
5487 	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5488 	if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5489 		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
5490 }
5491 
5492 void
5493 setsppppeerproto(const char *val, int d)
5494 {
5495 	setspppproto(val, 1);
5496 }
5497 
5498 void
5499 setspppname(const char *val, int d)
5500 {
5501 	struct sauthreq spa;
5502 
5503 	spppauthinfo(&spa, d);
5504 
5505 	if (spa.proto == 0)
5506 		errx(1, "unspecified protocol");
5507 	if (strlcpy(spa.name, val, sizeof(spa.name)) >= sizeof(spa.name))
5508 		errx(1, "setspppname");
5509 
5510 	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5511 	if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5512 		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
5513 }
5514 
5515 void
5516 setsppppeername(const char *val, int d)
5517 {
5518 	setspppname(val, 1);
5519 }
5520 
5521 void
5522 setspppkey(const char *val, int d)
5523 {
5524 	struct sauthreq spa;
5525 
5526 	spppauthinfo(&spa, d);
5527 
5528 	if (spa.proto == 0)
5529 		errx(1, "unspecified protocol");
5530 	if (strlcpy(spa.secret, val, sizeof(spa.secret)) >= sizeof(spa.secret))
5531 		errx(1, "setspppkey");
5532 
5533 	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5534 	if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5535 		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
5536 }
5537 
5538 void
5539 setsppppeerkey(const char *val, int d)
5540 {
5541 	setspppkey(val, 1);
5542 }
5543 
5544 void
5545 setsppppeerflag(const char *val, int d)
5546 {
5547 	struct sauthreq spa;
5548 	int flag;
5549 
5550 	spppauthinfo(&spa, 1);
5551 
5552 	if (spa.proto == 0)
5553 		errx(1, "unspecified protocol");
5554 	if (strcmp(val, "callin") == 0)
5555 		flag = AUTHFLAG_NOCALLOUT;
5556 	else if (strcmp(val, "norechallenge") == 0)
5557 		flag = AUTHFLAG_NORECHALLENGE;
5558 	else
5559 		errx(1, "setppppeerflags");
5560 
5561 	if (d)
5562 		spa.flags &= ~flag;
5563 	else
5564 		spa.flags |= flag;
5565 
5566 	spa.cmd = SPPPIOSHAUTH;
5567 	if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5568 		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
5569 }
5570 
5571 void
5572 unsetsppppeerflag(const char *val, int d)
5573 {
5574 	setsppppeerflag(val, 1);
5575 }
5576 
5577 void
5578 sppp_printproto(const char *name, struct sauthreq *auth)
5579 {
5580 	if (auth->proto == 0)
5581 		return;
5582 	printf("%sproto ", name);
5583 	switch (auth->proto) {
5584 	case PPP_PAP:
5585 		printf("pap ");
5586 		break;
5587 	case PPP_CHAP:
5588 		printf("chap ");
5589 		break;
5590 	default:
5591 		printf("0x%04x ", auth->proto);
5592 		break;
5593 	}
5594 	if (auth->name[0])
5595 		printf("%sname \"%s\" ", name, auth->name);
5596 	if (auth->secret[0])
5597 		printf("%skey \"%s\" ", name, auth->secret);
5598 }
5599 
5600 void
5601 sppp_status(void)
5602 {
5603 	struct spppreq spr;
5604 	struct sauthreq spa;
5605 	struct sdnsreq spd;
5606 	char astr[INET_ADDRSTRLEN];
5607 	int i, n;
5608 
5609 	bzero(&spr, sizeof(spr));
5610 
5611 	ifr.ifr_data = (caddr_t)&spr;
5612 	spr.cmd = SPPPIOGDEFS;
5613 	if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1) {
5614 		return;
5615 	}
5616 
5617 	if (spr.phase == PHASE_DEAD)
5618 		return;
5619 	printf("\tsppp: phase ");
5620 	switch (spr.phase) {
5621 	case PHASE_ESTABLISH:
5622 		printf("establish ");
5623 		break;
5624 	case PHASE_TERMINATE:
5625 		printf("terminate ");
5626 		break;
5627 	case PHASE_AUTHENTICATE:
5628 		printf("authenticate ");
5629 		break;
5630 	case PHASE_NETWORK:
5631 		printf("network ");
5632 		break;
5633 	default:
5634 		printf("illegal ");
5635 		break;
5636 	}
5637 
5638 	spppauthinfo(&spa, 0);
5639 	sppp_printproto("auth", &spa);
5640 	spppauthinfo(&spa, 1);
5641 	sppp_printproto("peer", &spa);
5642 	if (spa.flags & AUTHFLAG_NOCALLOUT)
5643 		printf("callin ");
5644 	if (spa.flags & AUTHFLAG_NORECHALLENGE)
5645 		printf("norechallenge ");
5646 	putchar('\n');
5647 
5648 	spppdnsinfo(&spd);
5649 	for (i = 0, n = 0; i < IPCP_MAX_DNSSRV; i++) {
5650 		if (spd.dns[i].s_addr == INADDR_ANY)
5651 			break;
5652 		printf("%s %s", n++ ? "" : "\tdns:",
5653 		    inet_ntop(AF_INET, &spd.dns[i], astr, sizeof(astr)));
5654 	}
5655 	if (n)
5656 		printf("\n");
5657 }
5658 
5659 void
5660 setkeepalive(const char *timeout, const char *count)
5661 {
5662 	const char *errmsg = NULL;
5663 	struct ifkalivereq ikar;
5664 	int t, c;
5665 
5666 	t = strtonum(timeout, 1, 3600, &errmsg);
5667 	if (errmsg)
5668 		errx(1, "keepalive period %s: %s", timeout, errmsg);
5669 	c = strtonum(count, 2, 600, &errmsg);
5670 	if (errmsg)
5671 		errx(1, "keepalive count %s: %s", count, errmsg);
5672 
5673 	strlcpy(ikar.ikar_name, ifname, sizeof(ikar.ikar_name));
5674 	ikar.ikar_timeo = t;
5675 	ikar.ikar_cnt = c;
5676 	if (ioctl(sock, SIOCSETKALIVE, (caddr_t)&ikar) == -1)
5677 		warn("SIOCSETKALIVE");
5678 }
5679 
5680 void
5681 unsetkeepalive(const char *val, int d)
5682 {
5683 	struct ifkalivereq ikar;
5684 
5685 	bzero(&ikar, sizeof(ikar));
5686 	strlcpy(ikar.ikar_name, ifname, sizeof(ikar.ikar_name));
5687 	if (ioctl(sock, SIOCSETKALIVE, (caddr_t)&ikar) == -1)
5688 		warn("SIOCSETKALIVE");
5689 }
5690 
5691 void
5692 setifpriority(const char *id, int param)
5693 {
5694 	const char *errmsg = NULL;
5695 	int prio;
5696 
5697 	prio = strtonum(id, 0, 15, &errmsg);
5698 	if (errmsg)
5699 		errx(1, "priority %s: %s", id, errmsg);
5700 
5701 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
5702 	ifr.ifr_metric = prio;
5703 	if (ioctl(sock, SIOCSIFPRIORITY, (caddr_t)&ifr) == -1)
5704 		warn("SIOCSIFPRIORITY");
5705 }
5706 
5707 /*
5708  * WireGuard configuration
5709  *
5710  * WG_BASE64_KEY_LEN specifies the size of a base64 encoded WireGuard key.
5711  * WG_TMP_KEY_LEN specifies the size of a decoded base64 key. For every 4
5712  * input (base64) bytes, 3 output bytes wil be produced. The output will be
5713  * padded with 0 bits, therefore we need more than the regular 32 bytes of
5714  * space.
5715  */
5716 #define WG_BASE64_KEY_LEN (4 * ((WG_KEY_LEN + 2) / 3))
5717 #define WG_LOAD_KEY(dst, src, fn_name) do {				\
5718 	uint8_t _tmp[WG_KEY_LEN]; int _r;				\
5719 	if (strlen(src) != WG_BASE64_KEY_LEN)				\
5720 		errx(1, fn_name " (key): invalid length");		\
5721 	if ((_r = b64_pton(src, _tmp, sizeof(_tmp))) != sizeof(_tmp))		\
5722 		errx(1, fn_name " (key): invalid base64 %d/%zu", _r, sizeof(_tmp));		\
5723 	memcpy(dst, _tmp, WG_KEY_LEN);					\
5724 } while (0)
5725 
5726 struct wg_data_io	 wgdata = { 0 };
5727 struct wg_interface_io	*wg_interface = NULL;
5728 struct wg_peer_io	*wg_peer = NULL;
5729 struct wg_aip_io	*wg_aip = NULL;
5730 
5731 void
5732 ensurewginterface(void)
5733 {
5734 	if (wg_interface != NULL)
5735 		return;
5736 	wgdata.wgd_size = sizeof(*wg_interface);
5737 	wgdata.wgd_interface = wg_interface = calloc(1, wgdata.wgd_size);
5738 	if (wg_interface == NULL)
5739 		err(1, "calloc");
5740 }
5741 
5742 void
5743 growwgdata(size_t by)
5744 {
5745 	ptrdiff_t peer_offset, aip_offset;
5746 
5747 	if (wg_interface == NULL)
5748 		wgdata.wgd_size = sizeof(*wg_interface);
5749 
5750 	peer_offset = (void *)wg_peer - (void *)wg_interface;
5751 	aip_offset = (void *)wg_aip - (void *)wg_interface;
5752 
5753 	wgdata.wgd_size += by;
5754 	wgdata.wgd_interface = realloc(wg_interface, wgdata.wgd_size);
5755 	if (wgdata.wgd_interface == NULL)
5756 		err(1, "calloc");
5757 	if (wg_interface == NULL)
5758 		bzero(wgdata.wgd_interface, sizeof(*wg_interface));
5759 	wg_interface = wgdata.wgd_interface;
5760 
5761 	if (wg_peer != NULL)
5762 		wg_peer = (void *)wg_interface + peer_offset;
5763 	if (wg_aip != NULL)
5764 		wg_aip = (void *)wg_interface + aip_offset;
5765 
5766 	bzero((char *)wg_interface + wgdata.wgd_size - by, by);
5767 }
5768 
5769 void
5770 setwgpeer(const char *peerkey_b64, int param)
5771 {
5772 	growwgdata(sizeof(*wg_peer));
5773 	if (wg_aip)
5774 		wg_peer = (struct wg_peer_io *)wg_aip;
5775 	else
5776 		wg_peer = &wg_interface->i_peers[0];
5777 	wg_aip = &wg_peer->p_aips[0];
5778 	wg_peer->p_flags |= WG_PEER_HAS_PUBLIC;
5779 	WG_LOAD_KEY(wg_peer->p_public, peerkey_b64, "wgpeer");
5780 	wg_interface->i_peers_count++;
5781 }
5782 
5783 void
5784 setwgpeeraip(const char *aip, int param)
5785 {
5786 	int res;
5787 	if (wg_peer == NULL)
5788 		errx(1, "wgaip: wgpeer not set");
5789 
5790 	growwgdata(sizeof(*wg_aip));
5791 
5792 	if ((res = inet_net_pton(AF_INET, aip, &wg_aip->a_ipv4,
5793 	    sizeof(wg_aip->a_ipv4))) != -1) {
5794 		wg_aip->a_af = AF_INET;
5795 	} else if ((res = inet_net_pton(AF_INET6, aip, &wg_aip->a_ipv6,
5796 	    sizeof(wg_aip->a_ipv6))) != -1) {
5797 		wg_aip->a_af = AF_INET6;
5798 	} else {
5799 		errx(1, "wgaip: bad address");
5800 	}
5801 
5802 	wg_aip->a_cidr = res;
5803 
5804 	wg_peer->p_flags |= WG_PEER_REPLACE_AIPS;
5805 	wg_peer->p_aips_count++;
5806 
5807 	wg_aip++;
5808 }
5809 
5810 void
5811 setwgpeerep(const char *host, const char *service)
5812 {
5813 	int error;
5814 	struct addrinfo *ai;
5815 
5816 	if (wg_peer == NULL)
5817 		errx(1, "wgendpoint: wgpeer not set");
5818 
5819 	if ((error = getaddrinfo(host, service, NULL, &ai)) != 0)
5820 		errx(1, "%s", gai_strerror(error));
5821 
5822 	wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT;
5823 	memcpy(&wg_peer->p_sa, ai->ai_addr, ai->ai_addrlen);
5824 	freeaddrinfo(ai);
5825 }
5826 
5827 void
5828 setwgpeerpsk(const char *psk_b64, int param)
5829 {
5830 	if (wg_peer == NULL)
5831 		errx(1, "wgpsk: wgpeer not set");
5832 	wg_peer->p_flags |= WG_PEER_HAS_PSK;
5833 	WG_LOAD_KEY(wg_peer->p_psk, psk_b64, "wgpsk");
5834 }
5835 
5836 void
5837 setwgpeerpka(const char *pka, int param)
5838 {
5839 	const char *errmsg = NULL;
5840 	if (wg_peer == NULL)
5841 		errx(1, "wgpka: wgpeer not set");
5842 	/* 43200 == 12h, reasonable for a 16 bit value */
5843 	wg_peer->p_flags |= WG_PEER_HAS_PKA;
5844 	wg_peer->p_pka = strtonum(pka, 0, 43200, &errmsg);
5845 	if (errmsg)
5846 		errx(1, "wgpka: %s, %s", pka, errmsg);
5847 }
5848 
5849 void
5850 setwgport(const char *port, int param)
5851 {
5852 	const char *errmsg = NULL;
5853 	ensurewginterface();
5854 	wg_interface->i_flags |= WG_INTERFACE_HAS_PORT;
5855 	wg_interface->i_port = strtonum(port, 0, 65535, &errmsg);
5856 	if (errmsg)
5857 		errx(1, "wgport: %s, %s", port, errmsg);
5858 }
5859 
5860 void
5861 setwgkey(const char *private_b64, int param)
5862 {
5863 	ensurewginterface();
5864 	wg_interface->i_flags |= WG_INTERFACE_HAS_PRIVATE;
5865 	WG_LOAD_KEY(wg_interface->i_private, private_b64, "wgkey");
5866 }
5867 
5868 void
5869 setwgrtable(const char *id, int param)
5870 {
5871 	const char *errmsg = NULL;
5872 	ensurewginterface();
5873 	wg_interface->i_flags |= WG_INTERFACE_HAS_RTABLE;
5874 	wg_interface->i_rtable = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
5875 	if (errmsg)
5876 		errx(1, "wgrtable %s: %s", id, errmsg);
5877 }
5878 
5879 void
5880 unsetwgpeer(const char *peerkey_b64, int param)
5881 {
5882 	setwgpeer(peerkey_b64, param);
5883 	wg_peer->p_flags |= WG_PEER_REMOVE;
5884 }
5885 
5886 void
5887 unsetwgpeerpsk(const char *value, int param)
5888 {
5889 	if (wg_peer == NULL)
5890 		errx(1, "wgpsk: wgpeer not set");
5891 	wg_peer->p_flags |= WG_PEER_HAS_PSK;
5892 	bzero(wg_peer->p_psk, WG_KEY_LEN);
5893 }
5894 
5895 void
5896 unsetwgpeerall(const char *value, int param)
5897 {
5898 	ensurewginterface();
5899 	wg_interface->i_flags |= WG_INTERFACE_REPLACE_PEERS;
5900 }
5901 
5902 void
5903 process_wg_commands(void)
5904 {
5905 	if (actions & A_WIREGUARD) {
5906 		strlcpy(wgdata.wgd_name, ifname, sizeof(wgdata.wgd_name));
5907 
5908 		if (ioctl(sock, SIOCSWG, (caddr_t)&wgdata) == -1)
5909 			err(1, "SIOCSWG");
5910 	}
5911 }
5912 
5913 void
5914 wg_status(void)
5915 {
5916 	size_t			 i, j, last_size;
5917 	struct timespec		 now;
5918 	char			 hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
5919 	char			 key[WG_BASE64_KEY_LEN + 1];
5920 
5921 	strlcpy(wgdata.wgd_name, ifname, sizeof(wgdata.wgd_name));
5922 	wgdata.wgd_size = 0;
5923 	wgdata.wgd_interface = NULL;
5924 	for (last_size = wgdata.wgd_size;; last_size = wgdata.wgd_size) {
5925 		if (ioctl(sock, SIOCGWG, (caddr_t)&wgdata) < 0) {
5926 			if (errno == ENOTTY)
5927 				goto out;
5928 			err(1, "SIOCGWG");
5929 		}
5930 		if (last_size >= wgdata.wgd_size)
5931 			break;
5932 		wgdata.wgd_interface = realloc(wgdata.wgd_interface,
5933 		    wgdata.wgd_size);
5934 		if (!wgdata.wgd_interface)
5935 			err(1, "realloc");
5936 	}
5937 	wg_interface = wgdata.wgd_interface;
5938 
5939 	if (wg_interface->i_flags & WG_INTERFACE_HAS_PORT)
5940 		printf("\twgport %hu\n", wg_interface->i_port);
5941 	if (wg_interface->i_flags & WG_INTERFACE_HAS_RTABLE)
5942 		printf("\twgrtable %d\n", wg_interface->i_rtable);
5943 	if (wg_interface->i_flags & WG_INTERFACE_HAS_PUBLIC) {
5944 		b64_ntop(wg_interface->i_public, WG_KEY_LEN,
5945 		    key, sizeof(key));
5946 		printf("\twgpubkey %s\n", key);
5947 	}
5948 
5949 	wg_peer = &wg_interface->i_peers[0];
5950 	for (i = 0; i < wg_interface->i_peers_count; i++) {
5951 		b64_ntop(wg_peer->p_public, WG_KEY_LEN,
5952 		    key, sizeof(key));
5953 		printf("\twgpeer %s\n", key);
5954 
5955 		if (wg_peer->p_flags & WG_PEER_HAS_PSK)
5956 			printf("\t\twgpsk (present)\n");
5957 
5958 		if (wg_peer->p_flags & WG_PEER_HAS_PKA && wg_peer->p_pka)
5959 			printf("\t\twgpka %u (sec)\n", wg_peer->p_pka);
5960 
5961 		if (wg_peer->p_flags & WG_PEER_HAS_ENDPOINT) {
5962 			if (getnameinfo(&wg_peer->p_sa, wg_peer->p_sa.sa_len,
5963 			    hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
5964 			    NI_NUMERICHOST | NI_NUMERICSERV) == 0)
5965 				printf("\t\twgendpoint %s %s\n", hbuf, sbuf);
5966 			else
5967 				printf("\t\twgendpoint unable to print\n");
5968 		}
5969 
5970 		printf("\t\ttx: %llu, rx: %llu\n",
5971 		    wg_peer->p_txbytes, wg_peer->p_rxbytes);
5972 
5973 		if (wg_peer->p_last_handshake.tv_sec != 0) {
5974 			timespec_get(&now, TIME_UTC);
5975 			printf("\t\tlast handshake: %lld seconds ago\n",
5976 			    now.tv_sec - wg_peer->p_last_handshake.tv_sec);
5977 		}
5978 
5979 
5980 		wg_aip = &wg_peer->p_aips[0];
5981 		for (j = 0; j < wg_peer->p_aips_count; j++) {
5982 			inet_ntop(wg_aip->a_af, &wg_aip->a_addr,
5983 			    hbuf, sizeof(hbuf));
5984 			printf("\t\twgaip %s/%d\n", hbuf, wg_aip->a_cidr);
5985 			wg_aip++;
5986 		}
5987 		wg_peer = (struct wg_peer_io *)wg_aip;
5988 	}
5989 out:
5990 	free(wgdata.wgd_interface);
5991 }
5992 
5993 const struct umb_valdescr umb_regstate[] = MBIM_REGSTATE_DESCRIPTIONS;
5994 const struct umb_valdescr umb_dataclass[] = MBIM_DATACLASS_DESCRIPTIONS;
5995 const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
5996 const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS;
5997 const struct umb_valdescr umb_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS;
5998 const struct umb_valdescr umb_actstate[] = MBIM_ACTIVATION_STATE_DESCRIPTIONS;
5999 
6000 const struct umb_valdescr umb_classalias[] = {
6001 	{ MBIM_DATACLASS_GPRS | MBIM_DATACLASS_EDGE, "2g" },
6002 	{ MBIM_DATACLASS_UMTS | MBIM_DATACLASS_HSDPA | MBIM_DATACLASS_HSUPA,
6003 	    "3g" },
6004 	{ MBIM_DATACLASS_LTE, "4g" },
6005 	{ 0, NULL }
6006 };
6007 
6008 static int
6009 umb_descr2val(const struct umb_valdescr *vdp, char *str)
6010 {
6011 	while (vdp->descr != NULL) {
6012 		if (!strcasecmp(vdp->descr, str))
6013 			return vdp->val;
6014 		vdp++;
6015 	}
6016 	return 0;
6017 }
6018 
6019 void
6020 umb_status(void)
6021 {
6022 	struct umb_info mi;
6023 	char	 provider[UMB_PROVIDERNAME_MAXLEN+1];
6024 	char	 providerid[UMB_PROVIDERID_MAXLEN+1];
6025 	char	 roamingtxt[UMB_ROAMINGTEXT_MAXLEN+1];
6026 	char	 devid[UMB_DEVID_MAXLEN+1];
6027 	char	 fwinfo[UMB_FWINFO_MAXLEN+1];
6028 	char	 hwinfo[UMB_HWINFO_MAXLEN+1];
6029 	char	 sid[UMB_SUBSCRIBERID_MAXLEN+1];
6030 	char	 iccid[UMB_ICCID_MAXLEN+1];
6031 	char	 apn[UMB_APN_MAXLEN+1];
6032 	char	 pn[UMB_PHONENR_MAXLEN+1];
6033 	int	 i, n;
6034 	char	 astr[INET6_ADDRSTRLEN];
6035 
6036 	memset((char *)&mi, 0, sizeof(mi));
6037 	ifr.ifr_data = (caddr_t)&mi;
6038 	if (ioctl(sock, SIOCGUMBINFO, (caddr_t)&ifr) == -1)
6039 		return;
6040 
6041 	if (mi.nwerror) {
6042 		/* 3GPP 24.008 Cause Code */
6043 		printf("\terror: ");
6044 		switch (mi.nwerror) {
6045 		case 2:
6046 			printf("SIM not activated");
6047 			break;
6048 		case 4:
6049 			printf("Roaming not supported");
6050 			break;
6051 		case 6:
6052 			printf("SIM reported stolen");
6053 			break;
6054 		case 7:
6055 			printf("No GPRS subscription");
6056 			break;
6057 		case 8:
6058 			printf("GPRS and non-GPRS services not allowed");
6059 			break;
6060 		case 11:
6061 			printf("Subscription expired");
6062 			break;
6063 		case 12:
6064 			printf("Subscription does not cover current location");
6065 			break;
6066 		case 13:
6067 			printf("No roaming in this location");
6068 			break;
6069 		case 14:
6070 			printf("GPRS not supported");
6071 			break;
6072 		case 15:
6073 			printf("No subscription for the service");
6074 			break;
6075 		case 17:
6076 			printf("Registration failed");
6077 			break;
6078 		case 22:
6079 			printf("Network congestion");
6080 			break;
6081 		default:
6082 			printf("Error code %d", mi.nwerror);
6083 			break;
6084 		}
6085 		printf("\n");
6086 	}
6087 
6088 	printf("\troaming %s registration %s",
6089 	    mi.enable_roaming ? "enabled" : "disabled",
6090 	    umb_val2descr(umb_regstate, mi.regstate));
6091 	utf16_to_char(mi.roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
6092 	    roamingtxt, sizeof (roamingtxt));
6093 	if (roamingtxt[0])
6094 		printf(" [%s]", roamingtxt);
6095 	printf("\n");
6096 
6097 	if (showclasses)
6098 		umb_printclasses("available classes", mi.supportedclasses);
6099 	printf("\tstate %s cell-class %s",
6100 	    umb_val2descr(umb_istate, mi.state),
6101 	    umb_val2descr(umb_dataclass, mi.highestclass));
6102 	if (mi.rssi != UMB_VALUE_UNKNOWN && mi.rssi != 0)
6103 		printf(" rssi %ddBm", mi.rssi);
6104 	if (mi.uplink_speed != 0 || mi.downlink_speed != 0) {
6105 		char s[2][FMT_SCALED_STRSIZE];
6106 		if (fmt_scaled(mi.uplink_speed, s[0]) != 0)
6107 			snprintf(s[0], sizeof (s[0]), "%llu", mi.uplink_speed);
6108 		if (fmt_scaled(mi.downlink_speed, s[1]) != 0)
6109 			snprintf(s[1], sizeof (s[1]), "%llu", mi.downlink_speed);
6110 		printf(" speed %sbps up %sbps down", s[0], s[1]);
6111 	}
6112 	printf("\n");
6113 
6114 	printf("\tSIM %s PIN ", umb_val2descr(umb_simstate, mi.sim_state));
6115 	switch (mi.pin_state) {
6116 	case UMB_PIN_REQUIRED:
6117 		printf("required");
6118 		break;
6119 	case UMB_PIN_UNLOCKED:
6120 		printf("valid");
6121 		break;
6122 	case UMB_PUK_REQUIRED:
6123 		printf("locked (PUK required)");
6124 		break;
6125 	default:
6126 		printf("unknown state (%d)", mi.pin_state);
6127 		break;
6128 	}
6129 	if (mi.pin_attempts_left != UMB_VALUE_UNKNOWN)
6130 		printf(" (%d attempts left)", mi.pin_attempts_left);
6131 	printf("\n");
6132 
6133 	utf16_to_char(mi.sid, UMB_SUBSCRIBERID_MAXLEN, sid, sizeof (sid));
6134 	utf16_to_char(mi.iccid, UMB_ICCID_MAXLEN, iccid, sizeof (iccid));
6135 	utf16_to_char(mi.provider, UMB_PROVIDERNAME_MAXLEN,
6136 	    provider, sizeof (provider));
6137 	utf16_to_char(mi.providerid, UMB_PROVIDERID_MAXLEN,
6138 	    providerid, sizeof (providerid));
6139 	if (sid[0] || iccid[0]) {
6140 		printf("\t");
6141 		n = 0;
6142 		if (sid[0])
6143 			printf("%ssubscriber-id %s", n++ ? " " : "", sid);
6144 		if (iccid[0])
6145 			printf("%sICC-id %s", n++ ? " " : "", iccid);
6146 		printf("\n");
6147 	}
6148 
6149 	utf16_to_char(mi.hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof (hwinfo));
6150 	utf16_to_char(mi.devid, UMB_DEVID_MAXLEN, devid, sizeof (devid));
6151 	utf16_to_char(mi.fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof (fwinfo));
6152 	if (hwinfo[0] || devid[0] || fwinfo[0]) {
6153 		printf("\t");
6154 		n = 0;
6155 		if (hwinfo[0])
6156 			printf("%sdevice %s", n++ ? " " : "", hwinfo);
6157 		if (devid[0]) {
6158 			printf("%s", n++ ? " " : "");
6159 			switch (mi.cellclass) {
6160 			case MBIM_CELLCLASS_GSM:
6161 				printf("IMEI");
6162 				break;
6163 			case MBIM_CELLCLASS_CDMA:
6164 				n = strlen(devid);
6165 				if (n == 8 || n == 11) {
6166 					printf("ESN");
6167 					break;
6168 				} else if (n == 14 || n == 18) {
6169 					printf("MEID");
6170 					break;
6171 				}
6172 				/*FALLTHROUGH*/
6173 			default:
6174 				printf("ID");
6175 				break;
6176 			}
6177 			printf(" %s", devid);
6178 		}
6179 		if (fwinfo[0])
6180 			printf("%sfirmware %s", n++ ? " " : "", fwinfo);
6181 		printf("\n");
6182 	}
6183 
6184 	utf16_to_char(mi.pn, UMB_PHONENR_MAXLEN, pn, sizeof (pn));
6185 	utf16_to_char(mi.apn, UMB_APN_MAXLEN, apn, sizeof (apn));
6186 	if (pn[0] || apn[0] || provider[0] || providerid[0]) {
6187 		printf("\t");
6188 		n = 0;
6189 		if (pn[0])
6190 			printf("%sphone# %s", n++ ? " " : "", pn);
6191 		if (apn[0])
6192 			printf("%sAPN %s", n++ ? " " : "", apn);
6193 		if (provider[0])
6194 			printf("%sprovider %s", n++ ? " " : "", provider);
6195 		if (providerid[0])
6196 			printf("%sprovider-id %s", n ? " " : "", providerid);
6197 		printf("\n");
6198 	}
6199 
6200 	for (i = 0, n = 0; i < UMB_MAX_DNSSRV; i++) {
6201 		if (mi.ipv4dns[i].s_addr == INADDR_ANY)
6202 			break;
6203 		printf("%s %s", n++ ? "" : "\tdns",
6204 		    inet_ntop(AF_INET, &mi.ipv4dns[i], astr, sizeof(astr)));
6205 	}
6206 	for (i = 0; i < UMB_MAX_DNSSRV; i++) {
6207 		if (memcmp(&mi.ipv6dns[i], &in6addr_any,
6208 		    sizeof (mi.ipv6dns[i])) == 0)
6209 			break;
6210 		printf("%s %s", n++ ? "" : "\tdns",
6211 		    inet_ntop(AF_INET6, &mi.ipv6dns[i], astr, sizeof(astr)));
6212 	}
6213 	if (n)
6214 		printf("\n");
6215 }
6216 
6217 void
6218 umb_printclasses(char *tag, int c)
6219 {
6220 	int	 i;
6221 	char	*sep = "";
6222 
6223 	printf("\t%s: ", tag);
6224 	i = 0;
6225 	while (umb_dataclass[i].descr) {
6226 		if (umb_dataclass[i].val & c) {
6227 			printf("%s%s", sep, umb_dataclass[i].descr);
6228 			sep = ",";
6229 		}
6230 		i++;
6231 	}
6232 	printf("\n");
6233 }
6234 
6235 int
6236 umb_parse_classes(const char *spec)
6237 {
6238 	char	*optlist, *str;
6239 	int	 c = 0, v;
6240 
6241 	if ((optlist = strdup(spec)) == NULL)
6242 		err(1, "strdup");
6243 	str = strtok(optlist, ",");
6244 	while (str != NULL) {
6245 		if ((v = umb_descr2val(umb_dataclass, str)) != 0 ||
6246 		    (v = umb_descr2val(umb_classalias, str)) != 0)
6247 			c |= v;
6248 		str = strtok(NULL, ",");
6249 	}
6250 	free(optlist);
6251 	return c;
6252 }
6253 
6254 void
6255 umb_setpin(const char *pin, int d)
6256 {
6257 	umb_pinop(MBIM_PIN_OP_ENTER, 0, pin, NULL);
6258 }
6259 
6260 void
6261 umb_chgpin(const char *pin, const char *newpin)
6262 {
6263 	umb_pinop(MBIM_PIN_OP_CHANGE, 0, pin, newpin);
6264 }
6265 
6266 void
6267 umb_puk(const char *pin, const char *newpin)
6268 {
6269 	umb_pinop(MBIM_PIN_OP_ENTER, 1, pin, newpin);
6270 }
6271 
6272 void
6273 umb_pinop(int op, int is_puk, const char *pin, const char *newpin)
6274 {
6275 	struct umb_parameter mp;
6276 
6277 	memset(&mp, 0, sizeof (mp));
6278 	ifr.ifr_data = (caddr_t)&mp;
6279 	if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6280 		err(1, "SIOCGUMBPARAM");
6281 
6282 	mp.op = op;
6283 	mp.is_puk = is_puk;
6284 	if ((mp.pinlen = char_to_utf16(pin, (uint16_t *)mp.pin,
6285 	    sizeof (mp.pin))) == -1)
6286 		errx(1, "PIN too long");
6287 
6288 	if (newpin) {
6289 		if ((mp.newpinlen = char_to_utf16(newpin, (uint16_t *)mp.newpin,
6290 		    sizeof (mp.newpin))) == -1)
6291 		errx(1, "new PIN too long");
6292 	}
6293 
6294 	if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6295 		err(1, "SIOCSUMBPARAM");
6296 }
6297 
6298 void
6299 umb_apn(const char *apn, int d)
6300 {
6301 	struct umb_parameter mp;
6302 
6303 	memset(&mp, 0, sizeof (mp));
6304 	ifr.ifr_data = (caddr_t)&mp;
6305 	if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6306 		err(1, "SIOCGUMBPARAM");
6307 
6308 	if (d != 0)
6309 		memset(mp.apn, 0, sizeof (mp.apn));
6310 	else if ((mp.apnlen = char_to_utf16(apn, mp.apn,
6311 	    sizeof (mp.apn))) == -1)
6312 		errx(1, "APN too long");
6313 
6314 	if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6315 		err(1, "SIOCSUMBPARAM");
6316 }
6317 
6318 void
6319 umb_setclass(const char *val, int d)
6320 {
6321 	struct umb_parameter mp;
6322 
6323 	if (val == NULL) {
6324 		if (showclasses)
6325 			usage();
6326 		showclasses = 1;
6327 		return;
6328 	}
6329 
6330 	memset(&mp, 0, sizeof (mp));
6331 	ifr.ifr_data = (caddr_t)&mp;
6332 	if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6333 		err(1, "SIOCGUMBPARAM");
6334 	if (d != -1)
6335 		mp.preferredclasses = umb_parse_classes(val);
6336 	else
6337 		mp.preferredclasses = MBIM_DATACLASS_NONE;
6338 	if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6339 		err(1, "SIOCSUMBPARAM");
6340 }
6341 
6342 void
6343 umb_roaming(const char *val, int d)
6344 {
6345 	struct umb_parameter mp;
6346 
6347 	memset(&mp, 0, sizeof (mp));
6348 	ifr.ifr_data = (caddr_t)&mp;
6349 	if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6350 		err(1, "SIOCGUMBPARAM");
6351 	mp.roaming = d;
6352 	if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6353 		err(1, "SIOCSUMBPARAM");
6354 }
6355 
6356 void
6357 utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
6358 {
6359 	uint16_t c;
6360 
6361 	while (outlen > 0) {
6362 		c = inlen > 0 ? letoh16(*in) : 0;
6363 		if (c == 0 || --outlen == 0) {
6364 			/* always NUL terminate result */
6365 			*out = '\0';
6366 			break;
6367 		}
6368 		*out++ = isascii(c) ? (char)c : '?';
6369 		in++;
6370 		inlen--;
6371 	}
6372 }
6373 
6374 int
6375 char_to_utf16(const char *in, uint16_t *out, size_t outlen)
6376 {
6377 	int	 n = 0;
6378 	uint16_t c;
6379 
6380 	for (;;) {
6381 		c = *in++;
6382 
6383 		if (c == '\0') {
6384 			/*
6385 			 * NUL termination is not required, but zero out the
6386 			 * residual buffer
6387 			 */
6388 			memset(out, 0, outlen);
6389 			return n;
6390 		}
6391 		if (outlen < sizeof (*out))
6392 			return -1;
6393 
6394 		*out++ = htole16(c);
6395 		n += sizeof (*out);
6396 		outlen -= sizeof (*out);
6397 	}
6398 }
6399 
6400 #endif
6401 
6402 #define SIN(x) ((struct sockaddr_in *) &(x))
6403 struct sockaddr_in *sintab[] = {
6404 SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
6405 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
6406 
6407 void
6408 in_getaddr(const char *s, int which)
6409 {
6410 	struct sockaddr_in *sin = sintab[which], tsin;
6411 	struct hostent *hp;
6412 	int bits, l;
6413 	char p[3];
6414 
6415 	bzero(&tsin, sizeof(tsin));
6416 	sin->sin_len = sizeof(*sin);
6417 	if (which != MASK)
6418 		sin->sin_family = AF_INET;
6419 
6420 	if (which == ADDR && strrchr(s, '/') != NULL &&
6421 	    (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
6422 	    sizeof(tsin.sin_addr))) != -1) {
6423 		l = snprintf(p, sizeof(p), "%d", bits);
6424 		if (l < 0 || l >= sizeof(p))
6425 			errx(1, "%d: bad prefixlen", bits);
6426 		in_getprefix(p, MASK);
6427 		memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
6428 	} else if (inet_aton(s, &sin->sin_addr) == 0) {
6429 		if ((hp = gethostbyname(s)))
6430 			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
6431 		else
6432 			errx(1, "%s: bad value", s);
6433 	}
6434 	if (which == MASK && (ntohl(sin->sin_addr.s_addr) &
6435 	    (~ntohl(sin->sin_addr.s_addr) >> 1)))
6436 		errx(1, "%s: non-contiguous mask", s);
6437 }
6438 
6439 /* ARGSUSED */
6440 void
6441 in_getprefix(const char *plen, int which)
6442 {
6443 	struct sockaddr_in *sin = sintab[which];
6444 	const char *errmsg = NULL;
6445 	u_char *cp;
6446 	int len;
6447 
6448 	len = strtonum(plen, 0, 32, &errmsg);
6449 	if (errmsg)
6450 		errx(1, "prefix %s: %s", plen, errmsg);
6451 
6452 	sin->sin_len = sizeof(*sin);
6453 	if (which != MASK)
6454 		sin->sin_family = AF_INET;
6455 	if ((len == 0) || (len == 32)) {
6456 		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
6457 		return;
6458 	}
6459 	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
6460 	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
6461 		*cp++ = 0xff;
6462 	if (len)
6463 		*cp = 0xff << (8 - len);
6464 }
6465 
6466 /*
6467  * Print a value a la the %b format of the kernel's printf
6468  */
6469 void
6470 printb(char *s, unsigned int v, unsigned char *bits)
6471 {
6472 	int i, any = 0;
6473 	unsigned char c;
6474 
6475 	if (bits && *bits == 8)
6476 		printf("%s=%o", s, v);
6477 	else
6478 		printf("%s=%x", s, v);
6479 
6480 	if (bits) {
6481 		bits++;
6482 		putchar('<');
6483 		while ((i = *bits++)) {
6484 			if (v & (1 << (i-1))) {
6485 				if (any)
6486 					putchar(',');
6487 				any = 1;
6488 				for (; (c = *bits) > 32; bits++)
6489 					putchar(c);
6490 			} else
6491 				for (; *bits > 32; bits++)
6492 					;
6493 		}
6494 		putchar('>');
6495 	}
6496 }
6497 
6498 /*
6499  * A simple version of printb for status output
6500  */
6501 void
6502 printb_status(unsigned short v, unsigned char *bits)
6503 {
6504 	int i, any = 0;
6505 	unsigned char c;
6506 
6507 	if (bits) {
6508 		bits++;
6509 		while ((i = *bits++)) {
6510 			if (v & (1 << (i-1))) {
6511 				if (any)
6512 					putchar(',');
6513 				any = 1;
6514 				for (; (c = *bits) > 32; bits++)
6515 					putchar(tolower(c));
6516 			} else
6517 				for (; *bits > 32; bits++)
6518 					;
6519 		}
6520 	}
6521 }
6522 
6523 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
6524 struct sockaddr_in6 *sin6tab[] = {
6525 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
6526 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
6527 
6528 void
6529 in6_getaddr(const char *s, int which)
6530 {
6531 	struct sockaddr_in6 *sin6 = sin6tab[which];
6532 	struct addrinfo hints, *res;
6533 	char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
6534 	int error;
6535 
6536 	memset(&hints, 0, sizeof(hints));
6537 	hints.ai_family = AF_INET6;
6538 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
6539 
6540 	if (which == ADDR && strchr(s, '/') != NULL) {
6541 		if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
6542 			errx(1, "%s: bad value", s);
6543 		pfxlen = strchr(buf, '/');
6544 		*pfxlen++ = '\0';
6545 		s = buf;
6546 		in6_getprefix(pfxlen, MASK);
6547 		explicit_prefix = 1;
6548 	}
6549 
6550 	error = getaddrinfo(s, "0", &hints, &res);
6551 	if (error)
6552 		errx(1, "%s: %s", s, gai_strerror(error));
6553 	memcpy(sin6, res->ai_addr, res->ai_addrlen);
6554 #ifdef __KAME__
6555 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
6556 	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
6557 	    sin6->sin6_scope_id) {
6558 		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
6559 		    htons(sin6->sin6_scope_id & 0xffff);
6560 		sin6->sin6_scope_id = 0;
6561 	}
6562 #endif /* __KAME__ */
6563 	freeaddrinfo(res);
6564 }
6565 
6566 void
6567 in6_getprefix(const char *plen, int which)
6568 {
6569 	struct sockaddr_in6 *sin6 = sin6tab[which];
6570 	const char *errmsg = NULL;
6571 	u_char *cp;
6572 	int len;
6573 
6574 	len = strtonum(plen, 0, 128, &errmsg);
6575 	if (errmsg)
6576 		errx(1, "prefix %s: %s", plen, errmsg);
6577 
6578 	sin6->sin6_len = sizeof(*sin6);
6579 	if (which != MASK)
6580 		sin6->sin6_family = AF_INET6;
6581 	if ((len == 0) || (len == 128)) {
6582 		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
6583 		return;
6584 	}
6585 	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
6586 	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
6587 		*cp++ = 0xff;
6588 	if (len)
6589 		*cp = 0xff << (8 - len);
6590 }
6591 
6592 int
6593 prefix(void *val, int size)
6594 {
6595 	u_char *nam = (u_char *)val;
6596 	int byte, bit, plen = 0;
6597 
6598 	for (byte = 0; byte < size; byte++, plen += 8)
6599 		if (nam[byte] != 0xff)
6600 			break;
6601 	if (byte == size)
6602 		return (plen);
6603 	for (bit = 7; bit != 0; bit--, plen++)
6604 		if (!(nam[byte] & (1 << bit)))
6605 			break;
6606 	for (; bit != 0; bit--)
6607 		if (nam[byte] & (1 << bit))
6608 			return (0);
6609 	byte++;
6610 	for (; byte < size; byte++)
6611 		if (nam[byte])
6612 			return (0);
6613 	return (plen);
6614 }
6615 
6616 /* Print usage and exit  */
6617 __dead void
6618 usage(void)
6619 {
6620 	fprintf(stderr,
6621 	    "usage: ifconfig [-AaC] [interface] [address_family] "
6622 	    "[address [dest_address]]\n"
6623 	    "\t\t[parameters]\n");
6624 	exit(1);
6625 }
6626 
6627 void
6628 getifgroups(void)
6629 {
6630 	int			 len, cnt;
6631 	struct ifgroupreq	 ifgr;
6632 	struct ifg_req		*ifg;
6633 
6634 	memset(&ifgr, 0, sizeof(ifgr));
6635 	strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
6636 
6637 	if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
6638 		if (errno == EINVAL || errno == ENOTTY)
6639 			return;
6640 		else
6641 			err(1, "SIOCGIFGROUP");
6642 	}
6643 
6644 	len = ifgr.ifgr_len;
6645 	ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
6646 	    sizeof(struct ifg_req));
6647 	if (ifgr.ifgr_groups == NULL)
6648 		err(1, "getifgroups");
6649 	if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
6650 		err(1, "SIOCGIFGROUP");
6651 
6652 	cnt = 0;
6653 	ifg = ifgr.ifgr_groups;
6654 	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
6655 		len -= sizeof(struct ifg_req);
6656 		if (strcmp(ifg->ifgrq_group, "all")) {
6657 			if (cnt == 0)
6658 				printf("\tgroups:");
6659 			cnt++;
6660 			printf(" %s", ifg->ifgrq_group);
6661 		}
6662 	}
6663 	if (cnt)
6664 		printf("\n");
6665 
6666 	free(ifgr.ifgr_groups);
6667 }
6668 
6669 #ifndef SMALL
6670 void
6671 printifhwfeatures(const char *unused, int show)
6672 {
6673 	struct if_data ifrdat;
6674 
6675 	if (!show) {
6676 		if (showcapsflag)
6677 			usage();
6678 		showcapsflag = 1;
6679 		return;
6680 	}
6681 	bzero(&ifrdat, sizeof(ifrdat));
6682 	ifr.ifr_data = (caddr_t)&ifrdat;
6683 	if (ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr) == -1)
6684 		err(1, "SIOCGIFDATA");
6685 	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
6686 
6687 	if (ioctl(sock, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
6688 		if (ifr.ifr_hardmtu)
6689 			printf(" hardmtu %u", ifr.ifr_hardmtu);
6690 	}
6691 	putchar('\n');
6692 }
6693 #endif
6694 
6695 char *
6696 sec2str(time_t total)
6697 {
6698 	static char result[256];
6699 	char *p = result;
6700 	char *end = &result[sizeof(result)];
6701 
6702 	snprintf(p, end - p, "%lld", (long long)total);
6703 	return (result);
6704 }
6705 
6706 /*ARGSUSED*/
6707 void
6708 setiflladdr(const char *addr, int param)
6709 {
6710 	struct ether_addr *eap, eabuf;
6711 
6712 	if (!strcmp(addr, "random")) {
6713 		arc4random_buf(&eabuf, sizeof eabuf);
6714 		/* Non-multicast and claim it is a hardware address */
6715 		eabuf.ether_addr_octet[0] &= 0xfc;
6716 		eap = &eabuf;
6717 	} else {
6718 		eap = ether_aton(addr);
6719 		if (eap == NULL) {
6720 			warnx("malformed link-level address");
6721 			return;
6722 		}
6723 	}
6724 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6725 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
6726 	ifr.ifr_addr.sa_family = AF_LINK;
6727 	bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
6728 	if (ioctl(sock, SIOCSIFLLADDR, (caddr_t)&ifr) == -1)
6729 		warn("SIOCSIFLLADDR");
6730 }
6731 
6732 #ifndef SMALL
6733 void
6734 setrdomain(const char *id, int param)
6735 {
6736 	const char *errmsg = NULL;
6737 	int rdomainid;
6738 
6739 	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
6740 	if (errmsg)
6741 		errx(1, "rdomain %s: %s", id, errmsg);
6742 
6743 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6744 	ifr.ifr_rdomainid = rdomainid;
6745 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
6746 		warn("SIOCSIFRDOMAIN");
6747 }
6748 
6749 void
6750 unsetrdomain(const char *ignored, int alsoignored)
6751 {
6752 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6753 	ifr.ifr_rdomainid = 0;
6754 	if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
6755 		warn("SIOCSIFRDOMAIN");
6756 }
6757 #endif
6758 
6759 #ifndef SMALL
6760 void
6761 setpair(const char *val, int d)
6762 {
6763 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6764 	if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
6765 		errno = ENOENT;
6766 		err(1, "patch %s", val);
6767 	}
6768 	if (ioctl(sock, SIOCSIFPAIR, (caddr_t)&ifr) == -1)
6769 		warn("SIOCSIFPAIR");
6770 }
6771 
6772 void
6773 unsetpair(const char *val, int d)
6774 {
6775 	ifr.ifr_index = 0;
6776 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6777 	if (ioctl(sock, SIOCSIFPAIR, (caddr_t)&ifr) == -1)
6778 		warn("SIOCSIFPAIR");
6779 }
6780 #endif
6781 
6782 #ifdef SMALL
6783 void
6784 setignore(const char *id, int param)
6785 {
6786 	/* just digest the command */
6787 }
6788 #endif
6789