ifconfig.c revision 1.149
1/*	$NetBSD: ifconfig.c,v 1.149 2004/12/20 23:04:55 dyoung 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
77static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
78#else
79__RCSID("$NetBSD: ifconfig.c,v 1.149 2004/12/20 23:04:55 dyoung 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 <net80211/ieee80211.h>
92#include <net80211/ieee80211_ioctl.h>
93#include <net/if_vlanvar.h>
94#include <netinet/in.h>
95#include <netinet/in_var.h>
96#ifdef INET6
97#include <netinet6/nd6.h>
98#endif
99#include <arpa/inet.h>
100
101#include <netatalk/at.h>
102
103#define	NSIP
104#include <netns/ns.h>
105#include <netns/ns_if.h>
106#include <netdb.h>
107
108#define EON
109#include <netiso/iso.h>
110#include <netiso/iso_var.h>
111#include <sys/protosw.h>
112
113#include <ctype.h>
114#include <err.h>
115#include <errno.h>
116#include <stddef.h>
117#include <stdio.h>
118#include <stdlib.h>
119#include <string.h>
120#include <unistd.h>
121#include <ifaddrs.h>
122#include <util.h>
123
124struct	ifreq		ifr, ridreq;
125struct	ifaliasreq	addreq __attribute__((aligned(4)));
126struct	in_aliasreq	in_addreq;
127#ifdef INET6
128struct	in6_ifreq	ifr6;
129struct	in6_ifreq	in6_ridreq;
130struct	in6_aliasreq	in6_addreq;
131#endif
132struct	iso_ifreq	iso_ridreq;
133struct	iso_aliasreq	iso_addreq;
134struct	sockaddr_in	netmask;
135struct	netrange	at_nr;		/* AppleTalk net range */
136
137char	name[30];
138u_short	flags;
139int	setaddr, setipdst, doalias;
140u_long	metric, mtu;
141int	clearaddr, s;
142int	newaddr = -1;
143int	conflicting = 0;
144int	nsellength = 1;
145int	af;
146int	aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag, vflag, zflag;
147#ifdef INET6
148int	Lflag;
149#endif
150int	explicit_prefix = 0;
151u_int	vlan_tag = (u_int)-1;
152
153struct ifcapreq g_ifcr;
154int	g_ifcr_updated;
155
156void 	notealias(const char *, int);
157void 	notrailers(const char *, int);
158void 	setifaddr(const char *, int);
159void 	setifdstaddr(const char *, int);
160void 	setifflags(const char *, int);
161void	setifcaps(const char *, int);
162void 	setifbroadaddr(const char *, int);
163void 	setifipdst(const char *, int);
164void 	setifmetric(const char *, int);
165void 	setifmtu(const char *, int);
166void	setifnwid(const char *, int);
167void	setifnwkey(const char *, int);
168void	setifbssid(const char *, int);
169void	setifchan(const char *, int);
170void	setifpowersave(const char *, int);
171void	setifpowersavesleep(const char *, int);
172void 	setifnetmask(const char *, int);
173void	setifprefixlen(const char *, int);
174void 	setnsellength(const char *, int);
175void 	setsnpaoffset(const char *, int);
176void	setatrange(const char *, int);
177void	setatphase(const char *, int);
178void	settunnel(const char *, const char *);
179void	deletetunnel(const char *, int);
180#ifdef INET6
181void 	setia6flags(const char *, int);
182void	setia6pltime(const char *, int);
183void	setia6vltime(const char *, int);
184void	setia6lifetime(const char *, const char *);
185void	setia6eui64(const char *, int);
186#endif
187void	checkatrange(struct sockaddr_at *);
188void	setmedia(const char *, int);
189void	setmediamode(const char *, int);
190void	setmediaopt(const char *, int);
191void	unsetmediaopt(const char *, int);
192void	setmediainst(const char *, int);
193void	clone_create(const char *, int);
194void	clone_destroy(const char *, int);
195void	fixnsel(struct sockaddr_iso *);
196void	setvlan(const char *, int);
197void	setvlanif(const char *, int);
198void	unsetvlanif(const char *, int);
199int	main(int, char *[]);
200
201/*
202 * Media stuff.  Whenever a media command is first performed, the
203 * currently select media is grabbed for this interface.  If `media'
204 * is given, the current media word is modifed.  `mediaopt' commands
205 * only modify the set and clear words.  They then operate on the
206 * current media word later.
207 */
208int	media_current;
209int	mediaopt_set;
210int	mediaopt_clear;
211
212int	actions;			/* Actions performed */
213
214#define	A_MEDIA		0x0001		/* media command */
215#define	A_MEDIAOPTSET	0x0002		/* mediaopt command */
216#define	A_MEDIAOPTCLR	0x0004		/* -mediaopt command */
217#define	A_MEDIAOPT	(A_MEDIAOPTSET|A_MEDIAOPTCLR)
218#define	A_MEDIAINST	0x0008		/* instance or inst command */
219#define	A_MEDIAMODE	0x0010		/* mode command */
220
221#define	NEXTARG		0xffffff
222#define	NEXTARG2	0xfffffe
223
224const struct cmd {
225	const char *c_name;
226	int	c_parameter;	/* NEXTARG means next argv */
227	int	c_action;	/* defered action */
228	void	(*c_func)(const char *, int);
229	void	(*c_func2)(const char *, const char *);
230} cmds[] = {
231	{ "up",		IFF_UP,		0,		setifflags } ,
232	{ "down",	-IFF_UP,	0,		setifflags },
233	{ "trailers",	-1,		0,		notrailers },
234	{ "-trailers",	1,		0,		notrailers },
235	{ "arp",	-IFF_NOARP,	0,		setifflags },
236	{ "-arp",	IFF_NOARP,	0,		setifflags },
237	{ "debug",	IFF_DEBUG,	0,		setifflags },
238	{ "-debug",	-IFF_DEBUG,	0,		setifflags },
239	{ "alias",	IFF_UP,		0,		notealias },
240	{ "-alias",	-IFF_UP,	0,		notealias },
241	{ "delete",	-IFF_UP,	0,		notealias },
242#ifdef notdef
243#define	EN_SWABIPS	0x1000
244	{ "swabips",	EN_SWABIPS,	0,		setifflags },
245	{ "-swabips",	-EN_SWABIPS,	0,		setifflags },
246#endif
247	{ "netmask",	NEXTARG,	0,		setifnetmask },
248	{ "metric",	NEXTARG,	0,		setifmetric },
249	{ "mtu",	NEXTARG,	0,		setifmtu },
250	{ "bssid",	NEXTARG,	0,		setifbssid },
251	{ "-bssid",	-1,		0,		setifbssid },
252	{ "chan",	NEXTARG,	0,		setifchan },
253	{ "-chan",	-1,		0,		setifchan },
254	{ "ssid",	NEXTARG,	0,		setifnwid },
255	{ "nwid",	NEXTARG,	0,		setifnwid },
256	{ "nwkey",	NEXTARG,	0,		setifnwkey },
257	{ "-nwkey",	-1,		0,		setifnwkey },
258	{ "powersave",	1,		0,		setifpowersave },
259	{ "-powersave",	0,		0,		setifpowersave },
260	{ "powersavesleep", NEXTARG,	0,		setifpowersavesleep },
261	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
262	{ "ipdst",	NEXTARG,	0,		setifipdst },
263	{ "prefixlen",	NEXTARG,	0,		setifprefixlen},
264#ifdef INET6
265	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
266	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
267	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
268	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
269	{ "deprecated",	IN6_IFF_DEPRECATED,	0,	setia6flags },
270	{ "-deprecated", -IN6_IFF_DEPRECATED,	0,	setia6flags },
271	{ "pltime",	NEXTARG,	0,		setia6pltime },
272	{ "vltime",	NEXTARG,	0,		setia6vltime },
273	{ "eui64",	0,		0,		setia6eui64 },
274#endif /*INET6*/
275#ifndef INET_ONLY
276	{ "range",	NEXTARG,	0,		setatrange },
277	{ "phase",	NEXTARG,	0,		setatphase },
278	{ "snpaoffset",	NEXTARG,	0,		setsnpaoffset },
279	{ "nsellength",	NEXTARG,	0,		setnsellength },
280#endif	/* INET_ONLY */
281	{ "tunnel",	NEXTARG2,	0,		NULL,
282							settunnel } ,
283	{ "deletetunnel", 0,		0,		deletetunnel },
284	{ "vlan",	NEXTARG,	0,		setvlan } ,
285	{ "vlanif",	NEXTARG,	0,		setvlanif } ,
286	{ "-vlanif",	0,		0,		unsetvlanif } ,
287#if 0
288	/* XXX `create' special-cased below */
289	{ "create",	0,		0,		clone_create } ,
290#endif
291	{ "destroy",	0,		0,		clone_destroy } ,
292	{ "link0",	IFF_LINK0,	0,		setifflags } ,
293	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
294	{ "link1",	IFF_LINK1,	0,		setifflags } ,
295	{ "-link1",	-IFF_LINK1,	0,		setifflags } ,
296	{ "link2",	IFF_LINK2,	0,		setifflags } ,
297	{ "-link2",	-IFF_LINK2,	0,		setifflags } ,
298	{ "media",	NEXTARG,	A_MEDIA,	setmedia },
299	{ "mediaopt",	NEXTARG,	A_MEDIAOPTSET,	setmediaopt },
300	{ "-mediaopt",	NEXTARG,	A_MEDIAOPTCLR,	unsetmediaopt },
301	{ "mode",	NEXTARG,	A_MEDIAMODE,	setmediamode },
302	{ "instance",	NEXTARG,	A_MEDIAINST,	setmediainst },
303	{ "inst",	NEXTARG,	A_MEDIAINST,	setmediainst },
304	{ "ip4csum",	IFCAP_CSUM_IPv4,0,		setifcaps },
305	{ "-ip4csum",	-IFCAP_CSUM_IPv4,0,		setifcaps },
306	{ "tcp4csum",	IFCAP_CSUM_TCPv4,0,		setifcaps },
307	{ "-tcp4csum",	-IFCAP_CSUM_TCPv4,0,		setifcaps },
308	{ "udp4csum",	IFCAP_CSUM_UDPv4,0,		setifcaps },
309	{ "-udp4csum",	-IFCAP_CSUM_UDPv4,0,		setifcaps },
310	{ "tcp6csum",	IFCAP_CSUM_TCPv6,0,		setifcaps },
311	{ "-tcp6csum",	-IFCAP_CSUM_TCPv6,0,		setifcaps },
312	{ "udp6csum",	IFCAP_CSUM_UDPv6,0,		setifcaps },
313	{ "-udp6csum",	-IFCAP_CSUM_UDPv6,0,		setifcaps },
314	{ "tcp4csum-rx",IFCAP_CSUM_TCPv4_Rx,0,		setifcaps },
315	{ "-tcp4csum-rx",-IFCAP_CSUM_TCPv4_Rx,0,	setifcaps },
316	{ "udp4csum-rx",IFCAP_CSUM_UDPv4_Rx,0,		setifcaps },
317	{ "-udp4csum-rx",-IFCAP_CSUM_UDPv4_Rx,0,	setifcaps },
318	{ 0,		0,		0,		setifaddr },
319	{ 0,		0,		0,		setifdstaddr },
320};
321
322void 	adjust_nsellength(void);
323int	getinfo(struct ifreq *);
324int	carrier(void);
325void	getsock(int);
326void	printall(const char *);
327void	list_cloners(void);
328int	prefix(void *, int);
329void 	status(const struct sockaddr_dl *);
330void 	usage(void);
331const char *get_string(const char *, const char *, u_int8_t *, int *);
332void	print_string(const u_int8_t *, int);
333char	*sec2str(time_t);
334
335void	print_media_word(int, const char *);
336void	process_media_commands(void);
337void	init_current_media(void);
338
339/*
340 * XNS support liberally adapted from code written at the University of
341 * Maryland principally by James O'Toole and Chris Torek.
342 */
343void	in_alias(struct ifreq *);
344void	in_status(int);
345void 	in_getaddr(const char *, int);
346void 	in_getprefix(const char *, int);
347#ifdef INET6
348void	in6_fillscopeid(struct sockaddr_in6 *sin6);
349void	in6_alias(struct in6_ifreq *);
350void	in6_status(int);
351void 	in6_getaddr(const char *, int);
352void 	in6_getprefix(const char *, int);
353#endif
354void	at_status(int);
355void	at_getaddr(const char *, int);
356void 	xns_status(int);
357void 	xns_getaddr(const char *, int);
358void 	iso_status(int);
359void 	iso_getaddr(const char *, int);
360
361void	ieee80211_statistics(void);
362void	ieee80211_status(void);
363void	tunnel_status(void);
364void	vlan_status(void);
365
366/* Known address families */
367struct afswtch {
368	const char *af_name;
369	short af_af;
370	void (*af_status)(int);
371	void (*af_getaddr)(const char *, int);
372	void (*af_getprefix)(const char *, int);
373	u_long af_difaddr;
374	u_long af_aifaddr;
375	u_long af_gifaddr;
376	void *af_ridreq;
377	void *af_addreq;
378} afs[] = {
379	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
380	     SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &in_addreq },
381#ifdef INET6
382	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
383	     SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
384	     /*
385	      * Deleting the first address before setting new one is
386	      * not prefered way in this protocol.
387	      */
388	     0,
389	     &in6_ridreq, &in6_addreq },
390#endif
391#ifndef INET_ONLY	/* small version, for boot media */
392	{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
393	     SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &addreq, &addreq },
394	{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
395	     SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &addreq },
396	{ "iso", AF_ISO, iso_status, iso_getaddr, NULL,
397	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
398	     &iso_ridreq, &iso_addreq },
399#endif	/* INET_ONLY */
400	{ 0,	0,	    0,		0 }
401};
402
403struct afswtch *afp;	/*the address family being set or asked about*/
404
405struct afswtch *lookup_af(const char *);
406
407int
408main(int argc, char *argv[])
409{
410	int ch;
411
412	/* Parse command-line options */
413	aflag = mflag = vflag = zflag = 0;
414	while ((ch = getopt(argc, argv, "AabCdlmsuvz"
415#ifdef INET6
416					"L"
417#endif
418			)) != -1) {
419		switch (ch) {
420		case 'A':
421			warnx("-A is deprecated");
422			break;
423
424		case 'a':
425			aflag = 1;
426			break;
427
428		case 'b':
429			bflag = 1;
430			break;
431
432		case 'C':
433			Cflag = 1;
434			break;
435
436		case 'd':
437			dflag = 1;
438			break;
439
440#ifdef INET6
441		case 'L':
442			Lflag = 1;
443			break;
444#endif
445
446		case 'l':
447			lflag = 1;
448			break;
449
450		case 'm':
451			mflag = 1;
452			break;
453
454		case 's':
455			sflag = 1;
456			break;
457
458		case 'u':
459			uflag = 1;
460			break;
461
462		case 'v':
463			vflag = 1;
464			break;
465
466		case 'z':
467			zflag = 1;
468			break;
469
470
471		default:
472			usage();
473			/* NOTREACHED */
474		}
475	}
476	argc -= optind;
477	argv += optind;
478
479	/*
480	 * -l means "list all interfaces", and is mutally exclusive with
481	 * all other flags/commands.
482	 *
483	 * -C means "list all names of cloners", and it mutually exclusive
484	 * with all other flags/commands.
485	 *
486	 * -a means "print status of all interfaces".
487	 */
488	if ((lflag || Cflag) && (aflag || mflag || vflag || argc || zflag))
489		usage();
490#ifdef INET6
491	if ((lflag || Cflag) && Lflag)
492		usage();
493#endif
494	if (lflag && Cflag)
495		usage();
496	if (Cflag) {
497		if (argc)
498			usage();
499		list_cloners();
500		exit(0);
501	}
502	if (aflag || lflag) {
503		if (argc > 1)
504			usage();
505		else if (argc == 1) {
506			afp = lookup_af(argv[0]);
507			if (afp == NULL)
508				usage();
509		}
510		if (afp)
511			af = ifr.ifr_addr.sa_family = afp->af_af;
512		else
513			af = ifr.ifr_addr.sa_family = afs[0].af_af;
514		printall(NULL);
515		exit(0);
516	}
517
518	/* Make sure there's an interface name. */
519	if (argc < 1)
520		usage();
521	if (strlcpy(name, argv[0], sizeof(name)) >= sizeof(name))
522		errx(1, "interface name '%s' too long", argv[0]);
523	argc--; argv++;
524
525	/*
526	 * NOTE:  We must special-case the `create' command right
527	 * here as we would otherwise fail in getinfo().
528	 */
529	if (argc > 0 && strcmp(argv[0], "create") == 0) {
530		clone_create(argv[0], 0);
531		argc--, argv++;
532		if (argc == 0)
533			exit(0);
534	}
535
536	/* Check for address family. */
537	afp = NULL;
538	if (argc > 0) {
539		afp = lookup_af(argv[0]);
540		if (afp != NULL) {
541			argv++;
542			argc--;
543		}
544	}
545
546	/* Initialize af, just for use in getinfo(). */
547	if (afp == NULL)
548		af = afs->af_af;
549	else
550		af = afp->af_af;
551
552	/* Get information about the interface. */
553	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
554	if (getinfo(&ifr) < 0)
555		exit(1);
556
557	if (sflag) {
558		if (argc != 0)
559			usage();
560		else
561			exit(carrier());
562	}
563
564	/* No more arguments means interface status. */
565	if (argc == 0) {
566		printall(name);
567		exit(0);
568	}
569
570	/* The following operations assume inet family as the default. */
571	if (afp == NULL)
572		afp = afs;
573	af = ifr.ifr_addr.sa_family = afp->af_af;
574
575#ifdef INET6
576	/* initialization */
577	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
578	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
579#endif
580
581	/* Process commands. */
582	while (argc > 0) {
583		const struct cmd *p;
584
585		for (p = cmds; p->c_name; p++)
586			if (strcmp(argv[0], p->c_name) == 0)
587				break;
588		if (p->c_name == 0 && setaddr) {
589			if ((flags & IFF_POINTOPOINT) == 0) {
590				errx(EXIT_FAILURE,
591				    "can't set destination address %s",
592				     "on non-point-to-point link");
593			}
594			p++;	/* got src, do dst */
595		}
596		if (p->c_func != NULL || p->c_func2 != NULL) {
597			if (p->c_parameter == NEXTARG) {
598				if (argc < 2)
599					errx(EXIT_FAILURE,
600					    "'%s' requires argument",
601					    p->c_name);
602				(*p->c_func)(argv[1], 0);
603				argc--, argv++;
604			} else if (p->c_parameter == NEXTARG2) {
605				if (argc < 3)
606					errx(EXIT_FAILURE,
607					    "'%s' requires 2 arguments",
608					    p->c_name);
609				(*p->c_func2)(argv[1], argv[2]);
610				argc -= 2, argv += 2;
611			} else
612				(*p->c_func)(argv[0], p->c_parameter);
613			actions |= p->c_action;
614		}
615		argc--, argv++;
616	}
617
618	/*
619	 * See if multiple alias, -alias, or delete commands were
620	 * specified. More than one constitutes an invalid command line
621	 */
622
623	if (conflicting > 1)
624		errx(EXIT_FAILURE,
625		    "Only one use of alias, -alias or delete is valid.");
626
627	/* Process any media commands that may have been issued. */
628	process_media_commands();
629
630	if (af == AF_INET6 && explicit_prefix == 0) {
631		/*
632		 * Aggregatable address architecture defines all prefixes
633		 * are 64. So, it is convenient to set prefixlen to 64 if
634		 * it is not specified.
635		 */
636		setifprefixlen("64", 0);
637		/* in6_getprefix("64", MASK) if MASK is available here... */
638	}
639
640#ifndef INET_ONLY
641	if (af == AF_ISO)
642		adjust_nsellength();
643
644	if (af == AF_APPLETALK)
645		checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
646
647	if (setipdst && af==AF_NS) {
648		struct nsip_req rq;
649		int size = sizeof(rq);
650
651		rq.rq_ns = addreq.ifra_addr;
652		rq.rq_ip = addreq.ifra_dstaddr;
653
654		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
655			warn("encapsulation routing");
656	}
657
658#endif	/* INET_ONLY */
659
660	if (clearaddr) {
661		(void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
662		if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1)
663			err(EXIT_FAILURE, "SIOCDIFADDR");
664	}
665	if (newaddr > 0) {
666		(void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
667		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1)
668			warn("SIOCAIFADDR");
669	}
670
671	if (g_ifcr_updated) {
672		(void) strncpy(g_ifcr.ifcr_name, name,
673		    sizeof(g_ifcr.ifcr_name));
674		if (ioctl(s, SIOCSIFCAP, &g_ifcr) == -1)
675			err(EXIT_FAILURE, "SIOCSIFCAP");
676	}
677
678	exit(0);
679}
680
681struct afswtch *
682lookup_af(const char *cp)
683{
684	struct afswtch *a;
685
686	for (a = afs; a->af_name != NULL; a++)
687		if (strcmp(a->af_name, cp) == 0)
688			return (a);
689	return (NULL);
690}
691
692void
693getsock(int naf)
694{
695	static int oaf = -1;
696
697	if (oaf == naf)
698		return;
699	if (oaf != -1)
700		close(s);
701	s = socket(naf, SOCK_DGRAM, 0);
702	if (s < 0)
703		oaf = -1;
704	else
705		oaf = naf;
706}
707
708int
709getinfo(struct ifreq *giifr)
710{
711
712	getsock(af);
713	if (s < 0)
714		err(EXIT_FAILURE, "socket");
715	if (ioctl(s, SIOCGIFFLAGS, giifr) == -1) {
716		warn("SIOCGIFFLAGS %s", giifr->ifr_name);
717		return (-1);
718	}
719	flags = giifr->ifr_flags;
720	if (ioctl(s, SIOCGIFMETRIC, giifr) == -1) {
721		warn("SIOCGIFMETRIC %s", giifr->ifr_name);
722		metric = 0;
723	} else
724		metric = giifr->ifr_metric;
725	if (ioctl(s, SIOCGIFMTU, giifr) == -1)
726		mtu = 0;
727	else
728		mtu = giifr->ifr_mtu;
729
730	memset(&g_ifcr, 0, sizeof(g_ifcr));
731	strcpy(g_ifcr.ifcr_name, giifr->ifr_name);
732	(void) ioctl(s, SIOCGIFCAP, &g_ifcr);
733
734	return (0);
735}
736
737void
738printall(const char *ifname)
739{
740	struct ifaddrs *ifap, *ifa;
741	struct ifreq paifr;
742	const struct sockaddr_dl *sdl = NULL;
743	int idx;
744	char *p;
745
746	if (getifaddrs(&ifap) != 0)
747		err(EXIT_FAILURE, "getifaddrs");
748	p = NULL;
749	idx = 0;
750	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
751		memset(&paifr, 0, sizeof(paifr));
752		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
753		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
754			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
755			    ifa->ifa_addr->sa_len);
756		}
757
758		if (ifname && strcmp(ifname, ifa->ifa_name) != 0)
759			continue;
760		if (ifa->ifa_addr->sa_family == AF_LINK)
761			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
762		if (p && strcmp(p, ifa->ifa_name) == 0)
763			continue;
764		if (strlcpy(name, ifa->ifa_name, sizeof(name)) >= sizeof(name))
765			continue;
766		p = ifa->ifa_name;
767
768		if (getinfo(&paifr) < 0)
769			continue;
770		if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
771			continue;
772		if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
773			continue;
774		if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
775			continue;
776
777		if (sflag && carrier())
778			continue;
779		idx++;
780		/*
781		 * Are we just listing the interfaces?
782		 */
783		if (lflag) {
784			if (idx > 1)
785				printf(" ");
786			fputs(name, stdout);
787			continue;
788		}
789
790		status(sdl);
791		sdl = NULL;
792	}
793	if (lflag)
794		printf("\n");
795	freeifaddrs(ifap);
796}
797
798void
799list_cloners(void)
800{
801	struct if_clonereq ifcr;
802	char *cp, *buf;
803	int idx;
804
805	memset(&ifcr, 0, sizeof(ifcr));
806
807	getsock(AF_INET);
808
809	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
810		err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
811
812	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
813	if (buf == NULL)
814		err(EXIT_FAILURE, "unable to allocate cloner name buffer");
815
816	ifcr.ifcr_count = ifcr.ifcr_total;
817	ifcr.ifcr_buffer = buf;
818
819	if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
820		err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
821
822	/*
823	 * In case some disappeared in the mean time, clamp it down.
824	 */
825	if (ifcr.ifcr_count > ifcr.ifcr_total)
826		ifcr.ifcr_count = ifcr.ifcr_total;
827
828	for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
829		if (idx > 0)
830			printf(" ");
831		printf("%s", cp);
832	}
833
834	printf("\n");
835	free(buf);
836	return;
837}
838
839/*ARGSUSED*/
840void
841clone_create(const char *addr, int param)
842{
843
844	/* We're called early... */
845	getsock(AF_INET);
846
847	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
848	if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
849		err(EXIT_FAILURE, "SIOCIFCREATE");
850}
851
852/*ARGSUSED*/
853void
854clone_destroy(const char *addr, int param)
855{
856
857	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
858	if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
859		err(EXIT_FAILURE, "SIOCIFDESTROY");
860}
861
862#define RIDADDR 0
863#define ADDR	1
864#define MASK	2
865#define DSTADDR	3
866
867/*ARGSUSED*/
868void
869setifaddr(const char *addr, int param)
870{
871	struct ifreq *siifr;		/* XXX */
872
873	/*
874	 * Delay the ioctl to set the interface addr until flags are all set.
875	 * The address interpretation may depend on the flags,
876	 * and the flags may change when the address is set.
877	 */
878	setaddr++;
879	if (newaddr == -1)
880		newaddr = 1;
881	if (doalias == 0 && afp->af_gifaddr != 0) {
882		siifr = (struct ifreq *)afp->af_ridreq;
883		(void) strncpy(siifr->ifr_name, name, sizeof(siifr->ifr_name));
884		siifr->ifr_addr.sa_family = afp->af_af;
885		if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
886			clearaddr = 1;
887		else if (errno == EADDRNOTAVAIL)
888			/* No address was assigned yet. */
889			;
890		else
891			err(EXIT_FAILURE, "SIOCGIFADDR");
892	}
893
894	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
895}
896
897void
898settunnel(const char *src, const char *dst)
899{
900	struct addrinfo hints, *srcres, *dstres;
901	int ecode;
902	struct if_laddrreq req;
903
904	memset(&hints, 0, sizeof(hints));
905	hints.ai_family = afp->af_af;
906	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
907
908	if ((ecode = getaddrinfo(src, NULL, &hints, &srcres)) != 0)
909		errx(EXIT_FAILURE, "error in parsing address string: %s",
910		    gai_strerror(ecode));
911
912	if ((ecode = getaddrinfo(dst, NULL, &hints, &dstres)) != 0)
913		errx(EXIT_FAILURE, "error in parsing address string: %s",
914		    gai_strerror(ecode));
915
916	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
917		errx(EXIT_FAILURE,
918		    "source and destination address families do not match");
919
920	if (srcres->ai_addrlen > sizeof(req.addr) ||
921	    dstres->ai_addrlen > sizeof(req.dstaddr))
922		errx(EXIT_FAILURE, "invalid sockaddr");
923
924	memset(&req, 0, sizeof(req));
925	strncpy(req.iflr_name, name, sizeof(req.iflr_name));
926	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
927	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
928
929#ifdef INET6
930	if (req.addr.ss_family == AF_INET6) {
931		struct sockaddr_in6 *s6, *d;
932
933		s6 = (struct sockaddr_in6 *)&req.addr;
934		d = (struct sockaddr_in6 *)&req.dstaddr;
935		if (s6->sin6_scope_id != d->sin6_scope_id) {
936			errx(EXIT_FAILURE, "scope mismatch");
937			/* NOTREACHED */
938		}
939#ifdef __KAME__
940		/* embed scopeid */
941		if (s6->sin6_scope_id &&
942		    (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) ||
943		     IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))) {
944			*(u_int16_t *)&s6->sin6_addr.s6_addr[2] =
945			    htons(s6->sin6_scope_id);
946		}
947		if (d->sin6_scope_id &&
948		    (IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr) ||
949		     IN6_IS_ADDR_MC_LINKLOCAL(&d->sin6_addr))) {
950			*(u_int16_t *)&d->sin6_addr.s6_addr[2] =
951			    htons(d->sin6_scope_id);
952		}
953#endif
954	}
955#endif
956
957	if (ioctl(s, SIOCSLIFPHYADDR, &req) == -1)
958		warn("SIOCSLIFPHYADDR");
959
960	freeaddrinfo(srcres);
961	freeaddrinfo(dstres);
962}
963
964/* ARGSUSED */
965void
966deletetunnel(const char *vname, int param)
967{
968
969	if (ioctl(s, SIOCDIFPHYADDR, &ifr) == -1)
970		err(EXIT_FAILURE, "SIOCDIFPHYADDR");
971}
972
973void
974setvlan(const char *val, int d)
975{
976	struct vlanreq vlr;
977
978	if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
979	    !isdigit((unsigned char)ifr.ifr_name[4]))
980		errx(EXIT_FAILURE,
981		    "``vlan'' valid only with vlan(4) interfaces");
982
983	vlan_tag = atoi(val);
984
985	memset(&vlr, 0, sizeof(vlr));
986	ifr.ifr_data = (void *)&vlr;
987
988	if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
989		err(EXIT_FAILURE, "SIOCGETVLAN");
990
991	vlr.vlr_tag = vlan_tag;
992
993	if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
994		err(EXIT_FAILURE, "SIOCSETVLAN");
995}
996
997void
998setvlanif(const char *val, int d)
999{
1000	struct vlanreq vlr;
1001
1002	if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
1003	    !isdigit((unsigned char)ifr.ifr_name[4]))
1004		errx(EXIT_FAILURE,
1005		    "``vlanif'' valid only with vlan(4) interfaces");
1006
1007	if (vlan_tag == (u_int)-1)
1008		errx(EXIT_FAILURE,
1009		    "must specify both ``vlan'' and ``vlanif''");
1010
1011	memset(&vlr, 0, sizeof(vlr));
1012	ifr.ifr_data = (void *)&vlr;
1013
1014	if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
1015		err(EXIT_FAILURE, "SIOCGETVLAN");
1016
1017	strlcpy(vlr.vlr_parent, val, sizeof(vlr.vlr_parent));
1018	vlr.vlr_tag = vlan_tag;
1019
1020	if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
1021		err(EXIT_FAILURE, "SIOCSETVLAN");
1022}
1023
1024void
1025unsetvlanif(const char *val, int d)
1026{
1027	struct vlanreq vlr;
1028
1029	if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
1030	    !isdigit((unsigned char)ifr.ifr_name[4]))
1031		errx(EXIT_FAILURE,
1032		    "``vlanif'' valid only with vlan(4) interfaces");
1033
1034	memset(&vlr, 0, sizeof(vlr));
1035	ifr.ifr_data = (void *)&vlr;
1036
1037	if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
1038		err(EXIT_FAILURE, "SIOCGETVLAN");
1039
1040	vlr.vlr_parent[0] = '\0';
1041	vlr.vlr_tag = 0;
1042
1043	if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
1044		err(EXIT_FAILURE, "SIOCSETVLAN");
1045}
1046
1047void
1048setifnetmask(const char *addr, int d)
1049{
1050	(*afp->af_getaddr)(addr, MASK);
1051}
1052
1053void
1054setifbroadaddr(const char *addr, int d)
1055{
1056	(*afp->af_getaddr)(addr, DSTADDR);
1057}
1058
1059void
1060setifipdst(const char *addr, int d)
1061{
1062	in_getaddr(addr, DSTADDR);
1063	setipdst++;
1064	clearaddr = 0;
1065	newaddr = 0;
1066}
1067
1068#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1069/*ARGSUSED*/
1070void
1071notealias(const char *addr, int param)
1072{
1073	if (setaddr && doalias == 0 && param < 0)
1074		(void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1075		    rqtosa(af_addreq)->sa_len);
1076	doalias = param;
1077	if (param < 0) {
1078		clearaddr = 1;
1079		newaddr = 0;
1080		conflicting++;
1081	} else {
1082		clearaddr = 0;
1083		conflicting++;
1084	}
1085}
1086
1087/*ARGSUSED*/
1088void
1089notrailers(const char *vname, int value)
1090{
1091	puts("Note: trailers are no longer sent, but always received");
1092}
1093
1094/*ARGSUSED*/
1095void
1096setifdstaddr(const char *addr, int param)
1097{
1098	(*afp->af_getaddr)(addr, DSTADDR);
1099}
1100
1101void
1102setifflags(const char *vname, int value)
1103{
1104	struct ifreq ifreq;
1105
1106	(void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
1107 	if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
1108		err(EXIT_FAILURE, "SIOCGIFFLAGS");
1109 	flags = ifreq.ifr_flags;
1110
1111	if (value < 0) {
1112		value = -value;
1113		flags &= ~value;
1114	} else
1115		flags |= value;
1116	ifreq.ifr_flags = flags;
1117	if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
1118		err(EXIT_FAILURE, "SIOCSIFFLAGS");
1119}
1120
1121void
1122setifcaps(const char *vname, int value)
1123{
1124
1125	if (value < 0) {
1126		value = -value;
1127		g_ifcr.ifcr_capenable &= ~value;
1128	} else
1129		g_ifcr.ifcr_capenable |= value;
1130
1131	g_ifcr_updated = 1;
1132}
1133
1134#ifdef INET6
1135void
1136setia6flags(const char *vname, int value)
1137{
1138
1139	if (value < 0) {
1140		value = -value;
1141		in6_addreq.ifra_flags &= ~value;
1142	} else
1143		in6_addreq.ifra_flags |= value;
1144}
1145
1146void
1147setia6pltime(const char *val, int d)
1148{
1149
1150	setia6lifetime("pltime", val);
1151}
1152
1153void
1154setia6vltime(const char *val, int d)
1155{
1156
1157	setia6lifetime("vltime", val);
1158}
1159
1160void
1161setia6lifetime(const char *cmd, const char *val)
1162{
1163	time_t newval, t;
1164	char *ep;
1165
1166	t = time(NULL);
1167	newval = (time_t)strtoul(val, &ep, 0);
1168	if (val == ep)
1169		errx(EXIT_FAILURE, "invalid %s", cmd);
1170	if (afp->af_af != AF_INET6)
1171		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
1172	if (strcmp(cmd, "vltime") == 0) {
1173		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1174		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1175	} else if (strcmp(cmd, "pltime") == 0) {
1176		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1177		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1178	}
1179}
1180
1181void
1182setia6eui64(const char *cmd, int val)
1183{
1184	struct ifaddrs *ifap, *ifa;
1185	const struct sockaddr_in6 *sin6 = NULL;
1186	const struct in6_addr *lladdr = NULL;
1187	struct in6_addr *in6;
1188
1189	if (afp->af_af != AF_INET6)
1190		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
1191 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1192	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1193		errx(EXIT_FAILURE, "interface index is already filled");
1194	if (getifaddrs(&ifap) != 0)
1195		err(EXIT_FAILURE, "getifaddrs");
1196	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1197		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1198		    strcmp(ifa->ifa_name, name) == 0) {
1199			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1200			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1201				lladdr = &sin6->sin6_addr;
1202				break;
1203			}
1204		}
1205	}
1206	if (!lladdr)
1207		errx(EXIT_FAILURE, "could not determine link local address");
1208
1209 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1210
1211	freeifaddrs(ifap);
1212}
1213#endif
1214
1215void
1216setifmetric(const char *val, int d)
1217{
1218	char *ep = NULL;
1219
1220	(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1221	ifr.ifr_metric = strtoul(val, &ep, 10);
1222	if (!ep || *ep)
1223		errx(EXIT_FAILURE, "%s: invalid metric", val);
1224	if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
1225		warn("SIOCSIFMETRIC");
1226}
1227
1228void
1229setifmtu(const char *val, int d)
1230{
1231	char *ep = NULL;
1232
1233	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1234	ifr.ifr_mtu = strtoul(val, &ep, 10);
1235	if (!ep || *ep)
1236		errx(EXIT_FAILURE, "%s: invalid mtu", val);
1237	if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
1238		warn("SIOCSIFMTU");
1239}
1240
1241const char *
1242get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1243{
1244	int len;
1245	int hexstr;
1246	u_int8_t *p;
1247
1248	len = *lenp;
1249	p = buf;
1250	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1251	if (hexstr)
1252		val += 2;
1253	for (;;) {
1254		if (*val == '\0')
1255			break;
1256		if (sep != NULL && strchr(sep, *val) != NULL) {
1257			val++;
1258			break;
1259		}
1260		if (hexstr) {
1261			if (!isxdigit((u_char)val[0]) ||
1262			    !isxdigit((u_char)val[1])) {
1263				warnx("bad hexadecimal digits");
1264				return NULL;
1265			}
1266		}
1267		if (p > buf + len) {
1268			if (hexstr)
1269				warnx("hexadecimal digits too long");
1270			else
1271				warnx("strings too long");
1272			return NULL;
1273		}
1274		if (hexstr) {
1275#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1276			*p++ = (tohex((u_char)val[0]) << 4) |
1277			    tohex((u_char)val[1]);
1278#undef tohex
1279			val += 2;
1280		} else
1281			*p++ = *val++;
1282	}
1283	len = p - buf;
1284	if (len < *lenp)
1285		memset(p, 0, *lenp - len);
1286	*lenp = len;
1287	return val;
1288}
1289
1290void
1291print_string(const u_int8_t *buf, int len)
1292{
1293	int i;
1294	int hasspc;
1295
1296	i = 0;
1297	hasspc = 0;
1298	if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1299		for (; i < len; i++) {
1300			if (!isprint(buf[i]))
1301				break;
1302			if (isspace(buf[i]))
1303				hasspc++;
1304		}
1305	}
1306	if (i == len) {
1307		if (hasspc || len == 0)
1308			printf("\"%.*s\"", len, buf);
1309		else
1310			printf("%.*s", len, buf);
1311	} else {
1312		printf("0x");
1313		for (i = 0; i < len; i++)
1314			printf("%02x", buf[i]);
1315	}
1316}
1317
1318void
1319setifnwid(const char *val, int d)
1320{
1321	struct ieee80211_nwid nwid;
1322	int len;
1323
1324	len = sizeof(nwid.i_nwid);
1325	if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1326		return;
1327	nwid.i_len = len;
1328	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1329	ifr.ifr_data = (void *)&nwid;
1330	if (ioctl(s, SIOCS80211NWID, &ifr) == -1)
1331		warn("SIOCS80211NWID");
1332}
1333
1334void
1335setifbssid(const char *val, int d)
1336{
1337	struct ieee80211_bssid bssid;
1338	struct ether_addr *ea;
1339
1340	if (d != 0) {
1341		/* no BSSID is especially desired */
1342		memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1343	} else {
1344		ea = ether_aton(val);
1345		if (ea == NULL) {
1346			warnx("malformed BSSID: %s", val);
1347			return;
1348		}
1349		memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1350		    sizeof(bssid.i_bssid));
1351	}
1352	(void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
1353	if (ioctl(s, SIOCS80211BSSID, &bssid) == -1)
1354		warn("SIOCS80211BSSID");
1355}
1356
1357void
1358setifchan(const char *val, int d)
1359{
1360	struct ieee80211chanreq channel;
1361	int chan;
1362
1363	if (d != 0)
1364		chan = IEEE80211_CHAN_ANY;
1365	else {
1366		chan = atoi(val);
1367		if (chan < 0 || chan > 0xffff) {
1368			warnx("invalid channel: %s", val);
1369			return;
1370		}
1371	}
1372
1373	(void)strncpy(channel.i_name, name, sizeof(channel.i_name));
1374	channel.i_channel = (u_int16_t) chan;
1375	if (ioctl(s, SIOCS80211CHANNEL, &channel) == -1)
1376		warn("SIOCS80211CHANNEL");
1377}
1378
1379void
1380setifnwkey(const char *val, int d)
1381{
1382	struct ieee80211_nwkey nwkey;
1383	int i;
1384	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1385
1386	nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1387	nwkey.i_defkid = 1;
1388	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1389		nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
1390		nwkey.i_key[i].i_keydat = keybuf[i];
1391	}
1392	if (d != 0) {
1393		/* disable WEP encryption */
1394		nwkey.i_wepon = 0;
1395		i = 0;
1396	} else if (strcasecmp("persist", val) == 0) {
1397		/* use all values from persistent memory */
1398		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1399		nwkey.i_defkid = 0;
1400		for (i = 0; i < IEEE80211_WEP_NKID; i++)
1401			nwkey.i_key[i].i_keylen = -1;
1402	} else if (strncasecmp("persist:", val, 8) == 0) {
1403		val += 8;
1404		/* program keys in persistent memory */
1405		nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1406		goto set_nwkey;
1407	} else {
1408  set_nwkey:
1409		if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1410			/* specifying a full set of four keys */
1411			nwkey.i_defkid = val[0] - '0';
1412			val += 2;
1413			for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1414				val = get_string(val, ",", keybuf[i],
1415				    &nwkey.i_key[i].i_keylen);
1416				if (val == NULL)
1417					return;
1418			}
1419			if (*val != '\0') {
1420				warnx("SIOCS80211NWKEY: too many keys.");
1421				return;
1422			}
1423		} else {
1424			val = get_string(val, NULL, keybuf[0],
1425			    &nwkey.i_key[0].i_keylen);
1426			if (val == NULL)
1427				return;
1428			i = 1;
1429		}
1430	}
1431	for (; i < IEEE80211_WEP_NKID; i++)
1432		nwkey.i_key[i].i_keylen = 0;
1433	(void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1434	if (ioctl(s, SIOCS80211NWKEY, &nwkey) == -1)
1435		warn("SIOCS80211NWKEY");
1436}
1437
1438void
1439setifpowersave(const char *val, int d)
1440{
1441	struct ieee80211_power power;
1442
1443	(void)strncpy(power.i_name, name, sizeof(power.i_name));
1444	if (ioctl(s, SIOCG80211POWER, &power) == -1) {
1445		warn("SIOCG80211POWER");
1446		return;
1447	}
1448
1449	power.i_enabled = d;
1450	if (ioctl(s, SIOCS80211POWER, &power) == -1)
1451		warn("SIOCS80211POWER");
1452}
1453
1454void
1455setifpowersavesleep(const char *val, int d)
1456{
1457	struct ieee80211_power power;
1458
1459	(void)strncpy(power.i_name, name, sizeof(power.i_name));
1460	if (ioctl(s, SIOCG80211POWER, &power) == -1) {
1461		warn("SIOCG80211POWER");
1462		return;
1463	}
1464
1465	power.i_maxsleep = atoi(val);
1466	if (ioctl(s, SIOCS80211POWER, &power) == -1)
1467		warn("SIOCS80211POWER");
1468}
1469
1470void
1471ieee80211_statistics(void)
1472{
1473	struct ieee80211_stats stats;
1474
1475	memset(&ifr, 0, sizeof(ifr));
1476	ifr.ifr_data = (caddr_t)&stats;
1477	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1478	if (ioctl(s, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS,
1479	    (caddr_t)&ifr) == -1)
1480		return;
1481#define	RX_PRINT(desc, member) printf("\trx " desc ": %u\n", stats.member)
1482#define	TX_PRINT(desc, member) printf("\ttx " desc ": %u\n", stats.member)
1483
1484	RX_PRINT("too short", is_rx_tooshort);
1485	RX_PRINT("bad version", is_rx_badversion);
1486	RX_PRINT("wrong bss", is_rx_wrongbss);
1487	RX_PRINT("duplicate", is_rx_dup);
1488	RX_PRINT("wrong direction", is_rx_wrongdir);
1489	RX_PRINT("multicast echo", is_rx_mcastecho);
1490	RX_PRINT("STA not associated", is_rx_notassoc);
1491	RX_PRINT("WEP-encrypted but WEP not configured", is_rx_nowep);
1492	RX_PRINT("WEP processing failed", is_rx_wepfail);
1493#if 0
1494	RX_PRINT("single (M)MSDU, both WEP/non-WEP fragments", is_rx_wepmix);
1495	RX_PRINT("non-consecutive fragments", is_rx_fragorder);
1496#endif
1497	RX_PRINT("decapsulation failed", is_rx_decap);
1498	RX_PRINT("management-type discarded", is_rx_mgtdiscard);
1499	RX_PRINT("control-type discarded", is_rx_ctl);
1500	RX_PRINT("truncated rate set", is_rx_rstoobig);
1501	RX_PRINT("beacon/prresp element missing", is_rx_elem_missing);
1502	RX_PRINT("beacon/prresp element too big", is_rx_elem_toobig);
1503	RX_PRINT("beacon/prresp element too small", is_rx_elem_toosmall);
1504	RX_PRINT("beacon/prresp element unknown", is_rx_elem_unknown);
1505	RX_PRINT("invalid channel", is_rx_badchan);
1506	RX_PRINT("channel mismatch", is_rx_chanmismatch);
1507	RX_PRINT("failed node allocation", is_rx_nodealloc);
1508	RX_PRINT("SSID mismatch", is_rx_ssidmismatch);
1509	RX_PRINT("unsupported authentication algor.", is_rx_auth_unsupported);
1510	RX_PRINT("STA authentication failure", is_rx_auth_fail);
1511	RX_PRINT("association for wrong bss", is_rx_assoc_bss);
1512	RX_PRINT("association without authenication", is_rx_assoc_notauth);
1513	RX_PRINT("association capability mismatch", is_rx_assoc_capmismatch);
1514	RX_PRINT("association without rate match", is_rx_assoc_norate);
1515	RX_PRINT("deauthentication", is_rx_deauth);
1516	RX_PRINT("disassocation", is_rx_disassoc);
1517	RX_PRINT("unknown subtype", is_rx_badsubtype);
1518	RX_PRINT("failed, mbuf unavailable", is_rx_nombuf);
1519	RX_PRINT("failed, bad ICV", is_rx_decryptcrc);
1520	RX_PRINT("discard mgmt frame in ad-hoc demo mode", is_rx_ahdemo_mgt);
1521	RX_PRINT("bad authentication", is_rx_bad_auth);
1522	TX_PRINT("failed, mbuf unavailable", is_tx_nombuf);
1523	TX_PRINT("failed, no node", is_tx_nonode);
1524	TX_PRINT("unknown mgmt frame", is_tx_unknownmgt);
1525	printf("\tactive scans: %u\n", stats.is_scan_active);
1526	printf("\tpassive scans: %u\n", stats.is_scan_passive);
1527	printf("\tnodes timed-out for inactivity: %u\n",
1528	    stats.is_node_timeout);
1529	printf("\tcrypto context memory unavailable: %u\n",
1530	    stats.is_crypto_nomem);
1531}
1532
1533void
1534ieee80211_status(void)
1535{
1536	int i, nwkey_verbose;
1537	struct ieee80211_nwid nwid;
1538	struct ieee80211_nwkey nwkey;
1539	struct ieee80211_power power;
1540	u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1541	struct ieee80211_bssid bssid;
1542	struct ieee80211chanreq channel;
1543	struct ether_addr ea;
1544	static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
1545
1546	memset(&ifr, 0, sizeof(ifr));
1547	ifr.ifr_data = (void *)&nwid;
1548	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1549	if (ioctl(s, SIOCG80211NWID, &ifr) == -1)
1550		return;
1551	if (nwid.i_len > IEEE80211_NWID_LEN) {
1552		warnx("SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len);
1553		return;
1554	}
1555	printf("\tssid ");
1556	print_string(nwid.i_nwid, nwid.i_len);
1557	memset(&nwkey, 0, sizeof(nwkey));
1558	(void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1559	/* show nwkey only when WEP is enabled */
1560	if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1 ||
1561	    nwkey.i_wepon == 0) {
1562		printf("\n");
1563		goto skip_wep;
1564	}
1565
1566	printf(" nwkey ");
1567	/* try to retrieve WEP keys */
1568	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1569		nwkey.i_key[i].i_keydat = keybuf[i];
1570		nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
1571	}
1572	if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1) {
1573		printf("*****");
1574	} else {
1575		nwkey_verbose = 0;
1576		/* check to see non default key or multiple keys defined */
1577		if (nwkey.i_defkid != 1) {
1578			nwkey_verbose = 1;
1579		} else {
1580			for (i = 1; i < IEEE80211_WEP_NKID; i++) {
1581				if (nwkey.i_key[i].i_keylen != 0) {
1582					nwkey_verbose = 1;
1583					break;
1584				}
1585			}
1586		}
1587		/* check extra ambiguity with keywords */
1588		if (!nwkey_verbose) {
1589			if (nwkey.i_key[0].i_keylen >= 2 &&
1590			    isdigit(nwkey.i_key[0].i_keydat[0]) &&
1591			    nwkey.i_key[0].i_keydat[1] == ':')
1592				nwkey_verbose = 1;
1593			else if (nwkey.i_key[0].i_keylen >= 7 &&
1594			    strncasecmp("persist", nwkey.i_key[0].i_keydat, 7)
1595			    == 0)
1596				nwkey_verbose = 1;
1597		}
1598		if (nwkey_verbose)
1599			printf("%d:", nwkey.i_defkid);
1600		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1601			if (i > 0)
1602				printf(",");
1603			if (nwkey.i_key[i].i_keylen < 0)
1604				printf("persist");
1605			else
1606				print_string(nwkey.i_key[i].i_keydat,
1607				    nwkey.i_key[i].i_keylen);
1608			if (!nwkey_verbose)
1609				break;
1610		}
1611	}
1612	printf("\n");
1613
1614 skip_wep:
1615	(void)strncpy(power.i_name, name, sizeof(power.i_name));
1616	if (ioctl(s, SIOCG80211POWER, &power) == -1)
1617		goto skip_power;
1618	printf("\tpowersave ");
1619	if (power.i_enabled)
1620		printf("on (%dms sleep)", power.i_maxsleep);
1621	else
1622		printf("off");
1623	printf("\n");
1624
1625 skip_power:
1626	(void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
1627	if (ioctl(s, SIOCG80211BSSID, &bssid) == -1)
1628		return;
1629	(void)strncpy(channel.i_name, name, sizeof(channel.i_name));
1630	if (ioctl(s, SIOCG80211CHANNEL, &channel) == -1)
1631		return;
1632	if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) {
1633		if (channel.i_channel != (u_int16_t)-1)
1634			printf("\tchan %d\n", channel.i_channel);
1635	} else {
1636		memcpy(ea.ether_addr_octet, bssid.i_bssid,
1637		    sizeof(ea.ether_addr_octet));
1638		printf("\tbssid %s", ether_ntoa(&ea));
1639		if (channel.i_channel != IEEE80211_CHAN_ANY)
1640			printf(" chan %d", channel.i_channel);
1641		printf("\n");
1642	}
1643}
1644
1645static void
1646media_error(int type, const char *val, const char *opt)
1647{
1648	errx(EXIT_FAILURE, "unknown %s media %s: %s",
1649		get_media_type_string(type), opt, val);
1650}
1651
1652void
1653init_current_media(void)
1654{
1655	struct ifmediareq ifmr;
1656
1657	/*
1658	 * If we have not yet done so, grab the currently-selected
1659	 * media.
1660	 */
1661	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1662		(void) memset(&ifmr, 0, sizeof(ifmr));
1663		(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1664
1665		if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1666			/*
1667			 * If we get E2BIG, the kernel is telling us
1668			 * that there are more, so we can ignore it.
1669			 */
1670			if (errno != E2BIG)
1671				err(EXIT_FAILURE, "SGIOCGIFMEDIA");
1672		}
1673
1674		media_current = ifmr.ifm_current;
1675	}
1676
1677	/* Sanity. */
1678	if (IFM_TYPE(media_current) == 0)
1679		errx(EXIT_FAILURE, "%s: no link type?", name);
1680}
1681
1682void
1683process_media_commands(void)
1684{
1685
1686	if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1687		/* Nothing to do. */
1688		return;
1689	}
1690
1691	/*
1692	 * Media already set up, and commands sanity-checked.  Set/clear
1693	 * any options, and we're ready to go.
1694	 */
1695	media_current |= mediaopt_set;
1696	media_current &= ~mediaopt_clear;
1697
1698	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1699	ifr.ifr_media = media_current;
1700
1701	if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
1702		err(EXIT_FAILURE, "SIOCSIFMEDIA");
1703}
1704
1705void
1706setmedia(const char *val, int d)
1707{
1708	int type, subtype, inst;
1709
1710	init_current_media();
1711
1712	/* Only one media command may be given. */
1713	if (actions & A_MEDIA)
1714		errx(EXIT_FAILURE, "only one `media' command may be issued");
1715
1716	/* Must not come after mode commands */
1717	if (actions & A_MEDIAMODE)
1718		errx(EXIT_FAILURE,
1719		    "may not issue `media' after `mode' commands");
1720
1721	/* Must not come after mediaopt commands */
1722	if (actions & A_MEDIAOPT)
1723		errx(EXIT_FAILURE,
1724		    "may not issue `media' after `mediaopt' commands");
1725
1726	/*
1727	 * No need to check if `instance' has been issued; setmediainst()
1728	 * craps out if `media' has not been specified.
1729	 */
1730
1731	type = IFM_TYPE(media_current);
1732	inst = IFM_INST(media_current);
1733
1734	/* Look up the subtype. */
1735	subtype = get_media_subtype(type, val);
1736	if (subtype == -1)
1737		media_error(type, val, "subtype");
1738
1739	/* Build the new current media word. */
1740	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1741
1742	/* Media will be set after other processing is complete. */
1743}
1744
1745void
1746setmediaopt(const char *val, int d)
1747{
1748	char *invalid;
1749
1750	init_current_media();
1751
1752	/* Can only issue `mediaopt' once. */
1753	if (actions & A_MEDIAOPTSET)
1754		errx(EXIT_FAILURE, "only one `mediaopt' command may be issued");
1755
1756	/* Can't issue `mediaopt' if `instance' has already been issued. */
1757	if (actions & A_MEDIAINST)
1758		errx(EXIT_FAILURE, "may not issue `mediaopt' after `instance'");
1759
1760	mediaopt_set = get_media_options(media_current, val, &invalid);
1761	if (mediaopt_set == -1)
1762		media_error(media_current, invalid, "option");
1763
1764	/* Media will be set after other processing is complete. */
1765}
1766
1767void
1768unsetmediaopt(const char *val, int d)
1769{
1770	char *invalid;
1771
1772	init_current_media();
1773
1774	/* Can only issue `-mediaopt' once. */
1775	if (actions & A_MEDIAOPTCLR)
1776		errx(EXIT_FAILURE,
1777		    "only one `-mediaopt' command may be issued");
1778
1779	/* May not issue `media' and `-mediaopt'. */
1780	if (actions & A_MEDIA)
1781		errx(EXIT_FAILURE,
1782		    "may not issue both `media' and `-mediaopt'");
1783
1784	/*
1785	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1786	 * implicitly checks for A_MEDIAINST.
1787	 */
1788
1789	mediaopt_clear = get_media_options(media_current, val, &invalid);
1790	if (mediaopt_clear == -1)
1791		media_error(media_current, invalid, "option");
1792
1793	/* Media will be set after other processing is complete. */
1794}
1795
1796void
1797setmediainst(const char *val, int d)
1798{
1799	int type, subtype, options, inst;
1800
1801	init_current_media();
1802
1803	/* Can only issue `instance' once. */
1804	if (actions & A_MEDIAINST)
1805		errx(EXIT_FAILURE, "only one `instance' command may be issued");
1806
1807	/* Must have already specified `media' */
1808	if ((actions & A_MEDIA) == 0)
1809		errx(EXIT_FAILURE, "must specify `media' before `instance'");
1810
1811	type = IFM_TYPE(media_current);
1812	subtype = IFM_SUBTYPE(media_current);
1813	options = IFM_OPTIONS(media_current);
1814
1815	inst = atoi(val);
1816	if (inst < 0 || inst > IFM_INST_MAX)
1817		errx(EXIT_FAILURE, "invalid media instance: %s", val);
1818
1819	media_current = IFM_MAKEWORD(type, subtype, options, inst);
1820
1821	/* Media will be set after other processing is complete. */
1822}
1823
1824void
1825setmediamode(const char *val, int d)
1826{
1827	int type, subtype, options, inst, mode;
1828
1829	init_current_media();
1830
1831	/* Can only issue `mode' once. */
1832	if (actions & A_MEDIAMODE)
1833		errx(EXIT_FAILURE, "only one `mode' command may be issued");
1834
1835	type = IFM_TYPE(media_current);
1836	subtype = IFM_SUBTYPE(media_current);
1837	options = IFM_OPTIONS(media_current);
1838	inst = IFM_INST(media_current);
1839
1840	mode = get_media_mode(type, val);
1841	if (mode == -1)
1842		media_error(type, val, "mode");
1843
1844	media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
1845
1846	/* Media will be set after other processing is complete. */
1847}
1848
1849void
1850print_media_word(int ifmw, const char *opt_sep)
1851{
1852	const char *str;
1853
1854	printf("%s", get_media_subtype_string(ifmw));
1855
1856	/* Find mode. */
1857	if (IFM_MODE(ifmw) != 0) {
1858		str = get_media_mode_string(ifmw);
1859		if (str != NULL)
1860			printf(" mode %s", str);
1861	}
1862
1863	/* Find options. */
1864	for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",")
1865		printf("%s%s", opt_sep, str);
1866
1867	if (IFM_INST(ifmw) != 0)
1868		printf(" instance %d", IFM_INST(ifmw));
1869}
1870
1871int
1872carrier(void)
1873{
1874	struct ifmediareq ifmr;
1875
1876	(void) memset(&ifmr, 0, sizeof(ifmr));
1877	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1878
1879	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1880		/*
1881		 * Interface doesn't support SIOC{G,S}IFMEDIA;
1882		 * assume ok.
1883		 */
1884		return 0;
1885	}
1886	if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1887		/*
1888		 * Interface doesn't report media-valid status.
1889		 * assume ok.
1890		 */
1891		return 0;
1892	}
1893	/* otherwise, return ok for active, not-ok if not active. */
1894	return !(ifmr.ifm_status & IFM_ACTIVE);
1895}
1896
1897
1898#define	IFFBITS \
1899"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1900\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1901
1902#define	IFCAPBITS \
1903"\020\1IP4CSUM\2TCP4CSUM\3UDP4CSUM\4TCP6CSUM\5UDP6CSUM\6TCP4CSUM_Rx\7UDP4CSUM_Rx"
1904
1905const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1906
1907const struct ifmedia_status_description ifm_status_descriptions[] =
1908    IFM_STATUS_DESCRIPTIONS;
1909
1910/*
1911 * Print the status of the interface.  If an address family was
1912 * specified, show it and it only; otherwise, show them all.
1913 */
1914void
1915status(const struct sockaddr_dl *sdl)
1916{
1917	struct afswtch *p = afp;
1918	struct ifmediareq ifmr;
1919	struct ifdatareq ifdr;
1920	int *media_list, i;
1921	char hbuf[NI_MAXHOST];
1922	char fbuf[BUFSIZ];
1923
1924	(void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1925	printf("%s: flags=%s", name, &fbuf[2]);
1926	if (metric)
1927		printf(" metric %lu", metric);
1928	if (mtu)
1929		printf(" mtu %lu", mtu);
1930	printf("\n");
1931
1932	if (g_ifcr.ifcr_capabilities) {
1933		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1934		    g_ifcr.ifcr_capabilities);
1935		printf("\tcapabilities=%s\n", &fbuf[2]);
1936		(void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1937		    g_ifcr.ifcr_capenable);
1938		printf("\tenabled=%s\n", &fbuf[2]);
1939	}
1940
1941	ieee80211_status();
1942	vlan_status();
1943	tunnel_status();
1944
1945	if (sdl != NULL &&
1946	    getnameinfo((struct sockaddr *)sdl, sdl->sdl_len,
1947		hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
1948	    hbuf[0] != '\0')
1949		printf("\taddress: %s\n", hbuf);
1950
1951	(void) memset(&ifmr, 0, sizeof(ifmr));
1952	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1953
1954	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1955		/*
1956		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1957		 */
1958		goto iface_stats;
1959	}
1960
1961	if (ifmr.ifm_count == 0) {
1962		warnx("%s: no media types?", name);
1963		goto iface_stats;
1964	}
1965
1966	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1967	if (media_list == NULL)
1968		err(EXIT_FAILURE, "malloc");
1969	ifmr.ifm_ulist = media_list;
1970
1971	if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
1972		err(EXIT_FAILURE, "SIOCGIFMEDIA");
1973
1974	printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current));
1975	print_media_word(ifmr.ifm_current, " ");
1976	if (ifmr.ifm_active != ifmr.ifm_current) {
1977		printf(" (");
1978		print_media_word(ifmr.ifm_active, " ");
1979		printf(")");
1980	}
1981	printf("\n");
1982
1983	if (ifmr.ifm_status & IFM_STATUS_VALID) {
1984		const struct ifmedia_status_description *ifms;
1985		int bitno, found = 0;
1986
1987		printf("\tstatus: ");
1988		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1989			for (ifms = ifm_status_descriptions;
1990			     ifms->ifms_valid != 0; ifms++) {
1991				if (ifms->ifms_type !=
1992				      IFM_TYPE(ifmr.ifm_current) ||
1993				    ifms->ifms_valid !=
1994				      ifm_status_valid_list[bitno])
1995					continue;
1996				printf("%s%s", found ? ", " : "",
1997				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1998				found = 1;
1999
2000				/*
2001				 * For each valid indicator bit, there's
2002				 * only one entry for each media type, so
2003				 * terminate the inner loop now.
2004				 */
2005				break;
2006			}
2007		}
2008
2009		if (found == 0)
2010			printf("unknown");
2011		printf("\n");
2012	}
2013
2014	if (mflag) {
2015		int type, printed_type;
2016
2017		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
2018			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
2019				if (IFM_TYPE(media_list[i]) != type)
2020					continue;
2021				if (printed_type == 0) {
2022					printf("\tsupported %s media:\n",
2023					    get_media_type_string(type));
2024					printed_type = 1;
2025				}
2026				printf("\t\tmedia ");
2027				print_media_word(media_list[i], " mediaopt ");
2028				printf("\n");
2029			}
2030		}
2031	}
2032
2033	free(media_list);
2034
2035 iface_stats:
2036	if (!vflag && !zflag)
2037		goto proto_status;
2038
2039	(void) strncpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name));
2040
2041	if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1) {
2042		err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
2043	} else {
2044		struct if_data * const ifi = &ifdr.ifdr_data;
2045#define	PLURAL(n)	((n) == 1 ? "" : "s")
2046		printf("\tinput: %llu packet%s, %llu byte%s",
2047		    (unsigned long long) ifi->ifi_ipackets,
2048		    PLURAL(ifi->ifi_ipackets),
2049		    (unsigned long long) ifi->ifi_ibytes,
2050		    PLURAL(ifi->ifi_ibytes));
2051		if (ifi->ifi_imcasts)
2052			printf(", %llu multicast%s",
2053			    (unsigned long long) ifi->ifi_imcasts,
2054			    PLURAL(ifi->ifi_imcasts));
2055		if (ifi->ifi_ierrors)
2056			printf(", %llu error%s",
2057			    (unsigned long long) ifi->ifi_ierrors,
2058			    PLURAL(ifi->ifi_ierrors));
2059		if (ifi->ifi_iqdrops)
2060			printf(", %llu queue drop%s",
2061			    (unsigned long long) ifi->ifi_iqdrops,
2062			    PLURAL(ifi->ifi_iqdrops));
2063		if (ifi->ifi_noproto)
2064			printf(", %llu unknown protocol",
2065			    (unsigned long long) ifi->ifi_noproto);
2066		printf("\n\toutput: %llu packet%s, %llu byte%s",
2067		    (unsigned long long) ifi->ifi_opackets,
2068		    PLURAL(ifi->ifi_opackets),
2069		    (unsigned long long) ifi->ifi_obytes,
2070		    PLURAL(ifi->ifi_obytes));
2071		if (ifi->ifi_omcasts)
2072			printf(", %llu multicast%s",
2073			    (unsigned long long) ifi->ifi_omcasts,
2074			    PLURAL(ifi->ifi_omcasts));
2075		if (ifi->ifi_oerrors)
2076			printf(", %llu error%s",
2077			    (unsigned long long) ifi->ifi_oerrors,
2078			    PLURAL(ifi->ifi_oerrors));
2079		if (ifi->ifi_collisions)
2080			printf(", %llu collision%s",
2081			    (unsigned long long) ifi->ifi_collisions,
2082			    PLURAL(ifi->ifi_collisions));
2083		printf("\n");
2084#undef PLURAL
2085	}
2086
2087	ieee80211_statistics();
2088
2089 proto_status:
2090	if ((p = afp) != NULL) {
2091		(*p->af_status)(1);
2092	} else for (p = afs; p->af_name; p++) {
2093		ifr.ifr_addr.sa_family = p->af_af;
2094		(*p->af_status)(0);
2095	}
2096}
2097
2098void
2099tunnel_status(void)
2100{
2101	char psrcaddr[NI_MAXHOST];
2102	char pdstaddr[NI_MAXHOST];
2103	const char *ver = "";
2104	const int niflag = NI_NUMERICHOST;
2105	struct if_laddrreq req;
2106
2107	psrcaddr[0] = pdstaddr[0] = '\0';
2108
2109	memset(&req, 0, sizeof(req));
2110	strncpy(req.iflr_name, name, IFNAMSIZ);
2111	if (ioctl(s, SIOCGLIFPHYADDR, &req) == -1)
2112		return;
2113#ifdef INET6
2114	if (req.addr.ss_family == AF_INET6)
2115		in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
2116#endif
2117	getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
2118	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
2119#ifdef INET6
2120	if (req.addr.ss_family == AF_INET6)
2121		ver = "6";
2122#endif
2123
2124#ifdef INET6
2125	if (req.dstaddr.ss_family == AF_INET6)
2126		in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
2127#endif
2128	getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
2129	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
2130
2131	printf("\ttunnel inet%s %s --> %s\n", ver, psrcaddr, pdstaddr);
2132}
2133
2134void
2135vlan_status(void)
2136{
2137	struct vlanreq vlr;
2138
2139	if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
2140	    !isdigit((unsigned char)ifr.ifr_name[4]))
2141		return;
2142
2143	memset(&vlr, 0, sizeof(vlr));
2144	ifr.ifr_data = (void *)&vlr;
2145
2146	if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
2147		return;
2148
2149	if (vlr.vlr_tag || vlr.vlr_parent[0] != '\0')
2150		printf("\tvlan: %d parent: %s\n",
2151		    vlr.vlr_tag, vlr.vlr_parent[0] == '\0' ?
2152		    "<none>" : vlr.vlr_parent);
2153}
2154
2155void
2156in_alias(struct ifreq *creq)
2157{
2158	struct sockaddr_in *iasin;
2159	int alias;
2160
2161	if (lflag)
2162		return;
2163
2164	alias = 1;
2165
2166	/* Get the non-alias address for this interface. */
2167	getsock(AF_INET);
2168	if (s < 0) {
2169		if (errno == EPROTONOSUPPORT)
2170			return;
2171		err(EXIT_FAILURE, "socket");
2172	}
2173	(void) memset(&ifr, 0, sizeof(ifr));
2174	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2175	if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2176		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2177			return;
2178		} else
2179			warn("SIOCGIFADDR");
2180	}
2181	/* If creq and ifr are the same address, this is not an alias. */
2182	if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
2183		   sizeof(creq->ifr_addr)) == 0)
2184		alias = 0;
2185	(void) memset(&in_addreq, 0, sizeof(in_addreq));
2186	(void) strncpy(in_addreq.ifra_name, name, sizeof(in_addreq.ifra_name));
2187	memcpy(&in_addreq.ifra_addr, &creq->ifr_addr,
2188	    sizeof(in_addreq.ifra_addr));
2189	if (ioctl(s, SIOCGIFALIAS, &in_addreq) == -1) {
2190		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2191			return;
2192		} else
2193			warn("SIOCGIFALIAS");
2194	}
2195
2196	iasin = &in_addreq.ifra_addr;
2197	printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(iasin->sin_addr));
2198
2199	if (flags & IFF_POINTOPOINT) {
2200		iasin = &in_addreq.ifra_dstaddr;
2201		printf(" -> %s", inet_ntoa(iasin->sin_addr));
2202	}
2203
2204	iasin = &in_addreq.ifra_mask;
2205	printf(" netmask 0x%x", ntohl(iasin->sin_addr.s_addr));
2206
2207	if (flags & IFF_BROADCAST) {
2208		iasin = &in_addreq.ifra_broadaddr;
2209		printf(" broadcast %s", inet_ntoa(iasin->sin_addr));
2210	}
2211	printf("\n");
2212}
2213
2214void
2215in_status(int force)
2216{
2217	struct ifaddrs *ifap, *ifa;
2218	struct ifreq isifr;
2219
2220	if (getifaddrs(&ifap) != 0)
2221		err(EXIT_FAILURE, "getifaddrs");
2222	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2223		if (strcmp(name, ifa->ifa_name) != 0)
2224			continue;
2225		if (ifa->ifa_addr->sa_family != AF_INET)
2226			continue;
2227		if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
2228			continue;
2229
2230		memset(&isifr, 0, sizeof(isifr));
2231		strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
2232		memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
2233		in_alias(&isifr);
2234	}
2235	freeifaddrs(ifap);
2236}
2237
2238void
2239setifprefixlen(const char *addr, int d)
2240{
2241	if (*afp->af_getprefix)
2242		(*afp->af_getprefix)(addr, MASK);
2243	explicit_prefix = 1;
2244}
2245
2246#ifdef INET6
2247void
2248in6_fillscopeid(struct sockaddr_in6 *sin6)
2249{
2250#if defined(__KAME__) && defined(KAME_SCOPEID)
2251	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
2252		sin6->sin6_scope_id =
2253			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
2254		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
2255	}
2256#endif
2257}
2258
2259/* XXX not really an alias */
2260void
2261in6_alias(struct in6_ifreq *creq)
2262{
2263	struct sockaddr_in6 *sin6;
2264	char hbuf[NI_MAXHOST];
2265	u_int32_t scopeid;
2266	const int niflag = NI_NUMERICHOST;
2267
2268	/* Get the non-alias address for this interface. */
2269	getsock(AF_INET6);
2270	if (s < 0) {
2271		if (errno == EPROTONOSUPPORT)
2272			return;
2273		err(EXIT_FAILURE, "socket");
2274	}
2275
2276	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
2277
2278	in6_fillscopeid(sin6);
2279	scopeid = sin6->sin6_scope_id;
2280	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
2281			hbuf, sizeof(hbuf), NULL, 0, niflag))
2282		strlcpy(hbuf, "", sizeof(hbuf));	/* some message? */
2283	printf("\tinet6 %s", hbuf);
2284
2285	if (flags & IFF_POINTOPOINT) {
2286		(void) memset(&ifr6, 0, sizeof(ifr6));
2287		(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2288		ifr6.ifr_addr = creq->ifr_addr;
2289		if (ioctl(s, SIOCGIFDSTADDR_IN6, &ifr6) == -1) {
2290			if (errno != EADDRNOTAVAIL)
2291				warn("SIOCGIFDSTADDR_IN6");
2292			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
2293			ifr6.ifr_addr.sin6_family = AF_INET6;
2294			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
2295		}
2296		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
2297		in6_fillscopeid(sin6);
2298		hbuf[0] = '\0';
2299		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
2300				hbuf, sizeof(hbuf), NULL, 0, niflag))
2301			strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
2302		printf(" -> %s", hbuf);
2303	}
2304
2305	(void) memset(&ifr6, 0, sizeof(ifr6));
2306	(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2307	ifr6.ifr_addr = creq->ifr_addr;
2308	if (ioctl(s, SIOCGIFNETMASK_IN6, &ifr6) == -1) {
2309		if (errno != EADDRNOTAVAIL)
2310			warn("SIOCGIFNETMASK_IN6");
2311	} else {
2312		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
2313		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
2314					       sizeof(struct in6_addr)));
2315	}
2316
2317	(void) memset(&ifr6, 0, sizeof(ifr6));
2318	(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2319	ifr6.ifr_addr = creq->ifr_addr;
2320	if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
2321		if (errno != EADDRNOTAVAIL)
2322			warn("SIOCGIFAFLAG_IN6");
2323	} else {
2324		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
2325			printf(" anycast");
2326		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
2327			printf(" tentative");
2328		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
2329			printf(" duplicated");
2330		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
2331			printf(" detached");
2332		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
2333			printf(" deprecated");
2334	}
2335
2336	if (scopeid)
2337		printf(" scopeid 0x%x", scopeid);
2338
2339	if (Lflag) {
2340		struct in6_addrlifetime *lifetime;
2341		(void) memset(&ifr6, 0, sizeof(ifr6));
2342		(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2343		ifr6.ifr_addr = creq->ifr_addr;
2344		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
2345		if (ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) == -1) {
2346			if (errno != EADDRNOTAVAIL)
2347				warn("SIOCGIFALIFETIME_IN6");
2348		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
2349			time_t t = time(NULL);
2350			printf(" pltime ");
2351			if (lifetime->ia6t_preferred) {
2352				printf("%s", lifetime->ia6t_preferred < t
2353					? "0"
2354					: sec2str(lifetime->ia6t_preferred - t));
2355			} else
2356				printf("infty");
2357
2358			printf(" vltime ");
2359			if (lifetime->ia6t_expire) {
2360				printf("%s", lifetime->ia6t_expire < t
2361					? "0"
2362					: sec2str(lifetime->ia6t_expire - t));
2363			} else
2364				printf("infty");
2365		}
2366	}
2367
2368	printf("\n");
2369}
2370
2371void
2372in6_status(int force)
2373{
2374	struct ifaddrs *ifap, *ifa;
2375	struct in6_ifreq isifr;
2376
2377	if (getifaddrs(&ifap) != 0)
2378		err(EXIT_FAILURE, "getifaddrs");
2379	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2380		if (strcmp(name, ifa->ifa_name) != 0)
2381			continue;
2382		if (ifa->ifa_addr->sa_family != AF_INET6)
2383			continue;
2384		if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
2385			continue;
2386
2387		memset(&isifr, 0, sizeof(isifr));
2388		strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
2389		memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
2390		in6_alias(&isifr);
2391	}
2392	freeifaddrs(ifap);
2393}
2394#endif /*INET6*/
2395
2396#ifndef INET_ONLY
2397
2398void
2399at_status(int force)
2400{
2401	struct sockaddr_at *sat, null_sat;
2402	struct netrange *nr;
2403
2404	getsock(AF_APPLETALK);
2405	if (s < 0) {
2406		if (errno == EPROTONOSUPPORT)
2407			return;
2408		err(EXIT_FAILURE, "socket");
2409	}
2410	(void) memset(&ifr, 0, sizeof(ifr));
2411	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2412	if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2413		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2414			if (!force)
2415				return;
2416			(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2417		} else
2418			warn("SIOCGIFADDR");
2419	}
2420	(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2421	sat = (struct sockaddr_at *)&ifr.ifr_addr;
2422
2423	(void) memset(&null_sat, 0, sizeof(null_sat));
2424
2425	nr = (struct netrange *) &sat->sat_zero;
2426	printf("\tatalk %d.%d range %d-%d phase %d",
2427	    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2428	    ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
2429	if (flags & IFF_POINTOPOINT) {
2430		if (ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) {
2431			if (errno == EADDRNOTAVAIL)
2432			    (void) memset(&ifr.ifr_addr, 0,
2433				sizeof(ifr.ifr_addr));
2434			else
2435			    warn("SIOCGIFDSTADDR");
2436		}
2437		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2438		sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
2439		if (!sat)
2440			sat = &null_sat;
2441		printf("--> %d.%d",
2442		    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
2443	}
2444	if (flags & IFF_BROADCAST) {
2445		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
2446		sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
2447		if (sat)
2448			printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
2449			    sat->sat_addr.s_node);
2450	}
2451	printf("\n");
2452}
2453
2454void
2455xns_status(int force)
2456{
2457	struct sockaddr_ns *sns;
2458
2459	getsock(AF_NS);
2460	if (s < 0) {
2461		if (errno == EPROTONOSUPPORT)
2462			return;
2463		err(EXIT_FAILURE, "socket");
2464	}
2465	(void) memset(&ifr, 0, sizeof(ifr));
2466	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2467	if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2468		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2469			if (!force)
2470				return;
2471			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2472		} else
2473			warn("SIOCGIFADDR");
2474	}
2475	(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2476	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
2477	printf("\tns %s ", ns_ntoa(sns->sns_addr));
2478	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
2479		if (ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) {
2480			if (errno == EADDRNOTAVAIL)
2481			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2482			else
2483			    warn("SIOCGIFDSTADDR");
2484		}
2485		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2486		sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
2487		printf("--> %s ", ns_ntoa(sns->sns_addr));
2488	}
2489	printf("\n");
2490}
2491
2492void
2493iso_status(int force)
2494{
2495	struct sockaddr_iso *siso;
2496	struct iso_ifreq isoifr;
2497
2498	getsock(AF_ISO);
2499	if (s < 0) {
2500		if (errno == EPROTONOSUPPORT)
2501			return;
2502		err(EXIT_FAILURE, "socket");
2503	}
2504	(void) memset(&isoifr, 0, sizeof(isoifr));
2505	(void) strncpy(isoifr.ifr_name, name, sizeof(isoifr.ifr_name));
2506	if (ioctl(s, SIOCGIFADDR_ISO, &isoifr) == -1) {
2507		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2508			if (!force)
2509				return;
2510			(void) memset(&isoifr.ifr_Addr, 0,
2511			    sizeof(isoifr.ifr_Addr));
2512		} else
2513			warn("SIOCGIFADDR_ISO");
2514	}
2515	(void) strncpy(isoifr.ifr_name, name, sizeof isoifr.ifr_name);
2516	siso = &isoifr.ifr_Addr;
2517	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
2518	if (ioctl(s, SIOCGIFNETMASK_ISO, &isoifr) == -1) {
2519		if (errno == EADDRNOTAVAIL)
2520			memset(&isoifr.ifr_Addr, 0, sizeof(isoifr.ifr_Addr));
2521		else
2522			warn("SIOCGIFNETMASK_ISO");
2523	} else {
2524		if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
2525			siso->siso_addr.isoa_len = siso->siso_len
2526			    - offsetof(struct sockaddr_iso, siso_addr);
2527		printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr));
2528	}
2529	if (flags & IFF_POINTOPOINT) {
2530		if (ioctl(s, SIOCGIFDSTADDR_ISO, &isoifr) == -1) {
2531			if (errno == EADDRNOTAVAIL)
2532			    memset(&isoifr.ifr_Addr, 0,
2533				sizeof(isoifr.ifr_Addr));
2534			else
2535			    warn("SIOCGIFDSTADDR_ISO");
2536		}
2537		(void) strncpy(isoifr.ifr_name, name, sizeof (isoifr.ifr_name));
2538		siso = &isoifr.ifr_Addr;
2539		printf("--> %s ", iso_ntoa(&siso->siso_addr));
2540	}
2541	printf("\n");
2542}
2543
2544#endif	/* INET_ONLY */
2545
2546#define SIN(x) ((struct sockaddr_in *) &(x))
2547struct sockaddr_in *sintab[] = {
2548    SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
2549    SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
2550
2551void
2552in_getaddr(const char *str, int which)
2553{
2554	struct sockaddr_in *gasin = sintab[which];
2555	struct hostent *hp;
2556	struct netent *np;
2557
2558	gasin->sin_len = sizeof(*gasin);
2559	if (which != MASK)
2560		gasin->sin_family = AF_INET;
2561
2562	if (which == ADDR) {
2563		char *p = NULL;
2564		if ((p = strrchr(str, '/')) != NULL) {
2565			*p = '\0';
2566			in_getprefix(p + 1, MASK);
2567		}
2568	}
2569
2570	if (inet_aton(str, &gasin->sin_addr) == 0) {
2571		if ((hp = gethostbyname(str)) != NULL)
2572			(void) memcpy(&gasin->sin_addr, hp->h_addr, hp->h_length);
2573		else if ((np = getnetbyname(str)) != NULL)
2574			gasin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
2575		else
2576			errx(EXIT_FAILURE, "%s: bad value", str);
2577	}
2578}
2579
2580void
2581in_getprefix(const char *plen, int which)
2582{
2583	register struct sockaddr_in *igsin = sintab[which];
2584	register u_char *cp;
2585	int len = strtol(plen, (char **)NULL, 10);
2586
2587	if ((len < 0) || (len > 32))
2588		errx(EXIT_FAILURE, "%s: bad value", plen);
2589	igsin->sin_len = sizeof(*igsin);
2590	if (which != MASK)
2591		igsin->sin_family = AF_INET;
2592	if ((len == 0) || (len == 32)) {
2593		memset(&igsin->sin_addr, 0xff, sizeof(struct in_addr));
2594		return;
2595	}
2596	memset((void *)&igsin->sin_addr, 0x00, sizeof(igsin->sin_addr));
2597	for (cp = (u_char *)&igsin->sin_addr; len > 7; len -= 8)
2598		*cp++ = 0xff;
2599	if (len)
2600		*cp = 0xff << (8 - len);
2601}
2602
2603#ifdef INET6
2604#define SIN6(x) ((struct sockaddr_in6 *) &(x))
2605struct sockaddr_in6 *sin6tab[] = {
2606    SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
2607    SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
2608
2609void
2610in6_getaddr(const char *str, int which)
2611{
2612#if defined(__KAME__) && defined(KAME_SCOPEID)
2613	struct sockaddr_in6 *sin6 = sin6tab[which];
2614	struct addrinfo hints, *res;
2615	int error;
2616	char *slash = NULL;
2617
2618	if (which == ADDR) {
2619		if ((slash = strrchr(str, '/')) != NULL)
2620			*slash = '\0';
2621	}
2622
2623	memset(&hints, 0, sizeof(hints));
2624	hints.ai_family = AF_INET6;
2625	hints.ai_socktype = SOCK_DGRAM;
2626#if 0 /* in_getaddr() allows FQDN */
2627	hints.ai_flags = AI_NUMERICHOST;
2628#endif
2629	error = getaddrinfo(str, "0", &hints, &res);
2630	if (error && slash) {
2631		/* try again treating the '/' as part of the name */
2632		*slash = '/';
2633		slash = NULL;
2634		error = getaddrinfo(str, "0", &hints, &res);
2635	}
2636	if (error)
2637		errx(EXIT_FAILURE, "%s: %s", str, gai_strerror(error));
2638	if (res->ai_next)
2639		errx(EXIT_FAILURE, "%s: resolved to multiple addresses", str);
2640	if (res->ai_addrlen != sizeof(struct sockaddr_in6))
2641		errx(EXIT_FAILURE, "%s: bad value", str);
2642	memcpy(sin6, res->ai_addr, res->ai_addrlen);
2643	freeaddrinfo(res);
2644	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
2645		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
2646			htons(sin6->sin6_scope_id);
2647		sin6->sin6_scope_id = 0;
2648	}
2649	if (slash) {
2650		in6_getprefix(slash + 1, MASK);
2651		explicit_prefix = 1;
2652	}
2653#else
2654	struct sockaddr_in6 *gasin = sin6tab[which];
2655
2656	gasin->sin6_len = sizeof(*gasin);
2657	if (which != MASK)
2658		gasin->sin6_family = AF_INET6;
2659
2660	if (which == ADDR) {
2661		char *p = NULL;
2662		if((p = strrchr(str, '/')) != NULL) {
2663			*p = '\0';
2664			in6_getprefix(p + 1, MASK);
2665			explicit_prefix = 1;
2666		}
2667	}
2668
2669	if (inet_pton(AF_INET6, str, &gasin->sin6_addr) != 1)
2670		errx(EXIT_FAILURE, "%s: bad value", str);
2671#endif
2672}
2673
2674void
2675in6_getprefix(const char *plen, int which)
2676{
2677	register struct sockaddr_in6 *gpsin = sin6tab[which];
2678	register u_char *cp;
2679	int len = strtol(plen, (char **)NULL, 10);
2680
2681	if ((len < 0) || (len > 128))
2682		errx(EXIT_FAILURE, "%s: bad value", plen);
2683	gpsin->sin6_len = sizeof(*gpsin);
2684	if (which != MASK)
2685		gpsin->sin6_family = AF_INET6;
2686	if ((len == 0) || (len == 128)) {
2687		memset(&gpsin->sin6_addr, 0xff, sizeof(struct in6_addr));
2688		return;
2689	}
2690	memset((void *)&gpsin->sin6_addr, 0x00, sizeof(gpsin->sin6_addr));
2691	for (cp = (u_char *)&gpsin->sin6_addr; len > 7; len -= 8)
2692		*cp++ = 0xff;
2693	if (len)
2694		*cp = 0xff << (8 - len);
2695}
2696
2697int
2698prefix(void *val, int size)
2699{
2700	register u_char *pname = (u_char *)val;
2701	register int byte, bit, plen = 0;
2702
2703	for (byte = 0; byte < size; byte++, plen += 8)
2704		if (pname[byte] != 0xff)
2705			break;
2706	if (byte == size)
2707		return (plen);
2708	for (bit = 7; bit != 0; bit--, plen++)
2709		if (!(pname[byte] & (1 << bit)))
2710			break;
2711	for (; bit != 0; bit--)
2712		if (pname[byte] & (1 << bit))
2713			return(0);
2714	byte++;
2715	for (; byte < size; byte++)
2716		if (pname[byte])
2717			return(0);
2718	return (plen);
2719}
2720#endif /*INET6*/
2721
2722#ifndef INET_ONLY
2723void
2724at_getaddr(const char *addr, int which)
2725{
2726	struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
2727	u_int net, node;
2728
2729	sat->sat_family = AF_APPLETALK;
2730	sat->sat_len = sizeof(*sat);
2731	if (which == MASK)
2732		errx(EXIT_FAILURE, "AppleTalk does not use netmasks");
2733	if (sscanf(addr, "%u.%u", &net, &node) != 2
2734	    || net == 0 || net > 0xffff || node == 0 || node > 0xfe)
2735		errx(EXIT_FAILURE, "%s: illegal address", addr);
2736	sat->sat_addr.s_net = htons(net);
2737	sat->sat_addr.s_node = node;
2738}
2739
2740void
2741setatrange(const char *range, int d)
2742{
2743	u_short	first = 123, last = 123;
2744
2745	if (sscanf(range, "%hu-%hu", &first, &last) != 2
2746	    || first == 0 /* || first > 0xffff */
2747	    || last == 0 /* || last > 0xffff */ || first > last)
2748		errx(EXIT_FAILURE, "%s: illegal net range: %u-%u", range,
2749		    first, last);
2750	at_nr.nr_firstnet = htons(first);
2751	at_nr.nr_lastnet = htons(last);
2752}
2753
2754void
2755setatphase(const char *phase, int d)
2756{
2757	if (!strcmp(phase, "1"))
2758		at_nr.nr_phase = 1;
2759	else if (!strcmp(phase, "2"))
2760		at_nr.nr_phase = 2;
2761	else
2762		errx(EXIT_FAILURE, "%s: illegal phase", phase);
2763}
2764
2765void
2766checkatrange(struct sockaddr_at *sat)
2767{
2768	if (at_nr.nr_phase == 0)
2769		at_nr.nr_phase = 2;	/* Default phase 2 */
2770	if (at_nr.nr_firstnet == 0)
2771		at_nr.nr_firstnet =	/* Default range of one */
2772		at_nr.nr_lastnet = sat->sat_addr.s_net;
2773	printf("\tatalk %d.%d range %d-%d phase %d\n",
2774	ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2775	ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
2776	if ((u_short) ntohs(at_nr.nr_firstnet) >
2777			(u_short) ntohs(sat->sat_addr.s_net)
2778		    || (u_short) ntohs(at_nr.nr_lastnet) <
2779			(u_short) ntohs(sat->sat_addr.s_net))
2780		errx(EXIT_FAILURE, "AppleTalk address is not in range");
2781	*((struct netrange *) &sat->sat_zero) = at_nr;
2782}
2783
2784#define SNS(x) ((struct sockaddr_ns *) &(x))
2785struct sockaddr_ns *snstab[] = {
2786    SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
2787    SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
2788
2789void
2790xns_getaddr(const char *addr, int which)
2791{
2792	struct sockaddr_ns *sns = snstab[which];
2793
2794	sns->sns_family = AF_NS;
2795	sns->sns_len = sizeof(*sns);
2796	sns->sns_addr = ns_addr(addr);
2797	if (which == MASK)
2798		puts("Attempt to set XNS netmask will be ineffectual");
2799}
2800
2801#define SISO(x) ((struct sockaddr_iso *) &(x))
2802struct sockaddr_iso *sisotab[] = {
2803    SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
2804    SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
2805
2806void
2807iso_getaddr(const char *addr, int which)
2808{
2809	struct sockaddr_iso *siso = sisotab[which];
2810	siso->siso_addr = *iso_addr(addr);
2811
2812	if (which == MASK) {
2813		siso->siso_len = TSEL(siso) - (char *)(siso);
2814		siso->siso_nlen = 0;
2815	} else {
2816		siso->siso_len = sizeof(*siso);
2817		siso->siso_family = AF_ISO;
2818	}
2819}
2820
2821void
2822setsnpaoffset(const char *val, int d)
2823{
2824	iso_addreq.ifra_snpaoffset = atoi(val);
2825}
2826
2827void
2828setnsellength(const char *val, int d)
2829{
2830	nsellength = atoi(val);
2831	if (nsellength < 0)
2832		errx(EXIT_FAILURE, "Negative NSEL length is absurd");
2833	if (afp == 0 || afp->af_af != AF_ISO)
2834		errx(EXIT_FAILURE, "Setting NSEL length valid only for iso");
2835}
2836
2837void
2838fixnsel(struct sockaddr_iso *siso)
2839{
2840	if (siso->siso_family == 0)
2841		return;
2842	siso->siso_tlen = nsellength;
2843}
2844
2845void
2846adjust_nsellength(void)
2847{
2848	fixnsel(sisotab[RIDADDR]);
2849	fixnsel(sisotab[ADDR]);
2850	fixnsel(sisotab[DSTADDR]);
2851}
2852
2853#endif	/* INET_ONLY */
2854
2855void
2856usage(void)
2857{
2858	const char *progname = getprogname();
2859
2860	fprintf(stderr,
2861	    "usage: %s [-m] [-v] [-z] "
2862#ifdef INET6
2863		"[-L] "
2864#endif
2865		"interface\n"
2866		"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
2867		"\t\t[ alias | -alias ] ]\n"
2868		"\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
2869		"\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
2870		"\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
2871		"\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
2872		"\t[ arp | -arp ]\n"
2873		"\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
2874		"[ instance minst ]\n"
2875		"\t[ vlan n vlanif i ]\n"
2876		"\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
2877		"\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n"
2878		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
2879		"       %s -a [-b] [-m] [-d] [-u] [-v] [-z] [ af ]\n"
2880		"       %s -l [-b] [-d] [-u] [-s]\n"
2881		"       %s -C\n"
2882		"       %s interface create\n"
2883		"       %s interface destroy\n",
2884		progname, progname, progname, progname, progname, progname);
2885	exit(1);
2886}
2887
2888#ifdef INET6
2889char *
2890sec2str(total)
2891	time_t total;
2892{
2893	static char result[256];
2894	int days, hours, mins, secs;
2895	int first = 1;
2896	char *p = result;
2897	char *end = &result[sizeof(result)];
2898	int n;
2899
2900	if (0) {	/*XXX*/
2901		days = total / 3600 / 24;
2902		hours = (total / 3600) % 24;
2903		mins = (total / 60) % 60;
2904		secs = total % 60;
2905
2906		if (days) {
2907			first = 0;
2908			n = snprintf(p, end - p, "%dd", days);
2909			if (n < 0 || n >= end - p)
2910				return(result);
2911			p += n;
2912		}
2913		if (!first || hours) {
2914			first = 0;
2915			n = snprintf(p, end - p, "%dh", hours);
2916			if (n < 0 || n >= end - p)
2917				return(result);
2918			p += n;
2919		}
2920		if (!first || mins) {
2921			first = 0;
2922			n = snprintf(p, end - p, "%dm", mins);
2923			if (n < 0 || n >= end - p)
2924				return(result);
2925			p += n;
2926		}
2927		snprintf(p, end - p, "%ds", secs);
2928	} else
2929		snprintf(p, end - p, "%lu", (u_long)total);
2930
2931	return(result);
2932}
2933#endif
2934