GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ifconfig/ifconfig.c Lines: 741 2676 27.7 %
Date: 2017-11-13 Branches: 366 1800 20.3 %

Line Branch Exec Source
1
/*	$OpenBSD: ifconfig.c,v 1.350 2017/11/05 22:09:26 benno 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/param.h> /* NBBY isset */
64
#include <sys/socket.h>
65
#include <sys/ioctl.h>
66
#include <sys/time.h>
67
68
#include <net/if.h>
69
#include <net/if_dl.h>
70
#include <net/if_media.h>
71
#include <net/if_types.h>
72
#include <netinet/in.h>
73
#include <netinet/in_var.h>
74
#include <netinet6/in6_var.h>
75
#include <netinet6/nd6.h>
76
#include <arpa/inet.h>
77
#include <netinet/ip_ipsp.h>
78
#include <netinet/if_ether.h>
79
#include <net/if_enc.h>
80
#include <net80211/ieee80211.h>
81
#include <net80211/ieee80211_ioctl.h>
82
#include <net/pfvar.h>
83
#include <net/if_pfsync.h>
84
#include <net/if_pflow.h>
85
#include <net/if_pppoe.h>
86
#include <net/if_trunk.h>
87
#include <net/if_sppp.h>
88
#include <net/ppp_defs.h>
89
90
#include <netinet/ip_carp.h>
91
92
#include <netdb.h>
93
94
#include <net/if_vlan_var.h>
95
96
#include <netmpls/mpls.h>
97
98
#include <ctype.h>
99
#include <err.h>
100
#include <errno.h>
101
#include <stdio.h>
102
#include <stdint.h>
103
#include <stdlib.h>
104
#include <string.h>
105
#include <unistd.h>
106
#include <limits.h>
107
#include <util.h>
108
#include <ifaddrs.h>
109
110
#include "brconfig.h"
111
#ifndef SMALL
112
#include <dev/usb/mbim.h>
113
#include <dev/usb/if_umb.h>
114
#endif /* SMALL */
115
116
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
117
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
118
119
#define HWFEATURESBITS							\
120
	"\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4"			\
121
	"\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6"			\
122
	"\11CSUM_UDPv6\20WOL"
123
124
struct	ifreq		ifr, ridreq;
125
struct	in_aliasreq	in_addreq;
126
struct	in6_ifreq	ifr6;
127
struct	in6_ifreq	in6_ridreq;
128
struct	in6_aliasreq	in6_addreq;
129
struct	sockaddr_in	netmask;
130
131
#ifndef SMALL
132
struct	ifaliasreq	addreq;
133
134
int	wconfig = 0;
135
int	wcwconfig = 0;
136
struct	ifmpwreq	imrsave;
137
#endif /* SMALL */
138
139
char	name[IFNAMSIZ];
140
int	flags, xflags, setaddr, setipdst, doalias;
141
u_long	metric, mtu;
142
int	rdomainid;
143
int	llprio;
144
int	clearaddr, s;
145
int	newaddr = 0;
146
int	af = AF_INET;
147
int	explicit_prefix = 0;
148
int	Lflag = 1;
149
150
int	showmediaflag;
151
int	showcapsflag;
152
int	shownet80211chans;
153
int	shownet80211nodes;
154
int	showclasses;
155
156
struct ifencap;
157
158
void	notealias(const char *, int);
159
void	setifaddr(const char *, int);
160
void	setifrtlabel(const char *, int);
161
void	setiflladdr(const char *, int);
162
void	setifdstaddr(const char *, int);
163
void	setifflags(const char *, int);
164
void	setifxflags(const char *, int);
165
void	addaf(const char *, int);
166
void	removeaf(const char *, int);
167
void	setifbroadaddr(const char *, int);
168
void	setifmtu(const char *, int);
169
void	setifllprio(const char *, int);
170
void	setifnwid(const char *, int);
171
void	setifbssid(const char *, int);
172
void	setifnwkey(const char *, int);
173
void	setifwpa(const char *, int);
174
void	setifwpaprotos(const char *, int);
175
void	setifwpaakms(const char *, int);
176
void	setifwpaciphers(const char *, int);
177
void	setifwpagroupcipher(const char *, int);
178
void	setifwpakey(const char *, int);
179
void	setifchan(const char *, int);
180
void	setifscan(const char *, int);
181
void	setifnwflag(const char *, int);
182
void	unsetifnwflag(const char *, int);
183
void	setifnetmask(const char *, int);
184
void	setifprefixlen(const char *, int);
185
void	settunnel(const char *, const char *);
186
void	deletetunnel(const char *, int);
187
void	settunnelinst(const char *, int);
188
void	settunnelttl(const char *, int);
189
void	setvnetid(const char *, int);
190
void	delvnetid(const char *, int);
191
void	getvnetid(struct ifencap *);
192
void	setifparent(const char *, int);
193
void	delifparent(const char *, int);
194
void	getifparent(struct ifencap *);
195
void	getencap(void);
196
void	setia6flags(const char *, int);
197
void	setia6pltime(const char *, int);
198
void	setia6vltime(const char *, int);
199
void	setia6lifetime(const char *, const char *);
200
void	setia6eui64(const char *, int);
201
void	setkeepalive(const char *, const char *);
202
void	unsetkeepalive(const char *, int);
203
void	setmedia(const char *, int);
204
void	setmediaopt(const char *, int);
205
void	setmediamode(const char *, int);
206
void	unsetmediamode(const char *, int);
207
void	clone_create(const char *, int);
208
void	clone_destroy(const char *, int);
209
void	unsetmediaopt(const char *, int);
210
void	setmediainst(const char *, int);
211
void	setmpelabel(const char *, int);
212
void	process_mpw_commands(void);
213
void	setmpwencap(const char *, int);
214
void	setmpwlabel(const char *, const char *);
215
void	setmpwneighbor(const char *, int);
216
void	setmpwcontrolword(const char *, int);
217
void	setvlantag(const char *, int);
218
void	setvlandev(const char *, int);
219
void	unsetvlandev(const char *, int);
220
void	mpe_status(void);
221
void	mpw_status(void);
222
void	setrdomain(const char *, int);
223
int	prefix(void *val, int);
224
void	getifgroups(void);
225
void	setifgroup(const char *, int);
226
void	unsetifgroup(const char *, int);
227
void	setgroupattribs(char *, int, char *[]);
228
int	printgroup(char *, int);
229
void	setautoconf(const char *, int);
230
void	settrunkport(const char *, int);
231
void	unsettrunkport(const char *, int);
232
void	settrunkproto(const char *, int);
233
void	trunk_status(void);
234
void	list_cloners(void);
235
236
#ifndef SMALL
237
void	carp_status(void);
238
void	setcarp_advbase(const char *,int);
239
void	setcarp_advskew(const char *, int);
240
void	setcarppeer(const char *, int);
241
void	unsetcarppeer(const char *, int);
242
void	setcarp_passwd(const char *, int);
243
void	setcarp_vhid(const char *, int);
244
void	setcarp_state(const char *, int);
245
void	setcarpdev(const char *, int);
246
void	setcarp_nodes(const char *, int);
247
void	setcarp_balancing(const char *, int);
248
void	setpfsync_syncdev(const char *, int);
249
void	setpfsync_maxupd(const char *, int);
250
void	unsetpfsync_syncdev(const char *, int);
251
void	setpfsync_syncpeer(const char *, int);
252
void	unsetpfsync_syncpeer(const char *, int);
253
void	setpfsync_defer(const char *, int);
254
void	pfsync_status(void);
255
void	setpppoe_dev(const char *,int);
256
void	setpppoe_svc(const char *,int);
257
void	setpppoe_ac(const char *,int);
258
void	pppoe_status(void);
259
void	setspppproto(const char *, int);
260
void	setspppname(const char *, int);
261
void	setspppkey(const char *, int);
262
void	setsppppeerproto(const char *, int);
263
void	setsppppeername(const char *, int);
264
void	setsppppeerkey(const char *, int);
265
void	setsppppeerflag(const char *, int);
266
void	unsetsppppeerflag(const char *, int);
267
void	sppp_status(void);
268
void	sppp_printproto(const char *, struct sauthreq *);
269
void	setifpriority(const char *, int);
270
void	setifpowersave(const char *, int);
271
void	setifmetric(const char *, int);
272
void	pflow_status(void);
273
void	pflow_addr(const char*, struct sockaddr_storage *);
274
void	setpflow_sender(const char *, int);
275
void	unsetpflow_sender(const char *, int);
276
void	setpflow_receiver(const char *, int);
277
void	unsetpflow_receiver(const char *, int);
278
void	setpflowproto(const char *, int);
279
void	setifipdst(const char *, int);
280
void	setifdesc(const char *, int);
281
void	unsetifdesc(const char *, int);
282
void	printifhwfeatures(const char *, int);
283
void	setpair(const char *, int);
284
void	unsetpair(const char *, int);
285
void	umb_status(void);
286
void	umb_printclasses(char *, int);
287
int	umb_parse_classes(const char *);
288
void	umb_setpin(const char *, int);
289
void	umb_chgpin(const char *, const char *);
290
void	umb_puk(const char *, const char *);
291
void	umb_pinop(int, int, const char *, const char *);
292
void	umb_apn(const char *, int);
293
void	umb_setclass(const char *, int);
294
void	umb_roaming(const char *, int);
295
void	utf16_to_char(uint16_t *, int, char *, size_t);
296
int	char_to_utf16(const char *, uint16_t *, size_t);
297
#else
298
void	setignore(const char *, int);
299
#endif
300
301
/*
302
 * Media stuff.  Whenever a media command is first performed, the
303
 * currently select media is grabbed for this interface.  If `media'
304
 * is given, the current media word is modified.  `mediaopt' commands
305
 * only modify the set and clear words.  They then operate on the
306
 * current media word later.
307
 */
308
uint64_t	media_current;
309
uint64_t	mediaopt_set;
310
uint64_t	mediaopt_clear;
311
312
int	actions;			/* Actions performed */
313
314
#define	A_MEDIA		0x0001		/* media command */
315
#define	A_MEDIAOPTSET	0x0002		/* mediaopt command */
316
#define	A_MEDIAOPTCLR	0x0004		/* -mediaopt command */
317
#define	A_MEDIAOPT	(A_MEDIAOPTSET|A_MEDIAOPTCLR)
318
#define	A_MEDIAINST	0x0008		/* instance or inst command */
319
#define	A_MEDIAMODE	0x0010		/* mode command */
320
#define A_SILENT	0x8000000	/* doing operation, do not print */
321
322
#define	NEXTARG0	0xffffff
323
#define NEXTARG		0xfffffe
324
#define	NEXTARG2	0xfffffd
325
326
const struct	cmd {
327
	char	*c_name;
328
	int	c_parameter;		/* NEXTARG means next argv */
329
	int	c_action;		/* defered action */
330
	void	(*c_func)(const char *, int);
331
	void	(*c_func2)(const char *, const char *);
332
} cmds[] = {
333
	{ "up",		IFF_UP,		0,		setifflags } ,
334
	{ "down",	-IFF_UP,	0,		setifflags },
335
	{ "arp",	-IFF_NOARP,	0,		setifflags },
336
	{ "-arp",	IFF_NOARP,	0,		setifflags },
337
	{ "debug",	IFF_DEBUG,	0,		setifflags },
338
	{ "-debug",	-IFF_DEBUG,	0,		setifflags },
339
	{ "alias",	IFF_UP,		0,		notealias },
340
	{ "-alias",	-IFF_UP,	0,		notealias },
341
	{ "delete",	-IFF_UP,	0,		notealias },
342
#ifdef notdef
343
#define	EN_SWABIPS	0x1000
344
	{ "swabips",	EN_SWABIPS,	0,		setifflags },
345
	{ "-swabips",	-EN_SWABIPS,	0,		setifflags },
346
#endif /* notdef */
347
	{ "netmask",	NEXTARG,	0,		setifnetmask },
348
	{ "mtu",	NEXTARG,	0,		setifmtu },
349
	{ "nwid",	NEXTARG,	0,		setifnwid },
350
	{ "-nwid",	-1,		0,		setifnwid },
351
	{ "bssid",	NEXTARG,	0,		setifbssid },
352
	{ "-bssid",	-1,		0,		setifbssid },
353
	{ "nwkey",	NEXTARG,	0,		setifnwkey },
354
	{ "-nwkey",	-1,		0,		setifnwkey },
355
	{ "wpa",	1,		0,		setifwpa },
356
	{ "-wpa",	0,		0,		setifwpa },
357
	{ "wpaakms",	NEXTARG,	0,		setifwpaakms },
358
	{ "wpaciphers",	NEXTARG,	0,		setifwpaciphers },
359
	{ "wpagroupcipher", NEXTARG,	0,		setifwpagroupcipher },
360
	{ "wpaprotos",	NEXTARG,	0,		setifwpaprotos },
361
	{ "wpakey",	NEXTARG,	0,		setifwpakey },
362
	{ "-wpakey",	-1,		0,		setifwpakey },
363
	{ "chan",	NEXTARG0,	0,		setifchan },
364
	{ "-chan",	-1,		0,		setifchan },
365
	{ "scan",	NEXTARG0,	0,		setifscan },
366
	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
367
	{ "prefixlen",  NEXTARG,	0,		setifprefixlen},
368
	{ "vnetid",	NEXTARG,	0,		setvnetid },
369
	{ "-vnetid",	0,		0,		delvnetid },
370
	{ "parent",	NEXTARG,	0,		setifparent },
371
	{ "-parent",	1,		0,		delifparent },
372
	{ "vlan",	NEXTARG,	0,		setvlantag },
373
	{ "vlandev",	NEXTARG,	0,		setvlandev },
374
	{ "-vlandev",	1,		0,		unsetvlandev },
375
	{ "group",	NEXTARG,	0,		setifgroup },
376
	{ "-group",	NEXTARG,	0,		unsetifgroup },
377
	{ "autoconf",	1,		0,		setautoconf },
378
	{ "-autoconf",	-1,		0,		setautoconf },
379
	{ "trunkport",	NEXTARG,	0,		settrunkport },
380
	{ "-trunkport",	NEXTARG,	0,		unsettrunkport },
381
	{ "trunkproto",	NEXTARG,	0,		settrunkproto },
382
	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
383
	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
384
	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
385
	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
386
	{ "pltime",	NEXTARG,	0,		setia6pltime },
387
	{ "vltime",	NEXTARG,	0,		setia6vltime },
388
	{ "eui64",	0,		0,		setia6eui64 },
389
	{ "autoconfprivacy",	-IFXF_INET6_NOPRIVACY,	0,	setifxflags },
390
	{ "-autoconfprivacy",	IFXF_INET6_NOPRIVACY,	0,	setifxflags },
391
#ifndef SMALL
392
	{ "hwfeatures", NEXTARG0,	0,		printifhwfeatures },
393
	{ "metric",	NEXTARG,	0,		setifmetric },
394
	{ "powersave",	NEXTARG0,	0,		setifpowersave },
395
	{ "-powersave",	-1,		0,		setifpowersave },
396
	{ "priority",	NEXTARG,	0,		setifpriority },
397
	{ "rtlabel",	NEXTARG,	0,		setifrtlabel },
398
	{ "-rtlabel",	-1,		0,		setifrtlabel },
399
	{ "rdomain",	NEXTARG,	0,		setrdomain },
400
	{ "mpls",	IFXF_MPLS,	0,		setifxflags },
401
	{ "-mpls",	-IFXF_MPLS,	0,		setifxflags },
402
	{ "mplslabel",	NEXTARG,	0,		setmpelabel },
403
	{ "mpwlabel",	NEXTARG2,	0,		NULL, setmpwlabel },
404
	{ "neighbor",	NEXTARG,	0,		setmpwneighbor },
405
	{ "controlword", 1,		0,		setmpwcontrolword },
406
	{ "-controlword", 0,		0,		setmpwcontrolword },
407
	{ "encap",	NEXTARG,	0,		setmpwencap },
408
	{ "advbase",	NEXTARG,	0,		setcarp_advbase },
409
	{ "advskew",	NEXTARG,	0,		setcarp_advskew },
410
	{ "carppeer",	NEXTARG,	0,		setcarppeer },
411
	{ "-carppeer",	1,		0,		unsetcarppeer },
412
	{ "pass",	NEXTARG,	0,		setcarp_passwd },
413
	{ "vhid",	NEXTARG,	0,		setcarp_vhid },
414
	{ "state",	NEXTARG,	0,		setcarp_state },
415
	{ "carpdev",	NEXTARG,	0,		setcarpdev },
416
	{ "carpnodes",	NEXTARG,	0,		setcarp_nodes },
417
	{ "balancing",	NEXTARG,	0,		setcarp_balancing },
418
	{ "syncdev",	NEXTARG,	0,		setpfsync_syncdev },
419
	{ "-syncdev",	1,		0,		unsetpfsync_syncdev },
420
	{ "syncif",	NEXTARG,	0,		setpfsync_syncdev },
421
	{ "-syncif",	1,		0,		unsetpfsync_syncdev },
422
	{ "syncpeer",	NEXTARG,	0,		setpfsync_syncpeer },
423
	{ "-syncpeer",	1,		0,		unsetpfsync_syncpeer },
424
	{ "maxupd",	NEXTARG,	0,		setpfsync_maxupd },
425
	{ "defer",	1,		0,		setpfsync_defer },
426
	{ "-defer",	0,		0,		setpfsync_defer },
427
	{ "tunnel",	NEXTARG2,	0,		NULL, settunnel } ,
428
	{ "deletetunnel",  0,		0,		deletetunnel } ,
429
	{ "tunneldomain", NEXTARG,	0,		settunnelinst } ,
430
	{ "tunnelttl",	NEXTARG,	0,		settunnelttl } ,
431
	{ "pppoedev",	NEXTARG,	0,		setpppoe_dev },
432
	{ "pppoesvc",	NEXTARG,	0,		setpppoe_svc },
433
	{ "-pppoesvc",	1,		0,		setpppoe_svc },
434
	{ "pppoeac",	NEXTARG,	0,		setpppoe_ac },
435
	{ "-pppoeac",	1,		0,		setpppoe_ac },
436
	{ "authproto",	NEXTARG,	0,		setspppproto },
437
	{ "authname",	NEXTARG,	0,		setspppname },
438
	{ "authkey",	NEXTARG,	0,		setspppkey },
439
	{ "peerproto",	NEXTARG,	0,		setsppppeerproto },
440
	{ "peername",	NEXTARG,	0,		setsppppeername },
441
	{ "peerkey",	NEXTARG,	0,		setsppppeerkey },
442
	{ "peerflag",	NEXTARG,	0,		setsppppeerflag },
443
	{ "-peerflag",	NEXTARG,	0,		unsetsppppeerflag },
444
	{ "nwflag",	NEXTARG,	0,		setifnwflag },
445
	{ "-nwflag",	NEXTARG,	0,		unsetifnwflag },
446
	{ "flowsrc",	NEXTARG,	0,		setpflow_sender },
447
	{ "-flowsrc",	1,		0,		unsetpflow_sender },
448
	{ "flowdst",	NEXTARG,	0,		setpflow_receiver },
449
	{ "-flowdst", 1,		0,		unsetpflow_receiver },
450
	{ "pflowproto", NEXTARG,	0,		setpflowproto },
451
	{ "-inet",	AF_INET,	0,		removeaf },
452
	{ "-inet6",	AF_INET6,	0,		removeaf },
453
	{ "keepalive",	NEXTARG2,	0,		NULL, setkeepalive },
454
	{ "-keepalive",	1,		0,		unsetkeepalive },
455
	{ "add",	NEXTARG,	0,		bridge_add },
456
	{ "del",	NEXTARG,	0,		bridge_delete },
457
	{ "addspan",	NEXTARG,	0,		bridge_addspan },
458
	{ "delspan",	NEXTARG,	0,		bridge_delspan },
459
	{ "discover",	NEXTARG,	0,		setdiscover },
460
	{ "-discover",	NEXTARG,	0,		unsetdiscover },
461
	{ "blocknonip", NEXTARG,	0,		setblocknonip },
462
	{ "-blocknonip",NEXTARG,	0,		unsetblocknonip },
463
	{ "learn",	NEXTARG,	0,		setlearn },
464
	{ "-learn",	NEXTARG,	0,		unsetlearn },
465
	{ "stp",	NEXTARG,	0,		setstp },
466
	{ "-stp",	NEXTARG,	0,		unsetstp },
467
	{ "edge",	NEXTARG,	0,		setedge },
468
	{ "-edge",	NEXTARG,	0,		unsetedge },
469
	{ "autoedge",	NEXTARG,	0,		setautoedge },
470
	{ "-autoedge",	NEXTARG,	0,		unsetautoedge },
471
	{ "ptp",	NEXTARG,	0,		setptp },
472
	{ "-ptp",	NEXTARG,	0,		unsetptp },
473
	{ "autoptp",	NEXTARG,	0,		setautoptp },
474
	{ "-autoptp",	NEXTARG,	0,		unsetautoptp },
475
	{ "flush",	0,		0,		bridge_flush },
476
	{ "flushall",	0,		0,		bridge_flushall },
477
	{ "static",	NEXTARG2,	0,		NULL, bridge_addaddr },
478
	{ "deladdr",	NEXTARG,	0,		bridge_deladdr },
479
	{ "maxaddr",	NEXTARG,	0,		bridge_maxaddr },
480
	{ "addr",	0,		0,		bridge_addrs },
481
	{ "hellotime",	NEXTARG,	0,		bridge_hellotime },
482
	{ "fwddelay",	NEXTARG,	0,		bridge_fwddelay },
483
	{ "maxage",	NEXTARG,	0,		bridge_maxage },
484
	{ "proto",	NEXTARG,	0,		bridge_proto },
485
	{ "ifpriority",	NEXTARG2,	0,		NULL, bridge_ifprio },
486
	{ "ifcost",	NEXTARG2,	0,		NULL, bridge_ifcost },
487
	{ "-ifcost",	NEXTARG,	0,		bridge_noifcost },
488
	{ "timeout",	NEXTARG,	0,		bridge_timeout },
489
	{ "holdcnt",	NEXTARG,	0,		bridge_holdcnt },
490
	{ "spanpriority", NEXTARG,	0,		bridge_priority },
491
	{ "ipdst",	NEXTARG,	0,		setifipdst },
492
#if 0
493
	/* XXX `rule` special-cased below */
494
	{ "rule",	0,		0,		bridge_rule },
495
#endif
496
	{ "rules",	NEXTARG,	0,		bridge_rules },
497
	{ "rulefile",	NEXTARG,	0,		bridge_rulefile },
498
	{ "flushrule",	NEXTARG,	0,		bridge_flushrule },
499
	{ "description", NEXTARG,	0,		setifdesc },
500
	{ "descr",	NEXTARG,	0,		setifdesc },
501
	{ "-description", 1,		0,		unsetifdesc },
502
	{ "-descr",	1,		0,		unsetifdesc },
503
	{ "wol",	IFXF_WOL,	0,		setifxflags },
504
	{ "-wol",	-IFXF_WOL,	0,		setifxflags },
505
	{ "pin",	NEXTARG,	0,		umb_setpin },
506
	{ "chgpin",	NEXTARG2,	0,		NULL, umb_chgpin },
507
	{ "puk",	NEXTARG2,	0,		NULL, umb_puk },
508
	{ "apn",	NEXTARG,	0,		umb_apn },
509
	{ "-apn",	-1,		0,		umb_apn },
510
	{ "class",	NEXTARG0,	0,		umb_setclass },
511
	{ "-class",	-1,		0,		umb_setclass },
512
	{ "roaming",	1,		0,		umb_roaming },
513
	{ "-roaming",	0,		0,		umb_roaming },
514
	{ "patch",	NEXTARG,	0,		setpair },
515
	{ "-patch",	1,		0,		unsetpair },
516
	{ "datapath",	NEXTARG,	0,		switch_datapathid },
517
	{ "portno",	NEXTARG2,	0,		NULL, switch_portno },
518
	{ "addlocal",	NEXTARG,	0,		addlocal },
519
#else /* SMALL */
520
	{ "powersave",	NEXTARG0,	0,		setignore },
521
	{ "priority",	NEXTARG,	0,		setignore },
522
	{ "rtlabel",	NEXTARG,	0,		setignore },
523
	{ "mpls",	IFXF_MPLS,	0,		setignore },
524
	{ "nwflag",	NEXTARG,	0,		setignore },
525
	{ "rdomain",	NEXTARG,	0,		setignore },
526
	{ "-inet",	AF_INET,	0,		removeaf },
527
	{ "-inet6",	AF_INET6,	0,		removeaf },
528
	{ "description", NEXTARG,	0,		setignore },
529
	{ "descr",	NEXTARG,	0,		setignore },
530
	{ "wol",	IFXF_WOL,	0,		setignore },
531
	{ "-wol",	-IFXF_WOL,	0,		setignore },
532
#endif /* SMALL */
533
#if 0
534
	/* XXX `create' special-cased below */
535
	{ "create",	0,		0,		clone_create } ,
536
#endif
537
	{ "destroy",	0,		0,		clone_destroy } ,
538
	{ "link0",	IFF_LINK0,	0,		setifflags } ,
539
	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
540
	{ "link1",	IFF_LINK1,	0,		setifflags } ,
541
	{ "-link1",	-IFF_LINK1,	0,		setifflags } ,
542
	{ "link2",	IFF_LINK2,	0,		setifflags } ,
543
	{ "-link2",	-IFF_LINK2,	0,		setifflags } ,
544
	{ "media",	NEXTARG0,	A_MEDIA,	setmedia },
545
	{ "mediaopt",	NEXTARG,	A_MEDIAOPTSET,	setmediaopt },
546
	{ "-mediaopt",	NEXTARG,	A_MEDIAOPTCLR,	unsetmediaopt },
547
	{ "mode",	NEXTARG,	A_MEDIAMODE,	setmediamode },
548
	{ "-mode",	0,		A_MEDIAMODE,	unsetmediamode },
549
	{ "instance",	NEXTARG,	A_MEDIAINST,	setmediainst },
550
	{ "inst",	NEXTARG,	A_MEDIAINST,	setmediainst },
551
	{ "lladdr",	NEXTARG,	0,		setiflladdr },
552
	{ "llprio",	NEXTARG,	0,		setifllprio },
553
	{ NULL, /*src*/	0,		0,		setifaddr },
554
	{ NULL, /*dst*/	0,		0,		setifdstaddr },
555
	{ NULL, /*illegal*/0,		0,		NULL },
556
};
557
558
int	getinfo(struct ifreq *, int);
559
void	getsock(int);
560
void	printgroupattribs(char *);
561
void	printif(char *, int);
562
void	printb_status(unsigned short, unsigned char *);
563
const char *get_linkstate(int, int);
564
void	status(int, struct sockaddr_dl *, int);
565
__dead void	usage(void);
566
const char *get_string(const char *, const char *, u_int8_t *, int *);
567
void	print_string(const u_int8_t *, int);
568
char	*sec2str(time_t);
569
570
const char *get_media_type_string(uint64_t);
571
const char *get_media_subtype_string(uint64_t);
572
uint64_t	get_media_mode(uint64_t, const char *);
573
uint64_t	get_media_subtype(uint64_t, const char *);
574
uint64_t	get_media_options(uint64_t, const char *);
575
uint64_t	lookup_media_word(const struct ifmedia_description *, uint64_t,
576
	    const char *);
577
void	print_media_word(uint64_t, int, int);
578
void	process_media_commands(void);
579
void	init_current_media(void);
580
581
unsigned long get_ts_map(int, int, int);
582
583
void	in_status(int);
584
void	in_getaddr(const char *, int);
585
void	in_getprefix(const char *, int);
586
void	in6_fillscopeid(struct sockaddr_in6 *sin6);
587
void	in6_alias(struct in6_ifreq *);
588
void	in6_status(int);
589
void	in6_getaddr(const char *, int);
590
void	in6_getprefix(const char *, int);
591
void	ieee80211_status(void);
592
void	ieee80211_listchans(void);
593
void	ieee80211_listnodes(void);
594
void	ieee80211_printnode(struct ieee80211_nodereq *);
595
u_int	getwpacipher(const char *name);
596
void	print_cipherset(u_int32_t cipherset);
597
598
void	spppauthinfo(struct sauthreq *spa, int d);
599
600
/* Known address families */
601
const struct afswtch {
602
	char *af_name;
603
	short af_af;
604
	void (*af_status)(int);
605
	void (*af_getaddr)(const char *, int);
606
	void (*af_getprefix)(const char *, int);
607
	u_long af_difaddr;
608
	u_long af_aifaddr;
609
	caddr_t af_ridreq;
610
	caddr_t af_addreq;
611
} afs[] = {
612
#define C(x) ((caddr_t) &x)
613
	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
614
	    SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) },
615
	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
616
	    SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
617
	{ 0,	0,	    0,		0 }
618
};
619
620
const struct afswtch *afp;	/*the address family being set or asked about*/
621
622
int ifaliases = 0;
623
int aflag = 0;
624
625
int
626
main(int argc, char *argv[])
627
{
628
	const struct afswtch *rafp = NULL;
629
	int create = 0;
630
	int Cflag = 0;
631
	int gflag = 0;
632
	int i;
633
634
	/* If no args at all, print all interfaces.  */
635
4992
	if (argc < 2) {
636
110
		aflag = 1;
637
110
		printif(NULL, 0);
638
110
		return (0);
639
	}
640
2386
	argc--, argv++;
641
2386
	if (*argv[0] == '-') {
642
		int nomore = 0;
643
644
		for (i = 1; argv[0][i]; i++) {
645
			switch (argv[0][i]) {
646
			case 'a':
647
				aflag = 1;
648
				nomore = 1;
649
				break;
650
			case 'A':
651
				aflag = 1;
652
				ifaliases = 1;
653
				nomore = 1;
654
				break;
655
			case 'g':
656
				gflag = 1;
657
				break;
658
			case 'C':
659
				Cflag = 1;
660
				nomore = 1;
661
				break;
662
			default:
663
				usage();
664
				break;
665
			}
666
		}
667
		if (nomore == 0) {
668
			argc--, argv++;
669
			if (argc < 1)
670
				usage();
671
			if (strlcpy(name, *argv, sizeof(name)) >= IFNAMSIZ)
672
				errx(1, "interface name '%s' too long", *argv);
673
		}
674
2386
	} else if (strlcpy(name, *argv, sizeof(name)) >= IFNAMSIZ)
675
		errx(1, "interface name '%s' too long", *argv);
676
2386
	argc--, argv++;
677
2386
	if (argc > 0) {
678
11644
		for (afp = rafp = afs; rafp->af_name; rafp++)
679
3950
			if (strcmp(rafp->af_name, *argv) == 0) {
680
122
				afp = rafp;
681
122
				argc--;
682
122
				argv++;
683
122
				break;
684
			}
685
1994
		rafp = afp;
686
1994
		af = ifr.ifr_addr.sa_family = rafp->af_af;
687
1994
	}
688
2386
	if (Cflag) {
689
		if (argc > 0 || aflag)
690
			usage();
691
		list_cloners();
692
		return (0);
693
	}
694
2386
	if (gflag) {
695
		if (argc == 0)
696
			printgroupattribs(name);
697
		else
698
			setgroupattribs(name, argc, argv);
699
		return (0);
700
	}
701
2386
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
702
703
	/* initialization */
704
2386
	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
705
2386
	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
706
707
	/*
708
	 * NOTE:  We must special-case the `create' command right
709
	 * here as we would otherwise fail in getinfo().
710
	 */
711

4380
	if (argc > 0 && strcmp(argv[0], "create") == 0) {
712
37
		clone_create(argv[0], 0);
713
37
		argc--, argv++;
714
37
		if (argc == 0)
715
37
			return (0);
716
	}
717
2349
	if (aflag == 0) {
718
6655
		create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
719
2349
		(void)getinfo(&ifr, create);
720
2349
	}
721
722
2349
	if (argc != 0 && af == AF_INET6)
723
84
		addaf(name, AF_INET6);
724
725
12342
	while (argc > 0) {
726
		const struct cmd *p;
727
728
820164
		for (p = cmds; p->c_name; p++)
729
409163
			if (strcmp(*argv, p->c_name) == 0)
730
				break;
731
#ifndef SMALL
732
3834
		if (strcmp(*argv, "rule") == 0) {
733
			argc--, argv++;
734
			return bridge_rule(argc, argv, -1);
735
		}
736
#endif
737
3834
		if (p->c_name == 0 && setaddr)
738
			for (i = setaddr; i > 0; i--) {
739
				p++;
740
				if (p->c_func == NULL)
741
					errx(1, "%s: bad value", *argv);
742
			}
743

3834
		if (p->c_func || p->c_func2) {
744
3834
			if (p->c_parameter == NEXTARG0) {
745
				const struct cmd *p0;
746
				int noarg = 1;
747
748
				if (argv[1]) {
749
					for (p0 = cmds; p0->c_name; p0++)
750
						if (strcmp(argv[1],
751
						    p0->c_name) == 0) {
752
							noarg = 0;
753
							break;
754
						}
755
				} else
756
					noarg = 0;
757
758
				if (noarg == 0)
759
					(*p->c_func)(NULL, 0);
760
				else
761
					goto nextarg;
762
3834
			} else if (p->c_parameter == NEXTARG) {
763
nextarg:
764
1036
				if (argv[1] == NULL)
765
					errx(1, "'%s' requires argument",
766
					    p->c_name);
767
1036
				(*p->c_func)(argv[1], 0);
768
1036
				argc--, argv++;
769
1036
				actions = actions | A_SILENT | p->c_action;
770
3834
			} else if (p->c_parameter == NEXTARG2) {
771
				if ((argv[1] == NULL) ||
772
				    (argv[2] == NULL))
773
					errx(1, "'%s' requires 2 arguments",
774
					    p->c_name);
775
				(*p->c_func2)(argv[1], argv[2]);
776
				argc -= 2;
777
				argv += 2;
778
				actions = actions | A_SILENT | p->c_action;
779
			} else {
780
2798
				(*p->c_func)(*argv, p->c_parameter);
781
2798
				actions = actions | A_SILENT | p->c_action;
782
			}
783
		}
784
3822
		argc--, argv++;
785
3822
	}
786
787
2337
	if (argc == 0 && actions == 0) {
788
392
		printif(ifr.ifr_name, aflag ? ifaliases : 1);
789
392
		return (0);
790
	}
791
792
	/* Process any media commands that may have been issued. */
793
1945
	process_media_commands();
794
795
#ifndef SMALL
796
	/* Process mpw commands */
797
1945
	process_mpw_commands();
798
#endif
799
800
1945
	if (af == AF_INET6 && explicit_prefix == 0) {
801
		/*
802
		 * Aggregatable address architecture defines all prefixes
803
		 * are 64. So, it is convenient to set prefixlen to 64 if
804
		 * it is not specified. If we are setting a destination
805
		 * address on a point-to-point interface, 128 is required.
806
		 */
807

48
		if (setipdst && (flags & IFF_POINTOPOINT))
808
			setifprefixlen("128", 0);
809
		else
810
48
			setifprefixlen("64", 0);
811
		/* in6_getprefix("64", MASK) if MASK is available here... */
812
	}
813
814
1945
	if (clearaddr) {
815
901
		(void) strlcpy(rafp->af_ridreq, name, sizeof(ifr.ifr_name));
816
901
		if (ioctl(s, rafp->af_difaddr, rafp->af_ridreq) < 0) {
817
898
			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
818
				/* means no previous address for interface */
819
			} else
820
				err(1, "SIOCDIFADDR");
821
		}
822
	}
823
1945
	if (newaddr) {
824
919
		(void) strlcpy(rafp->af_addreq, name, sizeof(ifr.ifr_name));
825
919
		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
826
			err(1, "SIOCAIFADDR");
827
	}
828
1945
	return (0);
829
2444
}
830
831
void
832
getsock(int naf)
833
{
834
	static int oaf = -1;
835
836
9620
	if (oaf == naf)
837
		return;
838
2988
	if (oaf != -1)
839
492
		close(s);
840
2988
	s = socket(naf, SOCK_DGRAM, 0);
841
2988
	if (s < 0)
842
		oaf = -1;
843
	else
844
		oaf = naf;
845
7798
}
846
847
int
848
getinfo(struct ifreq *ifr, int create)
849
{
850
851
7246
	getsock(af);
852
3623
	if (s < 0)
853
		err(1, "socket");
854
3623
	if (!isdigit((unsigned char)name[strlen(name) - 1]))
855
		return (-1);	/* ignore groups here */
856
3623
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
857
920
		int oerrno = errno;
858
859
920
		if (!create)
860
52
			return (-1);
861
868
		if (ioctl(s, SIOCIFCREATE, (caddr_t)ifr) < 0) {
862
			errno = oerrno;
863
			return (-1);
864
		}
865
868
		if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0)
866
			return (-1);
867
868
	}
868
3571
	flags = ifr->ifr_flags & 0xffff;
869
3571
	if (ioctl(s, SIOCGIFXFLAGS, (caddr_t)ifr) < 0)
870
		ifr->ifr_flags = 0;
871
3571
	xflags = ifr->ifr_flags;
872
3571
	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0)
873
		metric = 0;
874
	else
875
3571
		metric = ifr->ifr_metric;
876
#ifdef SMALL
877
	if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
878
#else
879

7142
	if (is_bridge(name) || ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
880
#endif
881
		mtu = 0;
882
	else
883
3571
		mtu = ifr->ifr_mtu;
884
#ifndef SMALL
885
3571
	if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)ifr) < 0)
886
		rdomainid = 0;
887
	else
888
3571
		rdomainid = ifr->ifr_rdomainid;
889
#endif
890
3571
	if (ioctl(s, SIOCGIFLLPRIO, (caddr_t)ifr) < 0)
891
		llprio = 0;
892
	else
893
3571
		llprio = ifr->ifr_llprio;
894
895
3571
	return (0);
896
3623
}
897
898
int
899
printgroup(char *groupname, int ifaliases)
900
{
901
	struct ifgroupreq	 ifgr;
902
	struct ifg_req		*ifg;
903
	int			 len, cnt = 0;
904
905
	getsock(AF_INET);
906
	bzero(&ifgr, sizeof(ifgr));
907
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
908
	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
909
		if (errno == EINVAL || errno == ENOTTY ||
910
		    errno == ENOENT)
911
			return (-1);
912
		else
913
			err(1, "SIOCGIFGMEMB");
914
	}
915
916
	len = ifgr.ifgr_len;
917
	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
918
		err(1, "printgroup");
919
	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
920
		err(1, "SIOCGIFGMEMB");
921
922
	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
923
	    ifg++) {
924
		len -= sizeof(struct ifg_req);
925
		printif(ifg->ifgrq_member, ifaliases);
926
		cnt++;
927
	}
928
	free(ifgr.ifgr_groups);
929
930
	return (cnt);
931
}
932
933
void
934
printgroupattribs(char *groupname)
935
{
936
	struct ifgroupreq	 ifgr;
937
938
	getsock(AF_INET);
939
	bzero(&ifgr, sizeof(ifgr));
940
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
941
	if (ioctl(s, SIOCGIFGATTR, (caddr_t)&ifgr) == -1)
942
		err(1, "SIOCGIFGATTR");
943
944
	printf("%s:", groupname);
945
	printf(" carp demote count %d", ifgr.ifgr_attrib.ifg_carp_demoted);
946
	printf("\n");
947
}
948
949
void
950
setgroupattribs(char *groupname, int argc, char *argv[])
951
{
952
	const char *errstr;
953
	char *p = argv[0];
954
	int neg = 1;
955
956
	struct ifgroupreq	 ifgr;
957
958
	getsock(AF_INET);
959
	bzero(&ifgr, sizeof(ifgr));
960
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
961
962
	if (argc > 1) {
963
		neg = strtonum(argv[1], 0, 128, &errstr);
964
		if (errstr)
965
			errx(1, "invalid carp demotion: %s", errstr);
966
	}
967
968
	if (p[0] == '-') {
969
		neg = neg * -1;
970
		p++;
971
	}
972
	if (!strcmp(p, "carpdemote"))
973
		ifgr.ifgr_attrib.ifg_carp_demoted = neg;
974
	else
975
		usage();
976
977
	if (ioctl(s, SIOCSIFGATTR, (caddr_t)&ifgr) == -1)
978
		err(1, "SIOCSIFGATTR");
979
}
980
981
void
982
printif(char *ifname, int ifaliases)
983
{
984
1004
	struct ifaddrs *ifap, *ifa;
985
	struct if_data *ifdata;
986
	const char *namep;
987
	char *oname = NULL;
988
	struct ifreq *ifrp;
989
	int count = 0, noinet = 1;
990
	size_t nlen = 0;
991
992
502
	if (aflag)
993
110
		ifname = NULL;
994
502
	if (ifname) {
995
392
		if ((oname = strdup(ifname)) == NULL)
996
			err(1, "strdup");
997
392
		nlen = strlen(oname);
998
		/* is it a group? */
999

784
		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
1000
			if (printgroup(oname, ifaliases) != -1) {
1001
				free(oname);
1002
				return;
1003
			}
1004
	}
1005
1006
502
	if (getifaddrs(&ifap) != 0)
1007
		err(1, "getifaddrs");
1008
1009
	namep = NULL;
1010
16712
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1011
7854
		if (oname) {
1012

12332
			if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
1013
				/* must have exact match */
1014
6166
				if (strcmp(oname, ifa->ifa_name) != 0)
1015
					continue;
1016
			} else {
1017
				/* partial match OK if it ends w/ digit */
1018
				if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
1019
				    !isdigit((unsigned char)ifa->ifa_name[nlen]))
1020
					continue;
1021
			}
1022
		}
1023
		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
1024
2424
		if (ifa->ifa_addr->sa_family == AF_INET6) {
1025
504
			memset(&ifr6, 0, sizeof(ifr6));
1026
1008
			memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
1027
1512
			    MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
1028
			ifrp = (struct ifreq *)&ifr6;
1029
504
		} else {
1030
1920
			memset(&ifr, 0, sizeof(ifr));
1031
3840
			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
1032
4486
			    MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
1033
			ifrp = &ifr;
1034
		}
1035
2424
		strlcpy(name, ifa->ifa_name, sizeof(name));
1036
2424
		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
1037
1038
2424
		if (ifa->ifa_addr->sa_family == AF_LINK) {
1039
1274
			namep = ifa->ifa_name;
1040
1274
			if (getinfo(ifrp, 0) < 0)
1041
				continue;
1042
1274
			ifdata = ifa->ifa_data;
1043
2548
			status(1, (struct sockaddr_dl *)ifa->ifa_addr,
1044
1274
			    ifdata->ifi_link_state);
1045
1274
			count++;
1046
			noinet = 1;
1047
1274
			continue;
1048
		}
1049
1050

2300
		if (!namep || !strcmp(namep, ifa->ifa_name)) {
1051
			const struct afswtch *p;
1052
1053
3450
			if (ifa->ifa_addr->sa_family == AF_INET &&
1054
2300
			    ifaliases == 0 && noinet == 0)
1055
				continue;
1056
1150
			if ((p = afp) != NULL) {
1057
				if (ifa->ifa_addr->sa_family == p->af_af)
1058
					p->af_status(1);
1059
			} else {
1060
6900
				for (p = afs; p->af_name; p++) {
1061
4600
					if (ifa->ifa_addr->sa_family ==
1062
2300
					    p->af_af)
1063
1150
						p->af_status(0);
1064
				}
1065
			}
1066
1150
			count++;
1067
1150
			if (ifa->ifa_addr->sa_family == AF_INET)
1068
646
				noinet = 0;
1069
1150
			continue;
1070
		}
1071
	}
1072
502
	freeifaddrs(ifap);
1073
502
	free(oname);
1074
502
	if (count == 0) {
1075
		fprintf(stderr, "%s: no such interface\n", name);
1076
		exit(1);
1077
	}
1078
924
}
1079
1080
/*ARGSUSED*/
1081
void
1082
clone_create(const char *addr, int param)
1083
{
1084
1085
	/* We're called early... */
1086
74
	getsock(AF_INET);
1087
1088
37
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1089
37
	if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
1090
		err(1, "SIOCIFCREATE");
1091
37
}
1092
1093
/*ARGSUSED*/
1094
void
1095
clone_destroy(const char *addr, int param)
1096
{
1097
1098
1832
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1099
916
	if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
1100
		err(1, "SIOCIFDESTROY");
1101
904
}
1102
1103
void
1104
list_cloners(void)
1105
{
1106
	struct if_clonereq ifcr;
1107
	char *cp, *buf;
1108
	int idx;
1109
1110
	memset(&ifcr, 0, sizeof(ifcr));
1111
1112
	getsock(AF_INET);
1113
1114
	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
1115
		err(1, "SIOCIFGCLONERS for count");
1116
1117
	buf = calloc(ifcr.ifcr_total, IFNAMSIZ);
1118
	if (buf == NULL)
1119
		err(1, "unable to allocate cloner name buffer");
1120
1121
	ifcr.ifcr_count = ifcr.ifcr_total;
1122
	ifcr.ifcr_buffer = buf;
1123
1124
	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
1125
		err(1, "SIOCIFGCLONERS for names");
1126
1127
	/*
1128
	 * In case some disappeared in the mean time, clamp it down.
1129
	 */
1130
	if (ifcr.ifcr_count > ifcr.ifcr_total)
1131
		ifcr.ifcr_count = ifcr.ifcr_total;
1132
1133
	qsort(buf, ifcr.ifcr_count, IFNAMSIZ,
1134
	    (int(*)(const void *, const void *))strcmp);
1135
1136
	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
1137
		if (idx > 0)
1138
			putchar(' ');
1139
		printf("%s", cp);
1140
	}
1141
1142
	putchar('\n');
1143
	free(buf);
1144
}
1145
1146
#define RIDADDR 0
1147
#define ADDR	1
1148
#define MASK	2
1149
#define DSTADDR	3
1150
1151
/*ARGSUSED*/
1152
void
1153
setifaddr(const char *addr, int param)
1154
{
1155
	/*
1156
	 * Delay the ioctl to set the interface addr until flags are all set.
1157
	 * The address interpretation may depend on the flags,
1158
	 * and the flags may change when the address is set.
1159
	 */
1160
1838
	setaddr++;
1161
919
	if (doalias >= 0)
1162
919
		newaddr = 1;
1163
919
	if (doalias == 0)
1164
901
		clearaddr = 1;
1165
919
	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
1166
919
}
1167
1168
#ifndef SMALL
1169
void
1170
setifrtlabel(const char *label, int d)
1171
{
1172
	if (d != 0)
1173
		ifr.ifr_data = (caddr_t)(const char *)"";
1174
	else
1175
		ifr.ifr_data = (caddr_t)label;
1176
	if (ioctl(s, SIOCSIFRTLABEL, &ifr) < 0)
1177
		warn("SIOCSIFRTLABEL");
1178
}
1179
#endif
1180
1181
/* ARGSUSED */
1182
void
1183
setifnetmask(const char *addr, int ignored)
1184
{
1185
48
	afp->af_getaddr(addr, MASK);
1186
24
}
1187
1188
/* ARGSUSED */
1189
void
1190
setifbroadaddr(const char *addr, int ignored)
1191
{
1192
40
	afp->af_getaddr(addr, DSTADDR);
1193
20
}
1194
1195
#ifndef SMALL
1196
/* ARGSUSED */
1197
void
1198
setifdesc(const char *val, int ignored)
1199
{
1200
	ifr.ifr_data = (caddr_t)val;
1201
	if (ioctl(s, SIOCSIFDESCR, &ifr) < 0)
1202
		warn("SIOCSIFDESCR");
1203
}
1204
1205
/* ARGSUSED */
1206
void
1207
unsetifdesc(const char *noval, int ignored)
1208
{
1209
	ifr.ifr_data = (caddr_t)(const char *)"";
1210
	if (ioctl(s, SIOCSIFDESCR, &ifr) < 0)
1211
		warn("SIOCSIFDESCR");
1212
}
1213
1214
/* ARGSUSED */
1215
void
1216
setifipdst(const char *addr, int ignored)
1217
{
1218
	in_getaddr(addr, DSTADDR);
1219
	setipdst++;
1220
	clearaddr = 0;
1221
	newaddr = 0;
1222
}
1223
#endif
1224
1225
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1226
/*ARGSUSED*/
1227
void
1228
notealias(const char *addr, int param)
1229
{
1230
36
	if (setaddr && doalias == 0 && param < 0)
1231
		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1232
		    rqtosa(af_addreq)->sa_len);
1233
18
	doalias = param;
1234
18
	if (param < 0) {
1235
		clearaddr = 1;
1236
		newaddr = 0;
1237
	} else
1238
		clearaddr = 0;
1239
18
}
1240
1241
/*ARGSUSED*/
1242
void
1243
setifdstaddr(const char *addr, int param)
1244
{
1245
	setaddr++;
1246
	setipdst++;
1247
	afp->af_getaddr(addr, DSTADDR);
1248
}
1249
1250
/*
1251
 * Note: doing an SIOCGIFFLAGS scribbles on the union portion
1252
 * of the ifreq structure, which may confuse other parts of ifconfig.
1253
 * Make a private copy so we can avoid that.
1254
 */
1255
/* ARGSUSED */
1256
void
1257
setifflags(const char *vname, int value)
1258
{
1259
1794
	struct ifreq my_ifr;
1260
1261
897
	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1262
1263
897
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0)
1264
		err(1, "SIOCGIFFLAGS");
1265
897
	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
1266
897
	flags = my_ifr.ifr_flags;
1267
1268
897
	if (value < 0) {
1269
38
		value = -value;
1270
38
		flags &= ~value;
1271
38
	} else
1272
859
		flags |= value;
1273
897
	my_ifr.ifr_flags = flags;
1274
897
	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
1275
		err(1, "SIOCSIFFLAGS");
1276
897
}
1277
1278
/* ARGSUSED */
1279
void
1280
setifxflags(const char *vname, int value)
1281
{
1282
24
	struct ifreq my_ifr;
1283
1284
12
	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1285
1286
12
	if (ioctl(s, SIOCGIFXFLAGS, (caddr_t)&my_ifr) < 0)
1287
		warn("SIOCGIFXFLAGS");
1288
12
	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
1289
12
	xflags = my_ifr.ifr_flags;
1290
1291
12
	if (value < 0) {
1292
		value = -value;
1293
		xflags &= ~value;
1294
	} else
1295
12
		xflags |= value;
1296
12
	my_ifr.ifr_flags = xflags;
1297
12
	if (ioctl(s, SIOCSIFXFLAGS, (caddr_t)&my_ifr) < 0)
1298
		warn("SIOCSIFXFLAGS");
1299
12
}
1300
1301
void
1302
addaf(const char *vname, int value)
1303
{
1304
240
	struct if_afreq	ifar;
1305
1306
120
	strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1307
120
	ifar.ifar_af = value;
1308
120
	if (ioctl(s, SIOCIFAFATTACH, (caddr_t)&ifar) < 0)
1309
		warn("SIOCIFAFATTACH");
1310
120
}
1311
1312
void
1313
removeaf(const char *vname, int value)
1314
{
1315
	struct if_afreq	ifar;
1316
1317
	strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1318
	ifar.ifar_af = value;
1319
	if (ioctl(s, SIOCIFAFDETACH, (caddr_t)&ifar) < 0)
1320
		warn("SIOCIFAFDETACH");
1321
}
1322
1323
void
1324
setia6flags(const char *vname, int value)
1325
{
1326
1327
	if (value < 0) {
1328
		value = -value;
1329
		in6_addreq.ifra_flags &= ~value;
1330
	} else
1331
		in6_addreq.ifra_flags |= value;
1332
}
1333
1334
void
1335
setia6pltime(const char *val, int d)
1336
{
1337
1338
	setia6lifetime("pltime", val);
1339
}
1340
1341
void
1342
setia6vltime(const char *val, int d)
1343
{
1344
1345
	setia6lifetime("vltime", val);
1346
}
1347
1348
void
1349
setia6lifetime(const char *cmd, const char *val)
1350
{
1351
	const char *errmsg = NULL;
1352
	time_t newval, t;
1353
1354
	newval = strtonum(val, 0, 1000000, &errmsg);
1355
	if (errmsg)
1356
		errx(1, "invalid %s %s: %s", cmd, val, errmsg);
1357
1358
	t = time(NULL);
1359
1360
	if (afp->af_af != AF_INET6)
1361
		errx(1, "%s not allowed for the AF", cmd);
1362
	if (strcmp(cmd, "vltime") == 0) {
1363
		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1364
		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1365
	} else if (strcmp(cmd, "pltime") == 0) {
1366
		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1367
		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1368
	}
1369
}
1370
1371
void
1372
setia6eui64(const char *cmd, int val)
1373
{
1374
72
	struct ifaddrs *ifap, *ifa;
1375
	const struct sockaddr_in6 *sin6 = NULL;
1376
	const struct in6_addr *lladdr = NULL;
1377
	struct in6_addr *in6;
1378
1379
36
	if (afp->af_af != AF_INET6)
1380
		errx(1, "%s not allowed for the AF", cmd);
1381
1382
36
	addaf(name, AF_INET6);
1383
1384
	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1385
36
	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1386
		errx(1, "interface index is already filled");
1387
36
	if (getifaddrs(&ifap) != 0)
1388
		err(1, "getifaddrs");
1389
1146
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1390

705
		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1391
132
		    strcmp(ifa->ifa_name, name) == 0) {
1392
48
			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1393

84
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1394
				lladdr = &sin6->sin6_addr;
1395
36
				break;
1396
			}
1397
		}
1398
	}
1399
36
	if (!lladdr)
1400
		errx(1, "could not determine link local address");
1401
1402
36
	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1403
1404
36
	freeifaddrs(ifap);
1405
36
}
1406
1407
void
1408
setautoconf(const char *cmd, int val)
1409
{
1410
24
	switch (afp->af_af) {
1411
	case AF_INET6:
1412
12
		setifxflags("inet6", val * IFXF_AUTOCONF6);
1413
		break;
1414
	default:
1415
		errx(1, "autoconf not allowed for this AF");
1416
	}
1417
12
}
1418
1419
#ifndef SMALL
1420
/* ARGSUSED */
1421
void
1422
setifmetric(const char *val, int ignored)
1423
{
1424
	const char *errmsg = NULL;
1425
1426
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1427
1428
	ifr.ifr_metric = strtonum(val, 0, INT_MAX, &errmsg);
1429
	if (errmsg)
1430
		errx(1, "metric %s: %s", val, errmsg);
1431
	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
1432
		warn("SIOCSIFMETRIC");
1433
}
1434
#endif
1435
1436
/* ARGSUSED */
1437
void
1438
setifmtu(const char *val, int d)
1439
{
1440
	const char *errmsg = NULL;
1441
1442
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1443
1444
	ifr.ifr_mtu = strtonum(val, 0, INT_MAX, &errmsg);
1445
	if (errmsg)
1446
		errx(1, "mtu %s: %s", val, errmsg);
1447
	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
1448
		warn("SIOCSIFMTU");
1449
}
1450
1451
/* ARGSUSED */
1452
void
1453
setifllprio(const char *val, int d)
1454
{
1455
	const char *errmsg = NULL;
1456
1457
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1458
1459
	ifr.ifr_llprio = strtonum(val, 0, UCHAR_MAX, &errmsg);
1460
	if (errmsg)
1461
		errx(1, "llprio %s: %s", val, errmsg);
1462
	if (ioctl(s, SIOCSIFLLPRIO, (caddr_t)&ifr) < 0)
1463
		warn("SIOCSIFLLPRIO");
1464
}
1465
1466
/* ARGSUSED */
1467
void
1468
setifgroup(const char *group_name, int dummy)
1469
{
1470
	struct ifgroupreq ifgr;
1471
1472
	memset(&ifgr, 0, sizeof(ifgr));
1473
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
1474
1475
	if (group_name[0] &&
1476
	    isdigit((unsigned char)group_name[strlen(group_name) - 1]))
1477
		errx(1, "setifgroup: group names may not end in a digit");
1478
1479
	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1480
		errx(1, "setifgroup: group name too long");
1481
	if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1) {
1482
		if (errno != EEXIST)
1483
			err(1," SIOCAIFGROUP");
1484
	}
1485
}
1486
1487
/* ARGSUSED */
1488
void
1489
unsetifgroup(const char *group_name, int dummy)
1490
{
1491
	struct ifgroupreq ifgr;
1492
1493
	memset(&ifgr, 0, sizeof(ifgr));
1494
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
1495
1496
	if (group_name[0] &&
1497
	    isdigit((unsigned char)group_name[strlen(group_name) - 1]))
1498
		errx(1, "unsetifgroup: group names may not end in a digit");
1499
1500
	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1501
		errx(1, "unsetifgroup: group name too long");
1502
	if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
1503
		err(1, "SIOCDIFGROUP");
1504
}
1505
1506
const char *
1507
get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1508
{
1509
	int len = *lenp, hexstr;
1510
	u_int8_t *p = buf;
1511
1512
	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1513
	if (hexstr)
1514
		val += 2;
1515
	for (;;) {
1516
		if (*val == '\0')
1517
			break;
1518
		if (sep != NULL && strchr(sep, *val) != NULL) {
1519
			val++;
1520
			break;
1521
		}
1522
		if (hexstr) {
1523
			if (!isxdigit((u_char)val[0]) ||
1524
			    !isxdigit((u_char)val[1])) {
1525
				warnx("bad hexadecimal digits");
1526
				return NULL;
1527
			}
1528
		}
1529
		if (p > buf + len) {
1530
			if (hexstr)
1531
				warnx("hexadecimal digits too long");
1532
			else
1533
				warnx("strings too long");
1534
			return NULL;
1535
		}
1536
		if (hexstr) {
1537
#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1538
			*p++ = (tohex((u_char)val[0]) << 4) |
1539
			    tohex((u_char)val[1]);
1540
#undef tohex
1541
			val += 2;
1542
		} else {
1543
			if (*val == '\\' &&
1544
			    sep != NULL && strchr(sep, *(val + 1)) != NULL)
1545
				val++;
1546
			*p++ = *val++;
1547
		}
1548
	}
1549
	len = p - buf;
1550
	if (len < *lenp)
1551
		memset(p, 0, *lenp - len);
1552
	*lenp = len;
1553
	return val;
1554
}
1555
1556
void
1557
print_string(const u_int8_t *buf, int len)
1558
{
1559
	int i = 0, hasspc = 0;
1560
1561
	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1562
		for (; i < len; i++) {
1563
			/* Only print 7-bit ASCII keys */
1564
			if (buf[i] & 0x80 || !isprint(buf[i]))
1565
				break;
1566
			if (isspace(buf[i]))
1567
				hasspc++;
1568
		}
1569
	}
1570
	if (i == len) {
1571
		if (hasspc || len == 0)
1572
			printf("\"%.*s\"", len, buf);
1573
		else
1574
			printf("%.*s", len, buf);
1575
	} else {
1576
		printf("0x");
1577
		for (i = 0; i < len; i++)
1578
			printf("%02x", buf[i]);
1579
	}
1580
}
1581
1582
void
1583
setifnwid(const char *val, int d)
1584
{
1585
	struct ieee80211_nwid nwid;
1586
	int len;
1587
1588
	if (d != 0) {
1589
		/* no network id is especially desired */
1590
		memset(&nwid, 0, sizeof(nwid));
1591
		len = 0;
1592
	} else {
1593
		len = sizeof(nwid.i_nwid);
1594
		if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1595
			return;
1596
	}
1597
	nwid.i_len = len;
1598
	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1599
	ifr.ifr_data = (caddr_t)&nwid;
1600
	if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
1601
		warn("SIOCS80211NWID");
1602
}
1603
1604
void
1605
setifbssid(const char *val, int d)
1606
{
1607
1608
	struct ieee80211_bssid bssid;
1609
	struct ether_addr *ea;
1610
1611
	if (d != 0) {
1612
		/* no BSSID is especially desired */
1613
		memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1614
	} else {
1615
		ea = ether_aton((char*)val);
1616
		if (ea == NULL) {
1617
			warnx("malformed BSSID: %s", val);
1618
			return;
1619
		}
1620
		memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1621
		    sizeof(bssid.i_bssid));
1622
	}
1623
	strlcpy(bssid.i_name, name, sizeof(bssid.i_name));
1624
	if (ioctl(s, SIOCS80211BSSID, &bssid) == -1)
1625
		warn("SIOCS80211BSSID");
1626
}
1627
1628
void
1629
setifnwkey(const char *val, int d)
1630
{
1631
	int i, len;
1632
	struct ieee80211_nwkey nwkey;
1633
	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1634
1635
	bzero(&nwkey, sizeof(nwkey));
1636
	bzero(&keybuf, sizeof(keybuf));
1637
1638
	nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1639
	nwkey.i_defkid = 1;
1640
	if (d == -1) {
1641
		/* disable WEP encryption */
1642
		nwkey.i_wepon = IEEE80211_NWKEY_OPEN;
1643
		i = 0;
1644
	} else if (strcasecmp("persist", val) == 0) {
1645
		/* use all values from persistent memory */
1646
		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1647
		nwkey.i_defkid = 0;
1648
		for (i = 0; i < IEEE80211_WEP_NKID; i++)
1649
			nwkey.i_key[i].i_keylen = -1;
1650
	} else if (strncasecmp("persist:", val, 8) == 0) {
1651
		val += 8;
1652
		/* program keys in persistent memory */
1653
		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1654
		goto set_nwkey;
1655
	} else {
1656
 set_nwkey:
1657
		if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1658
			/* specifying a full set of four keys */
1659
			nwkey.i_defkid = val[0] - '0';
1660
			val += 2;
1661
			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1662
				len = sizeof(keybuf[i]);
1663
				val = get_string(val, ",", keybuf[i], &len);
1664
				if (val == NULL)
1665
					return;
1666
				nwkey.i_key[i].i_keylen = len;
1667
				nwkey.i_key[i].i_keydat = keybuf[i];
1668
			}
1669
			if (*val != '\0') {
1670
				warnx("SIOCS80211NWKEY: too many keys.");
1671
				return;
1672
			}
1673
		} else {
1674
			/*
1675
			 * length of each key must be either a 5
1676
			 * character ASCII string or 10 hex digits for
1677
			 * 40 bit encryption, or 13 character ASCII
1678
			 * string or 26 hex digits for 128 bit
1679
			 * encryption.
1680
			 */
1681
			int j;
1682
			char *tmp = NULL;
1683
			size_t vlen = strlen(val);
1684
			switch(vlen) {
1685
			case 10:
1686
			case 26:
1687
				/* 0x must be missing for these lengths */
1688
				j = asprintf(&tmp, "0x%s", val);
1689
				if (j == -1) {
1690
					warnx("malloc failed");
1691
					return;
1692
				}
1693
				val = tmp;
1694
				break;
1695
			case 12:
1696
			case 28:
1697
			case 5:
1698
			case 13:
1699
				/* 0xkey or string case - all is ok */
1700
				break;
1701
			default:
1702
				warnx("Invalid WEP key length");
1703
				return;
1704
			}
1705
			len = sizeof(keybuf[0]);
1706
			val = get_string(val, NULL, keybuf[0], &len);
1707
			free(tmp);
1708
			if (val == NULL)
1709
				return;
1710
			nwkey.i_key[0].i_keylen = len;
1711
			nwkey.i_key[0].i_keydat = keybuf[0];
1712
			i = 1;
1713
		}
1714
	}
1715
	(void)strlcpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1716
	if (ioctl(s, SIOCS80211NWKEY, (caddr_t)&nwkey) == -1)
1717
		warn("SIOCS80211NWKEY");
1718
}
1719
1720
/* ARGSUSED */
1721
void
1722
setifwpa(const char *val, int d)
1723
{
1724
	struct ieee80211_wpaparams wpa;
1725
1726
	memset(&wpa, 0, sizeof(wpa));
1727
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1728
	/* Don't read current values. The kernel will set defaults. */
1729
	wpa.i_enabled = d;
1730
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1731
		err(1, "SIOCS80211WPAPARMS");
1732
}
1733
1734
/* ARGSUSED */
1735
void
1736
setifwpaprotos(const char *val, int d)
1737
{
1738
	struct ieee80211_wpaparams wpa;
1739
	char *optlist, *str;
1740
	u_int rval = 0;
1741
1742
	if ((optlist = strdup(val)) == NULL)
1743
		err(1, "strdup");
1744
	str = strtok(optlist, ",");
1745
	while (str != NULL) {
1746
		if (strcasecmp(str, "wpa1") == 0)
1747
			rval |= IEEE80211_WPA_PROTO_WPA1;
1748
		else if (strcasecmp(str, "wpa2") == 0)
1749
			rval |= IEEE80211_WPA_PROTO_WPA2;
1750
		else
1751
			errx(1, "wpaprotos: unknown protocol: %s", str);
1752
		str = strtok(NULL, ",");
1753
	}
1754
	free(optlist);
1755
1756
	memset(&wpa, 0, sizeof(wpa));
1757
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1758
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1759
		err(1, "SIOCG80211WPAPARMS");
1760
	wpa.i_protos = rval;
1761
	/* Let the kernel set up the appropriate default ciphers. */
1762
	wpa.i_ciphers = 0;
1763
	wpa.i_groupcipher = 0;
1764
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1765
		err(1, "SIOCS80211WPAPARMS");
1766
}
1767
1768
/* ARGSUSED */
1769
void
1770
setifwpaakms(const char *val, int d)
1771
{
1772
	struct ieee80211_wpaparams wpa;
1773
	char *optlist, *str;
1774
	u_int rval = 0;
1775
1776
	if ((optlist = strdup(val)) == NULL)
1777
		err(1, "strdup");
1778
	str = strtok(optlist, ",");
1779
	while (str != NULL) {
1780
		if (strcasecmp(str, "psk") == 0)
1781
			rval |= IEEE80211_WPA_AKM_PSK;
1782
		else if (strcasecmp(str, "802.1x") == 0)
1783
			rval |= IEEE80211_WPA_AKM_8021X;
1784
		else
1785
			errx(1, "wpaakms: unknown akm: %s", str);
1786
		str = strtok(NULL, ",");
1787
	}
1788
	free(optlist);
1789
1790
	memset(&wpa, 0, sizeof(wpa));
1791
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1792
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1793
		err(1, "SIOCG80211WPAPARMS");
1794
	wpa.i_akms = rval;
1795
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1796
		err(1, "SIOCS80211WPAPARMS");
1797
}
1798
1799
static const struct {
1800
	const char	*name;
1801
	u_int		cipher;
1802
} ciphers[] = {
1803
	{ "usegroup",	IEEE80211_WPA_CIPHER_USEGROUP },
1804
	{ "wep40",	IEEE80211_WPA_CIPHER_WEP40 },
1805
	{ "tkip",	IEEE80211_WPA_CIPHER_TKIP },
1806
	{ "ccmp",	IEEE80211_WPA_CIPHER_CCMP },
1807
	{ "wep104",	IEEE80211_WPA_CIPHER_WEP104 }
1808
};
1809
1810
u_int
1811
getwpacipher(const char *name)
1812
{
1813
	int i;
1814
1815
	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++)
1816
		if (strcasecmp(name, ciphers[i].name) == 0)
1817
			return ciphers[i].cipher;
1818
	return IEEE80211_WPA_CIPHER_NONE;
1819
}
1820
1821
/* ARGSUSED */
1822
void
1823
setifwpaciphers(const char *val, int d)
1824
{
1825
	struct ieee80211_wpaparams wpa;
1826
	char *optlist, *str;
1827
	u_int rval = 0;
1828
1829
	if ((optlist = strdup(val)) == NULL)
1830
		err(1, "strdup");
1831
	str = strtok(optlist, ",");
1832
	while (str != NULL) {
1833
		u_int cipher = getwpacipher(str);
1834
		if (cipher == IEEE80211_WPA_CIPHER_NONE)
1835
			errx(1, "wpaciphers: unknown cipher: %s", str);
1836
1837
		rval |= cipher;
1838
		str = strtok(NULL, ",");
1839
	}
1840
	free(optlist);
1841
1842
	memset(&wpa, 0, sizeof(wpa));
1843
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1844
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1845
		err(1, "SIOCG80211WPAPARMS");
1846
	wpa.i_ciphers = rval;
1847
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1848
		err(1, "SIOCS80211WPAPARMS");
1849
}
1850
1851
/* ARGSUSED */
1852
void
1853
setifwpagroupcipher(const char *val, int d)
1854
{
1855
	struct ieee80211_wpaparams wpa;
1856
	u_int cipher;
1857
1858
	cipher = getwpacipher(val);
1859
	if (cipher == IEEE80211_WPA_CIPHER_NONE)
1860
		errx(1, "wpagroupcipher: unknown cipher: %s", val);
1861
1862
	memset(&wpa, 0, sizeof(wpa));
1863
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1864
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1865
		err(1, "SIOCG80211WPAPARMS");
1866
	wpa.i_groupcipher = cipher;
1867
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1868
		err(1, "SIOCS80211WPAPARMS");
1869
}
1870
1871
void
1872
setifwpakey(const char *val, int d)
1873
{
1874
	struct ieee80211_wpaparams wpa;
1875
	struct ieee80211_wpapsk psk;
1876
	struct ieee80211_nwid nwid;
1877
	int passlen;
1878
1879
	memset(&psk, 0, sizeof(psk));
1880
	if (d != -1) {
1881
		memset(&ifr, 0, sizeof(ifr));
1882
		ifr.ifr_data = (caddr_t)&nwid;
1883
		strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1884
		if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr))
1885
			err(1, "SIOCG80211NWID");
1886
1887
		passlen = strlen(val);
1888
		if (passlen == 2 + 2 * sizeof(psk.i_psk) &&
1889
		    val[0] == '0' && val[1] == 'x') {
1890
			/* Parse a WPA hex key (must be full-length) */
1891
			passlen = sizeof(psk.i_psk);
1892
			val = get_string(val, NULL, psk.i_psk, &passlen);
1893
			if (val == NULL || passlen != sizeof(psk.i_psk))
1894
				errx(1, "wpakey: invalid pre-shared key");
1895
		} else {
1896
			/* Parse a WPA passphrase */
1897
			if (passlen < 8 || passlen > 63)
1898
				errx(1, "wpakey: passphrase must be between "
1899
				    "8 and 63 characters");
1900
			if (nwid.i_len == 0)
1901
				errx(1, "wpakey: nwid not set");
1902
			if (pkcs5_pbkdf2(val, passlen, nwid.i_nwid, nwid.i_len,
1903
			    psk.i_psk, sizeof(psk.i_psk), 4096) != 0)
1904
				errx(1, "wpakey: passphrase hashing failed");
1905
		}
1906
		psk.i_enabled = 1;
1907
	} else
1908
		psk.i_enabled = 0;
1909
1910
	(void)strlcpy(psk.i_name, name, sizeof(psk.i_name));
1911
	if (ioctl(s, SIOCS80211WPAPSK, (caddr_t)&psk) < 0)
1912
		err(1, "SIOCS80211WPAPSK");
1913
1914
	/* And ... automatically enable or disable WPA */
1915
	memset(&wpa, 0, sizeof(wpa));
1916
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1917
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1918
		err(1, "SIOCG80211WPAPARMS");
1919
	wpa.i_enabled = psk.i_enabled;
1920
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1921
		err(1, "SIOCS80211WPAPARMS");
1922
}
1923
1924
void
1925
setifchan(const char *val, int d)
1926
{
1927
	struct ieee80211chanreq channel;
1928
	const char *errstr;
1929
	int chan;
1930
1931
	if (val == NULL) {
1932
		if (shownet80211chans || shownet80211nodes)
1933
			usage();
1934
		shownet80211chans = 1;
1935
		return;
1936
	}
1937
	if (d != 0)
1938
		chan = IEEE80211_CHAN_ANY;
1939
	else {
1940
		chan = strtonum(val, 1, 256, &errstr);
1941
		if (errstr) {
1942
			warnx("invalid channel %s: %s", val, errstr);
1943
			return;
1944
		}
1945
	}
1946
1947
	strlcpy(channel.i_name, name, sizeof(channel.i_name));
1948
	channel.i_channel = (u_int16_t)chan;
1949
	if (ioctl(s, SIOCS80211CHANNEL, (caddr_t)&channel) == -1)
1950
		warn("SIOCS80211CHANNEL");
1951
}
1952
1953
/* ARGSUSED */
1954
void
1955
setifscan(const char *val, int d)
1956
{
1957
	if (shownet80211chans || shownet80211nodes)
1958
		usage();
1959
	shownet80211nodes = 1;
1960
}
1961
1962
#ifndef SMALL
1963
1964
void
1965
setifnwflag(const char *val, int d)
1966
{
1967
	static const struct ieee80211_flags nwflags[] = IEEE80211_FLAGS;
1968
	u_int i, flag = 0;
1969
1970
	for (i = 0; i < (sizeof(nwflags) / sizeof(nwflags[0])); i++) {
1971
		if (strcmp(val, nwflags[i].f_name) == 0) {
1972
			flag = nwflags[i].f_flag;
1973
			break;
1974
		}
1975
	}
1976
	if (flag == 0)
1977
		errx(1, "Invalid nwflag: %s", val);
1978
1979
	if (ioctl(s, SIOCG80211FLAGS, (caddr_t)&ifr) != 0)
1980
		err(1, "SIOCG80211FLAGS");
1981
1982
	if (d)
1983
		ifr.ifr_flags &= ~flag;
1984
	else
1985
		ifr.ifr_flags |= flag;
1986
1987
	if (ioctl(s, SIOCS80211FLAGS, (caddr_t)&ifr) != 0)
1988
		err(1, "SIOCS80211FLAGS");
1989
}
1990
1991
void
1992
unsetifnwflag(const char *val, int d)
1993
{
1994
	setifnwflag(val, 1);
1995
}
1996
1997
/* ARGSUSED */
1998
void
1999
setifpowersave(const char *val, int d)
2000
{
2001
	struct ieee80211_power power;
2002
	const char *errmsg = NULL;
2003
2004
	(void)strlcpy(power.i_name, name, sizeof(power.i_name));
2005
	if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) == -1) {
2006
		warn("SIOCG80211POWER");
2007
		return;
2008
	}
2009
2010
	if (d != -1 && val != NULL) {
2011
		power.i_maxsleep = strtonum(val, 0, INT_MAX, &errmsg);
2012
		if (errmsg)
2013
			errx(1, "powersave %s: %s", val, errmsg);
2014
	}
2015
2016
	power.i_enabled = d == -1 ? 0 : 1;
2017
	if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) == -1)
2018
		warn("SIOCS80211POWER");
2019
}
2020
#endif
2021
2022
void
2023
print_cipherset(u_int32_t cipherset)
2024
{
2025
	const char *sep = "";
2026
	int i;
2027
2028
	if (cipherset == IEEE80211_WPA_CIPHER_NONE) {
2029
		printf("none");
2030
		return;
2031
	}
2032
	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++) {
2033
		if (cipherset & ciphers[i].cipher) {
2034
			printf("%s%s", sep, ciphers[i].name);
2035
			sep = ",";
2036
		}
2037
	}
2038
}
2039
2040
void
2041
ieee80211_status(void)
2042
{
2043
	int len, i, nwkey_verbose, inwid, inwkey, ipsk, ichan, ipwr;
2044
	int ibssid, iwpa;
2045
692
	struct ieee80211_nwid nwid;
2046
346
	struct ieee80211_nwkey nwkey;
2047
346
	struct ieee80211_wpapsk psk;
2048
346
	struct ieee80211_power power;
2049
346
	struct ieee80211chanreq channel;
2050
346
	struct ieee80211_bssid bssid;
2051
346
	struct ieee80211_wpaparams wpa;
2052
346
	struct ieee80211_nodereq nr;
2053
346
	u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
2054
346
	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
2055
346
	struct ether_addr ea;
2056
2057
	/* get current status via ioctls */
2058
346
	memset(&ifr, 0, sizeof(ifr));
2059
346
	ifr.ifr_data = (caddr_t)&nwid;
2060
346
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2061
346
	inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
2062
2063
346
	memset(&nwkey, 0, sizeof(nwkey));
2064
346
	strlcpy(nwkey.i_name, name, sizeof(nwkey.i_name));
2065
346
	inwkey = ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey);
2066
2067
346
	memset(&psk, 0, sizeof(psk));
2068
346
	strlcpy(psk.i_name, name, sizeof(psk.i_name));
2069
346
	ipsk = ioctl(s, SIOCG80211WPAPSK, (caddr_t)&psk);
2070
2071
346
	memset(&power, 0, sizeof(power));
2072
346
	strlcpy(power.i_name, name, sizeof(power.i_name));
2073
346
	ipwr = ioctl(s, SIOCG80211POWER, &power);
2074
2075
346
	memset(&channel, 0, sizeof(channel));
2076
346
	strlcpy(channel.i_name, name, sizeof(channel.i_name));
2077
346
	ichan = ioctl(s, SIOCG80211CHANNEL, (caddr_t)&channel);
2078
2079
346
	memset(&bssid, 0, sizeof(bssid));
2080
346
	strlcpy(bssid.i_name, name, sizeof(bssid.i_name));
2081
346
	ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
2082
2083
346
	memset(&wpa, 0, sizeof(wpa));
2084
346
	strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
2085
346
	iwpa = ioctl(s, SIOCG80211WPAPARMS, &wpa);
2086
2087
	/* check if any ieee80211 option is active */
2088
1384
	if (inwid == 0 || inwkey == 0 || ipsk == 0 || ipwr == 0 ||
2089
1038
	    ichan == 0 || ibssid == 0 || iwpa == 0)
2090
		fputs("\tieee80211:", stdout);
2091
	else
2092
346
		return;
2093
2094
	if (inwid == 0) {
2095
		/* nwid.i_nwid is not NUL terminated. */
2096
		len = nwid.i_len;
2097
		if (len > IEEE80211_NWID_LEN)
2098
			len = IEEE80211_NWID_LEN;
2099
		fputs(" nwid ", stdout);
2100
		print_string(nwid.i_nwid, len);
2101
	}
2102
2103
	if (ichan == 0 && channel.i_channel != 0 &&
2104
	    channel.i_channel != IEEE80211_CHAN_ANY)
2105
		printf(" chan %u", channel.i_channel);
2106
2107
	memset(&zero_bssid, 0, sizeof(zero_bssid));
2108
	if (ibssid == 0 &&
2109
	    memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
2110
		memcpy(&ea.ether_addr_octet, bssid.i_bssid,
2111
		    sizeof(ea.ether_addr_octet));
2112
		printf(" bssid %s", ether_ntoa(&ea));
2113
2114
		bzero(&nr, sizeof(nr));
2115
		bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
2116
		strlcpy(nr.nr_ifname, name, sizeof(nr.nr_ifname));
2117
		if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
2118
			if (nr.nr_max_rssi)
2119
				printf(" %u%%", IEEE80211_NODEREQ_RSSI(&nr));
2120
			else
2121
				printf(" %ddBm", nr.nr_rssi);
2122
		}
2123
	}
2124
2125
	if (inwkey == 0 && nwkey.i_wepon > IEEE80211_NWKEY_OPEN) {
2126
		fputs(" nwkey ", stdout);
2127
		/* try to retrieve WEP keys */
2128
		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2129
			nwkey.i_key[i].i_keydat = keybuf[i];
2130
			nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
2131
		}
2132
		if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) == -1) {
2133
			fputs("<not displayed>", stdout);
2134
		} else {
2135
			nwkey_verbose = 0;
2136
			/*
2137
			 * check to see non default key
2138
			 * or multiple keys defined
2139
			 */
2140
			if (nwkey.i_defkid != 1) {
2141
				nwkey_verbose = 1;
2142
			} else {
2143
				for (i = 1; i < IEEE80211_WEP_NKID; i++) {
2144
					if (nwkey.i_key[i].i_keylen != 0) {
2145
						nwkey_verbose = 1;
2146
						break;
2147
					}
2148
				}
2149
			}
2150
			/* check extra ambiguity with keywords */
2151
			if (!nwkey_verbose) {
2152
				if (nwkey.i_key[0].i_keylen >= 2 &&
2153
				    isdigit((unsigned char)nwkey.i_key[0].i_keydat[0]) &&
2154
				    nwkey.i_key[0].i_keydat[1] == ':')
2155
					nwkey_verbose = 1;
2156
				else if (nwkey.i_key[0].i_keylen >= 7 &&
2157
				    strncasecmp("persist",
2158
				    (char *)nwkey.i_key[0].i_keydat, 7) == 0)
2159
					nwkey_verbose = 1;
2160
			}
2161
			if (nwkey_verbose)
2162
				printf("%d:", nwkey.i_defkid);
2163
			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2164
				if (i > 0)
2165
					putchar(',');
2166
				if (nwkey.i_key[i].i_keylen < 0) {
2167
					fputs("persist", stdout);
2168
				} else {
2169
					/*
2170
					 * XXX
2171
					 * sanity check nwkey.i_key[i].i_keylen
2172
					 */
2173
					print_string(nwkey.i_key[i].i_keydat,
2174
					    nwkey.i_key[i].i_keylen);
2175
				}
2176
				if (!nwkey_verbose)
2177
					break;
2178
			}
2179
		}
2180
	}
2181
2182
	if (ipsk == 0 && psk.i_enabled) {
2183
		fputs(" wpakey ", stdout);
2184
		if (psk.i_enabled == 2)
2185
			fputs("<not displayed>", stdout);
2186
		else
2187
			print_string(psk.i_psk, sizeof(psk.i_psk));
2188
	}
2189
	if (iwpa == 0 && wpa.i_enabled) {
2190
		const char *sep;
2191
2192
		fputs(" wpaprotos ", stdout); sep = "";
2193
		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1) {
2194
			fputs("wpa1", stdout);
2195
			sep = ",";
2196
		}
2197
		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
2198
			printf("%swpa2", sep);
2199
2200
		fputs(" wpaakms ", stdout); sep = "";
2201
		if (wpa.i_akms & IEEE80211_WPA_AKM_PSK) {
2202
			fputs("psk", stdout);
2203
			sep = ",";
2204
		}
2205
		if (wpa.i_akms & IEEE80211_WPA_AKM_8021X)
2206
			printf("%s802.1x", sep);
2207
2208
		fputs(" wpaciphers ", stdout);
2209
		print_cipherset(wpa.i_ciphers);
2210
2211
		fputs(" wpagroupcipher ", stdout);
2212
		print_cipherset(wpa.i_groupcipher);
2213
	}
2214
2215
	if (ipwr == 0 && power.i_enabled)
2216
		printf(" powersave on (%dms sleep)", power.i_maxsleep);
2217
2218
	if (ioctl(s, SIOCG80211FLAGS, (caddr_t)&ifr) == 0 &&
2219
	    ifr.ifr_flags) {
2220
		putchar(' ');
2221
		printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
2222
	}
2223
2224
	putchar('\n');
2225
	if (shownet80211chans)
2226
		ieee80211_listchans();
2227
	else if (shownet80211nodes)
2228
		ieee80211_listnodes();
2229
346
}
2230
2231
void
2232
ieee80211_listchans(void)
2233
{
2234
	static struct ieee80211_channel chans[256+1];
2235
	struct ieee80211_chanreq_all ca;
2236
	int i;
2237
2238
	bzero(&ca, sizeof(ca));
2239
	bzero(chans, sizeof(chans));
2240
	ca.i_chans = chans;
2241
	strlcpy(ca.i_name, name, sizeof(ca.i_name));
2242
2243
	if (ioctl(s, SIOCG80211ALLCHANS, &ca) != 0) {
2244
		warn("SIOCG80211ALLCHANS");
2245
		return;
2246
	}
2247
	printf("\t\t%4s  %-8s  %s\n", "chan", "freq", "properties");
2248
	for (i = 1; i <= 256; i++) {
2249
		if (chans[i].ic_flags == 0)
2250
			continue;
2251
		printf("\t\t%4d  %4d MHz  ", i, chans[i].ic_freq);
2252
		if (chans[i].ic_flags & IEEE80211_CHAN_PASSIVE)
2253
			printf("passive scan");
2254
		else
2255
			putchar('-');
2256
		putchar('\n');
2257
	}
2258
}
2259
2260
/*
2261
 * Returns an integer less than, equal to, or greater than zero if nr1's
2262
 * RSSI is respectively greater than, equal to, or less than nr2's RSSI.
2263
 */
2264
static int
2265
rssicmp(const void *nr1, const void *nr2)
2266
{
2267
	const struct ieee80211_nodereq *x = nr1, *y = nr2;
2268
	return y->nr_rssi < x->nr_rssi ? -1 : y->nr_rssi > x->nr_rssi;
2269
}
2270
2271
void
2272
ieee80211_listnodes(void)
2273
{
2274
	struct ieee80211_nodereq_all na;
2275
	struct ieee80211_nodereq nr[512];
2276
	struct ifreq ifr;
2277
	int i, down = 0;
2278
2279
	if ((flags & IFF_UP) == 0) {
2280
		down = 1;
2281
		setifflags("up", IFF_UP);
2282
	}
2283
2284
	bzero(&ifr, sizeof(ifr));
2285
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2286
2287
	if (ioctl(s, SIOCS80211SCAN, (caddr_t)&ifr) != 0) {
2288
		if (errno == EPERM)
2289
			printf("\t\tno permission to scan\n");
2290
		goto done;
2291
	}
2292
2293
	bzero(&na, sizeof(na));
2294
	bzero(&nr, sizeof(nr));
2295
	na.na_node = nr;
2296
	na.na_size = sizeof(nr);
2297
	strlcpy(na.na_ifname, name, sizeof(na.na_ifname));
2298
2299
	if (ioctl(s, SIOCG80211ALLNODES, &na) != 0) {
2300
		warn("SIOCG80211ALLNODES");
2301
		goto done;
2302
	}
2303
2304
	if (!na.na_nodes)
2305
		printf("\t\tnone\n");
2306
	else
2307
		qsort(nr, na.na_nodes, sizeof(*nr), rssicmp);
2308
2309
	for (i = 0; i < na.na_nodes; i++) {
2310
		printf("\t\t");
2311
		ieee80211_printnode(&nr[i]);
2312
		putchar('\n');
2313
	}
2314
2315
 done:
2316
	if (down)
2317
		setifflags("restore", -IFF_UP);
2318
}
2319
2320
void
2321
ieee80211_printnode(struct ieee80211_nodereq *nr)
2322
{
2323
	int len, i;
2324
2325
	if (nr->nr_flags & IEEE80211_NODEREQ_AP ||
2326
	    nr->nr_capinfo & IEEE80211_CAPINFO_IBSS) {
2327
		len = nr->nr_nwid_len;
2328
		if (len > IEEE80211_NWID_LEN)
2329
			len = IEEE80211_NWID_LEN;
2330
		printf("nwid ");
2331
		print_string(nr->nr_nwid, len);
2332
		putchar(' ');
2333
2334
		printf("chan %u ", nr->nr_channel);
2335
2336
		printf("bssid %s ",
2337
		    ether_ntoa((struct ether_addr*)nr->nr_bssid));
2338
	}
2339
2340
	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2341
		printf("lladdr %s ",
2342
		    ether_ntoa((struct ether_addr*)nr->nr_macaddr));
2343
2344
	if (nr->nr_max_rssi)
2345
		printf("%u%% ", IEEE80211_NODEREQ_RSSI(nr));
2346
	else
2347
		printf("%ddBm ", nr->nr_rssi);
2348
2349
	if (nr->nr_pwrsave)
2350
		printf("powersave ");
2351
	/*
2352
	 * Print our current Tx rate for associated nodes.
2353
	 * Print the fastest supported rate for APs.
2354
	 */
2355
	if ((nr->nr_flags & (IEEE80211_NODEREQ_AP)) == 0) {
2356
		if (nr->nr_flags & IEEE80211_NODEREQ_HT) {
2357
			printf("HT-MCS%d ", nr->nr_txmcs);
2358
		} else if (nr->nr_nrates) {
2359
			printf("%uM ",
2360
			    (nr->nr_rates[nr->nr_txrate] & IEEE80211_RATE_VAL)
2361
			    / 2);
2362
		}
2363
	} else if (nr->nr_max_rxrate) {
2364
		printf("%uM HT ", nr->nr_max_rxrate);
2365
	} else if (nr->nr_rxmcs[0] != 0) {
2366
		for (i = IEEE80211_HT_NUM_MCS - 1; i >= 0; i--) {
2367
			if (nr->nr_rxmcs[i / 8] & (1 << (i / 10)))
2368
				break;
2369
		}
2370
		printf("HT-MCS%d ", i);
2371
	} else if (nr->nr_nrates) {
2372
		printf("%uM ",
2373
		    (nr->nr_rates[nr->nr_nrates - 1] & IEEE80211_RATE_VAL) / 2);
2374
	}
2375
	/* ESS is the default, skip it */
2376
	nr->nr_capinfo &= ~IEEE80211_CAPINFO_ESS;
2377
	if (nr->nr_capinfo) {
2378
		printb_status(nr->nr_capinfo, IEEE80211_CAPINFO_BITS);
2379
		if (nr->nr_capinfo & IEEE80211_CAPINFO_PRIVACY) {
2380
			if (nr->nr_rsnprotos) {
2381
				if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA2)
2382
					fputs(",wpa2", stdout);
2383
				if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA1)
2384
					fputs(",wpa1", stdout);
2385
			} else
2386
				fputs(",wep", stdout);
2387
2388
			if (nr->nr_rsnakms & IEEE80211_WPA_AKM_8021X ||
2389
			    nr->nr_rsnakms & IEEE80211_WPA_AKM_SHA256_8021X)
2390
				fputs(",802.1x", stdout);
2391
		}
2392
		putchar(' ');
2393
	}
2394
2395
	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2396
		printb_status(IEEE80211_NODEREQ_STATE(nr->nr_state),
2397
		    IEEE80211_NODEREQ_STATE_BITS);
2398
}
2399
2400
void
2401
init_current_media(void)
2402
{
2403
	struct ifmediareq ifmr;
2404
2405
	/*
2406
	 * If we have not yet done so, grab the currently-selected
2407
	 * media.
2408
	 */
2409
	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2410
		(void) memset(&ifmr, 0, sizeof(ifmr));
2411
		(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
2412
2413
		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
2414
			/*
2415
			 * If we get E2BIG, the kernel is telling us
2416
			 * that there are more, so we can ignore it.
2417
			 */
2418
			if (errno != E2BIG)
2419
				err(1, "SIOCGIFMEDIA");
2420
		}
2421
2422
		media_current = ifmr.ifm_current;
2423
	}
2424
2425
	/* Sanity. */
2426
	if (IFM_TYPE(media_current) == 0)
2427
		errx(1, "%s: no link type?", name);
2428
}
2429
2430
void
2431
process_media_commands(void)
2432
{
2433
2434
3890
	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2435
		/* Nothing to do. */
2436
		return;
2437
	}
2438
2439
	/*
2440
	 * Media already set up, and commands sanity-checked.  Set/clear
2441
	 * any options, and we're ready to go.
2442
	 */
2443
	media_current |= mediaopt_set;
2444
	media_current &= ~mediaopt_clear;
2445
2446
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2447
	ifr.ifr_media = media_current;
2448
2449
	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
2450
		err(1, "SIOCSIFMEDIA");
2451
1945
}
2452
2453
/* ARGSUSED */
2454
void
2455
setmedia(const char *val, int d)
2456
{
2457
	uint64_t type, subtype, inst;
2458
2459
	if (val == NULL) {
2460
		if (showmediaflag)
2461
			usage();
2462
		showmediaflag = 1;
2463
		return;
2464
	}
2465
2466
	init_current_media();
2467
2468
	/* Only one media command may be given. */
2469
	if (actions & A_MEDIA)
2470
		errx(1, "only one `media' command may be issued");
2471
2472
	/* Must not come after mode commands */
2473
	if (actions & A_MEDIAMODE)
2474
		errx(1, "may not issue `media' after `mode' commands");
2475
2476
	/* Must not come after mediaopt commands */
2477
	if (actions & A_MEDIAOPT)
2478
		errx(1, "may not issue `media' after `mediaopt' commands");
2479
2480
	/*
2481
	 * No need to check if `instance' has been issued; setmediainst()
2482
	 * craps out if `media' has not been specified.
2483
	 */
2484
2485
	type = IFM_TYPE(media_current);
2486
	inst = IFM_INST(media_current);
2487
2488
	/* Look up the subtype. */
2489
	subtype = get_media_subtype(type, val);
2490
2491
	/* Build the new current media word. */
2492
	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
2493
2494
	/* Media will be set after other processing is complete. */
2495
}
2496
2497
/* ARGSUSED */
2498
void
2499
setmediamode(const char *val, int d)
2500
{
2501
	uint64_t type, subtype, options, inst, mode;
2502
2503
	init_current_media();
2504
2505
	/* Can only issue `mode' once. */
2506
	if (actions & A_MEDIAMODE)
2507
		errx(1, "only one `mode' command may be issued");
2508
2509
	type = IFM_TYPE(media_current);
2510
	subtype = IFM_SUBTYPE(media_current);
2511
	options = IFM_OPTIONS(media_current);
2512
	inst = IFM_INST(media_current);
2513
2514
	if ((mode = get_media_mode(type, val)) == -1)
2515
		errx(1, "invalid media mode: %s", val);
2516
	media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
2517
	/* Media will be set after other processing is complete. */
2518
}
2519
2520
void
2521
unsetmediamode(const char *val, int d)
2522
{
2523
	uint64_t type, subtype, options, inst;
2524
2525
	init_current_media();
2526
2527
	/* Can only issue `mode' once. */
2528
	if (actions & A_MEDIAMODE)
2529
		errx(1, "only one `mode' command may be issued");
2530
2531
	type = IFM_TYPE(media_current);
2532
	subtype = IFM_SUBTYPE(media_current);
2533
	options = IFM_OPTIONS(media_current);
2534
	inst = IFM_INST(media_current);
2535
2536
	media_current = IFM_MAKEWORD(type, subtype, options, inst) |
2537
	    (IFM_AUTO << IFM_MSHIFT);
2538
	/* Media will be set after other processing is complete. */
2539
}
2540
2541
void
2542
setmediaopt(const char *val, int d)
2543
{
2544
2545
	init_current_media();
2546
2547
	/* Can only issue `mediaopt' once. */
2548
	if (actions & A_MEDIAOPTSET)
2549
		errx(1, "only one `mediaopt' command may be issued");
2550
2551
	/* Can't issue `mediaopt' if `instance' has already been issued. */
2552
	if (actions & A_MEDIAINST)
2553
		errx(1, "may not issue `mediaopt' after `instance'");
2554
2555
	mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
2556
2557
	/* Media will be set after other processing is complete. */
2558
}
2559
2560
/* ARGSUSED */
2561
void
2562
unsetmediaopt(const char *val, int d)
2563
{
2564
2565
	init_current_media();
2566
2567
	/* Can only issue `-mediaopt' once. */
2568
	if (actions & A_MEDIAOPTCLR)
2569
		errx(1, "only one `-mediaopt' command may be issued");
2570
2571
	/* May not issue `media' and `-mediaopt'. */
2572
	if (actions & A_MEDIA)
2573
		errx(1, "may not issue both `media' and `-mediaopt'");
2574
2575
	/*
2576
	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
2577
	 * implicitly checks for A_MEDIAINST.
2578
	 */
2579
2580
	mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
2581
2582
	/* Media will be set after other processing is complete. */
2583
}
2584
2585
/* ARGSUSED */
2586
void
2587
setmediainst(const char *val, int d)
2588
{
2589
	uint64_t type, subtype, options, inst;
2590
	const char *errmsg = NULL;
2591
2592
	init_current_media();
2593
2594
	/* Can only issue `instance' once. */
2595
	if (actions & A_MEDIAINST)
2596
		errx(1, "only one `instance' command may be issued");
2597
2598
	/* Must have already specified `media' */
2599
	if ((actions & A_MEDIA) == 0)
2600
		errx(1, "must specify `media' before `instance'");
2601
2602
	type = IFM_TYPE(media_current);
2603
	subtype = IFM_SUBTYPE(media_current);
2604
	options = IFM_OPTIONS(media_current);
2605
2606
	inst = strtonum(val, 0, IFM_INST_MAX, &errmsg);
2607
	if (errmsg)
2608
		errx(1, "media instance %s: %s", val, errmsg);
2609
2610
	media_current = IFM_MAKEWORD(type, subtype, options, inst);
2611
2612
	/* Media will be set after other processing is complete. */
2613
}
2614
2615
2616
const struct ifmedia_description ifm_type_descriptions[] =
2617
    IFM_TYPE_DESCRIPTIONS;
2618
2619
const struct ifmedia_description ifm_subtype_descriptions[] =
2620
    IFM_SUBTYPE_DESCRIPTIONS;
2621
2622
struct ifmedia_description ifm_mode_descriptions[] =
2623
    IFM_MODE_DESCRIPTIONS;
2624
2625
const struct ifmedia_description ifm_option_descriptions[] =
2626
    IFM_OPTION_DESCRIPTIONS;
2627
2628
const char *
2629
get_media_type_string(uint64_t mword)
2630
{
2631
	const struct ifmedia_description *desc;
2632
2633
1038
	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
2634
	    desc++) {
2635
346
		if (IFM_TYPE(mword) == desc->ifmt_word)
2636
346
			return (desc->ifmt_string);
2637
	}
2638
	return ("<unknown type>");
2639
346
}
2640
2641
const char *
2642
get_media_subtype_string(uint64_t mword)
2643
{
2644
	const struct ifmedia_description *desc;
2645
2646
12888
	for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
2647
5700
	    desc++) {
2648

17642
		if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
2649
6196
		    IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
2650
496
			return (desc->ifmt_string);
2651
	}
2652
	return ("<unknown subtype>");
2653
496
}
2654
2655
uint64_t
2656
get_media_subtype(uint64_t type, const char *val)
2657
{
2658
	uint64_t rval;
2659
2660
	rval = lookup_media_word(ifm_subtype_descriptions, type, val);
2661
	if (rval == -1)
2662
		errx(1, "unknown %s media subtype: %s",
2663
		    get_media_type_string(type), val);
2664
2665
	return (rval);
2666
}
2667
2668
uint64_t
2669
get_media_mode(uint64_t type, const char *val)
2670
{
2671
	uint64_t rval;
2672
2673
	rval = lookup_media_word(ifm_mode_descriptions, type, val);
2674
	if (rval == -1)
2675
		errx(1, "unknown %s media mode: %s",
2676
		    get_media_type_string(type), val);
2677
	return (rval);
2678
}
2679
2680
uint64_t
2681
get_media_options(uint64_t type, const char *val)
2682
{
2683
	char *optlist, *str;
2684
	uint64_t option, rval = 0;
2685
2686
	/* We muck with the string, so copy it. */
2687
	optlist = strdup(val);
2688
	if (optlist == NULL)
2689
		err(1, "strdup");
2690
	str = optlist;
2691
2692
	/*
2693
	 * Look up the options in the user-provided comma-separated list.
2694
	 */
2695
	for (; (str = strtok(str, ",")) != NULL; str = NULL) {
2696
		option = lookup_media_word(ifm_option_descriptions, type, str);
2697
		if (option == -1)
2698
			errx(1, "unknown %s media option: %s",
2699
			    get_media_type_string(type), str);
2700
		rval |= IFM_OPTIONS(option);
2701
	}
2702
2703
	free(optlist);
2704
	return (rval);
2705
}
2706
2707
uint64_t
2708
lookup_media_word(const struct ifmedia_description *desc, uint64_t type,
2709
    const char *val)
2710
{
2711
2712
	for (; desc->ifmt_string != NULL; desc++) {
2713
		if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
2714
		    strcasecmp(desc->ifmt_string, val) == 0)
2715
			return (desc->ifmt_word);
2716
	}
2717
	return (-1);
2718
}
2719
2720
void
2721
print_media_word(uint64_t ifmw, int print_type, int as_syntax)
2722
{
2723
	const struct ifmedia_description *desc;
2724
	uint64_t seen_option = 0;
2725
2726
992
	if (print_type)
2727
346
		printf("%s ", get_media_type_string(ifmw));
2728
992
	printf("%s%s", as_syntax ? "media " : "",
2729
496
	    get_media_subtype_string(ifmw));
2730
2731
	/* Find mode. */
2732
496
	if (IFM_MODE(ifmw) != 0) {
2733
		for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL;
2734
		    desc++) {
2735
			if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
2736
			    IFM_MODE(ifmw) == IFM_MODE(desc->ifmt_word)) {
2737
				printf(" mode %s", desc->ifmt_string);
2738
				break;
2739
			}
2740
		}
2741
	}
2742
2743
	/* Find options. */
2744
25792
	for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
2745
12400
	    desc++) {
2746

20140
		if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
2747
6448
		    (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
2748
300
		    (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
2749
150
			if (seen_option == 0)
2750
150
				printf(" %s", as_syntax ? "mediaopt " : "");
2751
300
			printf("%s%s", seen_option ? "," : "",
2752
150
			    desc->ifmt_string);
2753
150
			seen_option |= IFM_OPTIONS(desc->ifmt_word);
2754
150
		}
2755
	}
2756
496
	if (IFM_INST(ifmw) != 0)
2757
		printf(" instance %lld", IFM_INST(ifmw));
2758
496
}
2759
2760
/* ARGSUSED */
2761
static void
2762
phys_status(int force)
2763
{
2764
2548
	char psrcaddr[NI_MAXHOST];
2765
1274
	char pdstaddr[NI_MAXHOST];
2766
	const char *ver = "";
2767
	const int niflag = NI_NUMERICHOST;
2768
1274
	struct if_laddrreq req;
2769
	in_port_t dstport = 0;
2770
2771
1274
	psrcaddr[0] = pdstaddr[0] = '\0';
2772
2773
1274
	memset(&req, 0, sizeof(req));
2774
1274
	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
2775
1274
	if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0)
2776
1274
		return;
2777
	if (getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
2778
	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
2779
		strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
2780
	if (req.addr.ss_family == AF_INET6)
2781
		ver = "6";
2782
2783
	if (req.dstaddr.ss_family == AF_INET)
2784
		dstport = ((struct sockaddr_in *)&req.dstaddr)->sin_port;
2785
	else if (req.dstaddr.ss_family == AF_INET6)
2786
		dstport = ((struct sockaddr_in6 *)&req.dstaddr)->sin6_port;
2787
	if (getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
2788
	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag) != 0)
2789
		strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
2790
2791
	printf("\ttunnel: inet%s %s -> %s", ver,
2792
	    psrcaddr, pdstaddr);
2793
2794
	if (dstport)
2795
		printf(":%u", ntohs(dstport));
2796
	if (ioctl(s, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0 && ifr.ifr_ttl > 0)
2797
		printf(" ttl %d", ifr.ifr_ttl);
2798
#ifndef SMALL
2799
	if (ioctl(s, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
2800
	    (rdomainid != 0 || ifr.ifr_rdomainid != 0))
2801
		printf(" rdomain %d", ifr.ifr_rdomainid);
2802
#endif
2803
	printf("\n");
2804
1274
}
2805
2806
#ifndef SMALL
2807
const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
2808
2809
const struct ifmedia_status_description ifm_status_descriptions[] =
2810
	IFM_STATUS_DESCRIPTIONS;
2811
#endif
2812
2813
const struct if_status_description if_status_descriptions[] =
2814
	LINK_STATE_DESCRIPTIONS;
2815
2816
const char *
2817
get_linkstate(int mt, int link_state)
2818
{
2819
	const struct if_status_description *p;
2820
	static char buf[8];
2821
2822
3792
	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
2823

3642
		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
2824
340
			return (p->ifs_string);
2825
	}
2826
	snprintf(buf, sizeof(buf), "[#%d]", link_state);
2827
	return buf;
2828
340
}
2829
2830
/*
2831
 * Print the status of the interface.  If an address family was
2832
 * specified, show it and it only; otherwise, show them all.
2833
 */
2834
void
2835
status(int link, struct sockaddr_dl *sdl, int ls)
2836
{
2837
	const struct afswtch *p = afp;
2838
2548
	struct ifmediareq ifmr;
2839
#ifndef SMALL
2840
1274
	struct ifreq ifrdesc;
2841
1274
	struct ifkalivereq ikardesc;
2842
1274
	char ifdescr[IFDESCRSIZE];
2843
1274
	char ifname[IF_NAMESIZE];
2844
#endif
2845
	uint64_t *media_list;
2846
	int i;
2847
	char sep;
2848
2849
2850
1274
	printf("%s: ", name);
2851
1274
	printb("flags", flags | (xflags << 16), IFFBITS);
2852
1274
	if (rdomainid)
2853
444
		printf(" rdomain %d", rdomainid);
2854
1274
	if (metric)
2855
		printf(" metric %lu", metric);
2856
1274
	if (mtu)
2857
1124
		printf(" mtu %lu", mtu);
2858
2548
	putchar('\n');
2859
#ifndef SMALL
2860
1274
	if (showcapsflag)
2861
		printifhwfeatures(NULL, 1);
2862
#endif
2863

2620
	if (sdl != NULL && sdl->sdl_alen &&
2864
608
	    (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
2865
536
		(void)printf("\tlladdr %s\n", ether_ntoa(
2866
536
		    (struct ether_addr *)LLADDR(sdl)));
2867
2868
	sep = '\t';
2869
#ifndef SMALL
2870
1274
	(void) memset(&ifrdesc, 0, sizeof(ifrdesc));
2871
1274
	(void) strlcpy(ifrdesc.ifr_name, name, sizeof(ifrdesc.ifr_name));
2872
1274
	ifrdesc.ifr_data = (caddr_t)&ifdescr;
2873

2548
	if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0 &&
2874
1274
	    strlen(ifrdesc.ifr_data))
2875
		printf("\tdescription: %s\n", ifrdesc.ifr_data);
2876
2877
1274
	if (sdl != NULL) {
2878
1274
		printf("%cindex %u", sep, sdl->sdl_index);
2879
		sep = ' ';
2880
1274
	}
2881

2548
	if (!is_bridge(name) && ioctl(s, SIOCGIFPRIORITY, &ifrdesc) == 0) {
2882
1274
		printf("%cpriority %d", sep, ifrdesc.ifr_metric);
2883
		sep = ' ';
2884
1274
	}
2885
#endif
2886
1274
	printf("%cllprio %d\n", sep, llprio);
2887
2888
#ifndef SMALL
2889
1274
	(void) memset(&ikardesc, 0, sizeof(ikardesc));
2890
1274
	(void) strlcpy(ikardesc.ikar_name, name, sizeof(ikardesc.ikar_name));
2891

1274
	if (ioctl(s, SIOCGETKALIVE, &ikardesc) == 0 &&
2892
	    (ikardesc.ikar_timeo != 0 || ikardesc.ikar_cnt != 0))
2893
		printf("\tkeepalive: timeout %d count %d\n",
2894
		    ikardesc.ikar_timeo, ikardesc.ikar_cnt);
2895

1586
	if (ioctl(s, SIOCGIFPAIR, &ifrdesc) == 0 && ifrdesc.ifr_index != 0 &&
2896
156
	    if_indextoname(ifrdesc.ifr_index, ifname) != NULL)
2897
156
		printf("\tpatch: %s\n", ifname);
2898
#endif
2899
1274
	getencap();
2900
#ifndef SMALL
2901
1274
	carp_status();
2902
1274
	pfsync_status();
2903
1274
	pppoe_status();
2904
1274
	sppp_status();
2905
1274
	mpe_status();
2906
1274
	mpw_status();
2907
1274
	pflow_status();
2908
1274
	umb_status();
2909
#endif
2910
1274
	trunk_status();
2911
1274
	getifgroups();
2912
2913
1274
	(void) memset(&ifmr, 0, sizeof(ifmr));
2914
1274
	(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
2915
2916
1274
	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
2917
		/*
2918
		 * Interface doesn't support SIOC{G,S}IFMEDIA.
2919
		 */
2920
928
		if (ls != LINK_STATE_UNKNOWN)
2921
340
			printf("\tstatus: %s\n",
2922
340
			    get_linkstate(sdl->sdl_type, ls));
2923
		goto proto_status;
2924
	}
2925
2926
346
	if (ifmr.ifm_count == 0) {
2927
		warnx("%s: no media types?", name);
2928
		goto proto_status;
2929
	}
2930
2931
346
	media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
2932
346
	if (media_list == NULL)
2933
		err(1, "calloc");
2934
346
	ifmr.ifm_ulist = media_list;
2935
2936
346
	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
2937
		err(1, "SIOCGIFMEDIA");
2938
2939
346
	printf("\tmedia: ");
2940
346
	print_media_word(ifmr.ifm_current, 1, 0);
2941
346
	if (ifmr.ifm_active != ifmr.ifm_current) {
2942
300
		putchar(' ');
2943
300
		putchar('(');
2944
150
		print_media_word(ifmr.ifm_active, 0, 0);
2945
300
		putchar(')');
2946
	}
2947
692
	putchar('\n');
2948
2949
#ifdef SMALL
2950
	printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
2951
#else
2952
346
	if (ifmr.ifm_status & IFM_AVALID) {
2953
		const struct ifmedia_status_description *ifms;
2954
		int bitno, found = 0;
2955
2956
346
		printf("\tstatus: ");
2957
1384
		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
2958
692
			for (ifms = ifm_status_descriptions;
2959
346
			    ifms->ifms_valid != 0; ifms++) {
2960
1038
				if (ifms->ifms_type !=
2961
692
				    IFM_TYPE(ifmr.ifm_current) ||
2962
346
				    ifms->ifms_valid !=
2963
346
				    ifm_status_valid_list[bitno])
2964
					continue;
2965
692
				printf("%s%s", found ? ", " : "",
2966
346
				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
2967
				found = 1;
2968
2969
				/*
2970
				 * For each valid indicator bit, there's
2971
				 * only one entry for each media type, so
2972
				 * terminate the inner loop now.
2973
				 */
2974
346
				break;
2975
			}
2976
		}
2977
2978
346
		if (found == 0)
2979
			printf("unknown");
2980
692
		putchar('\n');
2981
346
	}
2982
#endif
2983
346
	ieee80211_status();
2984
2985
346
	if (showmediaflag) {
2986
		uint64_t type;
2987
		int printed_type = 0;
2988
2989
		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
2990
			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
2991
				if (IFM_TYPE(media_list[i]) == type) {
2992
2993
					/*
2994
					 * Don't advertise media with fixed
2995
					 * data rates for wireless interfaces.
2996
					 * Normal people don't need these.
2997
					 */
2998
					if (type == IFM_IEEE80211 &&
2999
					    (media_list[i] & IFM_TMASK) !=
3000
					    IFM_AUTO)
3001
						continue;
3002
3003
					if (printed_type == 0) {
3004
					    printf("\tsupported media:\n");
3005
					    printed_type = 1;
3006
					}
3007
					printf("\t\t");
3008
					print_media_word(media_list[i], 0, 1);
3009
					printf("\n");
3010
				}
3011
			}
3012
		}
3013
	}
3014
3015
346
	free(media_list);
3016
3017
 proto_status:
3018
1274
	if (link == 0) {
3019
		if ((p = afp) != NULL) {
3020
			p->af_status(1);
3021
		} else for (p = afs; p->af_name; p++) {
3022
			ifr.ifr_addr.sa_family = p->af_af;
3023
			p->af_status(0);
3024
		}
3025
	}
3026
3027
1274
	phys_status(0);
3028
#ifndef SMALL
3029
1274
	bridge_status();
3030
1274
	switch_status();
3031
#endif
3032
1274
}
3033
3034
/* ARGSUSED */
3035
void
3036
in_status(int force)
3037
{
3038
1292
	struct sockaddr_in *sin, sin2;
3039
3040
646
	getsock(AF_INET);
3041
646
	if (s < 0) {
3042
		if (errno == EPROTONOSUPPORT)
3043
			return;
3044
		err(1, "socket");
3045
	}
3046
646
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3047
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
3048
3049
	/*
3050
	 * We keep the interface address and reset it before each
3051
	 * ioctl() so we can get ifaliases information (as opposed
3052
	 * to the primary interface netmask/dstaddr/broadaddr, if
3053
	 * the ifr_addr field is zero).
3054
	 */
3055
646
	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
3056
3057
646
	printf("\tinet %s", inet_ntoa(sin->sin_addr));
3058
646
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3059
646
	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
3060
		if (errno != EADDRNOTAVAIL)
3061
			warn("SIOCGIFNETMASK");
3062
		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3063
	} else
3064
		netmask.sin_addr =
3065
646
		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
3066
646
	if (flags & IFF_POINTOPOINT) {
3067
		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3068
		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
3069
			if (errno == EADDRNOTAVAIL)
3070
			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3071
			else
3072
			    warn("SIOCGIFDSTADDR");
3073
		}
3074
		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3075
		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
3076
		printf(" --> %s", inet_ntoa(sin->sin_addr));
3077
	}
3078
646
	printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
3079
646
	if (flags & IFF_BROADCAST) {
3080
496
		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3081
496
		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
3082
			if (errno == EADDRNOTAVAIL)
3083
			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3084
			else
3085
			    warn("SIOCGIFBRDADDR");
3086
		}
3087
496
		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3088
		sin = (struct sockaddr_in *)&ifr.ifr_addr;
3089
496
		if (sin->sin_addr.s_addr != 0)
3090
496
			printf(" broadcast %s", inet_ntoa(sin->sin_addr));
3091
	}
3092
1292
	putchar('\n');
3093
1292
}
3094
3095
/* ARGSUSED */
3096
void
3097
setifprefixlen(const char *addr, int d)
3098
{
3099
96
	if (afp->af_getprefix)
3100
48
		afp->af_getprefix(addr, MASK);
3101
48
	explicit_prefix = 1;
3102
48
}
3103
3104
void
3105
in6_fillscopeid(struct sockaddr_in6 *sin6)
3106
{
3107
#ifdef __KAME__
3108

1314
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
3109
306
		sin6->sin6_scope_id =
3110
306
			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3111
306
		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
3112
306
	}
3113
#endif /* __KAME__ */
3114
504
}
3115
3116
/* XXX not really an alias */
3117
void
3118
in6_alias(struct in6_ifreq *creq)
3119
{
3120
	struct sockaddr_in6 *sin6;
3121
1008
	struct	in6_ifreq ifr6;		/* shadows file static variable */
3122
	u_int32_t scopeid;
3123
504
	char hbuf[NI_MAXHOST];
3124
	const int niflag = NI_NUMERICHOST;
3125
3126
	/* Get the non-alias address for this interface. */
3127
504
	getsock(AF_INET6);
3128
504
	if (s < 0) {
3129
		if (errno == EPROTONOSUPPORT)
3130
			return;
3131
		err(1, "socket");
3132
	}
3133
3134
504
	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
3135
3136
504
	in6_fillscopeid(sin6);
3137
504
	scopeid = sin6->sin6_scope_id;
3138
1512
	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3139
1008
	    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3140
		strlcpy(hbuf, "", sizeof hbuf);
3141
504
	printf("\tinet6 %s", hbuf);
3142
3143
504
	if (flags & IFF_POINTOPOINT) {
3144
		(void) memset(&ifr6, 0, sizeof(ifr6));
3145
		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3146
		ifr6.ifr_addr = creq->ifr_addr;
3147
		if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
3148
			if (errno != EADDRNOTAVAIL)
3149
				warn("SIOCGIFDSTADDR_IN6");
3150
			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
3151
			ifr6.ifr_addr.sin6_family = AF_INET6;
3152
			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
3153
		}
3154
		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3155
		in6_fillscopeid(sin6);
3156
		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3157
		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3158
			strlcpy(hbuf, "", sizeof hbuf);
3159
		printf(" -> %s", hbuf);
3160
	}
3161
3162
504
	(void) memset(&ifr6, 0, sizeof(ifr6));
3163
504
	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3164
504
	ifr6.ifr_addr = creq->ifr_addr;
3165
504
	if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
3166
		if (errno != EADDRNOTAVAIL)
3167
			warn("SIOCGIFNETMASK_IN6");
3168
	} else {
3169
		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3170
504
		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
3171
		    sizeof(struct in6_addr)));
3172
	}
3173
3174
504
	(void) memset(&ifr6, 0, sizeof(ifr6));
3175
504
	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3176
504
	ifr6.ifr_addr = creq->ifr_addr;
3177
504
	if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
3178
		if (errno != EADDRNOTAVAIL)
3179
			warn("SIOCGIFAFLAG_IN6");
3180
	} else {
3181
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
3182
			printf(" anycast");
3183
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
3184
156
			printf(" tentative");
3185
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
3186
			printf(" duplicated");
3187
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
3188
			printf(" detached");
3189
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
3190
			printf(" deprecated");
3191
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
3192
48
			printf(" autoconf");
3193
504
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PRIVACY)
3194
24
			printf(" autoconfprivacy");
3195
	}
3196
3197
504
	if (scopeid)
3198
306
		printf(" scopeid 0x%x", scopeid);
3199
3200
504
	if (Lflag) {
3201
		struct in6_addrlifetime *lifetime;
3202
3203
504
		(void) memset(&ifr6, 0, sizeof(ifr6));
3204
504
		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3205
504
		ifr6.ifr_addr = creq->ifr_addr;
3206
504
		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
3207
504
		if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
3208
			if (errno != EADDRNOTAVAIL)
3209
				warn("SIOCGIFALIFETIME_IN6");
3210

960
		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
3211
48
			time_t t = time(NULL);
3212
3213
48
			printf(" pltime ");
3214
48
			if (lifetime->ia6t_preferred) {
3215
144
				printf("%s", lifetime->ia6t_preferred < t
3216
				    ? "0" :
3217
48
				    sec2str(lifetime->ia6t_preferred - t));
3218
48
			} else
3219
				printf("infty");
3220
3221
48
			printf(" vltime ");
3222
48
			if (lifetime->ia6t_expire) {
3223
144
				printf("%s", lifetime->ia6t_expire < t
3224
				    ? "0"
3225
48
				    : sec2str(lifetime->ia6t_expire - t));
3226
48
			} else
3227
				printf("infty");
3228
48
		}
3229
504
	}
3230
3231
504
	printf("\n");
3232
1008
}
3233
3234
void
3235
in6_status(int force)
3236
{
3237
1008
	in6_alias((struct in6_ifreq *)&ifr6);
3238
504
}
3239
3240
#ifndef SMALL
3241
void
3242
settunnel(const char *src, const char *dst)
3243
{
3244
	char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport;
3245
	const char *dstip;
3246
	struct addrinfo *srcres, *dstres;
3247
	int ecode;
3248
	struct if_laddrreq req;
3249
3250
	if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) {
3251
		/* no port or IPv6 */
3252
		dstip = dst;
3253
		dstport = NULL;
3254
	} else {
3255
		if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf))
3256
			errx(1, "%s bad value", dst);
3257
		dstport = strchr(buf, ':');
3258
		*dstport++ = '\0';
3259
		dstip = buf;
3260
	}
3261
3262
	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
3263
		errx(1, "error in parsing address string: %s",
3264
		    gai_strerror(ecode));
3265
3266
	if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0)
3267
		errx(1, "error in parsing address string: %s",
3268
		    gai_strerror(ecode));
3269
3270
	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
3271
		errx(1,
3272
		    "source and destination address families do not match");
3273
3274
	if (srcres->ai_addrlen > sizeof(req.addr) ||
3275
	    dstres->ai_addrlen > sizeof(req.dstaddr))
3276
		errx(1, "invalid sockaddr");
3277
3278
	memset(&req, 0, sizeof(req));
3279
	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
3280
	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
3281
	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
3282
	if (ioctl(s, SIOCSLIFPHYADDR, &req) < 0)
3283
		warn("SIOCSLIFPHYADDR");
3284
3285
	freeaddrinfo(srcres);
3286
	freeaddrinfo(dstres);
3287
}
3288
3289
/* ARGSUSED */
3290
void
3291
deletetunnel(const char *ignored, int alsoignored)
3292
{
3293
	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
3294
		warn("SIOCDIFPHYADDR");
3295
}
3296
3297
void
3298
settunnelinst(const char *id, int param)
3299
{
3300
	const char *errmsg = NULL;
3301
	int rdomainid;
3302
3303
	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
3304
	if (errmsg)
3305
		errx(1, "rdomain %s: %s", id, errmsg);
3306
3307
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3308
	ifr.ifr_rdomainid = rdomainid;
3309
	if (ioctl(s, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) < 0)
3310
		warn("SIOCSLIFPHYRTABLE");
3311
}
3312
3313
void
3314
settunnelttl(const char *id, int param)
3315
{
3316
	const char *errmsg = NULL;
3317
	int ttl;
3318
3319
	ttl = strtonum(id, 0, 0xff, &errmsg);
3320
	if (errmsg)
3321
		errx(1, "tunnelttl %s: %s", id, errmsg);
3322
3323
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3324
	ifr.ifr_ttl = ttl;
3325
	if (ioctl(s, SIOCSLIFPHYTTL, (caddr_t)&ifr) < 0)
3326
		warn("SIOCSLIFPHYTTL");
3327
}
3328
3329
void
3330
mpe_status(void)
3331
{
3332
2548
	struct shim_hdr	shim;
3333
3334
1274
	bzero(&shim, sizeof(shim));
3335
1274
	ifr.ifr_data = (caddr_t)&shim;
3336
3337
1274
	if (ioctl(s, SIOCGETLABEL , (caddr_t)&ifr) == -1)
3338
1274
		return;
3339
	printf("\tmpls label: %d\n", shim.shim_label);
3340
1274
}
3341
3342
void
3343
mpw_status(void)
3344
{
3345
	struct sockaddr_in *sin;
3346
2548
	struct ifmpwreq imr;
3347
3348
1274
	bzero(&imr, sizeof(imr));
3349
1274
	ifr.ifr_data = (caddr_t) &imr;
3350
1274
	if (ioctl(s, SIOCGETMPWCFG, (caddr_t) &ifr) == -1)
3351
1274
		return;
3352
3353
	printf("\tencapsulation-type ");
3354
	switch (imr.imr_type) {
3355
	case IMR_TYPE_NONE:
3356
		printf("none");
3357
		break;
3358
	case IMR_TYPE_ETHERNET:
3359
		printf("ethernet");
3360
		break;
3361
	case IMR_TYPE_ETHERNET_TAGGED:
3362
		printf("ethernet-tagged");
3363
		break;
3364
	default:
3365
		printf("unknown");
3366
		break;
3367
	}
3368
3369
	if (imr.imr_flags & IMR_FLAG_CONTROLWORD)
3370
		printf(", control-word");
3371
3372
	printf("\n");
3373
3374
	printf("\tmpls label: ");
3375
	if (imr.imr_lshim.shim_label == 0)
3376
		printf("local none ");
3377
	else
3378
		printf("local %u ", imr.imr_lshim.shim_label);
3379
3380
	if (imr.imr_rshim.shim_label == 0)
3381
		printf("remote none\n");
3382
	else
3383
		printf("remote %u\n", imr.imr_rshim.shim_label);
3384
3385
	sin = (struct sockaddr_in *) &imr.imr_nexthop;
3386
	if (sin->sin_addr.s_addr == 0)
3387
		printf("\tneighbor: none\n");
3388
	else
3389
		printf("\tneighbor: %s\n", inet_ntoa(sin->sin_addr));
3390
1274
}
3391
3392
/* ARGSUSED */
3393
void
3394
setmpelabel(const char *val, int d)
3395
{
3396
	struct shim_hdr	 shim;
3397
	const char	*estr;
3398
3399
	bzero(&shim, sizeof(shim));
3400
	ifr.ifr_data = (caddr_t)&shim;
3401
	shim.shim_label = strtonum(val, 0, MPLS_LABEL_MAX, &estr);
3402
3403
	if (estr)
3404
		errx(1, "mpls label %s is %s", val, estr);
3405
	if (ioctl(s, SIOCSETLABEL, (caddr_t)&ifr) == -1)
3406
		warn("SIOCSETLABEL");
3407
}
3408
3409
void
3410
process_mpw_commands(void)
3411
{
3412
	struct	sockaddr_in *sin, *sinn;
3413
3890
	struct	ifmpwreq imr;
3414
3415
1945
	if (wconfig == 0)
3416
1945
		return;
3417
3418
	bzero(&imr, sizeof(imr));
3419
	ifr.ifr_data = (caddr_t) &imr;
3420
	if (ioctl(s, SIOCGETMPWCFG, (caddr_t) &ifr) == -1)
3421
		err(1, "SIOCGETMPWCFG");
3422
3423
	if (imrsave.imr_type == 0) {
3424
		if (imr.imr_type == 0)
3425
			imrsave.imr_type = IMR_TYPE_ETHERNET;
3426
3427
		imrsave.imr_type = imr.imr_type;
3428
	}
3429
	if (wcwconfig == 0)
3430
		imrsave.imr_flags |= imr.imr_flags;
3431
3432
	if (imrsave.imr_lshim.shim_label == 0 ||
3433
	    imrsave.imr_rshim.shim_label == 0) {
3434
		if (imr.imr_lshim.shim_label == 0 ||
3435
		    imr.imr_rshim.shim_label == 0)
3436
			errx(1, "mpw local / remote label not specified");
3437
3438
		imrsave.imr_lshim.shim_label = imr.imr_lshim.shim_label;
3439
		imrsave.imr_rshim.shim_label = imr.imr_rshim.shim_label;
3440
	}
3441
3442
	sin = (struct sockaddr_in *) &imrsave.imr_nexthop;
3443
	sinn = (struct sockaddr_in *) &imr.imr_nexthop;
3444
	if (sin->sin_addr.s_addr == 0) {
3445
		if (sinn->sin_addr.s_addr == 0)
3446
			errx(1, "mpw neighbor address not specified");
3447
3448
		sin->sin_family = sinn->sin_family;
3449
		sin->sin_addr.s_addr = sinn->sin_addr.s_addr;
3450
	}
3451
3452
	ifr.ifr_data = (caddr_t) &imrsave;
3453
	if (ioctl(s, SIOCSETMPWCFG, (caddr_t) &ifr) == -1)
3454
		err(1, "SIOCSETMPWCFG");
3455
1945
}
3456
3457
void
3458
setmpwencap(const char *value, int d)
3459
{
3460
	wconfig = 1;
3461
3462
	if (strcmp(value, "ethernet") == 0)
3463
		imrsave.imr_type = IMR_TYPE_ETHERNET;
3464
	else if (strcmp(value, "ethernet-tagged") == 0)
3465
		imrsave.imr_type = IMR_TYPE_ETHERNET_TAGGED;
3466
	else
3467
		errx(1, "invalid mpw encapsulation type");
3468
}
3469
3470
void
3471
setmpwlabel(const char *local, const char *remote)
3472
{
3473
	const	char *errstr;
3474
3475
	wconfig = 1;
3476
3477
	imrsave.imr_lshim.shim_label = strtonum(local,
3478
	    (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
3479
	if (errstr != NULL)
3480
		errx(1, "invalid local label: %s", errstr);
3481
3482
	imrsave.imr_rshim.shim_label = strtonum(remote,
3483
	    (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
3484
	if (errstr != NULL)
3485
		errx(1, "invalid remote label: %s", errstr);
3486
}
3487
3488
void
3489
setmpwneighbor(const char *value, int d)
3490
{
3491
	struct sockaddr_in *sin;
3492
3493
	wconfig = 1;
3494
3495
	sin = (struct sockaddr_in *) &imrsave.imr_nexthop;
3496
	if (inet_aton(value, &sin->sin_addr) == 0)
3497
		errx(1, "invalid neighbor addresses");
3498
3499
	sin->sin_family = AF_INET;
3500
}
3501
3502
void
3503
setmpwcontrolword(const char *value, int d)
3504
{
3505
	wconfig = 1;
3506
	wcwconfig = 1;
3507
3508
	if (d == 1)
3509
		imrsave.imr_flags |= IMR_FLAG_CONTROLWORD;
3510
	else
3511
		imrsave.imr_flags &= ~IMR_FLAG_CONTROLWORD;
3512
}
3513
#endif /* SMALL */
3514
3515
struct ifencap {
3516
	unsigned int	 ife_flags;
3517
#define IFE_VNETID_MASK		0xf
3518
#define IFE_VNETID_NOPE		0x0
3519
#define IFE_VNETID_NONE		0x1
3520
#define IFE_VNETID_ANY		0x2
3521
#define IFE_VNETID_SET		0x3
3522
	int64_t		 ife_vnetid;
3523
3524
#define IFE_PARENT_MASK		0xf0
3525
#define IFE_PARENT_NOPE		0x00
3526
#define IFE_PARENT_NONE		0x10
3527
#define IFE_PARENT_SET		0x20
3528
	char		ife_parent[IFNAMSIZ];
3529
};
3530
3531
void
3532
setvnetid(const char *id, int param)
3533
{
3534
12
	const char *errmsg = NULL;
3535
	int64_t vnetid;
3536
3537
6
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3538
3539
6
	if (strcasecmp("any", id) == 0)
3540
		vnetid = -1;
3541
	else {
3542
6
		vnetid = strtonum(id, 0, INT64_MAX, &errmsg);
3543
6
		if (errmsg)
3544
			errx(1, "vnetid %s: %s", id, errmsg);
3545
	}
3546
3547
6
	ifr.ifr_vnetid = vnetid;
3548
6
	if (ioctl(s, SIOCSVNETID, (caddr_t)&ifr) < 0)
3549
		warn("SIOCSVNETID");
3550
6
}
3551
3552
/* ARGSUSED */
3553
void
3554
delvnetid(const char *ignored, int alsoignored)
3555
{
3556
	if (ioctl(s, SIOCDVNETID, &ifr) < 0)
3557
		warn("SIOCDVNETID");
3558
}
3559
3560
void
3561
getvnetid(struct ifencap *ife)
3562
{
3563
2548
	if (strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) >=
3564
	    sizeof(ifr.ifr_name))
3565
		errx(1, "vnetid: name is too long");
3566
3567
1274
	if (ioctl(s, SIOCGVNETID, &ifr) == -1) {
3568
1274
		if (errno != EADDRNOTAVAIL)
3569
			return;
3570
3571
		ife->ife_flags |= IFE_VNETID_NONE;
3572
		return;
3573
	}
3574
3575
	if (ifr.ifr_vnetid < 0) {
3576
		ife->ife_flags |= IFE_VNETID_ANY;
3577
		return;
3578
	}
3579
3580
	ife->ife_flags |= IFE_VNETID_SET;
3581
	ife->ife_vnetid = ifr.ifr_vnetid;
3582
1274
}
3583
3584
void
3585
setifparent(const char *id, int param)
3586
{
3587
12
	struct if_parent ifp;
3588
3589
6
	if (strlcpy(ifp.ifp_name, name, sizeof(ifp.ifp_name)) >=
3590
	    sizeof(ifp.ifp_name))
3591
		errx(1, "parent: name too long");
3592
3593
6
	if (strlcpy(ifp.ifp_parent, id, sizeof(ifp.ifp_parent)) >=
3594
	    sizeof(ifp.ifp_parent))
3595
		errx(1, "parent: parent too long");
3596
3597
6
	if (ioctl(s, SIOCSIFPARENT, (caddr_t)&ifp) < 0)
3598
		warn("SIOCSIFPARENT");
3599
6
}
3600
3601
/* ARGSUSED */
3602
void
3603
delifparent(const char *ignored, int alsoignored)
3604
{
3605
	if (ioctl(s, SIOCDIFPARENT, &ifr) < 0)
3606
		warn("SIOCDIFPARENT");
3607
}
3608
3609
void
3610
getifparent(struct ifencap *ife)
3611
{
3612
2548
	struct if_parent ifp;
3613
3614
1274
	memset(&ifp, 0, sizeof(ifp));
3615
1274
	if (strlcpy(ifp.ifp_name, name, sizeof(ifp.ifp_name)) >=
3616
	    sizeof(ifp.ifp_name))
3617
		errx(1, "parent: name too long");
3618
3619
1274
	if (ioctl(s, SIOCGIFPARENT, (caddr_t)&ifp) == -1) {
3620
1274
		if (errno != EADDRNOTAVAIL)
3621
1274
			return;
3622
3623
		ife->ife_flags |= IFE_PARENT_NONE;
3624
	} else {
3625
		memcpy(ife->ife_parent, ifp.ifp_parent,
3626
		    sizeof(ife->ife_parent));
3627
		ife->ife_flags |= IFE_PARENT_SET;
3628
	}
3629
1274
}
3630
3631
void
3632
getencap(void)
3633
{
3634
2548
	struct ifencap ife = { .ife_flags = 0 };
3635
3636
1274
	getvnetid(&ife);
3637
1274
	getifparent(&ife);
3638
3639
1274
	if (ife.ife_flags == 0)
3640
1274
		return;
3641
3642
	printf("\tencap:");
3643
3644
	switch (ife.ife_flags & IFE_VNETID_MASK) {
3645
	case IFE_VNETID_NONE:
3646
		printf(" vnetid none");
3647
		break;
3648
	case IFE_VNETID_ANY:
3649
		printf(" vnetid any");
3650
		break;
3651
	case IFE_VNETID_SET:
3652
		printf(" vnetid %lld", ife.ife_vnetid);
3653
		break;
3654
	}
3655
3656
	switch (ife.ife_flags & IFE_PARENT_MASK) {
3657
	case IFE_PARENT_NONE:
3658
		printf(" parent none");
3659
		break;
3660
	case IFE_PARENT_SET:
3661
		printf(" parent %s", ife.ife_parent);
3662
		break;
3663
	}
3664
3665
	printf("\n");
3666
1274
}
3667
3668
static int __tag = 0;
3669
static int __have_tag = 0;
3670
3671
/* ARGSUSED */
3672
void
3673
setvlantag(const char *val, int d)
3674
{
3675
	u_int16_t tag;
3676
	struct vlanreq vreq;
3677
	const char *errmsg = NULL;
3678
3679
	__tag = tag = strtonum(val, 0, 4095, &errmsg);
3680
	if (errmsg)
3681
		errx(1, "vlan tag %s: %s", val, errmsg);
3682
	__have_tag = 1;
3683
3684
	bzero((char *)&vreq, sizeof(struct vlanreq));
3685
	ifr.ifr_data = (caddr_t)&vreq;
3686
3687
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3688
		err(1, "SIOCGETVLAN");
3689
3690
	vreq.vlr_tag = tag;
3691
3692
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3693
		err(1, "SIOCSETVLAN");
3694
}
3695
3696
/* ARGSUSED */
3697
void
3698
setvlandev(const char *val, int d)
3699
{
3700
	struct vlanreq	 vreq;
3701
	int		 tag;
3702
	size_t		 skip;
3703
	const char	*estr;
3704
3705
	bzero((char *)&vreq, sizeof(struct vlanreq));
3706
	ifr.ifr_data = (caddr_t)&vreq;
3707
3708
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3709
		err(1, "SIOCGETVLAN");
3710
3711
	(void) strlcpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
3712
3713
	if (!__have_tag && vreq.vlr_tag == 0) {
3714
		skip = strcspn(ifr.ifr_name, "0123456789");
3715
		tag = strtonum(ifr.ifr_name + skip, 0, 4095, &estr);
3716
		if (estr != NULL)
3717
			errx(1, "invalid vlan tag and device specification");
3718
		vreq.vlr_tag = tag;
3719
	} else if (__have_tag)
3720
		vreq.vlr_tag = __tag;
3721
3722
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3723
		err(1, "SIOCSETVLAN");
3724
}
3725
3726
/* ARGSUSED */
3727
void
3728
unsetvlandev(const char *val, int d)
3729
{
3730
	struct vlanreq vreq;
3731
3732
	bzero((char *)&vreq, sizeof(struct vlanreq));
3733
	ifr.ifr_data = (caddr_t)&vreq;
3734
3735
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3736
		err(1, "SIOCGETVLAN");
3737
3738
	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
3739
	vreq.vlr_tag = 0;
3740
3741
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3742
		err(1, "SIOCSETVLAN");
3743
}
3744
3745
void
3746
settrunkport(const char *val, int d)
3747
{
3748
	struct trunk_reqport rp;
3749
3750
	bzero(&rp, sizeof(rp));
3751
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3752
	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
3753
3754
	if (ioctl(s, SIOCSTRUNKPORT, &rp))
3755
		err(1, "SIOCSTRUNKPORT");
3756
}
3757
3758
void
3759
unsettrunkport(const char *val, int d)
3760
{
3761
	struct trunk_reqport rp;
3762
3763
	bzero(&rp, sizeof(rp));
3764
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3765
	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
3766
3767
	if (ioctl(s, SIOCSTRUNKDELPORT, &rp))
3768
		err(1, "SIOCSTRUNKDELPORT");
3769
}
3770
3771
void
3772
settrunkproto(const char *val, int d)
3773
{
3774
	struct trunk_protos tpr[] = TRUNK_PROTOS;
3775
	struct trunk_reqall ra;
3776
	int i;
3777
3778
	bzero(&ra, sizeof(ra));
3779
	ra.ra_proto = TRUNK_PROTO_MAX;
3780
3781
	for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
3782
		if (strcmp(val, tpr[i].tpr_name) == 0) {
3783
			ra.ra_proto = tpr[i].tpr_proto;
3784
			break;
3785
		}
3786
	}
3787
	if (ra.ra_proto == TRUNK_PROTO_MAX)
3788
		errx(1, "Invalid trunk protocol: %s", val);
3789
3790
	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
3791
	if (ioctl(s, SIOCSTRUNK, &ra) != 0)
3792
		err(1, "SIOCSTRUNK");
3793
}
3794
3795
void
3796
trunk_status(void)
3797
{
3798
2548
	struct trunk_protos tpr[] = TRUNK_PROTOS;
3799
1274
	struct trunk_reqport rp, rpbuf[TRUNK_MAX_PORTS];
3800
1274
	struct trunk_reqall ra;
3801
	struct lacp_opreq *lp;
3802
	const char *proto = "<unknown>";
3803
	int i, isport = 0;
3804
3805
1274
	bzero(&rp, sizeof(rp));
3806
1274
	bzero(&ra, sizeof(ra));
3807
3808
1274
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3809
1274
	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
3810
3811
1274
	if (ioctl(s, SIOCGTRUNKPORT, &rp) == 0)
3812
		isport = 1;
3813
3814
1274
	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
3815
1274
	ra.ra_size = sizeof(rpbuf);
3816
1274
	ra.ra_port = rpbuf;
3817
3818
1274
	if (ioctl(s, SIOCGTRUNK, &ra) == 0) {
3819
		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
3820
3821
		for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
3822
			if (ra.ra_proto == tpr[i].tpr_proto) {
3823
				proto = tpr[i].tpr_name;
3824
				break;
3825
			}
3826
		}
3827
3828
		printf("\ttrunk: trunkproto %s", proto);
3829
		if (isport)
3830
			printf(" trunkdev %s", rp.rp_ifname);
3831
		putchar('\n');
3832
		if (ra.ra_proto == TRUNK_PROTO_LACP) {
3833
			char *act_mac = strdup(
3834
			    ether_ntoa((struct ether_addr*)lp->actor_mac));
3835
			if (act_mac == NULL)
3836
				err(1, "strdup");
3837
			printf("\ttrunk id: [(%04X,%s,%04X,%04X,%04X),\n"
3838
			    "\t\t (%04X,%s,%04X,%04X,%04X)]\n",
3839
			    lp->actor_prio, act_mac,
3840
			    lp->actor_key, lp->actor_portprio, lp->actor_portno,
3841
			    lp->partner_prio,
3842
			    ether_ntoa((struct ether_addr*)lp->partner_mac),
3843
			    lp->partner_key, lp->partner_portprio,
3844
			    lp->partner_portno);
3845
			free(act_mac);
3846
		}
3847
3848
		for (i = 0; i < ra.ra_ports; i++) {
3849
			printf("\t\ttrunkport %s ", rpbuf[i].rp_portname);
3850
			printb_status(rpbuf[i].rp_flags, TRUNK_PORT_BITS);
3851
			putchar('\n');
3852
		}
3853
3854
		if (showmediaflag) {
3855
			printf("\tsupported trunk protocols:\n");
3856
			for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++)
3857
				printf("\t\ttrunkproto %s\n", tpr[i].tpr_name);
3858
		}
3859
1274
	} else if (isport)
3860
		printf("\ttrunk: trunkdev %s\n", rp.rp_ifname);
3861
1274
}
3862
3863
#ifndef SMALL
3864
static const char *carp_states[] = { CARP_STATES };
3865
static const char *carp_bal_modes[] = { CARP_BAL_MODES };
3866
3867
void
3868
carp_status(void)
3869
{
3870
	const char *state, *balmode;
3871
2548
	struct carpreq carpr;
3872
1274
	char peer[32];
3873
	int i;
3874
3875
1274
	memset((char *)&carpr, 0, sizeof(struct carpreq));
3876
1274
	ifr.ifr_data = (caddr_t)&carpr;
3877
3878
1274
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3879
1202
		return;
3880
3881
72
	if (carpr.carpr_vhids[0] == 0)
3882
		return;
3883
3884
72
	if (carpr.carpr_balancing > CARP_BAL_MAXID)
3885
		balmode = "<UNKNOWN>";
3886
	else
3887
72
		balmode = carp_bal_modes[carpr.carpr_balancing];
3888
3889
72
	if (carpr.carpr_peer.s_addr != htonl(INADDR_CARP_GROUP))
3890
		snprintf(peer, sizeof(peer),
3891
		    " carppeer %s", inet_ntoa(carpr.carpr_peer));
3892
	else
3893
72
		peer[0] = '\0';
3894
3895
288
	for (i = 0; carpr.carpr_vhids[i]; i++) {
3896
72
		if (carpr.carpr_states[i] > CARP_MAXSTATE)
3897
			state = "<UNKNOWN>";
3898
		else
3899
72
			state = carp_states[carpr.carpr_states[i]];
3900
72
		if (carpr.carpr_vhids[1] == 0) {
3901
72
			printf("\tcarp: %s carpdev %s vhid %u advbase %d "
3902
			    "advskew %u%s\n", state,
3903
144
			    carpr.carpr_carpdev[0] != '\0' ?
3904
144
			    carpr.carpr_carpdev : "none", carpr.carpr_vhids[0],
3905
72
			    carpr.carpr_advbase, carpr.carpr_advskews[0],
3906
72
			    peer);
3907
72
		} else {
3908
			if (i == 0) {
3909
				printf("\tcarp: carpdev %s advbase %d"
3910
				    " balancing %s%s\n",
3911
				    carpr.carpr_carpdev[0] != '\0' ?
3912
				    carpr.carpr_carpdev : "none",
3913
				    carpr.carpr_advbase, balmode, peer);
3914
			}
3915
			printf("\t\tstate %s vhid %u advskew %u\n", state,
3916
			    carpr.carpr_vhids[i], carpr.carpr_advskews[i]);
3917
		}
3918
	}
3919
1346
}
3920
3921
/* ARGSUSED */
3922
void
3923
setcarp_passwd(const char *val, int d)
3924
{
3925
	struct carpreq carpr;
3926
3927
	bzero(&carpr, sizeof(struct carpreq));
3928
	ifr.ifr_data = (caddr_t)&carpr;
3929
3930
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3931
		err(1, "SIOCGVH");
3932
3933
	bzero(carpr.carpr_key, CARP_KEY_LEN);
3934
	strlcpy((char *)carpr.carpr_key, val, CARP_KEY_LEN);
3935
3936
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
3937
		err(1, "SIOCSVH");
3938
}
3939
3940
/* ARGSUSED */
3941
void
3942
setcarp_vhid(const char *val, int d)
3943
{
3944
40
	const char *errmsg = NULL;
3945
20
	struct carpreq carpr;
3946
	int vhid;
3947
3948
20
	vhid = strtonum(val, 1, 255, &errmsg);
3949
20
	if (errmsg)
3950
		errx(1, "vhid %s: %s", val, errmsg);
3951
3952
20
	bzero(&carpr, sizeof(struct carpreq));
3953
20
	ifr.ifr_data = (caddr_t)&carpr;
3954
3955
20
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3956
		err(1, "SIOCGVH");
3957
3958
20
	carpr.carpr_vhids[0] = vhid;
3959
20
	carpr.carpr_vhids[1] = 0;
3960
3961
20
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
3962
		err(1, "SIOCSVH");
3963
20
}
3964
3965
/* ARGSUSED */
3966
void
3967
setcarp_advskew(const char *val, int d)
3968
{
3969
	const char *errmsg = NULL;
3970
	struct carpreq carpr;
3971
	int advskew;
3972
3973
	advskew = strtonum(val, 0, 254, &errmsg);
3974
	if (errmsg)
3975
		errx(1, "advskew %s: %s", val, errmsg);
3976
3977
	bzero(&carpr, sizeof(struct carpreq));
3978
	ifr.ifr_data = (caddr_t)&carpr;
3979
3980
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3981
		err(1, "SIOCGVH");
3982
3983
	carpr.carpr_advskews[0] = advskew;
3984
3985
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
3986
		err(1, "SIOCSVH");
3987
}
3988
3989
/* ARGSUSED */
3990
void
3991
setcarp_advbase(const char *val, int d)
3992
{
3993
	const char *errmsg = NULL;
3994
	struct carpreq carpr;
3995
	int advbase;
3996
3997
	advbase = strtonum(val, 0, 254, &errmsg);
3998
	if (errmsg)
3999
		errx(1, "advbase %s: %s", val, errmsg);
4000
4001
	bzero(&carpr, sizeof(struct carpreq));
4002
	ifr.ifr_data = (caddr_t)&carpr;
4003
4004
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4005
		err(1, "SIOCGVH");
4006
4007
	carpr.carpr_advbase = advbase;
4008
4009
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4010
		err(1, "SIOCSVH");
4011
}
4012
4013
/* ARGSUSED */
4014
void
4015
setcarppeer(const char *val, int d)
4016
{
4017
	struct carpreq carpr;
4018
	struct addrinfo hints, *peerres;
4019
	int ecode;
4020
4021
	bzero(&carpr, sizeof(struct carpreq));
4022
	ifr.ifr_data = (caddr_t)&carpr;
4023
4024
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4025
		err(1, "SIOCGVH");
4026
4027
	bzero(&hints, sizeof(hints));
4028
	hints.ai_family = AF_INET;
4029
	hints.ai_socktype = SOCK_DGRAM;
4030
4031
	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4032
		errx(1, "error in parsing address string: %s",
4033
		    gai_strerror(ecode));
4034
4035
	if (peerres->ai_addr->sa_family != AF_INET)
4036
		errx(1, "only IPv4 addresses supported for the carppeer");
4037
4038
	carpr.carpr_peer.s_addr = ((struct sockaddr_in *)
4039
	    peerres->ai_addr)->sin_addr.s_addr;
4040
4041
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4042
		err(1, "SIOCSVH");
4043
4044
	freeaddrinfo(peerres);
4045
}
4046
4047
void
4048
unsetcarppeer(const char *val, int d)
4049
{
4050
	struct carpreq carpr;
4051
4052
	bzero(&carpr, sizeof(struct carpreq));
4053
	ifr.ifr_data = (caddr_t)&carpr;
4054
4055
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4056
		err(1, "SIOCGVH");
4057
4058
	bzero(&carpr.carpr_peer, sizeof(carpr.carpr_peer));
4059
4060
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4061
		err(1, "SIOCSVH");
4062
}
4063
4064
/* ARGSUSED */
4065
void
4066
setcarp_state(const char *val, int d)
4067
{
4068
	struct carpreq carpr;
4069
	int i;
4070
4071
	bzero(&carpr, sizeof(struct carpreq));
4072
	ifr.ifr_data = (caddr_t)&carpr;
4073
4074
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4075
		err(1, "SIOCGVH");
4076
4077
	for (i = 0; i <= CARP_MAXSTATE; i++) {
4078
		if (!strcasecmp(val, carp_states[i])) {
4079
			carpr.carpr_state = i;
4080
			break;
4081
		}
4082
	}
4083
4084
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4085
		err(1, "SIOCSVH");
4086
}
4087
4088
/* ARGSUSED */
4089
void
4090
setcarpdev(const char *val, int d)
4091
{
4092
40
	struct carpreq carpr;
4093
4094
20
	bzero(&carpr, sizeof(struct carpreq));
4095
20
	ifr.ifr_data = (caddr_t)&carpr;
4096
4097
20
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4098
		err(1, "SIOCGVH");
4099
4100
20
	strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
4101
4102
20
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4103
		err(1, "SIOCSVH");
4104
20
}
4105
4106
void
4107
setcarp_nodes(const char *val, int d)
4108
{
4109
	char *optlist, *str;
4110
	int i;
4111
	struct carpreq carpr;
4112
4113
	bzero(&carpr, sizeof(struct carpreq));
4114
	ifr.ifr_data = (caddr_t)&carpr;
4115
4116
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4117
		err(1, "SIOCGVH");
4118
4119
	bzero(carpr.carpr_vhids, sizeof(carpr.carpr_vhids));
4120
	bzero(carpr.carpr_advskews, sizeof(carpr.carpr_advskews));
4121
4122
	optlist = strdup(val);
4123
	if (optlist == NULL)
4124
		err(1, "strdup");
4125
4126
	str = strtok(optlist, ",");
4127
	for (i = 0; str != NULL; i++) {
4128
		u_int vhid, advskew;
4129
4130
		if (i >= CARP_MAXNODES)
4131
			errx(1, "too many carp nodes");
4132
		if (sscanf(str, "%u:%u", &vhid, &advskew) != 2) {
4133
			errx(1, "non parsable arg: %s", str);
4134
		}
4135
		if (vhid > 255)
4136
			errx(1, "vhid %u: value too large", vhid);
4137
		if (advskew >= 255)
4138
			errx(1, "advskew %u: value too large", advskew);
4139
4140
		carpr.carpr_vhids[i] = vhid;
4141
		carpr.carpr_advskews[i] = advskew;
4142
		str = strtok(NULL, ",");
4143
	}
4144
	free(optlist);
4145
4146
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4147
		err(1, "SIOCSVH");
4148
}
4149
4150
void
4151
setcarp_balancing(const char *val, int d)
4152
{
4153
	int i;
4154
	struct carpreq carpr;
4155
4156
	bzero(&carpr, sizeof(struct carpreq));
4157
	ifr.ifr_data = (caddr_t)&carpr;
4158
4159
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4160
		err(1, "SIOCGVH");
4161
4162
	for (i = 0; i <= CARP_BAL_MAXID; i++)
4163
		if (!strcasecmp(val, carp_bal_modes[i]))
4164
			break;
4165
4166
	if (i > CARP_BAL_MAXID)
4167
		errx(1, "balancing %s: unknown mode", val);
4168
4169
	carpr.carpr_balancing = i;
4170
4171
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4172
		err(1, "SIOCSVH");
4173
}
4174
4175
void
4176
setpfsync_syncdev(const char *val, int d)
4177
{
4178
	struct pfsyncreq preq;
4179
4180
	bzero(&preq, sizeof(struct pfsyncreq));
4181
	ifr.ifr_data = (caddr_t)&preq;
4182
4183
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4184
		err(1, "SIOCGETPFSYNC");
4185
4186
	strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
4187
4188
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4189
		err(1, "SIOCSETPFSYNC");
4190
}
4191
4192
/* ARGSUSED */
4193
void
4194
unsetpfsync_syncdev(const char *val, int d)
4195
{
4196
	struct pfsyncreq preq;
4197
4198
	bzero(&preq, sizeof(struct pfsyncreq));
4199
	ifr.ifr_data = (caddr_t)&preq;
4200
4201
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4202
		err(1, "SIOCGETPFSYNC");
4203
4204
	bzero(&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
4205
4206
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4207
		err(1, "SIOCSETPFSYNC");
4208
}
4209
4210
/* ARGSUSED */
4211
void
4212
setpfsync_syncpeer(const char *val, int d)
4213
{
4214
	struct pfsyncreq preq;
4215
	struct addrinfo hints, *peerres;
4216
	int ecode;
4217
4218
	bzero(&preq, sizeof(struct pfsyncreq));
4219
	ifr.ifr_data = (caddr_t)&preq;
4220
4221
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4222
		err(1, "SIOCGETPFSYNC");
4223
4224
	memset(&hints, 0, sizeof(hints));
4225
	hints.ai_family = AF_INET;
4226
	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
4227
4228
	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4229
		errx(1, "error in parsing address string: %s",
4230
		    gai_strerror(ecode));
4231
4232
	if (peerres->ai_addr->sa_family != AF_INET)
4233
		errx(1, "only IPv4 addresses supported for the syncpeer");
4234
4235
	preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
4236
	    peerres->ai_addr)->sin_addr.s_addr;
4237
4238
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4239
		err(1, "SIOCSETPFSYNC");
4240
4241
	freeaddrinfo(peerres);
4242
}
4243
4244
/* ARGSUSED */
4245
void
4246
unsetpfsync_syncpeer(const char *val, int d)
4247
{
4248
	struct pfsyncreq preq;
4249
4250
	bzero(&preq, sizeof(struct pfsyncreq));
4251
	ifr.ifr_data = (caddr_t)&preq;
4252
4253
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4254
		err(1, "SIOCGETPFSYNC");
4255
4256
	preq.pfsyncr_syncpeer.s_addr = 0;
4257
4258
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4259
		err(1, "SIOCSETPFSYNC");
4260
}
4261
4262
/* ARGSUSED */
4263
void
4264
setpfsync_maxupd(const char *val, int d)
4265
{
4266
	const char *errmsg = NULL;
4267
	struct pfsyncreq preq;
4268
	int maxupdates;
4269
4270
	maxupdates = strtonum(val, 0, 255, &errmsg);
4271
	if (errmsg)
4272
		errx(1, "maxupd %s: %s", val, errmsg);
4273
4274
	bzero(&preq, sizeof(struct pfsyncreq));
4275
	ifr.ifr_data = (caddr_t)&preq;
4276
4277
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4278
		err(1, "SIOCGETPFSYNC");
4279
4280
	preq.pfsyncr_maxupdates = maxupdates;
4281
4282
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4283
		err(1, "SIOCSETPFSYNC");
4284
}
4285
4286
void
4287
setpfsync_defer(const char *val, int d)
4288
{
4289
	struct pfsyncreq preq;
4290
4291
	bzero(&preq, sizeof(struct pfsyncreq));
4292
	ifr.ifr_data = (caddr_t)&preq;
4293
4294
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4295
		err(1, "SIOCGETPFSYNC");
4296
4297
	preq.pfsyncr_defer = d;
4298
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4299
		err(1, "SIOCSETPFSYNC");
4300
}
4301
4302
void
4303
pfsync_status(void)
4304
{
4305
2548
	struct pfsyncreq preq;
4306
4307
1274
	bzero(&preq, sizeof(struct pfsyncreq));
4308
1274
	ifr.ifr_data = (caddr_t)&preq;
4309
4310
1274
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4311
1274
		return;
4312
4313
	if (preq.pfsyncr_syncdev[0] != '\0') {
4314
		printf("\tpfsync: syncdev: %s ", preq.pfsyncr_syncdev);
4315
		if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
4316
			printf("syncpeer: %s ",
4317
			    inet_ntoa(preq.pfsyncr_syncpeer));
4318
		printf("maxupd: %d ", preq.pfsyncr_maxupdates);
4319
		printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
4320
	}
4321
1274
}
4322
4323
void
4324
pflow_status(void)
4325
{
4326
2548
	struct pflowreq		 preq;
4327
	struct sockaddr_in	*sin;
4328
	struct sockaddr_in6	*sin6;
4329
	int			 error;
4330
1274
	char			 buf[INET6_ADDRSTRLEN];
4331
4332
1274
	bzero(&preq, sizeof(struct pflowreq));
4333
1274
	ifr.ifr_data = (caddr_t)&preq;
4334
4335
1274
	if (ioctl(s, SIOCGETPFLOW, (caddr_t)&ifr) == -1)
4336
1274
		 return;
4337
4338
	if (preq.flowsrc.ss_family == AF_INET || preq.flowsrc.ss_family ==
4339
	    AF_INET6) {
4340
		error = getnameinfo((struct sockaddr*)&preq.flowsrc,
4341
		    preq.flowsrc.ss_len, buf, sizeof(buf), NULL, 0,
4342
		    NI_NUMERICHOST);
4343
		if (error)
4344
			err(1, "sender: %s", gai_strerror(error));
4345
	}
4346
4347
	printf("\tpflow: ");
4348
	switch (preq.flowsrc.ss_family) {
4349
	case AF_INET:
4350
		sin = (struct sockaddr_in*) &preq.flowsrc;
4351
		if (sin->sin_addr.s_addr != INADDR_ANY) {
4352
			printf("sender: %s", buf);
4353
			if (sin->sin_port != 0)
4354
				printf(":%u", ntohs(sin->sin_port));
4355
			printf(" ");
4356
		}
4357
		break;
4358
	case AF_INET6:
4359
		sin6 = (struct sockaddr_in6*) &preq.flowsrc;
4360
		if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4361
			printf("sender: [%s]", buf);
4362
			if (sin6->sin6_port != 0)
4363
				printf(":%u", ntohs(sin6->sin6_port));
4364
			printf(" ");
4365
		}
4366
	default:
4367
		break;
4368
	}
4369
	if (preq.flowdst.ss_family == AF_INET || preq.flowdst.ss_family ==
4370
	    AF_INET6) {
4371
		error = getnameinfo((struct sockaddr*)&preq.flowdst,
4372
		    preq.flowdst.ss_len, buf, sizeof(buf), NULL, 0,
4373
		    NI_NUMERICHOST);
4374
		if (error)
4375
			err(1, "receiver: %s", gai_strerror(error));
4376
	}
4377
	switch (preq.flowdst.ss_family) {
4378
	case AF_INET:
4379
		sin = (struct sockaddr_in*)&preq.flowdst;
4380
		printf("receiver: %s:", sin->sin_addr.s_addr != INADDR_ANY ?
4381
		    buf : "INVALID");
4382
		if (sin->sin_port == 0)
4383
			printf("%s ", "INVALID");
4384
		else
4385
			printf("%u ", ntohs(sin->sin_port));
4386
		break;
4387
	case AF_INET6:
4388
		sin6 = (struct sockaddr_in6*) &preq.flowdst;
4389
		printf("receiver: [%s]:",
4390
		    !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ? buf :
4391
		    "INVALID");
4392
		if (sin6->sin6_port == 0)
4393
			printf("%s ", "INVALID");
4394
		else
4395
			printf("%u ", ntohs(sin6->sin6_port));
4396
		break;
4397
	default:
4398
		printf("receiver: INVALID:INVALID ");
4399
		break;
4400
	}
4401
	printf("version: %d\n", preq.version);
4402
1274
}
4403
4404
void
4405
pflow_addr(const char *val, struct sockaddr_storage *ss) {
4406
	struct addrinfo hints, *res0;
4407
	int error, flag;
4408
	char *cp, *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
4409
4410
	if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
4411
		errx(1, "%s bad value", val);
4412
4413
	port = NULL;
4414
	cp = buf;
4415
	if (*cp == '[')
4416
		flag = 1;
4417
	else
4418
		flag = 0;
4419
4420
	for(; *cp; ++cp) {
4421
		if (*cp == ']' && *(cp + 1) == ':' && flag) {
4422
			*cp = '\0';
4423
			*(cp + 1) = '\0';
4424
			port = cp + 2;
4425
			break;
4426
		}
4427
		if (*cp == ']' && *(cp + 1) == '\0' && flag) {
4428
			*cp = '\0';
4429
			port = NULL;
4430
			break;
4431
		}
4432
		if (*cp == ':' && !flag) {
4433
			*cp = '\0';
4434
			port = cp + 1;
4435
			break;
4436
		}
4437
	}
4438
4439
	ip = buf;
4440
	if (flag)
4441
		ip++;
4442
4443
	bzero(&hints, sizeof(hints));
4444
	hints.ai_family = AF_UNSPEC;
4445
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
4446
	hints.ai_flags = AI_NUMERICHOST;
4447
4448
	if ((error = getaddrinfo(ip, port, &hints, &res0)) != 0)
4449
		errx(1, "error in parsing address string: %s",
4450
		    gai_strerror(error));
4451
4452
	memcpy(ss, res0->ai_addr, res0->ai_addr->sa_len);
4453
	freeaddrinfo(res0);
4454
}
4455
4456
void
4457
setpflow_sender(const char *val, int d)
4458
{
4459
	struct pflowreq preq;
4460
4461
	bzero(&preq, sizeof(struct pflowreq));
4462
	ifr.ifr_data = (caddr_t)&preq;
4463
	preq.addrmask |= PFLOW_MASK_SRCIP;
4464
	pflow_addr(val, &preq.flowsrc);
4465
4466
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4467
		err(1, "SIOCSETPFLOW");
4468
}
4469
4470
void
4471
unsetpflow_sender(const char *val, int d)
4472
{
4473
	struct pflowreq preq;
4474
4475
	bzero(&preq, sizeof(struct pflowreq));
4476
	preq.addrmask |= PFLOW_MASK_SRCIP;
4477
	ifr.ifr_data = (caddr_t)&preq;
4478
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4479
		err(1, "SIOCSETPFLOW");
4480
}
4481
4482
void
4483
setpflow_receiver(const char *val, int d)
4484
{
4485
	struct pflowreq preq;
4486
4487
	bzero(&preq, sizeof(struct pflowreq));
4488
	ifr.ifr_data = (caddr_t)&preq;
4489
	preq.addrmask |= PFLOW_MASK_DSTIP;
4490
	pflow_addr(val, &preq.flowdst);
4491
4492
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4493
		err(1, "SIOCSETPFLOW");
4494
}
4495
4496
void
4497
unsetpflow_receiver(const char *val, int d)
4498
{
4499
	struct pflowreq preq;
4500
4501
	bzero(&preq, sizeof(struct pflowreq));
4502
	ifr.ifr_data = (caddr_t)&preq;
4503
	preq.addrmask |= PFLOW_MASK_DSTIP;
4504
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4505
		err(1, "SIOCSETPFLOW");
4506
}
4507
4508
/* PFLOWPROTO XXX */
4509
void
4510
setpflowproto(const char *val, int d)
4511
{
4512
	struct pflow_protos ppr[] = PFLOW_PROTOS;
4513
	struct pflowreq preq;
4514
	int i;
4515
4516
	bzero(&preq, sizeof(preq));
4517
	preq.version = PFLOW_PROTO_MAX;
4518
4519
	for (i = 0; i < (sizeof(ppr) / sizeof(ppr[0])); i++) {
4520
		if (strcmp(val, ppr[i].ppr_name) == 0) {
4521
			preq.version = ppr[i].ppr_proto;
4522
			break;
4523
		}
4524
	}
4525
	if (preq.version == PFLOW_PROTO_MAX)
4526
		errx(1, "Invalid pflow protocol: %s", val);
4527
4528
	preq.addrmask |= PFLOW_MASK_VERSION;
4529
4530
	ifr.ifr_data = (caddr_t)&preq;
4531
4532
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4533
		err(1, "SIOCSETPFLOW");
4534
}
4535
4536
void
4537
pppoe_status(void)
4538
{
4539
2548
	struct pppoediscparms parms;
4540
1274
	struct pppoeconnectionstate state;
4541
4542
1274
	memset(&state, 0, sizeof(state));
4543
4544
1274
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4545
1274
	if (ioctl(s, PPPOEGETPARMS, &parms))
4546
1274
		return;
4547
4548
	printf("\tdev: %s ", parms.eth_ifname);
4549
4550
	if (*parms.ac_name)
4551
		printf("ac: %s ", parms.ac_name);
4552
	if (*parms.service_name)
4553
		printf("svc: %s ", parms.service_name);
4554
4555
	strlcpy(state.ifname, name, sizeof(state.ifname));
4556
	if (ioctl(s, PPPOEGETSESSION, &state))
4557
		err(1, "PPPOEGETSESSION");
4558
4559
	printf("state: ");
4560
	switch (state.state) {
4561
	case PPPOE_STATE_INITIAL:
4562
		printf("initial"); break;
4563
	case PPPOE_STATE_PADI_SENT:
4564
		printf("PADI sent"); break;
4565
	case PPPOE_STATE_PADR_SENT:
4566
		printf("PADR sent"); break;
4567
	case PPPOE_STATE_SESSION:
4568
		printf("session"); break;
4569
	case PPPOE_STATE_CLOSING:
4570
		printf("closing"); break;
4571
	}
4572
	printf("\n\tsid: 0x%x", state.session_id);
4573
	printf(" PADI retries: %d", state.padi_retry_no);
4574
	printf(" PADR retries: %d", state.padr_retry_no);
4575
4576
	if (state.state == PPPOE_STATE_SESSION) {
4577
		struct timeval temp_time;
4578
		time_t diff_time, day = 0;
4579
		unsigned int hour = 0, min = 0, sec = 0;
4580
4581
		if (state.session_time.tv_sec != 0) {
4582
			gettimeofday(&temp_time, NULL);
4583
			diff_time = temp_time.tv_sec -
4584
			    state.session_time.tv_sec;
4585
4586
			day = diff_time / (60 * 60 * 24);
4587
			diff_time %= (60 * 60 * 24);
4588
4589
			hour = diff_time / (60 * 60);
4590
			diff_time %= (60 * 60);
4591
4592
			min = diff_time / 60;
4593
			diff_time %= 60;
4594
4595
			sec = diff_time;
4596
		}
4597
		printf(" time: ");
4598
		if (day != 0)
4599
			printf("%lldd ", (long long)day);
4600
		printf("%02u:%02u:%02u", hour, min, sec);
4601
	}
4602
	putchar('\n');
4603
1274
}
4604
4605
/* ARGSUSED */
4606
void
4607
setpppoe_dev(const char *val, int d)
4608
{
4609
	struct pppoediscparms parms;
4610
4611
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4612
	if (ioctl(s, PPPOEGETPARMS, &parms))
4613
		return;
4614
4615
	strlcpy(parms.eth_ifname, val, sizeof(parms.eth_ifname));
4616
4617
	if (ioctl(s, PPPOESETPARMS, &parms))
4618
		err(1, "PPPOESETPARMS");
4619
}
4620
4621
/* ARGSUSED */
4622
void
4623
setpppoe_svc(const char *val, int d)
4624
{
4625
	struct pppoediscparms parms;
4626
4627
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4628
	if (ioctl(s, PPPOEGETPARMS, &parms))
4629
		return;
4630
4631
	if (d == 0)
4632
		strlcpy(parms.service_name, val, sizeof(parms.service_name));
4633
	else
4634
		memset(parms.service_name, 0, sizeof(parms.service_name));
4635
4636
	if (ioctl(s, PPPOESETPARMS, &parms))
4637
		err(1, "PPPOESETPARMS");
4638
}
4639
4640
/* ARGSUSED */
4641
void
4642
setpppoe_ac(const char *val, int d)
4643
{
4644
	struct pppoediscparms parms;
4645
4646
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4647
	if (ioctl(s, PPPOEGETPARMS, &parms))
4648
		return;
4649
4650
	if (d == 0)
4651
		strlcpy(parms.ac_name, val, sizeof(parms.ac_name));
4652
	else
4653
		memset(parms.ac_name, 0, sizeof(parms.ac_name));
4654
4655
	if (ioctl(s, PPPOESETPARMS, &parms))
4656
		err(1, "PPPOESETPARMS");
4657
}
4658
4659
void
4660
spppauthinfo(struct sauthreq *spa, int d)
4661
{
4662
	bzero(spa, sizeof(struct sauthreq));
4663
4664
	ifr.ifr_data = (caddr_t)spa;
4665
	spa->cmd = d == 0 ? SPPPIOGMAUTH : SPPPIOGHAUTH;
4666
	if (ioctl(s, SIOCGSPPPPARAMS, &ifr) == -1)
4667
		err(1, "SIOCGSPPPPARAMS(SPPPIOGXAUTH)");
4668
}
4669
4670
void
4671
setspppproto(const char *val, int d)
4672
{
4673
	struct sauthreq spa;
4674
4675
	spppauthinfo(&spa, d);
4676
4677
	if (strcmp(val, "pap") == 0)
4678
		spa.proto = PPP_PAP;
4679
	else if (strcmp(val, "chap") == 0)
4680
		spa.proto = PPP_CHAP;
4681
	else if (strcmp(val, "none") == 0)
4682
		spa.proto = 0;
4683
	else
4684
		errx(1, "setpppproto");
4685
4686
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4687
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4688
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4689
}
4690
4691
void
4692
setsppppeerproto(const char *val, int d)
4693
{
4694
	setspppproto(val, 1);
4695
}
4696
4697
void
4698
setspppname(const char *val, int d)
4699
{
4700
	struct sauthreq spa;
4701
4702
	spppauthinfo(&spa, d);
4703
4704
	if (spa.proto == 0)
4705
		errx(1, "unspecified protocol");
4706
	if (strlcpy(spa.name, val, sizeof(spa.name)) >= sizeof(spa.name))
4707
		errx(1, "setspppname");
4708
4709
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4710
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4711
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4712
}
4713
4714
void
4715
setsppppeername(const char *val, int d)
4716
{
4717
	setspppname(val, 1);
4718
}
4719
4720
void
4721
setspppkey(const char *val, int d)
4722
{
4723
	struct sauthreq spa;
4724
4725
	spppauthinfo(&spa, d);
4726
4727
	if (spa.proto == 0)
4728
		errx(1, "unspecified protocol");
4729
	if (strlcpy(spa.secret, val, sizeof(spa.secret)) >= sizeof(spa.secret))
4730
		errx(1, "setspppkey");
4731
4732
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4733
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4734
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4735
}
4736
4737
void
4738
setsppppeerkey(const char *val, int d)
4739
{
4740
	setspppkey(val, 1);
4741
}
4742
4743
void
4744
setsppppeerflag(const char *val, int d)
4745
{
4746
	struct sauthreq spa;
4747
	int flag;
4748
4749
	spppauthinfo(&spa, 1);
4750
4751
	if (spa.proto == 0)
4752
		errx(1, "unspecified protocol");
4753
	if (strcmp(val, "callin") == 0)
4754
		flag = AUTHFLAG_NOCALLOUT;
4755
	else if (strcmp(val, "norechallenge") == 0)
4756
		flag = AUTHFLAG_NORECHALLENGE;
4757
	else
4758
		errx(1, "setppppeerflags");
4759
4760
	if (d)
4761
		spa.flags &= ~flag;
4762
	else
4763
		spa.flags |= flag;
4764
4765
	spa.cmd = SPPPIOSHAUTH;
4766
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4767
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4768
}
4769
4770
void
4771
unsetsppppeerflag(const char *val, int d)
4772
{
4773
	setsppppeerflag(val, 1);
4774
}
4775
4776
void
4777
sppp_printproto(const char *name, struct sauthreq *auth)
4778
{
4779
	if (auth->proto == 0)
4780
		return;
4781
	printf("%sproto ", name);
4782
	switch (auth->proto) {
4783
	case PPP_PAP:
4784
		printf("pap ");
4785
		break;
4786
	case PPP_CHAP:
4787
		printf("chap ");
4788
		break;
4789
	default:
4790
		printf("0x%04x ", auth->proto);
4791
		break;
4792
	}
4793
	if (auth->name[0])
4794
		printf("%sname \"%s\" ", name, auth->name);
4795
	if (auth->secret[0])
4796
		printf("%skey \"%s\" ", name, auth->secret);
4797
}
4798
4799
void
4800
sppp_status(void)
4801
{
4802
2548
	struct spppreq spr;
4803
1274
	struct sauthreq spa;
4804
4805
1274
	bzero(&spr, sizeof(spr));
4806
4807
1274
	ifr.ifr_data = (caddr_t)&spr;
4808
1274
	spr.cmd = SPPPIOGDEFS;
4809
1274
	if (ioctl(s, SIOCGSPPPPARAMS, &ifr) == -1) {
4810
1274
		return;
4811
	}
4812
4813
	if (spr.phase == PHASE_DEAD)
4814
		return;
4815
	printf("\tsppp: phase ");
4816
	switch (spr.phase) {
4817
	case PHASE_ESTABLISH:
4818
		printf("establish ");
4819
		break;
4820
	case PHASE_TERMINATE:
4821
		printf("terminate ");
4822
		break;
4823
	case PHASE_AUTHENTICATE:
4824
		printf("authenticate ");
4825
		break;
4826
	case PHASE_NETWORK:
4827
		printf("network ");
4828
		break;
4829
	default:
4830
		printf("illegal ");
4831
		break;
4832
	}
4833
4834
	spppauthinfo(&spa, 0);
4835
	sppp_printproto("auth", &spa);
4836
	spppauthinfo(&spa, 1);
4837
	sppp_printproto("peer", &spa);
4838
	if (spa.flags & AUTHFLAG_NOCALLOUT)
4839
		printf("callin ");
4840
	if (spa.flags & AUTHFLAG_NORECHALLENGE)
4841
		printf("norechallenge ");
4842
	putchar('\n');
4843
1274
}
4844
4845
void
4846
setkeepalive(const char *timeout, const char *count)
4847
{
4848
	const char *errmsg = NULL;
4849
	struct ifkalivereq ikar;
4850
	int t, c;
4851
4852
	t = strtonum(timeout, 1, 3600, &errmsg);
4853
	if (errmsg)
4854
		errx(1, "keepalive period %s: %s", timeout, errmsg);
4855
	c = strtonum(count, 2, 600, &errmsg);
4856
	if (errmsg)
4857
		errx(1, "keepalive count %s: %s", count, errmsg);
4858
4859
	strlcpy(ikar.ikar_name, name, sizeof(ikar.ikar_name));
4860
	ikar.ikar_timeo = t;
4861
	ikar.ikar_cnt = c;
4862
	if (ioctl(s, SIOCSETKALIVE, (caddr_t)&ikar) < 0)
4863
		warn("SIOCSETKALIVE");
4864
}
4865
4866
void
4867
unsetkeepalive(const char *val, int d)
4868
{
4869
	struct ifkalivereq ikar;
4870
4871
	bzero(&ikar, sizeof(ikar));
4872
	strlcpy(ikar.ikar_name, name, sizeof(ikar.ikar_name));
4873
	if (ioctl(s, SIOCSETKALIVE, (caddr_t)&ikar) < 0)
4874
		warn("SIOCSETKALIVE");
4875
}
4876
4877
void
4878
setifpriority(const char *id, int param)
4879
{
4880
	const char *errmsg = NULL;
4881
	int prio;
4882
4883
	prio = strtonum(id, 0, 15, &errmsg);
4884
	if (errmsg)
4885
		errx(1, "priority %s: %s", id, errmsg);
4886
4887
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
4888
	ifr.ifr_metric = prio;
4889
	if (ioctl(s, SIOCSIFPRIORITY, (caddr_t)&ifr) < 0)
4890
		warn("SIOCSIFPRIORITY");
4891
}
4892
4893
4894
const struct umb_valdescr umb_regstate[] = MBIM_REGSTATE_DESCRIPTIONS;
4895
const struct umb_valdescr umb_dataclass[] = MBIM_DATACLASS_DESCRIPTIONS;
4896
const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
4897
const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS;
4898
const struct umb_valdescr umb_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS;
4899
const struct umb_valdescr umb_actstate[] = MBIM_ACTIVATION_STATE_DESCRIPTIONS;
4900
4901
const struct umb_valdescr umb_classalias[] = {
4902
	{ MBIM_DATACLASS_GPRS | MBIM_DATACLASS_EDGE, "2g" },
4903
	{ MBIM_DATACLASS_UMTS | MBIM_DATACLASS_HSDPA | MBIM_DATACLASS_HSUPA,
4904
	    "3g" },
4905
	{ MBIM_DATACLASS_LTE, "4g" },
4906
	{ 0, NULL }
4907
};
4908
4909
int
4910
umb_descr2val(const struct umb_valdescr *vdp, char *str)
4911
{
4912
	while (vdp->descr != NULL) {
4913
		if (!strcasecmp(vdp->descr, str))
4914
			return vdp->val;
4915
		vdp++;
4916
	}
4917
	return 0;
4918
}
4919
4920
void
4921
umb_status(void)
4922
{
4923
2548
	struct umb_info mi;
4924
1274
	char	 provider[UMB_PROVIDERNAME_MAXLEN+1];
4925
1274
	char	 roamingtxt[UMB_ROAMINGTEXT_MAXLEN+1];
4926
1274
	char	 devid[UMB_DEVID_MAXLEN+1];
4927
1274
	char	 fwinfo[UMB_FWINFO_MAXLEN+1];
4928
1274
	char	 hwinfo[UMB_HWINFO_MAXLEN+1];
4929
1274
	char	 sid[UMB_SUBSCRIBERID_MAXLEN+1];
4930
1274
	char	 iccid[UMB_ICCID_MAXLEN+1];
4931
1274
	char	 apn[UMB_APN_MAXLEN+1];
4932
1274
	char	 pn[UMB_PHONENR_MAXLEN+1];
4933
	int	 i, n;
4934
4935
1274
	memset((char *)&mi, 0, sizeof(mi));
4936
1274
	ifr.ifr_data = (caddr_t)&mi;
4937
1274
	if (ioctl(s, SIOCGUMBINFO, (caddr_t)&ifr) == -1)
4938
1274
		return;
4939
4940
	if (mi.nwerror) {
4941
		/* 3GPP 24.008 Cause Code */
4942
		printf("\terror: ");
4943
		switch (mi.nwerror) {
4944
		case 2:
4945
			printf("SIM not activated");
4946
			break;
4947
		case 4:
4948
			printf("Roaming not supported");
4949
			break;
4950
		case 6:
4951
			printf("SIM reported stolen");
4952
			break;
4953
		case 7:
4954
			printf("No GPRS subscription");
4955
			break;
4956
		case 8:
4957
			printf("GPRS and non-GPRS services not allowed");
4958
			break;
4959
		case 11:
4960
			printf("Subscription expired");
4961
			break;
4962
		case 12:
4963
			printf("Subscription does not cover current location");
4964
			break;
4965
		case 13:
4966
			printf("No roaming in this location");
4967
			break;
4968
		case 14:
4969
			printf("GPRS not supported");
4970
			break;
4971
		case 15:
4972
			printf("No subscription for the service");
4973
			break;
4974
		case 17:
4975
			printf("Registration failed");
4976
			break;
4977
		case 22:
4978
			printf("Network congestion");
4979
			break;
4980
		default:
4981
			printf("Error code %d", mi.nwerror);
4982
			break;
4983
		}
4984
		printf("\n");
4985
	}
4986
4987
	printf("\troaming %s registration %s",
4988
	    mi.enable_roaming ? "enabled" : "disabled",
4989
	    umb_val2descr(umb_regstate, mi.regstate));
4990
	utf16_to_char(mi.roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
4991
	    roamingtxt, sizeof (roamingtxt));
4992
	if (roamingtxt[0])
4993
		printf(" [%s]", roamingtxt);
4994
	printf("\n");
4995
4996
	if (showclasses)
4997
		umb_printclasses("available classes", mi.supportedclasses);
4998
	printf("\tstate %s cell-class %s",
4999
	    umb_val2descr(umb_istate, mi.state),
5000
	    umb_val2descr(umb_dataclass, mi.highestclass));
5001
	if (mi.rssi != UMB_VALUE_UNKNOWN && mi.rssi != 0)
5002
		printf(" rssi %ddBm", mi.rssi);
5003
	if (mi.uplink_speed != 0 || mi.downlink_speed != 0) {
5004
		char s[2][FMT_SCALED_STRSIZE];
5005
		if (fmt_scaled(mi.uplink_speed, s[0]) != 0)
5006
			snprintf(s[0], sizeof (s[0]), "%llu", mi.uplink_speed);
5007
		if (fmt_scaled(mi.downlink_speed, s[1]) != 0)
5008
			snprintf(s[1], sizeof (s[1]), "%llu", mi.downlink_speed);
5009
		printf(" speed %sps up %sps down", s[0], s[1]);
5010
	}
5011
	printf("\n");
5012
5013
	printf("\tSIM %s PIN ", umb_val2descr(umb_simstate, mi.sim_state));
5014
	switch (mi.pin_state) {
5015
	case UMB_PIN_REQUIRED:
5016
		printf("required");
5017
		break;
5018
	case UMB_PIN_UNLOCKED:
5019
		printf("valid");
5020
		break;
5021
	case UMB_PUK_REQUIRED:
5022
		printf("locked (PUK required)");
5023
		break;
5024
	default:
5025
		printf("unknown state (%d)", mi.pin_state);
5026
		break;
5027
	}
5028
	if (mi.pin_attempts_left != UMB_VALUE_UNKNOWN)
5029
		printf(" (%d attempts left)", mi.pin_attempts_left);
5030
	printf("\n");
5031
5032
	utf16_to_char(mi.sid, UMB_SUBSCRIBERID_MAXLEN, sid, sizeof (sid));
5033
	utf16_to_char(mi.iccid, UMB_ICCID_MAXLEN, iccid, sizeof (iccid));
5034
	utf16_to_char(mi.provider, UMB_PROVIDERNAME_MAXLEN,
5035
	    provider, sizeof (provider));
5036
	if (sid[0] || iccid[0] || provider[0]) {
5037
		printf("\t");
5038
		n = 0;
5039
		if (sid[0])
5040
			printf("%ssubscriber-id %s", n++ ? " " : "", sid);
5041
		if (iccid[0])
5042
			printf("%sICC-id %s", n++ ? " " : "", iccid);
5043
		if (provider[0])
5044
			printf("%sprovider %s", n ? " " : "", provider);
5045
		printf("\n");
5046
	}
5047
5048
	utf16_to_char(mi.hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof (hwinfo));
5049
	utf16_to_char(mi.devid, UMB_DEVID_MAXLEN, devid, sizeof (devid));
5050
	utf16_to_char(mi.fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof (fwinfo));
5051
	if (hwinfo[0] || devid[0] || fwinfo[0]) {
5052
		printf("\t");
5053
		n = 0;
5054
		if (hwinfo[0])
5055
			printf("%sdevice %s", n++ ? " " : "", hwinfo);
5056
		if (devid[0]) {
5057
			printf("%s", n++ ? " " : "");
5058
			switch (mi.cellclass) {
5059
			case MBIM_CELLCLASS_GSM:
5060
				printf("IMEI");
5061
				break;
5062
			case MBIM_CELLCLASS_CDMA:
5063
				n = strlen(devid);
5064
				if (n == 8 || n == 11) {
5065
					printf("ESN");
5066
					break;
5067
				} else if (n == 14 || n == 18) {
5068
					printf("MEID");
5069
					break;
5070
				}
5071
				/*FALLTHROUGH*/
5072
			default:
5073
				printf("ID");
5074
				break;
5075
			}
5076
			printf(" %s", devid);
5077
		}
5078
		if (fwinfo[0])
5079
			printf("%sfirmware %s", n++ ? " " : "", fwinfo);
5080
		printf("\n");
5081
	}
5082
5083
	utf16_to_char(mi.pn, UMB_PHONENR_MAXLEN, pn, sizeof (pn));
5084
	utf16_to_char(mi.apn, UMB_APN_MAXLEN, apn, sizeof (apn));
5085
	if (pn[0] || apn[0]) {
5086
		printf("\t");
5087
		n = 0;
5088
		if (pn[0])
5089
			printf("%sphone# %s", n++ ? " " : "", pn);
5090
		if (apn[0])
5091
			printf("%sAPN %s", n++ ? " " : "", apn);
5092
		printf("\n");
5093
	}
5094
5095
	for (i = 0, n = 0; i < UMB_MAX_DNSSRV; i++) {
5096
		if (mi.ipv4dns[i] == INADDR_ANY)
5097
			break;
5098
		printf("%s %s", n++ ? "" : "\tdns",
5099
		    inet_ntoa(*(struct in_addr *)&mi.ipv4dns[i]));
5100
	}
5101
	if (n)
5102
		printf("\n");
5103
1274
}
5104
5105
void
5106
umb_printclasses(char *tag, int c)
5107
{
5108
	int	 i;
5109
	char	*sep = "";
5110
5111
	printf("\t%s: ", tag);
5112
	i = 0;
5113
	while (umb_dataclass[i].descr) {
5114
		if (umb_dataclass[i].val & c) {
5115
			printf("%s%s", sep, umb_dataclass[i].descr);
5116
			sep = ",";
5117
		}
5118
		i++;
5119
	}
5120
	printf("\n");
5121
}
5122
5123
int
5124
umb_parse_classes(const char *spec)
5125
{
5126
	char	*optlist, *str;
5127
	int	 c = 0, v;
5128
5129
	if ((optlist = strdup(spec)) == NULL)
5130
		err(1, "strdup");
5131
	str = strtok(optlist, ",");
5132
	while (str != NULL) {
5133
		if ((v = umb_descr2val(umb_dataclass, str)) != 0 ||
5134
		    (v = umb_descr2val(umb_classalias, str)) != 0)
5135
			c |= v;
5136
		str = strtok(NULL, ",");
5137
	}
5138
	free(optlist);
5139
	return c;
5140
}
5141
5142
void
5143
umb_setpin(const char *pin, int d)
5144
{
5145
	umb_pinop(MBIM_PIN_OP_ENTER, 0, pin, NULL);
5146
}
5147
5148
void
5149
umb_chgpin(const char *pin, const char *newpin)
5150
{
5151
	umb_pinop(MBIM_PIN_OP_CHANGE, 0, pin, newpin);
5152
}
5153
5154
void
5155
umb_puk(const char *pin, const char *newpin)
5156
{
5157
	umb_pinop(MBIM_PIN_OP_ENTER, 1, pin, newpin);
5158
}
5159
5160
void
5161
umb_pinop(int op, int is_puk, const char *pin, const char *newpin)
5162
{
5163
	struct umb_parameter mp;
5164
5165
	memset(&mp, 0, sizeof (mp));
5166
	ifr.ifr_data = (caddr_t)&mp;
5167
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5168
		err(1, "SIOCGUMBPARAM");
5169
5170
	mp.op = op;
5171
	mp.is_puk = is_puk;
5172
	if ((mp.pinlen = char_to_utf16(pin, (uint16_t *)mp.pin,
5173
	    sizeof (mp.pin))) == -1)
5174
		errx(1, "PIN too long");
5175
5176
	if (newpin) {
5177
		if ((mp.newpinlen = char_to_utf16(newpin, (uint16_t *)mp.newpin,
5178
		    sizeof (mp.newpin))) == -1)
5179
		errx(1, "new PIN too long");
5180
	}
5181
5182
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5183
		err(1, "SIOCSUMBPARAM");
5184
}
5185
5186
void
5187
umb_apn(const char *apn, int d)
5188
{
5189
	struct umb_parameter mp;
5190
5191
	memset(&mp, 0, sizeof (mp));
5192
	ifr.ifr_data = (caddr_t)&mp;
5193
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5194
		err(1, "SIOCGUMBPARAM");
5195
5196
	if (d != 0)
5197
		memset(mp.apn, 0, sizeof (mp.apn));
5198
	else if ((mp.apnlen = char_to_utf16(apn, mp.apn,
5199
	    sizeof (mp.apn))) == -1)
5200
		errx(1, "APN too long");
5201
5202
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5203
		err(1, "SIOCSUMBPARAM");
5204
}
5205
5206
void
5207
umb_setclass(const char *val, int d)
5208
{
5209
	struct umb_parameter mp;
5210
5211
	if (val == NULL) {
5212
		if (showclasses)
5213
			usage();
5214
		showclasses = 1;
5215
		return;
5216
	}
5217
5218
	memset(&mp, 0, sizeof (mp));
5219
	ifr.ifr_data = (caddr_t)&mp;
5220
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5221
		err(1, "SIOCGUMBPARAM");
5222
	if (d != -1)
5223
		mp.preferredclasses = umb_parse_classes(val);
5224
	else
5225
		mp.preferredclasses = MBIM_DATACLASS_NONE;
5226
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5227
		err(1, "SIOCSUMBPARAM");
5228
}
5229
5230
void
5231
umb_roaming(const char *val, int d)
5232
{
5233
	struct umb_parameter mp;
5234
5235
	memset(&mp, 0, sizeof (mp));
5236
	ifr.ifr_data = (caddr_t)&mp;
5237
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5238
		err(1, "SIOCGUMBPARAM");
5239
	mp.roaming = d;
5240
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5241
		err(1, "SIOCSUMBPARAM");
5242
}
5243
5244
void
5245
utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
5246
{
5247
	uint16_t c;
5248
5249
	while (outlen > 0) {
5250
		c = inlen > 0 ? letoh16(*in) : 0;
5251
		if (c == 0 || --outlen == 0) {
5252
			/* always NUL terminate result */
5253
			*out = '\0';
5254
			break;
5255
		}
5256
		*out++ = isascii(c) ? (char)c : '?';
5257
		in++;
5258
		inlen--;
5259
	}
5260
}
5261
5262
int
5263
char_to_utf16(const char *in, uint16_t *out, size_t outlen)
5264
{
5265
	int	 n = 0;
5266
	uint16_t c;
5267
5268
	for (;;) {
5269
		c = *in++;
5270
5271
		if (c == '\0') {
5272
			/*
5273
			 * NUL termination is not required, but zero out the
5274
			 * residual buffer
5275
			 */
5276
			memset(out, 0, outlen);
5277
			return n;
5278
		}
5279
		if (outlen < sizeof (*out))
5280
			return -1;
5281
5282
		*out++ = htole16(c);
5283
		n += sizeof (*out);
5284
		outlen -= sizeof (*out);
5285
	}
5286
}
5287
5288
#endif
5289
5290
#define SIN(x) ((struct sockaddr_in *) &(x))
5291
struct sockaddr_in *sintab[] = {
5292
SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
5293
SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
5294
5295
void
5296
in_getaddr(const char *s, int which)
5297
{
5298
1854
	struct sockaddr_in *sin = sintab[which], tsin;
5299
	struct hostent *hp;
5300
	struct netent *np;
5301
	int bits, l;
5302
927
	char p[3];
5303
5304
927
	bzero(&tsin, sizeof(tsin));
5305
927
	sin->sin_len = sizeof(*sin);
5306
927
	if (which != MASK)
5307
903
		sin->sin_family = AF_INET;
5308
5309

2669
	if (which == ADDR && strrchr(s, '/') != NULL &&
5310
859
	    (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
5311
859
	    sizeof(tsin.sin_addr))) != -1) {
5312
859
		l = snprintf(p, sizeof(p), "%d", bits);
5313
859
		if (l >= sizeof(p) || l == -1)
5314
			errx(1, "%d: bad prefixlen", bits);
5315
859
		in_getprefix(p, MASK);
5316
859
		memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
5317
927
	} else if (inet_aton(s, &sin->sin_addr) == 0) {
5318
		if ((hp = gethostbyname(s)))
5319
			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
5320
		else if ((np = getnetbyname(s)))
5321
			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
5322
		else
5323
			errx(1, "%s: bad value", s);
5324
	}
5325
927
}
5326
5327
/* ARGSUSED */
5328
void
5329
in_getprefix(const char *plen, int which)
5330
{
5331
1718
	struct sockaddr_in *sin = sintab[which];
5332
859
	const char *errmsg = NULL;
5333
	u_char *cp;
5334
	int len;
5335
5336
859
	len = strtonum(plen, 0, 32, &errmsg);
5337
859
	if (errmsg)
5338
		errx(1, "prefix %s: %s", plen, errmsg);
5339
5340
859
	sin->sin_len = sizeof(*sin);
5341
859
	if (which != MASK)
5342
		sin->sin_family = AF_INET;
5343
859
	if ((len == 0) || (len == 32)) {
5344
784
		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
5345
784
		return;
5346
	}
5347
75
	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
5348
504
	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
5349
177
		*cp++ = 0xff;
5350
75
	if (len)
5351
24
		*cp = 0xff << (8 - len);
5352
934
}
5353
5354
/*
5355
 * Print a value a la the %b format of the kernel's printf
5356
 */
5357
void
5358
printb(char *s, unsigned int v, unsigned char *bits)
5359
{
5360
	int i, any = 0;
5361
	unsigned char c;
5362
5363

3822
	if (bits && *bits == 8)
5364
		printf("%s=%o", s, v);
5365
	else
5366
1274
		printf("%s=%x", s, v);
5367
5368
1274
	if (bits) {
5369
1274
		bits++;
5370
2548
		putchar('<');
5371
53508
		while ((i = *bits++)) {
5372
25480
			if (v & (1 << (i-1))) {
5373
4333
				if (any)
5374
6418
					putchar(',');
5375
				any = 1;
5376
68276
				for (; (c = *bits) > 32; bits++)
5377
59610
					putchar(c);
5378
			} else
5379
341952
				for (; *bits > 32; bits++)
5380
					;
5381
		}
5382
2548
		putchar('>');
5383
	}
5384
1274
}
5385
5386
/*
5387
 * A simple version of printb for status output
5388
 */
5389
void
5390
printb_status(unsigned short v, unsigned char *bits)
5391
{
5392
	int i, any = 0;
5393
	unsigned char c;
5394
5395
	if (bits) {
5396
		bits++;
5397
		while ((i = *bits++)) {
5398
			if (v & (1 << (i-1))) {
5399
				if (any)
5400
					putchar(',');
5401
				any = 1;
5402
				for (; (c = *bits) > 32; bits++)
5403
					putchar(tolower(c));
5404
			} else
5405
				for (; *bits > 32; bits++)
5406
					;
5407
		}
5408
	}
5409
}
5410
5411
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
5412
struct sockaddr_in6 *sin6tab[] = {
5413
SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
5414
SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
5415
5416
void
5417
in6_getaddr(const char *s, int which)
5418
{
5419
72
	struct sockaddr_in6 *sin6 = sin6tab[which];
5420
36
	struct addrinfo hints, *res;
5421
36
	char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
5422
	int error;
5423
5424
36
	memset(&hints, 0, sizeof(hints));
5425
36
	hints.ai_family = AF_INET6;
5426
36
	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
5427
5428

72
	if (which == ADDR && strchr(s, '/') != NULL) {
5429
36
		if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
5430
			errx(1, "%s: bad value", s);
5431
36
		pfxlen = strchr(buf, '/');
5432
36
		*pfxlen++ = '\0';
5433
		s = buf;
5434
36
		in6_getprefix(pfxlen, MASK);
5435
36
		explicit_prefix = 1;
5436
36
	}
5437
5438
36
	error = getaddrinfo(s, "0", &hints, &res);
5439
36
	if (error)
5440
		errx(1, "%s: %s", s, gai_strerror(error));
5441
36
	if (res->ai_addrlen != sizeof(struct sockaddr_in6))
5442
		errx(1, "%s: bad value", s);
5443
36
	memcpy(sin6, res->ai_addr, res->ai_addrlen);
5444
#ifdef __KAME__
5445

36
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
5446
	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
5447
	    sin6->sin6_scope_id) {
5448
		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
5449
		    htons(sin6->sin6_scope_id & 0xffff);
5450
		sin6->sin6_scope_id = 0;
5451
	}
5452
#endif /* __KAME__ */
5453
36
	freeaddrinfo(res);
5454
36
}
5455
5456
void
5457
in6_getprefix(const char *plen, int which)
5458
{
5459
168
	struct sockaddr_in6 *sin6 = sin6tab[which];
5460
84
	const char *errmsg = NULL;
5461
	u_char *cp;
5462
	int len;
5463
5464
84
	len = strtonum(plen, 0, 128, &errmsg);
5465
84
	if (errmsg)
5466
		errx(1, "prefix %s: %s", plen, errmsg);
5467
5468
84
	sin6->sin6_len = sizeof(*sin6);
5469
84
	if (which != MASK)
5470
		sin6->sin6_family = AF_INET6;
5471
84
	if ((len == 0) || (len == 128)) {
5472
		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
5473
		return;
5474
	}
5475
84
	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
5476
1512
	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
5477
672
		*cp++ = 0xff;
5478
84
	if (len)
5479
		*cp = 0xff << (8 - len);
5480
168
}
5481
5482
int
5483
prefix(void *val, int size)
5484
{
5485
	u_char *nam = (u_char *)val;
5486
	int byte, bit, plen = 0;
5487
5488
11976
	for (byte = 0; byte < size; byte++, plen += 8)
5489
5586
		if (nam[byte] != 0xff)
5490
			break;
5491
504
	if (byte == size)
5492
150
		return (plen);
5493
708
	for (bit = 7; bit != 0; bit--, plen++)
5494
354
		if (!(nam[byte] & (1 << bit)))
5495
			break;
5496
5664
	for (; bit != 0; bit--)
5497
2478
		if (nam[byte] & (1 << bit))
5498
			return (0);
5499
354
	byte++;
5500
5664
	for (; byte < size; byte++)
5501
2478
		if (nam[byte])
5502
			return (0);
5503
354
	return (plen);
5504
504
}
5505
5506
/* Print usage and exit  */
5507
__dead void
5508
usage(void)
5509
{
5510
	fprintf(stderr,
5511
	    "usage: ifconfig [-AaC] [interface] [address_family] "
5512
	    "[address [dest_address]]\n"
5513
	    "\t\t[parameters]\n");
5514
	exit(1);
5515
}
5516
5517
void
5518
getifgroups(void)
5519
{
5520
	int			 len, cnt;
5521
2548
	struct ifgroupreq	 ifgr;
5522
	struct ifg_req		*ifg;
5523
5524
1274
	memset(&ifgr, 0, sizeof(ifgr));
5525
1274
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
5526
5527
1274
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
5528
		if (errno == EINVAL || errno == ENOTTY)
5529
			return;
5530
		else
5531
			err(1, "SIOCGIFGROUP");
5532
	}
5533
5534
1274
	len = ifgr.ifgr_len;
5535
1274
	ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
5536
	    sizeof(struct ifg_req));
5537
1274
	if (ifgr.ifgr_groups == NULL)
5538
		err(1, "getifgroups");
5539
1274
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
5540
		err(1, "SIOCGIFGROUP");
5541
5542
	cnt = 0;
5543
1274
	ifg = ifgr.ifgr_groups;
5544
7644
	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
5545
2548
		len -= sizeof(struct ifg_req);
5546
2548
		if (strcmp(ifg->ifgrq_group, "all")) {
5547
1274
			if (cnt == 0)
5548
1274
				printf("\tgroups:");
5549
1274
			cnt++;
5550
1274
			printf(" %s", ifg->ifgrq_group);
5551
1274
		}
5552
	}
5553
1274
	if (cnt)
5554
1274
		printf("\n");
5555
5556
1274
	free(ifgr.ifgr_groups);
5557
2548
}
5558
5559
#ifndef SMALL
5560
void
5561
printifhwfeatures(const char *unused, int show)
5562
{
5563
	struct if_data ifrdat;
5564
5565
	if (!show) {
5566
		if (showcapsflag)
5567
			usage();
5568
		showcapsflag = 1;
5569
		return;
5570
	}
5571
	bzero(&ifrdat, sizeof(ifrdat));
5572
	ifr.ifr_data = (caddr_t)&ifrdat;
5573
	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
5574
		err(1, "SIOCGIFDATA");
5575
	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
5576
5577
	if (ioctl(s, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
5578
		if (ifr.ifr_hardmtu)
5579
			printf(" hardmtu %u", ifr.ifr_hardmtu);
5580
	}
5581
	putchar('\n');
5582
}
5583
#endif
5584
5585
char *
5586
sec2str(time_t total)
5587
{
5588
	static char result[256];
5589
	char *p = result;
5590
	char *end = &result[sizeof(result)];
5591
5592
192
	snprintf(p, end - p, "%lld", (long long)total);
5593
96
	return (result);
5594
}
5595
5596
/*ARGSUSED*/
5597
void
5598
setiflladdr(const char *addr, int param)
5599
{
5600
66
	struct ether_addr *eap, eabuf;
5601
5602
33
	if (!strcmp(addr, "random")) {
5603
		arc4random_buf(&eabuf, sizeof eabuf);
5604
		/* Non-multicast and claim it is a hardware address */
5605
		eabuf.ether_addr_octet[0] &= 0xfc;
5606
		eap = &eabuf;
5607
	} else {
5608
33
		eap = ether_aton(addr);
5609
33
		if (eap == NULL) {
5610
			warnx("malformed link-level address");
5611
			return;
5612
		}
5613
	}
5614
33
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5615
33
	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
5616
33
	ifr.ifr_addr.sa_family = AF_LINK;
5617
33
	bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
5618
33
	if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
5619
		warn("SIOCSIFLLADDR");
5620
66
}
5621
5622
#ifndef SMALL
5623
void
5624
setrdomain(const char *id, int param)
5625
{
5626
1790
	const char *errmsg = NULL;
5627
	int rdomainid;
5628
5629
895
	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
5630
895
	if (errmsg)
5631
		errx(1, "rdomain %s: %s", id, errmsg);
5632
5633
895
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5634
895
	ifr.ifr_rdomainid = rdomainid;
5635
895
	if (ioctl(s, SIOCSIFRDOMAIN, (caddr_t)&ifr) < 0)
5636
		warn("SIOCSIFRDOMAIN");
5637
895
}
5638
#endif
5639
5640
#ifndef SMALL
5641
void
5642
setpair(const char *val, int d)
5643
{
5644
24
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5645
12
	if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
5646
		errno = ENOENT;
5647
		err(1, "patch %s", val);
5648
	}
5649
12
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5650
		warn("SIOCSIFPAIR");
5651
12
}
5652
5653
void
5654
unsetpair(const char *val, int d)
5655
{
5656
	ifr.ifr_index = 0;
5657
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5658
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5659
		warn("SIOCSIFPAIR");
5660
}
5661
#endif
5662
5663
#ifdef SMALL
5664
void
5665
setignore(const char *id, int param)
5666
{
5667
	/* just digest the command */
5668
}
5669
#endif