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