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