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