GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ifconfig/ifconfig.c Lines: 207 2520 8.2 %
Date: 2016-12-06 Branches: 111 1912 5.8 %

Line Branch Exec Source
1
/*	$OpenBSD: ifconfig.c,v 1.324 2016/06/15 19:39:33 gerhard Exp $	*/
2
/*	$NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $	*/
3
4
/*
5
 * Copyright (c) 1983, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*-
34
 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
35
 * All rights reserved.
36
 *
37
 * This code is derived from software contributed to The NetBSD Foundation
38
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
39
 * NASA Ames Research Center.
40
 *
41
 * Redistribution and use in source and binary forms, with or without
42
 * modification, are permitted provided that the following conditions
43
 * are met:
44
 * 1. Redistributions of source code must retain the above copyright
45
 *    notice, this list of conditions and the following disclaimer.
46
 * 2. Redistributions in binary form must reproduce the above copyright
47
 *    notice, this list of conditions and the following disclaimer in the
48
 *    documentation and/or other materials provided with the distribution.
49
 *
50
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60
 * POSSIBILITY OF SUCH DAMAGE.
61
 */
62
63
#include <sys/types.h>
64
#include <sys/socket.h>
65
#include <sys/ioctl.h>
66
#include <sys/param.h>
67
68
#include <net/if.h>
69
#include <net/if_dl.h>
70
#include <net/if_media.h>
71
#include <net/if_types.h>
72
#include <netinet/in.h>
73
#include <netinet/in_var.h>
74
#include <netinet6/in6_var.h>
75
#include <netinet6/nd6.h>
76
#include <arpa/inet.h>
77
#include <netinet/ip_ipsp.h>
78
#include <netinet/if_ether.h>
79
#include <net/if_enc.h>
80
#include <net80211/ieee80211.h>
81
#include <net80211/ieee80211_ioctl.h>
82
#include <net/pfvar.h>
83
#include <net/if_pfsync.h>
84
#include <net/if_pflow.h>
85
#include <net/if_pppoe.h>
86
#include <net/if_trunk.h>
87
#include <net/if_sppp.h>
88
#include <net/ppp_defs.h>
89
90
#include <netinet/ip_carp.h>
91
92
#include <netdb.h>
93
94
#include <net/if_vlan_var.h>
95
96
#include <netmpls/mpls.h>
97
98
#include <ctype.h>
99
#include <err.h>
100
#include <errno.h>
101
#include <stdio.h>
102
#include <stdlib.h>
103
#include <string.h>
104
#include <unistd.h>
105
#include <limits.h>
106
#include <util.h>
107
#include <ifaddrs.h>
108
109
#include "brconfig.h"
110
#ifndef SMALL
111
#include <dev/usb/mbim.h>
112
#include <dev/usb/if_umb.h>
113
#endif /* SMALL */
114
115
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
116
#define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
117
118
#define HWFEATURESBITS							\
119
	"\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4"			\
120
	"\5VLAN_MTU\6VLAN_HWTAGGING\10CSUM_TCPv6"			\
121
	"\11CSUM_UDPv6\20WOL"
122
123
struct	ifreq		ifr, ridreq;
124
struct	in_aliasreq	in_addreq;
125
struct	in6_ifreq	ifr6;
126
struct	in6_ifreq	in6_ridreq;
127
struct	in6_aliasreq	in6_addreq;
128
struct	sockaddr_in	netmask;
129
130
#ifndef SMALL
131
struct	ifaliasreq	addreq;
132
133
int	wconfig = 0;
134
int	wcwconfig = 0;
135
struct	ifmpwreq	imrsave;
136
#endif /* SMALL */
137
138
char	name[IFNAMSIZ];
139
int	flags, xflags, setaddr, setipdst, doalias;
140
u_long	metric, mtu;
141
int	rdomainid;
142
int	llprio;
143
int	clearaddr, s;
144
int	newaddr = 0;
145
int	af = AF_INET;
146
int	explicit_prefix = 0;
147
int	Lflag = 1;
148
149
int	showmediaflag;
150
int	showcapsflag;
151
int	shownet80211chans;
152
int	shownet80211nodes;
153
int	showclasses;
154
155
void	notealias(const char *, int);
156
void	setifaddr(const char *, int);
157
void	setifrtlabel(const char *, int);
158
void	setiflladdr(const char *, int);
159
void	setifdstaddr(const char *, int);
160
void	setifflags(const char *, int);
161
void	setifxflags(const char *, int);
162
void	addaf(const char *, int);
163
void	removeaf(const char *, int);
164
void	setifbroadaddr(const char *, int);
165
void	setifmtu(const char *, int);
166
void	setifllprio(const char *, int);
167
void	setifnwid(const char *, int);
168
void	setifbssid(const char *, int);
169
void	setifnwkey(const char *, int);
170
void	setifwpa(const char *, int);
171
void	setifwpaprotos(const char *, int);
172
void	setifwpaakms(const char *, int);
173
void	setifwpaciphers(const char *, int);
174
void	setifwpagroupcipher(const char *, int);
175
void	setifwpakey(const char *, int);
176
void	setifchan(const char *, int);
177
void	setifscan(const char *, int);
178
void	setifnwflag(const char *, int);
179
void	unsetifnwflag(const char *, int);
180
void	setifnetmask(const char *, int);
181
void	setifprefixlen(const char *, int);
182
void	settunnel(const char *, const char *);
183
void	deletetunnel(const char *, int);
184
void	settunnelinst(const char *, int);
185
void	settunnelttl(const char *, int);
186
void	setvnetid(const char *, int);
187
void	delvnetid(const char *, int);
188
void	getvnetid(void);
189
void	setifparent(const char *, int);
190
void	delifparent(const char *, int);
191
void	getifparent(void);
192
void	setia6flags(const char *, int);
193
void	setia6pltime(const char *, int);
194
void	setia6vltime(const char *, int);
195
void	setia6lifetime(const char *, const char *);
196
void	setia6eui64(const char *, int);
197
void	setkeepalive(const char *, const char *);
198
void	unsetkeepalive(const char *, int);
199
void	setmedia(const char *, int);
200
void	setmediaopt(const char *, int);
201
void	setmediamode(const char *, int);
202
void	unsetmediamode(const char *, int);
203
void	clone_create(const char *, int);
204
void	clone_destroy(const char *, int);
205
void	unsetmediaopt(const char *, int);
206
void	setmediainst(const char *, int);
207
void	settimeslot(const char *, int);
208
void	timeslot_status(void);
209
void	setmpelabel(const char *, int);
210
void	process_mpw_commands(void);
211
void	setmpwencap(const char *, int);
212
void	setmpwlabel(const char *, const char *);
213
void	setmpwneighbor(const char *, int);
214
void	setmpwcontrolword(const char *, int);
215
void	setvlantag(const char *, int);
216
void	setvlandev(const char *, int);
217
void	unsetvlandev(const char *, int);
218
void	mpe_status(void);
219
void	mpw_status(void);
220
void	vlan_status(void);
221
void	setinstance(const char *, int);
222
int	main(int, char *[]);
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
	{ "vlan",	NEXTARG,	0,		setvlantag },
369
	{ "vlandev",	NEXTARG,	0,		setvlandev },
370
	{ "-vlandev",	1,		0,		unsetvlandev },
371
	{ "group",	NEXTARG,	0,		setifgroup },
372
	{ "-group",	NEXTARG,	0,		unsetifgroup },
373
	{ "autoconf",	1,		0,		setautoconf },
374
	{ "-autoconf",	-1,		0,		setautoconf },
375
	{ "trunkport",	NEXTARG,	0,		settrunkport },
376
	{ "-trunkport",	NEXTARG,	0,		unsettrunkport },
377
	{ "trunkproto",	NEXTARG,	0,		settrunkproto },
378
	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
379
	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
380
	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
381
	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
382
	{ "pltime",	NEXTARG,	0,		setia6pltime },
383
	{ "vltime",	NEXTARG,	0,		setia6vltime },
384
	{ "eui64",	0,		0,		setia6eui64 },
385
	{ "autoconfprivacy",	-IFXF_INET6_NOPRIVACY,	0,	setifxflags },
386
	{ "-autoconfprivacy",	IFXF_INET6_NOPRIVACY,	0,	setifxflags },
387
#ifndef SMALL
388
	{ "hwfeatures", NEXTARG0,	0,		printifhwfeatures },
389
	{ "metric",	NEXTARG,	0,		setifmetric },
390
	{ "powersave",	NEXTARG0,	0,		setifpowersave },
391
	{ "-powersave",	-1,		0,		setifpowersave },
392
	{ "priority",	NEXTARG,	0,		setifpriority },
393
	{ "rtlabel",	NEXTARG,	0,		setifrtlabel },
394
	{ "-rtlabel",	-1,		0,		setifrtlabel },
395
	{ "rdomain",	NEXTARG,	0,		setinstance },
396
	{ "mpls",	IFXF_MPLS,	0,		setifxflags },
397
	{ "-mpls",	-IFXF_MPLS,	0,		setifxflags },
398
	{ "mplslabel",	NEXTARG,	0,		setmpelabel },
399
	{ "mpwlabel",	NEXTARG2,	0,		NULL, setmpwlabel },
400
	{ "neighbor",	NEXTARG,	0,		setmpwneighbor },
401
	{ "controlword", 1,		0,		setmpwcontrolword },
402
	{ "-controlword", 0,		0,		setmpwcontrolword },
403
	{ "encap",	NEXTARG,	0,		setmpwencap },
404
	{ "advbase",	NEXTARG,	0,		setcarp_advbase },
405
	{ "advskew",	NEXTARG,	0,		setcarp_advskew },
406
	{ "carppeer",	NEXTARG,	0,		setcarppeer },
407
	{ "-carppeer",	1,		0,		unsetcarppeer },
408
	{ "pass",	NEXTARG,	0,		setcarp_passwd },
409
	{ "vhid",	NEXTARG,	0,		setcarp_vhid },
410
	{ "state",	NEXTARG,	0,		setcarp_state },
411
	{ "carpdev",	NEXTARG,	0,		setcarpdev },
412
	{ "carpnodes",	NEXTARG,	0,		setcarp_nodes },
413
	{ "balancing",	NEXTARG,	0,		setcarp_balancing },
414
	{ "syncdev",	NEXTARG,	0,		setpfsync_syncdev },
415
	{ "-syncdev",	1,		0,		unsetpfsync_syncdev },
416
	{ "syncif",	NEXTARG,	0,		setpfsync_syncdev },
417
	{ "-syncif",	1,		0,		unsetpfsync_syncdev },
418
	{ "syncpeer",	NEXTARG,	0,		setpfsync_syncpeer },
419
	{ "-syncpeer",	1,		0,		unsetpfsync_syncpeer },
420
	{ "maxupd",	NEXTARG,	0,		setpfsync_maxupd },
421
	{ "defer",	1,		0,		setpfsync_defer },
422
	{ "-defer",	0,		0,		setpfsync_defer },
423
	/* giftunnel is for backward compat */
424
	{ "giftunnel",  NEXTARG2,	0,		NULL, settunnel } ,
425
	{ "tunnel",	NEXTARG2,	0,		NULL, settunnel } ,
426
	{ "deletetunnel",  0,		0,		deletetunnel } ,
427
	{ "tunneldomain", NEXTARG,	0,		settunnelinst } ,
428
	{ "tunnelttl",	NEXTARG,	0,		settunnelttl } ,
429
	{ "vnetid",	NEXTARG,	0,		setvnetid },
430
	{ "-vnetid",	0,		0,		delvnetid },
431
	{ "parent",	NEXTARG,	0,		setifparent },
432
	{ "-parent",	1,		0,		delifparent },
433
	{ "pppoedev",	NEXTARG,	0,		setpppoe_dev },
434
	{ "pppoesvc",	NEXTARG,	0,		setpppoe_svc },
435
	{ "-pppoesvc",	1,		0,		setpppoe_svc },
436
	{ "pppoeac",	NEXTARG,	0,		setpppoe_ac },
437
	{ "-pppoeac",	1,		0,		setpppoe_ac },
438
	{ "timeslot",	NEXTARG,	0,		settimeslot },
439
	{ "authproto",	NEXTARG,	0,		setspppproto },
440
	{ "authname",	NEXTARG,	0,		setspppname },
441
	{ "authkey",	NEXTARG,	0,		setspppkey },
442
	{ "peerproto",	NEXTARG,	0,		setsppppeerproto },
443
	{ "peername",	NEXTARG,	0,		setsppppeername },
444
	{ "peerkey",	NEXTARG,	0,		setsppppeerkey },
445
	{ "peerflag",	NEXTARG,	0,		setsppppeerflag },
446
	{ "-peerflag",	NEXTARG,	0,		unsetsppppeerflag },
447
	{ "nwflag",	NEXTARG,	0,		setifnwflag },
448
	{ "-nwflag",	NEXTARG,	0,		unsetifnwflag },
449
	{ "flowsrc",	NEXTARG,	0,		setpflow_sender },
450
	{ "-flowsrc",	1,		0,		unsetpflow_sender },
451
	{ "flowdst",	NEXTARG,	0,		setpflow_receiver },
452
	{ "-flowdst", 1,		0,		unsetpflow_receiver },
453
	{ "pflowproto", NEXTARG,	0,		setpflowproto },
454
	{ "-inet",	AF_INET,	0,		removeaf },
455
	{ "-inet6",	AF_INET6,	0,		removeaf },
456
	{ "keepalive",	NEXTARG2,	0,		NULL, setkeepalive },
457
	{ "-keepalive",	1,		0,		unsetkeepalive },
458
	{ "add",	NEXTARG,	0,		bridge_add },
459
	{ "del",	NEXTARG,	0,		bridge_delete },
460
	{ "addspan",	NEXTARG,	0,		bridge_addspan },
461
	{ "delspan",	NEXTARG,	0,		bridge_delspan },
462
	{ "discover",	NEXTARG,	0,		setdiscover },
463
	{ "-discover",	NEXTARG,	0,		unsetdiscover },
464
	{ "blocknonip", NEXTARG,	0,		setblocknonip },
465
	{ "-blocknonip",NEXTARG,	0,		unsetblocknonip },
466
	{ "learn",	NEXTARG,	0,		setlearn },
467
	{ "-learn",	NEXTARG,	0,		unsetlearn },
468
	{ "stp",	NEXTARG,	0,		setstp },
469
	{ "-stp",	NEXTARG,	0,		unsetstp },
470
	{ "edge",	NEXTARG,	0,		setedge },
471
	{ "-edge",	NEXTARG,	0,		unsetedge },
472
	{ "autoedge",	NEXTARG,	0,		setautoedge },
473
	{ "-autoedge",	NEXTARG,	0,		unsetautoedge },
474
	{ "ptp",	NEXTARG,	0,		setptp },
475
	{ "-ptp",	NEXTARG,	0,		unsetptp },
476
	{ "autoptp",	NEXTARG,	0,		setautoptp },
477
	{ "-autoptp",	NEXTARG,	0,		unsetautoptp },
478
	{ "flush",	0,		0,		bridge_flush },
479
	{ "flushall",	0,		0,		bridge_flushall },
480
	{ "static",	NEXTARG2,	0,		NULL, bridge_addaddr },
481
	{ "deladdr",	NEXTARG,	0,		bridge_deladdr },
482
	{ "maxaddr",	NEXTARG,	0,		bridge_maxaddr },
483
	{ "addr",	0,		0,		bridge_addrs },
484
	{ "hellotime",	NEXTARG,	0,		bridge_hellotime },
485
	{ "fwddelay",	NEXTARG,	0,		bridge_fwddelay },
486
	{ "maxage",	NEXTARG,	0,		bridge_maxage },
487
	{ "proto",	NEXTARG,	0,		bridge_proto },
488
	{ "ifpriority",	NEXTARG2,	0,		NULL, bridge_ifprio },
489
	{ "ifcost",	NEXTARG2,	0,		NULL, bridge_ifcost },
490
	{ "-ifcost",	NEXTARG,	0,		bridge_noifcost },
491
	{ "timeout",	NEXTARG,	0,		bridge_timeout },
492
	{ "holdcnt",	NEXTARG,	0,		bridge_holdcnt },
493
	{ "spanpriority", NEXTARG,	0,		bridge_priority },
494
	{ "ipdst",	NEXTARG,	0,		setifipdst },
495
#if 0
496
	/* XXX `rule` special-cased below */
497
	{ "rule",	0,		0,		bridge_rule },
498
#endif
499
	{ "rules",	NEXTARG,	0,		bridge_rules },
500
	{ "rulefile",	NEXTARG,	0,		bridge_rulefile },
501
	{ "flushrule",	NEXTARG,	0,		bridge_flushrule },
502
	{ "description", NEXTARG,	0,		setifdesc },
503
	{ "descr",	NEXTARG,	0,		setifdesc },
504
	{ "-description", 1,		0,		unsetifdesc },
505
	{ "-descr",	1,		0,		unsetifdesc },
506
	{ "wol",	IFXF_WOL,	0,		setifxflags },
507
	{ "-wol",	-IFXF_WOL,	0,		setifxflags },
508
	{ "pin",	NEXTARG,	0,		umb_setpin },
509
	{ "chgpin",	NEXTARG2,	0,		NULL, umb_chgpin },
510
	{ "puk",	NEXTARG2,	0,		NULL, umb_puk },
511
	{ "apn",	NEXTARG,	0,		umb_apn },
512
	{ "-apn",	-1,		0,		umb_apn },
513
	{ "class",	NEXTARG0,	0,		umb_setclass },
514
	{ "-class",	-1,		0,		umb_setclass },
515
	{ "roaming",	1,		0,		umb_roaming },
516
	{ "-roaming",	0,		0,		umb_roaming },
517
	{ "patch",	NEXTARG,	0,		setpair },
518
	{ "-patch",	1,		0,		unsetpair },
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
void	usage(int);
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
102
{
628
102
	const struct afswtch *rafp = NULL;
629
102
	int create = 0;
630
102
	int Cflag = 0;
631
102
	int gflag = 0;
632
	int i;
633
634
	/* If no args at all, print all interfaces.  */
635
102
	if (argc < 2) {
636
		aflag = 1;
637
		printif(NULL, 0);
638
		exit(0);
639
	}
640
102
	argc--, argv++;
641
102
	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(1);
664
				break;
665
			}
666
		}
667
		if (nomore == 0) {
668
			argc--, argv++;
669
			if (argc < 1)
670
				usage(1);
671
			if (strlcpy(name, *argv, sizeof(name)) >= IFNAMSIZ)
672
				errx(1, "interface name '%s' too long", *argv);
673
		}
674
102
	} else if (strlcpy(name, *argv, sizeof(name)) >= IFNAMSIZ)
675
		errx(1, "interface name '%s' too long", *argv);
676
102
	argc--, argv++;
677
102
	if (argc > 0) {
678
298
		for (afp = rafp = afs; rafp->af_name; rafp++)
679
204
			if (strcmp(rafp->af_name, *argv) == 0) {
680
8
				afp = rafp;
681
8
				argc--;
682
8
				argv++;
683
8
				break;
684
			}
685
102
		rafp = afp;
686
102
		af = ifr.ifr_addr.sa_family = rafp->af_af;
687
	}
688
102
	if (Cflag) {
689
		if (argc > 0 || aflag)
690
			usage(1);
691
		list_cloners();
692
		exit(0);
693
	}
694
102
	if (gflag) {
695
		if (argc == 0)
696
			printgroupattribs(name);
697
		else
698
			setgroupattribs(name, argc, argv);
699
		exit(0);
700
	}
701
102
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
702
703
	/* initialization */
704
102
	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
705
102
	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

102
	if (argc > 0 && strcmp(argv[0], "create") == 0) {
712
		clone_create(argv[0], 0);
713
		argc--, argv++;
714
		if (argc == 0)
715
			exit(0);
716
	}
717
102
	if (aflag == 0) {
718

102
		create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
719
102
		(void)getinfo(&ifr, create);
720
	}
721
722

102
	if (argc != 0 && af == AF_INET6)
723
8
		addaf(name, AF_INET6);
724
725
380
	while (argc > 0) {
726
		const struct cmd *p;
727
728
23954
		for (p = cmds; p->c_name; p++)
729
23860
			if (strcmp(*argv, p->c_name) == 0)
730
184
				break;
731
#ifndef SMALL
732
278
		if (strcmp(*argv, "rule") == 0) {
733
			argc--, argv++;
734
			return bridge_rule(argc, argv, -1);
735
		}
736
#endif
737

278
		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

278
		if (p->c_func || p->c_func2) {
744
278
			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
278
			} else if (p->c_parameter == NEXTARG) {
763
88
nextarg:
764
88
				if (argv[1] == NULL)
765
					errx(1, "'%s' requires argument",
766
					    p->c_name);
767
88
				(*p->c_func)(argv[1], 0);
768
88
				argc--, argv++;
769
88
				actions = actions | A_SILENT | p->c_action;
770
190
			} 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
190
				(*p->c_func)(*argv, p->c_parameter);
781
190
				actions = actions | A_SILENT | p->c_action;
782
			}
783
		}
784
278
		argc--, argv++;
785
	}
786
787

102
	if (argc == 0 && actions == 0) {
788
		printif(ifr.ifr_name, aflag ? ifaliases : 1);
789
		exit(0);
790
	}
791
792
	/* Process any media commands that may have been issued. */
793
102
	process_media_commands();
794
795
#ifndef SMALL
796
	/* Process mpw commands */
797
102
	process_mpw_commands();
798
#endif
799
800

102
	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.
805
		 */
806
2
		setifprefixlen("64", 0);
807
		/* in6_getprefix("64", MASK) if MASK is available here... */
808
	}
809
810
102
	if (clearaddr) {
811
94
		(void) strlcpy(rafp->af_ridreq, name, sizeof(ifr.ifr_name));
812
94
		if (ioctl(s, rafp->af_difaddr, rafp->af_ridreq) < 0) {
813

10
			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
814
				/* means no previous address for interface */
815
			} else
816
				err(1, "SIOCDIFADDR");
817
		}
818
	}
819
102
	if (newaddr) {
820
94
		(void) strlcpy(rafp->af_addreq, name, sizeof(ifr.ifr_name));
821
94
		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
822
			err(1, "SIOCAIFADDR");
823
	}
824
102
	exit(0);
825
}
826
827
void
828
getsock(int naf)
829
102
{
830
	static int oaf = -1;
831
832
102
	if (oaf == naf)
833
		return;
834
102
	if (oaf != -1)
835
		close(s);
836
102
	s = socket(naf, SOCK_DGRAM, 0);
837
102
	if (s < 0)
838
		oaf = -1;
839
	else
840
102
		oaf = naf;
841
}
842
843
int
844
getinfo(struct ifreq *ifr, int create)
845
102
{
846
847
102
	getsock(af);
848
102
	if (s < 0)
849
		err(1, "socket");
850
102
	if (!isdigit((unsigned char)name[strlen(name) - 1]))
851
		return (-1);	/* ignore groups here */
852
102
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
853
4
		int oerrno = errno;
854
855
4
		if (!create)
856
			return (-1);
857
4
		if (ioctl(s, SIOCIFCREATE, (caddr_t)ifr) < 0) {
858
			errno = oerrno;
859
			return (-1);
860
		}
861
4
		if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0)
862
			return (-1);
863
	}
864
102
	flags = ifr->ifr_flags & 0xffff;
865
102
	if (ioctl(s, SIOCGIFXFLAGS, (caddr_t)ifr) < 0)
866
		ifr->ifr_flags = 0;
867
102
	xflags = ifr->ifr_flags;
868
102
	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0)
869
		metric = 0;
870
	else
871
102
		metric = ifr->ifr_metric;
872
#ifdef SMALL
873
	if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
874
#else
875

102
	if (is_bridge(name) || ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
876
#endif
877
		mtu = 0;
878
	else
879
102
		mtu = ifr->ifr_mtu;
880
#ifndef SMALL
881
102
	if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)ifr) < 0)
882
		rdomainid = 0;
883
	else
884
102
		rdomainid = ifr->ifr_rdomainid;
885
#endif
886
102
	if (ioctl(s, SIOCGIFLLPRIO, (caddr_t)ifr) < 0)
887
		llprio = 0;
888
	else
889
102
		llprio = ifr->ifr_llprio;
890
891
102
	return (0);
892
}
893
894
int
895
printgroup(char *groupname, int ifaliases)
896
{
897
	struct ifgroupreq	 ifgr;
898
	struct ifg_req		*ifg;
899
	int			 len, cnt = 0;
900
901
	getsock(AF_INET);
902
	bzero(&ifgr, sizeof(ifgr));
903
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
904
	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
905
		if (errno == EINVAL || errno == ENOTTY ||
906
		    errno == ENOENT)
907
			return (-1);
908
		else
909
			err(1, "SIOCGIFGMEMB");
910
	}
911
912
	len = ifgr.ifgr_len;
913
	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
914
		err(1, "printgroup");
915
	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
916
		err(1, "SIOCGIFGMEMB");
917
918
	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
919
	    ifg++) {
920
		len -= sizeof(struct ifg_req);
921
		printif(ifg->ifgrq_member, ifaliases);
922
		cnt++;
923
	}
924
	free(ifgr.ifgr_groups);
925
926
	return (cnt);
927
}
928
929
void
930
printgroupattribs(char *groupname)
931
{
932
	struct ifgroupreq	 ifgr;
933
934
	getsock(AF_INET);
935
	bzero(&ifgr, sizeof(ifgr));
936
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
937
	if (ioctl(s, SIOCGIFGATTR, (caddr_t)&ifgr) == -1)
938
		err(1, "SIOCGIFGATTR");
939
940
	printf("%s:", groupname);
941
	printf(" carp demote count %d", ifgr.ifgr_attrib.ifg_carp_demoted);
942
	printf("\n");
943
}
944
945
void
946
setgroupattribs(char *groupname, int argc, char *argv[])
947
{
948
	const char *errstr;
949
	char *p = argv[0];
950
	int neg = 1;
951
952
	struct ifgroupreq	 ifgr;
953
954
	getsock(AF_INET);
955
	bzero(&ifgr, sizeof(ifgr));
956
	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
957
958
	if (argc > 1) {
959
		neg = strtonum(argv[1], 0, 128, &errstr);
960
		if (errstr)
961
			errx(1, "invalid carp demotion: %s", errstr);
962
	}
963
964
	if (p[0] == '-') {
965
		neg = neg * -1;
966
		p++;
967
	}
968
	if (!strcmp(p, "carpdemote"))
969
		ifgr.ifgr_attrib.ifg_carp_demoted = neg;
970
	else
971
		usage(1);
972
973
	if (ioctl(s, SIOCSIFGATTR, (caddr_t)&ifgr) == -1)
974
		err(1, "SIOCSIFGATTR");
975
}
976
977
void
978
printif(char *ifname, int ifaliases)
979
{
980
	struct ifaddrs *ifap, *ifa;
981
	struct if_data *ifdata;
982
	const char *namep;
983
	char *oname = NULL;
984
	struct ifreq *ifrp;
985
	int count = 0, noinet = 1;
986
	size_t nlen = 0;
987
988
	if (aflag)
989
		ifname = NULL;
990
	if (ifname) {
991
		if ((oname = strdup(ifname)) == NULL)
992
			err(1, "strdup");
993
		nlen = strlen(oname);
994
		/* is it a group? */
995
		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
996
			if (printgroup(oname, ifaliases) != -1) {
997
				free(oname);
998
				return;
999
			}
1000
	}
1001
1002
	if (getifaddrs(&ifap) != 0)
1003
		err(1, "getifaddrs");
1004
1005
	namep = NULL;
1006
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1007
		if (oname) {
1008
			if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
1009
				/* must have exact match */
1010
				if (strcmp(oname, ifa->ifa_name) != 0)
1011
					continue;
1012
			} else {
1013
				/* partial match OK if it ends w/ digit */
1014
				if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
1015
				    !isdigit((unsigned char)ifa->ifa_name[nlen]))
1016
					continue;
1017
			}
1018
		}
1019
		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
1020
		if (ifa->ifa_addr->sa_family == AF_INET6) {
1021
			memset(&ifr6, 0, sizeof(ifr6));
1022
			memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
1023
			    MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
1024
			ifrp = (struct ifreq *)&ifr6;
1025
		} else {
1026
			memset(&ifr, 0, sizeof(ifr));
1027
			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
1028
			    MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
1029
			ifrp = &ifr;
1030
		}
1031
		strlcpy(name, ifa->ifa_name, sizeof(name));
1032
		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
1033
1034
		if (ifa->ifa_addr->sa_family == AF_LINK) {
1035
			namep = ifa->ifa_name;
1036
			if (getinfo(ifrp, 0) < 0)
1037
				continue;
1038
			ifdata = ifa->ifa_data;
1039
			status(1, (struct sockaddr_dl *)ifa->ifa_addr,
1040
			    ifdata->ifi_link_state);
1041
			count++;
1042
			noinet = 1;
1043
			continue;
1044
		}
1045
1046
		if (!namep || !strcmp(namep, ifa->ifa_name)) {
1047
			const struct afswtch *p;
1048
1049
			if (ifa->ifa_addr->sa_family == AF_INET &&
1050
			    ifaliases == 0 && noinet == 0)
1051
				continue;
1052
			if ((p = afp) != NULL) {
1053
				if (ifa->ifa_addr->sa_family == p->af_af)
1054
					p->af_status(1);
1055
			} else {
1056
				for (p = afs; p->af_name; p++) {
1057
					if (ifa->ifa_addr->sa_family ==
1058
					    p->af_af)
1059
						p->af_status(0);
1060
				}
1061
			}
1062
			count++;
1063
			if (ifa->ifa_addr->sa_family == AF_INET)
1064
				noinet = 0;
1065
			continue;
1066
		}
1067
	}
1068
	freeifaddrs(ifap);
1069
	free(oname);
1070
	if (count == 0) {
1071
		fprintf(stderr, "%s: no such interface\n", name);
1072
		exit(1);
1073
	}
1074
}
1075
1076
/*ARGSUSED*/
1077
void
1078
clone_create(const char *addr, int param)
1079
{
1080
1081
	/* We're called early... */
1082
	getsock(AF_INET);
1083
1084
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1085
	if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
1086
		err(1, "SIOCIFCREATE");
1087
}
1088
1089
/*ARGSUSED*/
1090
void
1091
clone_destroy(const char *addr, int param)
1092
4
{
1093
1094
4
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1095
4
	if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
1096
		err(1, "SIOCIFDESTROY");
1097
4
}
1098
1099
void
1100
list_cloners(void)
1101
{
1102
	struct if_clonereq ifcr;
1103
	char *cp, *buf;
1104
	int idx;
1105
1106
	memset(&ifcr, 0, sizeof(ifcr));
1107
1108
	getsock(AF_INET);
1109
1110
	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
1111
		err(1, "SIOCIFGCLONERS for count");
1112
1113
	buf = calloc(ifcr.ifcr_total, IFNAMSIZ);
1114
	if (buf == NULL)
1115
		err(1, "unable to allocate cloner name buffer");
1116
1117
	ifcr.ifcr_count = ifcr.ifcr_total;
1118
	ifcr.ifcr_buffer = buf;
1119
1120
	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
1121
		err(1, "SIOCIFGCLONERS for names");
1122
1123
	/*
1124
	 * In case some disappeared in the mean time, clamp it down.
1125
	 */
1126
	if (ifcr.ifcr_count > ifcr.ifcr_total)
1127
		ifcr.ifcr_count = ifcr.ifcr_total;
1128
1129
	qsort(buf, ifcr.ifcr_count, IFNAMSIZ,
1130
	    (int(*)(const void *, const void *))strcmp);
1131
1132
	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
1133
		if (idx > 0)
1134
			putchar(' ');
1135
		printf("%s", cp);
1136
	}
1137
1138
	putchar('\n');
1139
	free(buf);
1140
}
1141
1142
#define RIDADDR 0
1143
#define ADDR	1
1144
#define MASK	2
1145
#define DSTADDR	3
1146
1147
/*ARGSUSED*/
1148
void
1149
setifaddr(const char *addr, int param)
1150
94
{
1151
	/*
1152
	 * Delay the ioctl to set the interface addr until flags are all set.
1153
	 * The address interpretation may depend on the flags,
1154
	 * and the flags may change when the address is set.
1155
	 */
1156
94
	setaddr++;
1157
94
	if (doalias >= 0)
1158
94
		newaddr = 1;
1159
94
	if (doalias == 0)
1160
94
		clearaddr = 1;
1161
94
	afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
1162
94
}
1163
1164
#ifndef SMALL
1165
void
1166
setifrtlabel(const char *label, int d)
1167
{
1168
	if (d != 0)
1169
		ifr.ifr_data = (caddr_t)(const char *)"";
1170
	else
1171
		ifr.ifr_data = (caddr_t)label;
1172
	if (ioctl(s, SIOCSIFRTLABEL, &ifr) < 0)
1173
		warn("SIOCSIFRTLABEL");
1174
}
1175
#endif
1176
1177
/* ARGSUSED */
1178
void
1179
setifnetmask(const char *addr, int ignored)
1180
{
1181
	afp->af_getaddr(addr, MASK);
1182
}
1183
1184
/* ARGSUSED */
1185
void
1186
setifbroadaddr(const char *addr, int ignored)
1187
{
1188
	afp->af_getaddr(addr, DSTADDR);
1189
}
1190
1191
#ifndef SMALL
1192
/* ARGSUSED */
1193
void
1194
setifdesc(const char *val, int ignored)
1195
{
1196
	ifr.ifr_data = (caddr_t)val;
1197
	if (ioctl(s, SIOCSIFDESCR, &ifr) < 0)
1198
		warn("SIOCSIFDESCR");
1199
}
1200
1201
/* ARGSUSED */
1202
void
1203
unsetifdesc(const char *noval, int ignored)
1204
{
1205
	ifr.ifr_data = (caddr_t)(const char *)"";
1206
	if (ioctl(s, SIOCSIFDESCR, &ifr) < 0)
1207
		warn("SIOCSIFDESCR");
1208
}
1209
1210
/* ARGSUSED */
1211
void
1212
setifipdst(const char *addr, int ignored)
1213
{
1214
	in_getaddr(addr, DSTADDR);
1215
	setipdst++;
1216
	clearaddr = 0;
1217
	newaddr = 0;
1218
}
1219
#endif
1220
1221
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1222
/*ARGSUSED*/
1223
void
1224
notealias(const char *addr, int param)
1225
{
1226
	if (setaddr && doalias == 0 && param < 0)
1227
		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1228
		    rqtosa(af_addreq)->sa_len);
1229
	doalias = param;
1230
	if (param < 0) {
1231
		clearaddr = 1;
1232
		newaddr = 0;
1233
	} else
1234
		clearaddr = 0;
1235
}
1236
1237
/*ARGSUSED*/
1238
void
1239
setifdstaddr(const char *addr, int param)
1240
{
1241
	setaddr++;
1242
	afp->af_getaddr(addr, DSTADDR);
1243
}
1244
1245
/*
1246
 * Note: doing an SIOCGIFFLAGS scribbles on the union portion
1247
 * of the ifreq structure, which may confuse other parts of ifconfig.
1248
 * Make a private copy so we can avoid that.
1249
 */
1250
/* ARGSUSED */
1251
void
1252
setifflags(const char *vname, int value)
1253
90
{
1254
	struct ifreq my_ifr;
1255
1256
90
	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1257
1258
90
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0)
1259
		err(1, "SIOCGIFFLAGS");
1260
90
	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
1261
90
	flags = my_ifr.ifr_flags;
1262
1263
90
	if (value < 0) {
1264
2
		value = -value;
1265
2
		flags &= ~value;
1266
	} else
1267
88
		flags |= value;
1268
90
	my_ifr.ifr_flags = flags;
1269
90
	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
1270
		err(1, "SIOCSIFFLAGS");
1271
90
}
1272
1273
/* ARGSUSED */
1274
void
1275
setifxflags(const char *vname, int value)
1276
{
1277
	struct ifreq my_ifr;
1278
1279
	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1280
1281
	if (ioctl(s, SIOCGIFXFLAGS, (caddr_t)&my_ifr) < 0)
1282
		warn("SIOCGIFXFLAGS");
1283
	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
1284
	xflags = my_ifr.ifr_flags;
1285
1286
	if (value < 0) {
1287
		value = -value;
1288
		xflags &= ~value;
1289
	} else
1290
		xflags |= value;
1291
	my_ifr.ifr_flags = xflags;
1292
	if (ioctl(s, SIOCSIFXFLAGS, (caddr_t)&my_ifr) < 0)
1293
		warn("SIOCSIFXFLAGS");
1294
}
1295
1296
void
1297
addaf(const char *vname, int value)
1298
10
{
1299
	struct if_afreq	ifar;
1300
1301
10
	strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1302
10
	ifar.ifar_af = value;
1303
10
	if (ioctl(s, SIOCIFAFATTACH, (caddr_t)&ifar) < 0)
1304
		warn("SIOCIFAFATTACH");
1305
10
}
1306
1307
void
1308
removeaf(const char *vname, int value)
1309
{
1310
	struct if_afreq	ifar;
1311
1312
	strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
1313
	ifar.ifar_af = value;
1314
	if (ioctl(s, SIOCIFAFDETACH, (caddr_t)&ifar) < 0)
1315
		warn("SIOCIFAFDETACH");
1316
}
1317
1318
void
1319
setia6flags(const char *vname, int value)
1320
{
1321
1322
	if (value < 0) {
1323
		value = -value;
1324
		in6_addreq.ifra_flags &= ~value;
1325
	} else
1326
		in6_addreq.ifra_flags |= value;
1327
}
1328
1329
void
1330
setia6pltime(const char *val, int d)
1331
{
1332
1333
	setia6lifetime("pltime", val);
1334
}
1335
1336
void
1337
setia6vltime(const char *val, int d)
1338
{
1339
1340
	setia6lifetime("vltime", val);
1341
}
1342
1343
void
1344
setia6lifetime(const char *cmd, const char *val)
1345
{
1346
	const char *errmsg = NULL;
1347
	time_t newval, t;
1348
1349
	newval = strtonum(val, 0, 1000000, &errmsg);
1350
	if (errmsg)
1351
		errx(1, "invalid %s %s: %s", cmd, val, errmsg);
1352
1353
	t = time(NULL);
1354
1355
	if (afp->af_af != AF_INET6)
1356
		errx(1, "%s not allowed for the AF", cmd);
1357
	if (strcmp(cmd, "vltime") == 0) {
1358
		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1359
		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1360
	} else if (strcmp(cmd, "pltime") == 0) {
1361
		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1362
		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1363
	}
1364
}
1365
1366
void
1367
setia6eui64(const char *cmd, int val)
1368
2
{
1369
	struct ifaddrs *ifap, *ifa;
1370
2
	const struct sockaddr_in6 *sin6 = NULL;
1371
2
	const struct in6_addr *lladdr = NULL;
1372
	struct in6_addr *in6;
1373
1374
2
	if (afp->af_af != AF_INET6)
1375
		errx(1, "%s not allowed for the AF", cmd);
1376
1377
2
	addaf(name, AF_INET6);
1378
1379
2
	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1380
2
	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1381
		errx(1, "interface index is already filled");
1382
2
	if (getifaddrs(&ifap) != 0)
1383
		err(1, "getifaddrs");
1384
23
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1385

23
		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1386
		    strcmp(ifa->ifa_name, name) == 0) {
1387
4
			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1388

4
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1389
2
				lladdr = &sin6->sin6_addr;
1390
2
				break;
1391
			}
1392
		}
1393
	}
1394
2
	if (!lladdr)
1395
		errx(1, "could not determine link local address");
1396
1397
2
	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1398
1399
2
	freeifaddrs(ifap);
1400
2
}
1401
1402
void
1403
setautoconf(const char *cmd, int val)
1404
{
1405
	switch (afp->af_af) {
1406
	case AF_INET6:
1407
		setifxflags("inet6", val * IFXF_AUTOCONF6);
1408
		break;
1409
	default:
1410
		errx(1, "autoconf not allowed for this AF");
1411
	}
1412
}
1413
1414
#ifndef SMALL
1415
/* ARGSUSED */
1416
void
1417
setifmetric(const char *val, int ignored)
1418
{
1419
	const char *errmsg = NULL;
1420
1421
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1422
1423
	ifr.ifr_metric = strtonum(val, 0, INT_MAX, &errmsg);
1424
	if (errmsg)
1425
		errx(1, "metric %s: %s", val, errmsg);
1426
	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
1427
		warn("SIOCSIFMETRIC");
1428
}
1429
#endif
1430
1431
/* ARGSUSED */
1432
void
1433
setifmtu(const char *val, int d)
1434
{
1435
	const char *errmsg = NULL;
1436
1437
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1438
1439
	ifr.ifr_mtu = strtonum(val, 0, INT_MAX, &errmsg);
1440
	if (errmsg)
1441
		errx(1, "mtu %s: %s", val, errmsg);
1442
	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
1443
		warn("SIOCSIFMTU");
1444
}
1445
1446
/* ARGSUSED */
1447
void
1448
setifllprio(const char *val, int d)
1449
{
1450
	const char *errmsg = NULL;
1451
1452
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1453
1454
	ifr.ifr_mtu = strtonum(val, 0, UCHAR_MAX, &errmsg);
1455
	if (errmsg)
1456
		errx(1, "mtu %s: %s", val, errmsg);
1457
	if (ioctl(s, SIOCSIFLLPRIO, (caddr_t)&ifr) < 0)
1458
		warn("SIOCSIFLLPRIO");
1459
}
1460
1461
/* ARGSUSED */
1462
void
1463
setifgroup(const char *group_name, int dummy)
1464
{
1465
	struct ifgroupreq ifgr;
1466
1467
	memset(&ifgr, 0, sizeof(ifgr));
1468
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
1469
1470
	if (group_name[0] &&
1471
	    isdigit((unsigned char)group_name[strlen(group_name) - 1]))
1472
		errx(1, "setifgroup: group names may not end in a digit");
1473
1474
	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1475
		errx(1, "setifgroup: group name too long");
1476
	if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1) {
1477
		if (errno != EEXIST)
1478
			err(1," SIOCAIFGROUP");
1479
	}
1480
}
1481
1482
/* ARGSUSED */
1483
void
1484
unsetifgroup(const char *group_name, int dummy)
1485
{
1486
	struct ifgroupreq ifgr;
1487
1488
	memset(&ifgr, 0, sizeof(ifgr));
1489
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
1490
1491
	if (group_name[0] &&
1492
	    isdigit((unsigned char)group_name[strlen(group_name) - 1]))
1493
		errx(1, "unsetifgroup: group names may not end in a digit");
1494
1495
	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1496
		errx(1, "unsetifgroup: group name too long");
1497
	if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
1498
		err(1, "SIOCDIFGROUP");
1499
}
1500
1501
const char *
1502
get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1503
{
1504
	int len = *lenp, hexstr;
1505
	u_int8_t *p = buf;
1506
1507
	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1508
	if (hexstr)
1509
		val += 2;
1510
	for (;;) {
1511
		if (*val == '\0')
1512
			break;
1513
		if (sep != NULL && strchr(sep, *val) != NULL) {
1514
			val++;
1515
			break;
1516
		}
1517
		if (hexstr) {
1518
			if (!isxdigit((u_char)val[0]) ||
1519
			    !isxdigit((u_char)val[1])) {
1520
				warnx("bad hexadecimal digits");
1521
				return NULL;
1522
			}
1523
		}
1524
		if (p > buf + len) {
1525
			if (hexstr)
1526
				warnx("hexadecimal digits too long");
1527
			else
1528
				warnx("strings too long");
1529
			return NULL;
1530
		}
1531
		if (hexstr) {
1532
#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1533
			*p++ = (tohex((u_char)val[0]) << 4) |
1534
			    tohex((u_char)val[1]);
1535
#undef tohex
1536
			val += 2;
1537
		} else {
1538
			if (*val == '\\' &&
1539
			    sep != NULL && strchr(sep, *(val + 1)) != NULL)
1540
				val++;
1541
			*p++ = *val++;
1542
		}
1543
	}
1544
	len = p - buf;
1545
	if (len < *lenp)
1546
		memset(p, 0, *lenp - len);
1547
	*lenp = len;
1548
	return val;
1549
}
1550
1551
void
1552
print_string(const u_int8_t *buf, int len)
1553
{
1554
	int i = 0, hasspc = 0;
1555
1556
	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1557
		for (; i < len; i++) {
1558
			/* Only print 7-bit ASCII keys */
1559
			if (buf[i] & 0x80 || !isprint(buf[i]))
1560
				break;
1561
			if (isspace(buf[i]))
1562
				hasspc++;
1563
		}
1564
	}
1565
	if (i == len) {
1566
		if (hasspc || len == 0)
1567
			printf("\"%.*s\"", len, buf);
1568
		else
1569
			printf("%.*s", len, buf);
1570
	} else {
1571
		printf("0x");
1572
		for (i = 0; i < len; i++)
1573
			printf("%02x", buf[i]);
1574
	}
1575
}
1576
1577
void
1578
setifnwid(const char *val, int d)
1579
{
1580
	struct ieee80211_nwid nwid;
1581
	int len;
1582
1583
	if (d != 0) {
1584
		/* no network id is especially desired */
1585
		memset(&nwid, 0, sizeof(nwid));
1586
		len = 0;
1587
	} else {
1588
		len = sizeof(nwid.i_nwid);
1589
		if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1590
			return;
1591
	}
1592
	nwid.i_len = len;
1593
	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1594
	ifr.ifr_data = (caddr_t)&nwid;
1595
	if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
1596
		warn("SIOCS80211NWID");
1597
}
1598
1599
void
1600
setifbssid(const char *val, int d)
1601
{
1602
1603
	struct ieee80211_bssid bssid;
1604
	struct ether_addr *ea;
1605
1606
	if (d != 0) {
1607
		/* no BSSID is especially desired */
1608
		memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1609
	} else {
1610
		ea = ether_aton((char*)val);
1611
		if (ea == NULL) {
1612
			warnx("malformed BSSID: %s", val);
1613
			return;
1614
		}
1615
		memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1616
		    sizeof(bssid.i_bssid));
1617
	}
1618
	strlcpy(bssid.i_name, name, sizeof(bssid.i_name));
1619
	if (ioctl(s, SIOCS80211BSSID, &bssid) == -1)
1620
		warn("SIOCS80211BSSID");
1621
}
1622
1623
void
1624
setifnwkey(const char *val, int d)
1625
{
1626
	int i, len;
1627
	struct ieee80211_nwkey nwkey;
1628
	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1629
1630
	bzero(&nwkey, sizeof(nwkey));
1631
	bzero(&keybuf, sizeof(keybuf));
1632
1633
	nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1634
	nwkey.i_defkid = 1;
1635
	if (d == -1) {
1636
		/* disable WEP encryption */
1637
		nwkey.i_wepon = 0;
1638
		i = 0;
1639
	} else if (strcasecmp("persist", val) == 0) {
1640
		/* use all values from persistent memory */
1641
		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1642
		nwkey.i_defkid = 0;
1643
		for (i = 0; i < IEEE80211_WEP_NKID; i++)
1644
			nwkey.i_key[i].i_keylen = -1;
1645
	} else if (strncasecmp("persist:", val, 8) == 0) {
1646
		val += 8;
1647
		/* program keys in persistent memory */
1648
		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1649
		goto set_nwkey;
1650
	} else {
1651
 set_nwkey:
1652
		if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1653
			/* specifying a full set of four keys */
1654
			nwkey.i_defkid = val[0] - '0';
1655
			val += 2;
1656
			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1657
				len = sizeof(keybuf[i]);
1658
				val = get_string(val, ",", keybuf[i], &len);
1659
				if (val == NULL)
1660
					return;
1661
				nwkey.i_key[i].i_keylen = len;
1662
				nwkey.i_key[i].i_keydat = keybuf[i];
1663
			}
1664
			if (*val != '\0') {
1665
				warnx("SIOCS80211NWKEY: too many keys.");
1666
				return;
1667
			}
1668
		} else {
1669
			/*
1670
			 * length of each key must be either a 5
1671
			 * character ASCII string or 10 hex digits for
1672
			 * 40 bit encryption, or 13 character ASCII
1673
			 * string or 26 hex digits for 128 bit
1674
			 * encryption.
1675
			 */
1676
			int j;
1677
			char *tmp = NULL;
1678
			size_t vlen = strlen(val);
1679
			switch(vlen) {
1680
			case 10:
1681
			case 26:
1682
				/* 0x must be missing for these lengths */
1683
				j = asprintf(&tmp, "0x%s", val);
1684
				if (j == -1) {
1685
					warnx("malloc failed");
1686
					return;
1687
				}
1688
				val = tmp;
1689
				break;
1690
			case 12:
1691
			case 28:
1692
			case 5:
1693
			case 13:
1694
				/* 0xkey or string case - all is ok */
1695
				break;
1696
			default:
1697
				warnx("Invalid WEP key length");
1698
				return;
1699
			}
1700
			len = sizeof(keybuf[0]);
1701
			val = get_string(val, NULL, keybuf[0], &len);
1702
			free(tmp);
1703
			if (val == NULL)
1704
				return;
1705
			nwkey.i_key[0].i_keylen = len;
1706
			nwkey.i_key[0].i_keydat = keybuf[0];
1707
			i = 1;
1708
		}
1709
	}
1710
	(void)strlcpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1711
	if (ioctl(s, SIOCS80211NWKEY, (caddr_t)&nwkey) == -1)
1712
		warn("SIOCS80211NWKEY");
1713
}
1714
1715
/* ARGSUSED */
1716
void
1717
setifwpa(const char *val, int d)
1718
{
1719
	struct ieee80211_wpaparams wpa;
1720
1721
	memset(&wpa, 0, sizeof(wpa));
1722
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1723
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1724
		err(1, "SIOCG80211WPAPARMS");
1725
	wpa.i_enabled = d;
1726
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1727
		err(1, "SIOCS80211WPAPARMS");
1728
}
1729
1730
/* ARGSUSED */
1731
void
1732
setifwpaprotos(const char *val, int d)
1733
{
1734
	struct ieee80211_wpaparams wpa;
1735
	char *optlist, *str;
1736
	u_int rval = 0;
1737
1738
	if ((optlist = strdup(val)) == NULL)
1739
		err(1, "strdup");
1740
	str = strtok(optlist, ",");
1741
	while (str != NULL) {
1742
		if (strcasecmp(str, "wpa1") == 0)
1743
			rval |= IEEE80211_WPA_PROTO_WPA1;
1744
		else if (strcasecmp(str, "wpa2") == 0)
1745
			rval |= IEEE80211_WPA_PROTO_WPA2;
1746
		else
1747
			errx(1, "wpaprotos: unknown protocol: %s", str);
1748
		str = strtok(NULL, ",");
1749
	}
1750
	free(optlist);
1751
1752
	memset(&wpa, 0, sizeof(wpa));
1753
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1754
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1755
		err(1, "SIOCG80211WPAPARMS");
1756
	wpa.i_protos = rval;
1757
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1758
		err(1, "SIOCS80211WPAPARMS");
1759
}
1760
1761
/* ARGSUSED */
1762
void
1763
setifwpaakms(const char *val, int d)
1764
{
1765
	struct ieee80211_wpaparams wpa;
1766
	char *optlist, *str;
1767
	u_int rval = 0;
1768
1769
	if ((optlist = strdup(val)) == NULL)
1770
		err(1, "strdup");
1771
	str = strtok(optlist, ",");
1772
	while (str != NULL) {
1773
		if (strcasecmp(str, "psk") == 0)
1774
			rval |= IEEE80211_WPA_AKM_PSK;
1775
		else if (strcasecmp(str, "802.1x") == 0)
1776
			rval |= IEEE80211_WPA_AKM_8021X;
1777
		else
1778
			errx(1, "wpaakms: unknown akm: %s", str);
1779
		str = strtok(NULL, ",");
1780
	}
1781
	free(optlist);
1782
1783
	memset(&wpa, 0, sizeof(wpa));
1784
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1785
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1786
		err(1, "SIOCG80211WPAPARMS");
1787
	wpa.i_akms = rval;
1788
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1789
		err(1, "SIOCS80211WPAPARMS");
1790
}
1791
1792
static const struct {
1793
	const char	*name;
1794
	u_int		cipher;
1795
} ciphers[] = {
1796
	{ "usegroup",	IEEE80211_WPA_CIPHER_USEGROUP },
1797
	{ "wep40",	IEEE80211_WPA_CIPHER_WEP40 },
1798
	{ "tkip",	IEEE80211_WPA_CIPHER_TKIP },
1799
	{ "ccmp",	IEEE80211_WPA_CIPHER_CCMP },
1800
	{ "wep104",	IEEE80211_WPA_CIPHER_WEP104 }
1801
};
1802
1803
u_int
1804
getwpacipher(const char *name)
1805
{
1806
	int i;
1807
1808
	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++)
1809
		if (strcasecmp(name, ciphers[i].name) == 0)
1810
			return ciphers[i].cipher;
1811
	return IEEE80211_WPA_CIPHER_NONE;
1812
}
1813
1814
/* ARGSUSED */
1815
void
1816
setifwpaciphers(const char *val, int d)
1817
{
1818
	struct ieee80211_wpaparams wpa;
1819
	char *optlist, *str;
1820
	u_int rval = 0;
1821
1822
	if ((optlist = strdup(val)) == NULL)
1823
		err(1, "strdup");
1824
	str = strtok(optlist, ",");
1825
	while (str != NULL) {
1826
		u_int cipher = getwpacipher(str);
1827
		if (cipher == IEEE80211_WPA_CIPHER_NONE)
1828
			errx(1, "wpaciphers: unknown cipher: %s", str);
1829
1830
		rval |= cipher;
1831
		str = strtok(NULL, ",");
1832
	}
1833
	free(optlist);
1834
1835
	memset(&wpa, 0, sizeof(wpa));
1836
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1837
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1838
		err(1, "SIOCG80211WPAPARMS");
1839
	wpa.i_ciphers = rval;
1840
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1841
		err(1, "SIOCS80211WPAPARMS");
1842
}
1843
1844
/* ARGSUSED */
1845
void
1846
setifwpagroupcipher(const char *val, int d)
1847
{
1848
	struct ieee80211_wpaparams wpa;
1849
	u_int cipher;
1850
1851
	cipher = getwpacipher(val);
1852
	if (cipher == IEEE80211_WPA_CIPHER_NONE)
1853
		errx(1, "wpagroupcipher: unknown cipher: %s", val);
1854
1855
	memset(&wpa, 0, sizeof(wpa));
1856
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1857
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1858
		err(1, "SIOCG80211WPAPARMS");
1859
	wpa.i_groupcipher = cipher;
1860
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1861
		err(1, "SIOCS80211WPAPARMS");
1862
}
1863
1864
void
1865
setifwpakey(const char *val, int d)
1866
{
1867
	struct ieee80211_wpaparams wpa;
1868
	struct ieee80211_wpapsk psk;
1869
	struct ieee80211_nwid nwid;
1870
	int passlen;
1871
1872
	memset(&psk, 0, sizeof(psk));
1873
	if (d != -1) {
1874
		memset(&ifr, 0, sizeof(ifr));
1875
		ifr.ifr_data = (caddr_t)&nwid;
1876
		strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1877
		if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr))
1878
			err(1, "SIOCG80211NWID");
1879
1880
		passlen = strlen(val);
1881
		if (passlen == 2 + 2 * sizeof(psk.i_psk) &&
1882
		    val[0] == '0' && val[1] == 'x') {
1883
			/* Parse a WPA hex key (must be full-length) */
1884
			passlen = sizeof(psk.i_psk);
1885
			val = get_string(val, NULL, psk.i_psk, &passlen);
1886
			if (val == NULL || passlen != sizeof(psk.i_psk))
1887
				errx(1, "wpakey: invalid pre-shared key");
1888
		} else {
1889
			/* Parse a WPA passphrase */
1890
			if (passlen < 8 || passlen > 63)
1891
				errx(1, "wpakey: passphrase must be between "
1892
				    "8 and 63 characters");
1893
			if (nwid.i_len == 0)
1894
				errx(1, "wpakey: nwid not set");
1895
			if (pkcs5_pbkdf2(val, passlen, nwid.i_nwid, nwid.i_len,
1896
			    psk.i_psk, sizeof(psk.i_psk), 4096) != 0)
1897
				errx(1, "wpakey: passphrase hashing failed");
1898
		}
1899
		psk.i_enabled = 1;
1900
	} else
1901
		psk.i_enabled = 0;
1902
1903
	(void)strlcpy(psk.i_name, name, sizeof(psk.i_name));
1904
	if (ioctl(s, SIOCS80211WPAPSK, (caddr_t)&psk) < 0)
1905
		err(1, "SIOCS80211WPAPSK");
1906
1907
	/* And ... automatically enable or disable WPA */
1908
	memset(&wpa, 0, sizeof(wpa));
1909
	(void)strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
1910
	if (ioctl(s, SIOCG80211WPAPARMS, (caddr_t)&wpa) < 0)
1911
		err(1, "SIOCG80211WPAPARMS");
1912
	wpa.i_enabled = psk.i_enabled;
1913
	if (ioctl(s, SIOCS80211WPAPARMS, (caddr_t)&wpa) < 0)
1914
		err(1, "SIOCS80211WPAPARMS");
1915
}
1916
1917
void
1918
setifchan(const char *val, int d)
1919
{
1920
	struct ieee80211chanreq channel;
1921
	const char *errstr;
1922
	int chan;
1923
1924
	if (val == NULL) {
1925
		if (shownet80211chans || shownet80211nodes)
1926
			usage(1);
1927
		shownet80211chans = 1;
1928
		return;
1929
	}
1930
	if (d != 0)
1931
		chan = IEEE80211_CHAN_ANY;
1932
	else {
1933
		chan = strtonum(val, 1, 256, &errstr);
1934
		if (errstr) {
1935
			warnx("invalid channel %s: %s", val, errstr);
1936
			return;
1937
		}
1938
	}
1939
1940
	strlcpy(channel.i_name, name, sizeof(channel.i_name));
1941
	channel.i_channel = (u_int16_t)chan;
1942
	if (ioctl(s, SIOCS80211CHANNEL, (caddr_t)&channel) == -1)
1943
		warn("SIOCS80211CHANNEL");
1944
}
1945
1946
/* ARGSUSED */
1947
void
1948
setifscan(const char *val, int d)
1949
{
1950
	if (shownet80211chans || shownet80211nodes)
1951
		usage(1);
1952
	shownet80211nodes = 1;
1953
}
1954
1955
#ifndef SMALL
1956
1957
void
1958
setifnwflag(const char *val, int d)
1959
{
1960
	static const struct ieee80211_flags nwflags[] = IEEE80211_FLAGS;
1961
	u_int i, flag = 0;
1962
1963
	for (i = 0; i < (sizeof(nwflags) / sizeof(nwflags[0])); i++) {
1964
		if (strcmp(val, nwflags[i].f_name) == 0) {
1965
			flag = nwflags[i].f_flag;
1966
			break;
1967
		}
1968
	}
1969
	if (flag == 0)
1970
		errx(1, "Invalid nwflag: %s", val);
1971
1972
	if (ioctl(s, SIOCG80211FLAGS, (caddr_t)&ifr) != 0)
1973
		err(1, "SIOCG80211FLAGS");
1974
1975
	if (d)
1976
		ifr.ifr_flags &= ~flag;
1977
	else
1978
		ifr.ifr_flags |= flag;
1979
1980
	if (ioctl(s, SIOCS80211FLAGS, (caddr_t)&ifr) != 0)
1981
		err(1, "SIOCS80211FLAGS");
1982
}
1983
1984
void
1985
unsetifnwflag(const char *val, int d)
1986
{
1987
	setifnwflag(val, 1);
1988
}
1989
1990
/* ARGSUSED */
1991
void
1992
setifpowersave(const char *val, int d)
1993
{
1994
	struct ieee80211_power power;
1995
	const char *errmsg = NULL;
1996
1997
	(void)strlcpy(power.i_name, name, sizeof(power.i_name));
1998
	if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) == -1) {
1999
		warn("SIOCG80211POWER");
2000
		return;
2001
	}
2002
2003
	if (d != -1 && val != NULL) {
2004
		power.i_maxsleep = strtonum(val, 0, INT_MAX, &errmsg);
2005
		if (errmsg)
2006
			errx(1, "powersave %s: %s", val, errmsg);
2007
	}
2008
2009
	power.i_enabled = d == -1 ? 0 : 1;
2010
	if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) == -1)
2011
		warn("SIOCS80211POWER");
2012
}
2013
#endif
2014
2015
void
2016
print_cipherset(u_int32_t cipherset)
2017
{
2018
	const char *sep = "";
2019
	int i;
2020
2021
	if (cipherset == IEEE80211_WPA_CIPHER_NONE) {
2022
		printf("none");
2023
		return;
2024
	}
2025
	for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++) {
2026
		if (cipherset & ciphers[i].cipher) {
2027
			printf("%s%s", sep, ciphers[i].name);
2028
			sep = ",";
2029
		}
2030
	}
2031
}
2032
2033
void
2034
ieee80211_status(void)
2035
{
2036
	int len, i, nwkey_verbose, inwid, inwkey, ipsk, ichan, ipwr;
2037
	int ibssid, iwpa;
2038
	struct ieee80211_nwid nwid;
2039
	struct ieee80211_nwkey nwkey;
2040
	struct ieee80211_wpapsk psk;
2041
	struct ieee80211_power power;
2042
	struct ieee80211chanreq channel;
2043
	struct ieee80211_bssid bssid;
2044
	struct ieee80211_wpaparams wpa;
2045
	struct ieee80211_nodereq nr;
2046
	u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
2047
	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
2048
	struct ether_addr ea;
2049
2050
	/* get current status via ioctls */
2051
	memset(&ifr, 0, sizeof(ifr));
2052
	ifr.ifr_data = (caddr_t)&nwid;
2053
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2054
	inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
2055
2056
	memset(&nwkey, 0, sizeof(nwkey));
2057
	strlcpy(nwkey.i_name, name, sizeof(nwkey.i_name));
2058
	inwkey = ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey);
2059
2060
	memset(&psk, 0, sizeof(psk));
2061
	strlcpy(psk.i_name, name, sizeof(psk.i_name));
2062
	ipsk = ioctl(s, SIOCG80211WPAPSK, (caddr_t)&psk);
2063
2064
	memset(&power, 0, sizeof(power));
2065
	strlcpy(power.i_name, name, sizeof(power.i_name));
2066
	ipwr = ioctl(s, SIOCG80211POWER, &power);
2067
2068
	memset(&channel, 0, sizeof(channel));
2069
	strlcpy(channel.i_name, name, sizeof(channel.i_name));
2070
	ichan = ioctl(s, SIOCG80211CHANNEL, (caddr_t)&channel);
2071
2072
	memset(&bssid, 0, sizeof(bssid));
2073
	strlcpy(bssid.i_name, name, sizeof(bssid.i_name));
2074
	ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
2075
2076
	memset(&wpa, 0, sizeof(wpa));
2077
	strlcpy(wpa.i_name, name, sizeof(wpa.i_name));
2078
	iwpa = ioctl(s, SIOCG80211WPAPARMS, &wpa);
2079
2080
	/* check if any ieee80211 option is active */
2081
	if (inwid == 0 || inwkey == 0 || ipsk == 0 || ipwr == 0 ||
2082
	    ichan == 0 || ibssid == 0 || iwpa == 0)
2083
		fputs("\tieee80211:", stdout);
2084
	else
2085
		return;
2086
2087
	if (inwid == 0) {
2088
		/* nwid.i_nwid is not NUL terminated. */
2089
		len = nwid.i_len;
2090
		if (len > IEEE80211_NWID_LEN)
2091
			len = IEEE80211_NWID_LEN;
2092
		fputs(" nwid ", stdout);
2093
		print_string(nwid.i_nwid, len);
2094
	}
2095
2096
	if (ichan == 0 && channel.i_channel != 0 &&
2097
	    channel.i_channel != IEEE80211_CHAN_ANY)
2098
		printf(" chan %u", channel.i_channel);
2099
2100
	memset(&zero_bssid, 0, sizeof(zero_bssid));
2101
	if (ibssid == 0 &&
2102
	    memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
2103
		memcpy(&ea.ether_addr_octet, bssid.i_bssid,
2104
		    sizeof(ea.ether_addr_octet));
2105
		printf(" bssid %s", ether_ntoa(&ea));
2106
2107
		bzero(&nr, sizeof(nr));
2108
		bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
2109
		strlcpy(nr.nr_ifname, name, sizeof(nr.nr_ifname));
2110
		if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
2111
			if (nr.nr_max_rssi)
2112
				printf(" %u%%", IEEE80211_NODEREQ_RSSI(&nr));
2113
			else
2114
				printf(" %ddBm", nr.nr_rssi);
2115
		}
2116
	}
2117
2118
	if (inwkey == 0 && nwkey.i_wepon > 0) {
2119
		fputs(" nwkey ", stdout);
2120
		/* try to retrieve WEP keys */
2121
		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2122
			nwkey.i_key[i].i_keydat = keybuf[i];
2123
			nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
2124
		}
2125
		if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) == -1) {
2126
			fputs("<not displayed>", stdout);
2127
		} else {
2128
			nwkey_verbose = 0;
2129
			/*
2130
			 * check to see non default key
2131
			 * or multiple keys defined
2132
			 */
2133
			if (nwkey.i_defkid != 1) {
2134
				nwkey_verbose = 1;
2135
			} else {
2136
				for (i = 1; i < IEEE80211_WEP_NKID; i++) {
2137
					if (nwkey.i_key[i].i_keylen != 0) {
2138
						nwkey_verbose = 1;
2139
						break;
2140
					}
2141
				}
2142
			}
2143
			/* check extra ambiguity with keywords */
2144
			if (!nwkey_verbose) {
2145
				if (nwkey.i_key[0].i_keylen >= 2 &&
2146
				    isdigit((unsigned char)nwkey.i_key[0].i_keydat[0]) &&
2147
				    nwkey.i_key[0].i_keydat[1] == ':')
2148
					nwkey_verbose = 1;
2149
				else if (nwkey.i_key[0].i_keylen >= 7 &&
2150
				    strncasecmp("persist",
2151
				    (char *)nwkey.i_key[0].i_keydat, 7) == 0)
2152
					nwkey_verbose = 1;
2153
			}
2154
			if (nwkey_verbose)
2155
				printf("%d:", nwkey.i_defkid);
2156
			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
2157
				if (i > 0)
2158
					putchar(',');
2159
				if (nwkey.i_key[i].i_keylen < 0) {
2160
					fputs("persist", stdout);
2161
				} else {
2162
					/*
2163
					 * XXX
2164
					 * sanity check nwkey.i_key[i].i_keylen
2165
					 */
2166
					print_string(nwkey.i_key[i].i_keydat,
2167
					    nwkey.i_key[i].i_keylen);
2168
				}
2169
				if (!nwkey_verbose)
2170
					break;
2171
			}
2172
		}
2173
	}
2174
2175
	if (ipsk == 0 && psk.i_enabled) {
2176
		fputs(" wpakey ", stdout);
2177
		if (psk.i_enabled == 2)
2178
			fputs("<not displayed>", stdout);
2179
		else
2180
			print_string(psk.i_psk, sizeof(psk.i_psk));
2181
	}
2182
	if (iwpa == 0 && wpa.i_enabled) {
2183
		const char *sep;
2184
2185
		fputs(" wpaprotos ", stdout); sep = "";
2186
		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1) {
2187
			fputs("wpa1", stdout);
2188
			sep = ",";
2189
		}
2190
		if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
2191
			printf("%swpa2", sep);
2192
2193
		fputs(" wpaakms ", stdout); sep = "";
2194
		if (wpa.i_akms & IEEE80211_WPA_AKM_PSK) {
2195
			fputs("psk", stdout);
2196
			sep = ",";
2197
		}
2198
		if (wpa.i_akms & IEEE80211_WPA_AKM_8021X)
2199
			printf("%s802.1x", sep);
2200
2201
		fputs(" wpaciphers ", stdout);
2202
		print_cipherset(wpa.i_ciphers);
2203
2204
		fputs(" wpagroupcipher ", stdout);
2205
		print_cipherset(wpa.i_groupcipher);
2206
	}
2207
2208
	if (ipwr == 0 && power.i_enabled)
2209
		printf(" powersave on (%dms sleep)", power.i_maxsleep);
2210
2211
	if (ioctl(s, SIOCG80211FLAGS, (caddr_t)&ifr) == 0 &&
2212
	    ifr.ifr_flags) {
2213
		putchar(' ');
2214
		printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
2215
	}
2216
2217
	putchar('\n');
2218
	if (shownet80211chans)
2219
		ieee80211_listchans();
2220
	else if (shownet80211nodes)
2221
		ieee80211_listnodes();
2222
}
2223
2224
void
2225
ieee80211_listchans(void)
2226
{
2227
	static struct ieee80211_channel chans[256+1];
2228
	struct ieee80211_chanreq_all ca;
2229
	int i;
2230
2231
	bzero(&ca, sizeof(ca));
2232
	bzero(chans, sizeof(chans));
2233
	ca.i_chans = chans;
2234
	strlcpy(ca.i_name, name, sizeof(ca.i_name));
2235
2236
	if (ioctl(s, SIOCG80211ALLCHANS, &ca) != 0) {
2237
		warn("SIOCG80211ALLCHANS");
2238
		return;
2239
	}
2240
	printf("\t\t%4s  %-8s  %s\n", "chan", "freq", "properties");
2241
	for (i = 1; i <= 256; i++) {
2242
		if (chans[i].ic_flags == 0)
2243
			continue;
2244
		printf("\t\t%4d  %4d MHz  ", i, chans[i].ic_freq);
2245
		if (chans[i].ic_flags & IEEE80211_CHAN_PASSIVE)
2246
			printf("passive scan");
2247
		else
2248
			putchar('-');
2249
		putchar('\n');
2250
	}
2251
}
2252
2253
/*
2254
 * Returns an integer less than, equal to, or greater than zero if nr1's
2255
 * RSSI is respectively greater than, equal to, or less than nr2's RSSI.
2256
 */
2257
static int
2258
rssicmp(const void *nr1, const void *nr2)
2259
{
2260
	const struct ieee80211_nodereq *x = nr1, *y = nr2;
2261
	return y->nr_rssi < x->nr_rssi ? -1 : y->nr_rssi > x->nr_rssi;
2262
}
2263
2264
void
2265
ieee80211_listnodes(void)
2266
{
2267
	struct ieee80211_nodereq_all na;
2268
	struct ieee80211_nodereq nr[512];
2269
	struct ifreq ifr;
2270
	int i, down = 0;
2271
2272
	if ((flags & IFF_UP) == 0) {
2273
		down = 1;
2274
		setifflags("up", IFF_UP);
2275
	}
2276
2277
	bzero(&ifr, sizeof(ifr));
2278
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2279
2280
	if (ioctl(s, SIOCS80211SCAN, (caddr_t)&ifr) != 0) {
2281
		if (errno == EPERM)
2282
			printf("\t\tno permission to scan\n");
2283
		goto done;
2284
	}
2285
2286
	bzero(&na, sizeof(na));
2287
	bzero(&nr, sizeof(nr));
2288
	na.na_node = nr;
2289
	na.na_size = sizeof(nr);
2290
	strlcpy(na.na_ifname, name, sizeof(na.na_ifname));
2291
2292
	if (ioctl(s, SIOCG80211ALLNODES, &na) != 0) {
2293
		warn("SIOCG80211ALLNODES");
2294
		goto done;
2295
	}
2296
2297
	if (!na.na_nodes)
2298
		printf("\t\tnone\n");
2299
	else
2300
		qsort(nr, na.na_nodes, sizeof(*nr), rssicmp);
2301
2302
	for (i = 0; i < na.na_nodes; i++) {
2303
		printf("\t\t");
2304
		ieee80211_printnode(&nr[i]);
2305
		putchar('\n');
2306
	}
2307
2308
 done:
2309
	if (down)
2310
		setifflags("restore", -IFF_UP);
2311
}
2312
2313
void
2314
ieee80211_printnode(struct ieee80211_nodereq *nr)
2315
{
2316
	int len, i;
2317
2318
	if (nr->nr_flags & IEEE80211_NODEREQ_AP ||
2319
	    nr->nr_capinfo & IEEE80211_CAPINFO_IBSS) {
2320
		len = nr->nr_nwid_len;
2321
		if (len > IEEE80211_NWID_LEN)
2322
			len = IEEE80211_NWID_LEN;
2323
		printf("nwid ");
2324
		print_string(nr->nr_nwid, len);
2325
		putchar(' ');
2326
2327
		printf("chan %u ", nr->nr_channel);
2328
2329
		printf("bssid %s ",
2330
		    ether_ntoa((struct ether_addr*)nr->nr_bssid));
2331
	}
2332
2333
	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2334
		printf("lladdr %s ",
2335
		    ether_ntoa((struct ether_addr*)nr->nr_macaddr));
2336
2337
	if (nr->nr_max_rssi)
2338
		printf("%u%% ", IEEE80211_NODEREQ_RSSI(nr));
2339
	else
2340
		printf("%ddBm ", nr->nr_rssi);
2341
2342
	if (nr->nr_pwrsave)
2343
		printf("powersave ");
2344
	/* Only print the fastest rate */
2345
	if (nr->nr_max_rxrate) {
2346
		printf("%uM HT ", nr->nr_max_rxrate);
2347
	} else if (nr->nr_rxmcs[0] != 0) {
2348
		for (i = IEEE80211_HT_NUM_MCS - 1; i >= 0; i--) {
2349
			if (isset(nr->nr_rxmcs, i))
2350
				break;
2351
		}
2352
		printf("HT-MCS%d ", i);
2353
	} else if (nr->nr_nrates) {
2354
		printf("%uM",
2355
		    (nr->nr_rates[nr->nr_nrates - 1] & IEEE80211_RATE_VAL) / 2);
2356
		putchar(' ');
2357
	}
2358
	/* ESS is the default, skip it */
2359
	nr->nr_capinfo &= ~IEEE80211_CAPINFO_ESS;
2360
	if (nr->nr_capinfo) {
2361
		printb_status(nr->nr_capinfo, IEEE80211_CAPINFO_BITS);
2362
		if (nr->nr_capinfo & IEEE80211_CAPINFO_PRIVACY) {
2363
			if (nr->nr_rsnciphers & IEEE80211_WPA_CIPHER_CCMP)
2364
				fputs(",wpa2", stdout);
2365
			else if (nr->nr_rsnciphers & IEEE80211_WPA_CIPHER_TKIP)
2366
				fputs(",wpa1", stdout);
2367
			else
2368
				fputs(",wep", stdout);
2369
2370
			if (nr->nr_rsnakms & IEEE80211_WPA_AKM_8021X ||
2371
			    nr->nr_rsnakms & IEEE80211_WPA_AKM_SHA256_8021X)
2372
				fputs(",802.1x", stdout);
2373
		}
2374
		putchar(' ');
2375
	}
2376
2377
	if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2378
		printb_status(IEEE80211_NODEREQ_STATE(nr->nr_state),
2379
		    IEEE80211_NODEREQ_STATE_BITS);
2380
}
2381
2382
void
2383
init_current_media(void)
2384
{
2385
	struct ifmediareq ifmr;
2386
2387
	/*
2388
	 * If we have not yet done so, grab the currently-selected
2389
	 * media.
2390
	 */
2391
	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2392
		(void) memset(&ifmr, 0, sizeof(ifmr));
2393
		(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
2394
2395
		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
2396
			/*
2397
			 * If we get E2BIG, the kernel is telling us
2398
			 * that there are more, so we can ignore it.
2399
			 */
2400
			if (errno != E2BIG)
2401
				err(1, "SIOCGIFMEDIA");
2402
		}
2403
2404
		media_current = ifmr.ifm_current;
2405
	}
2406
2407
	/* Sanity. */
2408
	if (IFM_TYPE(media_current) == 0)
2409
		errx(1, "%s: no link type?", name);
2410
}
2411
2412
void
2413
process_media_commands(void)
2414
102
{
2415
2416
102
	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2417
		/* Nothing to do. */
2418
102
		return;
2419
	}
2420
2421
	/*
2422
	 * Media already set up, and commands sanity-checked.  Set/clear
2423
	 * any options, and we're ready to go.
2424
	 */
2425
	media_current |= mediaopt_set;
2426
	media_current &= ~mediaopt_clear;
2427
2428
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2429
	ifr.ifr_media = media_current;
2430
2431
	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
2432
		;
2433
}
2434
2435
/* ARGSUSED */
2436
void
2437
setmedia(const char *val, int d)
2438
{
2439
	uint64_t type, subtype, inst;
2440
2441
	if (val == NULL) {
2442
		if (showmediaflag)
2443
			usage(1);
2444
		showmediaflag = 1;
2445
		return;
2446
	}
2447
2448
	init_current_media();
2449
2450
	/* Only one media command may be given. */
2451
	if (actions & A_MEDIA)
2452
		errx(1, "only one `media' command may be issued");
2453
2454
	/* Must not come after mode commands */
2455
	if (actions & A_MEDIAMODE)
2456
		errx(1, "may not issue `media' after `mode' commands");
2457
2458
	/* Must not come after mediaopt commands */
2459
	if (actions & A_MEDIAOPT)
2460
		errx(1, "may not issue `media' after `mediaopt' commands");
2461
2462
	/*
2463
	 * No need to check if `instance' has been issued; setmediainst()
2464
	 * craps out if `media' has not been specified.
2465
	 */
2466
2467
	type = IFM_TYPE(media_current);
2468
	inst = IFM_INST(media_current);
2469
2470
	/* Look up the subtype. */
2471
	subtype = get_media_subtype(type, val);
2472
2473
	/* Build the new current media word. */
2474
	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
2475
2476
	/* Media will be set after other processing is complete. */
2477
}
2478
2479
/* ARGSUSED */
2480
void
2481
setmediamode(const char *val, int d)
2482
{
2483
	uint64_t type, subtype, options, inst, mode;
2484
2485
	init_current_media();
2486
2487
	/* Can only issue `mode' once. */
2488
	if (actions & A_MEDIAMODE)
2489
		errx(1, "only one `mode' command may be issued");
2490
2491
	type = IFM_TYPE(media_current);
2492
	subtype = IFM_SUBTYPE(media_current);
2493
	options = IFM_OPTIONS(media_current);
2494
	inst = IFM_INST(media_current);
2495
2496
	if ((mode = get_media_mode(type, val)) == -1)
2497
		errx(1, "invalid media mode: %s", val);
2498
	media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
2499
	/* Media will be set after other processing is complete. */
2500
}
2501
2502
void
2503
unsetmediamode(const char *val, int d)
2504
{
2505
	uint64_t type, subtype, options, inst;
2506
2507
	init_current_media();
2508
2509
	/* Can only issue `mode' once. */
2510
	if (actions & A_MEDIAMODE)
2511
		errx(1, "only one `mode' command may be issued");
2512
2513
	type = IFM_TYPE(media_current);
2514
	subtype = IFM_SUBTYPE(media_current);
2515
	options = IFM_OPTIONS(media_current);
2516
	inst = IFM_INST(media_current);
2517
2518
	media_current = IFM_MAKEWORD(type, subtype, options, inst) |
2519
	    (IFM_AUTO << IFM_MSHIFT);
2520
	/* Media will be set after other processing is complete. */
2521
}
2522
2523
void
2524
setmediaopt(const char *val, int d)
2525
{
2526
2527
	init_current_media();
2528
2529
	/* Can only issue `mediaopt' once. */
2530
	if (actions & A_MEDIAOPTSET)
2531
		errx(1, "only one `mediaopt' command may be issued");
2532
2533
	/* Can't issue `mediaopt' if `instance' has already been issued. */
2534
	if (actions & A_MEDIAINST)
2535
		errx(1, "may not issue `mediaopt' after `instance'");
2536
2537
	mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
2538
2539
	/* Media will be set after other processing is complete. */
2540
}
2541
2542
/* ARGSUSED */
2543
void
2544
unsetmediaopt(const char *val, int d)
2545
{
2546
2547
	init_current_media();
2548
2549
	/* Can only issue `-mediaopt' once. */
2550
	if (actions & A_MEDIAOPTCLR)
2551
		errx(1, "only one `-mediaopt' command may be issued");
2552
2553
	/* May not issue `media' and `-mediaopt'. */
2554
	if (actions & A_MEDIA)
2555
		errx(1, "may not issue both `media' and `-mediaopt'");
2556
2557
	/*
2558
	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
2559
	 * implicitly checks for A_MEDIAINST.
2560
	 */
2561
2562
	mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
2563
2564
	/* Media will be set after other processing is complete. */
2565
}
2566
2567
/* ARGSUSED */
2568
void
2569
setmediainst(const char *val, int d)
2570
{
2571
	uint64_t type, subtype, options, inst;
2572
	const char *errmsg = NULL;
2573
2574
	init_current_media();
2575
2576
	/* Can only issue `instance' once. */
2577
	if (actions & A_MEDIAINST)
2578
		errx(1, "only one `instance' command may be issued");
2579
2580
	/* Must have already specified `media' */
2581
	if ((actions & A_MEDIA) == 0)
2582
		errx(1, "must specify `media' before `instance'");
2583
2584
	type = IFM_TYPE(media_current);
2585
	subtype = IFM_SUBTYPE(media_current);
2586
	options = IFM_OPTIONS(media_current);
2587
2588
	inst = strtonum(val, 0, IFM_INST_MAX, &errmsg);
2589
	if (errmsg)
2590
		errx(1, "media instance %s: %s", val, errmsg);
2591
2592
	media_current = IFM_MAKEWORD(type, subtype, options, inst);
2593
2594
	/* Media will be set after other processing is complete. */
2595
}
2596
2597
/*
2598
 * Note:
2599
 * bits:       0   1   2   3   4   5   ....   24   25   ...   30   31
2600
 * T1 mode:   N/A ch1 ch2 ch3 ch4 ch5        ch24  N/A        N/A  N/A
2601
 * E1 mode:   ts0 ts1 ts2 ts3 ts4 ts5        ts24  ts25       ts30 ts31
2602
 */
2603
#ifndef SMALL
2604
/* ARGSUSED */
2605
void
2606
settimeslot(const char *val, int d)
2607
{
2608
#define SINGLE_CHANNEL	0x1
2609
#define RANGE_CHANNEL	0x2
2610
#define ALL_CHANNELS	0xFFFFFFFF
2611
	unsigned long	ts_map = 0;
2612
	char		*ptr = (char *)val;
2613
	int		ts_flag = 0;
2614
	int		ts = 0, ts_start = 0;
2615
2616
	if (strcmp(val,"all") == 0) {
2617
		ts_map = ALL_CHANNELS;
2618
	} else {
2619
		while (*ptr != '\0') {
2620
			if (isdigit((unsigned char)*ptr)) {
2621
				ts = strtoul(ptr, &ptr, 10);
2622
				ts_flag |= SINGLE_CHANNEL;
2623
			} else {
2624
				if (*ptr == '-') {
2625
					ts_flag |= RANGE_CHANNEL;
2626
					ts_start = ts;
2627
				} else {
2628
					ts_map |= get_ts_map(ts_flag,
2629
					    ts_start, ts);
2630
					ts_flag = 0;
2631
				}
2632
				ptr++;
2633
			}
2634
		}
2635
		if (ts_flag)
2636
			ts_map |= get_ts_map(ts_flag, ts_start, ts);
2637
2638
	}
2639
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2640
	ifr.ifr_data = (caddr_t)&ts_map;
2641
2642
	if (ioctl(s, SIOCSIFTIMESLOT, (caddr_t)&ifr) < 0)
2643
		err(1, "SIOCSIFTIMESLOT");
2644
}
2645
2646
unsigned long
2647
get_ts_map(int ts_flag, int ts_start, int ts_stop)
2648
{
2649
	int		i = 0;
2650
	unsigned long	map = 0, mask = 0;
2651
2652
	if ((ts_flag & (SINGLE_CHANNEL | RANGE_CHANNEL)) == 0)
2653
		return 0;
2654
	if (ts_flag & RANGE_CHANNEL) { /* Range of channels */
2655
		for (i = ts_start; i <= ts_stop; i++) {
2656
			mask = 1 << i;
2657
			map |=mask;
2658
		}
2659
	} else { /* Single channel */
2660
		mask = 1 << ts_stop;
2661
		map |= mask;
2662
	}
2663
	return map;
2664
}
2665
2666
void
2667
timeslot_status(void)
2668
{
2669
	char		*sep = " ";
2670
	unsigned long	 ts_map = 0;
2671
	int		 i, start = -1;
2672
2673
	ifr.ifr_data = (caddr_t)&ts_map;
2674
2675
	if (ioctl(s, SIOCGIFTIMESLOT, (caddr_t)&ifr) == -1)
2676
		return;
2677
2678
	printf("\ttimeslot:");
2679
	for (i = 0; i < sizeof(ts_map) * 8; i++) {
2680
		if (start == -1 && ts_map & (1 << i))
2681
			start = i;
2682
		else if (start != -1 && !(ts_map & (1 << i))) {
2683
			if (start == i - 1)
2684
				printf("%s%d", sep, start);
2685
			else
2686
				printf("%s%d-%d", sep, start, i-1);
2687
			sep = ",";
2688
			start = -1;
2689
		}
2690
	}
2691
	if (start != -1) {
2692
		if (start == i - 1)
2693
			printf("%s%d", sep, start);
2694
		else
2695
			printf("%s%d-%d", sep, start, i-1);
2696
	}
2697
	printf("\n");
2698
}
2699
#endif
2700
2701
2702
const struct ifmedia_description ifm_type_descriptions[] =
2703
    IFM_TYPE_DESCRIPTIONS;
2704
2705
const struct ifmedia_description ifm_subtype_descriptions[] =
2706
    IFM_SUBTYPE_DESCRIPTIONS;
2707
2708
struct ifmedia_description ifm_mode_descriptions[] =
2709
    IFM_MODE_DESCRIPTIONS;
2710
2711
const struct ifmedia_description ifm_option_descriptions[] =
2712
    IFM_OPTION_DESCRIPTIONS;
2713
2714
const char *
2715
get_media_type_string(uint64_t mword)
2716
{
2717
	const struct ifmedia_description *desc;
2718
2719
	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
2720
	    desc++) {
2721
		if (IFM_TYPE(mword) == desc->ifmt_word)
2722
			return (desc->ifmt_string);
2723
	}
2724
	return ("<unknown type>");
2725
}
2726
2727
const char *
2728
get_media_subtype_string(uint64_t mword)
2729
{
2730
	const struct ifmedia_description *desc;
2731
2732
	for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
2733
	    desc++) {
2734
		if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
2735
		    IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
2736
			return (desc->ifmt_string);
2737
	}
2738
	return ("<unknown subtype>");
2739
}
2740
2741
uint64_t
2742
get_media_subtype(uint64_t type, const char *val)
2743
{
2744
	uint64_t rval;
2745
2746
	rval = lookup_media_word(ifm_subtype_descriptions, type, val);
2747
	if (rval == -1)
2748
		errx(1, "unknown %s media subtype: %s",
2749
		    get_media_type_string(type), val);
2750
2751
	return (rval);
2752
}
2753
2754
uint64_t
2755
get_media_mode(uint64_t type, const char *val)
2756
{
2757
	uint64_t rval;
2758
2759
	rval = lookup_media_word(ifm_mode_descriptions, type, val);
2760
	if (rval == -1)
2761
		errx(1, "unknown %s media mode: %s",
2762
		    get_media_type_string(type), val);
2763
	return (rval);
2764
}
2765
2766
uint64_t
2767
get_media_options(uint64_t type, const char *val)
2768
{
2769
	char *optlist, *str;
2770
	uint64_t option, rval = 0;
2771
2772
	/* We muck with the string, so copy it. */
2773
	optlist = strdup(val);
2774
	if (optlist == NULL)
2775
		err(1, "strdup");
2776
	str = optlist;
2777
2778
	/*
2779
	 * Look up the options in the user-provided comma-separated list.
2780
	 */
2781
	for (; (str = strtok(str, ",")) != NULL; str = NULL) {
2782
		option = lookup_media_word(ifm_option_descriptions, type, str);
2783
		if (option == -1)
2784
			errx(1, "unknown %s media option: %s",
2785
			    get_media_type_string(type), str);
2786
		rval |= IFM_OPTIONS(option);
2787
	}
2788
2789
	free(optlist);
2790
	return (rval);
2791
}
2792
2793
uint64_t
2794
lookup_media_word(const struct ifmedia_description *desc, uint64_t type,
2795
    const char *val)
2796
{
2797
2798
	for (; desc->ifmt_string != NULL; desc++) {
2799
		if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
2800
		    strcasecmp(desc->ifmt_string, val) == 0)
2801
			return (desc->ifmt_word);
2802
	}
2803
	return (-1);
2804
}
2805
2806
void
2807
print_media_word(uint64_t ifmw, int print_type, int as_syntax)
2808
{
2809
	const struct ifmedia_description *desc;
2810
	uint64_t seen_option = 0;
2811
2812
	if (print_type)
2813
		printf("%s ", get_media_type_string(ifmw));
2814
	printf("%s%s", as_syntax ? "media " : "",
2815
	    get_media_subtype_string(ifmw));
2816
2817
	/* Find mode. */
2818
	if (IFM_MODE(ifmw) != 0) {
2819
		for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL;
2820
		    desc++) {
2821
			if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
2822
			    IFM_MODE(ifmw) == IFM_MODE(desc->ifmt_word)) {
2823
				printf(" mode %s", desc->ifmt_string);
2824
				break;
2825
			}
2826
		}
2827
	}
2828
2829
	/* Find options. */
2830
	for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
2831
	    desc++) {
2832
		if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
2833
		    (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
2834
		    (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
2835
			if (seen_option == 0)
2836
				printf(" %s", as_syntax ? "mediaopt " : "");
2837
			printf("%s%s", seen_option ? "," : "",
2838
			    desc->ifmt_string);
2839
			seen_option |= IFM_OPTIONS(desc->ifmt_word);
2840
		}
2841
	}
2842
	if (IFM_INST(ifmw) != 0)
2843
		printf(" instance %lld", IFM_INST(ifmw));
2844
}
2845
2846
/* ARGSUSED */
2847
static void
2848
phys_status(int force)
2849
{
2850
	char psrcaddr[NI_MAXHOST];
2851
	char pdstaddr[NI_MAXHOST];
2852
	const char *ver = "";
2853
	const int niflag = NI_NUMERICHOST;
2854
	struct if_laddrreq req;
2855
	in_port_t dstport = 0;
2856
2857
	psrcaddr[0] = pdstaddr[0] = '\0';
2858
2859
	memset(&req, 0, sizeof(req));
2860
	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
2861
	if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0)
2862
		return;
2863
	if (req.addr.ss_family == AF_INET6)
2864
		in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
2865
	if (getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
2866
	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0)
2867
		strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
2868
	if (req.addr.ss_family == AF_INET6)
2869
		ver = "6";
2870
2871
	if (req.dstaddr.ss_family == AF_INET)
2872
		dstport = ((struct sockaddr_in *)&req.dstaddr)->sin_port;
2873
	else if (req.dstaddr.ss_family == AF_INET6) {
2874
		in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
2875
		dstport = ((struct sockaddr_in6 *)&req.dstaddr)->sin6_port;
2876
	}
2877
	if (getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
2878
	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag) != 0)
2879
		strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
2880
2881
	printf("\ttunnel: inet%s %s -> %s", ver,
2882
	    psrcaddr, pdstaddr);
2883
2884
	if (dstport)
2885
		printf(":%u", ntohs(dstport));
2886
	if (ioctl(s, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0 && ifr.ifr_ttl > 0)
2887
		printf(" ttl %d", ifr.ifr_ttl);
2888
#ifndef SMALL
2889
	if (ioctl(s, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
2890
	    (rdomainid != 0 || ifr.ifr_rdomainid != 0))
2891
		printf(" rdomain %d", ifr.ifr_rdomainid);
2892
#endif
2893
	printf("\n");
2894
}
2895
2896
#ifndef SMALL
2897
const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
2898
2899
const struct ifmedia_status_description ifm_status_descriptions[] =
2900
	IFM_STATUS_DESCRIPTIONS;
2901
#endif
2902
2903
const struct if_status_description if_status_descriptions[] =
2904
	LINK_STATE_DESCRIPTIONS;
2905
2906
const char *
2907
get_linkstate(int mt, int link_state)
2908
{
2909
	const struct if_status_description *p;
2910
	static char buf[8];
2911
2912
	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
2913
		if (LINK_STATE_DESC_MATCH(p, mt, link_state))
2914
			return (p->ifs_string);
2915
	}
2916
	snprintf(buf, sizeof(buf), "[#%d]", link_state);
2917
	return buf;
2918
}
2919
2920
/*
2921
 * Print the status of the interface.  If an address family was
2922
 * specified, show it and it only; otherwise, show them all.
2923
 */
2924
void
2925
status(int link, struct sockaddr_dl *sdl, int ls)
2926
{
2927
	const struct afswtch *p = afp;
2928
	struct ifmediareq ifmr;
2929
#ifndef SMALL
2930
	struct ifreq ifrdesc;
2931
	struct ifkalivereq ikardesc;
2932
	char ifdescr[IFDESCRSIZE];
2933
	char ifname[IF_NAMESIZE];
2934
#endif
2935
	uint64_t *media_list;
2936
	int i;
2937
	char sep;
2938
2939
2940
	printf("%s: ", name);
2941
	printb("flags", flags | (xflags << 16), IFFBITS);
2942
	if (rdomainid)
2943
		printf(" rdomain %d", rdomainid);
2944
	if (metric)
2945
		printf(" metric %lu", metric);
2946
	if (mtu)
2947
		printf(" mtu %lu", mtu);
2948
	putchar('\n');
2949
#ifndef SMALL
2950
	if (showcapsflag)
2951
		printifhwfeatures(NULL, 1);
2952
#endif
2953
	if (sdl != NULL && sdl->sdl_alen &&
2954
	    (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
2955
		(void)printf("\tlladdr %s\n", ether_ntoa(
2956
		    (struct ether_addr *)LLADDR(sdl)));
2957
2958
	sep = '\t';
2959
#ifndef SMALL
2960
	(void) memset(&ifrdesc, 0, sizeof(ifrdesc));
2961
	(void) strlcpy(ifrdesc.ifr_name, name, sizeof(ifrdesc.ifr_name));
2962
	ifrdesc.ifr_data = (caddr_t)&ifdescr;
2963
	if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0 &&
2964
	    strlen(ifrdesc.ifr_data))
2965
		printf("\tdescription: %s\n", ifrdesc.ifr_data);
2966
2967
	if (sdl != NULL) {
2968
		printf("%cindex %u", sep, sdl->sdl_index);
2969
		sep = ' ';
2970
	}
2971
	if (!is_bridge(name) && ioctl(s, SIOCGIFPRIORITY, &ifrdesc) == 0) {
2972
		printf("%cpriority %d", sep, ifrdesc.ifr_metric);
2973
		sep = ' ';
2974
	}
2975
#endif
2976
	printf("%cllprio %d\n", sep, llprio);
2977
2978
#ifndef SMALL
2979
	(void) memset(&ikardesc, 0, sizeof(ikardesc));
2980
	(void) strlcpy(ikardesc.ikar_name, name, sizeof(ikardesc.ikar_name));
2981
	if (ioctl(s, SIOCGETKALIVE, &ikardesc) == 0 &&
2982
	    (ikardesc.ikar_timeo != 0 || ikardesc.ikar_cnt != 0))
2983
		printf("\tkeepalive: timeout %d count %d\n",
2984
		    ikardesc.ikar_timeo, ikardesc.ikar_cnt);
2985
	if (ioctl(s, SIOCGIFPAIR, &ifrdesc) == 0 && ifrdesc.ifr_index != 0 &&
2986
	    if_indextoname(ifrdesc.ifr_index, ifname) != NULL)
2987
		printf("\tpatch: %s\n", ifname);
2988
#endif
2989
	vlan_status();
2990
	getvnetid();
2991
	getifparent();
2992
#ifndef SMALL
2993
	carp_status();
2994
	pfsync_status();
2995
	pppoe_status();
2996
	timeslot_status();
2997
	sppp_status();
2998
	mpe_status();
2999
	mpw_status();
3000
	pflow_status();
3001
	umb_status();
3002
#endif
3003
	trunk_status();
3004
	getifgroups();
3005
3006
	(void) memset(&ifmr, 0, sizeof(ifmr));
3007
	(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
3008
3009
	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
3010
		/*
3011
		 * Interface doesn't support SIOC{G,S}IFMEDIA.
3012
		 */
3013
		if (ls != LINK_STATE_UNKNOWN)
3014
			printf("\tstatus: %s\n",
3015
			    get_linkstate(sdl->sdl_type, ls));
3016
		goto proto_status;
3017
	}
3018
3019
	if (ifmr.ifm_count == 0) {
3020
		warnx("%s: no media types?", name);
3021
		goto proto_status;
3022
	}
3023
3024
	media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
3025
	if (media_list == NULL)
3026
		err(1, "calloc");
3027
	ifmr.ifm_ulist = media_list;
3028
3029
	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
3030
		err(1, "SIOCGIFMEDIA");
3031
3032
	printf("\tmedia: ");
3033
	print_media_word(ifmr.ifm_current, 1, 0);
3034
	if (ifmr.ifm_active != ifmr.ifm_current) {
3035
		putchar(' ');
3036
		putchar('(');
3037
		print_media_word(ifmr.ifm_active, 0, 0);
3038
		putchar(')');
3039
	}
3040
	putchar('\n');
3041
3042
#ifdef SMALL
3043
	printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
3044
#else
3045
	if (ifmr.ifm_status & IFM_AVALID) {
3046
		const struct ifmedia_status_description *ifms;
3047
		int bitno, found = 0;
3048
3049
		printf("\tstatus: ");
3050
		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
3051
			for (ifms = ifm_status_descriptions;
3052
			    ifms->ifms_valid != 0; ifms++) {
3053
				if (ifms->ifms_type !=
3054
				    IFM_TYPE(ifmr.ifm_current) ||
3055
				    ifms->ifms_valid !=
3056
				    ifm_status_valid_list[bitno])
3057
					continue;
3058
				printf("%s%s", found ? ", " : "",
3059
				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
3060
				found = 1;
3061
3062
				/*
3063
				 * For each valid indicator bit, there's
3064
				 * only one entry for each media type, so
3065
				 * terminate the inner loop now.
3066
				 */
3067
				break;
3068
			}
3069
		}
3070
3071
		if (found == 0)
3072
			printf("unknown");
3073
		putchar('\n');
3074
	}
3075
#endif
3076
	ieee80211_status();
3077
3078
	if (showmediaflag) {
3079
		uint64_t type;
3080
		int printed_type = 0;
3081
3082
		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
3083
			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
3084
				if (IFM_TYPE(media_list[i]) == type) {
3085
3086
					/*
3087
					 * Don't advertise media with fixed
3088
					 * data rates for wireless interfaces.
3089
					 * Normal people don't need these.
3090
					 */
3091
					if (type == IFM_IEEE80211 &&
3092
					    (media_list[i] & IFM_TMASK) !=
3093
					    IFM_AUTO)
3094
						continue;
3095
3096
					if (printed_type == 0) {
3097
					    printf("\tsupported media:\n");
3098
					    printed_type = 1;
3099
					}
3100
					printf("\t\t");
3101
					print_media_word(media_list[i], 0, 1);
3102
					printf("\n");
3103
				}
3104
			}
3105
		}
3106
	}
3107
3108
	free(media_list);
3109
3110
 proto_status:
3111
	if (link == 0) {
3112
		if ((p = afp) != NULL) {
3113
			p->af_status(1);
3114
		} else for (p = afs; p->af_name; p++) {
3115
			ifr.ifr_addr.sa_family = p->af_af;
3116
			p->af_status(0);
3117
		}
3118
	}
3119
3120
	phys_status(0);
3121
#ifndef SMALL
3122
	bridge_status();
3123
#endif
3124
}
3125
3126
/* ARGSUSED */
3127
void
3128
in_status(int force)
3129
{
3130
	struct sockaddr_in *sin, sin2;
3131
3132
	getsock(AF_INET);
3133
	if (s < 0) {
3134
		if (errno == EPROTONOSUPPORT)
3135
			return;
3136
		err(1, "socket");
3137
	}
3138
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3139
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
3140
3141
	/*
3142
	 * We keep the interface address and reset it before each
3143
	 * ioctl() so we can get ifaliases information (as opposed
3144
	 * to the primary interface netmask/dstaddr/broadaddr, if
3145
	 * the ifr_addr field is zero).
3146
	 */
3147
	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
3148
3149
	printf("\tinet %s", inet_ntoa(sin->sin_addr));
3150
	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3151
	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
3152
		if (errno != EADDRNOTAVAIL)
3153
			warn("SIOCGIFNETMASK");
3154
		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3155
	} else
3156
		netmask.sin_addr =
3157
		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
3158
	if (flags & IFF_POINTOPOINT) {
3159
		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3160
		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
3161
			if (errno == EADDRNOTAVAIL)
3162
			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3163
			else
3164
			    warn("SIOCGIFDSTADDR");
3165
		}
3166
		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3167
		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
3168
		printf(" --> %s", inet_ntoa(sin->sin_addr));
3169
	}
3170
	printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
3171
	if (flags & IFF_BROADCAST) {
3172
		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3173
		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
3174
			if (errno == EADDRNOTAVAIL)
3175
			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3176
			else
3177
			    warn("SIOCGIFBRDADDR");
3178
		}
3179
		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3180
		sin = (struct sockaddr_in *)&ifr.ifr_addr;
3181
		if (sin->sin_addr.s_addr != 0)
3182
			printf(" broadcast %s", inet_ntoa(sin->sin_addr));
3183
	}
3184
	putchar('\n');
3185
}
3186
3187
/* ARGSUSED */
3188
void
3189
setifprefixlen(const char *addr, int d)
3190
2
{
3191
2
	if (afp->af_getprefix)
3192
2
		afp->af_getprefix(addr, MASK);
3193
2
	explicit_prefix = 1;
3194
2
}
3195
3196
void
3197
in6_fillscopeid(struct sockaddr_in6 *sin6)
3198
{
3199
#ifdef __KAME__
3200
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
3201
		sin6->sin6_scope_id =
3202
			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3203
		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
3204
	}
3205
#endif /* __KAME__ */
3206
}
3207
3208
/* XXX not really an alias */
3209
void
3210
in6_alias(struct in6_ifreq *creq)
3211
{
3212
	struct sockaddr_in6 *sin6;
3213
	struct	in6_ifreq ifr6;		/* shadows file static variable */
3214
	u_int32_t scopeid;
3215
	char hbuf[NI_MAXHOST];
3216
	const int niflag = NI_NUMERICHOST;
3217
3218
	/* Get the non-alias address for this interface. */
3219
	getsock(AF_INET6);
3220
	if (s < 0) {
3221
		if (errno == EPROTONOSUPPORT)
3222
			return;
3223
		err(1, "socket");
3224
	}
3225
3226
	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
3227
3228
	in6_fillscopeid(sin6);
3229
	scopeid = sin6->sin6_scope_id;
3230
	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3231
	    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3232
		strlcpy(hbuf, "", sizeof hbuf);
3233
	printf("\tinet6 %s", hbuf);
3234
3235
	if (flags & IFF_POINTOPOINT) {
3236
		(void) memset(&ifr6, 0, sizeof(ifr6));
3237
		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3238
		ifr6.ifr_addr = creq->ifr_addr;
3239
		if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
3240
			if (errno != EADDRNOTAVAIL)
3241
				warn("SIOCGIFDSTADDR_IN6");
3242
			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
3243
			ifr6.ifr_addr.sin6_family = AF_INET6;
3244
			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
3245
		}
3246
		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3247
		in6_fillscopeid(sin6);
3248
		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3249
		    hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3250
			strlcpy(hbuf, "", sizeof hbuf);
3251
		printf(" -> %s", hbuf);
3252
	}
3253
3254
	(void) memset(&ifr6, 0, sizeof(ifr6));
3255
	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3256
	ifr6.ifr_addr = creq->ifr_addr;
3257
	if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
3258
		if (errno != EADDRNOTAVAIL)
3259
			warn("SIOCGIFNETMASK_IN6");
3260
	} else {
3261
		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3262
		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
3263
		    sizeof(struct in6_addr)));
3264
	}
3265
3266
	(void) memset(&ifr6, 0, sizeof(ifr6));
3267
	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3268
	ifr6.ifr_addr = creq->ifr_addr;
3269
	if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
3270
		if (errno != EADDRNOTAVAIL)
3271
			warn("SIOCGIFAFLAG_IN6");
3272
	} else {
3273
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
3274
			printf(" anycast");
3275
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
3276
			printf(" tentative");
3277
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
3278
			printf(" duplicated");
3279
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
3280
			printf(" detached");
3281
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
3282
			printf(" deprecated");
3283
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
3284
			printf(" autoconf");
3285
		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PRIVACY)
3286
			printf(" autoconfprivacy");
3287
	}
3288
3289
	if (scopeid)
3290
		printf(" scopeid 0x%x", scopeid);
3291
3292
	if (Lflag) {
3293
		struct in6_addrlifetime *lifetime;
3294
3295
		(void) memset(&ifr6, 0, sizeof(ifr6));
3296
		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
3297
		ifr6.ifr_addr = creq->ifr_addr;
3298
		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
3299
		if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
3300
			if (errno != EADDRNOTAVAIL)
3301
				warn("SIOCGIFALIFETIME_IN6");
3302
		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
3303
			time_t t = time(NULL);
3304
3305
			printf(" pltime ");
3306
			if (lifetime->ia6t_preferred) {
3307
				printf("%s", lifetime->ia6t_preferred < t
3308
				    ? "0" :
3309
				    sec2str(lifetime->ia6t_preferred - t));
3310
			} else
3311
				printf("infty");
3312
3313
			printf(" vltime ");
3314
			if (lifetime->ia6t_expire) {
3315
				printf("%s", lifetime->ia6t_expire < t
3316
				    ? "0"
3317
				    : sec2str(lifetime->ia6t_expire - t));
3318
			} else
3319
				printf("infty");
3320
		}
3321
	}
3322
3323
	printf("\n");
3324
}
3325
3326
void
3327
in6_status(int force)
3328
{
3329
	in6_alias((struct in6_ifreq *)&ifr6);
3330
}
3331
3332
#ifndef SMALL
3333
void
3334
settunnel(const char *src, const char *dst)
3335
{
3336
	char buf[HOST_NAME_MAX+1 + sizeof (":65535")], *dstport;
3337
	const char *dstip;
3338
	struct addrinfo *srcres, *dstres;
3339
	int ecode;
3340
	struct if_laddrreq req;
3341
3342
	if (strchr(dst, ':') == NULL || strchr(dst, ':') != strrchr(dst, ':')) {
3343
		/* no port or IPv6 */
3344
		dstip = dst;
3345
		dstport = NULL;
3346
	} else {
3347
		if (strlcpy(buf, dst, sizeof(buf)) >= sizeof(buf))
3348
			errx(1, "%s bad value", dst);
3349
		dstport = strchr(buf, ':');
3350
		*dstport++ = '\0';
3351
		dstip = buf;
3352
	}
3353
3354
	if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
3355
		errx(1, "error in parsing address string: %s",
3356
		    gai_strerror(ecode));
3357
3358
	if ((ecode = getaddrinfo(dstip, dstport, NULL, &dstres)) != 0)
3359
		errx(1, "error in parsing address string: %s",
3360
		    gai_strerror(ecode));
3361
3362
	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
3363
		errx(1,
3364
		    "source and destination address families do not match");
3365
3366
	if (srcres->ai_addrlen > sizeof(req.addr) ||
3367
	    dstres->ai_addrlen > sizeof(req.dstaddr))
3368
		errx(1, "invalid sockaddr");
3369
3370
	memset(&req, 0, sizeof(req));
3371
	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
3372
	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
3373
	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
3374
	if (ioctl(s, SIOCSLIFPHYADDR, &req) < 0)
3375
		warn("SIOCSLIFPHYADDR");
3376
3377
	freeaddrinfo(srcres);
3378
	freeaddrinfo(dstres);
3379
}
3380
3381
/* ARGSUSED */
3382
void
3383
deletetunnel(const char *ignored, int alsoignored)
3384
{
3385
	if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
3386
		warn("SIOCDIFPHYADDR");
3387
}
3388
3389
void
3390
settunnelinst(const char *id, int param)
3391
{
3392
	const char *errmsg = NULL;
3393
	int rdomainid;
3394
3395
	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
3396
	if (errmsg)
3397
		errx(1, "rdomain %s: %s", id, errmsg);
3398
3399
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3400
	ifr.ifr_rdomainid = rdomainid;
3401
	if (ioctl(s, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) < 0)
3402
		warn("SIOCSLIFPHYRTABLE");
3403
}
3404
3405
void
3406
settunnelttl(const char *id, int param)
3407
{
3408
	const char *errmsg = NULL;
3409
	int ttl;
3410
3411
	ttl = strtonum(id, 0, 0xff, &errmsg);
3412
	if (errmsg)
3413
		errx(1, "tunnelttl %s: %s", id, errmsg);
3414
3415
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3416
	ifr.ifr_ttl = ttl;
3417
	if (ioctl(s, SIOCSLIFPHYTTL, (caddr_t)&ifr) < 0)
3418
		warn("SIOCSLIFPHYTTL");
3419
}
3420
3421
void
3422
mpe_status(void)
3423
{
3424
	struct shim_hdr	shim;
3425
3426
	bzero(&shim, sizeof(shim));
3427
	ifr.ifr_data = (caddr_t)&shim;
3428
3429
	if (ioctl(s, SIOCGETLABEL , (caddr_t)&ifr) == -1)
3430
		return;
3431
	printf("\tmpls label: %d\n", shim.shim_label);
3432
}
3433
3434
void
3435
mpw_status(void)
3436
{
3437
	struct sockaddr_in *sin;
3438
	struct ifmpwreq imr;
3439
3440
	bzero(&imr, sizeof(imr));
3441
	ifr.ifr_data = (caddr_t) &imr;
3442
	if (ioctl(s, SIOCGETMPWCFG, (caddr_t) &ifr) == -1)
3443
		return;
3444
3445
	printf("\tencapsulation-type ");
3446
	switch (imr.imr_type) {
3447
	case IMR_TYPE_NONE:
3448
		printf("none");
3449
		break;
3450
	case IMR_TYPE_ETHERNET:
3451
		printf("ethernet");
3452
		break;
3453
	case IMR_TYPE_ETHERNET_TAGGED:
3454
		printf("ethernet-tagged");
3455
		break;
3456
	default:
3457
		printf("unknown");
3458
		break;
3459
	}
3460
3461
	if (imr.imr_flags & IMR_FLAG_CONTROLWORD)
3462
		printf(", control-word");
3463
3464
	printf("\n");
3465
3466
	printf("\tmpls label: ");
3467
	if (imr.imr_lshim.shim_label == 0)
3468
		printf("local none ");
3469
	else
3470
		printf("local %u ", imr.imr_lshim.shim_label);
3471
3472
	if (imr.imr_rshim.shim_label == 0)
3473
		printf("remote none\n");
3474
	else
3475
		printf("remote %u\n", imr.imr_rshim.shim_label);
3476
3477
	sin = (struct sockaddr_in *) &imr.imr_nexthop;
3478
	if (sin->sin_addr.s_addr == 0)
3479
		printf("\tneighbor: none\n");
3480
	else
3481
		printf("\tneighbor: %s\n", inet_ntoa(sin->sin_addr));
3482
}
3483
3484
/* ARGSUSED */
3485
void
3486
setmpelabel(const char *val, int d)
3487
{
3488
	struct shim_hdr	 shim;
3489
	const char	*estr;
3490
3491
	bzero(&shim, sizeof(shim));
3492
	ifr.ifr_data = (caddr_t)&shim;
3493
	shim.shim_label = strtonum(val, 0, MPLS_LABEL_MAX, &estr);
3494
3495
	if (estr)
3496
		errx(1, "mpls label %s is %s", val, estr);
3497
	if (ioctl(s, SIOCSETLABEL, (caddr_t)&ifr) == -1)
3498
		warn("SIOCSETLABEL");
3499
}
3500
3501
void
3502
process_mpw_commands(void)
3503
102
{
3504
	struct	sockaddr_in *sin, *sinn;
3505
	struct	ifmpwreq imr;
3506
3507
102
	if (wconfig == 0)
3508
102
		return;
3509
3510
	bzero(&imr, sizeof(imr));
3511
	ifr.ifr_data = (caddr_t) &imr;
3512
	if (ioctl(s, SIOCGETMPWCFG, (caddr_t) &ifr) == -1)
3513
		err(1, "SIOCGETMPWCFG");
3514
3515
	if (imrsave.imr_type == 0) {
3516
		if (imr.imr_type == 0)
3517
			imrsave.imr_type = IMR_TYPE_ETHERNET;
3518
3519
		imrsave.imr_type = imr.imr_type;
3520
	}
3521
	if (wcwconfig == 0)
3522
		imrsave.imr_flags |= imr.imr_flags;
3523
3524
	if (imrsave.imr_lshim.shim_label == 0 ||
3525
	    imrsave.imr_rshim.shim_label == 0) {
3526
		if (imr.imr_lshim.shim_label == 0 ||
3527
		    imr.imr_rshim.shim_label == 0)
3528
			errx(1, "mpw local / remote label not specified");
3529
3530
		imrsave.imr_lshim.shim_label = imr.imr_lshim.shim_label;
3531
		imrsave.imr_rshim.shim_label = imr.imr_rshim.shim_label;
3532
	}
3533
3534
	sin = (struct sockaddr_in *) &imrsave.imr_nexthop;
3535
	sinn = (struct sockaddr_in *) &imr.imr_nexthop;
3536
	if (sin->sin_addr.s_addr == 0) {
3537
		if (sinn->sin_addr.s_addr == 0)
3538
			errx(1, "mpw neighbor address not specified");
3539
3540
		sin->sin_family = sinn->sin_family;
3541
		sin->sin_addr.s_addr = sinn->sin_addr.s_addr;
3542
	}
3543
3544
	ifr.ifr_data = (caddr_t) &imrsave;
3545
	if (ioctl(s, SIOCSETMPWCFG, (caddr_t) &ifr) == -1)
3546
		err(1, "SIOCSETMPWCFG");
3547
}
3548
3549
void
3550
setmpwencap(const char *value, int d)
3551
{
3552
	wconfig = 1;
3553
3554
	if (strcmp(value, "ethernet") == 0)
3555
		imrsave.imr_type = IMR_TYPE_ETHERNET;
3556
	else if (strcmp(value, "ethernet-tagged") == 0)
3557
		imrsave.imr_type = IMR_TYPE_ETHERNET_TAGGED;
3558
	else
3559
		errx(1, "invalid mpw encapsulation type");
3560
}
3561
3562
void
3563
setmpwlabel(const char *local, const char *remote)
3564
{
3565
	const	char *errstr;
3566
3567
	wconfig = 1;
3568
3569
	imrsave.imr_lshim.shim_label = strtonum(local,
3570
	    (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
3571
	if (errstr != NULL)
3572
		errx(1, "invalid local label: %s", errstr);
3573
3574
	imrsave.imr_rshim.shim_label = strtonum(remote,
3575
	    (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
3576
	if (errstr != NULL)
3577
		errx(1, "invalid remote label: %s", errstr);
3578
}
3579
3580
void
3581
setmpwneighbor(const char *value, int d)
3582
{
3583
	struct sockaddr_in *sin;
3584
3585
	wconfig = 1;
3586
3587
	sin = (struct sockaddr_in *) &imrsave.imr_nexthop;
3588
	if (inet_aton(value, &sin->sin_addr) == 0)
3589
		errx(1, "invalid neighbor addresses");
3590
3591
	sin->sin_family = AF_INET;
3592
}
3593
3594
void
3595
setmpwcontrolword(const char *value, int d)
3596
{
3597
	wconfig = 1;
3598
	wcwconfig = 1;
3599
3600
	if (d == 1)
3601
		imrsave.imr_flags |= IMR_FLAG_CONTROLWORD;
3602
	else
3603
		imrsave.imr_flags &= ~IMR_FLAG_CONTROLWORD;
3604
}
3605
#endif /* SMALL */
3606
3607
void
3608
setvnetid(const char *id, int param)
3609
{
3610
	const char *errmsg = NULL;
3611
	uint32_t vnetid;
3612
3613
	vnetid = strtonum(id, 0, UINT_MAX, &errmsg);
3614
	if (errmsg)
3615
		errx(1, "vnetid %s: %s", id, errmsg);
3616
3617
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3618
	ifr.ifr_vnetid = vnetid;
3619
	if (ioctl(s, SIOCSVNETID, (caddr_t)&ifr) < 0)
3620
		warn("SIOCSVNETID");
3621
}
3622
3623
/* ARGSUSED */
3624
void
3625
delvnetid(const char *ignored, int alsoignored)
3626
{
3627
	if (ioctl(s, SIOCDVNETID, &ifr) < 0)
3628
		warn("SIOCDVNETID");
3629
}
3630
3631
void
3632
getvnetid(void)
3633
{
3634
	if (strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) >=
3635
	    sizeof(ifr.ifr_name))
3636
		errx(1, "vnetid: name is too long");
3637
3638
	if (ioctl(s, SIOCGVNETID, &ifr) == -1) {
3639
		if (errno != EADDRNOTAVAIL)
3640
			return;
3641
3642
		printf("\tvnetid: none\n");
3643
3644
		return;
3645
	}
3646
3647
	printf("\tvnetid: %u\n", ifr.ifr_vnetid);
3648
}
3649
3650
void
3651
setifparent(const char *id, int param)
3652
{
3653
	struct if_parent ifp;
3654
3655
	if (strlcpy(ifp.ifp_name, name, sizeof(ifp.ifp_name)) >=
3656
	    sizeof(ifp.ifp_name))
3657
		errx(1, "parent: name too long");
3658
3659
	if (strlcpy(ifp.ifp_parent, id, sizeof(ifp.ifp_parent)) >=
3660
	    sizeof(ifp.ifp_parent))
3661
		errx(1, "parent: parent too long");
3662
3663
	if (ioctl(s, SIOCSIFPARENT, (caddr_t)&ifp) < 0)
3664
		warn("SIOCSIFPARENT");
3665
}
3666
3667
/* ARGSUSED */
3668
void
3669
delifparent(const char *ignored, int alsoignored)
3670
{
3671
	if (ioctl(s, SIOCDIFPARENT, &ifr) < 0)
3672
		warn("SIOCDIFPARENT");
3673
}
3674
3675
void
3676
getifparent(void)
3677
{
3678
	struct if_parent ifp;
3679
	const char *parent = "none";
3680
3681
	memset(&ifp, 0, sizeof(ifp));
3682
	if (strlcpy(ifp.ifp_name, name, sizeof(ifp.ifp_name)) >=
3683
	    sizeof(ifp.ifp_name))
3684
		errx(1, "parent: name too long");
3685
3686
	if (ioctl(s, SIOCGIFPARENT, (caddr_t)&ifp) == -1) {
3687
		if (errno != EADDRNOTAVAIL)
3688
			return;
3689
	} else
3690
		parent = ifp.ifp_parent;
3691
3692
	printf("\tparent: %s\n", parent);
3693
}
3694
3695
static int __tag = 0;
3696
static int __have_tag = 0;
3697
3698
void
3699
vlan_status(void)
3700
{
3701
	struct vlanreq vreq;
3702
3703
	bzero((char *)&vreq, sizeof(struct vlanreq));
3704
	ifr.ifr_data = (caddr_t)&vreq;
3705
3706
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3707
		return;
3708
3709
	if (vreq.vlr_tag || (vreq.vlr_parent[0] != '\0'))
3710
		printf("\tvlan: %d parent interface: %s\n",
3711
		    vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
3712
		    "<none>" : vreq.vlr_parent);
3713
}
3714
3715
/* ARGSUSED */
3716
void
3717
setvlantag(const char *val, int d)
3718
{
3719
	u_int16_t tag;
3720
	struct vlanreq vreq;
3721
	const char *errmsg = NULL;
3722
3723
	__tag = tag = strtonum(val, 0, 4095, &errmsg);
3724
	if (errmsg)
3725
		errx(1, "vlan tag %s: %s", val, errmsg);
3726
	__have_tag = 1;
3727
3728
	bzero((char *)&vreq, sizeof(struct vlanreq));
3729
	ifr.ifr_data = (caddr_t)&vreq;
3730
3731
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3732
		err(1, "SIOCGETVLAN");
3733
3734
	vreq.vlr_tag = tag;
3735
3736
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3737
		err(1, "SIOCSETVLAN");
3738
}
3739
3740
/* ARGSUSED */
3741
void
3742
setvlandev(const char *val, int d)
3743
{
3744
	struct vlanreq	 vreq;
3745
	int		 tag;
3746
	size_t		 skip;
3747
	const char	*estr;
3748
3749
	bzero((char *)&vreq, sizeof(struct vlanreq));
3750
	ifr.ifr_data = (caddr_t)&vreq;
3751
3752
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3753
		err(1, "SIOCGETVLAN");
3754
3755
	(void) strlcpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
3756
3757
	if (!__have_tag && vreq.vlr_tag == 0) {
3758
		skip = strcspn(ifr.ifr_name, "0123456789");
3759
		tag = strtonum(ifr.ifr_name + skip, 0, 4095, &estr);
3760
		if (estr != NULL)
3761
			errx(1, "invalid vlan tag and device specification");
3762
		vreq.vlr_tag = tag;
3763
	} else if (__have_tag)
3764
		vreq.vlr_tag = __tag;
3765
3766
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3767
		err(1, "SIOCSETVLAN");
3768
}
3769
3770
/* ARGSUSED */
3771
void
3772
unsetvlandev(const char *val, int d)
3773
{
3774
	struct vlanreq vreq;
3775
3776
	bzero((char *)&vreq, sizeof(struct vlanreq));
3777
	ifr.ifr_data = (caddr_t)&vreq;
3778
3779
	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
3780
		err(1, "SIOCGETVLAN");
3781
3782
	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
3783
	vreq.vlr_tag = 0;
3784
3785
	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
3786
		err(1, "SIOCSETVLAN");
3787
}
3788
3789
void
3790
settrunkport(const char *val, int d)
3791
{
3792
	struct trunk_reqport rp;
3793
3794
	bzero(&rp, sizeof(rp));
3795
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3796
	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
3797
3798
	if (ioctl(s, SIOCSTRUNKPORT, &rp))
3799
		err(1, "SIOCSTRUNKPORT");
3800
}
3801
3802
void
3803
unsettrunkport(const char *val, int d)
3804
{
3805
	struct trunk_reqport rp;
3806
3807
	bzero(&rp, sizeof(rp));
3808
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3809
	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
3810
3811
	if (ioctl(s, SIOCSTRUNKDELPORT, &rp))
3812
		err(1, "SIOCSTRUNKDELPORT");
3813
}
3814
3815
void
3816
settrunkproto(const char *val, int d)
3817
{
3818
	struct trunk_protos tpr[] = TRUNK_PROTOS;
3819
	struct trunk_reqall ra;
3820
	int i;
3821
3822
	bzero(&ra, sizeof(ra));
3823
	ra.ra_proto = TRUNK_PROTO_MAX;
3824
3825
	for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
3826
		if (strcmp(val, tpr[i].tpr_name) == 0) {
3827
			ra.ra_proto = tpr[i].tpr_proto;
3828
			break;
3829
		}
3830
	}
3831
	if (ra.ra_proto == TRUNK_PROTO_MAX)
3832
		errx(1, "Invalid trunk protocol: %s", val);
3833
3834
	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
3835
	if (ioctl(s, SIOCSTRUNK, &ra) != 0)
3836
		err(1, "SIOCSTRUNK");
3837
}
3838
3839
void
3840
trunk_status(void)
3841
{
3842
	struct trunk_protos tpr[] = TRUNK_PROTOS;
3843
	struct trunk_reqport rp, rpbuf[TRUNK_MAX_PORTS];
3844
	struct trunk_reqall ra;
3845
	struct lacp_opreq *lp;
3846
	const char *proto = "<unknown>";
3847
	int i, isport = 0;
3848
3849
	bzero(&rp, sizeof(rp));
3850
	bzero(&ra, sizeof(ra));
3851
3852
	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
3853
	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
3854
3855
	if (ioctl(s, SIOCGTRUNKPORT, &rp) == 0)
3856
		isport = 1;
3857
3858
	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
3859
	ra.ra_size = sizeof(rpbuf);
3860
	ra.ra_port = rpbuf;
3861
3862
	if (ioctl(s, SIOCGTRUNK, &ra) == 0) {
3863
		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
3864
3865
		for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
3866
			if (ra.ra_proto == tpr[i].tpr_proto) {
3867
				proto = tpr[i].tpr_name;
3868
				break;
3869
			}
3870
		}
3871
3872
		printf("\ttrunk: trunkproto %s", proto);
3873
		if (isport)
3874
			printf(" trunkdev %s", rp.rp_ifname);
3875
		putchar('\n');
3876
		if (ra.ra_proto == TRUNK_PROTO_LACP) {
3877
			char *act_mac = strdup(
3878
			    ether_ntoa((struct ether_addr*)lp->actor_mac));
3879
			if (act_mac == NULL)
3880
				err(1, "strdup");
3881
			printf("\ttrunk id: [(%04X,%s,%04X,%04X,%04X),\n"
3882
			    "\t\t (%04X,%s,%04X,%04X,%04X)]\n",
3883
			    lp->actor_prio, act_mac,
3884
			    lp->actor_key, lp->actor_portprio, lp->actor_portno,
3885
			    lp->partner_prio,
3886
			    ether_ntoa((struct ether_addr*)lp->partner_mac),
3887
			    lp->partner_key, lp->partner_portprio,
3888
			    lp->partner_portno);
3889
			free(act_mac);
3890
		}
3891
3892
		for (i = 0; i < ra.ra_ports; i++) {
3893
			printf("\t\ttrunkport %s ", rpbuf[i].rp_portname);
3894
			printb_status(rpbuf[i].rp_flags, TRUNK_PORT_BITS);
3895
			putchar('\n');
3896
		}
3897
3898
		if (showmediaflag) {
3899
			printf("\tsupported trunk protocols:\n");
3900
			for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++)
3901
				printf("\t\ttrunkproto %s\n", tpr[i].tpr_name);
3902
		}
3903
	} else if (isport)
3904
		printf("\ttrunk: trunkdev %s\n", rp.rp_ifname);
3905
}
3906
3907
#ifndef SMALL
3908
static const char *carp_states[] = { CARP_STATES };
3909
static const char *carp_bal_modes[] = { CARP_BAL_MODES };
3910
3911
void
3912
carp_status(void)
3913
{
3914
	const char *state, *balmode;
3915
	struct carpreq carpr;
3916
	char peer[32];
3917
	int i;
3918
3919
	memset((char *)&carpr, 0, sizeof(struct carpreq));
3920
	ifr.ifr_data = (caddr_t)&carpr;
3921
3922
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3923
		return;
3924
3925
	if (carpr.carpr_vhids[0] == 0)
3926
		return;
3927
3928
	if (carpr.carpr_balancing > CARP_BAL_MAXID)
3929
		balmode = "<UNKNOWN>";
3930
	else
3931
		balmode = carp_bal_modes[carpr.carpr_balancing];
3932
3933
	if (carpr.carpr_peer.s_addr != htonl(INADDR_CARP_GROUP))
3934
		snprintf(peer, sizeof(peer),
3935
		    " carppeer %s", inet_ntoa(carpr.carpr_peer));
3936
	else
3937
		peer[0] = '\0';
3938
3939
	for (i = 0; carpr.carpr_vhids[i]; i++) {
3940
		if (carpr.carpr_states[i] > CARP_MAXSTATE)
3941
			state = "<UNKNOWN>";
3942
		else
3943
			state = carp_states[carpr.carpr_states[i]];
3944
		if (carpr.carpr_vhids[1] == 0) {
3945
			printf("\tcarp: %s carpdev %s vhid %u advbase %d "
3946
			    "advskew %u%s\n", state,
3947
			    carpr.carpr_carpdev[0] != '\0' ?
3948
			    carpr.carpr_carpdev : "none", carpr.carpr_vhids[0],
3949
			    carpr.carpr_advbase, carpr.carpr_advskews[0],
3950
			    peer);
3951
		} else {
3952
			if (i == 0) {
3953
				printf("\tcarp: carpdev %s advbase %d"
3954
				    " balancing %s%s\n",
3955
				    carpr.carpr_carpdev[0] != '\0' ?
3956
				    carpr.carpr_carpdev : "none",
3957
				    carpr.carpr_advbase, balmode, peer);
3958
			}
3959
			printf("\t\tstate %s vhid %u advskew %u\n", state,
3960
			    carpr.carpr_vhids[i], carpr.carpr_advskews[i]);
3961
		}
3962
	}
3963
}
3964
3965
/* ARGSUSED */
3966
void
3967
setcarp_passwd(const char *val, int d)
3968
{
3969
	struct carpreq carpr;
3970
3971
	bzero(&carpr, sizeof(struct carpreq));
3972
	ifr.ifr_data = (caddr_t)&carpr;
3973
3974
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
3975
		err(1, "SIOCGVH");
3976
3977
	bzero(carpr.carpr_key, CARP_KEY_LEN);
3978
	strlcpy((char *)carpr.carpr_key, val, CARP_KEY_LEN);
3979
3980
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
3981
		err(1, "SIOCSVH");
3982
}
3983
3984
/* ARGSUSED */
3985
void
3986
setcarp_vhid(const char *val, int d)
3987
{
3988
	const char *errmsg = NULL;
3989
	struct carpreq carpr;
3990
	int vhid;
3991
3992
	vhid = strtonum(val, 1, 255, &errmsg);
3993
	if (errmsg)
3994
		errx(1, "vhid %s: %s", val, errmsg);
3995
3996
	bzero(&carpr, sizeof(struct carpreq));
3997
	ifr.ifr_data = (caddr_t)&carpr;
3998
3999
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4000
		err(1, "SIOCGVH");
4001
4002
	carpr.carpr_vhids[0] = vhid;
4003
	carpr.carpr_vhids[1] = 0;
4004
4005
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4006
		err(1, "SIOCSVH");
4007
}
4008
4009
/* ARGSUSED */
4010
void
4011
setcarp_advskew(const char *val, int d)
4012
{
4013
	const char *errmsg = NULL;
4014
	struct carpreq carpr;
4015
	int advskew;
4016
4017
	advskew = strtonum(val, 0, 254, &errmsg);
4018
	if (errmsg)
4019
		errx(1, "advskew %s: %s", val, errmsg);
4020
4021
	bzero(&carpr, sizeof(struct carpreq));
4022
	ifr.ifr_data = (caddr_t)&carpr;
4023
4024
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4025
		err(1, "SIOCGVH");
4026
4027
	carpr.carpr_advskews[0] = advskew;
4028
4029
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4030
		err(1, "SIOCSVH");
4031
}
4032
4033
/* ARGSUSED */
4034
void
4035
setcarp_advbase(const char *val, int d)
4036
{
4037
	const char *errmsg = NULL;
4038
	struct carpreq carpr;
4039
	int advbase;
4040
4041
	advbase = strtonum(val, 0, 254, &errmsg);
4042
	if (errmsg)
4043
		errx(1, "advbase %s: %s", val, errmsg);
4044
4045
	bzero(&carpr, sizeof(struct carpreq));
4046
	ifr.ifr_data = (caddr_t)&carpr;
4047
4048
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4049
		err(1, "SIOCGVH");
4050
4051
	carpr.carpr_advbase = advbase;
4052
4053
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4054
		err(1, "SIOCSVH");
4055
}
4056
4057
/* ARGSUSED */
4058
void
4059
setcarppeer(const char *val, int d)
4060
{
4061
	struct carpreq carpr;
4062
	struct addrinfo hints, *peerres;
4063
	int ecode;
4064
4065
	bzero(&carpr, sizeof(struct carpreq));
4066
	ifr.ifr_data = (caddr_t)&carpr;
4067
4068
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4069
		err(1, "SIOCGVH");
4070
4071
	bzero(&hints, sizeof(hints));
4072
	hints.ai_family = AF_INET;
4073
	hints.ai_socktype = SOCK_DGRAM;
4074
4075
	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4076
		errx(1, "error in parsing address string: %s",
4077
		    gai_strerror(ecode));
4078
4079
	if (peerres->ai_addr->sa_family != AF_INET)
4080
		errx(1, "only IPv4 addresses supported for the carppeer");
4081
4082
	carpr.carpr_peer.s_addr = ((struct sockaddr_in *)
4083
	    peerres->ai_addr)->sin_addr.s_addr;
4084
4085
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4086
		err(1, "SIOCSVH");
4087
4088
	freeaddrinfo(peerres);
4089
}
4090
4091
void
4092
unsetcarppeer(const char *val, int d)
4093
{
4094
	struct carpreq carpr;
4095
4096
	bzero(&carpr, sizeof(struct carpreq));
4097
	ifr.ifr_data = (caddr_t)&carpr;
4098
4099
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4100
		err(1, "SIOCGVH");
4101
4102
	bzero(&carpr.carpr_peer, sizeof(carpr.carpr_peer));
4103
4104
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4105
		err(1, "SIOCSVH");
4106
}
4107
4108
/* ARGSUSED */
4109
void
4110
setcarp_state(const char *val, int d)
4111
{
4112
	struct carpreq carpr;
4113
	int i;
4114
4115
	bzero(&carpr, sizeof(struct carpreq));
4116
	ifr.ifr_data = (caddr_t)&carpr;
4117
4118
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4119
		err(1, "SIOCGVH");
4120
4121
	for (i = 0; i <= CARP_MAXSTATE; i++) {
4122
		if (!strcasecmp(val, carp_states[i])) {
4123
			carpr.carpr_state = i;
4124
			break;
4125
		}
4126
	}
4127
4128
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4129
		err(1, "SIOCSVH");
4130
}
4131
4132
/* ARGSUSED */
4133
void
4134
setcarpdev(const char *val, int d)
4135
{
4136
	struct carpreq carpr;
4137
4138
	bzero(&carpr, sizeof(struct carpreq));
4139
	ifr.ifr_data = (caddr_t)&carpr;
4140
4141
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4142
		err(1, "SIOCGVH");
4143
4144
	strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
4145
4146
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4147
		err(1, "SIOCSVH");
4148
}
4149
4150
void
4151
setcarp_nodes(const char *val, int d)
4152
{
4153
	char *optlist, *str;
4154
	int i;
4155
	struct carpreq carpr;
4156
4157
	bzero(&carpr, sizeof(struct carpreq));
4158
	ifr.ifr_data = (caddr_t)&carpr;
4159
4160
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4161
		err(1, "SIOCGVH");
4162
4163
	bzero(carpr.carpr_vhids, sizeof(carpr.carpr_vhids));
4164
	bzero(carpr.carpr_advskews, sizeof(carpr.carpr_advskews));
4165
4166
	optlist = strdup(val);
4167
	if (optlist == NULL)
4168
		err(1, "strdup");
4169
4170
	str = strtok(optlist, ",");
4171
	for (i = 0; str != NULL; i++) {
4172
		u_int vhid, advskew;
4173
4174
		if (i >= CARP_MAXNODES)
4175
			errx(1, "too many carp nodes");
4176
		if (sscanf(str, "%u:%u", &vhid, &advskew) != 2) {
4177
			errx(1, "non parsable arg: %s", str);
4178
		}
4179
		if (vhid > 255)
4180
			errx(1, "vhid %u: value too large", vhid);
4181
		if (advskew >= 255)
4182
			errx(1, "advskew %u: value too large", advskew);
4183
4184
		carpr.carpr_vhids[i] = vhid;
4185
		carpr.carpr_advskews[i] = advskew;
4186
		str = strtok(NULL, ",");
4187
	}
4188
	free(optlist);
4189
4190
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4191
		err(1, "SIOCSVH");
4192
}
4193
4194
void
4195
setcarp_balancing(const char *val, int d)
4196
{
4197
	int i;
4198
	struct carpreq carpr;
4199
4200
	bzero(&carpr, sizeof(struct carpreq));
4201
	ifr.ifr_data = (caddr_t)&carpr;
4202
4203
	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1)
4204
		err(1, "SIOCGVH");
4205
4206
	for (i = 0; i <= CARP_BAL_MAXID; i++)
4207
		if (!strcasecmp(val, carp_bal_modes[i]))
4208
			break;
4209
4210
	if (i > CARP_BAL_MAXID)
4211
		errx(1, "balancing %s: unknown mode", val);
4212
4213
	carpr.carpr_balancing = i;
4214
4215
	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
4216
		err(1, "SIOCSVH");
4217
}
4218
4219
void
4220
setpfsync_syncdev(const char *val, int d)
4221
{
4222
	struct pfsyncreq preq;
4223
4224
	bzero(&preq, sizeof(struct pfsyncreq));
4225
	ifr.ifr_data = (caddr_t)&preq;
4226
4227
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4228
		err(1, "SIOCGETPFSYNC");
4229
4230
	strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
4231
4232
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4233
		err(1, "SIOCSETPFSYNC");
4234
}
4235
4236
/* ARGSUSED */
4237
void
4238
unsetpfsync_syncdev(const char *val, int d)
4239
{
4240
	struct pfsyncreq preq;
4241
4242
	bzero(&preq, sizeof(struct pfsyncreq));
4243
	ifr.ifr_data = (caddr_t)&preq;
4244
4245
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4246
		err(1, "SIOCGETPFSYNC");
4247
4248
	bzero(&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
4249
4250
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4251
		err(1, "SIOCSETPFSYNC");
4252
}
4253
4254
/* ARGSUSED */
4255
void
4256
setpfsync_syncpeer(const char *val, int d)
4257
{
4258
	struct pfsyncreq preq;
4259
	struct addrinfo hints, *peerres;
4260
	int ecode;
4261
4262
	bzero(&preq, sizeof(struct pfsyncreq));
4263
	ifr.ifr_data = (caddr_t)&preq;
4264
4265
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4266
		err(1, "SIOCGETPFSYNC");
4267
4268
	memset(&hints, 0, sizeof(hints));
4269
	hints.ai_family = AF_INET;
4270
	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
4271
4272
	if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4273
		errx(1, "error in parsing address string: %s",
4274
		    gai_strerror(ecode));
4275
4276
	if (peerres->ai_addr->sa_family != AF_INET)
4277
		errx(1, "only IPv4 addresses supported for the syncpeer");
4278
4279
	preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
4280
	    peerres->ai_addr)->sin_addr.s_addr;
4281
4282
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4283
		err(1, "SIOCSETPFSYNC");
4284
4285
	freeaddrinfo(peerres);
4286
}
4287
4288
/* ARGSUSED */
4289
void
4290
unsetpfsync_syncpeer(const char *val, int d)
4291
{
4292
	struct pfsyncreq preq;
4293
4294
	bzero(&preq, sizeof(struct pfsyncreq));
4295
	ifr.ifr_data = (caddr_t)&preq;
4296
4297
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4298
		err(1, "SIOCGETPFSYNC");
4299
4300
	preq.pfsyncr_syncpeer.s_addr = 0;
4301
4302
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4303
		err(1, "SIOCSETPFSYNC");
4304
}
4305
4306
/* ARGSUSED */
4307
void
4308
setpfsync_maxupd(const char *val, int d)
4309
{
4310
	const char *errmsg = NULL;
4311
	struct pfsyncreq preq;
4312
	int maxupdates;
4313
4314
	maxupdates = strtonum(val, 0, 255, &errmsg);
4315
	if (errmsg)
4316
		errx(1, "maxupd %s: %s", val, errmsg);
4317
4318
	bzero(&preq, sizeof(struct pfsyncreq));
4319
	ifr.ifr_data = (caddr_t)&preq;
4320
4321
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4322
		err(1, "SIOCGETPFSYNC");
4323
4324
	preq.pfsyncr_maxupdates = maxupdates;
4325
4326
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4327
		err(1, "SIOCSETPFSYNC");
4328
}
4329
4330
void
4331
setpfsync_defer(const char *val, int d)
4332
{
4333
	struct pfsyncreq preq;
4334
4335
	bzero(&preq, sizeof(struct pfsyncreq));
4336
	ifr.ifr_data = (caddr_t)&preq;
4337
4338
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4339
		err(1, "SIOCGETPFSYNC");
4340
4341
	preq.pfsyncr_defer = d;
4342
	if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4343
		err(1, "SIOCSETPFSYNC");
4344
}
4345
4346
void
4347
pfsync_status(void)
4348
{
4349
	struct pfsyncreq preq;
4350
4351
	bzero(&preq, sizeof(struct pfsyncreq));
4352
	ifr.ifr_data = (caddr_t)&preq;
4353
4354
	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4355
		return;
4356
4357
	if (preq.pfsyncr_syncdev[0] != '\0') {
4358
		printf("\tpfsync: syncdev: %s ", preq.pfsyncr_syncdev);
4359
		if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
4360
			printf("syncpeer: %s ",
4361
			    inet_ntoa(preq.pfsyncr_syncpeer));
4362
		printf("maxupd: %d ", preq.pfsyncr_maxupdates);
4363
		printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
4364
	}
4365
}
4366
4367
void
4368
pflow_status(void)
4369
{
4370
	struct pflowreq		 preq;
4371
	struct sockaddr_in	*sin;
4372
	struct sockaddr_in6	*sin6;
4373
	int			 error;
4374
	char			 buf[INET6_ADDRSTRLEN];
4375
4376
	bzero(&preq, sizeof(struct pflowreq));
4377
	ifr.ifr_data = (caddr_t)&preq;
4378
4379
	if (ioctl(s, SIOCGETPFLOW, (caddr_t)&ifr) == -1)
4380
		 return;
4381
4382
	if (preq.flowsrc.ss_family == AF_INET || preq.flowsrc.ss_family ==
4383
	    AF_INET6) {
4384
		error = getnameinfo((struct sockaddr*)&preq.flowsrc,
4385
		    preq.flowsrc.ss_len, buf, sizeof(buf), NULL, 0,
4386
		    NI_NUMERICHOST);
4387
		if (error)
4388
			err(1, "sender: %s", gai_strerror(error));
4389
	}
4390
4391
	printf("\tpflow: ");
4392
	switch (preq.flowsrc.ss_family) {
4393
	case AF_INET:
4394
		sin = (struct sockaddr_in*) &preq.flowsrc;
4395
		if (sin->sin_addr.s_addr != INADDR_ANY) {
4396
			printf("sender: %s", buf);
4397
			if (sin->sin_port != 0)
4398
				printf(":%u", ntohs(sin->sin_port));
4399
			printf(" ");
4400
		}
4401
		break;
4402
	case AF_INET6:
4403
		sin6 = (struct sockaddr_in6*) &preq.flowsrc;
4404
		if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4405
			printf("sender: [%s]", buf);
4406
			if (sin6->sin6_port != 0)
4407
				printf(":%u", ntohs(sin6->sin6_port));
4408
			printf(" ");
4409
		}
4410
	default:
4411
		break;
4412
	}
4413
	if (preq.flowdst.ss_family == AF_INET || preq.flowdst.ss_family ==
4414
	    AF_INET6) {
4415
		error = getnameinfo((struct sockaddr*)&preq.flowdst,
4416
		    preq.flowdst.ss_len, buf, sizeof(buf), NULL, 0,
4417
		    NI_NUMERICHOST);
4418
		if (error)
4419
			err(1, "receiver: %s", gai_strerror(error));
4420
	}
4421
	switch (preq.flowdst.ss_family) {
4422
	case AF_INET:
4423
		sin = (struct sockaddr_in*)&preq.flowdst;
4424
		printf("receiver: %s:", sin->sin_addr.s_addr != INADDR_ANY ?
4425
		    buf : "INVALID");
4426
		if (sin->sin_port == 0)
4427
			printf("%s ", "INVALID");
4428
		else
4429
			printf("%u ", ntohs(sin->sin_port));
4430
		break;
4431
	case AF_INET6:
4432
		sin6 = (struct sockaddr_in6*) &preq.flowdst;
4433
		printf("receiver: [%s]:",
4434
		    !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ? buf :
4435
		    "INVALID");
4436
		if (sin6->sin6_port == 0)
4437
			printf("%s ", "INVALID");
4438
		else
4439
			printf("%u ", ntohs(sin6->sin6_port));
4440
		break;
4441
	default:
4442
		printf("receiver: INVALID:INVALID ");
4443
		break;
4444
	}
4445
	printf("version: %d\n", preq.version);
4446
}
4447
4448
void
4449
pflow_addr(const char *val, struct sockaddr_storage *ss) {
4450
	struct addrinfo hints, *res0;
4451
	int error, flag;
4452
	char *cp, *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
4453
4454
	if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
4455
		errx(1, "%s bad value", val);
4456
4457
	port = NULL;
4458
	cp = buf;
4459
	if (*cp == '[')
4460
		flag = 1;
4461
	else
4462
		flag = 0;
4463
4464
	for(; *cp; ++cp) {
4465
		if (*cp == ']' && *(cp + 1) == ':' && flag) {
4466
			*cp = '\0';
4467
			*(cp + 1) = '\0';
4468
			port = cp + 2;
4469
			break;
4470
		}
4471
		if (*cp == ']' && *(cp + 1) == '\0' && flag) {
4472
			*cp = '\0';
4473
			port = NULL;
4474
			break;
4475
		}
4476
		if (*cp == ':' && !flag) {
4477
			*cp = '\0';
4478
			port = cp + 1;
4479
			break;
4480
		}
4481
	}
4482
4483
	ip = buf;
4484
	if (flag)
4485
		ip++;
4486
4487
	bzero(&hints, sizeof(hints));
4488
	hints.ai_family = AF_UNSPEC;
4489
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
4490
4491
	if ((error = getaddrinfo(ip, port, &hints, &res0)) != 0)
4492
		errx(1, "error in parsing address string: %s",
4493
		    gai_strerror(error));
4494
4495
	memcpy(ss, res0->ai_addr, res0->ai_addr->sa_len);
4496
	freeaddrinfo(res0);
4497
}
4498
4499
void
4500
setpflow_sender(const char *val, int d)
4501
{
4502
	struct pflowreq preq;
4503
4504
	bzero(&preq, sizeof(struct pflowreq));
4505
	ifr.ifr_data = (caddr_t)&preq;
4506
	preq.addrmask |= PFLOW_MASK_SRCIP;
4507
	pflow_addr(val, &preq.flowsrc);
4508
4509
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4510
		err(1, "SIOCSETPFLOW");
4511
}
4512
4513
void
4514
unsetpflow_sender(const char *val, int d)
4515
{
4516
	struct pflowreq preq;
4517
4518
	bzero(&preq, sizeof(struct pflowreq));
4519
	preq.addrmask |= PFLOW_MASK_SRCIP;
4520
	ifr.ifr_data = (caddr_t)&preq;
4521
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4522
		err(1, "SIOCSETPFLOW");
4523
}
4524
4525
void
4526
setpflow_receiver(const char *val, int d)
4527
{
4528
	struct pflowreq preq;
4529
4530
	bzero(&preq, sizeof(struct pflowreq));
4531
	ifr.ifr_data = (caddr_t)&preq;
4532
	preq.addrmask |= PFLOW_MASK_DSTIP;
4533
	pflow_addr(val, &preq.flowdst);
4534
4535
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4536
		err(1, "SIOCSETPFLOW");
4537
}
4538
4539
void
4540
unsetpflow_receiver(const char *val, int d)
4541
{
4542
	struct pflowreq preq;
4543
4544
	bzero(&preq, sizeof(struct pflowreq));
4545
	ifr.ifr_data = (caddr_t)&preq;
4546
	preq.addrmask |= PFLOW_MASK_DSTIP;
4547
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4548
		err(1, "SIOCSETPFLOW");
4549
}
4550
4551
/* PFLOWPROTO XXX */
4552
void
4553
setpflowproto(const char *val, int d)
4554
{
4555
	struct pflow_protos ppr[] = PFLOW_PROTOS;
4556
	struct pflowreq preq;
4557
	int i;
4558
4559
	bzero(&preq, sizeof(preq));
4560
	preq.version = PFLOW_PROTO_MAX;
4561
4562
	for (i = 0; i < (sizeof(ppr) / sizeof(ppr[0])); i++) {
4563
		if (strcmp(val, ppr[i].ppr_name) == 0) {
4564
			preq.version = ppr[i].ppr_proto;
4565
			break;
4566
		}
4567
	}
4568
	if (preq.version == PFLOW_PROTO_MAX)
4569
		errx(1, "Invalid pflow protocol: %s", val);
4570
4571
	preq.addrmask |= PFLOW_MASK_VERSION;
4572
4573
	ifr.ifr_data = (caddr_t)&preq;
4574
4575
	if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
4576
		err(1, "SIOCSETPFLOW");
4577
}
4578
4579
void
4580
pppoe_status(void)
4581
{
4582
	struct pppoediscparms parms;
4583
	struct pppoeconnectionstate state;
4584
4585
	memset(&state, 0, sizeof(state));
4586
4587
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4588
	if (ioctl(s, PPPOEGETPARMS, &parms))
4589
		return;
4590
4591
	printf("\tdev: %s ", parms.eth_ifname);
4592
4593
	if (*parms.ac_name)
4594
		printf("ac: %s ", parms.ac_name);
4595
	if (*parms.service_name)
4596
		printf("svc: %s ", parms.service_name);
4597
4598
	strlcpy(state.ifname, name, sizeof(state.ifname));
4599
	if (ioctl(s, PPPOEGETSESSION, &state))
4600
		err(1, "PPPOEGETSESSION");
4601
4602
	printf("state: ");
4603
	switch (state.state) {
4604
	case PPPOE_STATE_INITIAL:
4605
		printf("initial"); break;
4606
	case PPPOE_STATE_PADI_SENT:
4607
		printf("PADI sent"); break;
4608
	case PPPOE_STATE_PADR_SENT:
4609
		printf("PADR sent"); break;
4610
	case PPPOE_STATE_SESSION:
4611
		printf("session"); break;
4612
	case PPPOE_STATE_CLOSING:
4613
		printf("closing"); break;
4614
	}
4615
	printf("\n\tsid: 0x%x", state.session_id);
4616
	printf(" PADI retries: %d", state.padi_retry_no);
4617
	printf(" PADR retries: %d", state.padr_retry_no);
4618
4619
	if (state.state == PPPOE_STATE_SESSION) {
4620
		struct timeval temp_time;
4621
		time_t diff_time, day = 0;
4622
		unsigned int hour = 0, min = 0, sec = 0;
4623
4624
		if (state.session_time.tv_sec != 0) {
4625
			gettimeofday(&temp_time, NULL);
4626
			diff_time = temp_time.tv_sec -
4627
			    state.session_time.tv_sec;
4628
4629
			day = diff_time / (60 * 60 * 24);
4630
			diff_time %= (60 * 60 * 24);
4631
4632
			hour = diff_time / (60 * 60);
4633
			diff_time %= (60 * 60);
4634
4635
			min = diff_time / 60;
4636
			diff_time %= 60;
4637
4638
			sec = diff_time;
4639
		}
4640
		printf(" time: ");
4641
		if (day != 0)
4642
			printf("%lldd ", (long long)day);
4643
		printf("%02u:%02u:%02u", hour, min, sec);
4644
	}
4645
	putchar('\n');
4646
}
4647
4648
/* ARGSUSED */
4649
void
4650
setpppoe_dev(const char *val, int d)
4651
{
4652
	struct pppoediscparms parms;
4653
4654
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4655
	if (ioctl(s, PPPOEGETPARMS, &parms))
4656
		return;
4657
4658
	strlcpy(parms.eth_ifname, val, sizeof(parms.eth_ifname));
4659
4660
	if (ioctl(s, PPPOESETPARMS, &parms))
4661
		err(1, "PPPOESETPARMS");
4662
}
4663
4664
/* ARGSUSED */
4665
void
4666
setpppoe_svc(const char *val, int d)
4667
{
4668
	struct pppoediscparms parms;
4669
4670
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4671
	if (ioctl(s, PPPOEGETPARMS, &parms))
4672
		return;
4673
4674
	if (d == 0)
4675
		strlcpy(parms.service_name, val, sizeof(parms.service_name));
4676
	else
4677
		memset(parms.service_name, 0, sizeof(parms.service_name));
4678
4679
	if (ioctl(s, PPPOESETPARMS, &parms))
4680
		err(1, "PPPOESETPARMS");
4681
}
4682
4683
/* ARGSUSED */
4684
void
4685
setpppoe_ac(const char *val, int d)
4686
{
4687
	struct pppoediscparms parms;
4688
4689
	strlcpy(parms.ifname, name, sizeof(parms.ifname));
4690
	if (ioctl(s, PPPOEGETPARMS, &parms))
4691
		return;
4692
4693
	if (d == 0)
4694
		strlcpy(parms.ac_name, val, sizeof(parms.ac_name));
4695
	else
4696
		memset(parms.ac_name, 0, sizeof(parms.ac_name));
4697
4698
	if (ioctl(s, PPPOESETPARMS, &parms))
4699
		err(1, "PPPOESETPARMS");
4700
}
4701
4702
void
4703
spppauthinfo(struct sauthreq *spa, int d)
4704
{
4705
	bzero(spa, sizeof(struct sauthreq));
4706
4707
	ifr.ifr_data = (caddr_t)spa;
4708
	spa->cmd = d == 0 ? SPPPIOGMAUTH : SPPPIOGHAUTH;
4709
	if (ioctl(s, SIOCGSPPPPARAMS, &ifr) == -1)
4710
		err(1, "SIOCGSPPPPARAMS(SPPPIOGXAUTH)");
4711
}
4712
4713
void
4714
setspppproto(const char *val, int d)
4715
{
4716
	struct sauthreq spa;
4717
4718
	spppauthinfo(&spa, d);
4719
4720
	if (strcmp(val, "pap") == 0)
4721
		spa.proto = PPP_PAP;
4722
	else if (strcmp(val, "chap") == 0)
4723
		spa.proto = PPP_CHAP;
4724
	else if (strcmp(val, "none") == 0)
4725
		spa.proto = 0;
4726
	else
4727
		errx(1, "setpppproto");
4728
4729
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4730
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4731
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4732
}
4733
4734
void
4735
setsppppeerproto(const char *val, int d)
4736
{
4737
	setspppproto(val, 1);
4738
}
4739
4740
void
4741
setspppname(const char *val, int d)
4742
{
4743
	struct sauthreq spa;
4744
4745
	spppauthinfo(&spa, d);
4746
4747
	if (spa.proto == 0)
4748
		errx(1, "unspecified protocol");
4749
	if (strlcpy(spa.name, val, sizeof(spa.name)) >= sizeof(spa.name))
4750
		errx(1, "setspppname");
4751
4752
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4753
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4754
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4755
}
4756
4757
void
4758
setsppppeername(const char *val, int d)
4759
{
4760
	setspppname(val, 1);
4761
}
4762
4763
void
4764
setspppkey(const char *val, int d)
4765
{
4766
	struct sauthreq spa;
4767
4768
	spppauthinfo(&spa, d);
4769
4770
	if (spa.proto == 0)
4771
		errx(1, "unspecified protocol");
4772
	if (strlcpy(spa.secret, val, sizeof(spa.secret)) >= sizeof(spa.secret))
4773
		errx(1, "setspppkey");
4774
4775
	spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
4776
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4777
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4778
}
4779
4780
void
4781
setsppppeerkey(const char *val, int d)
4782
{
4783
	setspppkey(val, 1);
4784
}
4785
4786
void
4787
setsppppeerflag(const char *val, int d)
4788
{
4789
	struct sauthreq spa;
4790
	int flag;
4791
4792
	spppauthinfo(&spa, 1);
4793
4794
	if (spa.proto == 0)
4795
		errx(1, "unspecified protocol");
4796
	if (strcmp(val, "callin") == 0)
4797
		flag = AUTHFLAG_NOCALLOUT;
4798
	else if (strcmp(val, "norechallenge") == 0)
4799
		flag = AUTHFLAG_NORECHALLENGE;
4800
	else
4801
		errx(1, "setppppeerflags");
4802
4803
	if (d)
4804
		spa.flags &= ~flag;
4805
	else
4806
		spa.flags |= flag;
4807
4808
	spa.cmd = SPPPIOSHAUTH;
4809
	if (ioctl(s, SIOCSSPPPPARAMS, &ifr) == -1)
4810
		err(1, "SIOCSSPPPPARAMS(SPPPIOSXAUTH)");
4811
}
4812
4813
void
4814
unsetsppppeerflag(const char *val, int d)
4815
{
4816
	setsppppeerflag(val, 1);
4817
}
4818
4819
void
4820
sppp_printproto(const char *name, struct sauthreq *auth)
4821
{
4822
	if (auth->proto == 0)
4823
		return;
4824
	printf("%sproto ", name);
4825
	switch (auth->proto) {
4826
	case PPP_PAP:
4827
		printf("pap ");
4828
		break;
4829
	case PPP_CHAP:
4830
		printf("chap ");
4831
		break;
4832
	default:
4833
		printf("0x%04x ", auth->proto);
4834
		break;
4835
	}
4836
	if (auth->name[0])
4837
		printf("%sname \"%s\" ", name, auth->name);
4838
	if (auth->secret[0])
4839
		printf("%skey \"%s\" ", name, auth->secret);
4840
}
4841
4842
void
4843
sppp_status(void)
4844
{
4845
	struct spppreq spr;
4846
	struct sauthreq spa;
4847
4848
	bzero(&spr, sizeof(spr));
4849
4850
	ifr.ifr_data = (caddr_t)&spr;
4851
	spr.cmd = SPPPIOGDEFS;
4852
	if (ioctl(s, SIOCGSPPPPARAMS, &ifr) == -1) {
4853
		return;
4854
	}
4855
4856
	if (spr.phase == PHASE_DEAD)
4857
		return;
4858
	printf("\tsppp: phase ");
4859
	switch (spr.phase) {
4860
	case PHASE_ESTABLISH:
4861
		printf("establish ");
4862
		break;
4863
	case PHASE_TERMINATE:
4864
		printf("terminate ");
4865
		break;
4866
	case PHASE_AUTHENTICATE:
4867
		printf("authenticate ");
4868
		break;
4869
	case PHASE_NETWORK:
4870
		printf("network ");
4871
		break;
4872
	default:
4873
		printf("illegal ");
4874
		break;
4875
	}
4876
4877
	spppauthinfo(&spa, 0);
4878
	sppp_printproto("auth", &spa);
4879
	spppauthinfo(&spa, 1);
4880
	sppp_printproto("peer", &spa);
4881
	if (spa.flags & AUTHFLAG_NOCALLOUT)
4882
		printf("callin ");
4883
	if (spa.flags & AUTHFLAG_NORECHALLENGE)
4884
		printf("norechallenge ");
4885
	putchar('\n');
4886
}
4887
4888
void
4889
setkeepalive(const char *timeout, const char *count)
4890
{
4891
	const char *errmsg = NULL;
4892
	struct ifkalivereq ikar;
4893
	int t, c;
4894
4895
	t = strtonum(timeout, 1, 3600, &errmsg);
4896
	if (errmsg)
4897
		errx(1, "keepalive period %s: %s", timeout, errmsg);
4898
	c = strtonum(count, 2, 600, &errmsg);
4899
	if (errmsg)
4900
		errx(1, "keepalive count %s: %s", count, errmsg);
4901
4902
	strlcpy(ikar.ikar_name, name, sizeof(ikar.ikar_name));
4903
	ikar.ikar_timeo = t;
4904
	ikar.ikar_cnt = c;
4905
	if (ioctl(s, SIOCSETKALIVE, (caddr_t)&ikar) < 0)
4906
		warn("SIOCSETKALIVE");
4907
}
4908
4909
void
4910
unsetkeepalive(const char *val, int d)
4911
{
4912
	struct ifkalivereq ikar;
4913
4914
	bzero(&ikar, sizeof(ikar));
4915
	strlcpy(ikar.ikar_name, name, sizeof(ikar.ikar_name));
4916
	if (ioctl(s, SIOCSETKALIVE, (caddr_t)&ikar) < 0)
4917
		warn("SIOCSETKALIVE");
4918
}
4919
4920
void
4921
setifpriority(const char *id, int param)
4922
{
4923
	const char *errmsg = NULL;
4924
	int prio;
4925
4926
	prio = strtonum(id, 0, 15, &errmsg);
4927
	if (errmsg)
4928
		errx(1, "priority %s: %s", id, errmsg);
4929
4930
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
4931
	ifr.ifr_metric = prio;
4932
	if (ioctl(s, SIOCSIFPRIORITY, (caddr_t)&ifr) < 0)
4933
		warn("SIOCSIFPRIORITY");
4934
}
4935
4936
4937
const struct umb_valdescr umb_regstate[] = MBIM_REGSTATE_DESCRIPTIONS;
4938
const struct umb_valdescr umb_dataclass[] = MBIM_DATACLASS_DESCRIPTIONS;
4939
const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
4940
const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS;
4941
const struct umb_valdescr umb_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS;
4942
const struct umb_valdescr umb_actstate[] = MBIM_ACTIVATION_STATE_DESCRIPTIONS;
4943
4944
const struct umb_valdescr umb_classalias[] = {
4945
	{ MBIM_DATACLASS_GPRS | MBIM_DATACLASS_EDGE, "2g" },
4946
	{ MBIM_DATACLASS_UMTS | MBIM_DATACLASS_HSDPA | MBIM_DATACLASS_HSUPA,
4947
	    "3g" },
4948
	{ MBIM_DATACLASS_LTE, "4g" },
4949
	{ 0, NULL }
4950
};
4951
4952
int
4953
umb_descr2val(const struct umb_valdescr *vdp, char *str)
4954
{
4955
	while (vdp->descr != NULL) {
4956
		if (!strcasecmp(vdp->descr, str))
4957
			return vdp->val;
4958
		vdp++;
4959
	}
4960
	return 0;
4961
}
4962
4963
void
4964
umb_status(void)
4965
{
4966
	struct umb_info mi;
4967
	char	 provider[UMB_PROVIDERNAME_MAXLEN+1];
4968
	char	 roamingtxt[UMB_ROAMINGTEXT_MAXLEN+1];
4969
	char	 devid[UMB_DEVID_MAXLEN+1];
4970
	char	 fwinfo[UMB_FWINFO_MAXLEN+1];
4971
	char	 hwinfo[UMB_HWINFO_MAXLEN+1];
4972
	char	 sid[UMB_SUBSCRIBERID_MAXLEN+1];
4973
	char	 iccid[UMB_ICCID_MAXLEN+1];
4974
	char	 apn[UMB_APN_MAXLEN+1];
4975
	char	 pn[UMB_PHONENR_MAXLEN+1];
4976
	int	 i, n;
4977
4978
	memset((char *)&mi, 0, sizeof(mi));
4979
	ifr.ifr_data = (caddr_t)&mi;
4980
	if (ioctl(s, SIOCGUMBINFO, (caddr_t)&ifr) == -1)
4981
		return;
4982
4983
	if (mi.nwerror) {
4984
		/* 3GPP 24.008 Cause Code */
4985
		printf("\terror: ");
4986
		switch (mi.nwerror) {
4987
		case 2:
4988
			printf("SIM not activated");
4989
			break;
4990
		case 4:
4991
			printf("Roaming not supported");
4992
			break;
4993
		case 6:
4994
			printf("SIM reported stolen");
4995
			break;
4996
		case 7:
4997
			printf("No GPRS subscription");
4998
			break;
4999
		case 8:
5000
			printf("GPRS and non-GPRS services not allowed");
5001
			break;
5002
		case 11:
5003
			printf("Subscription expired");
5004
			break;
5005
		case 12:
5006
			printf("Subscription does not cover current location");
5007
			break;
5008
		case 13:
5009
			printf("No roaming in this location");
5010
			break;
5011
		case 14:
5012
			printf("GPRS not supported");
5013
			break;
5014
		case 15:
5015
			printf("No subscription for the service");
5016
			break;
5017
		case 17:
5018
			printf("Registration failed");
5019
			break;
5020
		case 22:
5021
			printf("Network congestion");
5022
			break;
5023
		default:
5024
			printf("Error code %d", mi.nwerror);
5025
			break;
5026
		}
5027
		printf("\n");
5028
	}
5029
5030
	printf("\troaming %s registration %s",
5031
	    mi.enable_roaming ? "enabled" : "disabled",
5032
	    umb_val2descr(umb_regstate, mi.regstate));
5033
	utf16_to_char(mi.roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
5034
	    roamingtxt, sizeof (roamingtxt));
5035
	if (roamingtxt[0])
5036
		printf(" [%s]", roamingtxt);
5037
	printf("\n");
5038
5039
	if (showclasses)
5040
		umb_printclasses("available classes", mi.supportedclasses);
5041
	printf("\tstate %s cell-class %s",
5042
	    umb_val2descr(umb_istate, mi.state),
5043
	    umb_val2descr(umb_dataclass, mi.highestclass));
5044
	if (mi.rssi != UMB_VALUE_UNKNOWN && mi.rssi != 0)
5045
		printf(" rssi %ddBm", mi.rssi);
5046
	if (mi.uplink_speed != 0 || mi.downlink_speed != 0) {
5047
		char s[2][FMT_SCALED_STRSIZE];
5048
		if (fmt_scaled(mi.uplink_speed, s[0]) != 0)
5049
			snprintf(s[0], sizeof (s[0]), "%llu", mi.uplink_speed);
5050
		if (fmt_scaled(mi.downlink_speed, s[1]) != 0)
5051
			snprintf(s[1], sizeof (s[1]), "%llu", mi.downlink_speed);
5052
		printf(" speed %sps up %sps down", s[0], s[1]);
5053
	}
5054
	printf("\n");
5055
5056
	printf("\tSIM %s PIN ", umb_val2descr(umb_simstate, mi.sim_state));
5057
	switch (mi.pin_state) {
5058
	case UMB_PIN_REQUIRED:
5059
		printf("required");
5060
		break;
5061
	case UMB_PIN_UNLOCKED:
5062
		printf("valid");
5063
		break;
5064
	case UMB_PUK_REQUIRED:
5065
		printf("locked (PUK required)");
5066
		break;
5067
	default:
5068
		printf("unknown state (%d)", mi.pin_state);
5069
		break;
5070
	}
5071
	if (mi.pin_attempts_left != UMB_VALUE_UNKNOWN)
5072
		printf(" (%d attempts left)", mi.pin_attempts_left);
5073
	printf("\n");
5074
5075
	utf16_to_char(mi.sid, UMB_SUBSCRIBERID_MAXLEN, sid, sizeof (sid));
5076
	utf16_to_char(mi.iccid, UMB_ICCID_MAXLEN, iccid, sizeof (iccid));
5077
	utf16_to_char(mi.provider, UMB_PROVIDERNAME_MAXLEN,
5078
	    provider, sizeof (provider));
5079
	if (sid[0] || iccid[0] || provider[0]) {
5080
		printf("\t");
5081
		n = 0;
5082
		if (sid[0])
5083
			printf("%ssubscriber-id %s", n++ ? " " : "", sid);
5084
		if (iccid[0])
5085
			printf("%sICC-id %s", n++ ? " " : "", iccid);
5086
		if (provider[0])
5087
			printf("%sprovider %s", n ? " " : "", provider);
5088
		printf("\n");
5089
	}
5090
5091
	utf16_to_char(mi.hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof (hwinfo));
5092
	utf16_to_char(mi.devid, UMB_DEVID_MAXLEN, devid, sizeof (devid));
5093
	utf16_to_char(mi.fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof (fwinfo));
5094
	if (hwinfo[0] || devid[0] || fwinfo[0]) {
5095
		printf("\t");
5096
		n = 0;
5097
		if (hwinfo[0])
5098
			printf("%sdevice %s", n++ ? " " : "", hwinfo);
5099
		if (devid[0]) {
5100
			printf("%s", n++ ? " " : "");
5101
			switch (mi.cellclass) {
5102
			case MBIM_CELLCLASS_GSM:
5103
				printf("IMEI");
5104
				break;
5105
			case MBIM_CELLCLASS_CDMA:
5106
				n = strlen(devid);
5107
				if (n == 8 || n == 11) {
5108
					printf("ESN");
5109
					break;
5110
				} else if (n == 14 || n == 18) {
5111
					printf("MEID");
5112
					break;
5113
				}
5114
				/*FALLTHROUGH*/
5115
			default:
5116
				printf("ID");
5117
				break;
5118
			}
5119
			printf(" %s", devid);
5120
		}
5121
		if (fwinfo[0])
5122
			printf("%sfirmware %s", n++ ? " " : "", fwinfo);
5123
		printf("\n");
5124
	}
5125
5126
	utf16_to_char(mi.pn, UMB_PHONENR_MAXLEN, pn, sizeof (pn));
5127
	utf16_to_char(mi.apn, UMB_APN_MAXLEN, apn, sizeof (apn));
5128
	if (pn[0] || apn[0]) {
5129
		printf("\t");
5130
		n = 0;
5131
		if (pn[0])
5132
			printf("%sphone# +%s", n++ ? " " : "", pn);
5133
		if (apn[0])
5134
			printf("%sAPN %s", n++ ? " " : "", apn);
5135
		printf("\n");
5136
	}
5137
5138
	for (i = 0, n = 0; i < UMB_MAX_DNSSRV; i++) {
5139
		if (mi.ipv4dns[i] == INADDR_ANY)
5140
			break;
5141
		printf("%s %s", n++ ? "" : "\tdns",
5142
		    inet_ntoa(*(struct in_addr *)&mi.ipv4dns[i]));
5143
	}
5144
	if (n)
5145
		printf("\n");
5146
}
5147
5148
void
5149
umb_printclasses(char *tag, int c)
5150
{
5151
	int	 i;
5152
	char	*sep = "";
5153
5154
	printf("\t%s: ", tag);
5155
	i = 0;
5156
	while (umb_dataclass[i].descr) {
5157
		if (umb_dataclass[i].val & c) {
5158
			printf("%s%s", sep, umb_dataclass[i].descr);
5159
			sep = ",";
5160
		}
5161
		i++;
5162
	}
5163
	printf("\n");
5164
}
5165
5166
int
5167
umb_parse_classes(const char *spec)
5168
{
5169
	char	*optlist, *str;
5170
	int	 c = 0, v;
5171
5172
	if ((optlist = strdup(spec)) == NULL)
5173
		err(1, "strdup");
5174
	str = strtok(optlist, ",");
5175
	while (str != NULL) {
5176
		if ((v = umb_descr2val(umb_dataclass, str)) != 0 ||
5177
		    (v = umb_descr2val(umb_classalias, str)) != 0)
5178
			c |= v;
5179
		str = strtok(NULL, ",");
5180
	}
5181
	free(optlist);
5182
	return c;
5183
}
5184
5185
void
5186
umb_setpin(const char *pin, int d)
5187
{
5188
	umb_pinop(MBIM_PIN_OP_ENTER, 0, pin, NULL);
5189
}
5190
5191
void
5192
umb_chgpin(const char *pin, const char *newpin)
5193
{
5194
	umb_pinop(MBIM_PIN_OP_CHANGE, 0, pin, newpin);
5195
}
5196
5197
void
5198
umb_puk(const char *pin, const char *newpin)
5199
{
5200
	umb_pinop(MBIM_PIN_OP_ENTER, 1, pin, newpin);
5201
}
5202
5203
void
5204
umb_pinop(int op, int is_puk, const char *pin, const char *newpin)
5205
{
5206
	struct umb_parameter mp;
5207
5208
	memset(&mp, 0, sizeof (mp));
5209
	ifr.ifr_data = (caddr_t)&mp;
5210
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5211
		err(1, "SIOCGUMBPARAM");
5212
5213
	mp.op = op;
5214
	mp.is_puk = is_puk;
5215
	if ((mp.pinlen = char_to_utf16(pin, (uint16_t *)mp.pin,
5216
	    sizeof (mp.pin))) == -1)
5217
		errx(1, "PIN too long");
5218
5219
	if (newpin) {
5220
		if ((mp.newpinlen = char_to_utf16(newpin, (uint16_t *)mp.newpin,
5221
		    sizeof (mp.newpin))) == -1)
5222
		errx(1, "new PIN too long");
5223
	}
5224
5225
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5226
		err(1, "SIOCSUMBPARAM");
5227
}
5228
5229
void
5230
umb_apn(const char *apn, int d)
5231
{
5232
	struct umb_parameter mp;
5233
5234
	memset(&mp, 0, sizeof (mp));
5235
	ifr.ifr_data = (caddr_t)&mp;
5236
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5237
		err(1, "SIOCGUMBPARAM");
5238
5239
	if (d != 0)
5240
		memset(mp.apn, 0, sizeof (mp.apn));
5241
	else if ((mp.apnlen = char_to_utf16(apn, mp.apn,
5242
	    sizeof (mp.apn))) == -1)
5243
		errx(1, "APN too long");
5244
5245
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5246
		err(1, "SIOCSUMBPARAM");
5247
}
5248
5249
void
5250
umb_setclass(const char *val, int d)
5251
{
5252
	struct umb_parameter mp;
5253
5254
	if (val == NULL) {
5255
		if (showclasses)
5256
			usage(1);
5257
		showclasses = 1;
5258
		return;
5259
	}
5260
5261
	memset(&mp, 0, sizeof (mp));
5262
	ifr.ifr_data = (caddr_t)&mp;
5263
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5264
		err(1, "SIOCGUMBPARAM");
5265
	if (d != -1)
5266
		mp.preferredclasses = umb_parse_classes(val);
5267
	else
5268
		mp.preferredclasses = MBIM_DATACLASS_NONE;
5269
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5270
		err(1, "SIOCSUMBPARAM");
5271
}
5272
5273
void
5274
umb_roaming(const char *val, int d)
5275
{
5276
	struct umb_parameter mp;
5277
5278
	memset(&mp, 0, sizeof (mp));
5279
	ifr.ifr_data = (caddr_t)&mp;
5280
	if (ioctl(s, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
5281
		err(1, "SIOCGUMBPARAM");
5282
	mp.roaming = d;
5283
	if (ioctl(s, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
5284
		err(1, "SIOCSUMBPARAM");
5285
}
5286
5287
void
5288
utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
5289
{
5290
	uint16_t c;
5291
5292
	while (outlen > 0) {
5293
		c = inlen > 0 ? letoh16(*in) : 0;
5294
		if (c == 0 || --outlen == 0) {
5295
			/* always NUL terminate result */
5296
done:
5297
			*out = '\0';
5298
			break;
5299
		}
5300
		*out++ = isascii(c) ? (char)c : '?';
5301
		in++;
5302
		inlen -= sizeof (*in);
5303
	}
5304
}
5305
5306
int
5307
char_to_utf16(const char *in, uint16_t *out, size_t outlen)
5308
{
5309
	int	 n = 0;
5310
	uint16_t c;
5311
5312
	for (;;) {
5313
		c = *in++;
5314
5315
		if (c == '\0') {
5316
			/*
5317
			 * NUL termination is not required, but zero out the
5318
			 * residual buffer
5319
			 */
5320
			memset(out, 0, outlen);
5321
			return n;
5322
		}
5323
		if (outlen < sizeof (*out))
5324
			return -1;
5325
5326
		*out++ = htole16(c);
5327
		n += sizeof (*out);
5328
		outlen -= sizeof (*out);
5329
	}
5330
}
5331
5332
#endif
5333
5334
#define SIN(x) ((struct sockaddr_in *) &(x))
5335
struct sockaddr_in *sintab[] = {
5336
SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
5337
SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
5338
5339
void
5340
in_getaddr(const char *s, int which)
5341
88
{
5342
88
	struct sockaddr_in *sin = sintab[which], tsin;
5343
	struct hostent *hp;
5344
	struct netent *np;
5345
	int bits, l;
5346
	char p[3];
5347
5348
88
	bzero(&tsin, sizeof(tsin));
5349
88
	sin->sin_len = sizeof(*sin);
5350
88
	if (which != MASK)
5351
88
		sin->sin_family = AF_INET;
5352
5353

176
	if (which == ADDR && strrchr(s, '/') != NULL &&
5354
	    (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
5355
	    sizeof(tsin.sin_addr))) != -1) {
5356
88
		l = snprintf(p, sizeof(p), "%d", bits);
5357
88
		if (l >= sizeof(p) || l == -1)
5358
			errx(1, "%d: bad prefixlen", bits);
5359
88
		in_getprefix(p, MASK);
5360
88
		memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
5361
	} else if (inet_aton(s, &sin->sin_addr) == 0) {
5362
		if ((hp = gethostbyname(s)))
5363
			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
5364
		else if ((np = getnetbyname(s)))
5365
			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
5366
		else
5367
			errx(1, "%s: bad value", s);
5368
	}
5369
88
}
5370
5371
/* ARGSUSED */
5372
void
5373
in_getprefix(const char *plen, int which)
5374
88
{
5375
88
	struct sockaddr_in *sin = sintab[which];
5376
88
	const char *errmsg = NULL;
5377
	u_char *cp;
5378
	int len;
5379
5380
88
	len = strtonum(plen, 0, 32, &errmsg);
5381
88
	if (errmsg)
5382
		errx(1, "prefix %s: %s", plen, errmsg);
5383
5384
88
	sin->sin_len = sizeof(*sin);
5385
88
	if (which != MASK)
5386
		sin->sin_family = AF_INET;
5387
88
	if ((len == 0) || (len == 32)) {
5388
88
		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
5389
88
		return;
5390
	}
5391
	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
5392
	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
5393
		*cp++ = 0xff;
5394
	if (len)
5395
		*cp = 0xff << (8 - len);
5396
}
5397
5398
/*
5399
 * Print a value a la the %b format of the kernel's printf
5400
 */
5401
void
5402
printb(char *s, unsigned int v, unsigned char *bits)
5403
{
5404
	int i, any = 0;
5405
	unsigned char c;
5406
5407
	if (bits && *bits == 8)
5408
		printf("%s=%o", s, v);
5409
	else
5410
		printf("%s=%x", s, v);
5411
5412
	if (bits) {
5413
		bits++;
5414
		putchar('<');
5415
		while ((i = *bits++)) {
5416
			if (v & (1 << (i-1))) {
5417
				if (any)
5418
					putchar(',');
5419
				any = 1;
5420
				for (; (c = *bits) > 32; bits++)
5421
					putchar(c);
5422
			} else
5423
				for (; *bits > 32; bits++)
5424
					;
5425
		}
5426
		putchar('>');
5427
	}
5428
}
5429
5430
/*
5431
 * A simple version of printb for status output
5432
 */
5433
void
5434
printb_status(unsigned short v, unsigned char *bits)
5435
{
5436
	int i, any = 0;
5437
	unsigned char c;
5438
5439
	if (bits) {
5440
		bits++;
5441
		while ((i = *bits++)) {
5442
			if (v & (1 << (i-1))) {
5443
				if (any)
5444
					putchar(',');
5445
				any = 1;
5446
				for (; (c = *bits) > 32; bits++)
5447
					putchar(tolower(c));
5448
			} else
5449
				for (; *bits > 32; bits++)
5450
					;
5451
		}
5452
	}
5453
}
5454
5455
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
5456
struct sockaddr_in6 *sin6tab[] = {
5457
SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
5458
SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
5459
5460
void
5461
in6_getaddr(const char *s, int which)
5462
6
{
5463
6
	struct sockaddr_in6 *sin6 = sin6tab[which];
5464
	struct addrinfo hints, *res;
5465
	char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
5466
	int error;
5467
5468
6
	memset(&hints, 0, sizeof(hints));
5469
6
	hints.ai_family = AF_INET6;
5470
6
	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
5471
5472

6
	if (which == ADDR && strchr(s, '/') != NULL) {
5473
6
		if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
5474
			errx(1, "%s: bad value", s);
5475
6
		pfxlen = strchr(buf, '/');
5476
6
		*pfxlen++ = '\0';
5477
6
		s = buf;
5478
6
		in6_getprefix(pfxlen, MASK);
5479
6
		explicit_prefix = 1;
5480
	}
5481
5482
6
	error = getaddrinfo(s, "0", &hints, &res);
5483
6
	if (error)
5484
		errx(1, "%s: %s", s, gai_strerror(error));
5485
6
	if (res->ai_addrlen != sizeof(struct sockaddr_in6))
5486
		errx(1, "%s: bad value", s);
5487
6
	memcpy(sin6, res->ai_addr, res->ai_addrlen);
5488
#ifdef __KAME__
5489


6
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
5490
	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
5491
	    sin6->sin6_scope_id) {
5492
		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
5493
		    htons(sin6->sin6_scope_id & 0xffff);
5494
		sin6->sin6_scope_id = 0;
5495
	}
5496
#endif /* __KAME__ */
5497
6
	freeaddrinfo(res);
5498
6
}
5499
5500
void
5501
in6_getprefix(const char *plen, int which)
5502
8
{
5503
8
	struct sockaddr_in6 *sin6 = sin6tab[which];
5504
8
	const char *errmsg = NULL;
5505
	u_char *cp;
5506
	int len;
5507
5508
8
	len = strtonum(plen, 0, 128, &errmsg);
5509
8
	if (errmsg)
5510
		errx(1, "prefix %s: %s", plen, errmsg);
5511
5512
8
	sin6->sin6_len = sizeof(*sin6);
5513
8
	if (which != MASK)
5514
		sin6->sin6_family = AF_INET6;
5515
8
	if ((len == 0) || (len == 128)) {
5516
		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
5517
		return;
5518
	}
5519
8
	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
5520
72
	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
5521
64
		*cp++ = 0xff;
5522
8
	if (len)
5523
		*cp = 0xff << (8 - len);
5524
}
5525
5526
int
5527
prefix(void *val, int size)
5528
{
5529
	u_char *nam = (u_char *)val;
5530
	int byte, bit, plen = 0;
5531
5532
	for (byte = 0; byte < size; byte++, plen += 8)
5533
		if (nam[byte] != 0xff)
5534
			break;
5535
	if (byte == size)
5536
		return (plen);
5537
	for (bit = 7; bit != 0; bit--, plen++)
5538
		if (!(nam[byte] & (1 << bit)))
5539
			break;
5540
	for (; bit != 0; bit--)
5541
		if (nam[byte] & (1 << bit))
5542
			return (0);
5543
	byte++;
5544
	for (; byte < size; byte++)
5545
		if (nam[byte])
5546
			return (0);
5547
	return (plen);
5548
}
5549
5550
/* Print usage, exit(value) if value is non-zero. */
5551
void
5552
usage(int value)
5553
{
5554
	fprintf(stderr,
5555
	    "usage: ifconfig [-AaC] [interface] [address_family] "
5556
	    "[address [dest_address]]\n"
5557
	    "\t\t[parameters]\n");
5558
	exit(value);
5559
}
5560
5561
void
5562
getifgroups(void)
5563
{
5564
	int			 len, cnt;
5565
	struct ifgroupreq	 ifgr;
5566
	struct ifg_req		*ifg;
5567
5568
	memset(&ifgr, 0, sizeof(ifgr));
5569
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
5570
5571
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
5572
		if (errno == EINVAL || errno == ENOTTY)
5573
			return;
5574
		else
5575
			err(1, "SIOCGIFGROUP");
5576
	}
5577
5578
	len = ifgr.ifgr_len;
5579
	ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
5580
	    sizeof(struct ifg_req));
5581
	if (ifgr.ifgr_groups == NULL)
5582
		err(1, "getifgroups");
5583
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
5584
		err(1, "SIOCGIFGROUP");
5585
5586
	cnt = 0;
5587
	ifg = ifgr.ifgr_groups;
5588
	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
5589
		len -= sizeof(struct ifg_req);
5590
		if (strcmp(ifg->ifgrq_group, "all")) {
5591
			if (cnt == 0)
5592
				printf("\tgroups:");
5593
			cnt++;
5594
			printf(" %s", ifg->ifgrq_group);
5595
		}
5596
	}
5597
	if (cnt)
5598
		printf("\n");
5599
5600
	free(ifgr.ifgr_groups);
5601
}
5602
5603
#ifndef SMALL
5604
void
5605
printifhwfeatures(const char *unused, int show)
5606
{
5607
	struct if_data ifrdat;
5608
5609
	if (!show) {
5610
		if (showcapsflag)
5611
			usage(1);
5612
		showcapsflag = 1;
5613
		return;
5614
	}
5615
	bzero(&ifrdat, sizeof(ifrdat));
5616
	ifr.ifr_data = (caddr_t)&ifrdat;
5617
	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
5618
		err(1, "SIOCGIFDATA");
5619
	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
5620
5621
	if (ioctl(s, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
5622
		if (ifr.ifr_hardmtu)
5623
			printf(" hardmtu %u", ifr.ifr_hardmtu);
5624
	}
5625
	putchar('\n');
5626
}
5627
#endif
5628
5629
char *
5630
sec2str(time_t total)
5631
{
5632
	static char result[256];
5633
	char *p = result;
5634
	char *end = &result[sizeof(result)];
5635
5636
	snprintf(p, end - p, "%lld", (long long)total);
5637
	return (result);
5638
}
5639
5640
/*ARGSUSED*/
5641
void
5642
setiflladdr(const char *addr, int param)
5643
{
5644
	struct ether_addr *eap, eabuf;
5645
5646
	if (!strcmp(addr, "random")) {
5647
		arc4random_buf(&eabuf, sizeof eabuf);
5648
		/* Non-multicast and claim it is a hardware address */
5649
		eabuf.ether_addr_octet[0] &= 0xfc;
5650
		eap = &eabuf;
5651
	} else {
5652
		eap = ether_aton(addr);
5653
		if (eap == NULL) {
5654
			warnx("malformed link-level address");
5655
			return;
5656
		}
5657
	}
5658
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5659
	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
5660
	ifr.ifr_addr.sa_family = AF_LINK;
5661
	bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
5662
	if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
5663
		warn("SIOCSIFLLADDR");
5664
}
5665
5666
#ifndef SMALL
5667
void
5668
setinstance(const char *id, int param)
5669
88
{
5670
88
	const char *errmsg = NULL;
5671
	int rdomainid;
5672
5673
88
	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
5674
88
	if (errmsg)
5675
		errx(1, "rdomain %s: %s", id, errmsg);
5676
5677
88
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5678
88
	ifr.ifr_rdomainid = rdomainid;
5679
88
	if (ioctl(s, SIOCSIFRDOMAIN, (caddr_t)&ifr) < 0)
5680
		warn("SIOCSIFRDOMAIN");
5681
88
}
5682
#endif
5683
5684
#ifndef SMALL
5685
void
5686
setpair(const char *val, int d)
5687
{
5688
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5689
	if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
5690
		errno = ENOENT;
5691
		err(1, "patch %s", val);
5692
	}
5693
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5694
		warn("SIOCSIFPAIR");
5695
}
5696
5697
void
5698
unsetpair(const char *val, int d)
5699
{
5700
	ifr.ifr_index = 0;
5701
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5702
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5703
		warn("SIOCSIFPAIR");
5704
}
5705
#endif
5706
5707
#ifdef SMALL
5708
void
5709
setignore(const char *id, int param)
5710
{
5711
	/* just digest the command */
5712
}
5713
#endif