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