ifconfig.c revision 13345
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 not real!! */
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%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		    "\t[ -a ] [ -ad ] [ -au ]\n");
257		exit(1);
258	}
259	argc--, argv++;
260	strncpy(name, *argv, sizeof(name));
261	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
262	argc--, argv++;
263	if (argc > 0) {
264		for (afp = rafp = afs; rafp->af_name; rafp++)
265			if (strcmp(rafp->af_name, *argv) == 0) {
266				afp = rafp; argc--; argv++;
267				break;
268			}
269		rafp = afp;
270		af = ifr.ifr_addr.sa_family = rafp->af_af;
271	}
272
273	mib[0] = CTL_NET;
274	mib[1] = PF_ROUTE;
275	mib[2] = 0;
276	mib[3] = 0;	/* address family */
277	mib[4] = NET_RT_IFLIST;
278	mib[5] = 0;
279
280	/* if particular family specified, only ask about it */
281	if (afp) {
282		mib[3] = afp->af_af;
283	}
284
285	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
286		errx(1, "iflist-sysctl-estimate");
287	if ((buf = malloc(needed)) == NULL)
288		errx(1, "malloc");
289	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
290		errx(1, "actual retrieval of interface table");
291	lim = buf + needed;
292
293	all = 0;
294	if (strcmp(name, "-a") == 0)
295		all = 1;	/* All interfaces */
296	else if (strcmp(name, "-au") == 0)
297		all = 2;	/* All IFF_UPinterfaces */
298	else if (strcmp(name, "-ad") == 0)
299		all = 3;	/* All !IFF_UP interfaces */
300
301	for (next = buf; next < lim; next += ifm->ifm_msglen) {
302
303		ifm = (struct if_msghdr *)next;
304
305		/* XXX: Swallow up leftover NEWADDR messages */
306		if (ifm->ifm_type == RTM_NEWADDR)
307			continue;
308
309		if (ifm->ifm_type == RTM_IFINFO) {
310			sdl = (struct sockaddr_dl *)(ifm + 1);
311			flags = ifm->ifm_flags;
312		} else {
313			errx(1, "out of sync parsing NET_RT_IFLIST");
314		}
315
316		switch(all) {
317		case -1:
318		case 0:
319			if (strlen(name) != sdl->sdl_nlen)
320				continue; /* not same len */
321			if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
322				continue; /* not same name */
323			break;
324		case 1:
325			break;	/* always do it */
326		case 2:
327			if ((flags & IFF_UP) == 0)
328				continue; /* not up */
329			break;
330		case 3:
331			if (flags & IFF_UP)
332				continue; /* not down */
333			break;
334		}
335
336		if (all > 0) {
337			strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
338			name[sdl->sdl_nlen] = '\0';
339		}
340
341		if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
342			perror("ifconfig: socket");
343			exit(1);
344		}
345
346		ifconfig(argc,argv,af,rafp);
347
348		close(s);
349
350		if (all == 0) {
351			all = -1; /* flag it as 'done' */
352			break;
353		}
354	}
355	free(buf);
356
357	if (all == 0)
358		errx(1, "interface %s does not exist..", name);
359
360
361	exit (0);
362}
363
364
365
366int
367ifconfig(argc,argv,af,rafp)
368	int argc;
369	char *argv[];
370	int af;
371	struct afswtch *rafp;
372{
373
374	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
375
376	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
377		perror("ioctl (SIOCGIFMETRIC)");
378	else
379		metric = ifr.ifr_metric;
380
381	if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
382		perror("ioctl (SIOCGIFMTU)");
383	else
384		mtu = ifr.ifr_mtu;
385
386	if (argc == 0) {
387		status();
388		return(0);
389	}
390
391	while (argc > 0) {
392		register struct cmd *p;
393
394		for (p = cmds; p->c_name; p++)
395			if (strcmp(*argv, p->c_name) == 0)
396				break;
397		if (p->c_name == 0 && setaddr)
398			p++;	/* got src, do dst */
399		if (p->c_func) {
400			if (p->c_parameter == NEXTARG) {
401				if (argv[1] == NULL)
402					errx(1, "'%s' requires argument",
403					    p->c_name);
404				(*p->c_func)(argv[1]);
405				argc--, argv++;
406			} else
407				(*p->c_func)(*argv, p->c_parameter);
408		}
409		argc--, argv++;
410	}
411	if (af == AF_ISO)
412		adjust_nsellength();
413	if (setipdst && af==AF_IPX) {
414		struct ipxip_req rq;
415		int size = sizeof(rq);
416
417		rq.rq_ipx = addreq.ifra_addr;
418		rq.rq_ip = addreq.ifra_dstaddr;
419
420		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
421			Perror("Encapsulation Routing");
422	}
423	if (setipdst && af==AF_NS) {
424		struct nsip_req rq;
425		int size = sizeof(rq);
426
427		rq.rq_ns = addreq.ifra_addr;
428		rq.rq_ip = addreq.ifra_dstaddr;
429
430		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
431			Perror("Encapsulation Routing");
432	}
433	if (clearaddr) {
434		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
435			warnx("interface %s cannot change %s addresses!",
436			      name, rafp->af_name);
437			clearaddr = NULL;
438		}
439	}
440	if (clearaddr) {
441		int ret;
442		strncpy(rafp->af_ridreq, name, sizeof ifr.ifr_name);
443		if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
444			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
445				/* means no previous address for interface */
446			} else
447				Perror("ioctl (SIOCDIFADDR)");
448		}
449	}
450	if (newaddr) {
451		if (rafp->af_ridreq == NULL || rafp->af_difaddr == 0) {
452			warnx("interface %s cannot change %s addresses!",
453			      name, rafp->af_name);
454			newaddr = NULL;
455		}
456	}
457	if (newaddr) {
458		strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
459		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
460			Perror("ioctl (SIOCAIFADDR)");
461	}
462	return(0);
463}
464#define RIDADDR 0
465#define ADDR	1
466#define MASK	2
467#define DSTADDR	3
468
469/*ARGSUSED*/
470setifaddr(addr, param)
471	char *addr;
472	short param;
473{
474	/*
475	 * Delay the ioctl to set the interface addr until flags are all set.
476	 * The address interpretation may depend on the flags,
477	 * and the flags may change when the address is set.
478	 */
479	setaddr++;
480	if (doalias == 0)
481		clearaddr = 1;
482	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
483}
484
485setifnetmask(addr)
486	char *addr;
487{
488	(*afp->af_getaddr)(addr, MASK);
489}
490
491setifbroadaddr(addr)
492	char *addr;
493{
494	(*afp->af_getaddr)(addr, DSTADDR);
495}
496
497setifipdst(addr)
498	char *addr;
499{
500	in_getaddr(addr, DSTADDR);
501	setipdst++;
502	clearaddr = 0;
503	newaddr = 0;
504}
505#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
506/*ARGSUSED*/
507notealias(addr, param)
508	char *addr;
509{
510	if (setaddr && doalias == 0 && param < 0)
511		bcopy((caddr_t)rqtosa(af_addreq),
512		      (caddr_t)rqtosa(af_ridreq),
513		      rqtosa(af_addreq)->sa_len);
514	doalias = param;
515	if (param < 0) {
516		clearaddr = 1;
517		newaddr = 0;
518	} else
519		clearaddr = 0;
520}
521
522/*ARGSUSED*/
523notrailers(vname, value)
524	char *vname;
525	int value;
526{
527	printf("Note: trailers are no longer sent, but always received\n");
528}
529
530/*ARGSUSED*/
531setifdstaddr(addr, param)
532	char *addr;
533	int param;
534{
535	(*afp->af_getaddr)(addr, DSTADDR);
536}
537
538setifflags(vname, value)
539	char *vname;
540	short value;
541{
542 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
543 		Perror("ioctl (SIOCGIFFLAGS)");
544 		exit(1);
545 	}
546	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
547 	flags = ifr.ifr_flags;
548
549	if (value < 0) {
550		value = -value;
551		flags &= ~value;
552	} else
553		flags |= value;
554	ifr.ifr_flags = flags;
555	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
556		Perror(vname);
557}
558
559setifmetric(val)
560	char *val;
561{
562	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
563	ifr.ifr_metric = atoi(val);
564	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
565		perror("ioctl (set metric)");
566}
567
568setifmtu(val)
569	char *val;
570{
571	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
572	ifr.ifr_mtu = atoi(val);
573	if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
574		perror("ioctl (set mtu)");
575}
576
577setsnpaoffset(val)
578	char *val;
579{
580	iso_addreq.ifra_snpaoffset = atoi(val);
581}
582
583#define	IFFBITS \
584"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
585\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
586
587/*
588 * Print the status of the interface.  If an address family was
589 * specified, show it and it only; otherwise, show them all.
590 */
591status()
592{
593	struct afswtch *p = NULL;
594	short af = ifr.ifr_addr.sa_family;
595	char *mynext;
596	struct if_msghdr *myifm;
597
598	printf("%s: ", name);
599	printb("flags", flags, IFFBITS);
600	if (metric)
601		printf(" metric %d", metric);
602	if (mtu)
603		printf(" mtu %d", mtu);
604	putchar('\n');
605
606	/*
607	 * XXX: Sigh. This is bad, I know.  At this point, we may have
608	 * *zero* RTM_NEWADDR's, so we have to "feel the water" before
609	 * incrementing the loop.  One day, I might feel inspired enough
610	 * to get the top level loop to pass a count down here so we
611	 * dont have to mess with this.  -Peter
612	 */
613	myifm = ifm;
614
615	while (1) {
616
617		mynext = next + ifm->ifm_msglen;
618
619		if (mynext >= lim)
620			break;
621
622		myifm = (struct if_msghdr *)mynext;
623
624		if (myifm->ifm_type != RTM_NEWADDR)
625			break;
626
627		next = mynext;
628
629		ifm = (struct if_msghdr *)next;
630
631		ifam = (struct ifa_msghdr *)myifm;
632		info.rti_addrs = ifam->ifam_addrs;
633
634		/* Expand the compacted addresses */
635		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
636			  &info);
637
638		if (afp) {
639			if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
640			    afp->af_status != ether_status) {
641				p = afp;
642				if (p->af_status != ether_status)
643					(*p->af_status)(1);
644			}
645		} else for (p = afs; p->af_name; p++) {
646			if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
647			    p->af_status != ether_status)
648				(*p->af_status)(0);
649		}
650	}
651	if (afp == NULL || afp->af_status == ether_status)
652		ether_status();
653	else if (afp && !p) {
654		warnx("%s has no %s IFA address!", name, afp->af_name);
655	}
656}
657
658in_status(force)
659	int force;
660{
661	struct sockaddr_in *sin, null_sin;
662	char *inet_ntoa();
663
664
665	memset(&null_sin, 0, sizeof(null_sin));
666
667	sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
668	if (!sin || sin->sin_family != AF_INET) {
669		if (!force)
670			return;
671		/* warnx("%s has no AF_INET IFA address!", name); */
672		sin = &null_sin;
673	}
674	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
675
676	if (flags & IFF_POINTOPOINT) {
677		/* note RTAX_BRD overlap with IFF_BROADCAST */
678		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
679		if (!sin)
680			sin = &null_sin;
681		printf("--> %s ", inet_ntoa(sin->sin_addr));
682	}
683
684	sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
685	if (!sin)
686		sin = &null_sin;
687	printf("netmask 0x%x ", ntohl(sin->sin_addr.s_addr));
688
689	if (flags & IFF_BROADCAST) {
690		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
691		sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
692		if (sin && sin->sin_addr.s_addr != 0)
693			printf("broadcast %s", inet_ntoa(sin->sin_addr));
694	}
695	putchar('\n');
696}
697
698ipx_status(force)
699	int force;
700{
701	struct sockaddr_ipx *sipx, null_sipx;
702
703	close(s);
704	s = socket(AF_IPX, SOCK_DGRAM, 0);
705	if (s < 0) {
706		if (errno == EPROTONOSUPPORT)
707			return;
708		perror("ifconfig: socket");
709		exit(1);
710	}
711
712	memset(&null_sipx, 0, sizeof(null_sipx));
713
714	sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_IFA];
715	if (!sipx || sipx->sipx_family != AF_IPX) {
716		if (!force)
717			return;
718		warnx("%s has no AF_IPX IFA address!", name);
719		sipx = &null_sipx;
720	}
721	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
722
723	if (flags & IFF_POINTOPOINT) {
724		sipx = (struct sockaddr_ipx *)info.rti_info[RTAX_BRD];
725		if (!sipx)
726			sipx = &null_sipx;
727		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
728	}
729	putchar('\n');
730
731}
732
733xns_status(force)
734	int force;
735{
736	struct sockaddr_ns *sns, null_sns;
737
738	close(s);
739	s = socket(AF_NS, SOCK_DGRAM, 0);
740	if (s < 0) {
741		if (errno == EPROTONOSUPPORT)
742			return;
743		perror("ifconfig: socket");
744		exit(1);
745	}
746	memset(&null_sns, 0, sizeof(null_sns));
747
748	sns = (struct sockaddr_ns *)info.rti_info[RTAX_IFA];
749	if (!sns || sns->sns_family != AF_NS) {
750		if (!force)
751			return;
752		/* warnx("%s has no AF_NS IFA address!", name); */
753		sns = &null_sns;
754	}
755	printf("\tns %s ", ns_ntoa(sns->sns_addr));
756
757	if (flags & IFF_POINTOPOINT) {
758		sns = (struct sockaddr_ns *)info.rti_info[RTAX_BRD];
759		if (!sns)
760			sns = &null_sns;
761		printf("--> %s ", ns_ntoa(sns->sns_addr));
762	}
763
764	putchar('\n');
765}
766
767iso_status(force)
768	int force;
769{
770	struct sockaddr_iso *siso, null_siso;
771
772	close(s);
773	s = socket(AF_ISO, SOCK_DGRAM, 0);
774	if (s < 0) {
775		if (errno == EPROTONOSUPPORT)
776			return;
777		perror("ifconfig: socket");
778		exit(1);
779	}
780
781	memset(&null_siso, 0, sizeof(null_siso));
782
783	siso = (struct sockaddr_iso *)info.rti_info[RTAX_IFA];
784	if (!siso || siso->siso_family != AF_ISO) {
785		if (!force)
786			return;
787		/* warnx("%s has no AF_ISO IFA address!", name); */
788		siso = &null_siso;
789	}
790	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
791
792	/* XXX: is this right? is the ISO netmask meant to be before P2P? */
793	siso = (struct sockaddr_iso *)info.rti_info[RTAX_NETMASK];
794	if (siso)
795		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
796
797	if (flags & IFF_POINTOPOINT) {
798		siso = (struct sockaddr_iso *)info.rti_info[RTAX_BRD];
799		if (!siso)
800			siso = &null_siso;
801		printf("--> %s ", iso_ntoa(&siso->siso_addr));
802	}
803
804	putchar('\n');
805}
806
807
808ether_status()
809{
810	char *cp;
811	int n;
812
813	cp = (char *)LLADDR(sdl);
814	if ((n = sdl->sdl_alen) > 0) {
815		if (sdl->sdl_type == IFT_ETHER)
816			printf ("\tether ");
817		else
818			printf ("\tlladdr ");
819             	while (--n >= 0)
820			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
821		putchar('\n');
822	}
823}
824
825Perror(cmd)
826	char *cmd;
827{
828	extern int errno;
829
830	switch (errno) {
831
832	case ENXIO:
833		errx(1, "%s: no such interface", cmd);
834		break;
835
836	case EPERM:
837		errx(1, "%s: permission denied", cmd);
838		break;
839
840	default:
841		err(1, "%s", cmd);
842	}
843}
844
845struct	in_addr inet_makeaddr();
846
847#define SIN(x) ((struct sockaddr_in *) &(x))
848struct sockaddr_in *sintab[] = {
849SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
850SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
851
852in_getaddr(s, which)
853	char *s;
854{
855	register struct sockaddr_in *sin = sintab[which];
856	struct hostent *hp;
857	struct netent *np;
858	int val;
859
860	sin->sin_len = sizeof(*sin);
861	if (which != MASK)
862		sin->sin_family = AF_INET;
863
864	if (inet_aton(s, &sin->sin_addr))
865		;
866	else if (hp = gethostbyname(s))
867		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
868	else if (np = getnetbyname(s))
869		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
870	else
871		errx(1, "%s: bad value", s);
872}
873
874/*
875 * Print a value a la the %b format of the kernel's printf
876 */
877printb(s, v, bits)
878	char *s;
879	register char *bits;
880	register unsigned short v;
881{
882	register int i, any = 0;
883	register char c;
884
885	if (bits && *bits == 8)
886		printf("%s=%o", s, v);
887	else
888		printf("%s=%x", s, v);
889	bits++;
890	if (bits) {
891		putchar('<');
892		while (i = *bits++) {
893			if (v & (1 << (i-1))) {
894				if (any)
895					putchar(',');
896				any = 1;
897				for (; (c = *bits) > 32; bits++)
898					putchar(c);
899			} else
900				for (; *bits > 32; bits++)
901					;
902		}
903		putchar('>');
904	}
905}
906
907#define SIPX(x) ((struct sockaddr_ipx *) &(x))
908struct sockaddr_ipx *sipxtab[] = {
909SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
910SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
911
912ipx_getaddr(addr, which)
913char *addr;
914{
915	struct sockaddr_ipx *sipx = sipxtab[which];
916	struct ipx_addr ipx_addr();
917
918	sipx->sipx_family = AF_IPX;
919	sipx->sipx_len = sizeof(*sipx);
920	sipx->sipx_addr = ipx_addr(addr);
921	if (which == MASK)
922		printf("Attempt to set IPX netmask will be ineffectual\n");
923}
924
925#define SNS(x) ((struct sockaddr_ns *) &(x))
926struct sockaddr_ns *snstab[] = {
927SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
928SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
929
930xns_getaddr(addr, which)
931char *addr;
932{
933	struct sockaddr_ns *sns = snstab[which];
934	struct ns_addr ns_addr();
935
936	sns->sns_family = AF_NS;
937	sns->sns_len = sizeof(*sns);
938	sns->sns_addr = ns_addr(addr);
939	if (which == MASK)
940		printf("Attempt to set XNS netmask will be ineffectual\n");
941}
942
943#define SISO(x) ((struct sockaddr_iso *) &(x))
944struct sockaddr_iso *sisotab[] = {
945SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
946SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
947
948iso_getaddr(addr, which)
949char *addr;
950{
951	register struct sockaddr_iso *siso = sisotab[which];
952	struct iso_addr *iso_addr();
953	siso->siso_addr = *iso_addr(addr);
954
955	if (which == MASK) {
956		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
957		siso->siso_nlen = 0;
958	} else {
959		siso->siso_len = sizeof(*siso);
960		siso->siso_family = AF_ISO;
961	}
962}
963
964setnsellength(val)
965	char *val;
966{
967	nsellength = atoi(val);
968	if (nsellength < 0)
969		errx(1, "Negative NSEL length is absurd");
970	if (afp == 0 || afp->af_af != AF_ISO)
971		errx(1, "Setting NSEL length valid only for iso");
972}
973
974fixnsel(s)
975register struct sockaddr_iso *s;
976{
977	if (s->siso_family == 0)
978		return;
979	s->siso_tlen = nsellength;
980}
981
982adjust_nsellength()
983{
984	fixnsel(sisotab[RIDADDR]);
985	fixnsel(sisotab[ADDR]);
986	fixnsel(sisotab[DSTADDR]);
987}
988