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