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