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