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