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