ifconfig.c revision 1.36
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
69static 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
76static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
77#else
78static 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
112struct	ifreq		ifr, ridreq;
113struct	ifaliasreq	addreq __attribute__((aligned(4)));
114struct	iso_aliasreq	iso_addreq;
115struct	sockaddr_in	netmask;
116struct	netrange	at_nr;		/* AppleTalk net range */
117
118char	name[30];
119int	flags, metric, mtu, setaddr, setipdst, doalias;
120int	clearaddr, s;
121int	newaddr = -1;
122int	nsellength = 1;
123int	af;
124int	dflag, mflag, lflag, uflag;
125
126void 	notealias __P((char *, int));
127void 	notrailers __P((char *, int));
128void 	setifaddr __P((char *, int));
129void 	setifdstaddr __P((char *, int));
130void 	setifflags __P((char *, int));
131void 	setifbroadaddr __P((char *, int));
132void 	setifipdst __P((char *, int));
133void 	setifmetric __P((char *, int));
134void 	setifmtu __P((char *, int));
135void 	setifnetmask __P((char *, int));
136void 	setnsellength __P((char *, int));
137void 	setsnpaoffset __P((char *, int));
138void	setatrange __P((char *, int));
139void	setatphase __P((char *, int));
140void	checkatrange __P ((struct sockaddr_at *));
141void	setmedia __P((char *, int));
142void	setmediaopt __P((char *, int));
143void	unsetmediaopt __P((char *, int));
144void	fixnsel __P((struct sockaddr_iso *));
145int	main __P((int, char *[]));
146
147#define	NEXTARG		0xffffff
148
149struct	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
194void 	adjust_nsellength __P((void));
195int	getinfo __P((struct ifreq *));
196void	getsock __P((int));
197void	printall __P((void));
198void 	printb __P((char *, unsigned short, char *));
199void 	status __P((const u_int8_t *, int));
200void 	usage __P((void));
201
202void	domediaopt __P((char *, int));
203int	get_media_subtype __P((int, char *));
204int	get_media_options __P((int, char *));
205int	lookup_media_word __P((struct ifmedia_description *, char *));
206void	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 */
212void	in_status __P((int));
213void 	in_getaddr __P((char *, int));
214void	at_status __P((int));
215void	at_getaddr __P((char *, int));
216void 	xns_status __P((int));
217void 	xns_getaddr __P((char *, int));
218void 	iso_status __P((int));
219void 	iso_getaddr __P((char *, int));
220
221/* Known address families */
222struct 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
246struct afswtch *afp;	/*the address family being set or asked about*/
247
248struct afswtch *lookup_af __P((const char *));
249
250int
251main(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
406struct afswtch *
407lookup_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
418void
419getsock(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
435int
436getinfo(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
460void
461printall()
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*/
527void
528setifaddr(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
545void
546setifnetmask(addr, d)
547	char *addr;
548	int d;
549{
550	(*afp->af_getaddr)(addr, MASK);
551}
552
553void
554setifbroadaddr(addr, d)
555	char *addr;
556	int d;
557{
558	(*afp->af_getaddr)(addr, DSTADDR);
559}
560
561void
562setifipdst(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*/
574void
575notealias(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*/
591void
592notrailers(vname, value)
593	char *vname;
594	int value;
595{
596	puts("Note: trailers are no longer sent, but always received");
597}
598
599/*ARGSUSED*/
600void
601setifdstaddr(addr, param)
602	char *addr;
603	int param;
604{
605	(*afp->af_getaddr)(addr, DSTADDR);
606}
607
608void
609setifflags(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
628void
629setifmetric(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
639void
640setifmtu(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
650void
651setmedia(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
694void
695setmediaopt(val, d)
696	char *val;
697	int d;
698{
699
700	domediaopt(val, 0);
701}
702
703void
704unsetmediaopt(val, d)
705	int d;
706	char *val;
707{
708
709	domediaopt(val, 1);
710}
711
712void
713domediaopt(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
762struct ifmedia_description ifm_type_descriptions[] =
763    IFM_TYPE_DESCRIPTIONS;
764
765struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
766    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
767
768struct ifmedia_description ifm_subtype_ethernet_aliases[] =
769    IFM_SUBTYPE_ETHERNET_ALIASES;
770
771struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
772    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
773
774struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
775    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
776
777struct ifmedia_description ifm_subtype_tokenring_aliases[] =
778    IFM_SUBTYPE_TOKENRING_ALIASES;
779
780struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
781    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
782
783struct ifmedia_description ifm_subtype_fddi_descriptions[] =
784    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
785
786struct ifmedia_description ifm_subtype_fddi_aliases[] =
787    IFM_SUBTYPE_FDDI_ALIASES;
788
789struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
790    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
791
792struct ifmedia_description ifm_subtype_shared_descriptions[] =
793    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
794
795struct ifmedia_description ifm_subtype_shared_aliases[] =
796    IFM_SUBTYPE_SHARED_ALIASES;
797
798struct ifmedia_description ifm_shared_option_descriptions[] =
799    IFM_SHARED_OPTION_DESCRIPTIONS;
800
801struct 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 */
813struct 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
858int
859get_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
884int
885get_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
927int
928lookup_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
940void
941print_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 */
1010void
1011status(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
1107void
1108in_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
1171void
1172at_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
1228void
1229xns_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
1267void
1268iso_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))
1317struct sockaddr_in *sintab[] = {
1318SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1319SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1320
1321void
1322in_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 */
1347void
1348printb(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
1380void
1381at_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
1399void
1400setatrange(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
1414void
1415setatphase(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
1427void
1428checkatrange(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))
1448struct sockaddr_ns *snstab[] = {
1449SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1450SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1451
1452void
1453xns_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))
1467struct sockaddr_iso *sisotab[] = {
1468SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1469SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1470
1471void
1472iso_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
1488void
1489setsnpaoffset(val, d)
1490	char *val;
1491	int d;
1492{
1493	iso_addreq.ifra_snpaoffset = atoi(val);
1494}
1495
1496void
1497setnsellength(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
1508void
1509fixnsel(s)
1510	register struct sockaddr_iso *s;
1511{
1512	if (s->siso_family == 0)
1513		return;
1514	s->siso_tlen = nsellength;
1515}
1516
1517void
1518adjust_nsellength()
1519{
1520	fixnsel(sisotab[RIDADDR]);
1521	fixnsel(sisotab[ADDR]);
1522	fixnsel(sisotab[DSTADDR]);
1523}
1524
1525#endif	/* INET_ONLY */
1526
1527void
1528usage()
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