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