ifconfig.c revision 1.40
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
76static 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
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;
125int	reset_if_flags;
126
127void 	notealias __P((char *, int));
128void 	notrailers __P((char *, int));
129void 	setifaddr __P((char *, int));
130void 	setifdstaddr __P((char *, int));
131void 	setifflags __P((char *, int));
132void 	setifbroadaddr __P((char *, int));
133void 	setifipdst __P((char *, int));
134void 	setifmetric __P((char *, int));
135void 	setifmtu __P((char *, int));
136void 	setifnetmask __P((char *, int));
137void 	setnsellength __P((char *, int));
138void 	setsnpaoffset __P((char *, int));
139void	setatrange __P((char *, int));
140void	setatphase __P((char *, int));
141void	checkatrange __P ((struct sockaddr_at *));
142void	setmedia __P((char *, int));
143void	setmediaopt __P((char *, int));
144void	unsetmediaopt __P((char *, int));
145void	fixnsel __P((struct sockaddr_iso *));
146int	main __P((int, char *[]));
147
148#define	NEXTARG		0xffffff
149
150struct	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
195void 	adjust_nsellength __P((void));
196int	getinfo __P((struct ifreq *));
197void	getsock __P((int));
198void	printall __P((void));
199void 	printb __P((char *, unsigned short, char *));
200void 	status __P((const u_int8_t *, int));
201void 	usage __P((void));
202
203void	domediaopt __P((char *, int));
204int	get_media_subtype __P((int, char *));
205int	get_media_options __P((int, char *));
206int	lookup_media_word __P((struct ifmedia_description *, char *));
207void	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 */
213void	in_status __P((int));
214void 	in_getaddr __P((char *, int));
215void	at_status __P((int));
216void	at_getaddr __P((char *, int));
217void 	xns_status __P((int));
218void 	xns_getaddr __P((char *, int));
219void 	iso_status __P((int));
220void 	iso_getaddr __P((char *, int));
221
222/* Known address families */
223struct 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
247struct afswtch *afp;	/*the address family being set or asked about*/
248
249struct afswtch *lookup_af __P((const char *));
250
251int
252main(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
408struct afswtch *
409lookup_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
420void
421getsock(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
437int
438getinfo(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
462void
463printall()
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*/
529void
530setifaddr(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
547void
548setifnetmask(addr, d)
549	char *addr;
550	int d;
551{
552	(*afp->af_getaddr)(addr, MASK);
553}
554
555void
556setifbroadaddr(addr, d)
557	char *addr;
558	int d;
559{
560	(*afp->af_getaddr)(addr, DSTADDR);
561}
562
563void
564setifipdst(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*/
576void
577notealias(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*/
593void
594notrailers(vname, value)
595	char *vname;
596	int value;
597{
598	puts("Note: trailers are no longer sent, but always received");
599}
600
601/*ARGSUSED*/
602void
603setifdstaddr(addr, param)
604	char *addr;
605	int param;
606{
607	(*afp->af_getaddr)(addr, DSTADDR);
608}
609
610void
611setifflags(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
632void
633setifmetric(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
643void
644setifmtu(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
654void
655setmedia(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
698void
699setmediaopt(val, d)
700	char *val;
701	int d;
702{
703
704	domediaopt(val, 0);
705}
706
707void
708unsetmediaopt(val, d)
709	int d;
710	char *val;
711{
712
713	domediaopt(val, 1);
714}
715
716void
717domediaopt(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
766struct ifmedia_description ifm_type_descriptions[] =
767    IFM_TYPE_DESCRIPTIONS;
768
769struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
770    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
771
772struct ifmedia_description ifm_subtype_ethernet_aliases[] =
773    IFM_SUBTYPE_ETHERNET_ALIASES;
774
775struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
776    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
777
778struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
779    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
780
781struct ifmedia_description ifm_subtype_tokenring_aliases[] =
782    IFM_SUBTYPE_TOKENRING_ALIASES;
783
784struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
785    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
786
787struct ifmedia_description ifm_subtype_fddi_descriptions[] =
788    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
789
790struct ifmedia_description ifm_subtype_fddi_aliases[] =
791    IFM_SUBTYPE_FDDI_ALIASES;
792
793struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
794    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
795
796struct ifmedia_description ifm_subtype_shared_descriptions[] =
797    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
798
799struct ifmedia_description ifm_subtype_shared_aliases[] =
800    IFM_SUBTYPE_SHARED_ALIASES;
801
802struct ifmedia_description ifm_shared_option_descriptions[] =
803    IFM_SHARED_OPTION_DESCRIPTIONS;
804
805struct 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 */
817struct 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
862int
863get_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
888int
889get_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
931int
932lookup_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
944void
945print_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 */
1014void
1015status(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
1111void
1112in_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
1175void
1176at_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
1232void
1233xns_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
1271void
1272iso_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))
1321struct sockaddr_in *sintab[] = {
1322SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1323SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1324
1325void
1326in_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 */
1351void
1352printb(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
1384void
1385at_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
1403void
1404setatrange(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
1418void
1419setatphase(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
1431void
1432checkatrange(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))
1452struct sockaddr_ns *snstab[] = {
1453SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1454SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1455
1456void
1457xns_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))
1471struct sockaddr_iso *sisotab[] = {
1472SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1473SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1474
1475void
1476iso_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
1492void
1493setsnpaoffset(val, d)
1494	char *val;
1495	int d;
1496{
1497	iso_addreq.ifra_snpaoffset = atoi(val);
1498}
1499
1500void
1501setnsellength(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
1512void
1513fixnsel(s)
1514	struct sockaddr_iso *s;
1515{
1516	if (s->siso_family == 0)
1517		return;
1518	s->siso_tlen = nsellength;
1519}
1520
1521void
1522adjust_nsellength()
1523{
1524	fixnsel(sisotab[RIDADDR]);
1525	fixnsel(sisotab[ADDR]);
1526	fixnsel(sisotab[DSTADDR]);
1527}
1528
1529#endif	/* INET_ONLY */
1530
1531void
1532usage()
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