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