xref: /netbsd-src/sbin/ifconfig/ifconfig.c (revision c0179c282a5968435315a82f4128c61372c68fc3)
1 /*	$NetBSD: ifconfig.c,v 1.179 2006/11/23 19:43:52 yamt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Copyright (c) 1983, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. Redistributions in binary form must reproduce the above copyright
50  *    notice, this list of conditions and the following disclaimer in the
51  *    documentation and/or other materials provided with the distribution.
52  * 3. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  */
68 
69 #include <sys/cdefs.h>
70 #ifndef lint
71 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
72 	The Regents of the University of California.  All rights reserved.\n");
73 #endif /* not lint */
74 
75 #ifndef lint
76 #if 0
77 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
78 #else
79 __RCSID("$NetBSD: ifconfig.c,v 1.179 2006/11/23 19:43:52 yamt Exp $");
80 #endif
81 #endif /* not lint */
82 
83 #include <sys/param.h>
84 #include <sys/socket.h>
85 #include <sys/ioctl.h>
86 
87 #include <net/if.h>
88 #include <net/if_dl.h>
89 #include <net/if_media.h>
90 #include <net/if_ether.h>
91 #include <netinet/in.h>		/* XXX */
92 #include <netinet/in_var.h>	/* XXX */
93 
94 #include <netdb.h>
95 
96 #include <sys/protosw.h>
97 
98 #include <ctype.h>
99 #include <err.h>
100 #include <errno.h>
101 #include <stddef.h>
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <string.h>
105 #include <unistd.h>
106 #include <ifaddrs.h>
107 #include <util.h>
108 
109 #include "extern.h"
110 
111 #ifndef INET_ONLY
112 #include "af_atalk.h"
113 #include "af_iso.h"
114 #endif /* ! INET_ONLY */
115 #include "af_inet.h"
116 #ifdef INET6
117 #include "af_inet6.h"
118 #endif /* INET6 */
119 
120 #include "agr.h"
121 #include "carp.h"
122 #include "ieee80211.h"
123 #include "tunnel.h"
124 #include "vlan.h"
125 
126 struct	ifreq		ifr, ridreq;
127 struct	ifaliasreq	addreq __attribute__((aligned(4)));
128 
129 char	name[30];
130 u_short	flags;
131 int	setaddr, doalias;
132 u_long	metric, mtu, preference;
133 int	clearaddr, s;
134 int	newaddr = -1;
135 int	conflicting = 0;
136 int	check_up_state = -1;
137 int	af;
138 int	aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag, vflag, zflag;
139 int	hflag;
140 int	have_preference = 0;
141 #ifdef INET6
142 int	Lflag;
143 #endif
144 int	explicit_prefix = 0;
145 
146 struct ifcapreq g_ifcr;
147 int	g_ifcr_updated;
148 
149 void 	notealias(const char *, int);
150 void 	notrailers(const char *, int);
151 void 	setifaddr(const char *, int);
152 void 	setifdstaddr(const char *, int);
153 void 	setifflags(const char *, int);
154 void	check_ifflags_up(const char *);
155 void	setifcaps(const char *, int);
156 void 	setifbroadaddr(const char *, int);
157 void 	setifipdst(const char *, int);
158 void 	setifmetric(const char *, int);
159 void	setifpreference(const char *, int);
160 void 	setifmtu(const char *, int);
161 void 	setifnetmask(const char *, int);
162 void	setifprefixlen(const char *, int);
163 void	setmedia(const char *, int);
164 void	setmediamode(const char *, int);
165 void	setmediaopt(const char *, int);
166 void	unsetmediaopt(const char *, int);
167 void	setmediainst(const char *, int);
168 void	clone_create(const char *, int);
169 void	clone_destroy(const char *, int);
170 int	main(int, char *[]);
171 void	do_setifpreference(void);
172 
173 /*
174  * Media stuff.  Whenever a media command is first performed, the
175  * currently select media is grabbed for this interface.  If `media'
176  * is given, the current media word is modifed.  `mediaopt' commands
177  * only modify the set and clear words.  They then operate on the
178  * current media word later.
179  */
180 int	media_current;
181 int	mediaopt_set;
182 int	mediaopt_clear;
183 
184 int	actions;			/* Actions performed */
185 
186 #define	A_MEDIA		0x0001		/* media command */
187 #define	A_MEDIAOPTSET	0x0002		/* mediaopt command */
188 #define	A_MEDIAOPTCLR	0x0004		/* -mediaopt command */
189 #define	A_MEDIAOPT	(A_MEDIAOPTSET|A_MEDIAOPTCLR)
190 #define	A_MEDIAINST	0x0008		/* instance or inst command */
191 #define	A_MEDIAMODE	0x0010		/* mode command */
192 
193 #define	NEXTARG		0xffffff
194 #define	NEXTARG2	0xfffffe
195 
196 const struct cmd {
197 	const char *c_name;
198 	int	c_parameter;	/* NEXTARG means next argv */
199 	int	c_action;	/* defered action */
200 	void	(*c_func)(const char *, int);
201 } cmds[] = {
202 	{ "up",		IFF_UP,		0,		setifflags } ,
203 	{ "down",	-IFF_UP,	0,		setifflags },
204 	{ "trailers",	-1,		0,		notrailers },
205 	{ "-trailers",	1,		0,		notrailers },
206 	{ "arp",	-IFF_NOARP,	0,		setifflags },
207 	{ "-arp",	IFF_NOARP,	0,		setifflags },
208 	{ "debug",	IFF_DEBUG,	0,		setifflags },
209 	{ "-debug",	-IFF_DEBUG,	0,		setifflags },
210 	{ "alias",	IFF_UP,		0,		notealias },
211 	{ "-alias",	-IFF_UP,	0,		notealias },
212 	{ "delete",	-IFF_UP,	0,		notealias },
213 #ifdef notdef
214 #define	EN_SWABIPS	0x1000
215 	{ "swabips",	EN_SWABIPS,	0,		setifflags },
216 	{ "-swabips",	-EN_SWABIPS,	0,		setifflags },
217 #endif
218 	{ "netmask",	NEXTARG,	0,		setifnetmask },
219 	{ "metric",	NEXTARG,	0,		setifmetric },
220 	{ "mtu",	NEXTARG,	0,		setifmtu },
221 	{ "bssid",	NEXTARG,	0,		setifbssid },
222 	{ "-bssid",	-1,		0,		setifbssid },
223 	{ "chan",	NEXTARG,	0,		setifchan },
224 	{ "-chan",	-1,		0,		setifchan },
225 	{ "ssid",	NEXTARG,	0,		setifnwid },
226 	{ "nwid",	NEXTARG,	0,		setifnwid },
227 	{ "nwkey",	NEXTARG,	0,		setifnwkey },
228 	{ "-nwkey",	-1,		0,		setifnwkey },
229 	{ "powersave",	1,		0,		setifpowersave },
230 	{ "-powersave",	0,		0,		setifpowersave },
231 	{ "powersavesleep", NEXTARG,	0,		setifpowersavesleep },
232 	{ "hidessid",	1,		0,		sethidessid },
233 	{ "-hidessid",	0,		0,		sethidessid },
234 	{ "apbridge",	1,		0,		setapbridge },
235 	{ "-apbridge",	0,		0,		setapbridge },
236 	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
237 	{ "ipdst",	NEXTARG,	0,		setifipdst },
238 	{ "prefixlen",	NEXTARG,	0,		setifprefixlen},
239 	{ "preference",	NEXTARG,	0,		setifpreference},
240 #ifndef INET_ONLY
241 	/* CARP */
242 	{ "advbase",	NEXTARG,	0,		setcarp_advbase },
243 	{ "advskew",	NEXTARG,	0,		setcarp_advskew },
244 	{ "pass",	NEXTARG,	0,		setcarp_passwd },
245 	{ "vhid",	NEXTARG,	0,		setcarp_vhid },
246 	{ "state",	NEXTARG,	0,		setcarp_state },
247 	{ "carpdev",	NEXTARG,	0,		setcarpdev },
248 	{ "-carpdev",	1,		0,		unsetcarpdev },
249 #endif
250 #ifdef INET6
251 	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
252 	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
253 	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
254 	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
255 	{ "deprecated",	IN6_IFF_DEPRECATED,	0,	setia6flags },
256 	{ "-deprecated", -IN6_IFF_DEPRECATED,	0,	setia6flags },
257 	{ "pltime",	NEXTARG,	0,		setia6pltime },
258 	{ "vltime",	NEXTARG,	0,		setia6vltime },
259 	{ "eui64",	0,		0,		setia6eui64 },
260 #endif /*INET6*/
261 #ifndef INET_ONLY
262 	{ "range",	NEXTARG,	0,		setatrange },
263 	{ "phase",	NEXTARG,	0,		setatphase },
264 	{ "snpaoffset",	NEXTARG,	0,		setsnpaoffset },
265 	{ "nsellength",	NEXTARG,	0,		setnsellength },
266 #endif	/* INET_ONLY */
267 	{ "tunnel",	NEXTARG2,	0,	(void (*)(const char *, int))
268 							settunnel } ,
269 	{ "deletetunnel", 0,		0,		deletetunnel },
270 	{ "vlan",	NEXTARG,	0,		setvlan } ,
271 	{ "vlanif",	NEXTARG,	0,		setvlanif } ,
272 	{ "-vlanif",	0,		0,		unsetvlanif } ,
273 #if 0
274 	/* XXX `create' special-cased below */
275 	{ "create",	0,		0,		clone_create } ,
276 #endif
277 	{ "destroy",	0,		0,		clone_destroy } ,
278 	{ "link0",	IFF_LINK0,	0,		setifflags } ,
279 	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
280 	{ "link1",	IFF_LINK1,	0,		setifflags } ,
281 	{ "-link1",	-IFF_LINK1,	0,		setifflags } ,
282 	{ "link2",	IFF_LINK2,	0,		setifflags } ,
283 	{ "-link2",	-IFF_LINK2,	0,		setifflags } ,
284 	{ "media",	NEXTARG,	A_MEDIA,	setmedia },
285 	{ "mediaopt",	NEXTARG,	A_MEDIAOPTSET,	setmediaopt },
286 	{ "-mediaopt",	NEXTARG,	A_MEDIAOPTCLR,	unsetmediaopt },
287 	{ "mode",	NEXTARG,	A_MEDIAMODE,	setmediamode },
288 	{ "instance",	NEXTARG,	A_MEDIAINST,	setmediainst },
289 	{ "inst",	NEXTARG,	A_MEDIAINST,	setmediainst },
290 	{ "ip4csum-tx",	IFCAP_CSUM_IPv4_Tx,0,		setifcaps },
291 	{ "-ip4csum-tx",-IFCAP_CSUM_IPv4_Tx,0,		setifcaps },
292 	{ "ip4csum-rx",	IFCAP_CSUM_IPv4_Rx,0,		setifcaps },
293 	{ "-ip4csum-rx",-IFCAP_CSUM_IPv4_Rx,0,		setifcaps },
294 	{ "tcp4csum-tx",IFCAP_CSUM_TCPv4_Tx,0,		setifcaps },
295 	{ "-tcp4csum-tx",-IFCAP_CSUM_TCPv4_Tx,0,	setifcaps },
296 	{ "tcp4csum-rx",IFCAP_CSUM_TCPv4_Rx,0,		setifcaps },
297 	{ "-tcp4csum-rx",-IFCAP_CSUM_TCPv4_Rx,0,	setifcaps },
298 	{ "udp4csum-tx",IFCAP_CSUM_UDPv4_Tx,0,		setifcaps },
299 	{ "-udp4csum-tx",-IFCAP_CSUM_UDPv4_Tx,0,	setifcaps },
300 	{ "udp4csum-rx",IFCAP_CSUM_UDPv4_Rx,0,		setifcaps },
301 	{ "-udp4csum-rx",-IFCAP_CSUM_UDPv4_Rx,0,	setifcaps },
302 	{ "tcp6csum-tx",IFCAP_CSUM_TCPv6_Tx,0,		setifcaps },
303 	{ "-tcp6csum-tx",-IFCAP_CSUM_TCPv6_Tx,0,	setifcaps },
304 	{ "tcp6csum-rx",IFCAP_CSUM_TCPv6_Rx,0,		setifcaps },
305 	{ "-tcp6csum-rx",-IFCAP_CSUM_TCPv6_Rx,0,	setifcaps },
306 	{ "udp6csum-tx",IFCAP_CSUM_UDPv6_Tx,0,		setifcaps },
307 	{ "-udp6csum-tx",-IFCAP_CSUM_UDPv6_Tx,0,	setifcaps },
308 	{ "udp6csum-rx",IFCAP_CSUM_UDPv6_Rx,0,		setifcaps },
309 	{ "-udp6csum-rx",-IFCAP_CSUM_UDPv6_Rx,0,	setifcaps },
310 	{ "ip4csum",	IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx,
311 					0,		setifcaps },
312 	{ "-ip4csum",	-(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx),
313 					0,		setifcaps },
314 	{ "tcp4csum",	IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx,
315 					0,		setifcaps },
316 	{ "-tcp4csum",	-(IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx),
317 					0,		setifcaps },
318 	{ "udp4csum",	IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx,
319 					0,		setifcaps },
320 	{ "-udp4csum",	-(IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx),
321 					0,		setifcaps },
322 	{ "tcp6csum",	IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx,
323 					0,		setifcaps },
324 	{ "-tcp6csum",	-(IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx),
325 					0,		setifcaps },
326 	{ "udp6csum",	IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx,
327 					0,		setifcaps },
328 	{ "-udp6csum",	-(IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx),
329 					0,		setifcaps },
330 	{ "tso4",	IFCAP_TSOv4,	0,		setifcaps },
331 	{ "-tso4",	-IFCAP_TSOv4,	0,		setifcaps },
332 	{ "tso6",	IFCAP_TSOv6,	0,		setifcaps },
333 	{ "-tso6",	-IFCAP_TSOv6,	0,		setifcaps },
334 	{ "agrport",	NEXTARG,	0,		agraddport } ,
335 	{ "-agrport",	NEXTARG,	0,		agrremport } ,
336 	{ 0,		0,		0,		setifaddr },
337 	{ 0,		0,		0,		setifdstaddr },
338 };
339 
340 int	getinfo(struct ifreq *);
341 int	carrier(void);
342 void	printall(const char *);
343 void	list_cloners(void);
344 void 	status(const struct sockaddr_dl *);
345 void 	usage(void);
346 
347 void	print_media_word(int, const char *);
348 void	process_media_commands(void);
349 void	init_current_media(void);
350 
351 /* Known address families */
352 const struct afswtch afs[] = {
353 	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
354 	     SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &in_addreq },
355 #ifdef INET6
356 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
357 	     SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
358 	     /*
359 	      * Deleting the first address before setting new one is
360 	      * not prefered way in this protocol.
361 	      */
362 	     0,
363 	     &in6_ridreq, &in6_addreq },
364 #endif
365 #ifndef INET_ONLY	/* small version, for boot media */
366 	{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
367 	     SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &addreq, &addreq },
368 	{ "iso", AF_ISO, iso_status, iso_getaddr, NULL,
369 	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
370 	     &iso_ridreq, &iso_addreq },
371 #endif	/* INET_ONLY */
372 	{ 0,	0,	    0,		0, 0, 0, 0, 0, 0, 0 }
373 };
374 
375 const struct afswtch *afp;	/*the address family being set or asked about*/
376 
377 int
378 main(int argc, char *argv[])
379 {
380 	int ch;
381 
382 	/* Parse command-line options */
383 	aflag = mflag = vflag = zflag = 0;
384 	while ((ch = getopt(argc, argv, "AabCdhlmsuvz"
385 #ifdef INET6
386 					"L"
387 #endif
388 			)) != -1) {
389 		switch (ch) {
390 		case 'A':
391 			warnx("-A is deprecated");
392 			break;
393 
394 		case 'a':
395 			aflag = 1;
396 			break;
397 
398 		case 'b':
399 			bflag = 1;
400 			break;
401 
402 		case 'C':
403 			Cflag = 1;
404 			break;
405 
406 		case 'd':
407 			dflag = 1;
408 			break;
409 		case 'h':
410 			hflag = 1;
411 			break;
412 #ifdef INET6
413 		case 'L':
414 			Lflag = 1;
415 			break;
416 #endif
417 
418 		case 'l':
419 			lflag = 1;
420 			break;
421 
422 		case 'm':
423 			mflag = 1;
424 			break;
425 
426 		case 's':
427 			sflag = 1;
428 			break;
429 
430 		case 'u':
431 			uflag = 1;
432 			break;
433 
434 		case 'v':
435 			vflag = 1;
436 			break;
437 
438 		case 'z':
439 			zflag = 1;
440 			break;
441 
442 
443 		default:
444 			usage();
445 			/* NOTREACHED */
446 		}
447 	}
448 	argc -= optind;
449 	argv += optind;
450 
451 	/*
452 	 * -l means "list all interfaces", and is mutally exclusive with
453 	 * all other flags/commands.
454 	 *
455 	 * -C means "list all names of cloners", and it mutually exclusive
456 	 * with all other flags/commands.
457 	 *
458 	 * -a means "print status of all interfaces".
459 	 */
460 	if ((lflag || Cflag) && (aflag || mflag || vflag || argc || zflag))
461 		usage();
462 #ifdef INET6
463 	if ((lflag || Cflag) && Lflag)
464 		usage();
465 #endif
466 	if (lflag && Cflag)
467 		usage();
468 	if (Cflag) {
469 		if (argc)
470 			usage();
471 		list_cloners();
472 		exit(0);
473 	}
474 	if (aflag || lflag) {
475 		if (argc > 1)
476 			usage();
477 		else if (argc == 1) {
478 			afp = lookup_af_byname(argv[0]);
479 			if (afp == NULL)
480 				usage();
481 		}
482 		if (afp)
483 			af = ifr.ifr_addr.sa_family = afp->af_af;
484 		else
485 			af = ifr.ifr_addr.sa_family = afs[0].af_af;
486 		printall(NULL);
487 		exit(0);
488 	}
489 
490 	/* Make sure there's an interface name. */
491 	if (argc < 1)
492 		usage();
493 	if (strlcpy(name, argv[0], sizeof(name)) >= sizeof(name))
494 		errx(1, "interface name '%s' too long", argv[0]);
495 	argc--; argv++;
496 
497 	/*
498 	 * NOTE:  We must special-case the `create' command right
499 	 * here as we would otherwise fail in getinfo().
500 	 */
501 	if (argc > 0 && strcmp(argv[0], "create") == 0) {
502 		clone_create(argv[0], 0);
503 		argc--, argv++;
504 		if (argc == 0)
505 			exit(0);
506 	}
507 
508 	/* Check for address family. */
509 	afp = NULL;
510 	if (argc > 0) {
511 		afp = lookup_af_byname(argv[0]);
512 		if (afp != NULL) {
513 			argv++;
514 			argc--;
515 		}
516 	}
517 
518 	/* Initialize af, just for use in getinfo(). */
519 	if (afp == NULL)
520 		af = afs->af_af;
521 	else
522 		af = afp->af_af;
523 
524 	/* Get information about the interface. */
525 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
526 	if (getinfo(&ifr) < 0)
527 		exit(1);
528 
529 	if (sflag) {
530 		if (argc != 0)
531 			usage();
532 		else
533 			exit(carrier());
534 	}
535 
536 	/* No more arguments means interface status. */
537 	if (argc == 0) {
538 		printall(name);
539 		exit(0);
540 	}
541 
542 	/* The following operations assume inet family as the default. */
543 	if (afp == NULL)
544 		afp = afs;
545 	af = ifr.ifr_addr.sa_family = afp->af_af;
546 
547 #ifdef INET6
548 	in6_init();
549 #endif
550 
551 	/* Process commands. */
552 	while (argc > 0) {
553 		const struct cmd *p;
554 
555 		for (p = cmds; p->c_name; p++)
556 			if (strcmp(argv[0], p->c_name) == 0)
557 				break;
558 		if (p->c_name == 0 && setaddr) {
559 			if ((flags & IFF_POINTOPOINT) == 0) {
560 				errx(EXIT_FAILURE,
561 				    "can't set destination address %s",
562 				     "on non-point-to-point link");
563 			}
564 			p++;	/* got src, do dst */
565 		}
566 		if (p->c_func != NULL) {
567 			if (p->c_parameter == NEXTARG) {
568 				if (argc < 2)
569 					errx(EXIT_FAILURE,
570 					    "'%s' requires argument",
571 					    p->c_name);
572 				(*p->c_func)(argv[1], 0);
573 				argc--, argv++;
574 			} else if (p->c_parameter == NEXTARG2) {
575 				if (argc < 3)
576 					errx(EXIT_FAILURE,
577 					    "'%s' requires 2 arguments",
578 					    p->c_name);
579 				((void (*)(const char *, const char *))
580 				    *p->c_func)(argv[1], argv[2]);
581 				argc -= 2, argv += 2;
582 			} else
583 				(*p->c_func)(argv[0], p->c_parameter);
584 			actions |= p->c_action;
585 		}
586 		argc--, argv++;
587 	}
588 
589 	/*
590 	 * See if multiple alias, -alias, or delete commands were
591 	 * specified. More than one constitutes an invalid command line
592 	 */
593 
594 	if (conflicting > 1)
595 		errx(EXIT_FAILURE,
596 		    "Only one use of alias, -alias or delete is valid.");
597 
598 	/* Process any media commands that may have been issued. */
599 	process_media_commands();
600 
601 	if (af == AF_INET6 && explicit_prefix == 0) {
602 		/*
603 		 * Aggregatable address architecture defines all prefixes
604 		 * are 64. So, it is convenient to set prefixlen to 64 if
605 		 * it is not specified.
606 		 */
607 		setifprefixlen("64", 0);
608 		/* in6_getprefix("64", MASK) if MASK is available here... */
609 	}
610 
611 #ifndef INET_ONLY
612 	if (af == AF_ISO)
613 		adjust_nsellength();
614 
615 	if (af == AF_APPLETALK)
616 		checkatrange(&addreq.ifra_addr);
617 #endif	/* INET_ONLY */
618 
619 	if (clearaddr) {
620 		estrlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
621 		if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1)
622 			err(EXIT_FAILURE, "SIOCDIFADDR");
623 	}
624 	if (newaddr > 0) {
625 		estrlcpy(afp->af_addreq, name, sizeof ifr.ifr_name);
626 		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1)
627 			warn("SIOCAIFADDR");
628 		else if (check_up_state < 0)
629 			check_up_state = 1;
630 	}
631 
632 	if (have_preference)
633 		do_setifpreference();
634 	if (g_ifcr_updated) {
635 		strlcpy(g_ifcr.ifcr_name, name,
636 		    sizeof(g_ifcr.ifcr_name));
637 		if (ioctl(s, SIOCSIFCAP, &g_ifcr) == -1)
638 			err(EXIT_FAILURE, "SIOCSIFCAP");
639 	}
640 
641 	if (check_up_state == 1)
642 		check_ifflags_up(name);
643 
644 	exit(0);
645 }
646 
647 const struct afswtch *
648 lookup_af_byname(const char *cp)
649 {
650 	const struct afswtch *a;
651 
652 	for (a = afs; a->af_name != NULL; a++)
653 		if (strcmp(a->af_name, cp) == 0)
654 			return (a);
655 	return (NULL);
656 }
657 
658 const struct afswtch *
659 lookup_af_bynum(int afnum)
660 {
661 	const struct afswtch *a;
662 
663 	for (a = afs; a->af_name != NULL; a++)
664 		if (a->af_af == afnum)
665 			return (a);
666 	return (NULL);
667 }
668 
669 void
670 getsock(int naf)
671 {
672 	static int oaf = -1;
673 
674 	if (oaf == naf)
675 		return;
676 	if (oaf != -1)
677 		close(s);
678 	s = socket(naf, SOCK_DGRAM, 0);
679 	if (s < 0)
680 		oaf = -1;
681 	else
682 		oaf = naf;
683 }
684 
685 int
686 getinfo(struct ifreq *giifr)
687 {
688 
689 	getsock(af);
690 	if (s < 0)
691 		err(EXIT_FAILURE, "socket");
692 	if (ioctl(s, SIOCGIFFLAGS, giifr) == -1) {
693 		warn("SIOCGIFFLAGS %s", giifr->ifr_name);
694 		return (-1);
695 	}
696 	flags = giifr->ifr_flags;
697 	if (ioctl(s, SIOCGIFMETRIC, giifr) == -1) {
698 		warn("SIOCGIFMETRIC %s", giifr->ifr_name);
699 		metric = 0;
700 	} else
701 		metric = giifr->ifr_metric;
702 	if (ioctl(s, SIOCGIFMTU, giifr) == -1)
703 		mtu = 0;
704 	else
705 		mtu = giifr->ifr_mtu;
706 
707 	memset(&g_ifcr, 0, sizeof(g_ifcr));
708 	estrlcpy(g_ifcr.ifcr_name, giifr->ifr_name, sizeof(g_ifcr.ifcr_name));
709 	(void) ioctl(s, SIOCGIFCAP, &g_ifcr);
710 
711 	return (0);
712 }
713 
714 void
715 printall(const char *ifname)
716 {
717 	struct ifaddrs *ifap, *ifa;
718 	struct ifreq paifr;
719 	const struct sockaddr_dl *sdl = NULL;
720 	int idx;
721 	char *p;
722 
723 	if (getifaddrs(&ifap) != 0)
724 		err(EXIT_FAILURE, "getifaddrs");
725 	p = NULL;
726 	idx = 0;
727 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
728 		memset(&paifr, 0, sizeof(paifr));
729 		estrlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
730 		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
731 			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
732 			    ifa->ifa_addr->sa_len);
733 		}
734 
735 		if (ifname && strcmp(ifname, ifa->ifa_name) != 0)
736 			continue;
737 		if (ifa->ifa_addr->sa_family == AF_LINK)
738 			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
739 		if (p && strcmp(p, ifa->ifa_name) == 0)
740 			continue;
741 		if (strlcpy(name, ifa->ifa_name, sizeof(name)) >= sizeof(name))
742 			continue;
743 		p = ifa->ifa_name;
744 
745 		if (getinfo(&paifr) < 0)
746 			continue;
747 		if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
748 			continue;
749 		if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
750 			continue;
751 		if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
752 			continue;
753 
754 		if (sflag && carrier())
755 			continue;
756 		idx++;
757 		/*
758 		 * Are we just listing the interfaces?
759 		 */
760 		if (lflag) {
761 			if (idx > 1)
762 				printf(" ");
763 			fputs(name, stdout);
764 			continue;
765 		}
766 
767 		status(sdl);
768 		sdl = NULL;
769 	}
770 	if (lflag)
771 		printf("\n");
772 	freeifaddrs(ifap);
773 }
774 
775 void
776 list_cloners(void)
777 {
778 	struct if_clonereq ifcr;
779 	char *cp, *buf;
780 	int idx;
781 
782 	memset(&ifcr, 0, sizeof(ifcr));
783 
784 	getsock(AF_INET);
785 
786 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
787 		err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
788 
789 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
790 	if (buf == NULL)
791 		err(EXIT_FAILURE, "unable to allocate cloner name buffer");
792 
793 	ifcr.ifcr_count = ifcr.ifcr_total;
794 	ifcr.ifcr_buffer = buf;
795 
796 	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
797 		err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
798 
799 	/*
800 	 * In case some disappeared in the mean time, clamp it down.
801 	 */
802 	if (ifcr.ifcr_count > ifcr.ifcr_total)
803 		ifcr.ifcr_count = ifcr.ifcr_total;
804 
805 	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
806 		if (idx > 0)
807 			printf(" ");
808 		printf("%s", cp);
809 	}
810 
811 	printf("\n");
812 	free(buf);
813 	return;
814 }
815 
816 /*ARGSUSED*/
817 void
818 clone_create(const char *addr, int param)
819 {
820 
821 	/* We're called early... */
822 	getsock(AF_INET);
823 
824 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
825 	if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
826 		err(EXIT_FAILURE, "SIOCIFCREATE");
827 }
828 
829 /*ARGSUSED*/
830 void
831 clone_destroy(const char *addr, int param)
832 {
833 
834 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
835 	if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
836 		err(EXIT_FAILURE, "SIOCIFDESTROY");
837 }
838 
839 /*ARGSUSED*/
840 void
841 setifaddr(const char *addr, int param)
842 {
843 	struct ifreq *siifr;		/* XXX */
844 
845 	/*
846 	 * Delay the ioctl to set the interface addr until flags are all set.
847 	 * The address interpretation may depend on the flags,
848 	 * and the flags may change when the address is set.
849 	 */
850 	setaddr++;
851 	if (newaddr == -1)
852 		newaddr = 1;
853 	if (doalias == 0 && afp->af_gifaddr != 0) {
854 		siifr = (struct ifreq *)afp->af_ridreq;
855 		estrlcpy(siifr->ifr_name, name, sizeof(siifr->ifr_name));
856 		siifr->ifr_addr.sa_family = afp->af_af;
857 		if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
858 			clearaddr = 1;
859 		else if (errno == EADDRNOTAVAIL)
860 			/* No address was assigned yet. */
861 			;
862 		else
863 			err(EXIT_FAILURE, "SIOCGIFADDR");
864 	}
865 
866 	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
867 }
868 
869 void
870 setifnetmask(const char *addr, int d)
871 {
872 	(*afp->af_getaddr)(addr, MASK);
873 }
874 
875 void
876 setifbroadaddr(const char *addr, int d)
877 {
878 	(*afp->af_getaddr)(addr, DSTADDR);
879 }
880 
881 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
882 /*ARGSUSED*/
883 void
884 notealias(const char *addr, int param)
885 {
886 	if (setaddr && doalias == 0 && param < 0)
887 		(void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
888 		    rqtosa(af_addreq)->sa_len);
889 	doalias = param;
890 	if (param < 0) {
891 		clearaddr = 1;
892 		newaddr = 0;
893 		conflicting++;
894 	} else {
895 		clearaddr = 0;
896 		conflicting++;
897 	}
898 }
899 
900 /*ARGSUSED*/
901 void
902 notrailers(const char *vname, int value)
903 {
904 	puts("Note: trailers are no longer sent, but always received");
905 }
906 
907 /*ARGSUSED*/
908 void
909 setifdstaddr(const char *addr, int param)
910 {
911 	(*afp->af_getaddr)(addr, DSTADDR);
912 }
913 
914 void
915 check_ifflags_up(const char *vname)
916 {
917 	struct ifreq ifreq;
918 
919 	estrlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
920  	if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
921 		err(EXIT_FAILURE, "SIOCGIFFLAGS");
922 	if (ifreq.ifr_flags & IFF_UP)
923 		return;
924 	ifreq.ifr_flags |= IFF_UP;
925 	if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
926 		err(EXIT_FAILURE, "SIOCSIFFLAGS");
927 }
928 
929 void
930 setifflags(const char *vname, int value)
931 {
932 	struct ifreq ifreq;
933 
934 	estrlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
935  	if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
936 		err(EXIT_FAILURE, "SIOCGIFFLAGS");
937  	flags = ifreq.ifr_flags;
938 
939 	if (value < 0) {
940 		value = -value;
941 		if (value == IFF_UP)
942 			check_up_state = 0;
943 		flags &= ~value;
944 	} else
945 		flags |= value;
946 	ifreq.ifr_flags = flags;
947 	if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
948 		err(EXIT_FAILURE, "SIOCSIFFLAGS");
949 }
950 
951 void
952 setifcaps(const char *vname, int value)
953 {
954 
955 	if (value < 0) {
956 		value = -value;
957 		g_ifcr.ifcr_capenable &= ~value;
958 	} else
959 		g_ifcr.ifcr_capenable |= value;
960 
961 	g_ifcr_updated = 1;
962 }
963 
964 void
965 setifmetric(const char *val, int d)
966 {
967 	char *ep = NULL;
968 
969 	estrlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
970 	ifr.ifr_metric = strtoul(val, &ep, 10);
971 	if (!ep || *ep)
972 		errx(EXIT_FAILURE, "%s: invalid metric", val);
973 	if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
974 		warn("SIOCSIFMETRIC");
975 }
976 
977 void
978 setifpreference(const char *val, int d)
979 {
980 	char *end = NULL;
981 	if (setaddr <= 0) {
982 		errx(EXIT_FAILURE,
983 		    "set address preference: first specify an address");
984 	}
985 	preference = strtoul(val, &end, 10);
986 	if (end == NULL || *end != '\0' || preference > UINT16_MAX)
987 		errx(EXIT_FAILURE, "invalid preference %s", val);
988 	have_preference = 1;
989 }
990 
991 void
992 do_setifpreference(void)
993 {
994 	struct if_addrprefreq ifap;
995 	(void)strncpy(ifap.ifap_name, name, sizeof(ifap.ifap_name));
996 	ifap.ifap_preference = (uint16_t)preference;
997 	(void)memcpy(&ifap.ifap_addr, rqtosa(af_addreq),
998 	    MIN(sizeof(ifap.ifap_addr), rqtosa(af_addreq)->sa_len));
999 	if (ioctl(s, SIOCSIFADDRPREF, &ifap) == -1)
1000 		warn("SIOCSIFADDRPREF");
1001 }
1002 
1003 void
1004 setifmtu(const char *val, int d)
1005 {
1006 	char *ep = NULL;
1007 
1008 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1009 	ifr.ifr_mtu = strtoul(val, &ep, 10);
1010 	if (!ep || *ep)
1011 		errx(EXIT_FAILURE, "%s: invalid mtu", val);
1012 	if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
1013 		warn("SIOCSIFMTU");
1014 }
1015 
1016 const char *
1017 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1018 {
1019 	int len;
1020 	int hexstr;
1021 	u_int8_t *p;
1022 
1023 	len = *lenp;
1024 	p = buf;
1025 	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1026 	if (hexstr)
1027 		val += 2;
1028 	for (;;) {
1029 		if (*val == '\0')
1030 			break;
1031 		if (sep != NULL && strchr(sep, *val) != NULL) {
1032 			val++;
1033 			break;
1034 		}
1035 		if (hexstr) {
1036 			if (!isxdigit((u_char)val[0]) ||
1037 			    !isxdigit((u_char)val[1])) {
1038 				warnx("bad hexadecimal digits");
1039 				return NULL;
1040 			}
1041 		}
1042 		if (p > buf + len) {
1043 			if (hexstr)
1044 				warnx("hexadecimal digits too long");
1045 			else
1046 				warnx("strings too long");
1047 			return NULL;
1048 		}
1049 		if (hexstr) {
1050 #define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1051 			*p++ = (tohex((u_char)val[0]) << 4) |
1052 			    tohex((u_char)val[1]);
1053 #undef tohex
1054 			val += 2;
1055 		} else
1056 			*p++ = *val++;
1057 	}
1058 	len = p - buf;
1059 	if (len < *lenp)
1060 		memset(p, 0, *lenp - len);
1061 	*lenp = len;
1062 	return val;
1063 }
1064 
1065 void
1066 print_string(const u_int8_t *buf, int len)
1067 {
1068 	int i;
1069 	int hasspc;
1070 
1071 	i = 0;
1072 	hasspc = 0;
1073 	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1074 		for (; i < len; i++) {
1075 			if (!isprint(buf[i]))
1076 				break;
1077 			if (isspace(buf[i]))
1078 				hasspc++;
1079 		}
1080 	}
1081 	if (i == len) {
1082 		if (hasspc || len == 0)
1083 			printf("\"%.*s\"", len, buf);
1084 		else
1085 			printf("%.*s", len, buf);
1086 	} else {
1087 		printf("0x");
1088 		for (i = 0; i < len; i++)
1089 			printf("%02x", buf[i]);
1090 	}
1091 }
1092 
1093 static void
1094 media_error(int type, const char *val, const char *opt)
1095 {
1096 	errx(EXIT_FAILURE, "unknown %s media %s: %s",
1097 		get_media_type_string(type), opt, val);
1098 }
1099 
1100 void
1101 init_current_media(void)
1102 {
1103 	struct ifmediareq ifmr;
1104 
1105 	/*
1106 	 * If we have not yet done so, grab the currently-selected
1107 	 * media.
1108 	 */
1109 	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1110 		(void) memset(&ifmr, 0, sizeof(ifmr));
1111 		estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1112 
1113 		if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1114 			/*
1115 			 * If we get E2BIG, the kernel is telling us
1116 			 * that there are more, so we can ignore it.
1117 			 */
1118 			if (errno != E2BIG)
1119 				err(EXIT_FAILURE, "SGIOCGIFMEDIA");
1120 		}
1121 
1122 		media_current = ifmr.ifm_current;
1123 	}
1124 
1125 	/* Sanity. */
1126 	if (IFM_TYPE(media_current) == 0)
1127 		errx(EXIT_FAILURE, "%s: no link type?", name);
1128 }
1129 
1130 void
1131 process_media_commands(void)
1132 {
1133 
1134 	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1135 		/* Nothing to do. */
1136 		return;
1137 	}
1138 
1139 	/*
1140 	 * Media already set up, and commands sanity-checked.  Set/clear
1141 	 * any options, and we're ready to go.
1142 	 */
1143 	media_current |= mediaopt_set;
1144 	media_current &= ~mediaopt_clear;
1145 
1146 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1147 	ifr.ifr_media = media_current;
1148 
1149 	if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
1150 		err(EXIT_FAILURE, "SIOCSIFMEDIA");
1151 }
1152 
1153 void
1154 setmedia(const char *val, int d)
1155 {
1156 	int type, subtype, inst;
1157 
1158 	init_current_media();
1159 
1160 	/* Only one media command may be given. */
1161 	if (actions & A_MEDIA)
1162 		errx(EXIT_FAILURE, "only one `media' command may be issued");
1163 
1164 	/* Must not come after mode commands */
1165 	if (actions & A_MEDIAMODE)
1166 		errx(EXIT_FAILURE,
1167 		    "may not issue `media' after `mode' commands");
1168 
1169 	/* Must not come after mediaopt commands */
1170 	if (actions & A_MEDIAOPT)
1171 		errx(EXIT_FAILURE,
1172 		    "may not issue `media' after `mediaopt' commands");
1173 
1174 	/*
1175 	 * No need to check if `instance' has been issued; setmediainst()
1176 	 * craps out if `media' has not been specified.
1177 	 */
1178 
1179 	type = IFM_TYPE(media_current);
1180 	inst = IFM_INST(media_current);
1181 
1182 	/* Look up the subtype. */
1183 	subtype = get_media_subtype(type, val);
1184 	if (subtype == -1)
1185 		media_error(type, val, "subtype");
1186 
1187 	/* Build the new current media word. */
1188 	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1189 
1190 	/* Media will be set after other processing is complete. */
1191 }
1192 
1193 void
1194 setmediaopt(const char *val, int d)
1195 {
1196 	char *invalid;
1197 
1198 	init_current_media();
1199 
1200 	/* Can only issue `mediaopt' once. */
1201 	if (actions & A_MEDIAOPTSET)
1202 		errx(EXIT_FAILURE, "only one `mediaopt' command may be issued");
1203 
1204 	/* Can't issue `mediaopt' if `instance' has already been issued. */
1205 	if (actions & A_MEDIAINST)
1206 		errx(EXIT_FAILURE, "may not issue `mediaopt' after `instance'");
1207 
1208 	mediaopt_set = get_media_options(media_current, val, &invalid);
1209 	if (mediaopt_set == -1)
1210 		media_error(media_current, invalid, "option");
1211 
1212 	/* Media will be set after other processing is complete. */
1213 }
1214 
1215 void
1216 unsetmediaopt(const char *val, int d)
1217 {
1218 	char *invalid;
1219 
1220 	init_current_media();
1221 
1222 	/* Can only issue `-mediaopt' once. */
1223 	if (actions & A_MEDIAOPTCLR)
1224 		errx(EXIT_FAILURE,
1225 		    "only one `-mediaopt' command may be issued");
1226 
1227 	/* May not issue `media' and `-mediaopt'. */
1228 	if (actions & A_MEDIA)
1229 		errx(EXIT_FAILURE,
1230 		    "may not issue both `media' and `-mediaopt'");
1231 
1232 	/*
1233 	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1234 	 * implicitly checks for A_MEDIAINST.
1235 	 */
1236 
1237 	mediaopt_clear = get_media_options(media_current, val, &invalid);
1238 	if (mediaopt_clear == -1)
1239 		media_error(media_current, invalid, "option");
1240 
1241 	/* Media will be set after other processing is complete. */
1242 }
1243 
1244 void
1245 setmediainst(const char *val, int d)
1246 {
1247 	int type, subtype, options, inst;
1248 
1249 	init_current_media();
1250 
1251 	/* Can only issue `instance' once. */
1252 	if (actions & A_MEDIAINST)
1253 		errx(EXIT_FAILURE, "only one `instance' command may be issued");
1254 
1255 	/* Must have already specified `media' */
1256 	if ((actions & A_MEDIA) == 0)
1257 		errx(EXIT_FAILURE, "must specify `media' before `instance'");
1258 
1259 	type = IFM_TYPE(media_current);
1260 	subtype = IFM_SUBTYPE(media_current);
1261 	options = IFM_OPTIONS(media_current);
1262 
1263 	inst = atoi(val);
1264 	if (inst < 0 || inst > IFM_INST_MAX)
1265 		errx(EXIT_FAILURE, "invalid media instance: %s", val);
1266 
1267 	media_current = IFM_MAKEWORD(type, subtype, options, inst);
1268 
1269 	/* Media will be set after other processing is complete. */
1270 }
1271 
1272 void
1273 setmediamode(const char *val, int d)
1274 {
1275 	int type, subtype, options, inst, mode;
1276 
1277 	init_current_media();
1278 
1279 	/* Can only issue `mode' once. */
1280 	if (actions & A_MEDIAMODE)
1281 		errx(EXIT_FAILURE, "only one `mode' command may be issued");
1282 
1283 	type = IFM_TYPE(media_current);
1284 	subtype = IFM_SUBTYPE(media_current);
1285 	options = IFM_OPTIONS(media_current);
1286 	inst = IFM_INST(media_current);
1287 
1288 	mode = get_media_mode(type, val);
1289 	if (mode == -1)
1290 		media_error(type, val, "mode");
1291 
1292 	media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
1293 
1294 	/* Media will be set after other processing is complete. */
1295 }
1296 
1297 void
1298 print_media_word(int ifmw, const char *opt_sep)
1299 {
1300 	const char *str;
1301 
1302 	printf("%s", get_media_subtype_string(ifmw));
1303 
1304 	/* Find mode. */
1305 	if (IFM_MODE(ifmw) != 0) {
1306 		str = get_media_mode_string(ifmw);
1307 		if (str != NULL)
1308 			printf(" mode %s", str);
1309 	}
1310 
1311 	/* Find options. */
1312 	for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",")
1313 		printf("%s%s", opt_sep, str);
1314 
1315 	if (IFM_INST(ifmw) != 0)
1316 		printf(" instance %d", IFM_INST(ifmw));
1317 }
1318 
1319 int
1320 carrier(void)
1321 {
1322 	struct ifmediareq ifmr;
1323 
1324 	(void) memset(&ifmr, 0, sizeof(ifmr));
1325 	estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1326 
1327 	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1328 		/*
1329 		 * Interface doesn't support SIOC{G,S}IFMEDIA;
1330 		 * assume ok.
1331 		 */
1332 		return 0;
1333 	}
1334 	if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1335 		/*
1336 		 * Interface doesn't report media-valid status.
1337 		 * assume ok.
1338 		 */
1339 		return 0;
1340 	}
1341 	/* otherwise, return ok for active, not-ok if not active. */
1342 	return !(ifmr.ifm_status & IFM_ACTIVE);
1343 }
1344 
1345 
1346 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1347 
1348 const struct ifmedia_status_description ifm_status_descriptions[] =
1349     IFM_STATUS_DESCRIPTIONS;
1350 
1351 /*
1352  * Print the status of the interface.  If an address family was
1353  * specified, show it and it only; otherwise, show them all.
1354  */
1355 void
1356 status(const struct sockaddr_dl *sdl)
1357 {
1358 	const struct afswtch *p = afp;
1359 	struct ifmediareq ifmr;
1360 	struct ifdatareq ifdr;
1361 	int *media_list, i;
1362 	char hbuf[NI_MAXHOST];
1363 	char fbuf[BUFSIZ];
1364 
1365 	(void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1366 	printf("%s: flags=%s", name, &fbuf[2]);
1367 	if (metric)
1368 		printf(" metric %lu", metric);
1369 	if (mtu)
1370 		printf(" mtu %lu", mtu);
1371 	printf("\n");
1372 
1373 	if (g_ifcr.ifcr_capabilities) {
1374 		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1375 		    g_ifcr.ifcr_capabilities);
1376 		printf("\tcapabilities=%s\n", &fbuf[2]);
1377 		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1378 		    g_ifcr.ifcr_capenable);
1379 		printf("\tenabled=%s\n", &fbuf[2]);
1380 	}
1381 
1382 	ieee80211_status();
1383 	vlan_status();
1384 #ifndef INET_ONLY
1385 	carp_status();
1386 #endif
1387 	tunnel_status();
1388 	agr_status();
1389 
1390 	if (sdl != NULL &&
1391 	    getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len,
1392 		hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
1393 	    hbuf[0] != '\0')
1394 		printf("\taddress: %s\n", hbuf);
1395 
1396 	(void) memset(&ifmr, 0, sizeof(ifmr));
1397 	estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1398 
1399 	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1400 		/*
1401 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1402 		 */
1403 		goto iface_stats;
1404 	}
1405 
1406 	if (ifmr.ifm_count == 0) {
1407 		warnx("%s: no media types?", name);
1408 		goto iface_stats;
1409 	}
1410 
1411 	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1412 	if (media_list == NULL)
1413 		err(EXIT_FAILURE, "malloc");
1414 	ifmr.ifm_ulist = media_list;
1415 
1416 	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
1417 		err(EXIT_FAILURE, "SIOCGIFMEDIA");
1418 
1419 	printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current));
1420 	print_media_word(ifmr.ifm_current, " ");
1421 	if (ifmr.ifm_active != ifmr.ifm_current) {
1422 		printf(" (");
1423 		print_media_word(ifmr.ifm_active, " ");
1424 		printf(")");
1425 	}
1426 	printf("\n");
1427 
1428 	if (ifmr.ifm_status & IFM_STATUS_VALID) {
1429 		const struct ifmedia_status_description *ifms;
1430 		int bitno, found = 0;
1431 
1432 		printf("\tstatus: ");
1433 		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1434 			for (ifms = ifm_status_descriptions;
1435 			     ifms->ifms_valid != 0; ifms++) {
1436 				if (ifms->ifms_type !=
1437 				      IFM_TYPE(ifmr.ifm_current) ||
1438 				    ifms->ifms_valid !=
1439 				      ifm_status_valid_list[bitno])
1440 					continue;
1441 				printf("%s%s", found ? ", " : "",
1442 				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1443 				found = 1;
1444 
1445 				/*
1446 				 * For each valid indicator bit, there's
1447 				 * only one entry for each media type, so
1448 				 * terminate the inner loop now.
1449 				 */
1450 				break;
1451 			}
1452 		}
1453 
1454 		if (found == 0)
1455 			printf("unknown");
1456 		printf("\n");
1457 	}
1458 
1459 	if (mflag) {
1460 		int type, printed_type;
1461 
1462 		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
1463 			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
1464 				if (IFM_TYPE(media_list[i]) != type)
1465 					continue;
1466 				if (printed_type == 0) {
1467 					printf("\tsupported %s media:\n",
1468 					    get_media_type_string(type));
1469 					printed_type = 1;
1470 				}
1471 				printf("\t\tmedia ");
1472 				print_media_word(media_list[i], " mediaopt ");
1473 				printf("\n");
1474 			}
1475 		}
1476 	}
1477 
1478 	free(media_list);
1479 
1480  iface_stats:
1481 	if (!vflag && !zflag)
1482 		goto proto_status;
1483 
1484 	estrlcpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name));
1485 
1486 	if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1) {
1487 		err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
1488 	} else {
1489 		struct if_data * const ifi = &ifdr.ifdr_data;
1490 		char buf[5];
1491 
1492 #define	PLURAL(n)	((n) == 1 ? "" : "s")
1493 #define PLURALSTR(s)	((atof(s)) == 1.0 ? "" : "s")
1494 		printf("\tinput: %llu packet%s, ",
1495 		    (unsigned long long) ifi->ifi_ipackets,
1496 		    PLURAL(ifi->ifi_ipackets));
1497 		if (hflag) {
1498 			(void) humanize_number(buf, sizeof(buf),
1499 			    (int64_t) ifi->ifi_ibytes, "", HN_AUTOSCALE,
1500 			    HN_NOSPACE | HN_DECIMAL);
1501 			printf("%s byte%s", buf,
1502 			    PLURALSTR(buf));
1503 		} else
1504 			printf("%llu byte%s",
1505 			    (unsigned long long) ifi->ifi_ibytes,
1506 		            PLURAL(ifi->ifi_ibytes));
1507 		if (ifi->ifi_imcasts)
1508 			printf(", %llu multicast%s",
1509 			    (unsigned long long) ifi->ifi_imcasts,
1510 			    PLURAL(ifi->ifi_imcasts));
1511 		if (ifi->ifi_ierrors)
1512 			printf(", %llu error%s",
1513 			    (unsigned long long) ifi->ifi_ierrors,
1514 			    PLURAL(ifi->ifi_ierrors));
1515 		if (ifi->ifi_iqdrops)
1516 			printf(", %llu queue drop%s",
1517 			    (unsigned long long) ifi->ifi_iqdrops,
1518 			    PLURAL(ifi->ifi_iqdrops));
1519 		if (ifi->ifi_noproto)
1520 			printf(", %llu unknown protocol",
1521 			    (unsigned long long) ifi->ifi_noproto);
1522 		printf("\n\toutput: %llu packet%s, ",
1523 		    (unsigned long long) ifi->ifi_opackets,
1524 		    PLURAL(ifi->ifi_opackets));
1525 		if (hflag) {
1526 			(void) humanize_number(buf, sizeof(buf),
1527 			    (int64_t) ifi->ifi_obytes, "", HN_AUTOSCALE,
1528 			    HN_NOSPACE | HN_DECIMAL);
1529 			printf("%s byte%s", buf,
1530 			    PLURALSTR(buf));
1531 		} else
1532 			printf("%llu byte%s",
1533 			    (unsigned long long) ifi->ifi_obytes,
1534 			    PLURAL(ifi->ifi_obytes));
1535 		if (ifi->ifi_omcasts)
1536 			printf(", %llu multicast%s",
1537 			    (unsigned long long) ifi->ifi_omcasts,
1538 			    PLURAL(ifi->ifi_omcasts));
1539 		if (ifi->ifi_oerrors)
1540 			printf(", %llu error%s",
1541 			    (unsigned long long) ifi->ifi_oerrors,
1542 			    PLURAL(ifi->ifi_oerrors));
1543 		if (ifi->ifi_collisions)
1544 			printf(", %llu collision%s",
1545 			    (unsigned long long) ifi->ifi_collisions,
1546 			    PLURAL(ifi->ifi_collisions));
1547 		printf("\n");
1548 #undef PLURAL
1549 #undef PLURALSTR
1550 	}
1551 
1552 	ieee80211_statistics();
1553 
1554  proto_status:
1555 	if ((p = afp) != NULL) {
1556 		(*p->af_status)(1);
1557 	} else for (p = afs; p->af_name; p++) {
1558 		ifr.ifr_addr.sa_family = p->af_af;
1559 		(*p->af_status)(0);
1560 	}
1561 }
1562 
1563 void
1564 setifprefixlen(const char *addr, int d)
1565 {
1566 	if (*afp->af_getprefix)
1567 		(*afp->af_getprefix)(addr, MASK);
1568 	explicit_prefix = 1;
1569 }
1570 
1571 void
1572 usage(void)
1573 {
1574 	const char *progname = getprogname();
1575 
1576 	fprintf(stderr,
1577 	    "usage: %s [-h] [-m] [-v] [-z] "
1578 #ifdef INET6
1579 		"[-L] "
1580 #endif
1581 		"interface\n"
1582 		"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1583 		"\t\t[ alias | -alias ] ]\n"
1584 		"\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
1585 		"\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
1586 		"\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
1587 		"\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n"
1588 		"\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
1589 		"\t[ arp | -arp ]\n"
1590 		"\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
1591 		"[ instance minst ]\n"
1592 		"\t[ preference n ]\n"
1593 		"\t[ vlan n vlanif i ]\n"
1594 		"\t[ agrport i ] [ -agrport i ]\n"
1595 		"\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
1596 		"\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n"
1597 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1598 		"       %s -a [-b] [-h] [-m] [-d] [-u] [-v] [-z] [ af ]\n"
1599 		"       %s -l [-b] [-d] [-u] [-s]\n"
1600 		"       %s -C\n"
1601 		"       %s interface create\n"
1602 		"       %s interface destroy\n",
1603 		progname, progname, progname, progname, progname, progname);
1604 	exit(1);
1605 }
1606