ifconfig.c revision 13940
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/*
35 *  951109 - Andrew@pubnix.net - Changed to iterative buffer growing mechanism
36 *				 for ifconfig -a so all interfaces are queried.
37 *
38 *  960101 - peter@freebsd.org - Blow away the SIOCGIFCONF code and use
39 *				 sysctl() to get the structured interface conf
40 *				 and parse the messages in there. REALLY UGLY!
41 */
42#ifndef lint
43static char copyright[] =
44"@(#) Copyright (c) 1983, 1993\n\
45	The Regents of the University of California.  All rights reserved.\n";
46#endif /* not lint */
47
48#ifndef lint
49static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
50#endif /* not lint */
51
52#include <sys/param.h>
53#include <sys/socket.h>
54#include <sys/ioctl.h>
55#include <sys/sysctl.h>
56
57#include <net/if.h>
58#include <net/if_dl.h>
59#include <net/if_types.h>
60#include <net/route.h>
61#include <netinet/in.h>
62#include <netinet/in_var.h>
63#include <arpa/inet.h>
64#include <netdb.h>
65
66#define	IPXIP
67#define IPTUNNEL
68#include <netipx/ipx.h>
69#include <netipx/ipx_if.h>
70
71#define	NSIP
72#include <netns/ns.h>
73#include <netns/ns_if.h>
74
75#ifdef ISO
76#define EON
77#include <netiso/iso.h>
78#include <netiso/iso_var.h>
79#endif
80#include <sys/protosw.h>
81
82#include <ctype.h>
83#include <err.h>
84#include <errno.h>
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
88#include <unistd.h>
89#include <nlist.h>
90#include <kvm.h>
91#include <fcntl.h>
92
93struct	ifreq		ifr, ridreq;
94struct	ifaliasreq	addreq;
95#ifdef ISO
96struct	iso_ifreq	iso_ridreq;
97struct	iso_aliasreq	iso_addreq;
98#endif
99struct	sockaddr_in	netmask;
100
101char	name[32];
102int	flags;
103int	metric;
104int	mtu;
105int	nsellength = 1;
106int	setaddr;
107int	setipdst;
108int	doalias;
109int	clearaddr;
110int	newaddr = 1;
111int	s;
112kvm_t	*kvmd;
113extern	int errno;
114
115int	setifflags(), setifaddr(), setifdstaddr(), setifnetmask();
116int	setifmetric(), setifmtu(), setifbroadaddr(), setifipdst();
117int	notealias();
118#ifdef ISO
119int	setsnpaoffset(), setnsellength();
120#endif
121int	notrailers();
122
123#define	NEXTARG		0xffffff
124
125struct	cmd {
126	char	*c_name;
127	int	c_parameter;		/* NEXTARG means next argv */
128	int	(*c_func)();
129} cmds[] = {
130	{ "up",		IFF_UP,		setifflags } ,
131	{ "down",	-IFF_UP,	setifflags },
132	{ "trailers",	-1,		notrailers },
133	{ "-trailers",	1,		notrailers },
134	{ "arp",	-IFF_NOARP,	setifflags },
135	{ "-arp",	IFF_NOARP,	setifflags },
136	{ "debug",	IFF_DEBUG,	setifflags },
137	{ "-debug",	-IFF_DEBUG,	setifflags },
138	{ "alias",	IFF_UP,		notealias },
139	{ "-alias",	-IFF_UP,	notealias },
140	{ "delete",	-IFF_UP,	notealias },
141#ifdef notdef
142#define	EN_SWABIPS	0x1000
143	{ "swabips",	EN_SWABIPS,	setifflags },
144	{ "-swabips",	-EN_SWABIPS,	setifflags },
145#endif
146	{ "netmask",	NEXTARG,	setifnetmask },
147	{ "metric",	NEXTARG,	setifmetric },
148	{ "broadcast",	NEXTARG,	setifbroadaddr },
149	{ "ipdst",	NEXTARG,	setifipdst },
150#ifdef ISO
151	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
152	{ "nsellength",	NEXTARG,	setnsellength },
153#endif
154	{ "link0",	IFF_LINK0,	setifflags },
155	{ "-link0",	-IFF_LINK0,	setifflags },
156	{ "link1",	IFF_LINK1,	setifflags },
157	{ "-link1",	-IFF_LINK1,	setifflags },
158	{ "link2",	IFF_LINK2,	setifflags },
159	{ "-link2",	-IFF_LINK2,	setifflags },
160	{ "normal",	-IFF_LINK0,	setifflags },
161	{ "compress",	IFF_LINK0,	setifflags },
162	{ "noicmp",	IFF_LINK1,	setifflags },
163	{ "mtu",	NEXTARG,	setifmtu },
164	{ 0,		0,		setifaddr },
165	{ 0,		0,		setifdstaddr },
166};
167
168/*
169 * XNS support liberally adapted from code written at the University of
170 * Maryland principally by James O'Toole and Chris Torek.
171 */
172int	in_status(), in_getaddr();
173int	ipx_status(), ipx_getaddr();
174int	xns_status(), xns_getaddr();
175#ifdef ISO
176int	iso_status(), iso_getaddr();
177#endif
178int	ether_status();
179
180/* Known address families */
181struct afswtch {
182	char *af_name;
183	short af_af;
184	int (*af_status)();
185	int (*af_getaddr)();
186	int af_difaddr;
187	int af_aifaddr;
188	caddr_t af_ridreq;
189	caddr_t af_addreq;
190} afs[] = {
191#define C(x) ((caddr_t) &x)
192	{ "inet", AF_INET, in_status, in_getaddr,
193	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
194	{ "ipx", AF_IPX, ipx_status, ipx_getaddr,
195	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
196	{ "ns", AF_NS, xns_status, xns_getaddr,
197	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
198#ifdef ISO
199	{ "iso", AF_ISO, iso_status, iso_getaddr,
200	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
201#endif
202	{ "ether", AF_INET, ether_status, NULL },	/* XXX not real!! */
203	{ 0,	0,	    0,		0 }
204};
205
206struct afswtch *afp;	/*the address family being set or asked about*/
207
208void	rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
209int	ifconfig __P((int argc, char *argv[], int af, struct afswtch *rafp));
210
211
212/*
213 * Expand the compacted form of addresses as returned via the
214 * configuration read via sysctl().
215 */
216
217#define ROUNDUP(a) \
218	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
219#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
220
221void
222rt_xaddrs(cp, cplim, rtinfo)
223	caddr_t cp, cplim;
224	struct rt_addrinfo *rtinfo;
225{
226	struct sockaddr *sa;
227	int i;
228
229	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
230	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
231		if ((rtinfo->rti_addrs & (1 << i)) == 0)
232			continue;
233		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
234		ADVANCE(cp, sa);
235	}
236}
237
238
239/*
240 * Grunge for new-style sysctl() decoding.. :-(
241 * Apologies to the world for committing gross things like this in 1996..
242 */
243struct if_msghdr *ifm;
244struct ifa_msghdr *ifam;
245struct sockaddr_dl *sdl;
246struct rt_addrinfo info;
247char *buf, *lim, *next;
248
249
250
251main(argc, argv)
252	int argc;
253	char *argv[];
254{
255	int af = AF_INET;
256	struct afswtch *rafp;
257
258	size_t needed;
259	int mib[6],  len;
260	int all;
261
262	if (argc < 2) {
263		fprintf(stderr, "usage: ifconfig interface\n%s%s%s%s%s%s%s",
264		    "\t[ af [ address [ dest_addr ] ] [ up ] [ down ]",
265			    "[ netmask mask ] ]\n",
266		    "\t[ metric n ]\n",
267		    "\t[ mtu n ]\n",
268		    "\t[ arp | -arp ]\n",
269		    "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ] \n",
270		    "\t[ -a ] [ -ad ] [ -au ]\n");
271		exit(1);
272	}
273	argc--, argv++;
274	strncpy(name, *argv, sizeof(name));
275	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
276	argc--, argv++;
277	if (argc > 0) {
278		for (afp = rafp = afs; rafp->af_name; rafp++)
279			if (strcmp(rafp->af_name, *argv) == 0) {
280				afp = rafp; argc--; argv++;
281				break;
282			}
283		rafp = afp;
284		af = ifr.ifr_addr.sa_family = rafp->af_af;
285	}
286
287	mib[0] = CTL_NET;
288	mib[1] = PF_ROUTE;
289	mib[2] = 0;
290	mib[3] = 0;	/* address family */
291	mib[4] = NET_RT_IFLIST;
292	mib[5] = 0;
293
294	/* if particular family specified, only ask about it */
295	if (afp) {
296		mib[3] = afp->af_af;
297	}
298
299	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
300		errx(1, "iflist-sysctl-estimate");
301	if ((buf = malloc(needed)) == NULL)
302		errx(1, "malloc");
303	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
304		errx(1, "actual retrieval of interface table");
305	lim = buf + needed;
306
307	all = 0;
308	if (strcmp(name, "-a") == 0)
309		all = 1;	/* All interfaces */
310	else if (strcmp(name, "-au") == 0)
311		all = 2;	/* All IFF_UPinterfaces */
312	else if (strcmp(name, "-ad") == 0)
313		all = 3;	/* All !IFF_UP interfaces */
314
315	for (next = buf; next < lim; next += ifm->ifm_msglen) {
316
317		ifm = (struct if_msghdr *)next;
318
319		/* XXX: Swallow up leftover NEWADDR messages */
320		if (ifm->ifm_type == RTM_NEWADDR)
321			continue;
322
323		if (ifm->ifm_type == RTM_IFINFO) {
324			sdl = (struct sockaddr_dl *)(ifm + 1);
325			flags = ifm->ifm_flags;
326		} else {
327			errx(1, "out of sync parsing NET_RT_IFLIST");
328		}
329
330		switch(all) {
331		case -1:
332		case 0:
333			if (strlen(name) != sdl->sdl_nlen)
334				continue; /* not same len */
335			if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
336				continue; /* not same name */
337			break;
338		case 1:
339			break;	/* always do it */
340		case 2:
341			if ((flags & IFF_UP) == 0)
342				continue; /* not up */
343			break;
344		case 3:
345			if (flags & IFF_UP)
346				continue; /* not down */
347			break;
348		}
349
350		if (all > 0) {
351			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
352			name[sdl->sdl_nlen] = '\0';
353		}
354
355		if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
356			perror("ifconfig: socket");
357			exit(1);
358		}
359
360		ifconfig(argc,argv,af,rafp);
361
362		close(s);
363
364		if (all == 0) {
365			all = -1; /* flag it as 'done' */
366			break;
367		}
368	}
369	free(buf);
370
371	if (all == 0)
372		errx(1, "interface %s does not exist..", name);
373
374
375	exit (0);
376}
377
378
379
380int
381ifconfig(argc,argv,af,rafp)
382	int argc;
383	char *argv[];
384	int af;
385	struct afswtch *rafp;
386{
387
388	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
389
390	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
391		perror("ioctl (SIOCGIFMETRIC)");
392	else
393		metric = ifr.ifr_metric;
394
395	if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
396		perror("ioctl (SIOCGIFMTU)");
397	else
398		mtu = ifr.ifr_mtu;
399
400	if (argc == 0) {
401		status();
402		return(0);
403	}
404
405	while (argc > 0) {
406		register struct cmd *p;
407
408		for (p = cmds; p->c_name; p++)
409			if (strcmp(*argv, p->c_name) == 0)
410				break;
411		if (p->c_name == 0 && setaddr)
412			p++;	/* got src, do dst */
413		if (p->c_func) {
414			if (p->c_parameter == NEXTARG) {
415				if (argv[1] == NULL)
416					errx(1, "'%s' requires argument",
417					    p->c_name);
418				(*p->c_func)(argv[1]);
419				argc--, argv++;
420			} else
421				(*p->c_func)(*argv, p->c_parameter);
422		}
423		argc--, argv++;
424	}
425#ifdef ISO
426	if (af == AF_ISO)
427		adjust_nsellength();
428#endif
429	if (setipdst && af==AF_IPX) {
430		struct ipxip_req rq;
431		int size = sizeof(rq);
432
433		rq.rq_ipx = addreq.ifra_addr;
434		rq.rq_ip = addreq.ifra_dstaddr;
435
436		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
437			Perror("Encapsulation Routing");
438	}
439	if (setipdst && af==AF_NS) {
440		struct nsip_req rq;
441		int size = sizeof(rq);
442
443		rq.rq_ns = addreq.ifra_addr;
444		rq.rq_ip = addreq.ifra_dstaddr;
445
446		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
447			Perror("Encapsulation Routing");
448	}
449	if (clearaddr) {
450		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
451			warnx("interface %s cannot change %s addresses!",
452			      name, rafp->af_name);
453			clearaddr = NULL;
454		}
455	}
456	if (clearaddr) {
457		int ret;
458		strncpy(rafp->af_ridreq, name, sizeof ifr.ifr_name);
459		if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
460			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
461				/* means no previous address for interface */
462			} else
463				Perror("ioctl (SIOCDIFADDR)");
464		}
465	}
466	if (newaddr) {
467		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
468			warnx("interface %s cannot change %s addresses!",
469			      name, rafp->af_name);
470			newaddr = NULL;
471		}
472	}
473	if (newaddr) {
474		strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
475		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
476			Perror("ioctl (SIOCAIFADDR)");
477	}
478	return(0);
479}
480#define RIDADDR 0
481#define ADDR	1
482#define MASK	2
483#define DSTADDR	3
484
485/*ARGSUSED*/
486setifaddr(addr, param)
487	char *addr;
488	short param;
489{
490	/*
491	 * Delay the ioctl to set the interface addr until flags are all set.
492	 * The address interpretation may depend on the flags,
493	 * and the flags may change when the address is set.
494	 */
495	setaddr++;
496	if (doalias == 0)
497		clearaddr = 1;
498	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
499}
500
501setifnetmask(addr)
502	char *addr;
503{
504	(*afp->af_getaddr)(addr, MASK);
505}
506
507setifbroadaddr(addr)
508	char *addr;
509{
510	(*afp->af_getaddr)(addr, DSTADDR);
511}
512
513setifipdst(addr)
514	char *addr;
515{
516	in_getaddr(addr, DSTADDR);
517	setipdst++;
518	clearaddr = 0;
519	newaddr = 0;
520}
521#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
522/*ARGSUSED*/
523notealias(addr, param)
524	char *addr;
525{
526	if (setaddr && doalias == 0 && param < 0)
527		bcopy((caddr_t)rqtosa(af_addreq),
528		      (caddr_t)rqtosa(af_ridreq),
529		      rqtosa(af_addreq)->sa_len);
530	doalias = param;
531	if (param < 0) {
532		clearaddr = 1;
533		newaddr = 0;
534	} else
535		clearaddr = 0;
536}
537
538/*ARGSUSED*/
539notrailers(vname, value)
540	char *vname;
541	int value;
542{
543	printf("Note: trailers are no longer sent, but always received\n");
544}
545
546/*ARGSUSED*/
547setifdstaddr(addr, param)
548	char *addr;
549	int param;
550{
551	(*afp->af_getaddr)(addr, DSTADDR);
552}
553
554setifflags(vname, value)
555	char *vname;
556	short value;
557{
558 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
559 		Perror("ioctl (SIOCGIFFLAGS)");
560 		exit(1);
561 	}
562	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
563 	flags = ifr.ifr_flags;
564
565	if (value < 0) {
566		value = -value;
567		flags &= ~value;
568	} else
569		flags |= value;
570	ifr.ifr_flags = flags;
571	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
572		Perror(vname);
573}
574
575setifmetric(val)
576	char *val;
577{
578	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
579	ifr.ifr_metric = atoi(val);
580	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
581		perror("ioctl (set metric)");
582}
583
584setifmtu(val)
585	char *val;
586{
587	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
588	ifr.ifr_mtu = atoi(val);
589	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
590		perror("ioctl (set mtu)");
591}
592
593#ifdef ISO
594setsnpaoffset(val)
595	char *val;
596{
597	iso_addreq.ifra_snpaoffset = atoi(val);
598}
599#endif
600
601#define	IFFBITS \
602"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
603\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
604
605/*
606 * Print the status of the interface.  If an address family was
607 * specified, show it and it only; otherwise, show them all.
608 */
609status()
610{
611	struct afswtch *p = NULL;
612	short af = ifr.ifr_addr.sa_family;
613	char *mynext;
614	struct if_msghdr *myifm;
615
616	printf("%s: ", name);
617	printb("flags", flags, IFFBITS);
618	if (metric)
619		printf(" metric %d", metric);
620	if (mtu)
621		printf(" mtu %d", mtu);
622	putchar('\n');
623
624	/*
625	 * XXX: Sigh. This is bad, I know.  At this point, we may have
626	 * *zero* RTM_NEWADDR's, so we have to "feel the water" before
627	 * incrementing the loop.  One day, I might feel inspired enough
628	 * to get the top level loop to pass a count down here so we
629	 * dont have to mess with this.  -Peter
630	 */
631	myifm = ifm;
632
633	while (1) {
634
635		mynext = next + ifm->ifm_msglen;
636
637		if (mynext >= lim)
638			break;
639
640		myifm = (struct if_msghdr *)mynext;
641
642		if (myifm->ifm_type != RTM_NEWADDR)
643			break;
644
645		next = mynext;
646
647		ifm = (struct if_msghdr *)next;
648
649		ifam = (struct ifa_msghdr *)myifm;
650		info.rti_addrs = ifam->ifam_addrs;
651
652		/* Expand the compacted addresses */
653		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
654			  &info);
655
656		if (afp) {
657			if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
658			    afp->af_status != ether_status) {
659				p = afp;
660				if (p->af_status != ether_status)
661					(*p->af_status)(1);
662			}
663		} else for (p = afs; p->af_name; p++) {
664			if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
665			    p->af_status != ether_status)
666				(*p->af_status)(0);
667		}
668	}
669	if (afp == NULL || afp->af_status == ether_status)
670		ether_status();
671	else if (afp && !p) {
672		warnx("%s has no %s IFA address!", name, afp->af_name);
673	}
674}
675
676in_status(force)
677	int force;
678{
679	struct sockaddr_in *sin, null_sin;
680	char *inet_ntoa();
681
682
683	memset(&null_sin, 0, sizeof(null_sin));
684
685	sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
686	if (!sin || sin->sin_family != AF_INET) {
687		if (!force)
688			return;
689		/* warnx("%s has no AF_INET IFA address!", name); */
690		sin = &null_sin;
691	}
692	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
693
694	if (flags & IFF_POINTOPOINT) {
695		/* note RTAX_BRD overlap with IFF_BROADCAST */
696		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
697		if (!sin)
698			sin = &null_sin;
699		printf("--> %s ", inet_ntoa(sin->sin_addr));
700	}
701
702	sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
703	if (!sin)
704		sin = &null_sin;
705	printf("netmask 0x%x ", ntohl(sin->sin_addr.s_addr));
706
707	if (flags & IFF_BROADCAST) {
708		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
709		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
710		if (sin && sin->sin_addr.s_addr != 0)
711			printf("broadcast %s", inet_ntoa(sin->sin_addr));
712	}
713	putchar('\n');
714}
715
716ipx_status(force)
717	int force;
718{
719	struct sockaddr_ipx *sipx, null_sipx;
720
721	close(s);
722	s = socket(AF_IPX, SOCK_DGRAM, 0);
723	if (s < 0) {
724		if (errno == EPROTONOSUPPORT)
725			return;
726		perror("ifconfig: socket");
727		exit(1);
728	}
729
730	memset(&null_sipx, 0, sizeof(null_sipx));
731
732	sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
733	if (!sipx || sipx->sipx_family != AF_IPX) {
734		if (!force)
735			return;
736		warnx("%s has no AF_IPX IFA address!", name);
737		sipx = &null_sipx;
738	}
739	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
740
741	if (flags & IFF_POINTOPOINT) {
742		sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_BRD];
743		if (!sipx)
744			sipx = &null_sipx;
745		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
746	}
747	putchar('\n');
748
749}
750
751xns_status(force)
752	int force;
753{
754	struct sockaddr_ns *sns, null_sns;
755
756	close(s);
757	s = socket(AF_NS, SOCK_DGRAM, 0);
758	if (s < 0) {
759		if (errno == EPROTONOSUPPORT)
760			return;
761		perror("ifconfig: socket");
762		exit(1);
763	}
764	memset(&null_sns, 0, sizeof(null_sns));
765
766	sns = (struct sockaddr_ns *)info.rti_info[RTAX_IFA];
767	if (!sns || sns->sns_family != AF_NS) {
768		if (!force)
769			return;
770		/* warnx("%s has no AF_NS IFA address!", name); */
771		sns = &null_sns;
772	}
773	printf("\tns %s ", ns_ntoa(sns->sns_addr));
774
775	if (flags & IFF_POINTOPOINT) {
776		sns = (struct sockaddr_ns *)info.rti_info[RTAX_BRD];
777		if (!sns)
778			sns = &null_sns;
779		printf("--> %s ", ns_ntoa(sns->sns_addr));
780	}
781
782	putchar('\n');
783}
784
785#ifdef ISO
786iso_status(force)
787	int force;
788{
789	struct sockaddr_iso *siso, null_siso;
790
791	close(s);
792	s = socket(AF_ISO, SOCK_DGRAM, 0);
793	if (s < 0) {
794		if (errno == EPROTONOSUPPORT)
795			return;
796		perror("ifconfig: socket");
797		exit(1);
798	}
799
800	memset(&null_siso, 0, sizeof(null_siso));
801
802	siso = (struct sockaddr_iso *)info.rti_info[RTAX_IFA];
803	if (!siso || siso->siso_family != AF_ISO) {
804		if (!force)
805			return;
806		/* warnx("%s has no AF_ISO IFA address!", name); */
807		siso = &null_siso;
808	}
809	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
810
811	/* XXX: is this right? is the ISO netmask meant to be before P2P? */
812	siso = (struct sockaddr_iso *)info.rti_info[RTAX_NETMASK];
813	if (siso)
814		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
815
816	if (flags & IFF_POINTOPOINT) {
817		siso = (struct sockaddr_iso *)info.rti_info[RTAX_BRD];
818		if (!siso)
819			siso = &null_siso;
820		printf("--> %s ", iso_ntoa(&siso->siso_addr));
821	}
822
823	putchar('\n');
824}
825#endif
826
827ether_status()
828{
829	char *cp;
830	int n;
831
832	cp = (char *)LLADDR(sdl);
833	if ((n = sdl->sdl_alen) > 0) {
834		if (sdl->sdl_type == IFT_ETHER)
835			printf ("\tether ");
836		else
837			printf ("\tlladdr ");
838             	while (--n >= 0)
839			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
840		putchar('\n');
841	}
842}
843
844Perror(cmd)
845	char *cmd;
846{
847	extern int errno;
848
849	switch (errno) {
850
851	case ENXIO:
852		errx(1, "%s: no such interface", cmd);
853		break;
854
855	case EPERM:
856		errx(1, "%s: permission denied", cmd);
857		break;
858
859	default:
860		err(1, "%s", cmd);
861	}
862}
863
864struct	in_addr inet_makeaddr();
865
866#define SIN(x) ((struct sockaddr_in *) &(x))
867struct sockaddr_in *sintab[] = {
868SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
869SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
870
871in_getaddr(s, which)
872	char *s;
873{
874	register struct sockaddr_in *sin = sintab[which];
875	struct hostent *hp;
876	struct netent *np;
877	int val;
878
879	sin->sin_len = sizeof(*sin);
880	if (which != MASK)
881		sin->sin_family = AF_INET;
882
883	if (inet_aton(s, &sin->sin_addr))
884		;
885	else if (hp = gethostbyname(s))
886		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
887	else if (np = getnetbyname(s))
888		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
889	else
890		errx(1, "%s: bad value", s);
891}
892
893/*
894 * Print a value a la the %b format of the kernel's printf
895 */
896printb(s, v, bits)
897	char *s;
898	register char *bits;
899	register unsigned short v;
900{
901	register int i, any = 0;
902	register char c;
903
904	if (bits && *bits == 8)
905		printf("%s=%o", s, v);
906	else
907		printf("%s=%x", s, v);
908	bits++;
909	if (bits) {
910		putchar('<');
911		while (i = *bits++) {
912			if (v & (1 << (i-1))) {
913				if (any)
914					putchar(',');
915				any = 1;
916				for (; (c = *bits) > 32; bits++)
917					putchar(c);
918			} else
919				for (; *bits > 32; bits++)
920					;
921		}
922		putchar('>');
923	}
924}
925
926#define SIPX(x) ((struct sockaddr_ipx *) &(x))
927struct sockaddr_ipx *sipxtab[] = {
928SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
929SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
930
931ipx_getaddr(addr, which)
932char *addr;
933{
934	struct sockaddr_ipx *sipx = sipxtab[which];
935	struct ipx_addr ipx_addr();
936
937	sipx->sipx_family = AF_IPX;
938	sipx->sipx_len = sizeof(*sipx);
939	sipx->sipx_addr = ipx_addr(addr);
940	if (which == MASK)
941		printf("Attempt to set IPX netmask will be ineffectual\n");
942}
943
944#define SNS(x) ((struct sockaddr_ns *) &(x))
945struct sockaddr_ns *snstab[] = {
946SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
947SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
948
949xns_getaddr(addr, which)
950char *addr;
951{
952	struct sockaddr_ns *sns = snstab[which];
953	struct ns_addr ns_addr();
954
955	sns->sns_family = AF_NS;
956	sns->sns_len = sizeof(*sns);
957	sns->sns_addr = ns_addr(addr);
958	if (which == MASK)
959		printf("Attempt to set XNS netmask will be ineffectual\n");
960}
961
962#ifdef ISO
963#define SISO(x) ((struct sockaddr_iso *) &(x))
964struct sockaddr_iso *sisotab[] = {
965SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
966SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
967
968iso_getaddr(addr, which)
969char *addr;
970{
971	register struct sockaddr_iso *siso = sisotab[which];
972	struct iso_addr *iso_addr();
973	siso->siso_addr = *iso_addr(addr);
974
975	if (which == MASK) {
976		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
977		siso->siso_nlen = 0;
978	} else {
979		siso->siso_len = sizeof(*siso);
980		siso->siso_family = AF_ISO;
981	}
982}
983
984setnsellength(val)
985	char *val;
986{
987	nsellength = atoi(val);
988	if (nsellength < 0)
989		errx(1, "Negative NSEL length is absurd");
990	if (afp == 0 || afp->af_af != AF_ISO)
991		errx(1, "Setting NSEL length valid only for iso");
992}
993
994fixnsel(s)
995register struct sockaddr_iso *s;
996{
997	if (s->siso_family == 0)
998		return;
999	s->siso_tlen = nsellength;
1000}
1001
1002adjust_nsellength()
1003{
1004	fixnsel(sisotab[RIDADDR]);
1005	fixnsel(sisotab[ADDR]);
1006	fixnsel(sisotab[DSTADDR]);
1007}
1008#endif
1009