xref: /openbsd/sbin/ifconfig/ifconfig.c (revision d485f761)
1 /*	$OpenBSD: ifconfig.c,v 1.54 2001/11/05 07:39:16 mpech Exp $	*/
2 /*      $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $      */
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 /*-
38  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
39  * All rights reserved.
40  *
41  * This code is derived from software contributed to The NetBSD Foundation
42  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
43  * NASA Ames Research Center.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 3. All advertising materials mentioning features or use of this software
54  *    must display the following acknowledgement:
55  *	This product includes software developed by the NetBSD
56  *	Foundation, Inc. and its contributors.
57  * 4. Neither the name of The NetBSD Foundation nor the names of its
58  *    contributors may be used to endorse or promote products derived
59  *    from this software without specific prior written permission.
60  *
61  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
62  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
63  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
64  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
65  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
66  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
68  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
69  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
70  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
71  * POSSIBILITY OF SUCH DAMAGE.
72  */
73 
74 #ifndef lint
75 static const char copyright[] =
76 "@(#) Copyright (c) 1983, 1993\n\
77 	The Regents of the University of California.  All rights reserved.\n";
78 #endif /* not lint */
79 
80 #ifndef lint
81 #if 0
82 static const char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
83 #else
84 static const char rcsid[] = "$OpenBSD: ifconfig.c,v 1.54 2001/11/05 07:39:16 mpech Exp $";
85 #endif
86 #endif /* not lint */
87 
88 #include <sys/param.h>
89 #include <sys/socket.h>
90 #include <sys/ioctl.h>
91 
92 #include <net/if.h>
93 #include <net/if_dl.h>
94 #include <net/if_media.h>
95 #include <netinet/in.h>
96 #include <netinet/in_var.h>
97 #include <netinet6/nd6.h>
98 #include <arpa/inet.h>
99 #include <netinet/ip_ipsp.h>
100 #include <netinet/if_ether.h>
101 #include <net/if_enc.h>
102 #include <net/if_ieee80211.h>
103 
104 #include <netatalk/at.h>
105 
106 #define	NSIP
107 #include <netns/ns.h>
108 #include <netns/ns_if.h>
109 
110 #define	IPXIP
111 #include <netipx/ipx.h>
112 #include <netipx/ipx_if.h>
113 
114 #include <netdb.h>
115 
116 #define EON
117 #include <netiso/iso.h>
118 #include <netiso/iso_var.h>
119 #include <sys/protosw.h>
120 
121 #ifndef INET_ONLY
122 #include <net/if_vlan_var.h>
123 #endif
124 
125 #include <ctype.h>
126 #include <err.h>
127 #include <errno.h>
128 #include <stdio.h>
129 #include <stdlib.h>
130 #include <string.h>
131 #include <unistd.h>
132 #ifdef HAVE_IFADDRS_H
133 #include <ifaddrs.h>
134 #endif
135 
136 struct	ifreq		ifr, ridreq;
137 struct	ifaliasreq	addreq;
138 #ifdef INET6
139 struct	in6_ifreq	ifr6;
140 struct	in6_ifreq	in6_ridreq;
141 struct	in6_aliasreq	in6_addreq __attribute__((aligned(4)));
142 #endif
143 struct	iso_ifreq	iso_ridreq;
144 struct	iso_aliasreq	iso_addreq;
145 struct	sockaddr_in	netmask;
146 struct  netrange	at_nr;		/* AppleTalk net range */
147 
148 int	ipx_type = ETHERTYPE_II;
149 char	name[IFNAMSIZ];
150 int	flags, metric, mtu, setaddr, setipdst, doalias;
151 int	clearaddr, s;
152 int	newaddr = 0;
153 int	nsellength = 1;
154 int	af = AF_INET;
155 int     dflag, mflag, lflag, uflag;
156 int     reset_if_flags;
157 int	explicit_prefix = 0;
158 #ifdef INET6
159 int	Lflag = 1;
160 #endif
161 
162 void 	notealias __P((char *, int));
163 void 	notrailers __P((char *, int));
164 void 	setifaddr __P((char *, int));
165 void 	setifdstaddr __P((char *, int));
166 void 	setifflags __P((char *, int));
167 void 	setifbroadaddr __P((char *));
168 void 	setifipdst __P((char *));
169 void 	setifmetric __P((char *));
170 void	setifmtu __P((char *, int));
171 void	setifnwid __P((char *, int));
172 void 	setifnetmask __P((char *));
173 void	setifprefixlen __P((char *, int));
174 void 	setnsellength __P((char *));
175 void 	setsnpaoffset __P((char *));
176 void	setipxframetype __P((char *, int));
177 void    setatrange __P((char *, int));
178 void    setatphase __P((char *, int));
179 void    settunnel __P((char *, char *));
180 void    deletetunnel __P((void));
181 #ifdef INET6
182 void 	setia6flags __P((char *, int));
183 void	setia6pltime __P((char *, int));
184 void	setia6vltime __P((char *, int));
185 void	setia6lifetime __P((char *, char *));
186 #endif
187 void    checkatrange __P ((struct sockaddr_at *));
188 void	setmedia __P((char *, int));
189 void	setmediaopt __P((char *, int));
190 void	unsetmediaopt __P((char *, int));
191 void	setmediainst __P((char *, int));
192 void	setvlantag __P((char *, int));
193 void	setvlandev __P((char *, int));
194 void	unsetvlandev __P((char *, int));
195 void	vlan_status ();
196 void	fixnsel __P((struct sockaddr_iso *));
197 int	main __P((int, char *[]));
198 int	prefix __P((void *val, int));
199 
200 /*
201  * Media stuff.  Whenever a media command is first performed, the
202  * currently select media is grabbed for this interface.  If `media'
203  * is given, the current media word is modifed.  `mediaopt' commands
204  * only modify the set and clear words.  They then operate on the
205  * current media word later.
206  */
207 int	media_current;
208 int	mediaopt_set;
209 int	mediaopt_clear;
210 
211 int	actions;			/* Actions performed */
212 
213 #define	A_MEDIA		0x0001		/* media command */
214 #define	A_MEDIAOPTSET	0x0002		/* mediaopt command */
215 #define	A_MEDIAOPTCLR	0x0004		/* -mediaopt command */
216 #define	A_MEDIAOPT	(A_MEDIAOPTSET|A_MEDIAOPTCLR)
217 #define	A_MEDIAINST	0x0008		/* instance or inst command */
218 
219 #define	NEXTARG		0xffffff
220 #define NEXTARG2        0xfffffe
221 
222 const struct	cmd {
223 	char	*c_name;
224 	int	c_parameter;		/* NEXTARG means next argv */
225 	int	c_action;		/* defered action */
226 	void	(*c_func)();
227 } cmds[] = {
228 	{ "up",		IFF_UP,		0,		setifflags } ,
229 	{ "down",	-IFF_UP,	0,		setifflags },
230 	{ "trailers",	-1,		0,		notrailers },
231 	{ "-trailers",	1,		0,		notrailers },
232 	{ "arp",	-IFF_NOARP,	0,		setifflags },
233 	{ "-arp",	IFF_NOARP,	0,		setifflags },
234 	{ "debug",	IFF_DEBUG,	0,		setifflags },
235 	{ "-debug",	-IFF_DEBUG,	0,		setifflags },
236 	{ "alias",	IFF_UP,		0,		notealias },
237 	{ "-alias",	-IFF_UP,	0,		notealias },
238 	{ "delete",	-IFF_UP,	0,		notealias },
239 #ifdef notdef
240 #define	EN_SWABIPS	0x1000
241 	{ "swabips",	EN_SWABIPS,	0,		setifflags },
242 	{ "-swabips",	-EN_SWABIPS,	0,		setifflags },
243 #endif
244 	{ "netmask",	NEXTARG,	0,		setifnetmask },
245 	{ "metric",	NEXTARG,	0,		setifmetric },
246 	{ "mtu",	NEXTARG,	0,		setifmtu },
247 	{ "nwid",	NEXTARG,	0,		setifnwid },
248 	{ "broadcast",	NEXTARG,	0,		setifbroadaddr },
249 	{ "ipdst",	NEXTARG,	0,		setifipdst },
250 	{ "prefixlen",  NEXTARG,	0,		setifprefixlen},
251 #ifdef INET6
252 	{ "anycast",	IN6_IFF_ANYCAST,	0,	setia6flags },
253 	{ "-anycast",	-IN6_IFF_ANYCAST,	0,	setia6flags },
254 	{ "tentative",	IN6_IFF_TENTATIVE,	0,	setia6flags },
255 	{ "-tentative",	-IN6_IFF_TENTATIVE,	0,	setia6flags },
256 	{ "pltime",	NEXTARG,	0,		setia6pltime },
257 	{ "vltime",	NEXTARG,	0,		setia6vltime },
258 #endif /*INET6*/
259 #ifndef INET_ONLY
260 	{ "range",	NEXTARG,	0,		setatrange },
261 	{ "phase",	NEXTARG,	0,		setatphase },
262 	{ "snpaoffset",	NEXTARG,	0,		setsnpaoffset },
263 	{ "nsellength",	NEXTARG,	0,		setnsellength },
264 	{ "802.2",	ETHERTYPE_8022,	0,		setipxframetype },
265 	{ "802.2tr",	ETHERTYPE_8022TR, 0,		setipxframetype },
266 	{ "802.3",	ETHERTYPE_8023,	0,		setipxframetype },
267 	{ "snap",	ETHERTYPE_SNAP,	0,		setipxframetype },
268 	{ "EtherII",	ETHERTYPE_II,	0,		setipxframetype },
269 	{ "vlan",	NEXTARG,	0,		setvlantag },
270 	{ "vlandev",	NEXTARG,	0,		setvlandev },
271 	{ "-vlandev",	1,		0,		unsetvlandev },
272 #endif	/* INET_ONLY */
273 	/* giftunnel is for backward compat */
274 	{ "giftunnel",  NEXTARG2,       0,              settunnel } ,
275 	{ "tunnel",  	NEXTARG2,       0,              settunnel } ,
276 	{ "deletetunnel",  0,       	0,              deletetunnel } ,
277 	{ "link0",	IFF_LINK0,	0,		setifflags } ,
278 	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
279 	{ "link1",	IFF_LINK1,	0,		setifflags } ,
280 	{ "-link1",	-IFF_LINK1,	0,		setifflags } ,
281 	{ "link2",	IFF_LINK2,	0,		setifflags } ,
282 	{ "-link2",	-IFF_LINK2,	0,		setifflags } ,
283 	{ "media",	NEXTARG,	A_MEDIA,	setmedia },
284 	{ "mediaopt",	NEXTARG,	A_MEDIAOPTSET,	setmediaopt },
285 	{ "-mediaopt",	NEXTARG,	A_MEDIAOPTCLR,	unsetmediaopt },
286 	{ "instance",	NEXTARG,	A_MEDIAINST,	setmediainst },
287 	{ "inst",	NEXTARG,	A_MEDIAINST,	setmediainst },
288 	{ NULL, /*src*/	0,		0,		setifaddr },
289 	{ NULL, /*dst*/	0,		0,		setifdstaddr },
290 	{ NULL, /*illegal*/0,		0,		NULL },
291 };
292 
293 void 	adjust_nsellength();
294 int	getinfo __P((struct ifreq *));
295 void	getsock __P((int));
296 void	printif __P((struct ifreq *, int));
297 void 	printb __P((char *, unsigned short, char *));
298 void 	status __P((int));
299 void 	usage();
300 char	*sec2str __P((time_t));
301 
302 const char *get_media_type_string __P((int));
303 const char *get_media_subtype_string __P((int));
304 int	get_media_subtype __P((int, const char *));
305 int	get_media_options __P((int, const char *));
306 int	lookup_media_word __P((const struct ifmedia_description *, int,
307 	    const char *));
308 void	print_media_word __P((int, int, int));
309 void	process_media_commands __P((void));
310 void	init_current_media __P((void));
311 
312 /*
313  * XNS support liberally adapted from code written at the University of
314  * Maryland principally by James O'Toole and Chris Torek.
315  */
316 void	in_status __P((int));
317 void 	in_getaddr __P((char *, int));
318 void 	in_getprefix __P((char *, int));
319 #ifdef INET6
320 void	in6_fillscopeid __P((struct sockaddr_in6 *sin6));
321 void	in6_alias __P((struct in6_ifreq *));
322 void	in6_status __P((int));
323 void 	in6_getaddr __P((char *, int));
324 void 	in6_getprefix __P((char *, int));
325 #endif
326 void    at_status __P((int));
327 void    at_getaddr __P((char *, int));
328 void 	xns_status __P((int));
329 void 	xns_getaddr __P((char *, int));
330 void 	ipx_status __P((int));
331 void 	ipx_getaddr __P((char *, int));
332 void 	iso_status __P((int));
333 void 	iso_getaddr __P((char *, int));
334 void	ieee80211_status __P((void));
335 
336 /* Known address families */
337 const struct afswtch {
338 	char *af_name;
339 	short af_af;
340 	void (*af_status)();
341 	void (*af_getaddr)();
342 	void (*af_getprefix)();
343 	u_long af_difaddr;
344 	u_long af_aifaddr;
345 	caddr_t af_ridreq;
346 	caddr_t af_addreq;
347 } afs[] = {
348 #define C(x) ((caddr_t) &x)
349 	{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
350 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
351 #ifdef INET6
352 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
353 	     SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
354 #endif
355 #ifndef INET_ONLY	/* small version, for boot media */
356 	{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
357 	    SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
358 	{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
359 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
360 	{ "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
361 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
362 	{ "iso", AF_ISO, iso_status, iso_getaddr, NULL,
363 	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
364 #endif	/* INET_ONLY */
365 	{ 0,	0,	    0,		0 }
366 };
367 
368 const struct afswtch *afp;	/*the address family being set or asked about*/
369 
370 int
371 main(argc, argv)
372 	int argc;
373 	char *argv[];
374 {
375 	const struct afswtch *rafp = NULL;
376 	int aflag = 0;
377 	int ifaliases = 0;
378 	int i;
379 
380 	if (argc < 2)
381 		usage();
382 	argc--, argv++;
383 	if (!strcmp(*argv, "-a"))
384 		aflag = 1;
385 	else if (!strcmp(*argv, "-A")) {
386 		aflag = 1;
387 		ifaliases = 1;
388 	}
389 	else if (!strcmp(*argv, "-ma") || !strcmp(*argv, "-am")) {
390 		aflag = 1;
391 		mflag = 1;
392 	}
393 	else if (!strcmp(*argv, "-mA") || !strcmp(*argv, "-Am")) {
394 		aflag = 1;
395 		ifaliases = 1;
396 		mflag = 1;
397 	}
398 	else if (!strcmp(*argv, "-m")) {
399 		mflag = 1;
400 		argc--, argv++;
401 		if (argc < 1)
402 			usage();
403 		(void) strlcpy(name, *argv, sizeof(name));
404 	} else
405 		(void) strlcpy(name, *argv, sizeof(name));
406 	argc--, argv++;
407 	if (argc > 0) {
408 		for (afp = rafp = afs; rafp->af_name; rafp++)
409 			if (strcmp(rafp->af_name, *argv) == 0) {
410 				afp = rafp; argc--; argv++;
411 				break;
412 			}
413 		rafp = afp;
414 		af = ifr.ifr_addr.sa_family = rafp->af_af;
415 	}
416 	if (aflag) {
417 		if (argc > 0)
418 			usage();
419 		printif(NULL, ifaliases);
420 		exit(0);
421 	}
422 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
423 	if (argc == 0) {
424 		printif(&ifr, 1);
425 		exit(0);
426 	}
427 
428 #ifdef INET6
429 	/* initialization */
430 	in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
431 	in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
432 #endif
433 
434 	if (getinfo(&ifr) < 0)
435 		exit(1);
436 	while (argc > 0) {
437 		const struct cmd *p;
438 
439 		for (p = cmds; p->c_name; p++)
440 			if (strcmp(*argv, p->c_name) == 0)
441 				break;
442 		if (p->c_name == 0 && setaddr)
443 			for (i = setaddr; i > 0; i--) {
444 				p++;
445 				if (p->c_func == NULL)
446 					errx(1, "extra address not accepted");
447 			}
448 		if (p->c_func) {
449 			if (p->c_parameter == NEXTARG) {
450 				if (argv[1] == NULL)
451 					errx(1, "'%s' requires argument",
452 					    p->c_name);
453 				(*p->c_func)(argv[1]);
454 				argc--, argv++;
455 			} else if (p->c_parameter == NEXTARG2) {
456 			        if ((argv[1] == NULL) ||
457 				    (argv[2] == NULL))
458 					errx(1, "'%s' requires 2 arguments",
459 					    p->c_name);
460 				(*p->c_func)(argv[1], argv[2]);
461 				argc -= 2;
462 				argv += 2;
463 			} else
464 				(*p->c_func)(*argv, p->c_parameter);
465 			actions |= p->c_action;
466 		}
467 		argc--, argv++;
468 	}
469 
470 	/* Process any media commands that may have been issued. */
471 	process_media_commands();
472 
473 	if (af == AF_INET6 && explicit_prefix == 0) {
474 		/*
475 		 * Aggregatable address architecture defines all prefixes
476 		 * are 64. So, it is convenient to set prefixlen to 64 if
477 		 * it is not specified.
478 		 */
479 		setifprefixlen("64", 0);
480 		/* in6_getprefix("64", MASK) if MASK is available here... */
481 	}
482 
483 #ifndef INET_ONLY
484 
485 	switch (af) {
486 	case AF_ISO:
487 		adjust_nsellength();
488 		break;
489 	case AF_NS:
490 		if (setipdst) {
491 			struct nsip_req rq;
492 			int size = sizeof(rq);
493 
494 			rq.rq_ns = addreq.ifra_addr;
495 			rq.rq_ip = addreq.ifra_dstaddr;
496 
497 			if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
498 				warn("encapsulation routing");
499 		}
500 		break;
501 	case AF_IPX:
502 		if (setipdst) {
503 			struct ipxip_req rq;
504 			int size = sizeof(rq);
505 
506 			rq.rq_ipx = addreq.ifra_addr;
507 			rq.rq_ip = addreq.ifra_dstaddr;
508 
509 			if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
510 				warn("encapsulation routing");
511 		}
512 		break;
513 	case AF_APPLETALK:
514 		checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
515 		break;
516 	}
517 #endif	/* INET_ONLY */
518 
519 	if (clearaddr) {
520 		int ret;
521 		(void) strlcpy(rafp->af_ridreq, name, sizeof(ifr.ifr_name));
522 		if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
523 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
524 				/* means no previous address for interface */
525 			} else
526 				warn("SIOCDIFADDR");
527 		}
528 	}
529 	if (newaddr) {
530 		(void) strlcpy(rafp->af_addreq, name, sizeof(ifr.ifr_name));
531 		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
532 			warn("SIOCAIFADDR");
533 	}
534 	exit(0);
535 }
536 
537 void
538 getsock(naf)
539 	int naf;
540 {
541 	static int oaf = -1;
542 
543 	if (oaf == naf)
544 		return;
545 	if (oaf != -1)
546 		close(s);
547 	s = socket(naf, SOCK_DGRAM, 0);
548 	if (s < 0)
549 		oaf = -1;
550 	else
551 		oaf = naf;
552 }
553 
554 int
555 getinfo(ifr)
556 	struct ifreq *ifr;
557 {
558 
559 	getsock(af);
560 	if (s < 0)
561 		err(1, "socket");
562 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
563 		warn("SIOCGIFFLAGS");
564 		return (-1);
565 	}
566 	flags = ifr->ifr_flags;
567 	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
568 		warn("SIOCGIFMETRIC");
569 		metric = 0;
570 	} else
571 		metric = ifr->ifr_metric;
572 	if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
573 		mtu = 0;
574 	else
575 		mtu = ifr->ifr_mtu;
576 	return (0);
577 }
578 
579 void
580 printif(ifrm, ifaliases)
581 	struct ifreq *ifrm;
582 {
583 #ifdef HAVE_IFADDRS_H
584 	struct ifaddrs *ifap, *ifa;
585 	const char *namep;
586 	struct ifreq *ifrp;
587 	int count = 0, noinet = 1;
588 
589 	if (getifaddrs(&ifap) != 0)
590 		err(1, "getifaddrs");
591 
592 	namep = NULL;
593 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
594 		if (ifrm && strncmp(ifrm->ifr_name, ifa->ifa_name,
595 		    sizeof(ifrm->ifr_name)))
596 			continue;
597 		(void) strlcpy(name, ifa->ifa_name, sizeof(name));
598 		name[sizeof(name) - 1] = '\0';
599 
600 #ifdef INET6
601 		/* quickhack: sizeof(ifr) < sizeof(ifr6) */
602 		if (ifa->ifa_addr->sa_family == AF_INET6) {
603 			ifrp = (struct ifreq *)&ifr6;
604 			memset(&ifr6, 0, sizeof(ifr6));
605 		} else {
606 			ifrp = &ifr;
607 			memset(&ifr, 0, sizeof(ifr));
608 		}
609 #else
610 		ifrp = &ifr;
611 		memset(&ifr, 0, sizeof(ifr));
612 #endif
613 
614 		strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
615 		/* XXX boundary check? */
616 		memcpy(&ifrp->ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
617 
618 		if (ifa->ifa_addr->sa_family == AF_LINK) {
619 			namep = ifa->ifa_name;
620 			if (getinfo(ifrp) < 0)
621 				continue;
622 			status(1);
623 			count++;
624 			noinet = 1;
625 			continue;
626 		}
627 
628 		if (!namep || !strcmp(namep, ifa->ifa_name)) {
629 			const struct afswtch *p;
630 
631 			if (ifa->ifa_addr->sa_family == AF_INET &&
632 			    ifaliases == 0 && noinet == 0)
633 				continue;
634 			if ((p = afp) != NULL) {
635 				if (ifa->ifa_addr->sa_family == p->af_af)
636 					(*p->af_status)(1);
637 			} else {
638 				for (p = afs; p->af_name; p++) {
639 					if (ifa->ifa_addr->sa_family == p->af_af)
640 						(*p->af_status)(0);
641 				}
642 			}
643 			count++;
644 			if (ifa->ifa_addr->sa_family == AF_INET)
645 				noinet = 0;
646 			continue;
647 		}
648 	}
649 	freeifaddrs(ifap);
650 	if (count == 0) {
651 		fprintf(stderr, "%s: no such interface\n", name);
652 		exit(1);
653 	}
654 #else
655 	char *inbuf = NULL;
656 	struct ifconf ifc;
657 	struct ifreq ifreq, *ifrp;
658 	int i, siz, len = 8192;
659 	int count = 0, noinet = 1;
660 	char ifrbuf[8192];
661 
662 	getsock(af);
663 	if (s < 0)
664 		err(1, "socket");
665 	while (1) {
666 		ifc.ifc_len = len;
667 		ifc.ifc_buf = inbuf = realloc(inbuf, len);
668 		if (inbuf == NULL)
669 			err(1, "malloc");
670 		if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
671 			err(1, "SIOCGIFCONF");
672 		if (ifc.ifc_len + sizeof(ifreq) < len)
673 			break;
674 		len *= 2;
675 	}
676 	ifrp = ifc.ifc_req;
677 	ifreq.ifr_name[0] = '\0';
678 	for (i = 0; i < ifc.ifc_len; ) {
679 		ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
680 		memcpy(ifrbuf, ifrp, sizeof(*ifrp));
681 		siz = ((struct ifreq *)ifrbuf)->ifr_addr.sa_len;
682 		if (siz < sizeof(ifrp->ifr_addr))
683 			siz = sizeof(ifrp->ifr_addr);
684 		siz += sizeof(ifrp->ifr_name);
685 		i += siz;
686 		/* avoid alignment issue */
687 		if (sizeof(ifrbuf) < siz)
688 			errx(1, "ifr too big");
689 		memcpy(ifrbuf, ifrp, siz);
690 		ifrp = (struct ifreq *)ifrbuf;
691 
692 		if (ifrm && strncmp(ifrm->ifr_name, ifrp->ifr_name,
693 		    sizeof(ifrp->ifr_name)))
694 			continue;
695 		(void) strlcpy(name, ifrp->ifr_name, sizeof(ifrp->ifr_name));
696 		if (ifrp->ifr_addr.sa_family == AF_LINK) {
697 			ifreq = ifr = *ifrp;
698 			if (getinfo(&ifreq) < 0)
699 				continue;
700 			status(1);
701 			count++;
702 			noinet = 1;
703 			continue;
704 		}
705 		if (!strncmp(ifreq.ifr_name, ifrp->ifr_name,
706 		    sizeof(ifrp->ifr_name))) {
707 			const struct afswtch *p;
708 
709 			if (ifrp->ifr_addr.sa_family == AF_INET &&
710 			    ifaliases == 0 && noinet == 0)
711 				continue;
712 			ifr = *ifrp;
713 #ifdef INET6
714 			/* quickhack: sizeof(ifr) < sizeof(ifr6) */
715 			if (ifrp->ifr_addr.sa_family == AF_INET6)
716 				bcopy(ifrp, &ifr6, sizeof(ifr6));
717 #endif
718 			if ((p = afp) != NULL) {
719 				if (ifr.ifr_addr.sa_family == p->af_af)
720 					(*p->af_status)(1);
721 			} else {
722 				for (p = afs; p->af_name; p++) {
723 					if (ifr.ifr_addr.sa_family == p->af_af)
724 						(*p->af_status)(0);
725 				}
726 			}
727 			count++;
728 			if (ifrp->ifr_addr.sa_family == AF_INET)
729 				noinet = 0;
730 			continue;
731 		}
732 	}
733 	free(inbuf);
734 	if (count == 0) {
735 		fprintf(stderr, "%s: no such interface\n", name);
736 		exit(1);
737 	}
738 #endif
739 }
740 
741 #define RIDADDR 0
742 #define ADDR	1
743 #define MASK	2
744 #define DSTADDR	3
745 
746 /*ARGSUSED*/
747 void
748 setifaddr(addr, param)
749 	char *addr;
750 	int param;
751 {
752 	/*
753 	 * Delay the ioctl to set the interface addr until flags are all set.
754 	 * The address interpretation may depend on the flags,
755 	 * and the flags may change when the address is set.
756 	 */
757 	setaddr++;
758 	newaddr = 1;
759 	if (doalias == 0)
760 		clearaddr = 1;
761 	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
762 }
763 
764 void
765 settunnel(src, dst)
766 	char *src;
767 	char *dst;
768 {
769 	struct addrinfo hints, *srcres, *dstres;
770 	int ecode;
771 	struct if_laddrreq req;
772 
773 	memset(&hints, 0, sizeof(hints));
774 	hints.ai_family = afp->af_af;
775 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
776 
777 	if ((ecode = getaddrinfo(src, NULL, &hints, &srcres)) != 0)
778 		errx(1, "error in parsing address string: %s",
779 		    gai_strerror(ecode));
780 
781 	if ((ecode = getaddrinfo(dst, NULL, &hints, &dstres)) != 0)
782 		errx(1, "error in parsing address string: %s",
783 		    gai_strerror(ecode));
784 
785 	if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
786 		errx(1,
787 		    "source and destination address families do not match");
788 
789 	if (srcres->ai_addrlen > sizeof(req.addr) ||
790 	    dstres->ai_addrlen > sizeof(req.dstaddr))
791 		errx(1, "invalid sockaddr");
792 
793 	memset(&req, 0, sizeof(req));
794 	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
795 	memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
796 	memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
797 	if (ioctl(s, SIOCSLIFPHYADDR, &req) < 0)
798 		warn("SIOCSLIFPHYADDR");
799 
800 	freeaddrinfo(srcres);
801 	freeaddrinfo(dstres);
802 }
803 
804 void
805 deletetunnel()
806 {
807         if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
808                 warn("SIOCDIFPHYADDR");
809 }
810 
811 
812 void
813 setifnetmask(addr)
814 	char *addr;
815 {
816 	(*afp->af_getaddr)(addr, MASK);
817 }
818 
819 void
820 setifbroadaddr(addr)
821 	char *addr;
822 {
823 	(*afp->af_getaddr)(addr, DSTADDR);
824 }
825 
826 void
827 setifipdst(addr)
828 	char *addr;
829 {
830 	in_getaddr(addr, DSTADDR);
831 	setipdst++;
832 	clearaddr = 0;
833 	newaddr = 0;
834 }
835 
836 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
837 /*ARGSUSED*/
838 void
839 notealias(addr, param)
840 	char *addr;
841 	int param;
842 {
843 	if (setaddr && doalias == 0 && param < 0)
844 		memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
845 		    rqtosa(af_addreq)->sa_len);
846 	doalias = param;
847 	if (param < 0) {
848 		clearaddr = 1;
849 		newaddr = 0;
850 	} else
851 		clearaddr = 0;
852 }
853 
854 /*ARGSUSED*/
855 void
856 notrailers(vname, value)
857 	char *vname;
858 	int value;
859 {
860 	printf("Note: trailers are no longer sent, but always received\n");
861 }
862 
863 /*ARGSUSED*/
864 void
865 setifdstaddr(addr, param)
866 	char *addr;
867 	int param;
868 {
869 	setaddr++;
870 	(*afp->af_getaddr)(addr, DSTADDR);
871 }
872 
873 /*
874  * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
875  * of the ifreq structure, which may confuse other parts of ifconfig.
876  * Make a private copy so we can avoid that.
877  */
878 void
879 setifflags(vname, value)
880 	char *vname;
881 	int value;
882 {
883 	struct ifreq my_ifr;
884 
885 	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
886 
887 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0)
888 		err(1, "SIOCGIFFLAGS");
889 	(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name));
890  	flags = my_ifr.ifr_flags;
891 
892 	if (value < 0) {
893 		value = -value;
894 		flags &= ~value;
895 	} else
896 		flags |= value;
897 	my_ifr.ifr_flags = flags;
898 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
899 		err(1, "SIOCSIFFLAGS");
900 }
901 
902 #ifdef INET6
903 void
904 setia6flags(vname, value)
905 	char *vname;
906 	int value;
907 {
908 	if (value < 0) {
909 		value = -value;
910 		in6_addreq.ifra_flags &= ~value;
911 	} else
912 		in6_addreq.ifra_flags |= value;
913 }
914 
915 void
916 setia6pltime(val, d)
917 	char *val;
918 	int d;
919 {
920 	setia6lifetime("pltime", val);
921 }
922 
923 void
924 setia6vltime(val, d)
925 	char *val;
926 	int d;
927 {
928 	setia6lifetime("vltime", val);
929 }
930 
931 void
932 setia6lifetime(cmd, val)
933 	char *cmd;
934 	char *val;
935 {
936 	time_t newval, t;
937 	char *ep;
938 
939 	t = time(NULL);
940 	newval = (time_t)strtoul(val, &ep, 0);
941 	if (val == ep)
942 		errx(1, "invalid %s", cmd);
943 	if (afp->af_af != AF_INET6)
944 		errx(1, "%s not allowed for the AF", cmd);
945 	if (strcmp(cmd, "vltime") == 0) {
946 		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
947 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
948 	} else if (strcmp(cmd, "pltime") == 0) {
949 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
950 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
951 	}
952 }
953 #endif
954 
955 void
956 setifmetric(val)
957 	char *val;
958 {
959 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
960 	ifr.ifr_metric = atoi(val);
961 	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
962 		warn("SIOCSIFMETRIC");
963 }
964 
965 void
966 setifmtu(val, d)
967 	char *val;
968 	int d;
969 {
970 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
971 	ifr.ifr_mtu = atoi(val);
972 	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
973 		warn("SIOCSIFMTU");
974 }
975 
976 void
977 setifnwid(val, d)
978 	char *val;
979 	int d;
980 {
981 	struct ieee80211_nwid nwid;
982 
983 	memset(&nwid, 0, sizeof(nwid));
984 	(void)strlcpy(nwid.i_nwid, val, sizeof(nwid.i_nwid));
985 	nwid.i_len = sizeof(nwid.i_nwid);
986 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
987 	ifr.ifr_data = (caddr_t)&nwid;
988 	if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
989 		warn("SIOCS80211NWID");
990 }
991 
992 void
993 ieee80211_status()
994 {
995 	struct ieee80211_nwid nwid;
996 	char buf[IEEE80211_NWID_LEN + 1];
997 
998 	memset(&ifr, 0, sizeof(ifr));
999 	ifr.ifr_data = (caddr_t)&nwid;
1000 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1001 	if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr) == 0) {
1002 		(void) strlcpy(buf, nwid.i_nwid, sizeof(buf));
1003 		printf("\tnwid %s\n", nwid.i_nwid);
1004 	}
1005 }
1006 
1007 void
1008 init_current_media()
1009 {
1010 	struct ifmediareq ifmr;
1011 
1012 	/*
1013 	 * If we have not yet done so, grab the currently-selected
1014 	 * media.
1015 	 */
1016 	if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1017 		(void) memset(&ifmr, 0, sizeof(ifmr));
1018 		(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1019 
1020 		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1021 			/*
1022 			 * If we get E2BIG, the kernel is telling us
1023 			 * that there are more, so we can ignore it.
1024 			 */
1025 			if (errno != E2BIG)
1026 				err(1, "SGIOCGIFMEDIA");
1027 		}
1028 
1029 		media_current = ifmr.ifm_current;
1030 	}
1031 
1032 	/* Sanity. */
1033 	if (IFM_TYPE(media_current) == 0)
1034 		errx(1, "%s: no link type?", name);
1035 }
1036 
1037 void
1038 process_media_commands()
1039 {
1040 
1041 	if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1042 		/* Nothing to do. */
1043 		return;
1044 	}
1045 
1046 	/*
1047 	 * Media already set up, and commands sanity-checked.  Set/clear
1048 	 * any options, and we're ready to go.
1049 	 */
1050 	media_current |= mediaopt_set;
1051 	media_current &= ~mediaopt_clear;
1052 
1053 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1054 	ifr.ifr_media = media_current;
1055 
1056 	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
1057 		err(1, "SIOCSIFMEDIA");
1058 }
1059 
1060 void
1061 setmedia(val, d)
1062 	char *val;
1063 	int d;
1064 {
1065 	int type, subtype, inst;
1066 
1067 	init_current_media();
1068 
1069 	/* Only one media command may be given. */
1070 	if (actions & A_MEDIA)
1071 		errx(1, "only one `media' command may be issued");
1072 
1073 	/* Must not come after mediaopt commands */
1074 	if (actions & A_MEDIAOPT)
1075 		errx(1, "may not issue `media' after `mediaopt' commands");
1076 
1077 	/*
1078 	 * No need to check if `instance' has been issued; setmediainst()
1079 	 * craps out if `media' has not been specified.
1080 	 */
1081 
1082 	type = IFM_TYPE(media_current);
1083 	inst = IFM_INST(media_current);
1084 
1085 	/* Look up the subtype. */
1086 	subtype = get_media_subtype(type, val);
1087 
1088 	/* Build the new current media word. */
1089 	media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1090 
1091 	/* Media will be set after other processing is complete. */
1092 }
1093 
1094 void
1095 setmediaopt(val, d)
1096 	char *val;
1097 	int d;
1098 {
1099 
1100 	init_current_media();
1101 
1102 	/* Can only issue `mediaopt' once. */
1103 	if (actions & A_MEDIAOPTSET)
1104 		errx(1, "only one `mediaopt' command may be issued");
1105 
1106 	/* Can't issue `mediaopt' if `instance' has already been issued. */
1107 	if (actions & A_MEDIAINST)
1108 		errx(1, "may not issue `mediaopt' after `instance'");
1109 
1110 	mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
1111 
1112 	/* Media will be set after other processing is complete. */
1113 }
1114 
1115 void
1116 unsetmediaopt(val, d)
1117 	char *val;
1118 	int d;
1119 {
1120 
1121 	init_current_media();
1122 
1123 	/* Can only issue `-mediaopt' once. */
1124 	if (actions & A_MEDIAOPTCLR)
1125 		errx(1, "only one `-mediaopt' command may be issued");
1126 
1127 	/* May not issue `media' and `-mediaopt'. */
1128 	if (actions & A_MEDIA)
1129 		errx(1, "may not issue both `media' and `-mediaopt'");
1130 
1131 	/*
1132 	 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1133 	 * implicitly checks for A_MEDIAINST.
1134 	 */
1135 
1136 	mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
1137 
1138 	/* Media will be set after other processing is complete. */
1139 }
1140 
1141 void
1142 setmediainst(val, d)
1143 	char *val;
1144 	int d;
1145 {
1146 	int type, subtype, options, inst;
1147 
1148 	init_current_media();
1149 
1150 	/* Can only issue `instance' once. */
1151 	if (actions & A_MEDIAINST)
1152 		errx(1, "only one `instance' command may be issued");
1153 
1154 	/* Must have already specified `media' */
1155 	if ((actions & A_MEDIA) == 0)
1156 		errx(1, "must specify `media' before `instance'");
1157 
1158 	type = IFM_TYPE(media_current);
1159 	subtype = IFM_SUBTYPE(media_current);
1160 	options = IFM_OPTIONS(media_current);
1161 
1162 	inst = atoi(val);
1163 	if (inst < 0 || inst > IFM_INST_MAX)
1164 		errx(1, "invalid media instance: %s", val);
1165 
1166 	media_current = IFM_MAKEWORD(type, subtype, options, inst);
1167 
1168 	/* Media will be set after other processing is complete. */
1169 }
1170 
1171 const struct ifmedia_description ifm_type_descriptions[] =
1172     IFM_TYPE_DESCRIPTIONS;
1173 
1174 const struct ifmedia_description ifm_subtype_descriptions[] =
1175     IFM_SUBTYPE_DESCRIPTIONS;
1176 
1177 const struct ifmedia_description ifm_option_descriptions[] =
1178     IFM_OPTION_DESCRIPTIONS;
1179 
1180 const char *
1181 get_media_type_string(mword)
1182 	int mword;
1183 {
1184 	const struct ifmedia_description *desc;
1185 
1186 	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
1187 	     desc++) {
1188 		if (IFM_TYPE(mword) == desc->ifmt_word)
1189 			return (desc->ifmt_string);
1190 	}
1191 	return ("<unknown type>");
1192 }
1193 
1194 const char *
1195 get_media_subtype_string(mword)
1196 	int mword;
1197 {
1198 	const struct ifmedia_description *desc;
1199 
1200 	for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
1201 	     desc++) {
1202 		if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
1203 		    IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
1204 			return (desc->ifmt_string);
1205 	}
1206 	return ("<unknown subtype>");
1207 }
1208 
1209 int
1210 get_media_subtype(type, val)
1211 	int type;
1212 	const char *val;
1213 {
1214 	int rval;
1215 
1216 	rval = lookup_media_word(ifm_subtype_descriptions, type, val);
1217 	if (rval == -1)
1218 		errx(1, "unknown %s media subtype: %s",
1219 		    get_media_type_string(type), val);
1220 
1221 	return (rval);
1222 }
1223 
1224 int
1225 get_media_options(type, val)
1226 	int type;
1227 	const char *val;
1228 {
1229 	char *optlist, *str;
1230 	int option, rval = 0;
1231 
1232 	/* We muck with the string, so copy it. */
1233 	optlist = strdup(val);
1234 	if (optlist == NULL)
1235 		err(1, "strdup");
1236 	str = optlist;
1237 
1238 	/*
1239 	 * Look up the options in the user-provided comma-separated list.
1240 	 */
1241 	for (; (str = strtok(str, ",")) != NULL; str = NULL) {
1242 		option = lookup_media_word(ifm_option_descriptions, type, str);
1243 		if (option == -1)
1244 			errx(1, "unknown %s media option: %s",
1245 			    get_media_type_string(type), str);
1246 		rval |= option;
1247 	}
1248 
1249 	free(optlist);
1250 	return (rval);
1251 }
1252 
1253 int
1254 lookup_media_word(desc, type, val)
1255 	const struct ifmedia_description *desc;
1256 	int type;
1257 	const char *val;
1258 {
1259 
1260 	for (; desc->ifmt_string != NULL; desc++) {
1261 		if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
1262 		    strcasecmp(desc->ifmt_string, val) == 0)
1263 			return (desc->ifmt_word);
1264 	}
1265 	return (-1);
1266 }
1267 
1268 void
1269 print_media_word(ifmw, print_type, as_syntax)
1270 	int ifmw, print_type, as_syntax;
1271 {
1272 	const struct ifmedia_description *desc;
1273 	int seen_option = 0;
1274 
1275 	if (print_type)
1276 		printf("%s ", get_media_type_string(ifmw));
1277 	printf("%s%s", as_syntax ? "media " : "",
1278 	    get_media_subtype_string(ifmw));
1279 
1280 	/* Find options. */
1281 	for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
1282 	     desc++) {
1283 		if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
1284 		    (ifmw & desc->ifmt_word) != 0 &&
1285 		    (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
1286 			if (seen_option == 0)
1287 				printf(" %s", as_syntax ? "mediaopt " : "");
1288 			printf("%s%s", seen_option ? "," : "",
1289 			    desc->ifmt_string);
1290 			seen_option |= IFM_OPTIONS(desc->ifmt_word);
1291 		}
1292 	}
1293 	if (IFM_INST(ifmw) != 0)
1294 		printf(" instance %d", IFM_INST(ifmw));
1295 }
1296 
1297 #define	IFFBITS \
1298 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1299 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1300 
1301 static void
1302 phys_status(force)
1303 	int force;
1304 {
1305 	char psrcaddr[NI_MAXHOST];
1306 	char pdstaddr[NI_MAXHOST];
1307 	const char *ver = "";
1308 #ifdef NI_WITHSCOPEID
1309 	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1310 #else
1311 	const int niflag = NI_NUMERICHOST;
1312 #endif
1313 	struct if_laddrreq req;
1314 
1315 	psrcaddr[0] = pdstaddr[0] = '\0';
1316 
1317 	memset(&req, 0, sizeof(req));
1318 	(void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name));
1319 	if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0)
1320 		return;
1321 #ifdef INET6
1322 	if (req.addr.ss_family == AF_INET6)
1323 		in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
1324 #endif
1325 	getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
1326 	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
1327 #ifdef INET6
1328 	if (req.addr.ss_family == AF_INET6)
1329 		ver = "6";
1330 #endif
1331 
1332 #ifdef INET6
1333 	if (req.dstaddr.ss_family == AF_INET6)
1334 		in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
1335 #endif
1336 	getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
1337 	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
1338 
1339 	printf("\tphysical address inet%s %s --> %s\n", ver,
1340 	    psrcaddr, pdstaddr);
1341 }
1342 
1343 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1344 
1345 const struct ifmedia_status_description ifm_status_descriptions[] =
1346 	IFM_STATUS_DESCRIPTIONS;
1347 
1348 /*
1349  * Print the status of the interface.  If an address family was
1350  * specified, show it and it only; otherwise, show them all.
1351  */
1352 void
1353 status(link)
1354 	int link;
1355 {
1356 	const struct afswtch *p = afp;
1357 	struct ifmediareq ifmr;
1358 	int *media_list, i;
1359 
1360 	printf("%s: ", name);
1361 	printb("flags", flags, IFFBITS);
1362 	if (metric)
1363 		printf(" metric %d", metric);
1364 	if (mtu)
1365 		printf(" mtu %d", mtu);
1366 	putchar('\n');
1367 
1368 #ifndef	INET_ONLY
1369 	vlan_status();
1370 #endif
1371 	ieee80211_status();
1372 
1373 	(void) memset(&ifmr, 0, sizeof(ifmr));
1374 	(void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1375 
1376 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1377 		/*
1378 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1379 		 */
1380 		goto proto_status;
1381 	}
1382 
1383 	if (ifmr.ifm_count == 0) {
1384 		warnx("%s: no media types?", name);
1385 		goto proto_status;
1386 	}
1387 
1388 	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1389 	if (media_list == NULL)
1390 		err(1, "malloc");
1391 	ifmr.ifm_ulist = media_list;
1392 
1393 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
1394 		err(1, "SIOCGIFMEDIA");
1395 
1396 	printf("\tmedia: ");
1397 	print_media_word(ifmr.ifm_current, 1, 0);
1398 	if (ifmr.ifm_active != ifmr.ifm_current) {
1399 		putchar(' ');
1400 		putchar('(');
1401 		print_media_word(ifmr.ifm_active, 0, 0);
1402 		putchar(')');
1403 	}
1404 	putchar('\n');
1405 
1406 	if (ifmr.ifm_status & IFM_AVALID) {
1407 		const struct ifmedia_status_description *ifms;
1408 		int bitno, found = 0;
1409 
1410 		printf("\tstatus: ");
1411 		for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1412 			for (ifms = ifm_status_descriptions;
1413 			     ifms->ifms_valid != 0; ifms++) {
1414 				if (ifms->ifms_type !=
1415 				      IFM_TYPE(ifmr.ifm_current) ||
1416 				    ifms->ifms_valid !=
1417 				      ifm_status_valid_list[bitno])
1418 					continue;
1419 				printf("%s%s", found ? ", " : "",
1420 				    IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1421 				found = 1;
1422 
1423 				/*
1424 				 * For each valid indicator bit, there's
1425 				 * only one entry for each media type, so
1426 				 * terminate the inner loop now.
1427 				 */
1428 				break;
1429 			}
1430 		}
1431 
1432 		if (found == 0)
1433 			printf("unknown");
1434 		putchar('\n');
1435 	}
1436 
1437 	if (mflag) {
1438 		int type, printed_type = 0;
1439 
1440 		for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
1441 			for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
1442 				if (IFM_TYPE(media_list[i]) == type) {
1443 					if (printed_type == 0) {
1444 					    printf("\tsupported media:\n");
1445 					    printed_type = 1;
1446 					}
1447 					printf("\t\t");
1448 					print_media_word(media_list[i], 0, 1);
1449 					printf("\n");
1450 				}
1451 			}
1452 		}
1453 	}
1454 
1455 	free(media_list);
1456 
1457  proto_status:
1458 	if (link == 0) {
1459 		if ((p = afp) != NULL) {
1460 			(*p->af_status)(1);
1461 		} else for (p = afs; p->af_name; p++) {
1462 			ifr.ifr_addr.sa_family = p->af_af;
1463 			(*p->af_status)(0);
1464 		}
1465 	}
1466 
1467 	phys_status(0);
1468 }
1469 
1470 
1471 void
1472 in_status(force)
1473 	int force;
1474 {
1475 	struct sockaddr_in *sin, sin2;
1476 	char *inet_ntoa();
1477 
1478 	getsock(AF_INET);
1479 	if (s < 0) {
1480 		if (errno == EPROTONOSUPPORT)
1481 			return;
1482 		err(1, "socket");
1483 	}
1484 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1485 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1486 
1487 	/*
1488 	 * We keep the interface address and reset it before each
1489 	 * ioctl() so we can get ifaliases information (as opposed
1490  	 * to the primary interface netmask/dstaddr/broadaddr, if
1491 	 * the ifr_addr field is zero).
1492 	 */
1493 	memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
1494 
1495 	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1496 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1497 	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1498 		if (errno != EADDRNOTAVAIL)
1499 			warn("SIOCGIFNETMASK");
1500 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1501 	} else
1502 		netmask.sin_addr =
1503 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1504 	if (flags & IFF_POINTOPOINT) {
1505 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1506 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1507 			if (errno == EADDRNOTAVAIL)
1508 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1509 			else
1510 			    warn("SIOCGIFDSTADDR");
1511 		}
1512 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1513 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1514 		printf("--> %s ", inet_ntoa(sin->sin_addr));
1515 	}
1516 	printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1517 	if (flags & IFF_BROADCAST) {
1518 		memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
1519 		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1520 			if (errno == EADDRNOTAVAIL)
1521 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1522 			else
1523 			    warn("SIOCGIFBRDADDR");
1524 		}
1525 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1526 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
1527 		if (sin->sin_addr.s_addr != 0)
1528 			printf("broadcast %s", inet_ntoa(sin->sin_addr));
1529 	}
1530 	putchar('\n');
1531 }
1532 
1533 void
1534 setifprefixlen(addr, d)
1535 	char *addr;
1536 	int d;
1537 {
1538 	if (*afp->af_getprefix)
1539 		(*afp->af_getprefix)(addr, MASK);
1540 	explicit_prefix = 1;
1541 }
1542 
1543 #ifdef INET6
1544 void
1545 in6_fillscopeid(sin6)
1546 	struct sockaddr_in6 *sin6;
1547 {
1548 #if defined(__KAME__) && defined(KAME_SCOPEID)
1549 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1550 		sin6->sin6_scope_id =
1551 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1552 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1553 	}
1554 #endif
1555 }
1556 
1557 /* XXX not really an alias */
1558 void
1559 in6_alias(creq)
1560 	struct in6_ifreq *creq;
1561 {
1562 	struct sockaddr_in6 *sin6;
1563 	struct	in6_ifreq ifr6;		/* shadows file static variable */
1564 	u_int32_t scopeid;
1565 	char hbuf[NI_MAXHOST];
1566 #ifdef NI_WITHSCOPEID
1567 	const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1568 #else
1569 	const int niflag = NI_NUMERICHOST;
1570 #endif
1571 
1572 	/* Get the non-alias address for this interface. */
1573 	getsock(AF_INET6);
1574 	if (s < 0) {
1575 		if (errno == EPROTONOSUPPORT)
1576 			return;
1577 		err(1, "socket");
1578 	}
1579 
1580 	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
1581 
1582 	in6_fillscopeid(sin6);
1583 	scopeid = sin6->sin6_scope_id;
1584 	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1585 			hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1586 		strcpy(hbuf, "");
1587 	printf("\tinet6 %s", hbuf);
1588 
1589 	if (flags & IFF_POINTOPOINT) {
1590 		(void) memset(&ifr6, 0, sizeof(ifr6));
1591 		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1592 		ifr6.ifr_addr = creq->ifr_addr;
1593 		if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
1594 			if (errno != EADDRNOTAVAIL)
1595 				warn("SIOCGIFDSTADDR_IN6");
1596 			(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
1597 			ifr6.ifr_addr.sin6_family = AF_INET6;
1598 			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1599 		}
1600 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1601 		in6_fillscopeid(sin6);
1602 		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1603 				hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
1604 			strcpy(hbuf, "");
1605 		printf(" -> %s", hbuf);
1606 	}
1607 
1608 	(void) memset(&ifr6, 0, sizeof(ifr6));
1609 	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1610 	ifr6.ifr_addr = creq->ifr_addr;
1611 	if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
1612 		if (errno != EADDRNOTAVAIL)
1613 			warn("SIOCGIFNETMASK_IN6");
1614 	} else {
1615 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1616 		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
1617 					       sizeof(struct in6_addr)));
1618 	}
1619 
1620 	(void) memset(&ifr6, 0, sizeof(ifr6));
1621 	(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1622 	ifr6.ifr_addr = creq->ifr_addr;
1623 	if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
1624 		if (errno != EADDRNOTAVAIL)
1625 			warn("SIOCGIFAFLAG_IN6");
1626 	} else {
1627 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
1628 			printf(" anycast");
1629 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
1630 			printf(" tentative");
1631 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
1632 			printf(" duplicated");
1633 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
1634 			printf(" detached");
1635 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
1636 			printf(" deprecated");
1637 	}
1638 
1639 	if (scopeid)
1640 		printf(" scopeid 0x%x", scopeid);
1641 
1642 	if (Lflag) {
1643 		struct in6_addrlifetime *lifetime;
1644 		(void) memset(&ifr6, 0, sizeof(ifr6));
1645 		(void) strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1646 		ifr6.ifr_addr = creq->ifr_addr;
1647 		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
1648 		if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
1649 			if (errno != EADDRNOTAVAIL)
1650 				warn("SIOCGIFALIFETIME_IN6");
1651 		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
1652 			time_t t = time(NULL);
1653 			printf(" pltime ");
1654 			if (lifetime->ia6t_preferred) {
1655 				printf("%s", lifetime->ia6t_preferred < t
1656 					? "0"
1657 					: sec2str(lifetime->ia6t_preferred - t));
1658 			} else
1659 				printf("infty");
1660 
1661 			printf(" vltime ");
1662 			if (lifetime->ia6t_expire) {
1663 				printf("%s", lifetime->ia6t_expire < t
1664 					? "0"
1665 					: sec2str(lifetime->ia6t_expire - t));
1666 			} else
1667 				printf("infty");
1668 		}
1669 	}
1670 
1671 	printf("\n");
1672 }
1673 
1674 void
1675 in6_status(force)
1676 	int force;
1677 {
1678 	in6_alias((struct in6_ifreq *)&ifr6);
1679 }
1680 #endif /*INET6*/
1681 
1682 #ifndef INET_ONLY
1683 
1684 void
1685 at_status(force)
1686 	int force;
1687 {
1688 	struct sockaddr_at *sat, null_sat;
1689 	struct netrange *nr;
1690 
1691 	getsock(AF_APPLETALK);
1692 	if (s < 0) {
1693 		if (errno == EPROTONOSUPPORT)
1694 			return;
1695 		err(1, "socket");
1696 	}
1697 	(void) memset(&ifr, 0, sizeof(ifr));
1698 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1699 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1700 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1701 			if (!force)
1702 				return;
1703 			(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1704 		} else
1705 			warn("SIOCGIFADDR");
1706 	}
1707 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1708 	sat = (struct sockaddr_at *)&ifr.ifr_addr;
1709 
1710 	(void) memset(&null_sat, 0, sizeof(null_sat));
1711 
1712 	nr = (struct netrange *) &sat->sat_zero;
1713 	printf("\tAppleTalk %d.%d range %d-%d phase %d",
1714 	    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
1715 	    ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
1716 	if (flags & IFF_POINTOPOINT) {
1717 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1718 			if (errno == EADDRNOTAVAIL)
1719 			    (void) memset(&ifr.ifr_addr, 0,
1720 				sizeof(ifr.ifr_addr));
1721 			else
1722 			    warn("SIOCGIFDSTADDR");
1723 		}
1724 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1725 		sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
1726 		if (!sat)
1727 			sat = &null_sat;
1728 		printf("--> %d.%d",
1729 		    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
1730 	}
1731 	if (flags & IFF_BROADCAST) {
1732 		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
1733 		sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
1734 		if (sat)
1735 			printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
1736 			    sat->sat_addr.s_node);
1737 	}
1738 	putchar('\n');
1739 }
1740 
1741 void
1742 xns_status(force)
1743 	int force;
1744 {
1745 	struct sockaddr_ns *sns;
1746 
1747 	getsock(AF_NS);
1748 	if (s < 0) {
1749 		if (errno == EPROTONOSUPPORT)
1750 			return;
1751 		err(1, "socket");
1752 	}
1753 	memset(&ifr, 0, sizeof(ifr));
1754 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1755 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1756 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1757 			if (!force)
1758 				return;
1759 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1760 		} else
1761 			warn("SIOCGIFADDR");
1762 	}
1763 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1764 	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1765 	printf("\tns %s ", ns_ntoa(sns->sns_addr));
1766 	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1767 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1768 			if (errno == EADDRNOTAVAIL)
1769 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1770 			else
1771 			    warn("SIOCGIFDSTADDR");
1772 		}
1773 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1774 		sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1775 		printf("--> %s ", ns_ntoa(sns->sns_addr));
1776 	}
1777 	putchar('\n');
1778 }
1779 
1780 void
1781 setipxframetype(vname, type)
1782 	char	*vname;
1783 	int	type;
1784 {
1785 	ipx_type = type;
1786 }
1787 
1788 void
1789 ipx_status(force)
1790 	int force;
1791 {
1792 	struct sockaddr_ipx *sipx;
1793 
1794 	getsock(AF_IPX);
1795 	if (s < 0) {
1796 		if (errno == EPROTONOSUPPORT)
1797 			return;
1798 		err(1, "socket");
1799 	}
1800 	memset(&ifr, 0, sizeof(ifr));
1801 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1802 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1803 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1804 			if (!force)
1805 				return;
1806 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1807 		} else
1808 			warn("SIOCGIFADDR");
1809 	}
1810 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1811 	sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;
1812 	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
1813 	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1814 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1815 			if (errno == EADDRNOTAVAIL)
1816 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1817 			else
1818 			    warn("SIOCGIFDSTADDR");
1819 		}
1820 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1821 		sipx = (struct sockaddr_ipx *)&ifr.ifr_dstaddr;
1822 		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
1823 	}
1824 	{
1825 		struct frame_types {
1826 			int	type;
1827 			char	*name;
1828 		} *p, frames[] = {
1829 			{ ETHERTYPE_8022, "802.2" },
1830 			{ ETHERTYPE_8022TR, "802.2tr" },
1831 			{ ETHERTYPE_8023, "802.3" },
1832 			{ ETHERTYPE_SNAP, "SNAP" },
1833 			{ ETHERTYPE_II,  "EtherII" },
1834 			{ 0, NULL }
1835 		};
1836 		for (p = frames; p->name && p->type != sipx->sipx_type; p++);
1837 		if (p->name != NULL)
1838 			printf("frame %s ", p->name);
1839 	}
1840 	putchar('\n');
1841 }
1842 
1843 void
1844 iso_status(force)
1845 	int force;
1846 {
1847 	struct sockaddr_iso *siso;
1848 	struct iso_ifreq ifr;
1849 
1850 	getsock(AF_ISO);
1851 	if (s < 0) {
1852 		if (errno == EPROTONOSUPPORT)
1853 			return;
1854 		err(1, "socket");
1855 	}
1856 	memset(&ifr, 0, sizeof(ifr));
1857 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1858 	if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&ifr) < 0) {
1859 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1860 			if (!force)
1861 				return;
1862 			memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
1863 		} else
1864 			warn("SIOCGIFADDR_ISO");
1865 	}
1866 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1867 	siso = &ifr.ifr_Addr;
1868 	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1869 	if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&ifr) < 0) {
1870 		if (errno == EADDRNOTAVAIL)
1871 			memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
1872 		else
1873 			warn("SIOCGIFNETMASK_ISO");
1874 	} else {
1875 		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1876 	}
1877 	if (flags & IFF_POINTOPOINT) {
1878 		if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
1879 			if (errno == EADDRNOTAVAIL)
1880 			    memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
1881 			else
1882 			    warn("SIOCGIFDSTADDR_ISO");
1883 		}
1884 		(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1885 		siso = &ifr.ifr_Addr;
1886 		printf("--> %s ", iso_ntoa(&siso->siso_addr));
1887 	}
1888 	putchar('\n');
1889 }
1890 
1891 #endif	/* INET_ONLY */
1892 
1893 struct	in_addr inet_makeaddr();
1894 
1895 #define SIN(x) ((struct sockaddr_in *) &(x))
1896 struct sockaddr_in *sintab[] = {
1897 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1898 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1899 
1900 void
1901 in_getaddr(s, which)
1902 	char *s;
1903 	int which;
1904 {
1905 	struct sockaddr_in *sin = sintab[which];
1906 	struct hostent *hp;
1907 	struct netent *np;
1908 
1909 	sin->sin_len = sizeof(*sin);
1910 	if (which != MASK)
1911 		sin->sin_family = AF_INET;
1912 
1913 	if (inet_aton(s, &sin->sin_addr) == 0) {
1914 		if ((hp = gethostbyname(s)))
1915 			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1916 		else if ((np = getnetbyname(s)))
1917 			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1918 		else
1919 			errx(1, "%s: bad value", s);
1920 	}
1921 }
1922 
1923 void
1924 in_getprefix(plen, which)
1925 	char *plen;
1926 	int which;
1927 {
1928 	struct sockaddr_in *sin = sintab[which];
1929 	u_char *cp;
1930 	int len = strtol(plen, (char **)NULL, 10);
1931 
1932 	if ((len < 0) || (len > 32))
1933 		errx(1, "%s: bad value", plen);
1934 	sin->sin_len = sizeof(*sin);
1935 	if (which != MASK)
1936 		sin->sin_family = AF_INET;
1937 	if ((len == 0) || (len == 32)) {
1938 		memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
1939 		return;
1940 	}
1941 	memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
1942 	for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
1943 		*cp++ = 0xff;
1944 	if (len)
1945 		*cp = 0xff << (8 - len);
1946 }
1947 
1948 /*
1949  * Print a value a la the %b format of the kernel's printf
1950  */
1951 void
1952 printb(s, v, bits)
1953 	char *s;
1954 	char *bits;
1955 	unsigned short v;
1956 {
1957 	int i, any = 0;
1958 	char c;
1959 
1960 	if (bits && *bits == 8)
1961 		printf("%s=%o", s, v);
1962 	else
1963 		printf("%s=%x", s, v);
1964 	bits++;
1965 	if (bits) {
1966 		putchar('<');
1967 		while ((i = *bits++)) {
1968 			if (v & (1 << (i-1))) {
1969 				if (any)
1970 					putchar(',');
1971 				any = 1;
1972 				for (; (c = *bits) > 32; bits++)
1973 					putchar(c);
1974 			} else
1975 				for (; *bits > 32; bits++)
1976 					;
1977 		}
1978 		putchar('>');
1979 	}
1980 }
1981 
1982 #ifdef INET6
1983 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
1984 struct sockaddr_in6 *sin6tab[] = {
1985 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
1986 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
1987 
1988 void
1989 in6_getaddr(s, which)
1990 	char *s;
1991 	int which;
1992 {
1993 #ifndef KAME_SCOPEID
1994 	struct sockaddr_in6 *sin6 = sin6tab[which];
1995 
1996 	sin->sin6_len = sizeof(*sin6);
1997 	if (which != MASK)
1998 		sin6->sin6_family = AF_INET6;
1999 
2000 	if (inet_pton(AF_INET6, s, &sin6->sin6_addr) != 1)
2001 		errx(1, "%s: bad value", s);
2002 #else
2003 	struct sockaddr_in6 *sin6 = sin6tab[which];
2004 	struct addrinfo hints, *res;
2005 	int error;
2006 
2007 	memset(&hints, 0, sizeof(hints));
2008 	hints.ai_family = AF_INET6;
2009 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
2010 	error = getaddrinfo(s, "0", &hints, &res);
2011 	if (error)
2012 		errx(1, "%s: %s", s, gai_strerror(error));
2013 	if (res->ai_addrlen != sizeof(struct sockaddr_in6))
2014 		errx(1, "%s: bad value", s);
2015 	memcpy(sin6, res->ai_addr, res->ai_addrlen);
2016 #ifdef __KAME__
2017 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
2018 	    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
2019 	    sin6->sin6_scope_id) {
2020 		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
2021 		    htons(sin6->sin6_scope_id & 0xffff);
2022 		sin6->sin6_scope_id = 0;
2023 	}
2024 #endif
2025 	freeaddrinfo(res);
2026 #endif
2027 }
2028 
2029 void
2030 in6_getprefix(plen, which)
2031 	char *plen;
2032 	int which;
2033 {
2034 	struct sockaddr_in6 *sin = sin6tab[which];
2035 	u_char *cp;
2036 	int len = strtol(plen, (char **)NULL, 10);
2037 
2038 	if ((len < 0) || (len > 128))
2039 		errx(1, "%s: bad value", plen);
2040 	sin->sin6_len = sizeof(*sin);
2041 	if (which != MASK)
2042 		sin->sin6_family = AF_INET6;
2043 	if ((len == 0) || (len == 128)) {
2044 		memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
2045 		return;
2046 	}
2047 	memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
2048 	for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
2049 		*cp++ = 0xff;
2050 	if (len)
2051 		*cp = 0xff << (8 - len);
2052 }
2053 
2054 int
2055 prefix(val, size)
2056 	void *val;
2057 	int size;
2058 {
2059 	u_char *name = (u_char *)val;
2060 	int byte, bit, plen = 0;
2061 
2062 	for (byte = 0; byte < size; byte++, plen += 8)
2063 		if (name[byte] != 0xff)
2064 			break;
2065 	if (byte == size)
2066 		return (plen);
2067 	for (bit = 7; bit != 0; bit--, plen++)
2068 		if (!(name[byte] & (1 << bit)))
2069 			break;
2070 	for (; bit != 0; bit--)
2071 		if (name[byte] & (1 << bit))
2072 			return(0);
2073 	byte++;
2074 	for (; byte < size; byte++)
2075 		if (name[byte])
2076 			return(0);
2077 	return (plen);
2078 }
2079 #endif /*INET6*/
2080 
2081 #ifndef INET_ONLY
2082 void
2083 at_getaddr(addr, which)
2084 	char *addr;
2085 	int which;
2086 {
2087 	struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
2088 	u_int net, node;
2089 
2090 	sat->sat_family = AF_APPLETALK;
2091 	sat->sat_len = sizeof(*sat);
2092 	if (which == MASK)
2093 		errx(1, "AppleTalk does not use netmasks");
2094 	if (sscanf(addr, "%u.%u", &net, &node) != 2 ||
2095 	    net == 0 || net > 0xffff || node == 0 || node > 0xfe)
2096 		errx(1, "%s: illegal address", addr);
2097 	sat->sat_addr.s_net = htons(net);
2098 	sat->sat_addr.s_node = node;
2099 }
2100 
2101 void
2102 setatrange(range, d)
2103 	char *range;
2104 	int d;
2105 {
2106 	u_short first = 123, last = 123;
2107 
2108 	if (sscanf(range, "%hu-%hu", &first, &last) != 2 ||
2109 	    first == 0 || first > 0xffff ||
2110 	    last == 0 || last > 0xffff || first > last)
2111 		errx(1, "%s: illegal net range: %u-%u", range, first, last);
2112 	at_nr.nr_firstnet = htons(first);
2113 	at_nr.nr_lastnet = htons(last);
2114 }
2115 
2116 void
2117 setatphase(phase, d)
2118 	char *phase;
2119 	int d;
2120 {
2121 	if (!strcmp(phase, "1"))
2122 		at_nr.nr_phase = 1;
2123 	else if (!strcmp(phase, "2"))
2124 		at_nr.nr_phase = 2;
2125 	else
2126 		errx(1, "%s: illegal phase", phase);
2127 }
2128 
2129 void
2130 checkatrange(sat)
2131 	struct sockaddr_at *sat;
2132 {
2133 	if (at_nr.nr_phase == 0)
2134 		at_nr.nr_phase = 2;     /* Default phase 2 */
2135 	if (at_nr.nr_firstnet == 0)	/* Default range of one */
2136 		at_nr.nr_firstnet = at_nr.nr_lastnet = sat->sat_addr.s_net;
2137 	printf("\tatalk %d.%d range %d-%d phase %d\n",
2138 	ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2139 	ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
2140 	if ((u_short) ntohs(at_nr.nr_firstnet) >
2141 	    (u_short) ntohs(sat->sat_addr.s_net) ||
2142 	    (u_short) ntohs(at_nr.nr_lastnet) <
2143 	    (u_short) ntohs(sat->sat_addr.s_net))
2144 		errx(1, "AppleTalk address is not in range");
2145 	*((struct netrange *) &sat->sat_zero) = at_nr;
2146 }
2147 
2148 #define SNS(x) ((struct sockaddr_ns *) &(x))
2149 struct sockaddr_ns *snstab[] = {
2150 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
2151 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
2152 
2153 void
2154 xns_getaddr(addr, which)
2155 	char *addr;
2156 	int which;
2157 {
2158 	struct sockaddr_ns *sns = snstab[which];
2159 	struct ns_addr ns_addr();
2160 
2161 	sns->sns_family = AF_NS;
2162 	sns->sns_len = sizeof(*sns);
2163 	sns->sns_addr = ns_addr(addr);
2164 	if (which == MASK)
2165 		printf("Attempt to set XNS netmask will be ineffectual\n");
2166 }
2167 
2168 #define SIPX(x) ((struct sockaddr_ipx *) &(x))
2169 struct sockaddr_ipx *sipxtab[] = {
2170 SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
2171 SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
2172 
2173 void
2174 ipx_getaddr(addr, which)
2175 	char *addr;
2176 	int which;
2177 {
2178 	struct sockaddr_ipx *sipx = sipxtab[which];
2179 	struct ipx_addr ipx_addr();
2180 
2181 	sipx->sipx_family = AF_IPX;
2182 	sipx->sipx_len  = sizeof(*sipx);
2183 	sipx->sipx_addr = ipx_addr(addr);
2184 	sipx->sipx_type = ipx_type;
2185 	if (which == MASK)
2186 		printf("Attempt to set IPX netmask will be ineffectual\n");
2187 }
2188 
2189 #define SISO(x) ((struct sockaddr_iso *) &(x))
2190 struct sockaddr_iso *sisotab[] = {
2191 SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
2192 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
2193 
2194 void
2195 iso_getaddr(addr, which)
2196 	char *addr;
2197 	int which;
2198 {
2199 	struct sockaddr_iso *siso = sisotab[which];
2200 	struct iso_addr *iso_addr();
2201 	siso->siso_addr = *iso_addr(addr);
2202 
2203 	if (which == MASK) {
2204 		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
2205 		siso->siso_nlen = 0;
2206 	} else {
2207 		siso->siso_len = sizeof(*siso);
2208 		siso->siso_family = AF_ISO;
2209 	}
2210 }
2211 
2212 void
2213 setsnpaoffset(val)
2214 	char *val;
2215 {
2216 	iso_addreq.ifra_snpaoffset = atoi(val);
2217 }
2218 
2219 void
2220 setnsellength(val)
2221 	char *val;
2222 {
2223 	nsellength = atoi(val);
2224 	if (nsellength < 0)
2225 		errx(1, "negative NSEL length is absurd");
2226 	if (afp == 0 || afp->af_af != AF_ISO)
2227 		errx(1, "setting NSEL length valid only for iso");
2228 }
2229 
2230 void
2231 fixnsel(s)
2232 	struct sockaddr_iso *s;
2233 {
2234 	if (s->siso_family == 0)
2235 		return;
2236 	s->siso_tlen = nsellength;
2237 }
2238 
2239 void
2240 adjust_nsellength()
2241 {
2242 	fixnsel(sisotab[RIDADDR]);
2243 	fixnsel(sisotab[ADDR]);
2244 	fixnsel(sisotab[DSTADDR]);
2245 }
2246 
2247 #endif	/* INET_ONLY */
2248 
2249 void
2250 usage()
2251 {
2252 	fprintf(stderr, "usage: ifconfig [ -m ] [ -a ] [ -A ] [ interface ]\n"
2253 		"\t[ [af] [ address [ dest_addr ] ] [ up ] [ down ] "
2254 		"[ netmask mask ] ]\n"
2255 		"\t[media media_type] [mediaopt media_option]\n"
2256 		"\t[ metric n ]\n"
2257 		"\t[ mtu n ]\n"
2258 		"\t[ nwid netword_id ]\n"
2259 		"\t[ tunnel srcaddress dstaddress ]\n"
2260 		"\t[ deletetunnel ]\n"
2261 		"\t[ vlan n vlandev interface ]\n"
2262 		"\t[ arp | -arp ]\n"
2263 		"\t[ -802.2 | -802.3 | -802.2tr | -snap | -EtherII ]\n"
2264 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
2265 		"       ifconfig [-a | -A | -am | -Am] [ af ]\n"
2266 		"       ifconfig -m interface [af]\n");
2267 	exit(1);
2268 }
2269 
2270 #ifndef INET_ONLY
2271 
2272 static int __tag = 0;
2273 static int __have_tag = 0;
2274 
2275 void vlan_status()
2276 {
2277 	struct vlanreq vreq;
2278 
2279 	bzero((char *)&vreq, sizeof(struct vlanreq));
2280 	ifr.ifr_data = (caddr_t)&vreq;
2281 
2282 	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
2283 		return;
2284 
2285 	if (vreq.vlr_tag || (vreq.vlr_parent[0] != '\0'))
2286 		printf("\tvlan: %d parent interface: %s\n",
2287 		       vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
2288 	               "<none>" : vreq.vlr_parent);
2289 
2290 	return;
2291 }
2292 
2293 void setvlantag(val, d)
2294 	char *val;
2295 	int d;
2296 {
2297 	u_int16_t tag;
2298 	struct vlanreq vreq;
2299 
2300 	__tag = tag = atoi(val);
2301 	__have_tag = 1;
2302 
2303 	bzero((char *)&vreq, sizeof(struct vlanreq));
2304 	ifr.ifr_data = (caddr_t)&vreq;
2305 
2306 	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
2307 		err(1, "SIOCGETVLAN");
2308 
2309 	vreq.vlr_tag = tag;
2310 
2311 	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
2312 		err(1, "SIOCSETVLAN");
2313 
2314 	return;
2315 }
2316 
2317 void setvlandev(val, d)
2318 	char *val;
2319 	int d;
2320 {
2321 	struct vlanreq vreq;
2322 
2323 	if (!__have_tag)
2324 		errx(1, "must specify both vlan tag and device");
2325 
2326 	bzero((char *)&vreq, sizeof(struct vlanreq));
2327 	ifr.ifr_data = (caddr_t)&vreq;
2328 
2329 	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
2330 		err(1, "SIOCGETVLAN");
2331 
2332 	(void) strlcpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
2333 	vreq.vlr_tag = __tag;
2334 
2335 	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
2336 		err(1, "SIOCSETVLAN");
2337 
2338 	return;
2339 }
2340 
2341 void unsetvlandev(val, d)
2342 	char *val;
2343 	int d;
2344 {
2345 	struct vlanreq vreq;
2346 
2347 	bzero((char *)&vreq, sizeof(struct vlanreq));
2348 	ifr.ifr_data = (caddr_t)&vreq;
2349 
2350 	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
2351 		err(1, "SIOCGETVLAN");
2352 
2353 	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
2354 	vreq.vlr_tag = 0;
2355 
2356 	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
2357 		err(1, "SIOCSETVLAN");
2358 
2359 	return;
2360 }
2361 
2362 #endif /* INET_ONLY */
2363 
2364 #ifdef INET6
2365 char *
2366 sec2str(total)
2367 	time_t total;
2368 {
2369 	static char result[256];
2370 	int days, hours, mins, secs;
2371 	int first = 1;
2372 	char *p = result;
2373 	char *end = &result[sizeof(result)];
2374 	int n;
2375 
2376 	if (0) {	/*XXX*/
2377 		days = total / 3600 / 24;
2378 		hours = (total / 3600) % 24;
2379 		mins = (total / 60) % 60;
2380 		secs = total % 60;
2381 
2382 		if (days) {
2383 			first = 0;
2384 			n = snprintf(p, end - p, "%dd", days);
2385 			if (n < 0 || n >= end - p)
2386 				return(result);
2387 			p += n;
2388 		}
2389 		if (!first || hours) {
2390 			first = 0;
2391 			n = snprintf(p, end - p, "%dh", hours);
2392 			if (n < 0 || n >= end - p)
2393 				return(result);
2394 			p += n;
2395 		}
2396 		if (!first || mins) {
2397 			first = 0;
2398 			n = snprintf(p, end - p, "%dm", mins);
2399 			if (n < 0 || n >= end - p)
2400 				return(result);
2401 			p += n;
2402 		}
2403 		snprintf(p, end - p, "%ds", secs);
2404 	} else
2405 		snprintf(p, end - p, "%lu", (u_long)total);
2406 
2407 	return(result);
2408 }
2409 #endif
2410