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