GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ifconfig/ifconfig.c Lines: 725 2673 27.1 %
Date: 2017-11-07 Branches: 360 1802 20.0 %

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

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

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

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

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

738
		if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
1002
			if (printgroup(oname, ifaliases) != -1) {
1003
				free(oname);
1004
				return;
1005
			}
1006
	}
1007
1008
520
	if (getifaddrs(&ifap) != 0)
1009
		err(1, "getifaddrs");
1010
1011
	namep = NULL;
1012
16656
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1013
7808
		if (oname) {
1014

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

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

711
		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1393
135
		    strcmp(ifa->ifa_name, name) == 0) {
1394
54
			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1395

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

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

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

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

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

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

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

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

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

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

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

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

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

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

54
	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
5448
	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
5449
	    sin6->sin6_scope_id) {
5450
		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
5451
		    htons(sin6->sin6_scope_id & 0xffff);
5452
		sin6->sin6_scope_id = 0;
5453
	}
5454
#endif /* __KAME__ */
5455
54
	freeaddrinfo(res);
5456
54
}
5457
5458
void
5459
in6_getprefix(const char *plen, int which)
5460
{
5461
198
	struct sockaddr_in6 *sin6 = sin6tab[which];
5462
99
	const char *errmsg = NULL;
5463
	u_char *cp;
5464
	int len;
5465
5466
99
	len = strtonum(plen, 0, 128, &errmsg);
5467
99
	if (errmsg)
5468
		errx(1, "prefix %s: %s", plen, errmsg);
5469
5470
99
	sin6->sin6_len = sizeof(*sin6);
5471
99
	if (which != MASK)
5472
		sin6->sin6_family = AF_INET6;
5473
99
	if ((len == 0) || (len == 128)) {
5474
		memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
5475
		return;
5476
	}
5477
99
	memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
5478
1782
	for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
5479
792
		*cp++ = 0xff;
5480
99
	if (len)
5481
		*cp = 0xff << (8 - len);
5482
198
}
5483
5484
int
5485
prefix(void *val, int size)
5486
{
5487
	u_char *nam = (u_char *)val;
5488
	int byte, bit, plen = 0;
5489
5490
12204
	for (byte = 0; byte < size; byte++, plen += 8)
5491
5672
		if (nam[byte] != 0xff)
5492
			break;
5493
484
	if (byte == size)
5494
188
		return (plen);
5495
592
	for (bit = 7; bit != 0; bit--, plen++)
5496
296
		if (!(nam[byte] & (1 << bit)))
5497
			break;
5498
4440
	for (; bit != 0; bit--)
5499
2072
		if (nam[byte] & (1 << bit))
5500
			return (0);
5501
296
	byte++;
5502
4736
	for (; byte < size; byte++)
5503
2072
		if (nam[byte])
5504
			return (0);
5505
296
	return (plen);
5506
484
}
5507
5508
/* Print usage and exit  */
5509
__dead void
5510
usage(void)
5511
{
5512
	fprintf(stderr,
5513
	    "usage: ifconfig [-AaC] [interface] [address_family] "
5514
	    "[address [dest_address]]\n"
5515
	    "\t\t[parameters]\n");
5516
	exit(1);
5517
}
5518
5519
void
5520
getifgroups(void)
5521
{
5522
	int			 len, cnt;
5523
3246
	struct ifgroupreq	 ifgr;
5524
	struct ifg_req		*ifg;
5525
5526
1623
	memset(&ifgr, 0, sizeof(ifgr));
5527
1623
	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
5528
5529
1623
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
5530
		if (errno == EINVAL || errno == ENOTTY)
5531
			return;
5532
		else
5533
			err(1, "SIOCGIFGROUP");
5534
	}
5535
5536
1623
	len = ifgr.ifgr_len;
5537
1623
	ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
5538
	    sizeof(struct ifg_req));
5539
1623
	if (ifgr.ifgr_groups == NULL)
5540
		err(1, "getifgroups");
5541
1623
	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
5542
		err(1, "SIOCGIFGROUP");
5543
5544
	cnt = 0;
5545
1623
	ifg = ifgr.ifgr_groups;
5546

14607
	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
5547
3246
		len -= sizeof(struct ifg_req);
5548
3246
		if (strcmp(ifg->ifgrq_group, "all")) {
5549
1623
			if (cnt == 0)
5550
1623
				printf("\tgroups:");
5551
1623
			cnt++;
5552
1623
			printf(" %s", ifg->ifgrq_group);
5553
1623
		}
5554
	}
5555
1623
	if (cnt)
5556
1623
		printf("\n");
5557
5558
1623
	free(ifgr.ifgr_groups);
5559
3246
}
5560
5561
#ifndef SMALL
5562
void
5563
printifhwfeatures(const char *unused, int show)
5564
{
5565
	struct if_data ifrdat;
5566
5567
	if (!show) {
5568
		if (showcapsflag)
5569
			usage();
5570
		showcapsflag = 1;
5571
		return;
5572
	}
5573
	bzero(&ifrdat, sizeof(ifrdat));
5574
	ifr.ifr_data = (caddr_t)&ifrdat;
5575
	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
5576
		err(1, "SIOCGIFDATA");
5577
	printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
5578
5579
	if (ioctl(s, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
5580
		if (ifr.ifr_hardmtu)
5581
			printf(" hardmtu %u", ifr.ifr_hardmtu);
5582
	}
5583
	putchar('\n');
5584
}
5585
#endif
5586
5587
char *
5588
sec2str(time_t total)
5589
{
5590
	static char result[256];
5591
	char *p = result;
5592
	char *end = &result[sizeof(result)];
5593
5594
	snprintf(p, end - p, "%lld", (long long)total);
5595
	return (result);
5596
}
5597
5598
/*ARGSUSED*/
5599
void
5600
setiflladdr(const char *addr, int param)
5601
{
5602
104
	struct ether_addr *eap, eabuf;
5603
5604
52
	if (!strcmp(addr, "random")) {
5605
		arc4random_buf(&eabuf, sizeof eabuf);
5606
		/* Non-multicast and claim it is a hardware address */
5607
		eabuf.ether_addr_octet[0] &= 0xfc;
5608
		eap = &eabuf;
5609
	} else {
5610
52
		eap = ether_aton(addr);
5611
52
		if (eap == NULL) {
5612
			warnx("malformed link-level address");
5613
			return;
5614
		}
5615
	}
5616
52
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5617
52
	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
5618
52
	ifr.ifr_addr.sa_family = AF_LINK;
5619
52
	bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
5620
52
	if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0)
5621
		warn("SIOCSIFLLADDR");
5622
104
}
5623
5624
#ifndef SMALL
5625
void
5626
setrdomain(const char *id, int param)
5627
{
5628
2542
	const char *errmsg = NULL;
5629
	int rdomainid;
5630
5631
1271
	rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
5632
1271
	if (errmsg)
5633
		errx(1, "rdomain %s: %s", id, errmsg);
5634
5635
1271
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5636
1271
	ifr.ifr_rdomainid = rdomainid;
5637
1271
	if (ioctl(s, SIOCSIFRDOMAIN, (caddr_t)&ifr) < 0)
5638
		warn("SIOCSIFRDOMAIN");
5639
1271
}
5640
#endif
5641
5642
#ifndef SMALL
5643
void
5644
setpair(const char *val, int d)
5645
{
5646
18
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5647
9
	if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
5648
		errno = ENOENT;
5649
		err(1, "patch %s", val);
5650
	}
5651
9
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5652
		warn("SIOCSIFPAIR");
5653
9
}
5654
5655
void
5656
unsetpair(const char *val, int d)
5657
{
5658
	ifr.ifr_index = 0;
5659
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
5660
	if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
5661
		warn("SIOCSIFPAIR");
5662
}
5663
#endif
5664
5665
#ifdef SMALL
5666
void
5667
setignore(const char *id, int param)
5668
{
5669
	/* just digest the command */
5670
}
5671
#endif