xref: /netbsd-src/sbin/ifconfig/ifconfig.c (revision 3fe138c1461e710931a50b66f08982c5f52c371f)
1 /*	$NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Jason R. Thorpe.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *	by Jason R. Thorpe.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1983, 1993
37  *	The Regents of the University of California.  All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *	This product includes software developed by the University of
50  *	California, Berkeley and its contributors.
51  * 4. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  */
67 
68 #include <sys/cdefs.h>
69 #ifndef lint
70 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
71 	The Regents of the University of California.  All rights reserved.\n");
72 #endif /* not lint */
73 
74 #ifndef lint
75 #if 0
76 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
77 #else
78 __RCSID("$NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $");
79 #endif
80 #endif /* not lint */
81 
82 #include <sys/param.h>
83 #include <sys/socket.h>
84 #include <sys/ioctl.h>
85 
86 #include <net/if.h>
87 #include <net/if_dl.h>
88 #include <net/if_media.h>
89 #include <netinet/in.h>
90 #include <arpa/inet.h>
91 
92 #include <netatalk/at.h>
93 
94 #define	NSIP
95 #include <netns/ns.h>
96 #include <netns/ns_if.h>
97 #include <netdb.h>
98 
99 #define EON
100 #include <netiso/iso.h>
101 #include <netiso/iso_var.h>
102 #include <sys/protosw.h>
103 
104 #include <ctype.h>
105 #include <err.h>
106 #include <errno.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include <unistd.h>
111 
112 struct	ifreq		ifr, ridreq;
113 struct	ifaliasreq	addreq __attribute__((aligned(4)));
114 struct	iso_aliasreq	iso_addreq;
115 struct	sockaddr_in	netmask;
116 struct	netrange	at_nr;		/* AppleTalk net range */
117 
118 char	name[30];
119 int	flags, metric, mtu, setaddr, setipdst, doalias;
120 int	clearaddr, s;
121 int	newaddr = -1;
122 int	nsellength = 1;
123 int	af;
124 int	dflag, mflag, lflag, uflag;
125 int	reset_if_flags;
126 
127 void 	notealias __P((char *, int));
128 void 	notrailers __P((char *, int));
129 void 	setifaddr __P((char *, int));
130 void 	setifdstaddr __P((char *, int));
131 void 	setifflags __P((char *, int));
132 void 	setifbroadaddr __P((char *, int));
133 void 	setifipdst __P((char *, int));
134 void 	setifmetric __P((char *, int));
135 void 	setifmtu __P((char *, int));
136 void 	setifnetmask __P((char *, int));
137 void 	setnsellength __P((char *, int));
138 void 	setsnpaoffset __P((char *, int));
139 void	setatrange __P((char *, int));
140 void	setatphase __P((char *, int));
141 void	checkatrange __P ((struct sockaddr_at *));
142 void	setmedia __P((char *, int));
143 void	setmediaopt __P((char *, int));
144 void	unsetmediaopt __P((char *, int));
145 void	fixnsel __P((struct sockaddr_iso *));
146 int	main __P((int, char *[]));
147 
148 #define	NEXTARG		0xffffff
149 
150 struct	cmd {
151 	char	*c_name;
152 	int	c_parameter;		/* NEXTARG means next argv */
153 	void	(*c_func) __P((char *, int));
154 } cmds[] = {
155 	{ "up",		IFF_UP,		setifflags } ,
156 	{ "down",	-IFF_UP,	setifflags },
157 	{ "trailers",	-1,		notrailers },
158 	{ "-trailers",	1,		notrailers },
159 	{ "arp",	-IFF_NOARP,	setifflags },
160 	{ "-arp",	IFF_NOARP,	setifflags },
161 	{ "debug",	IFF_DEBUG,	setifflags },
162 	{ "-debug",	-IFF_DEBUG,	setifflags },
163 	{ "alias",	IFF_UP,		notealias },
164 	{ "-alias",	-IFF_UP,	notealias },
165 	{ "delete",	-IFF_UP,	notealias },
166 #ifdef notdef
167 #define	EN_SWABIPS	0x1000
168 	{ "swabips",	EN_SWABIPS,	setifflags },
169 	{ "-swabips",	-EN_SWABIPS,	setifflags },
170 #endif
171 	{ "netmask",	NEXTARG,	setifnetmask },
172 	{ "metric",	NEXTARG,	setifmetric },
173 	{ "mtu",	NEXTARG,	setifmtu },
174 	{ "broadcast",	NEXTARG,	setifbroadaddr },
175 	{ "ipdst",	NEXTARG,	setifipdst },
176 #ifndef INET_ONLY
177 	{ "range",	NEXTARG,	setatrange },
178 	{ "phase",	NEXTARG,	setatphase },
179 	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
180 	{ "nsellength",	NEXTARG,	setnsellength },
181 #endif	/* INET_ONLY */
182 	{ "link0",	IFF_LINK0,	setifflags } ,
183 	{ "-link0",	-IFF_LINK0,	setifflags } ,
184 	{ "link1",	IFF_LINK1,	setifflags } ,
185 	{ "-link1",	-IFF_LINK1,	setifflags } ,
186 	{ "link2",	IFF_LINK2,	setifflags } ,
187 	{ "-link2",	-IFF_LINK2,	setifflags } ,
188 	{ "media",	NEXTARG,	setmedia },
189 	{ "mediaopt",	NEXTARG,	setmediaopt },
190 	{ "-mediaopt",	NEXTARG,	unsetmediaopt },
191 	{ 0,		0,		setifaddr },
192 	{ 0,		0,		setifdstaddr },
193 };
194 
195 void 	adjust_nsellength __P((void));
196 int	getinfo __P((struct ifreq *));
197 void	getsock __P((int));
198 void	printall __P((void));
199 void 	printb __P((char *, unsigned short, char *));
200 void 	status __P((const u_int8_t *, int));
201 void 	usage __P((void));
202 
203 void	domediaopt __P((char *, int));
204 int	get_media_subtype __P((int, char *));
205 int	get_media_options __P((int, char *));
206 int	lookup_media_word __P((struct ifmedia_description *, char *));
207 void	print_media_word __P((int));
208 
209 /*
210  * XNS support liberally adapted from code written at the University of
211  * Maryland principally by James O'Toole and Chris Torek.
212  */
213 void	in_status __P((int));
214 void 	in_getaddr __P((char *, int));
215 void	at_status __P((int));
216 void	at_getaddr __P((char *, int));
217 void 	xns_status __P((int));
218 void 	xns_getaddr __P((char *, int));
219 void 	iso_status __P((int));
220 void 	iso_getaddr __P((char *, int));
221 
222 /* Known address families */
223 struct afswtch {
224 	char *af_name;
225 	short af_af;
226 	void (*af_status) __P((int));
227 	void (*af_getaddr) __P((char *, int));
228 	u_long af_difaddr;
229 	u_long af_aifaddr;
230 	caddr_t af_ridreq;
231 	caddr_t af_addreq;
232 } afs[] = {
233 #define C(x) ((caddr_t) &x)
234 	{ "inet", AF_INET, in_status, in_getaddr,
235 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
236 #ifndef INET_ONLY	/* small version, for boot media */
237 	{ "atalk", AF_APPLETALK, at_status, at_getaddr,
238 	     SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
239 	{ "ns", AF_NS, xns_status, xns_getaddr,
240 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
241 	{ "iso", AF_ISO, iso_status, iso_getaddr,
242 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(iso_addreq) },
243 #endif	/* INET_ONLY */
244 	{ 0,	0,	    0,		0 }
245 };
246 
247 struct afswtch *afp;	/*the address family being set or asked about*/
248 
249 struct afswtch *lookup_af __P((const char *));
250 
251 int
252 main(argc, argv)
253 	int argc;
254 	char *argv[];
255 {
256 	int ch, aflag;
257 
258 	/* Parse command-line options */
259 	aflag = mflag = 0;
260 	while ((ch = getopt(argc, argv, "adlmu")) != -1) {
261 		switch (ch) {
262 		case 'a':
263 			aflag = 1;
264 			break;
265 
266 		case 'd':
267 			dflag = 1;
268 			break;
269 
270 		case 'l':
271 			lflag = 1;
272 			break;
273 
274 		case 'm':
275 			mflag = 1;
276 			break;
277 
278 		case 'u':
279 			uflag = 1;
280 			break;
281 
282 		default:
283 			usage();
284 			/* NOTREACHED */
285 		}
286 	}
287 	argc -= optind;
288 	argv += optind;
289 
290 	/*
291 	 * -l means "list all interfaces", and is mutally exclusive with
292 	 * all other flags/commands.
293 	 *
294 	 * -a means "print status of all interfaces".
295 	 */
296 	if (lflag && (aflag || mflag || argc))
297 		usage();
298 	if (aflag || lflag) {
299 		if (argc > 1)
300 			usage();
301 		else if (argc == 1) {
302 			afp = lookup_af(argv[0]);
303 			if (afp == NULL)
304 				usage();
305 		}
306 		if (afp)
307 			af = ifr.ifr_addr.sa_family = afp->af_af;
308 		else
309 			af = ifr.ifr_addr.sa_family = afs[0].af_af;
310 		printall();
311 		exit(0);
312 	}
313 
314 	/* Make sure there's an interface name. */
315 	if (argc < 1)
316 		usage();
317 	(void) strncpy(name, argv[0], sizeof(name));
318 	argc--; argv++;
319 
320 	/* Check for address family. */
321 	afp = NULL;
322 	if (argc > 0) {
323 		afp = lookup_af(argv[0]);
324 		if (afp != NULL) {
325 			argv++;
326 			argc--;
327 		}
328 	}
329 
330 	if (afp == NULL)
331 		afp = afs;
332 	af = ifr.ifr_addr.sa_family = afp->af_af;
333 
334 	/* Get information about the interface. */
335 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
336 	if (getinfo(&ifr) < 0)
337 		exit(1);
338 
339 	/* No more arguments means interface status. */
340 	if (argc == 0) {
341 		status(NULL, 0);
342 		exit(0);
343 	}
344 
345 	/* Process commands. */
346 	while (argc > 0) {
347 		struct cmd *p;
348 
349 		for (p = cmds; p->c_name; p++)
350 			if (strcmp(argv[0], p->c_name) == 0)
351 				break;
352 		if (p->c_name == 0 && setaddr)
353 			p++;	/* got src, do dst */
354 		if (p->c_func) {
355 			if (p->c_parameter == NEXTARG) {
356 				if (argc < 2)
357 					errx(1, "'%s' requires argument",
358 					    p->c_name);
359 				(*p->c_func)(argv[1], 0);
360 				argc--, argv++;
361 			} else
362 				(*p->c_func)(argv[0], p->c_parameter);
363 		}
364 		argc--, argv++;
365 	}
366 
367 #ifndef INET_ONLY
368 
369 	if (af == AF_ISO)
370 		adjust_nsellength();
371 
372 	if (af == AF_APPLETALK)
373 		checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
374 
375 	if (setipdst && af==AF_NS) {
376 		struct nsip_req rq;
377 		int size = sizeof(rq);
378 
379 		rq.rq_ns = addreq.ifra_addr;
380 		rq.rq_ip = addreq.ifra_dstaddr;
381 
382 		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
383 			warn("encapsulation routing");
384 	}
385 
386 #endif	/* INET_ONLY */
387 
388 	if (clearaddr) {
389 		int ret;
390 		(void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
391 		if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
392 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
393 				/* means no previous address for interface */
394 			} else
395 				warn("SIOCDIFADDR");
396 		}
397 	}
398 	if (newaddr > 0) {
399 		(void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
400 		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
401 			warn("SIOCAIFADDR");
402 	}
403 	if (reset_if_flags && ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
404 		err(1, "SIOCSIFFLAGS");
405 	exit(0);
406 }
407 
408 struct afswtch *
409 lookup_af(cp)
410 	const char *cp;
411 {
412 	struct afswtch *a;
413 
414 	for (a = afs; a->af_name != NULL; a++)
415 		if (strcmp(a->af_name, cp) == 0)
416 			return (a);
417 	return (NULL);
418 }
419 
420 void
421 getsock(naf)
422 	int naf;
423 {
424 	static int oaf = -1;
425 
426 	if (oaf == naf)
427 		return;
428 	if (oaf != -1)
429 		close(s);
430 	s = socket(naf, SOCK_DGRAM, 0);
431 	if (s < 0)
432 		oaf = -1;
433 	else
434 		oaf = naf;
435 }
436 
437 int
438 getinfo(ifr)
439 	struct ifreq *ifr;
440 {
441 
442 	getsock(af);
443 	if (s < 0)
444 		err(1, "socket");
445 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
446 		warn("SIOCGIFFLAGS %s", ifr->ifr_name);
447 		return (-1);
448 	}
449 	flags = ifr->ifr_flags;
450 	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
451 		warn("SIOCGIFMETRIC %s", ifr->ifr_name);
452 		metric = 0;
453 	} else
454 		metric = ifr->ifr_metric;
455 	if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
456 		mtu = 0;
457 	else
458 		mtu = ifr->ifr_mtu;
459 	return (0);
460 }
461 
462 void
463 printall()
464 {
465 	char inbuf[8192];
466 	const struct sockaddr_dl *sdl = NULL;
467 	struct ifconf ifc;
468 	struct ifreq ifreq, *ifr;
469 	int i, idx;
470 
471 	ifc.ifc_len = sizeof(inbuf);
472 	ifc.ifc_buf = inbuf;
473 	getsock(af);
474 	if (s < 0)
475 		err(1, "socket");
476 	if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
477 		err(1, "SIOCGIFCONF");
478 	ifr = ifc.ifc_req;
479 	ifreq.ifr_name[0] = '\0';
480 	for (i = 0, idx = 0; i < ifc.ifc_len; ) {
481 		ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
482 		i += sizeof(ifr->ifr_name) +
483 			(ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
484 				? ifr->ifr_addr.sa_len
485 				: sizeof(struct sockaddr));
486 		if (ifr->ifr_addr.sa_family == AF_LINK)
487 			sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
488 		if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
489 			     sizeof(ifr->ifr_name)))
490 			continue;
491 		(void) strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
492 		ifreq = *ifr;
493 
494 		if (getinfo(&ifreq) < 0)
495 			continue;
496 		if (dflag && (flags & IFF_UP) != 0)
497 			continue;
498 		if (uflag && (flags & IFF_UP) == 0)
499 			continue;
500 
501 		idx++;
502 		/*
503 		 * Are we just listing the interfaces?
504 		 */
505 		if (lflag) {
506 			if (idx > 1)
507 				putchar(' ');
508 			fputs(name, stdout);
509 			continue;
510 		}
511 
512 		if (sdl == NULL) {
513 			status(NULL, 0);
514 		} else {
515 			status(LLADDR(sdl), sdl->sdl_alen);
516 			sdl = NULL;
517 		}
518 	}
519 	if (lflag)
520 		putchar('\n');
521 }
522 
523 #define RIDADDR 0
524 #define ADDR	1
525 #define MASK	2
526 #define DSTADDR	3
527 
528 /*ARGSUSED*/
529 void
530 setifaddr(addr, param)
531 	char *addr;
532 	int param;
533 {
534 	/*
535 	 * Delay the ioctl to set the interface addr until flags are all set.
536 	 * The address interpretation may depend on the flags,
537 	 * and the flags may change when the address is set.
538 	 */
539 	setaddr++;
540 	if (newaddr == -1)
541 		newaddr = 1;
542 	if (doalias == 0)
543 		clearaddr = 1;
544 	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
545 }
546 
547 void
548 setifnetmask(addr, d)
549 	char *addr;
550 	int d;
551 {
552 	(*afp->af_getaddr)(addr, MASK);
553 }
554 
555 void
556 setifbroadaddr(addr, d)
557 	char *addr;
558 	int d;
559 {
560 	(*afp->af_getaddr)(addr, DSTADDR);
561 }
562 
563 void
564 setifipdst(addr, d)
565 	char *addr;
566 	int d;
567 {
568 	in_getaddr(addr, DSTADDR);
569 	setipdst++;
570 	clearaddr = 0;
571 	newaddr = 0;
572 }
573 
574 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
575 /*ARGSUSED*/
576 void
577 notealias(addr, param)
578 	char *addr;
579 	int param;
580 {
581 	if (setaddr && doalias == 0 && param < 0)
582 		(void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
583 		    rqtosa(af_addreq)->sa_len);
584 	doalias = param;
585 	if (param < 0) {
586 		clearaddr = 1;
587 		newaddr = 0;
588 	} else
589 		clearaddr = 0;
590 }
591 
592 /*ARGSUSED*/
593 void
594 notrailers(vname, value)
595 	char *vname;
596 	int value;
597 {
598 	puts("Note: trailers are no longer sent, but always received");
599 }
600 
601 /*ARGSUSED*/
602 void
603 setifdstaddr(addr, param)
604 	char *addr;
605 	int param;
606 {
607 	(*afp->af_getaddr)(addr, DSTADDR);
608 }
609 
610 void
611 setifflags(vname, value)
612 	char *vname;
613 	int value;
614 {
615  	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
616 		err(1, "SIOCGIFFLAGS");
617 	(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
618  	flags = ifr.ifr_flags;
619 
620 	if (value < 0) {
621 		value = -value;
622 		flags &= ~value;
623 	} else
624 		flags |= value;
625 	ifr.ifr_flags = flags;
626 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
627 		err(1, "SIOCSIFFLAGS");
628 
629 	reset_if_flags = 1;
630 }
631 
632 void
633 setifmetric(val, d)
634 	char *val;
635 	int d;
636 {
637 	(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
638 	ifr.ifr_metric = atoi(val);
639 	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
640 		warn("SIOCSIFMETRIC");
641 }
642 
643 void
644 setifmtu(val, d)
645 	char *val;
646 	int d;
647 {
648 	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
649 	ifr.ifr_mtu = atoi(val);
650 	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
651 		warn("SIOCSIFMTU");
652 }
653 
654 void
655 setmedia(val, d)
656 	char *val;
657 	int d;
658 {
659 	struct ifmediareq ifmr;
660 	int first_type, subtype;
661 
662 	(void) memset(&ifmr, 0, sizeof(ifmr));
663 	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
664 
665 	ifmr.ifm_count = 1;
666 	ifmr.ifm_ulist = &first_type;
667 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
668 		/*
669 		 * If we get E2BIG, the kernel is telling us
670 		 * that there are more, so we can ignore it.
671 		 */
672 		if (errno != E2BIG)
673 			err(1, "SIOCGIFMEDIA");
674 	}
675 
676 	if (ifmr.ifm_count == 0)
677 		errx(1, "%s: no media types?", name);
678 
679 	/*
680 	 * We are primarily concerned with the top-level type.
681 	 * However, "current" may be only IFM_NONE, so we just look
682 	 * for the top-level type in the first "supported type"
683 	 * entry.
684 	 *
685 	 * (I'm assuming that all supported media types for a given
686 	 * interface will be the same top-level type..)
687 	 */
688 	subtype = get_media_subtype(IFM_TYPE(first_type), val);
689 
690 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
691 	ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
692 	    IFM_TYPE(first_type) | subtype;
693 
694 	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
695 		err(1, "SIOCSIFMEDIA");
696 }
697 
698 void
699 setmediaopt(val, d)
700 	char *val;
701 	int d;
702 {
703 
704 	domediaopt(val, 0);
705 }
706 
707 void
708 unsetmediaopt(val, d)
709 	int d;
710 	char *val;
711 {
712 
713 	domediaopt(val, 1);
714 }
715 
716 void
717 domediaopt(val, clear)
718 	char *val;
719 	int clear;
720 {
721 	struct ifmediareq ifmr;
722 	int *mwords, options;
723 
724 	(void) memset(&ifmr, 0, sizeof(ifmr));
725 	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
726 
727 	/*
728 	 * We must go through the motions of reading all
729 	 * supported media because we need to know both
730 	 * the current media type and the top-level type.
731 	 */
732 
733 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
734 		err(1, "SIOCGIFMEDIA");
735 
736 	if (ifmr.ifm_count == 0)
737 		errx(1, "%s: no media types?", name);
738 
739 	mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
740 	if (mwords == NULL)
741 		err(1, "malloc");
742 
743 	ifmr.ifm_ulist = mwords;
744 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
745 		err(1, "SIOCGIFMEDIA");
746 
747 	options = get_media_options(IFM_TYPE(mwords[0]), val);
748 
749 	free(mwords);
750 
751 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
752 	ifr.ifr_media = ifmr.ifm_current;
753 	if (clear)
754 		ifr.ifr_media &= ~options;
755 	else
756 		ifr.ifr_media |= options;
757 
758 	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
759 		err(1, "SIOCSIFMEDIA");
760 }
761 
762 /**********************************************************************
763  * A good chunk of this is duplicated from sys/net/ifmedia.c
764  **********************************************************************/
765 
766 struct ifmedia_description ifm_type_descriptions[] =
767     IFM_TYPE_DESCRIPTIONS;
768 
769 struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
770     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
771 
772 struct ifmedia_description ifm_subtype_ethernet_aliases[] =
773     IFM_SUBTYPE_ETHERNET_ALIASES;
774 
775 struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
776     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
777 
778 struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
779     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
780 
781 struct ifmedia_description ifm_subtype_tokenring_aliases[] =
782     IFM_SUBTYPE_TOKENRING_ALIASES;
783 
784 struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
785     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
786 
787 struct ifmedia_description ifm_subtype_fddi_descriptions[] =
788     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
789 
790 struct ifmedia_description ifm_subtype_fddi_aliases[] =
791     IFM_SUBTYPE_FDDI_ALIASES;
792 
793 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
794     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
795 
796 struct ifmedia_description ifm_subtype_shared_descriptions[] =
797     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
798 
799 struct ifmedia_description ifm_subtype_shared_aliases[] =
800     IFM_SUBTYPE_SHARED_ALIASES;
801 
802 struct ifmedia_description ifm_shared_option_descriptions[] =
803     IFM_SHARED_OPTION_DESCRIPTIONS;
804 
805 struct ifmedia_type_to_subtype {
806 	struct {
807 		struct ifmedia_description *desc;
808 		int alias;
809 	} subtypes[5];
810 	struct {
811 		struct ifmedia_description *desc;
812 		int alias;
813 	} options[3];
814 };
815 
816 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
817 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
818 	{
819 		{
820 			{ &ifm_subtype_shared_descriptions[0], 0 },
821 			{ &ifm_subtype_shared_aliases[0], 1 },
822 			{ &ifm_subtype_ethernet_descriptions[0], 0 },
823 			{ &ifm_subtype_ethernet_aliases[0], 1 },
824 			{ NULL, 0 },
825 		},
826 		{
827 			{ &ifm_shared_option_descriptions[0], 0 },
828 			{ &ifm_subtype_ethernet_option_descriptions[0], 1 },
829 			{ NULL, 0 },
830 		},
831 	},
832 	{
833 		{
834 			{ &ifm_subtype_shared_descriptions[0], 0 },
835 			{ &ifm_subtype_shared_aliases[0], 1 },
836 			{ &ifm_subtype_tokenring_descriptions[0], 0 },
837 			{ &ifm_subtype_tokenring_aliases[0], 1 },
838 			{ NULL, 0 },
839 		},
840 		{
841 			{ &ifm_shared_option_descriptions[0], 0 },
842 			{ &ifm_subtype_tokenring_option_descriptions[0], 1 },
843 			{ NULL, 0 },
844 		},
845 	},
846 	{
847 		{
848 			{ &ifm_subtype_shared_descriptions[0], 0 },
849 			{ &ifm_subtype_shared_aliases[0], 1 },
850 			{ &ifm_subtype_fddi_descriptions[0], 0 },
851 			{ &ifm_subtype_fddi_aliases[0], 1 },
852 			{ NULL, 0 },
853 		},
854 		{
855 			{ &ifm_shared_option_descriptions[0], 0 },
856 			{ &ifm_subtype_fddi_option_descriptions[0], 1 },
857 			{ NULL, 0 },
858 		},
859 	},
860 };
861 
862 int
863 get_media_subtype(type, val)
864 	int type;
865 	char *val;
866 {
867 	struct ifmedia_description *desc;
868 	struct ifmedia_type_to_subtype *ttos;
869 	int rval, i;
870 
871 	/* Find the top-level interface type. */
872 	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
873 	    desc->ifmt_string != NULL; desc++, ttos++)
874 		if (type == desc->ifmt_word)
875 			break;
876 	if (desc->ifmt_string == NULL)
877 		errx(1, "unknown media type 0x%x", type);
878 
879 	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
880 		rval = lookup_media_word(ttos->subtypes[i].desc, val);
881 		if (rval != -1)
882 			return (rval);
883 	}
884 	errx(1, "unknown media subtype: %s", val);
885 	/* NOTREACHED */
886 }
887 
888 int
889 get_media_options(type, val)
890 	int type;
891 	char *val;
892 {
893 	struct ifmedia_description *desc;
894 	struct ifmedia_type_to_subtype *ttos;
895 	char *optlist;
896 	int option = 0, i, rval = 0;
897 
898 	/* We muck with the string, so copy it. */
899 	optlist = strdup(val);
900 	if (optlist == NULL)
901 		err(1, "strdup");
902 	val = optlist;
903 
904 	/* Find the top-level interface type. */
905 	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
906 	    desc->ifmt_string != NULL; desc++, ttos++)
907 		if (type == desc->ifmt_word)
908 			break;
909 	if (desc->ifmt_string == NULL)
910 		errx(1, "unknown media type 0x%x", type);
911 
912 	/*
913 	 * Look up the options in the user-provided comma-separated
914 	 * list.
915 	 */
916 	for (; (val = strtok(val, ",")) != NULL; val = NULL) {
917 		for (i = 0; ttos->options[i].desc != NULL; i++) {
918 			option = lookup_media_word(ttos->options[i].desc, val);
919 			if (option != -1)
920 				break;
921 		}
922 		if (option == 0)
923 			errx(1, "unknown option: %s", val);
924 		rval |= option;
925 	}
926 
927 	free(optlist);
928 	return (rval);
929 }
930 
931 int
932 lookup_media_word(desc, val)
933 	struct ifmedia_description *desc;
934 	char *val;
935 {
936 
937 	for (; desc->ifmt_string != NULL; desc++)
938 		if (strcasecmp(desc->ifmt_string, val) == 0)
939 			return (desc->ifmt_word);
940 
941 	return (-1);
942 }
943 
944 void
945 print_media_word(ifmw)
946 	int ifmw;
947 {
948 	struct ifmedia_description *desc;
949 	struct ifmedia_type_to_subtype *ttos;
950 	int seen_option = 0, i;
951 
952 	/* Find the top-level interface type. */
953 	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
954 	    desc->ifmt_string != NULL; desc++, ttos++)
955 		if (IFM_TYPE(ifmw) == desc->ifmt_word)
956 			break;
957 	if (desc->ifmt_string == NULL) {
958 		printf("<unknown type>");
959 		return;
960 	}
961 
962 	/*
963 	 * Don't print the top-level type; it's not like we can
964 	 * change it, or anything.
965 	 */
966 
967 	/* Find subtype. */
968 	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
969 		if (ttos->subtypes[i].alias)
970 			continue;
971 		for (desc = ttos->subtypes[i].desc;
972 		    desc->ifmt_string != NULL; desc++) {
973 			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
974 				goto got_subtype;
975 		}
976 	}
977 
978 	/* Falling to here means unknown subtype. */
979 	printf("<unknown subtype>");
980 	return;
981 
982  got_subtype:
983 	printf("%s", desc->ifmt_string);
984 
985 	/* Find options. */
986 	for (i = 0; ttos->options[i].desc != NULL; i++) {
987 		if (ttos->options[i].alias)
988 			continue;
989 		for (desc = ttos->options[i].desc;
990 		    desc->ifmt_string != NULL; desc++) {
991 			if (ifmw & desc->ifmt_word) {
992 				if (seen_option == 0)
993 					printf(" <");
994 				printf("%s%s", seen_option++ ? "," : "",
995 				    desc->ifmt_string);
996 			}
997 		}
998 	}
999 	printf("%s", seen_option ? ">" : "");
1000 }
1001 
1002 /**********************************************************************
1003  * ...until here.
1004  **********************************************************************/
1005 
1006 #define	IFFBITS \
1007 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1008 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1009 
1010 /*
1011  * Print the status of the interface.  If an address family was
1012  * specified, show it and it only; otherwise, show them all.
1013  */
1014 void
1015 status(ap, alen)
1016 	const u_int8_t *ap;
1017 	int alen;
1018 {
1019 	struct afswtch *p = afp;
1020 	struct ifmediareq ifmr;
1021 	int *media_list, i;
1022 
1023 	printf("%s: ", name);
1024 	printb("flags", flags, IFFBITS);
1025 	if (metric)
1026 		printf(" metric %d", metric);
1027 	if (mtu)
1028 		printf(" mtu %d", mtu);
1029 	putchar('\n');
1030 	if (ap && alen > 0) {
1031 		printf("\taddress:");
1032 		for (i = 0; i < alen; i++, ap++)
1033 			printf("%c%02x", i > 0 ? ':' : ' ', *ap);
1034 		putchar('\n');
1035 	}
1036 
1037 	(void) memset(&ifmr, 0, sizeof(ifmr));
1038 	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1039 
1040 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1041 		/*
1042 		 * Interface doesn't support SIOC{G,S}IFMEDIA.
1043 		 */
1044 		goto proto_status;
1045 	}
1046 
1047 	if (ifmr.ifm_count == 0) {
1048 		warnx("%s: no media types?", name);
1049 		goto proto_status;
1050 	}
1051 
1052 	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1053 	if (media_list == NULL)
1054 		err(1, "malloc");
1055 	ifmr.ifm_ulist = media_list;
1056 
1057 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
1058 		err(1, "SIOCGIFMEDIA");
1059 
1060 	printf("\tmedia: ");
1061 	print_media_word(ifmr.ifm_current);
1062 	if (ifmr.ifm_active != ifmr.ifm_current) {
1063 		putchar(' ');
1064 		putchar('(');
1065 		print_media_word(ifmr.ifm_active);
1066 		putchar(')');
1067 	}
1068 
1069 	if (ifmr.ifm_status & IFM_AVALID) {
1070 		printf(" status: ");
1071 		switch (IFM_TYPE(ifmr.ifm_active)) {
1072 		case IFM_ETHER:
1073 			if (ifmr.ifm_status & IFM_ACTIVE)
1074 				printf("active");
1075 			else
1076 				printf("no carrier");
1077 			break;
1078 
1079 		case IFM_FDDI:
1080 		case IFM_TOKEN:
1081 			if (ifmr.ifm_status & IFM_ACTIVE)
1082 				printf("inserted");
1083 			else
1084 				printf("no ring");
1085 			break;
1086 		}
1087 	}
1088 
1089 	putchar('\n');
1090 
1091 	if (mflag) {
1092 		printf("\tsupported media:");
1093 		for (i = 0; i < ifmr.ifm_count; i++) {
1094 			putchar(' ');
1095 			print_media_word(media_list[i]);
1096 		}
1097 		putchar('\n');
1098 	}
1099 
1100 	free(media_list);
1101 
1102  proto_status:
1103 	if ((p = afp) != NULL) {
1104 		(*p->af_status)(1);
1105 	} else for (p = afs; p->af_name; p++) {
1106 		ifr.ifr_addr.sa_family = p->af_af;
1107 		(*p->af_status)(0);
1108 	}
1109 }
1110 
1111 void
1112 in_status(force)
1113 	int force;
1114 {
1115 	struct sockaddr_in *sin;
1116 
1117 	getsock(AF_INET);
1118 	if (s < 0) {
1119 		if (errno == EPROTONOSUPPORT)
1120 			return;
1121 		err(1, "socket");
1122 	}
1123 	(void) memset(&ifr, 0, sizeof(ifr));
1124 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1125 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1126 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1127 			if (!force)
1128 				return;
1129 			(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1130 		} else
1131 			warn("SIOCGIFADDR");
1132 	}
1133 	(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1134 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1135 	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1136 	(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1137 	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1138 		if (errno != EADDRNOTAVAIL)
1139 			warn("SIOCGIFNETMASK");
1140 		(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1141 	} else
1142 		netmask.sin_addr =
1143 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1144 	if (flags & IFF_POINTOPOINT) {
1145 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1146 			if (errno == EADDRNOTAVAIL)
1147 			    (void) memset(&ifr.ifr_addr, 0,
1148 				sizeof(ifr.ifr_addr));
1149 			else
1150 			    warn("SIOCGIFDSTADDR");
1151 		}
1152 		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1153 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1154 		printf("--> %s ", inet_ntoa(sin->sin_addr));
1155 	}
1156 	printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1157 	if (flags & IFF_BROADCAST) {
1158 		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1159 			if (errno == EADDRNOTAVAIL)
1160 				(void) memset(&ifr.ifr_addr, 0,
1161 				    sizeof(ifr.ifr_addr));
1162 			else
1163 			    warn("SIOCGIFBRDADDR");
1164 		}
1165 		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1166 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
1167 		if (sin->sin_addr.s_addr != 0)
1168 			printf("broadcast %s", inet_ntoa(sin->sin_addr));
1169 	}
1170 	putchar('\n');
1171 }
1172 
1173 #ifndef INET_ONLY
1174 
1175 void
1176 at_status(force)
1177 	int force;
1178 {
1179 	struct sockaddr_at *sat, null_sat;
1180 	struct netrange *nr;
1181 
1182 	getsock(AF_APPLETALK);
1183 	if (s < 0) {
1184 		if (errno == EPROTONOSUPPORT)
1185 			return;
1186 		err(1, "socket");
1187 	}
1188 	(void) memset(&ifr, 0, sizeof(ifr));
1189 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1190 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1191 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1192 			if (!force)
1193 				return;
1194 			(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1195 		} else
1196 			warn("SIOCGIFADDR");
1197 	}
1198 	(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1199 	sat = (struct sockaddr_at *)&ifr.ifr_addr;
1200 
1201 	(void) memset(&null_sat, 0, sizeof(null_sat));
1202 
1203 	nr = (struct netrange *) &sat->sat_zero;
1204 	printf("\tatalk %d.%d range %d-%d phase %d",
1205 	    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
1206 	    ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
1207 	if (flags & IFF_POINTOPOINT) {
1208 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1209 			if (errno == EADDRNOTAVAIL)
1210 			    (void) memset(&ifr.ifr_addr, 0,
1211 				sizeof(ifr.ifr_addr));
1212 			else
1213 			    warn("SIOCGIFDSTADDR");
1214 		}
1215 		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1216 		sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
1217 		if (!sat)
1218 			sat = &null_sat;
1219 		printf("--> %d.%d",
1220 		    ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
1221 	}
1222 	if (flags & IFF_BROADCAST) {
1223 		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
1224 		sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
1225 		if (sat)
1226 			printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
1227 			    sat->sat_addr.s_node);
1228 	}
1229 	putchar('\n');
1230 }
1231 
1232 void
1233 xns_status(force)
1234 	int force;
1235 {
1236 	struct sockaddr_ns *sns;
1237 
1238 	getsock(AF_NS);
1239 	if (s < 0) {
1240 		if (errno == EPROTONOSUPPORT)
1241 			return;
1242 		err(1, "socket");
1243 	}
1244 	(void) memset(&ifr, 0, sizeof(ifr));
1245 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1246 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1247 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1248 			if (!force)
1249 				return;
1250 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1251 		} else
1252 			warn("SIOCGIFADDR");
1253 	}
1254 	(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1255 	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1256 	printf("\tns %s ", ns_ntoa(sns->sns_addr));
1257 	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1258 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1259 			if (errno == EADDRNOTAVAIL)
1260 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1261 			else
1262 			    warn("SIOCGIFDSTADDR");
1263 		}
1264 		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1265 		sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1266 		printf("--> %s ", ns_ntoa(sns->sns_addr));
1267 	}
1268 	putchar('\n');
1269 }
1270 
1271 void
1272 iso_status(force)
1273 	int force;
1274 {
1275 	struct sockaddr_iso *siso;
1276 
1277 	getsock(AF_ISO);
1278 	if (s < 0) {
1279 		if (errno == EPROTONOSUPPORT)
1280 			return;
1281 		err(1, "socket");
1282 	}
1283 	(void) memset(&ifr, 0, sizeof(ifr));
1284 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1285 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1286 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1287 			if (!force)
1288 				return;
1289 			(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1290 		} else
1291 			warn("SIOCGIFADDR");
1292 	}
1293 	(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1294 	siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1295 	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1296 	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1297 		if (errno == EADDRNOTAVAIL)
1298 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1299 		else
1300 			warn("SIOCGIFNETMASK");
1301 	} else {
1302 		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1303 	}
1304 	if (flags & IFF_POINTOPOINT) {
1305 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1306 			if (errno == EADDRNOTAVAIL)
1307 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1308 			else
1309 			    warn("SIOCGIFDSTADDR");
1310 		}
1311 		(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1312 		siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1313 		printf("--> %s ", iso_ntoa(&siso->siso_addr));
1314 	}
1315 	putchar('\n');
1316 }
1317 
1318 #endif	/* INET_ONLY */
1319 
1320 #define SIN(x) ((struct sockaddr_in *) &(x))
1321 struct sockaddr_in *sintab[] = {
1322 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1323 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1324 
1325 void
1326 in_getaddr(s, which)
1327 	char *s;
1328 	int which;
1329 {
1330 	struct sockaddr_in *sin = sintab[which];
1331 	struct hostent *hp;
1332 	struct netent *np;
1333 
1334 	sin->sin_len = sizeof(*sin);
1335 	if (which != MASK)
1336 		sin->sin_family = AF_INET;
1337 
1338 	if (inet_aton(s, &sin->sin_addr) == 0) {
1339 		if ((hp = gethostbyname(s)) != NULL)
1340 			(void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1341 		else if ((np = getnetbyname(s)) != NULL)
1342 			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1343 		else
1344 			errx(1, "%s: bad value", s);
1345 	}
1346 }
1347 
1348 /*
1349  * Print a value a la the %b format of the kernel's printf
1350  */
1351 void
1352 printb(s, v, bits)
1353 	char *s;
1354 	char *bits;
1355 	unsigned short v;
1356 {
1357 	int i, any = 0;
1358 	char c;
1359 
1360 	if (bits && *bits == 8)
1361 		printf("%s=%o", s, v);
1362 	else
1363 		printf("%s=%x", s, v);
1364 	bits++;
1365 	if (bits) {
1366 		putchar('<');
1367 		while ((i = *bits++) != 0) {
1368 			if (v & (1 << (i-1))) {
1369 				if (any)
1370 					putchar(',');
1371 				any = 1;
1372 				for (; (c = *bits) > 32; bits++)
1373 					putchar(c);
1374 			} else
1375 				for (; *bits > 32; bits++)
1376 					;
1377 		}
1378 		putchar('>');
1379 	}
1380 }
1381 
1382 #ifndef INET_ONLY
1383 
1384 void
1385 at_getaddr(addr, which)
1386 	char *addr;
1387 	int which;
1388 {
1389 	struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
1390 	u_int net, node;
1391 
1392 	sat->sat_family = AF_APPLETALK;
1393 	sat->sat_len = sizeof(*sat);
1394 	if (which == MASK)
1395 		errx(1, "AppleTalk does not use netmasks\n");
1396 	if (sscanf(addr, "%u.%u", &net, &node) != 2
1397 	    || net == 0 || net > 0xffff || node == 0 || node > 0xfe)
1398 		errx(1, "%s: illegal address", addr);
1399 	sat->sat_addr.s_net = htons(net);
1400 	sat->sat_addr.s_node = node;
1401 }
1402 
1403 void
1404 setatrange(range, d)
1405 	char *range;
1406 	int d;
1407 {
1408 	u_short	first = 123, last = 123;
1409 
1410 	if (sscanf(range, "%hu-%hu", &first, &last) != 2
1411 	    || first == 0 || first > 0xffff
1412 	    || last == 0 || last > 0xffff || first > last)
1413 		errx(1, "%s: illegal net range: %u-%u", range, first, last);
1414 	at_nr.nr_firstnet = htons(first);
1415 	at_nr.nr_lastnet = htons(last);
1416 }
1417 
1418 void
1419 setatphase(phase, d)
1420 	char *phase;
1421 	int d;
1422 {
1423 	if (!strcmp(phase, "1"))
1424 		at_nr.nr_phase = 1;
1425 	else if (!strcmp(phase, "2"))
1426 		at_nr.nr_phase = 2;
1427 	else
1428 		errx(1, "%s: illegal phase", phase);
1429 }
1430 
1431 void
1432 checkatrange(sat)
1433 	struct sockaddr_at *sat;
1434 {
1435 	if (at_nr.nr_phase == 0)
1436 		at_nr.nr_phase = 2;	/* Default phase 2 */
1437 	if (at_nr.nr_firstnet == 0)
1438 		at_nr.nr_firstnet =	/* Default range of one */
1439 		at_nr.nr_lastnet = sat->sat_addr.s_net;
1440 	printf("\tatalk %d.%d range %d-%d phase %d\n",
1441 	ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
1442 	ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
1443 	if ((u_short) ntohs(at_nr.nr_firstnet) >
1444 			(u_short) ntohs(sat->sat_addr.s_net)
1445 		    || (u_short) ntohs(at_nr.nr_lastnet) <
1446 			(u_short) ntohs(sat->sat_addr.s_net))
1447 		errx(1, "AppleTalk address is not in range");
1448 	*((struct netrange *) &sat->sat_zero) = at_nr;
1449 }
1450 
1451 #define SNS(x) ((struct sockaddr_ns *) &(x))
1452 struct sockaddr_ns *snstab[] = {
1453 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1454 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1455 
1456 void
1457 xns_getaddr(addr, which)
1458 	char *addr;
1459 	int which;
1460 {
1461 	struct sockaddr_ns *sns = snstab[which];
1462 
1463 	sns->sns_family = AF_NS;
1464 	sns->sns_len = sizeof(*sns);
1465 	sns->sns_addr = ns_addr(addr);
1466 	if (which == MASK)
1467 		puts("Attempt to set XNS netmask will be ineffectual");
1468 }
1469 
1470 #define SISO(x) ((struct sockaddr_iso *) &(x))
1471 struct sockaddr_iso *sisotab[] = {
1472 SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1473 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1474 
1475 void
1476 iso_getaddr(addr, which)
1477 	char *addr;
1478 	int which;
1479 {
1480 	struct sockaddr_iso *siso = sisotab[which];
1481 	siso->siso_addr = *iso_addr(addr);
1482 
1483 	if (which == MASK) {
1484 		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1485 		siso->siso_nlen = 0;
1486 	} else {
1487 		siso->siso_len = sizeof(*siso);
1488 		siso->siso_family = AF_ISO;
1489 	}
1490 }
1491 
1492 void
1493 setsnpaoffset(val, d)
1494 	char *val;
1495 	int d;
1496 {
1497 	iso_addreq.ifra_snpaoffset = atoi(val);
1498 }
1499 
1500 void
1501 setnsellength(val, d)
1502 	char *val;
1503 	int d;
1504 {
1505 	nsellength = atoi(val);
1506 	if (nsellength < 0)
1507 		errx(1, "Negative NSEL length is absurd");
1508 	if (afp == 0 || afp->af_af != AF_ISO)
1509 		errx(1, "Setting NSEL length valid only for iso");
1510 }
1511 
1512 void
1513 fixnsel(s)
1514 	struct sockaddr_iso *s;
1515 {
1516 	if (s->siso_family == 0)
1517 		return;
1518 	s->siso_tlen = nsellength;
1519 }
1520 
1521 void
1522 adjust_nsellength()
1523 {
1524 	fixnsel(sisotab[RIDADDR]);
1525 	fixnsel(sisotab[ADDR]);
1526 	fixnsel(sisotab[DSTADDR]);
1527 }
1528 
1529 #endif	/* INET_ONLY */
1530 
1531 void
1532 usage()
1533 {
1534 	fprintf(stderr,
1535 	    "usage: ifconfig [ -m ] interface\n%s%s%s%s%s%s%s%s%s%s%s",
1536 		"\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
1537 		"[ netmask mask ] ]\n",
1538 		"\t[ metric n ]\n",
1539 		"\t[ mtu n ]\n",
1540 		"\t[ arp | -arp ]\n",
1541 		"\t[ media mtype ]\n",
1542 		"\t[ mediaopt mopts ]\n",
1543 		"\t[ -mediaopt mopts ]\n",
1544 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n",
1545 		"       ifconfig -a [ -m ] [ -d ] [ -u ] [ af ]\n",
1546 		"       ifconfig -l [ -d ] [ -u ]\n");
1547 	exit(1);
1548 }
1549