ifconfig.c revision 13329
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 },
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		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
429			warnx("interface %s cannot change %s addresses!",
430			      name, rafp->af_name);
431			clearaddr = NULL;
432		}
433	}
434	if (clearaddr) {
435		int ret;
436		strncpy(rafp->af_ridreq, name, sizeof ifr.ifr_name);
437		if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
438			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
439				/* means no previous address for interface */
440			} else
441				Perror("ioctl (SIOCDIFADDR)");
442		}
443	}
444	if (newaddr) {
445		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
446			warnx("interface %s cannot change %s addresses!",
447			      name, rafp->af_name);
448			newaddr = NULL;
449		}
450	}
451	if (newaddr) {
452		strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
453		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
454			Perror("ioctl (SIOCAIFADDR)");
455	}
456	return(0);
457}
458#define RIDADDR 0
459#define ADDR	1
460#define MASK	2
461#define DSTADDR	3
462
463/*ARGSUSED*/
464setifaddr(addr, param)
465	char *addr;
466	short param;
467{
468	/*
469	 * Delay the ioctl to set the interface addr until flags are all set.
470	 * The address interpretation may depend on the flags,
471	 * and the flags may change when the address is set.
472	 */
473	setaddr++;
474	if (doalias == 0)
475		clearaddr = 1;
476	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
477}
478
479setifnetmask(addr)
480	char *addr;
481{
482	(*afp->af_getaddr)(addr, MASK);
483}
484
485setifbroadaddr(addr)
486	char *addr;
487{
488	(*afp->af_getaddr)(addr, DSTADDR);
489}
490
491setifipdst(addr)
492	char *addr;
493{
494	in_getaddr(addr, DSTADDR);
495	setipdst++;
496	clearaddr = 0;
497	newaddr = 0;
498}
499#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
500/*ARGSUSED*/
501notealias(addr, param)
502	char *addr;
503{
504	if (setaddr && doalias == 0 && param < 0)
505		bcopy((caddr_t)rqtosa(af_addreq),
506		      (caddr_t)rqtosa(af_ridreq),
507		      rqtosa(af_addreq)->sa_len);
508	doalias = param;
509	if (param < 0) {
510		clearaddr = 1;
511		newaddr = 0;
512	} else
513		clearaddr = 0;
514}
515
516/*ARGSUSED*/
517notrailers(vname, value)
518	char *vname;
519	int value;
520{
521	printf("Note: trailers are no longer sent, but always received\n");
522}
523
524/*ARGSUSED*/
525setifdstaddr(addr, param)
526	char *addr;
527	int param;
528{
529	(*afp->af_getaddr)(addr, DSTADDR);
530}
531
532setifflags(vname, value)
533	char *vname;
534	short value;
535{
536 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
537 		Perror("ioctl (SIOCGIFFLAGS)");
538 		exit(1);
539 	}
540	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
541 	flags = ifr.ifr_flags;
542
543	if (value < 0) {
544		value = -value;
545		flags &= ~value;
546	} else
547		flags |= value;
548	ifr.ifr_flags = flags;
549	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
550		Perror(vname);
551}
552
553setifmetric(val)
554	char *val;
555{
556	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
557	ifr.ifr_metric = atoi(val);
558	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
559		perror("ioctl (set metric)");
560}
561
562setifmtu(val)
563	char *val;
564{
565	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
566	ifr.ifr_mtu = atoi(val);
567	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
568		perror("ioctl (set mtu)");
569}
570
571setsnpaoffset(val)
572	char *val;
573{
574	iso_addreq.ifra_snpaoffset = atoi(val);
575}
576
577#define	IFFBITS \
578"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
579\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
580
581/*
582 * Print the status of the interface.  If an address family was
583 * specified, show it and it only; otherwise, show them all.
584 */
585status()
586{
587	register struct afswtch *p = afp;
588	short af = ifr.ifr_addr.sa_family;
589	char *mynext;
590	struct if_msghdr *myifm;
591
592	printf("%s: ", name);
593	printb("flags", flags, IFFBITS);
594	if (metric)
595		printf(" metric %d", metric);
596	if (mtu)
597		printf(" mtu %d", mtu);
598	putchar('\n');
599
600	/*
601	 * XXX: Sigh. This is bad, I know.  At this point, we may have
602	 * *zero* RTM_NEWADDR's, so we have to "feel the water" before
603	 * incrementing the loop.  One day, I might feel inspired enough
604	 * to get the top level loop to pass a count down here so we
605	 * dont have to mess with this.  -Peter
606	 */
607	myifm = ifm;
608
609	while (1) {
610
611		mynext = next + ifm->ifm_msglen;
612
613		if (mynext >= lim)
614			break;
615
616		myifm = (struct if_msghdr *)mynext;
617
618		if (myifm->ifm_type != RTM_NEWADDR)
619			break;
620
621		next = mynext;
622
623		ifm = (struct if_msghdr *)next;
624
625		ifam = (struct ifa_msghdr *)myifm;
626		info.rti_addrs = ifam->ifam_addrs;
627
628		/* Expand the compacted addresses */
629		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
630			  &info);
631
632
633		if ((p = afp) != NULL) {
634			if (p->af_status != ether_status)
635				(*p->af_status)(1);
636		} else for (p = afs; p->af_name; p++) {
637			ifr.ifr_addr.sa_family = p->af_af;
638			if (p->af_status != ether_status)
639				(*p->af_status)(0);
640		}
641	}
642	if (afp == NULL || afp->af_status == ether_status)
643		ether_status();
644}
645
646in_status(force)
647	int force;
648{
649	struct sockaddr_in *sin, null_sin;
650	char *inet_ntoa();
651
652
653	memset(&null_sin, 0, sizeof(null_sin));
654
655	sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
656	if (!sin || sin->sin_family != AF_INET) {
657		if (!force)
658			return;
659		/* warnx("%s has no AF_INET IFA address!", name); */
660		sin = &null_sin;
661	}
662	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
663
664	if (flags & IFF_POINTOPOINT) {
665		/* note RTAX_BRD overlap with IFF_BROADCAST */
666		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
667		if (!sin)
668			sin = &null_sin;
669		printf("--> %s ", inet_ntoa(sin->sin_addr));
670	}
671
672	sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
673	if (!sin)
674		sin = &null_sin;
675	printf("netmask 0x%x ", ntohl(sin->sin_addr.s_addr));
676
677	if (flags & IFF_BROADCAST) {
678		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
679		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
680		if (sin && sin->sin_addr.s_addr != 0)
681			printf("broadcast %s", inet_ntoa(sin->sin_addr));
682	}
683	putchar('\n');
684}
685
686ipx_status(force)
687	int force;
688{
689	struct sockaddr_ipx *sipx, null_sipx;
690
691	close(s);
692	s = socket(AF_IPX, SOCK_DGRAM, 0);
693	if (s < 0) {
694		if (errno == EPROTONOSUPPORT)
695			return;
696		perror("ifconfig: socket");
697		exit(1);
698	}
699
700	memset(&null_sipx, 0, sizeof(null_sipx));
701
702	sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
703	if (!sipx || sipx->sipx_family != AF_IPX) {
704		if (!force)
705			return;
706		/* warnx("%s has no AF_IPX IFA address!", name); */
707		sipx = &null_sipx;
708	}
709	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
710
711	if (flags & IFF_POINTOPOINT) {
712		sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_BRD];
713		if (!sipx)
714			sipx = &null_sipx;
715		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
716	}
717	putchar('\n');
718
719}
720
721xns_status(force)
722	int force;
723{
724	struct sockaddr_ns *sns, null_sns;
725
726	close(s);
727	s = socket(AF_NS, SOCK_DGRAM, 0);
728	if (s < 0) {
729		if (errno == EPROTONOSUPPORT)
730			return;
731		perror("ifconfig: socket");
732		exit(1);
733	}
734	memset(&null_sns, 0, sizeof(null_sns));
735
736	sns = (struct sockaddr_ns *)info.rti_info[RTAX_IFA];
737	if (!sns || sns->sns_family != AF_NS) {
738		if (!force)
739			return;
740		/* warnx("%s has no AF_NS IFA address!", name); */
741		sns = &null_sns;
742	}
743	printf("\tns %s ", ns_ntoa(sns->sns_addr));
744
745	if (flags & IFF_POINTOPOINT) {
746		sns = (struct sockaddr_ns *)info.rti_info[RTAX_BRD];
747		if (!sns)
748			sns = &null_sns;
749		printf("--> %s ", ns_ntoa(sns->sns_addr));
750	}
751
752	putchar('\n');
753}
754
755iso_status(force)
756	int force;
757{
758	struct sockaddr_iso *siso, null_siso;
759
760	close(s);
761	s = socket(AF_ISO, SOCK_DGRAM, 0);
762	if (s < 0) {
763		if (errno == EPROTONOSUPPORT)
764			return;
765		perror("ifconfig: socket");
766		exit(1);
767	}
768
769	memset(&null_siso, 0, sizeof(null_siso));
770
771	siso = (struct sockaddr_iso *)info.rti_info[RTAX_IFA];
772	if (!siso || siso->siso_family != AF_ISO) {
773		if (!force)
774			return;
775		/* warnx("%s has no AF_ISO IFA address!", name); */
776		siso = &null_siso;
777	}
778	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
779
780	/* XXX: is this right? is the ISO netmask meant to be before P2P? */
781	siso = (struct sockaddr_iso *)info.rti_info[RTAX_NETMASK];
782	if (siso)
783		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
784
785	if (flags & IFF_POINTOPOINT) {
786		siso = (struct sockaddr_iso *)info.rti_info[RTAX_BRD];
787		if (!siso)
788			siso = &null_siso;
789		printf("--> %s ", iso_ntoa(&siso->siso_addr));
790	}
791
792	putchar('\n');
793}
794
795
796ether_status()
797{
798	char *cp;
799	int n;
800
801	cp = (char *)LLADDR(sdl);
802	if ((n = sdl->sdl_alen) > 0) {
803		if (sdl->sdl_type == IFT_ETHER)
804			printf ("\tether ");
805		else
806			printf ("\tlladdr ");
807             	while (--n >= 0)
808			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
809		putchar('\n');
810	}
811}
812
813Perror(cmd)
814	char *cmd;
815{
816	extern int errno;
817
818	switch (errno) {
819
820	case ENXIO:
821		errx(1, "%s: no such interface", cmd);
822		break;
823
824	case EPERM:
825		errx(1, "%s: permission denied", cmd);
826		break;
827
828	default:
829		err(1, "%s", cmd);
830	}
831}
832
833struct	in_addr inet_makeaddr();
834
835#define SIN(x) ((struct sockaddr_in *) &(x))
836struct sockaddr_in *sintab[] = {
837SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
838SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
839
840in_getaddr(s, which)
841	char *s;
842{
843	register struct sockaddr_in *sin = sintab[which];
844	struct hostent *hp;
845	struct netent *np;
846	int val;
847
848	sin->sin_len = sizeof(*sin);
849	if (which != MASK)
850		sin->sin_family = AF_INET;
851
852	if (inet_aton(s, &sin->sin_addr))
853		;
854	else if (hp = gethostbyname(s))
855		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
856	else if (np = getnetbyname(s))
857		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
858	else
859		errx(1, "%s: bad value", s);
860}
861
862/*
863 * Print a value a la the %b format of the kernel's printf
864 */
865printb(s, v, bits)
866	char *s;
867	register char *bits;
868	register unsigned short v;
869{
870	register int i, any = 0;
871	register char c;
872
873	if (bits && *bits == 8)
874		printf("%s=%o", s, v);
875	else
876		printf("%s=%x", s, v);
877	bits++;
878	if (bits) {
879		putchar('<');
880		while (i = *bits++) {
881			if (v & (1 << (i-1))) {
882				if (any)
883					putchar(',');
884				any = 1;
885				for (; (c = *bits) > 32; bits++)
886					putchar(c);
887			} else
888				for (; *bits > 32; bits++)
889					;
890		}
891		putchar('>');
892	}
893}
894
895#define SIPX(x) ((struct sockaddr_ipx *) &(x))
896struct sockaddr_ipx *sipxtab[] = {
897SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
898SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
899
900ipx_getaddr(addr, which)
901char *addr;
902{
903	struct sockaddr_ipx *sipx = sipxtab[which];
904	struct ipx_addr ipx_addr();
905
906	sipx->sipx_family = AF_IPX;
907	sipx->sipx_len = sizeof(*sipx);
908	sipx->sipx_addr = ipx_addr(addr);
909	if (which == MASK)
910		printf("Attempt to set IPX netmask will be ineffectual\n");
911}
912
913#define SNS(x) ((struct sockaddr_ns *) &(x))
914struct sockaddr_ns *snstab[] = {
915SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
916SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
917
918xns_getaddr(addr, which)
919char *addr;
920{
921	struct sockaddr_ns *sns = snstab[which];
922	struct ns_addr ns_addr();
923
924	sns->sns_family = AF_NS;
925	sns->sns_len = sizeof(*sns);
926	sns->sns_addr = ns_addr(addr);
927	if (which == MASK)
928		printf("Attempt to set XNS netmask will be ineffectual\n");
929}
930
931#define SISO(x) ((struct sockaddr_iso *) &(x))
932struct sockaddr_iso *sisotab[] = {
933SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
934SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
935
936iso_getaddr(addr, which)
937char *addr;
938{
939	register struct sockaddr_iso *siso = sisotab[which];
940	struct iso_addr *iso_addr();
941	siso->siso_addr = *iso_addr(addr);
942
943	if (which == MASK) {
944		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
945		siso->siso_nlen = 0;
946	} else {
947		siso->siso_len = sizeof(*siso);
948		siso->siso_family = AF_ISO;
949	}
950}
951
952setnsellength(val)
953	char *val;
954{
955	nsellength = atoi(val);
956	if (nsellength < 0)
957		errx(1, "Negative NSEL length is absurd");
958	if (afp == 0 || afp->af_af != AF_ISO)
959		errx(1, "Setting NSEL length valid only for iso");
960}
961
962fixnsel(s)
963register struct sockaddr_iso *s;
964{
965	if (s->siso_family == 0)
966		return;
967	s->siso_tlen = nsellength;
968}
969
970adjust_nsellength()
971{
972	fixnsel(sisotab[RIDADDR]);
973	fixnsel(sisotab[ADDR]);
974	fixnsel(sisotab[DSTADDR]);
975}
976