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