xref: /openbsd/sbin/ifconfig/ifconfig.c (revision 07ea8d15)
1 /*	$OpenBSD: ifconfig.c,v 1.5 1996/09/19 06:01:44 deraadt Exp $	*/
2 /*	$NetBSD: ifconfig.c,v 1.22 1996/01/04 20:11:20 pk Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1983, 1993\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
46 #else
47 static char rcsid[] = "$OpenBSD: ifconfig.c,v 1.5 1996/09/19 06:01:44 deraadt Exp $";
48 #endif
49 #endif /* not lint */
50 
51 #include <sys/param.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 
55 #include <net/if.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 
59 #define	NSIP
60 #include <netns/ns.h>
61 #include <netns/ns_if.h>
62 
63 #define	IPXIP
64 #include <netipx/ipx.h>
65 #include <netipx/ipx_if.h>
66 
67 #include <netdb.h>
68 
69 #define EON
70 #include <netiso/iso.h>
71 #include <netiso/iso_var.h>
72 #include <sys/protosw.h>
73 
74 #include <ctype.h>
75 #include <err.h>
76 #include <errno.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <unistd.h>
81 
82 struct	ifreq		ifr, ridreq;
83 struct	ifaliasreq	addreq;
84 struct	iso_ifreq	iso_ridreq;
85 struct	iso_aliasreq	iso_addreq;
86 struct	sockaddr_in	netmask;
87 int	ipx_type = ETHERTYPE_II;
88 char	name[30];
89 int	flags, metric, setaddr, setipdst, doalias;
90 int	clearaddr, s;
91 int	newaddr = 1;
92 int	nsellength = 1;
93 int	af = AF_INET;
94 
95 void 	notealias __P((char *, int));
96 void 	notrailers __P((char *, int));
97 void 	setifaddr __P((char *, int));
98 void 	setifdstaddr __P((char *, int));
99 void 	setifflags __P((char *, int));
100 void 	setifbroadaddr __P((char *));
101 void 	setifipdst __P((char *));
102 void 	setifmetric __P((char *));
103 void 	setifnetmask __P((char *));
104 void 	setnsellength __P((char *));
105 void 	setsnpaoffset __P((char *));
106 void	setipxframetype __P((char *, int));
107 
108 #define	NEXTARG		0xffffff
109 
110 struct	cmd {
111 	char	*c_name;
112 	int	c_parameter;		/* NEXTARG means next argv */
113 	void	(*c_func)();
114 } cmds[] = {
115 	{ "up",		IFF_UP,		setifflags } ,
116 	{ "down",	-IFF_UP,	setifflags },
117 	{ "trailers",	-1,		notrailers },
118 	{ "-trailers",	1,		notrailers },
119 	{ "arp",	-IFF_NOARP,	setifflags },
120 	{ "-arp",	IFF_NOARP,	setifflags },
121 	{ "debug",	IFF_DEBUG,	setifflags },
122 	{ "-debug",	-IFF_DEBUG,	setifflags },
123 	{ "alias",	IFF_UP,		notealias },
124 	{ "-alias",	-IFF_UP,	notealias },
125 	{ "delete",	-IFF_UP,	notealias },
126 #ifdef notdef
127 #define	EN_SWABIPS	0x1000
128 	{ "swabips",	EN_SWABIPS,	setifflags },
129 	{ "-swabips",	-EN_SWABIPS,	setifflags },
130 #endif
131 	{ "netmask",	NEXTARG,	setifnetmask },
132 	{ "metric",	NEXTARG,	setifmetric },
133 	{ "broadcast",	NEXTARG,	setifbroadaddr },
134 	{ "ipdst",	NEXTARG,	setifipdst },
135 #ifndef INET_ONLY
136 	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
137 	{ "nsellength",	NEXTARG,	setnsellength },
138 	{ "802.2",	ETHERTYPE_8022,	setipxframetype },
139 	{ "802.2tr",	ETHERTYPE_8022TR, setipxframetype },
140 	{ "802.3",	ETHERTYPE_8023,	setipxframetype },
141 	{ "snap",	ETHERTYPE_SNAP,	setipxframetype },
142 	{ "EtherII",	ETHERTYPE_II,	setipxframetype },
143 #endif	/* INET_ONLY */
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 	{ 0,		0,		setifaddr },
151 	{ 0,		0,		setifdstaddr },
152 };
153 
154 void 	adjust_nsellength();
155 int	getinfo __P((struct ifreq *));
156 void	getsock __P((int));
157 void	printall __P((void));
158 void 	printb __P((char *, unsigned short, char *));
159 void 	status();
160 void 	usage();
161 
162 /*
163  * XNS support liberally adapted from code written at the University of
164  * Maryland principally by James O'Toole and Chris Torek.
165  */
166 void	in_status __P((int));
167 void 	in_getaddr __P((char *, int));
168 void 	xns_status __P((int));
169 void 	xns_getaddr __P((char *, int));
170 void 	ipx_status __P((int));
171 void 	ipx_getaddr __P((char *, int));
172 void 	iso_status __P((int));
173 void 	iso_getaddr __P((char *, int));
174 
175 /* Known address families */
176 struct afswtch {
177 	char *af_name;
178 	short af_af;
179 	void (*af_status)();
180 	void (*af_getaddr)();
181 	u_long af_difaddr;
182 	u_long af_aifaddr;
183 	caddr_t af_ridreq;
184 	caddr_t af_addreq;
185 } afs[] = {
186 #define C(x) ((caddr_t) &x)
187 	{ "inet", AF_INET, in_status, in_getaddr,
188 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
189 #ifndef INET_ONLY	/* small version, for boot media */
190 	{ "ns", AF_NS, xns_status, xns_getaddr,
191 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
192 	{ "ipx", AF_IPX, ipx_status, ipx_getaddr,
193 	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
194 	{ "iso", AF_ISO, iso_status, iso_getaddr,
195 	     SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
196 #endif	/* INET_ONLY */
197 	{ 0,	0,	    0,		0 }
198 };
199 
200 struct afswtch *afp;	/*the address family being set or asked about*/
201 
202 int
203 main(argc, argv)
204 	int argc;
205 	char *argv[];
206 {
207 	register struct afswtch *rafp;
208 	int aflag = 0;
209 
210 	if (argc < 2)
211 		usage();
212 	argc--, argv++;
213 	if (!strcmp(*argv, "-a"))
214 		aflag = 1;
215 	else
216 		strncpy(name, *argv, sizeof(name));
217 	argc--, argv++;
218 	if (argc > 0) {
219 		for (afp = rafp = afs; rafp->af_name; rafp++)
220 			if (strcmp(rafp->af_name, *argv) == 0) {
221 				afp = rafp; argc--; argv++;
222 				break;
223 			}
224 		rafp = afp;
225 		af = ifr.ifr_addr.sa_family = rafp->af_af;
226 	}
227 	if (aflag) {
228 		if (argc > 0)
229 			usage();
230 		printall();
231 		exit(0);
232 	}
233 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
234 	if (getinfo(&ifr) < 0)
235 		exit(1);
236 	if (argc == 0) {
237 		status();
238 		exit(0);
239 	}
240 	while (argc > 0) {
241 		register struct cmd *p;
242 
243 		for (p = cmds; p->c_name; p++)
244 			if (strcmp(*argv, p->c_name) == 0)
245 				break;
246 		if (p->c_name == 0 && setaddr)
247 			p++;	/* got src, do dst */
248 		if (p->c_func) {
249 			if (p->c_parameter == NEXTARG) {
250 				if (argv[1] == NULL)
251 					errx(1, "'%s' requires argument",
252 					    p->c_name);
253 				(*p->c_func)(argv[1]);
254 				argc--, argv++;
255 			} else
256 				(*p->c_func)(*argv, p->c_parameter);
257 		}
258 		argc--, argv++;
259 	}
260 
261 #ifndef INET_ONLY
262 
263 	switch (af) {
264 	case AF_ISO:
265 		adjust_nsellength();
266 		break;
267 	case AF_NS:
268 		if (setipdst) {
269 			struct nsip_req rq;
270 			int size = sizeof(rq);
271 
272 			rq.rq_ns = addreq.ifra_addr;
273 			rq.rq_ip = addreq.ifra_dstaddr;
274 
275 			if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
276 				warn("encapsulation routing");
277 		}
278 		break;
279 	case AF_IPX:
280 		if (setipdst) {
281 			struct ipxip_req rq;
282 			int size = sizeof(rq);
283 
284 			rq.rq_ipx = addreq.ifra_addr;
285 			rq.rq_ip = addreq.ifra_dstaddr;
286 
287 			if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
288 				warn("encapsulation routing");
289 		}
290 		break;
291 	}
292 #endif	/* INET_ONLY */
293 
294 	if (clearaddr) {
295 		int ret;
296 		strncpy(rafp->af_ridreq, name, sizeof ifr.ifr_name);
297 		if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
298 			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
299 				/* means no previous address for interface */
300 			} else
301 				warn("SIOCDIFADDR");
302 		}
303 	}
304 	if (newaddr) {
305 		strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
306 		if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
307 			warn("SIOCAIFADDR");
308 	}
309 	exit(0);
310 }
311 
312 void
313 getsock(naf)
314 	int naf;
315 {
316 	static int oaf = -1;
317 
318 	if (oaf == naf)
319 		return;
320 	if (oaf != -1)
321 		close(s);
322 	s = socket(naf, SOCK_DGRAM, 0);
323 	if (s < 0)
324 		oaf = -1;
325 	else
326 		oaf = naf;
327 }
328 
329 int
330 getinfo(ifr)
331 	struct ifreq *ifr;
332 {
333 
334 	getsock(af);
335 	if (s < 0)
336 		err(1, "socket");
337 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
338 		warn("SIOCGIFFLAGS");
339 		return (-1);
340 	}
341 	flags = ifr->ifr_flags;
342 	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
343 		warn("SIOCGIFMETRIC");
344 		metric = 0;
345 	} else
346 		metric = ifr->ifr_metric;
347 	return (0);
348 }
349 
350 void
351 printall()
352 {
353 	char *inbuf = NULL;
354 	struct ifconf ifc;
355 	struct ifreq ifreq, *ifr;
356 	int i, len = 8192;
357 
358 	getsock(af);
359 	if (s < 0)
360 		err(1, "socket");
361 	while (1) {
362 		ifc.ifc_len = len;
363 		ifc.ifc_buf = inbuf = realloc(inbuf, len);
364 		if (inbuf == NULL)
365 			err(1, "malloc");
366 		if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
367 			err(1, "SIOCGIFCONF");
368 		if (ifc.ifc_len + sizeof(ifreq) < len)
369 			break;
370 		len *= 2;
371 	}
372 	ifr = ifc.ifc_req;
373 	ifreq.ifr_name[0] = '\0';
374 	for (i = 0; i < ifc.ifc_len; ) {
375 		ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
376 		i += sizeof(ifr->ifr_name) +
377 			(ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
378 				? ifr->ifr_addr.sa_len
379 				: sizeof(struct sockaddr));
380 		if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
381 			     sizeof(ifr->ifr_name)))
382 			continue;
383 		strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
384 		ifreq = *ifr;
385 		if (getinfo(&ifreq) < 0)
386 			continue;
387 		status();
388 	}
389 	free(inbuf);
390 }
391 
392 #define RIDADDR 0
393 #define ADDR	1
394 #define MASK	2
395 #define DSTADDR	3
396 
397 /*ARGSUSED*/
398 void
399 setifaddr(addr, param)
400 	char *addr;
401 	int param;
402 {
403 	/*
404 	 * Delay the ioctl to set the interface addr until flags are all set.
405 	 * The address interpretation may depend on the flags,
406 	 * and the flags may change when the address is set.
407 	 */
408 	setaddr++;
409 	if (doalias == 0)
410 		clearaddr = 1;
411 	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
412 }
413 
414 void
415 setifnetmask(addr)
416 	char *addr;
417 {
418 	(*afp->af_getaddr)(addr, MASK);
419 }
420 
421 void
422 setifbroadaddr(addr)
423 	char *addr;
424 {
425 	(*afp->af_getaddr)(addr, DSTADDR);
426 }
427 
428 void
429 setifipdst(addr)
430 	char *addr;
431 {
432 	in_getaddr(addr, DSTADDR);
433 	setipdst++;
434 	clearaddr = 0;
435 	newaddr = 0;
436 }
437 
438 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
439 /*ARGSUSED*/
440 void
441 notealias(addr, param)
442 	char *addr;
443 	int param;
444 {
445 	if (setaddr && doalias == 0 && param < 0)
446 		memcpy(rqtosa(af_ridreq),
447 		       rqtosa(af_addreq),
448 		       rqtosa(af_addreq)->sa_len);
449 	doalias = param;
450 	if (param < 0) {
451 		clearaddr = 1;
452 		newaddr = 0;
453 	} else
454 		clearaddr = 0;
455 }
456 
457 /*ARGSUSED*/
458 void
459 notrailers(vname, value)
460 	char *vname;
461 	int value;
462 {
463 	printf("Note: trailers are no longer sent, but always received\n");
464 }
465 
466 /*ARGSUSED*/
467 void
468 setifdstaddr(addr, param)
469 	char *addr;
470 	int param;
471 {
472 	(*afp->af_getaddr)(addr, DSTADDR);
473 }
474 
475 void
476 setifflags(vname, value)
477 	char *vname;
478 	int value;
479 {
480  	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
481 		err(1, "SIOCGIFFLAGS");
482 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
483  	flags = ifr.ifr_flags;
484 
485 	if (value < 0) {
486 		value = -value;
487 		flags &= ~value;
488 	} else
489 		flags |= value;
490 	ifr.ifr_flags = flags;
491 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
492 		err(1, "SIOCSIFFLAGS");
493 }
494 
495 void
496 setifmetric(val)
497 	char *val;
498 {
499 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
500 	ifr.ifr_metric = atoi(val);
501 	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
502 		warn("SIOCSIFMETRIC");
503 }
504 
505 #define	IFFBITS \
506 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
507 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
508 
509 /*
510  * Print the status of the interface.  If an address family was
511  * specified, show it and it only; otherwise, show them all.
512  */
513 void
514 status()
515 {
516 	register struct afswtch *p = afp;
517 
518 	printf("%s: ", name);
519 	printb("flags", flags, IFFBITS);
520 	if (metric)
521 		printf(" metric %d", metric);
522 	putchar('\n');
523 	if ((p = afp) != NULL) {
524 		(*p->af_status)(1);
525 	} else for (p = afs; p->af_name; p++) {
526 		ifr.ifr_addr.sa_family = p->af_af;
527 		(*p->af_status)(0);
528 	}
529 }
530 
531 void
532 in_status(force)
533 	int force;
534 {
535 	struct sockaddr_in *sin;
536 	char *inet_ntoa();
537 
538 	getsock(AF_INET);
539 	if (s < 0) {
540 		if (errno == EPROTONOSUPPORT)
541 			return;
542 		err(1, "socket");
543 	}
544 	memset(&ifr, 0, sizeof(ifr));
545 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
546 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
547 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
548 			if (!force)
549 				return;
550 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
551 		} else
552 			warn("SIOCGIFADDR");
553 	}
554 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
555 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
556 	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
557 	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
558 	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
559 		if (errno != EADDRNOTAVAIL)
560 			warn("SIOCGIFNETMASK");
561 		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
562 	} else
563 		netmask.sin_addr =
564 		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
565 	if (flags & IFF_POINTOPOINT) {
566 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
567 			if (errno == EADDRNOTAVAIL)
568 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
569 			else
570 			    warn("SIOCGIFDSTADDR");
571 		}
572 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
573 		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
574 		printf("--> %s ", inet_ntoa(sin->sin_addr));
575 	}
576 	printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
577 	if (flags & IFF_BROADCAST) {
578 		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
579 			if (errno == EADDRNOTAVAIL)
580 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
581 			else
582 			    warn("SIOCGIFBRDADDR");
583 		}
584 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
585 		sin = (struct sockaddr_in *)&ifr.ifr_addr;
586 		if (sin->sin_addr.s_addr != 0)
587 			printf("broadcast %s", inet_ntoa(sin->sin_addr));
588 	}
589 	putchar('\n');
590 }
591 
592 #ifndef INET_ONLY
593 
594 void
595 xns_status(force)
596 	int force;
597 {
598 	struct sockaddr_ns *sns;
599 
600 	getsock(AF_NS);
601 	if (s < 0) {
602 		if (errno == EPROTONOSUPPORT)
603 			return;
604 		err(1, "socket");
605 	}
606 	memset(&ifr, 0, sizeof(ifr));
607 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
608 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
609 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
610 			if (!force)
611 				return;
612 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
613 		} else
614 			warn("SIOCGIFADDR");
615 	}
616 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
617 	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
618 	printf("\tns %s ", ns_ntoa(sns->sns_addr));
619 	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
620 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
621 			if (errno == EADDRNOTAVAIL)
622 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
623 			else
624 			    warn("SIOCGIFDSTADDR");
625 		}
626 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
627 		sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
628 		printf("--> %s ", ns_ntoa(sns->sns_addr));
629 	}
630 	putchar('\n');
631 }
632 
633 void
634 setipxframetype(vname, type)
635 	char	*vname;
636 	int	type;
637 {
638 	ipx_type = type;
639 }
640 
641 void
642 ipx_status(force)
643 	int force;
644 {
645 	struct sockaddr_ipx *sipx;
646 
647 	getsock(AF_IPX);
648 	if (s < 0) {
649 		if (errno == EPROTONOSUPPORT)
650 			return;
651 		err(1, "socket");
652 	}
653 	memset(&ifr, 0, sizeof(ifr));
654 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
655 	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
656 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
657 			if (!force)
658 				return;
659 			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
660 		} else
661 			warn("SIOCGIFADDR");
662 	}
663 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
664 	sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;
665 	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
666 	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
667 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
668 			if (errno == EADDRNOTAVAIL)
669 			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
670 			else
671 			    warn("SIOCGIFDSTADDR");
672 		}
673 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
674 		sipx = (struct sockaddr_ipx *)&ifr.ifr_dstaddr;
675 		printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
676 	}
677 	{
678 		struct frame_types {
679 			int	type;
680 			char	*name;
681 		} *p, frames[] = {
682 			{ ETHERTYPE_8022, "802.2" },
683 			{ ETHERTYPE_8022TR, "802.2tr" },
684 			{ ETHERTYPE_8023, "802.3" },
685 			{ ETHERTYPE_SNAP, "SNAP" },
686 			{ ETHERTYPE_II,  "EtherII" },
687 			{ 0, NULL }
688 		};
689 		for (p = frames; p->name && p->type != sipx->sipx_type; p++);
690 		if (p->name != NULL)
691 			printf("frame %s ", p->name);
692 	}
693 	putchar('\n');
694 }
695 
696 void
697 iso_status(force)
698 	int force;
699 {
700 	struct sockaddr_iso *siso;
701 	struct iso_ifreq ifr;
702 
703 	getsock(AF_ISO);
704 	if (s < 0) {
705 		if (errno == EPROTONOSUPPORT)
706 			return;
707 		err(1, "socket");
708 	}
709 	memset(&ifr, 0, sizeof(ifr));
710 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
711 	if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&ifr) < 0) {
712 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
713 			if (!force)
714 				return;
715 			memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
716 		} else
717 			warn("SIOCGIFADDR_ISO");
718 	}
719 	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
720 	siso = &ifr.ifr_Addr;
721 	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
722 	if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&ifr) < 0) {
723 		if (errno == EADDRNOTAVAIL)
724 			memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
725 		else
726 			warn("SIOCGIFNETMASK_ISO");
727 	} else {
728 		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
729 	}
730 	if (flags & IFF_POINTOPOINT) {
731 		if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
732 			if (errno == EADDRNOTAVAIL)
733 			    memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
734 			else
735 			    warn("SIOCGIFDSTADDR_ISO");
736 		}
737 		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
738 		siso = &ifr.ifr_Addr;
739 		printf("--> %s ", iso_ntoa(&siso->siso_addr));
740 	}
741 	putchar('\n');
742 }
743 
744 #endif	/* INET_ONLY */
745 
746 struct	in_addr inet_makeaddr();
747 
748 #define SIN(x) ((struct sockaddr_in *) &(x))
749 struct sockaddr_in *sintab[] = {
750 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
751 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
752 
753 void
754 in_getaddr(s, which)
755 	char *s;
756 	int which;
757 {
758 	register struct sockaddr_in *sin = sintab[which];
759 	struct hostent *hp;
760 	struct netent *np;
761 
762 	sin->sin_len = sizeof(*sin);
763 	if (which != MASK)
764 		sin->sin_family = AF_INET;
765 
766 	if (inet_aton(s, &sin->sin_addr) == 0) {
767 		if (hp = gethostbyname(s))
768 			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
769 		else if (np = getnetbyname(s))
770 			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
771 		else
772 			errx(1, "%s: bad value", s);
773 	}
774 }
775 
776 /*
777  * Print a value a la the %b format of the kernel's printf
778  */
779 void
780 printb(s, v, bits)
781 	char *s;
782 	register char *bits;
783 	register unsigned short v;
784 {
785 	register int i, any = 0;
786 	register char c;
787 
788 	if (bits && *bits == 8)
789 		printf("%s=%o", s, v);
790 	else
791 		printf("%s=%x", s, v);
792 	bits++;
793 	if (bits) {
794 		putchar('<');
795 		while (i = *bits++) {
796 			if (v & (1 << (i-1))) {
797 				if (any)
798 					putchar(',');
799 				any = 1;
800 				for (; (c = *bits) > 32; bits++)
801 					putchar(c);
802 			} else
803 				for (; *bits > 32; bits++)
804 					;
805 		}
806 		putchar('>');
807 	}
808 }
809 
810 #ifndef INET_ONLY
811 
812 #define SNS(x) ((struct sockaddr_ns *) &(x))
813 struct sockaddr_ns *snstab[] = {
814 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
815 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
816 
817 void
818 xns_getaddr(addr, which)
819 	char *addr;
820 	int which;
821 {
822 	struct sockaddr_ns *sns = snstab[which];
823 	struct ns_addr ns_addr();
824 
825 	sns->sns_family = AF_NS;
826 	sns->sns_len = sizeof(*sns);
827 	sns->sns_addr = ns_addr(addr);
828 	if (which == MASK)
829 		printf("Attempt to set XNS netmask will be ineffectual\n");
830 }
831 
832 #define SIPX(x) ((struct sockaddr_ipx *) &(x))
833 struct sockaddr_ipx *sipxtab[] = {
834 SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
835 SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
836 
837 void
838 ipx_getaddr(addr, which)
839 	char *addr;
840 	int which;
841 {
842 	struct sockaddr_ipx *sipx = sipxtab[which];
843 	struct ipx_addr ipx_addr();
844 
845 	sipx->sipx_family = AF_IPX;
846 	sipx->sipx_len  = sizeof(*sipx);
847 	sipx->sipx_addr = ipx_addr(addr);
848 	sipx->sipx_type = ipx_type;
849 	if (which == MASK)
850 		printf("Attempt to set IPX netmask will be ineffectual\n");
851 }
852 
853 #define SISO(x) ((struct sockaddr_iso *) &(x))
854 struct sockaddr_iso *sisotab[] = {
855 SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
856 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
857 
858 void
859 iso_getaddr(addr, which)
860 	char *addr;
861 	int which;
862 {
863 	register struct sockaddr_iso *siso = sisotab[which];
864 	struct iso_addr *iso_addr();
865 	siso->siso_addr = *iso_addr(addr);
866 
867 	if (which == MASK) {
868 		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
869 		siso->siso_nlen = 0;
870 	} else {
871 		siso->siso_len = sizeof(*siso);
872 		siso->siso_family = AF_ISO;
873 	}
874 }
875 
876 void
877 setsnpaoffset(val)
878 	char *val;
879 {
880 	iso_addreq.ifra_snpaoffset = atoi(val);
881 }
882 
883 void
884 setnsellength(val)
885 	char *val;
886 {
887 	nsellength = atoi(val);
888 	if (nsellength < 0)
889 		errx(1, "Negative NSEL length is absurd");
890 	if (afp == 0 || afp->af_af != AF_ISO)
891 		errx(1, "Setting NSEL length valid only for iso");
892 }
893 
894 void
895 fixnsel(s)
896 	register struct sockaddr_iso *s;
897 {
898 	if (s->siso_family == 0)
899 		return;
900 	s->siso_tlen = nsellength;
901 }
902 
903 void
904 adjust_nsellength()
905 {
906 	fixnsel(sisotab[RIDADDR]);
907 	fixnsel(sisotab[ADDR]);
908 	fixnsel(sisotab[DSTADDR]);
909 }
910 
911 #endif	/* INET_ONLY */
912 
913 void
914 usage()
915 {
916 	fprintf(stderr, "usage: ifconfig interface\n%s",
917 		"\t[ af [ address [ dest_addr ] ] [ up ] [ down ] "
918 		"[ netmask mask ] ]\n"
919 		"\t[ metric n ]\n"
920 		"\t[ arp | -arp ]\n"
921 		"\t[ -802.2 | -802.3 | -802.2tr | -snap | -EtherII ]\n"
922 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
923 		"       ifconfig -a [ af ]\n");
924 	exit(1);
925 }
926