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