ifconfig.c revision 25667
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41/*
42static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
43*/
44static const char rcsid[] =
45	"$Id: ifconfig.c,v 1.29 1997/05/10 14:47:34 peter Exp $";
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/ioctl.h>
50#include <sys/socket.h>
51#include <sys/sysctl.h>
52#include <sys/time.h>
53
54#include <net/if.h>
55#include <net/if_var.h>
56#include <net/if_dl.h>
57#include <net/if_types.h>
58#include <net/route.h>
59
60/* IP */
61#include <netinet/in.h>
62#include <netinet/in_var.h>
63#include <arpa/inet.h>
64#include <netdb.h>
65
66/* IPX */
67#define	IPXIP
68#define IPTUNNEL
69#include <netipx/ipx.h>
70#include <netipx/ipx_if.h>
71
72/* Appletalk */
73#include <netatalk/at.h>
74
75/* XNS */
76#ifdef NS
77#define	NSIP
78#include <netns/ns.h>
79#include <netns/ns_if.h>
80#endif
81
82/* OSI */
83#ifdef ISO
84#define EON
85#include <netiso/iso.h>
86#include <netiso/iso_var.h>
87#endif
88
89#include <ctype.h>
90#include <err.h>
91#include <errno.h>
92#include <fcntl.h>
93#include <stdio.h>
94#include <stdlib.h>
95#include <string.h>
96#include <unistd.h>
97
98#include "ifconfig.h"
99
100struct	ifreq		ifr, ridreq;
101struct	ifaliasreq	addreq;
102#ifdef ISO
103struct	iso_ifreq	iso_ridreq;
104struct	iso_aliasreq	iso_addreq;
105#endif
106struct	sockaddr_in	netmask;
107struct	netrange	at_nr;		/* AppleTalk net range */
108
109char	name[32];
110int	flags;
111int	metric;
112int	mtu;
113#ifdef ISO
114int	nsellength = 1;
115#endif
116int	setaddr;
117int	setipdst;
118int	doalias;
119int	clearaddr;
120int	newaddr = 1;
121int	allmedia;
122
123struct	afswtch;
124
125void	Perror __P((const char *cmd));
126void	checkatrange __P((struct sockaddr_at *));
127int	ifconfig __P((int argc, char *const *argv, const struct afswtch *afp));
128void	notealias __P((const char *, int, int, const struct afswtch *afp));
129void	printb __P((const char *s, unsigned value, const char *bits));
130void	rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
131void	status __P((const struct afswtch *afp, int addrcount,
132		    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
133		    struct ifa_msghdr *ifam));
134void	usage __P((void));
135
136typedef	void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp));
137c_func	setatphase, setatrange;
138c_func	setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
139c_func	setifipdst;
140c_func	setifflags, setifmetric, setifmtu;
141
142#ifdef ISO
143c_func	setsnpaoffset, setnsellength;
144#endif
145
146#define	NEXTARG		0xffffff
147
148const
149struct	cmd {
150	const	char *c_name;
151	int	c_parameter;		/* NEXTARG means next argv */
152	void	(*c_func) __P((const char *, int, int, const struct afswtch *afp));
153} cmds[] = {
154	{ "up",		IFF_UP,		setifflags } ,
155	{ "down",	-IFF_UP,	setifflags },
156	{ "arp",	-IFF_NOARP,	setifflags },
157	{ "-arp",	IFF_NOARP,	setifflags },
158	{ "debug",	IFF_DEBUG,	setifflags },
159	{ "-debug",	-IFF_DEBUG,	setifflags },
160	{ "alias",	IFF_UP,		notealias },
161	{ "-alias",	-IFF_UP,	notealias },
162	{ "delete",	-IFF_UP,	notealias },
163#ifdef notdef
164#define	EN_SWABIPS	0x1000
165	{ "swabips",	EN_SWABIPS,	setifflags },
166	{ "-swabips",	-EN_SWABIPS,	setifflags },
167#endif
168	{ "netmask",	NEXTARG,	setifnetmask },
169	{ "range",	NEXTARG,	setatrange },
170	{ "phase",	NEXTARG,	setatphase },
171	{ "metric",	NEXTARG,	setifmetric },
172	{ "broadcast",	NEXTARG,	setifbroadaddr },
173	{ "ipdst",	NEXTARG,	setifipdst },
174#ifdef ISO
175	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
176	{ "nsellength",	NEXTARG,	setnsellength },
177#endif
178	{ "link0",	IFF_LINK0,	setifflags },
179	{ "-link0",	-IFF_LINK0,	setifflags },
180	{ "link1",	IFF_LINK1,	setifflags },
181	{ "-link1",	-IFF_LINK1,	setifflags },
182	{ "link2",	IFF_LINK2,	setifflags },
183	{ "-link2",	-IFF_LINK2,	setifflags },
184#ifdef USE_IF_MEDIA
185	{ "media",	NEXTARG,	setmedia },
186	{ "mediaopt",	NEXTARG,	setmediaopt },
187	{ "-mediaopt",	NEXTARG,	unsetmediaopt },
188#endif
189	{ "normal",	-IFF_LINK0,	setifflags },
190	{ "compress",	IFF_LINK0,	setifflags },
191	{ "noicmp",	IFF_LINK1,	setifflags },
192	{ "mtu",	NEXTARG,	setifmtu },
193	{ 0,		0,		setifaddr },
194	{ 0,		0,		setifdstaddr },
195};
196
197/*
198 * XNS support liberally adapted from code written at the University of
199 * Maryland principally by James O'Toole and Chris Torek.
200 */
201typedef	void af_status __P((int, struct rt_addrinfo *));
202typedef	void af_getaddr __P((const char *, int));
203
204af_status	in_status, ipx_status, at_status, ether_status;
205af_getaddr	in_getaddr, ipx_getaddr, at_getaddr;
206
207#ifdef NS
208af_status	xns_status;
209af_getaddr	xns_getaddr;
210#endif
211#ifdef ISO
212af_status	iso_status;
213af_getaddr	iso_getaddr;
214#endif
215
216/* Known address families */
217const
218struct	afswtch {
219	const char *af_name;
220	short af_af;
221	af_status *af_status;
222	af_getaddr *af_getaddr;
223	int af_difaddr;
224	int af_aifaddr;
225	caddr_t af_ridreq;
226	caddr_t af_addreq;
227} afs[] = {
228#define C(x) ((caddr_t) &x)
229	{ "inet", AF_INET, in_status, in_getaddr,
230	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
231	{ "ipx", AF_IPX, ipx_status, ipx_getaddr,
232	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
233	{ "atalk", AF_APPLETALK, at_status, at_getaddr,
234	     SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
235#ifdef NS
236	{ "ns", AF_NS, xns_status, xns_getaddr,
237	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
238#endif
239#ifdef ISO
240	{ "iso", AF_ISO, iso_status, iso_getaddr,
241	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
242#endif
243	{ "ether", AF_INET, ether_status, NULL },	/* XXX not real!! */
244#if 0	/* XXX conflicts with the media command */
245#ifdef USE_IF_MEDIA
246	{ "media", AF_INET, media_status, NULL },	/* XXX not real!! */
247#endif
248#endif
249	{ 0,	0,	    0,		0 }
250};
251
252/*
253 * Expand the compacted form of addresses as returned via the
254 * configuration read via sysctl().
255 */
256
257#define ROUNDUP(a) \
258	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
259#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
260
261void
262rt_xaddrs(cp, cplim, rtinfo)
263	caddr_t cp, cplim;
264	struct rt_addrinfo *rtinfo;
265{
266	struct sockaddr *sa;
267	int i;
268
269	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
270	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
271		if ((rtinfo->rti_addrs & (1 << i)) == 0)
272			continue;
273		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
274		ADVANCE(cp, sa);
275	}
276}
277
278
279void
280usage()
281{
282	fputs("usage: ifconfig -a [ -m ] [ -d ] [ -u ] [ af ]\n", stderr);
283	fputs("       ifconfig -l [ -d ] [ -u ]\n", stderr);
284	fputs("       ifconfig [ -m ] interface\n", stderr);
285	fputs("        [ af [ address [ dest_addr ] ] [ netmask mask ] [ broadcast addr ]\n", stderr);
286	fputs("             [ alias ] [ delete ] ]\n", stderr);
287	fputs("        [ up ] [ down ]\n", stderr);
288	fputs("        [ metric n ]\n", stderr);
289	fputs("        [ mtu n ]\n", stderr);
290	fputs("        [ arp | -arp ]\n", stderr);
291	fputs("        [ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n", stderr);
292#ifdef USE_IF_MEDIA
293	fputs("        [ media mtype ]\n", stderr);
294	fputs("        [ mediaopt mopts ]\n", stderr);
295	fputs("        [ -mediaopt mopts ]\n", stderr);
296#endif
297	exit(1);
298}
299
300int
301main(argc, argv)
302	int argc;
303	char *const *argv;
304{
305	int c;
306	int all, namesonly, downonly, uponly;
307	int foundit = 0, need_nl = 0;
308	const struct afswtch *afp = 0;
309	int addrcount;
310	struct	if_msghdr *ifm, *nextifm;
311	struct	ifa_msghdr *ifam;
312	struct	sockaddr_dl *sdl;
313	char	*buf, *lim, *next;
314
315
316	size_t needed;
317	int mib[6];
318
319	/* Parse leading line options */
320	all = allmedia = downonly = uponly = namesonly = 0;
321	while ((c = getopt(argc, argv, "adlmu")) != -1) {
322		switch (c) {
323		case 'a':	/* scan all interfaces */
324			all++;
325			break;
326		case 'l':	/* scan interface names only */
327			namesonly++;
328			break;
329		case 'd':	/* restrict scan to "down" interfaces */
330			downonly++;
331			break;
332		case 'u':	/* restrict scan to "down" interfaces */
333			uponly++;
334			break;
335		case 'm':	/* show media choices in status */
336#ifdef USE_IF_MEDIA
337			allmedia++;
338#else
339			fputs("WARNING: if_media not compiled in!\n", stderr);
340			usage();
341#endif
342			break;
343		default:
344			usage();
345			break;
346		}
347	}
348	argc -= optind;
349	argv += optind;
350
351	/* -l cannot be used with -a or -m */
352	if (namesonly && (all || allmedia))
353		usage();
354
355	/* nonsense.. */
356	if (uponly && downonly)
357		usage();
358
359	/* -a and -l allow an address family arg to limit the output */
360	if (all || namesonly) {
361		if (argc > 1)
362			usage();
363
364		if (argc == 1) {
365			for (afp = afs; afp->af_name; afp++)
366				if (strcmp(afp->af_name, *argv) == 0) {
367					argc--, argv++;
368					break;
369				}
370			if (afp->af_name == NULL)
371				usage();
372			/* leave with afp non-zero */
373		}
374	} else {
375		/* not listsing, need an argument */
376		if (argc < 1)
377			usage();
378
379		strncpy(name, *argv, sizeof(name));
380		argc--, argv++;
381	}
382
383	/* Check for address family */
384	if (argc > 0) {
385		for (afp = afs; afp->af_name; afp++)
386			if (strcmp(afp->af_name, *argv) == 0) {
387				argc--, argv++;
388				break;
389			}
390		if (afp->af_name == NULL)
391			afp = NULL;	/* not a family, NULL */
392	}
393
394	mib[0] = CTL_NET;
395	mib[1] = PF_ROUTE;
396	mib[2] = 0;
397	mib[3] = 0;	/* address family */
398	mib[4] = NET_RT_IFLIST;
399	mib[5] = 0;
400
401	/* if particular family specified, only ask about it */
402	if (afp)
403		mib[3] = afp->af_af;
404
405	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
406		errx(1, "iflist-sysctl-estimate");
407	if ((buf = malloc(needed)) == NULL)
408		errx(1, "malloc");
409	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
410		errx(1, "actual retrieval of interface table");
411	lim = buf + needed;
412
413	next = buf;
414	while (next < lim) {
415
416		ifm = (struct if_msghdr *)next;
417
418		if (ifm->ifm_type == RTM_IFINFO) {
419			sdl = (struct sockaddr_dl *)(ifm + 1);
420			flags = ifm->ifm_flags;
421		} else {
422			fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
423			fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
424				ifm->ifm_type);
425			fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
426			fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next,
427				lim);
428			exit (1);
429		}
430
431		next += ifm->ifm_msglen;
432		ifam = NULL;
433		addrcount = 0;
434		while (next < lim) {
435
436			nextifm = (struct if_msghdr *)next;
437
438			if (nextifm->ifm_type != RTM_NEWADDR)
439				break;
440
441			if (ifam == NULL)
442				ifam = (struct ifa_msghdr *)nextifm;
443
444			addrcount++;
445			next += nextifm->ifm_msglen;
446		}
447
448		if (all || namesonly) {
449			if (uponly)
450				if ((flags & IFF_UP) == 0)
451					continue; /* not up */
452			if (downonly)
453				if (flags & IFF_UP)
454					continue; /* not down */
455			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
456			name[sdl->sdl_nlen] = '\0';
457			if (namesonly) {
458				if (need_nl)
459					putchar(' ');
460				fputs(name, stdout);
461				need_nl++;
462				continue;
463			}
464		} else {
465			if (strlen(name) != sdl->sdl_nlen)
466				continue; /* not same len */
467			if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
468				continue; /* not same name */
469		}
470
471		if (argc > 0)
472			ifconfig(argc, argv, afp);
473		else
474			status(afp, addrcount, sdl, ifm, ifam);
475
476		if (all == 0 && namesonly == 0) {
477			foundit++; /* flag it as 'done' */
478			break;
479		}
480	}
481	free(buf);
482
483	if (namesonly && need_nl > 0)
484		putchar('\n');
485
486	if (all == 0 && namesonly == 0 && foundit == 0)
487		errx(1, "interface %s does not exist", name);
488
489
490	exit (0);
491}
492
493
494int
495ifconfig(argc, argv, afp)
496	int argc;
497	char *const *argv;
498	const struct afswtch *afp;
499{
500	int s;
501
502	if (afp == NULL)
503		afp = &afs[0];
504	ifr.ifr_addr.sa_family = afp->af_af;
505	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
506
507	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
508		perror("ifconfig: socket");
509		exit(1);
510	}
511
512	while (argc > 0) {
513		register const struct cmd *p;
514
515		for (p = cmds; p->c_name; p++)
516			if (strcmp(*argv, p->c_name) == 0)
517				break;
518		if (p->c_name == 0 && setaddr)
519			p++;	/* got src, do dst */
520		if (p->c_func) {
521			if (p->c_parameter == NEXTARG) {
522				if (argv[1] == NULL)
523					errx(1, "'%s' requires argument",
524					    p->c_name);
525				(*p->c_func)(argv[1], 0, s, afp);
526				argc--, argv++;
527			} else
528				(*p->c_func)(*argv, p->c_parameter, s, afp);
529		}
530		argc--, argv++;
531	}
532#ifdef ISO
533	if (af == AF_ISO)
534		adjust_nsellength();
535#endif
536	if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
537		struct ipxip_req rq;
538		int size = sizeof(rq);
539
540		rq.rq_ipx = addreq.ifra_addr;
541		rq.rq_ip = addreq.ifra_dstaddr;
542
543		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
544			Perror("Encapsulation Routing");
545	}
546	if (ifr.ifr_addr.sa_family == AF_APPLETALK)
547		checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
548#ifdef NS
549	if (setipdst && ifr.ifr_addr.sa_family == AF_NS) {
550		struct nsip_req rq;
551		int size = sizeof(rq);
552
553		rq.rq_ns = addreq.ifra_addr;
554		rq.rq_ip = addreq.ifra_dstaddr;
555
556		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
557			Perror("Encapsulation Routing");
558	}
559#endif
560	if (clearaddr) {
561		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
562			warnx("interface %s cannot change %s addresses!",
563			      name, afp->af_name);
564			clearaddr = NULL;
565		}
566	}
567	if (clearaddr) {
568		int ret;
569		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
570		if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
571			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
572				/* means no previous address for interface */
573			} else
574				Perror("ioctl (SIOCDIFADDR)");
575		}
576	}
577	if (newaddr) {
578		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
579			warnx("interface %s cannot change %s addresses!",
580			      name, afp->af_name);
581			newaddr = NULL;
582		}
583	}
584	if (newaddr) {
585		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
586		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
587			Perror("ioctl (SIOCAIFADDR)");
588	}
589	close(s);
590	return(0);
591}
592#define RIDADDR 0
593#define ADDR	1
594#define MASK	2
595#define DSTADDR	3
596
597/*ARGSUSED*/
598void
599setifaddr(addr, param, s, afp)
600	const char *addr;
601	int param;
602	int s;
603	const struct afswtch *afp;
604{
605	/*
606	 * Delay the ioctl to set the interface addr until flags are all set.
607	 * The address interpretation may depend on the flags,
608	 * and the flags may change when the address is set.
609	 */
610	setaddr++;
611	if (doalias == 0)
612		clearaddr = 1;
613	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
614}
615
616void
617setifnetmask(addr, dummy, s, afp)
618	const char *addr;
619	int dummy __unused;
620	int s;
621	const struct afswtch *afp;
622{
623	(*afp->af_getaddr)(addr, MASK);
624}
625
626void
627setifbroadaddr(addr, dummy, s, afp)
628	const char *addr;
629	int dummy __unused;
630	int s;
631	const struct afswtch *afp;
632{
633	(*afp->af_getaddr)(addr, DSTADDR);
634}
635
636void
637setifipdst(addr, dummy, s, afp)
638	const char *addr;
639	int dummy __unused;
640	int s;
641	const struct afswtch *afp;
642{
643	in_getaddr(addr, DSTADDR);
644	setipdst++;
645	clearaddr = 0;
646	newaddr = 0;
647}
648#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
649
650void
651notealias(addr, param, s, afp)
652	const char *addr;
653	int param;
654	int s;
655	const struct afswtch *afp;
656{
657	if (setaddr && doalias == 0 && param < 0)
658		bcopy((caddr_t)rqtosa(af_addreq),
659		      (caddr_t)rqtosa(af_ridreq),
660		      rqtosa(af_addreq)->sa_len);
661	doalias = param;
662	if (param < 0) {
663		clearaddr = 1;
664		newaddr = 0;
665	} else
666		clearaddr = 0;
667}
668
669/*ARGSUSED*/
670void
671setifdstaddr(addr, param, s, afp)
672	const char *addr;
673	int param __unused;
674	int s;
675	const struct afswtch *afp;
676{
677	(*afp->af_getaddr)(addr, DSTADDR);
678}
679
680void
681setifflags(vname, value, s, afp)
682	const char *vname;
683	int value;
684	int s;
685	const struct afswtch *afp;
686{
687 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
688 		Perror("ioctl (SIOCGIFFLAGS)");
689 		exit(1);
690 	}
691	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
692 	flags = ifr.ifr_flags;
693
694	if (value < 0) {
695		value = -value;
696		flags &= ~value;
697	} else
698		flags |= value;
699	ifr.ifr_flags = flags;
700	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
701		Perror(vname);
702}
703
704void
705setifmetric(val, dummy, s, afp)
706	const char *val;
707	int dummy __unused;
708	int s;
709	const struct afswtch *afp;
710{
711	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
712	ifr.ifr_metric = atoi(val);
713	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
714		perror("ioctl (set metric)");
715}
716
717void
718setifmtu(val, dummy, s, afp)
719	const char *val;
720	int dummy __unused;
721	int s;
722	const struct afswtch *afp;
723{
724	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		perror("ioctl (set mtu)");
728}
729
730#ifdef ISO
731void
732setsnpaoffset(val, dummy)
733	char *val;
734	int dummy __unused;
735{
736	iso_addreq.ifra_snpaoffset = atoi(val);
737}
738#endif
739
740#define	IFFBITS \
741"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6b6\7RUNNING" \
742"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
743"\20MULTICAST"
744
745/*
746 * Print the status of the interface.  If an address family was
747 * specified, show it and it only; otherwise, show them all.
748 */
749void
750status(afp, addrcount, sdl, ifm, ifam)
751	const struct afswtch *afp;
752	int addrcount;
753	struct	sockaddr_dl *sdl;
754	struct if_msghdr *ifm;
755	struct ifa_msghdr *ifam;
756{
757	const struct afswtch *p = NULL;
758	struct	rt_addrinfo info;
759	int allfamilies, s;
760
761	if (afp == NULL) {
762		allfamilies = 1;
763		afp = &afs[0];
764	} else
765		allfamilies = 0;
766
767	ifr.ifr_addr.sa_family = afp->af_af;
768	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
769
770	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
771		perror("ifconfig: socket");
772		exit(1);
773	}
774
775	/*
776	 * XXX is it we are doing a SIOCGIFMETRIC etc for one family.
777	 * is it possible that the metric and mtu can be different for
778	 * each family?  If so, we have a format problem, because the
779	 * metric and mtu is printed on the global the flags line.
780	 */
781	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
782		perror("ioctl (SIOCGIFMETRIC)");
783	else
784		metric = ifr.ifr_metric;
785
786	if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
787		perror("ioctl (SIOCGIFMTU)");
788	else
789		mtu = ifr.ifr_mtu;
790
791	printf("%s: ", name);
792	printb("flags", flags, IFFBITS);
793	if (metric)
794		printf(" metric %d", metric);
795	if (mtu)
796		printf(" mtu %d", mtu);
797	putchar('\n');
798
799	while (addrcount > 0) {
800
801		info.rti_addrs = ifam->ifam_addrs;
802
803		/* Expand the compacted addresses */
804		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
805			  &info);
806
807		if (!allfamilies) {
808			if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
809#ifdef USE_IF_MEDIA
810			    afp->af_status != media_status &&
811#endif
812			    afp->af_status != ether_status) {
813				p = afp;
814				(*p->af_status)(s, &info);
815			}
816		} else for (p = afs; p->af_name; p++) {
817			if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
818#ifdef USE_IF_MEDIA
819			    p->af_status != media_status &&
820#endif
821			    p->af_status != ether_status)
822				(*p->af_status)(s, &info);
823		}
824		addrcount--;
825		ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
826	}
827	if (allfamilies || afp->af_status == ether_status)
828		ether_status(s, (struct rt_addrinfo *)sdl);
829#ifdef USE_IF_MEDIA
830	if (allfamilies || afp->af_status == media_status)
831		media_status(s, NULL);
832#endif
833	if (!allfamilies && !p && afp->af_status != media_status &&
834	    afp->af_status != ether_status)
835		warnx("%s has no %s interface address!", name, afp->af_name);
836
837	close(s);
838	return;
839}
840
841void
842in_status(s, info)
843	int s __unused;
844	struct rt_addrinfo * info;
845{
846	struct sockaddr_in *sin, null_sin;
847
848	memset(&null_sin, 0, sizeof(null_sin));
849
850	sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
851	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
852
853	if (flags & IFF_POINTOPOINT) {
854		/* note RTAX_BRD overlap with IFF_BROADCAST */
855		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
856		if (!sin)
857			sin = &null_sin;
858		printf("--> %s ", inet_ntoa(sin->sin_addr));
859	}
860
861	sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
862	if (!sin)
863		sin = &null_sin;
864	printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
865
866	if (flags & IFF_BROADCAST) {
867		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
868		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
869		if (sin && sin->sin_addr.s_addr != 0)
870			printf("broadcast %s", inet_ntoa(sin->sin_addr));
871	}
872	putchar('\n');
873}
874
875void
876ipx_status(s, info)
877	int s __unused;
878	struct rt_addrinfo * info;
879{
880	struct sockaddr_ipx *sipx, null_sipx;
881
882	memset(&null_sipx, 0, sizeof(null_sipx));
883
884	sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
885	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
886
887	if (flags & IFF_POINTOPOINT) {
888		sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
889		if (!sipx)
890			sipx = &null_sipx;
891		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
892	}
893	putchar('\n');
894}
895
896void
897at_status(s, info)
898	int s __unused;
899	struct rt_addrinfo * info;
900{
901	struct sockaddr_at *sat, null_sat;
902	struct netrange *nr;
903
904	memset(&null_sat, 0, sizeof(null_sat));
905
906	sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
907	nr = &sat->sat_range.r_netrange;
908	printf("\tatalk %d.%d range %d-%d phase %d",
909		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
910		ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
911	if (flags & IFF_POINTOPOINT) {
912		/* note RTAX_BRD overlap with IFF_BROADCAST */
913		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
914		if (!sat)
915			sat = &null_sat;
916		printf("--> %d.%d",
917			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
918	}
919	if (flags & IFF_BROADCAST) {
920		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
921		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
922		if (sat)
923			printf(" broadcast %d.%d",
924				ntohs(sat->sat_addr.s_net),
925				sat->sat_addr.s_node);
926	}
927
928	putchar('\n');
929}
930
931#ifdef NS
932void
933xns_status(s, info)
934	int s __unused;
935	struct rt_addrinfo * info;
936{
937	struct sockaddr_ns *sns, null_sns;
938
939	memset(&null_sns, 0, sizeof(null_sns));
940
941	sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA];
942	printf("\tns %s ", ns_ntoa(sns->sns_addr));
943
944	if (flags & IFF_POINTOPOINT) {
945		sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD];
946		if (!sns)
947			sns = &null_sns;
948		printf("--> %s ", ns_ntoa(sns->sns_addr));
949	}
950
951	putchar('\n');
952	close(s);
953}
954#endif
955
956#ifdef ISO
957void
958iso_status(s, info)
959	int s __unused;
960	struct rt_addrinfo * info;
961{
962	struct sockaddr_iso *siso, null_siso;
963
964	memset(&null_siso, 0, sizeof(null_siso));
965
966	siso = (struct sockaddr_iso *)info->rti_info[RTAX_IFA];
967	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
968
969	if (flags & IFF_POINTOPOINT) {
970		siso = (struct sockaddr_iso *)info->rti_info[RTAX_BRD];
971		if (!siso)
972			siso = &null_siso;
973		printf("--> %s ", iso_ntoa(&siso->siso_addr));
974	}
975
976	siso = (struct sockaddr_iso *)info->rti_info[RTAX_NETMASK];
977	if (siso)
978		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
979
980	putchar('\n');
981}
982#endif
983
984void
985ether_status(s, info)
986	int s __unused;
987	struct rt_addrinfo *info;
988{
989	char *cp;
990	int n;
991	struct sockaddr_dl *sdl = (struct sockaddr_dl *)info;
992
993	cp = (char *)LLADDR(sdl);
994	if ((n = sdl->sdl_alen) > 0) {
995		if (sdl->sdl_type == IFT_ETHER)
996			printf ("\tether ");
997		else
998			printf ("\tlladdr ");
999             	while (--n >= 0)
1000			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
1001		putchar('\n');
1002	}
1003}
1004
1005void
1006Perror(cmd)
1007	const char *cmd;
1008{
1009	switch (errno) {
1010
1011	case ENXIO:
1012		errx(1, "%s: no such interface", cmd);
1013		break;
1014
1015	case EPERM:
1016		errx(1, "%s: permission denied", cmd);
1017		break;
1018
1019	default:
1020		err(1, "%s", cmd);
1021	}
1022}
1023
1024#define SIN(x) ((struct sockaddr_in *) &(x))
1025struct sockaddr_in *sintab[] = {
1026SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1027SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1028
1029void
1030in_getaddr(s, which)
1031	const char *s;
1032	int which;
1033{
1034	register struct sockaddr_in *sin = sintab[which];
1035	struct hostent *hp;
1036	struct netent *np;
1037
1038	sin->sin_len = sizeof(*sin);
1039	if (which != MASK)
1040		sin->sin_family = AF_INET;
1041
1042	if (inet_aton(s, &sin->sin_addr))
1043		return;
1044	if ((hp = gethostbyname(s)) != 0)
1045		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
1046	else if ((np = getnetbyname(s)) != 0)
1047		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1048	else
1049		errx(1, "%s: bad value", s);
1050}
1051
1052/*
1053 * Print a value a la the %b format of the kernel's printf
1054 */
1055void
1056printb(s, v, bits)
1057	const char *s;
1058	register unsigned v;
1059	register const char *bits;
1060{
1061	register int i, any = 0;
1062	register char c;
1063
1064	if (bits && *bits == 8)
1065		printf("%s=%o", s, v);
1066	else
1067		printf("%s=%x", s, v);
1068	bits++;
1069	if (bits) {
1070		putchar('<');
1071		while ((i = *bits++) != '\0') {
1072			if (v & (1 << (i-1))) {
1073				if (any)
1074					putchar(',');
1075				any = 1;
1076				for (; (c = *bits) > 32; bits++)
1077					putchar(c);
1078			} else
1079				for (; *bits > 32; bits++)
1080					;
1081		}
1082		putchar('>');
1083	}
1084}
1085
1086#define SIPX(x) ((struct sockaddr_ipx *) &(x))
1087struct sockaddr_ipx *sipxtab[] = {
1088SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
1089SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
1090
1091void
1092ipx_getaddr(addr, which)
1093	const char *addr;
1094	int which;
1095{
1096	struct sockaddr_ipx *sipx = sipxtab[which];
1097
1098	sipx->sipx_family = AF_IPX;
1099	sipx->sipx_len = sizeof(*sipx);
1100	sipx->sipx_addr = ipx_addr(addr);
1101	if (which == MASK)
1102		printf("Attempt to set IPX netmask will be ineffectual\n");
1103}
1104
1105void
1106at_getaddr(addr, which)
1107	const char *addr;
1108	int which;
1109{
1110	struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
1111	u_int net, node;
1112
1113	sat->sat_family = AF_APPLETALK;
1114	sat->sat_len = sizeof(*sat);
1115	if (which == MASK)
1116		errx(1, "AppleTalk does not use netmasks\n");
1117	if (sscanf(addr, "%u.%u", &net, &node) != 2
1118	    || net > 0xffff || node > 0xfe)
1119		errx(1, "%s: illegal address", addr);
1120	sat->sat_addr.s_net = htons(net);
1121	sat->sat_addr.s_node = node;
1122}
1123
1124/* XXX  FIXME -- should use strtoul for better parsing. */
1125void
1126setatrange(range, dummy, s, afp)
1127	const char *range;
1128	int dummy __unused;
1129	int s;
1130	const struct afswtch *afp;
1131{
1132	u_short	first = 123, last = 123;
1133
1134	if (sscanf(range, "%hu-%hu", &first, &last) != 2
1135	    || first == 0 || first > 0xffff
1136	    || last == 0 || last > 0xffff || first > last)
1137		errx(1, "%s: illegal net range: %u-%u", range, first, last);
1138	at_nr.nr_firstnet = htons(first);
1139	at_nr.nr_lastnet = htons(last);
1140}
1141
1142void
1143setatphase(phase, dummy, s, afp)
1144	const char *phase;
1145	int dummy __unused;
1146	int s;
1147	const struct afswtch *afp;
1148{
1149	if (!strcmp(phase, "1"))
1150		at_nr.nr_phase = 1;
1151	else if (!strcmp(phase, "2"))
1152		at_nr.nr_phase = 2;
1153	else
1154		errx(1, "%s: illegal phase", phase);
1155}
1156
1157void
1158checkatrange(struct sockaddr_at *sat)
1159{
1160	if (at_nr.nr_phase == 0)
1161		at_nr.nr_phase = 2;	/* Default phase 2 */
1162	if (at_nr.nr_firstnet == 0)
1163		at_nr.nr_firstnet =	/* Default range of one */
1164		at_nr.nr_lastnet = sat->sat_addr.s_net;
1165printf("\tatalk %d.%d range %d-%d phase %d\n",
1166	ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
1167	ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
1168	if ((u_short) ntohs(at_nr.nr_firstnet) >
1169			(u_short) ntohs(sat->sat_addr.s_net)
1170		    || (u_short) ntohs(at_nr.nr_lastnet) <
1171			(u_short) ntohs(sat->sat_addr.s_net))
1172		errx(1, "AppleTalk address is not in range");
1173	sat->sat_range.r_netrange = at_nr;
1174}
1175
1176#ifdef NS
1177#define SNS(x) ((struct sockaddr_ns *) &(x))
1178struct sockaddr_ns *snstab[] = {
1179SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1180SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1181
1182void
1183xns_getaddr(addr, which)
1184	const char *addr;
1185	int which;
1186{
1187	struct sockaddr_ns *sns = snstab[which];
1188
1189	sns->sns_family = AF_NS;
1190	sns->sns_len = sizeof(*sns);
1191	sns->sns_addr = ns_addr(addr);
1192	if (which == MASK)
1193		printf("Attempt to set XNS netmask will be ineffectual\n");
1194}
1195#endif
1196
1197#ifdef ISO
1198#define SISO(x) ((struct sockaddr_iso *) &(x))
1199struct sockaddr_iso *sisotab[] = {
1200SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
1201SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1202
1203void
1204iso_getaddr(addr, which)
1205char *addr;
1206{
1207	register struct sockaddr_iso *siso = sisotab[which];
1208	struct iso_addr *iso_addr();
1209	siso->siso_addr = *iso_addr(addr);
1210
1211	if (which == MASK) {
1212		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1213		siso->siso_nlen = 0;
1214	} else {
1215		siso->siso_len = sizeof(*siso);
1216		siso->siso_family = AF_ISO;
1217	}
1218}
1219
1220void
1221setnsellength(val)
1222	char *val;
1223{
1224	nsellength = atoi(val);
1225	if (nsellength < 0)
1226		errx(1, "Negative NSEL length is absurd");
1227	if (afp == 0 || afp->af_af != AF_ISO)
1228		errx(1, "Setting NSEL length valid only for iso");
1229}
1230
1231void
1232fixnsel(s)
1233register struct sockaddr_iso *s;
1234{
1235	if (s->siso_family == 0)
1236		return;
1237	s->siso_tlen = nsellength;
1238}
1239
1240void
1241adjust_nsellength()
1242{
1243	fixnsel(sisotab[RIDADDR]);
1244	fixnsel(sisotab[ADDR]);
1245	fixnsel(sisotab[DSTADDR]);
1246}
1247#endif
1248