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