xref: /netbsd-src/sbin/route/route.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /*	$NetBSD: route.c,v 1.52 2001/11/15 21:25:08 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1989, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)route.c	8.6 (Berkeley) 4/28/95";
45 #else
46 __RCSID("$NetBSD: route.c,v 1.52 2001/11/15 21:25:08 christos Exp $");
47 #endif
48 #endif /* not lint */
49 
50 #include <sys/param.h>
51 #include <sys/file.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 #include <sys/mbuf.h>
55 #include <sys/sysctl.h>
56 
57 #include <net/if.h>
58 #include <net/route.h>
59 #include <net/if_dl.h>
60 #include <netinet/in.h>
61 #include <netatalk/at.h>
62 #include <netns/ns.h>
63 #include <netiso/iso.h>
64 #include <netccitt/x25.h>
65 #include <arpa/inet.h>
66 #include <netdb.h>
67 
68 #include <errno.h>
69 #include <unistd.h>
70 #include <stdio.h>
71 #include <ctype.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <time.h>
75 #include <paths.h>
76 #include <err.h>
77 
78 #include "keywords.h"
79 #include "extern.h"
80 
81 typedef union sockunion *sup;
82 
83 int main __P((int, char **));
84 static void usage __P((char *)) __attribute__((__noreturn__));
85 static char *any_ntoa __P((const struct sockaddr *));
86 static void set_metric __P((char *, int));
87 static int newroute __P((int, char **));
88 static void inet_makenetandmask __P((u_int32_t, struct sockaddr_in *));
89 #ifdef INET6
90 static void inet6_makenetandmask __P((struct sockaddr_in6 *));
91 #endif
92 static int getaddr __P((int, char *, struct hostent **));
93 static int flushroutes __P((int, char *[]));
94 #ifndef SMALL
95 static int prefixlen __P((char *));
96 static int x25_makemask __P((void));
97 static void interfaces __P((void));
98 static void monitor __P((void));
99 static void print_getmsg __P((struct rt_msghdr *, int));
100 #endif
101 static int rtmsg __P((int, int ));
102 static void mask_addr __P((void));
103 static void print_rtmsg __P((struct rt_msghdr *, int));
104 static void pmsg_common __P((struct rt_msghdr *));
105 static void pmsg_addrs __P((char *, int));
106 static void bprintf __P((FILE *, int, u_char *));
107 static int keyword __P((char *));
108 static void sodump __P((sup, char *));
109 static void sockaddr __P((char *, struct sockaddr *));
110 
111 union	sockunion {
112 	struct	sockaddr sa;
113 	struct	sockaddr_in sin;
114 #ifdef INET6
115 	struct	sockaddr_in6 sin6;
116 #endif
117 	struct	sockaddr_at sat;
118 	struct	sockaddr_dl sdl;
119 #ifndef SMALL
120 	struct	sockaddr_ns sns;
121 	struct	sockaddr_iso siso;
122 	struct	sockaddr_x25 sx25;
123 #endif /* SMALL */
124 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
125 
126 int	pid, rtm_addrs;
127 int	sock;
128 int	forcehost, forcenet, doflush, nflag, af, qflag, tflag;
129 int	iflag, verbose, aflen = sizeof (struct sockaddr_in);
130 int	locking, lockrest, debugonly, shortoutput, rv;
131 struct	rt_metrics rt_metrics;
132 u_int32_t  rtm_inits;
133 short ns_nullh[] = {0,0,0};
134 short ns_bh[] = {-1,-1,-1};
135 
136 
137 static void
138 usage(cp)
139 	char *cp;
140 {
141 
142 	if (cp)
143 		warnx("botched keyword: %s", cp);
144 	(void) fprintf(stderr,
145 	    "Usage: %s [ -fnqvs ] cmd [[ -<qualifers> ] args ]\n",
146 	    getprogname());
147 	exit(1);
148 	/* NOTREACHED */
149 }
150 
151 #define ROUNDUP(a) \
152 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
153 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
154 
155 int
156 main(argc, argv)
157 	int argc;
158 	char **argv;
159 {
160 	int ch;
161 
162 	if (argc < 2)
163 		usage(NULL);
164 
165 	while ((ch = getopt(argc, argv, "fnqvdts")) != -1)
166 		switch(ch) {
167 		case 'f':
168 			doflush = 1;
169 			break;
170 		case 'n':
171 			nflag = 1;
172 			break;
173 		case 'q':
174 			qflag = 1;
175 			break;
176 		case 'v':
177 			verbose = 1;
178 			break;
179 		case 't':
180 			tflag = 1;
181 			break;
182 		case 'd':
183 			debugonly = 1;
184 			break;
185 		case 's':
186 			shortoutput = 1;
187 			break;
188 		case '?':
189 		default:
190 			usage(NULL);
191 			/*NOTREACHED*/
192 		}
193 	argc -= optind;
194 	argv += optind;
195 
196 	pid = getpid();
197 	if (tflag)
198 		sock = open("/dev/null", O_WRONLY, 0);
199 	else
200 		sock = socket(PF_ROUTE, SOCK_RAW, 0);
201 	if (sock < 0)
202 		err(1, "socket");
203 
204 	if (*argv == NULL) {
205 		if (doflush)
206 			ch = K_FLUSH;
207 		else
208 			goto no_cmd;
209 	} else
210 		ch = keyword(*argv);
211 
212 	switch (ch) {
213 #ifndef SMALL
214 	case K_GET:
215 #endif /* SMALL */
216 	case K_CHANGE:
217 	case K_ADD:
218 	case K_DELETE:
219 		if (doflush)
220 			(void)flushroutes(1, argv);
221 		return newroute(argc, argv);
222 
223 	case K_SHOW:
224 		show(argc, argv);
225 		return 0;
226 
227 #ifndef SMALL
228 	case K_MONITOR:
229 		monitor();
230 		return 0;
231 
232 #endif /* SMALL */
233 	case K_FLUSH:
234 		return flushroutes(argc, argv);
235 
236 	no_cmd:
237 	default:
238 		usage(*argv);
239 		/*NOTREACHED*/
240 	}
241 }
242 
243 /*
244  * Purge all entries in the routing tables not
245  * associated with network interfaces.
246  */
247 static int
248 flushroutes(argc, argv)
249 	int argc;
250 	char *argv[];
251 {
252 	size_t needed;
253 	int mib[6], rlen, seqno;
254 	char *buf, *next, *lim;
255 	struct rt_msghdr *rtm;
256 
257 	af = 0;
258 	shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
259 	if (argc > 1) {
260 		argv++;
261 		if (argc == 2 && **argv == '-')
262 		    switch (keyword(*argv + 1)) {
263 			case K_INET:
264 				af = AF_INET;
265 				break;
266 #ifdef INET6
267 			case K_INET6:
268 				af = AF_INET6;
269 				break;
270 #endif
271 			case K_ATALK:
272 				af = AF_APPLETALK;
273 				break;
274 #ifndef SMALL
275 			case K_XNS:
276 				af = AF_NS;
277 				break;
278 #endif /* SMALL */
279 			case K_LINK:
280 				af = AF_LINK;
281 				break;
282 #ifndef SMALL
283 			case K_ISO:
284 			case K_OSI:
285 				af = AF_ISO;
286 				break;
287 			case K_X25:
288 				af = AF_CCITT;
289 #endif /* SMALL */
290 			default:
291 				goto bad;
292 		} else
293 bad:			usage(*argv);
294 	}
295 	mib[0] = CTL_NET;
296 	mib[1] = PF_ROUTE;
297 	mib[2] = 0;		/* protocol */
298 	mib[3] = 0;		/* wildcard address family */
299 	mib[4] = NET_RT_DUMP;
300 	mib[5] = 0;		/* no flags */
301 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
302 		err(1, "route-sysctl-estimate");
303 	if (needed == 0)
304 		return 0;
305 	if ((buf = malloc(needed)) == NULL)
306 		err(1, "malloc");
307 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
308 		err(1, "actual retrieval of routing table");
309 	lim = buf + needed;
310 	if (verbose) {
311 		(void) printf("Examining routing table from sysctl\n");
312 		if (af) printf("(address family %s)\n", (*argv + 1));
313 	}
314 	seqno = 0;		/* ??? */
315 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
316 		rtm = (struct rt_msghdr *)next;
317 		if (verbose)
318 			print_rtmsg(rtm, rtm->rtm_msglen);
319 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
320 			continue;
321 		if (af) {
322 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
323 
324 			if (sa->sa_family != af)
325 				continue;
326 		}
327 		if (debugonly)
328 			continue;
329 		rtm->rtm_type = RTM_DELETE;
330 		rtm->rtm_seq = seqno;
331 		rlen = write(sock, next, rtm->rtm_msglen);
332 		if (rlen < (int)rtm->rtm_msglen) {
333 			warn("write to routing socket, got %d for rlen", rlen);
334 			break;
335 		}
336 		seqno++;
337 		if (qflag)
338 			continue;
339 		if (verbose)
340 			print_rtmsg(rtm, rlen);
341 		else {
342 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
343 			(void) printf("%-20.20s ",
344 			    routename(sa, NULL, rtm->rtm_flags));
345 			sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
346 			(void) printf("%-20.20s ",
347 			    routename(sa, NULL, RTF_HOST));
348 			(void) printf("done\n");
349 		}
350 	}
351 	return 0;
352 }
353 
354 
355 static char hexlist[] = "0123456789abcdef";
356 
357 static char *
358 any_ntoa(sa)
359 	const struct sockaddr *sa;
360 {
361 	static char obuf[64];
362 	const char *in;
363 	char *out;
364 	int len;
365 
366 	len = sa->sa_len;
367 	in  = sa->sa_data;
368 	out = obuf;
369 
370 	do {
371 		*out++ = hexlist[(*in >> 4) & 15];
372 		*out++ = hexlist[(*in++)    & 15];
373 		*out++ = '.';
374 	} while (--len > 0);
375 	out[-1] = '\0';
376 	return obuf;
377 }
378 
379 
380 int
381 netmask_length(nm, family)
382 	struct sockaddr *nm;
383 	int family;
384 {
385 	static int
386 	    /* number of bits in a nibble */
387 	    _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
388 	    /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
389 	    _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
390 	int mask, good, zeroes, maskbytes, bit, i;
391 	unsigned char *maskdata;
392 
393 	if (nm == NULL)
394 		return 0;
395 
396 	mask = 0;
397 	good = 1;
398 	zeroes = 0;
399 
400 	switch (family) {
401 	case AF_INET: {
402 		struct sockaddr_in *nsin = (struct sockaddr_in *)nm;
403 		maskdata = (unsigned char *) &nsin->sin_addr;
404 		maskbytes = nsin->sin_len -
405 		    ((caddr_t)&nsin->sin_addr - (caddr_t)nsin);
406 		break;
407 	}
408 	case AF_INET6: {
409 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm;
410 		maskdata = (unsigned char *) &sin6->sin6_addr;
411 		maskbytes = sin6->sin6_len -
412 		    ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6);
413 		break;
414 	}
415 	default:
416 		return 0;
417 	}
418 
419 	/*
420 	 * Count the bits in the nibbles of the mask, and marking the
421 	 * netmask as not good (or at best, non-standard and very
422 	 * discouraged, in the case of AF_INET) if we find either of
423 	 * a nibble with non-contiguous bits, or a non-zero nibble
424 	 * after we've found a zero nibble.
425 	 */
426 	for (i = 0; i < maskbytes; i++) {
427 		/* high nibble */
428 		mask += bit = _t[maskdata[i] >> 4];
429 		good &= _g[maskdata[i] >> 4];
430 		if (zeroes && bit)
431 			good = 0;
432 		if (bit == 0)
433 			zeroes = 1;
434 		/* low nibble */
435 		mask += bit = _t[maskdata[i] & 0xf];
436 		good &= _g[maskdata[i] & 0xf];
437 		if (zeroes && bit)
438 			good = 0;
439 		if (bit == 0)
440 			zeroes = 1;
441 	}
442 
443 	/*
444 	 * Always return the number of bits found, but as a negative
445 	 * if the mask wasn't one we like.
446 	 */
447 	return good ? mask : -mask;
448 }
449 
450 char *
451 netmask_string(mask, len)
452 	struct sockaddr *mask;
453 	int len;
454 {
455 	static char smask[16];
456 
457 	if (len >= 0)
458 		snprintf(smask, sizeof(smask), "%d", len);
459 	else {
460 		/* XXX AF_INET only?! */
461 		struct sockaddr_in nsin;
462 
463 		memset(&nsin, 0, sizeof(nsin));
464 		memcpy(&nsin, mask, mask->sa_len);
465 		snprintf(smask, sizeof(smask), "%s", inet_ntoa(nsin.sin_addr));
466 	}
467 
468 	return smask;
469 }
470 
471 
472 char *
473 routename(sa, nm, flags)
474 	struct sockaddr *sa, *nm;
475 	int flags;
476 {
477 	char *cp;
478 	static char line[50];
479 	struct hostent *hp;
480 	static char domain[MAXHOSTNAMELEN + 1];
481 	static int first = 1;
482 	struct in_addr in;
483 	int nml;
484 
485 	if ((flags & RTF_HOST) == 0)
486 		return netname(sa, nm);
487 
488 	if (first) {
489 		first = 0;
490 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
491 		    (cp = strchr(domain, '.'))) {
492 			(void)strncpy(domain, cp + 1, sizeof(domain) - 1);
493 			domain[sizeof(domain) - 1] = '\0';
494 		} else
495 			domain[0] = 0;
496 	}
497 
498 	if (sa->sa_len == 0) {
499 		strncpy(line, "default", sizeof(line) - 1);
500 		line[sizeof(line) - 1] = '\0';
501 	} else switch (sa->sa_family) {
502 
503 	case AF_INET:
504 		in = ((struct sockaddr_in *)sa)->sin_addr;
505 		nml = netmask_length(nm, AF_INET);
506 
507 		cp = 0;
508 		if (in.s_addr == INADDR_ANY || sa->sa_len < 4) {
509 			if (nml == 0)
510 				cp = "default";
511 			else {
512 				static char notdefault[sizeof(NOTDEFSTRING)];
513 
514 				snprintf(notdefault, sizeof(notdefault),
515 				    "0.0.0.0/%s", netmask_string(nm, nml));
516 				cp = notdefault;
517 			}
518 		}
519 		if (cp == 0 && !nflag) {
520 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
521 				AF_INET);
522 			if (hp) {
523 				if ((cp = strchr(hp->h_name, '.')) &&
524 				    !strcmp(cp + 1, domain))
525 					*cp = 0;
526 				cp = hp->h_name;
527 			}
528 		}
529 		if (cp)
530 			(void)strncpy(line, cp, sizeof(line) - 1);
531 		else
532 			(void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
533 		line[sizeof(line) - 1] = '\0';
534 		break;
535 
536 	case AF_LINK:
537 		return (link_ntoa((struct sockaddr_dl *)sa));
538 
539 #ifndef SMALL
540 #ifdef INET6
541 	case AF_INET6:
542 	    {
543 		struct sockaddr_in6 sin6;
544 		int niflags;
545 
546 #ifdef NI_WITHSCOPEID
547 		niflags = NI_WITHSCOPEID;
548 #else
549 		niflags = 0;
550 #endif
551 		if (nflag)
552 			niflags |= NI_NUMERICHOST;
553 		memset(&sin6, 0, sizeof(sin6));
554 		memcpy(&sin6, sa, sa->sa_len);
555 		sin6.sin6_len = sizeof(struct sockaddr_in6);
556 		sin6.sin6_family = AF_INET6;
557 #ifdef __KAME__
558 		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
559 		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
560 		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
561 		    sin6.sin6_scope_id == 0) {
562 			sin6.sin6_scope_id =
563 			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
564 			sin6.sin6_addr.s6_addr[2] = 0;
565 			sin6.sin6_addr.s6_addr[3] = 0;
566 		}
567 #endif
568 		nml = netmask_length(nm, AF_INET6);
569 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
570 			if (nml == 0) {
571 				strncpy(line, "::", sizeof(line) - 1);
572 				line[sizeof(line) - 1] = '\0';
573 			}
574 			else
575 				/* noncontiguous never happens in ipv6 */
576 				snprintf(line, sizeof(line), "::/%d", nml);
577 		}
578 
579 		else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
580 		    line, sizeof(line), NULL, 0, niflags) != 0)
581 			strncpy(line, "invalid", sizeof(line));
582 		break;
583 	    }
584 #endif
585 
586 	case AF_NS:
587 		return (ns_print((struct sockaddr_ns *)sa));
588 
589 	case AF_ISO:
590 		(void)snprintf(line, sizeof line, "iso %s",
591 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
592 		break;
593 #endif /* SMALL */
594 
595 	case AF_APPLETALK:
596 		(void) snprintf(line, sizeof(line), "atalk %d.%d",
597 		    ((struct sockaddr_at *)sa)->sat_addr.s_net,
598 		    ((struct sockaddr_at *)sa)->sat_addr.s_node);
599 		break;
600 
601 	default:
602 		(void)snprintf(line, sizeof line, "(%d) %s",
603 			sa->sa_family, any_ntoa(sa));
604 		break;
605 
606 	}
607 	return (line);
608 }
609 
610 /*
611  * Return the name of the network whose address is given.
612  * The address is assumed to be that of a net or subnet, not a host.
613  */
614 char *
615 netname(sa, nm)
616 	struct sockaddr *sa, *nm;
617 {
618 	char *cp = 0;
619 	static char line[50];
620 	struct netent *np = 0;
621 	u_int32_t net, mask;
622 	u_int32_t i;
623 	int subnetshift, nml;
624 	struct in_addr in;
625 
626 	switch (sa->sa_family) {
627 
628 	case AF_INET:
629 		in = ((struct sockaddr_in *)sa)->sin_addr;
630 		i = ntohl(in.s_addr);
631 		nml = netmask_length(nm, AF_INET);
632 		if (i == 0) {
633 			if (nml == 0)
634 				cp = "default";
635 			else {
636 				static char notdefault[sizeof(NOTDEFSTRING)];
637 
638 				snprintf(notdefault, sizeof(notdefault),
639 				    "0.0.0.0/%s", netmask_string(nm, nml));
640 				cp = notdefault;
641 			}
642 		}
643 		else if (!nflag) {
644 			if (IN_CLASSA(i)) {
645 				mask = IN_CLASSA_NET;
646 				subnetshift = 8;
647 			} else if (IN_CLASSB(i)) {
648 				mask = IN_CLASSB_NET;
649 				subnetshift = 8;
650 			} else {
651 				mask = IN_CLASSC_NET;
652 				subnetshift = 4;
653 			}
654 			/*
655 			 * If there are more bits than the standard mask
656 			 * would suggest, subnets must be in use.
657 			 * Guess at the subnet mask, assuming reasonable
658 			 * width subnet fields.
659 			 */
660 			while (i &~ mask)
661 				mask = (int32_t)mask >> subnetshift;
662 			net = i & mask;
663 			while ((mask & 1) == 0)
664 				mask >>= 1, net >>= 1;
665 			np = getnetbyaddr(net, AF_INET);
666 			if (np)
667 				cp = np->n_name;
668 		}
669 		if (cp) {
670 			(void)strncpy(line, cp, sizeof(line) - 1);
671 			line[sizeof(line) - 1] = '\0';
672 		} else {
673 #if 0	/* XXX - This is silly... */
674 #define C(x)	((x) & 0xff)
675 			if ((i & 0xffffff) == 0)
676 				(void)snprintf(line, sizeof line, "%u",
677 				    C(i >> 24));
678 			else if ((i & 0xffff) == 0)
679 				(void)snprintf(line, sizeof line, "%u.%u",
680 				    C(i >> 24), C(i >> 16));
681 			else if ((i & 0xff) == 0)
682 				(void)snprintf(line, sizeof line, "%u.%u.%u",
683 				    C(i >> 24), C(i >> 16), C(i >> 8));
684 			else
685 				(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
686 				    C(i >> 24), C(i >> 16), C(i >> 8), C(i));
687 #undef C
688 #else /* XXX */
689 			(void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
690 #endif /* XXX */
691 		}
692 		break;
693 
694 	case AF_LINK:
695 		return (link_ntoa((struct sockaddr_dl *)sa));
696 
697 #ifndef SMALL
698 #ifdef INET6
699 	case AF_INET6:
700 	    {
701 		struct sockaddr_in6 sin6;
702 		int niflags;
703 
704 #ifdef NI_WITHSCOPEID
705 		niflags = NI_WITHSCOPEID;
706 #else
707 		niflags = 0;
708 #endif
709 		if (nflag)
710 			niflags |= NI_NUMERICHOST;
711 		memset(&sin6, 0, sizeof(sin6));
712 		memcpy(&sin6, sa, sa->sa_len);
713 		sin6.sin6_len = sizeof(struct sockaddr_in6);
714 		sin6.sin6_family = AF_INET6;
715 #ifdef __KAME__
716 		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
717 		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
718 		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
719 		    sin6.sin6_scope_id == 0) {
720 			sin6.sin6_scope_id =
721 			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
722 			sin6.sin6_addr.s6_addr[2] = 0;
723 			sin6.sin6_addr.s6_addr[3] = 0;
724 		}
725 #endif
726 		nml = netmask_length(nm, AF_INET6);
727 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
728 			if (nml == 0) {
729 				strncpy(line, "::", sizeof(line) - 1);
730 				line[sizeof(line) - 1] = '\0';
731 			}
732 			else
733 				/* noncontiguous never happens in ipv6 */
734 				snprintf(line, sizeof(line), "::/%d", nml);
735 		}
736 
737 		else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
738 		    line, sizeof(line), NULL, 0, niflags) != 0)
739 			strncpy(line, "invalid", sizeof(line));
740 		break;
741 	    }
742 #endif
743 
744 	case AF_NS:
745 		return (ns_print((struct sockaddr_ns *)sa));
746 
747 	case AF_ISO:
748 		(void)snprintf(line, sizeof line, "iso %s",
749 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
750 		break;
751 #endif /* SMALL */
752 
753 	case AF_APPLETALK:
754 		(void) snprintf(line, sizeof(line), "atalk %d.%d",
755 		    ((struct sockaddr_at *)sa)->sat_addr.s_net,
756 		    ((struct sockaddr_at *)sa)->sat_addr.s_node);
757 		break;
758 
759 	default:
760 		(void)snprintf(line, sizeof line, "af %d: %s",
761 			sa->sa_family, any_ntoa(sa));
762 		break;
763 	}
764 	return (line);
765 }
766 
767 static void
768 set_metric(value, key)
769 	char *value;
770 	int key;
771 {
772 	int flag = 0;
773 	u_long noval, *valp = &noval;
774 
775 	switch (key) {
776 #define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
777 	caseof(K_MTU, RTV_MTU, rmx_mtu);
778 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
779 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
780 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
781 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
782 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
783 	caseof(K_RTT, RTV_RTT, rmx_rtt);
784 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
785 	}
786 	rtm_inits |= flag;
787 	if (lockrest || locking)
788 		rt_metrics.rmx_locks |= flag;
789 	if (locking)
790 		locking = 0;
791 	*valp = atoi(value);
792 }
793 
794 static int
795 newroute(argc, argv)
796 	int argc;
797 	char **argv;
798 {
799 	char *cmd, *dest = "", *gateway = "";
800 	const char *error;
801 	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
802 	int key;
803 	struct hostent *hp = 0;
804 
805 	cmd = argv[0];
806 	af = 0;
807 	if (*cmd != 'g')
808 		shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
809 	while (--argc > 0) {
810 		if (**(++argv)== '-') {
811 			switch (key = keyword(1 + *argv)) {
812 
813 			case K_SA:
814 				af = PF_ROUTE;
815 				aflen = sizeof(union sockunion);
816 				break;
817 
818 			case K_ATALK:
819 				af = AF_APPLETALK;
820 				aflen = sizeof(struct sockaddr_at);
821 				break;
822 
823 			case K_INET:
824 				af = AF_INET;
825 				aflen = sizeof(struct sockaddr_in);
826 				break;
827 
828 #ifdef INET6
829 			case K_INET6:
830 				af = AF_INET6;
831 				aflen = sizeof(struct sockaddr_in6);
832 				break;
833 #endif
834 
835 			case K_LINK:
836 				af = AF_LINK;
837 				aflen = sizeof(struct sockaddr_dl);
838 				break;
839 
840 #ifndef SMALL
841 			case K_OSI:
842 			case K_ISO:
843 				af = AF_ISO;
844 				aflen = sizeof(struct sockaddr_iso);
845 				break;
846 
847 			case K_X25:
848 				af = AF_CCITT;
849 				aflen = sizeof(struct sockaddr_x25);
850 				break;
851 
852 			case K_XNS:
853 				af = AF_NS;
854 				aflen = sizeof(struct sockaddr_ns);
855 				break;
856 #endif /* SMALL */
857 
858 			case K_IFACE:
859 			case K_INTERFACE:
860 				iflag++;
861 				break;
862 			case K_NOSTATIC:
863 				flags &= ~RTF_STATIC;
864 				break;
865 			case K_LLINFO:
866 				flags |= RTF_LLINFO;
867 				break;
868 			case K_LOCK:
869 				locking = 1;
870 				break;
871 			case K_LOCKREST:
872 				lockrest = 1;
873 				break;
874 			case K_HOST:
875 				forcehost++;
876 				break;
877 			case K_REJECT:
878 				flags |= RTF_REJECT;
879 				break;
880 			case K_BLACKHOLE:
881 				flags |= RTF_BLACKHOLE;
882 				break;
883 			case K_CLONED:
884 				flags |= RTF_CLONED;
885 				break;
886 			case K_PROTO1:
887 				flags |= RTF_PROTO1;
888 				break;
889 			case K_PROTO2:
890 				flags |= RTF_PROTO2;
891 				break;
892 			case K_CLONING:
893 				flags |= RTF_CLONING;
894 				break;
895 			case K_XRESOLVE:
896 				flags |= RTF_XRESOLVE;
897 				break;
898 			case K_STATIC:
899 				flags |= RTF_STATIC;
900 				break;
901 			case K_IFA:
902 				if (!--argc)
903 					usage(1+*argv);
904 				(void) getaddr(RTA_IFA, *++argv, 0);
905 				break;
906 			case K_IFP:
907 				if (!--argc)
908 					usage(1+*argv);
909 				(void) getaddr(RTA_IFP, *++argv, 0);
910 				break;
911 			case K_GENMASK:
912 				if (!--argc)
913 					usage(1+*argv);
914 				(void) getaddr(RTA_GENMASK, *++argv, 0);
915 				break;
916 			case K_GATEWAY:
917 				if (!--argc)
918 					usage(1+*argv);
919 				(void) getaddr(RTA_GATEWAY, *++argv, 0);
920 				break;
921 			case K_DST:
922 				if (!--argc)
923 					usage(1+*argv);
924 				ishost = getaddr(RTA_DST, *++argv, &hp);
925 				dest = *argv;
926 				break;
927 			case K_NETMASK:
928 				if (!--argc)
929 					usage(1+*argv);
930 				(void) getaddr(RTA_NETMASK, *++argv, 0);
931 				/* FALLTHROUGH */
932 			case K_NET:
933 				forcenet++;
934 				break;
935 			case K_PREFIXLEN:
936 				argc--;
937 				if (prefixlen(*++argv) == 128) {
938 					forcenet = 0;
939 					ishost = 1;
940 				} else {
941 					forcenet = 1;
942 					ishost = 0;
943 				}
944 				break;
945 			case K_MTU:
946 			case K_HOPCOUNT:
947 			case K_EXPIRE:
948 			case K_RECVPIPE:
949 			case K_SENDPIPE:
950 			case K_SSTHRESH:
951 			case K_RTT:
952 			case K_RTTVAR:
953 				if (!--argc)
954 					usage(1+*argv);
955 				set_metric(*++argv, key);
956 				break;
957 			default:
958 				usage(1+*argv);
959 			}
960 		} else {
961 			if ((rtm_addrs & RTA_DST) == 0) {
962 				dest = *argv;
963 				ishost = getaddr(RTA_DST, *argv, &hp);
964 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
965 				gateway = *argv;
966 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
967 			} else {
968 				ret = atoi(*argv);
969 
970 				if (ret == 0) {
971 				    if (!qflag && strcmp(*argv, "0") == 0)
972 				        warnx("%s, %s",
973 					    "old usage of trailing 0",
974 					    "assuming route to if");
975 				    else
976 					usage((char *)NULL);
977 				    iflag = 1;
978 				    continue;
979 				} else if (ret > 0 && ret < 10) {
980 				    if (!qflag) {
981 				        warnx("%s, %s",
982 					    "old usage of trailing digit",
983 					    "assuming route via gateway");
984 				    }
985 				    iflag = 0;
986 				    continue;
987 				}
988 				(void) getaddr(RTA_NETMASK, *argv, 0);
989 			}
990 		}
991 	}
992 	if (forcehost)
993 		ishost = 1;
994 	if (forcenet)
995 		ishost = 0;
996 	flags |= RTF_UP;
997 	if (ishost)
998 		flags |= RTF_HOST;
999 	if (iflag == 0)
1000 		flags |= RTF_GATEWAY;
1001 	for (attempts = 1; ; attempts++) {
1002 		errno = 0;
1003 		if ((ret = rtmsg(*cmd, flags)) == 0)
1004 			break;
1005 		if (errno != ENETUNREACH && errno != ESRCH)
1006 			break;
1007 		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
1008 			hp->h_addr_list++;
1009 			memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
1010 			    hp->h_length);
1011 		} else
1012 			break;
1013 	}
1014 	if (*cmd == 'g')
1015 		return rv;
1016 	oerrno = errno;
1017 	if (!qflag) {
1018 		(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
1019 		if (*gateway) {
1020 			(void) printf(": gateway %s", gateway);
1021 			if (attempts > 1 && ret == 0 && af == AF_INET)
1022 			    (void) printf(" (%s)",
1023 			        inet_ntoa(so_gate.sin.sin_addr));
1024 		}
1025 		if (ret == 0)
1026 			(void) printf("\n");
1027 	}
1028 	if (ret != 0) {
1029 		switch (oerrno) {
1030 		case ESRCH:
1031 			error = "not in table";
1032 			break;
1033 		case EBUSY:
1034 			error = "entry in use";
1035 			break;
1036 		case ENOBUFS:
1037 			error = "routing table overflow";
1038 			break;
1039 		default:
1040 			error = strerror(oerrno);
1041 			break;
1042 		}
1043 		(void) printf(": %s\n", error);
1044 		return 1;
1045 	}
1046 	return 0;
1047 }
1048 
1049 static void
1050 inet_makenetandmask(net, isin)
1051 	u_int32_t net;
1052 	struct sockaddr_in *isin;
1053 {
1054 	u_int32_t addr, mask = 0;
1055 	char *cp;
1056 
1057 	rtm_addrs |= RTA_NETMASK;
1058 	if (net == 0)
1059 		mask = addr = 0;
1060 	else if (net < 128) {
1061 		addr = net << IN_CLASSA_NSHIFT;
1062 		mask = IN_CLASSA_NET;
1063 	} else if (net < 65536) {
1064 		addr = net << IN_CLASSB_NSHIFT;
1065 		mask = IN_CLASSB_NET;
1066 	} else if (net < 16777216L) {
1067 		addr = net << IN_CLASSC_NSHIFT;
1068 		mask = IN_CLASSC_NET;
1069 	} else {
1070 		addr = net;
1071 		if ((addr & IN_CLASSA_HOST) == 0)
1072 			mask =  IN_CLASSA_NET;
1073 		else if ((addr & IN_CLASSB_HOST) == 0)
1074 			mask =  IN_CLASSB_NET;
1075 		else if ((addr & IN_CLASSC_HOST) == 0)
1076 			mask =  IN_CLASSC_NET;
1077 		else
1078 			mask = -1;
1079 	}
1080 	isin->sin_addr.s_addr = htonl(addr);
1081 	isin = &so_mask.sin;
1082 	isin->sin_addr.s_addr = htonl(mask);
1083 	isin->sin_len = 0;
1084 	isin->sin_family = 0;
1085 	cp = (char *)(&isin->sin_addr + 1);
1086 	while (*--cp == 0 && cp > (char *)isin)
1087 		;
1088 	isin->sin_len = 1 + cp - (char *)isin;
1089 }
1090 
1091 #ifdef INET6
1092 /*
1093  * XXX the function may need more improvement...
1094  */
1095 static void
1096 inet6_makenetandmask(sin6)
1097 	struct sockaddr_in6 *sin6;
1098 {
1099 	char *plen;
1100 	struct in6_addr in6;
1101 
1102 	plen = NULL;
1103 	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1104 	    sin6->sin6_scope_id == 0) {
1105 		plen = "0";
1106 	} else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
1107 		/* aggregatable global unicast - RFC2374 */
1108 		memset(&in6, 0, sizeof(in6));
1109 		if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
1110 			plen = "64";
1111 		else
1112 			plen = "128";
1113 	}
1114 
1115 	if (plen) {
1116 		rtm_addrs |= RTA_NETMASK;
1117 		prefixlen(plen);
1118 	}
1119 }
1120 #endif
1121 
1122 /*
1123  * Interpret an argument as a network address of some kind,
1124  * returning 1 if a host address, 0 if a network address.
1125  */
1126 static int
1127 getaddr(which, s, hpp)
1128 	int which;
1129 	char *s;
1130 	struct hostent **hpp;
1131 {
1132 	sup su;
1133 	struct hostent *hp;
1134 	struct netent *np;
1135 	u_int32_t val;
1136 	char *t;
1137 	int afamily;  /* local copy of af so we can change it */
1138 
1139 	if (af == 0) {
1140 		af = AF_INET;
1141 		aflen = sizeof(struct sockaddr_in);
1142 	}
1143 	afamily = af;
1144 	rtm_addrs |= which;
1145 	switch (which) {
1146 	case RTA_DST:
1147 		su = &so_dst;
1148 		break;
1149 	case RTA_GATEWAY:
1150 		su = &so_gate;
1151 		break;
1152 	case RTA_NETMASK:
1153 		su = &so_mask;
1154 		break;
1155 	case RTA_GENMASK:
1156 		su = &so_genmask;
1157 		break;
1158 	case RTA_IFP:
1159 		su = &so_ifp;
1160 		afamily = AF_LINK;
1161 		break;
1162 	case RTA_IFA:
1163 		su = &so_ifa;
1164 		su->sa.sa_family = af;
1165 		break;
1166 	default:
1167 		su = NULL;
1168 		usage("Internal Error");
1169 		/*NOTREACHED*/
1170 	}
1171 	su->sa.sa_len = aflen;
1172 	su->sa.sa_family = afamily; /* cases that don't want it have left already */
1173 	if (strcmp(s, "default") == 0) {
1174 		switch (which) {
1175 		case RTA_DST:
1176 			forcenet++;
1177 			(void) getaddr(RTA_NETMASK, s, 0);
1178 			break;
1179 		case RTA_NETMASK:
1180 		case RTA_GENMASK:
1181 			su->sa.sa_len = 0;
1182 		}
1183 		return (0);
1184 	}
1185 	switch (afamily) {
1186 #ifndef SMALL
1187 #ifdef INET6
1188 	case AF_INET6:
1189 	    {
1190 		struct addrinfo hints, *res;
1191 
1192 		memset(&hints, 0, sizeof(hints));
1193 		hints.ai_family = afamily;	/*AF_INET6*/
1194 		hints.ai_flags = AI_NUMERICHOST;
1195 		hints.ai_socktype = SOCK_DGRAM;		/*dummy*/
1196 		if (getaddrinfo(s, "0", &hints, &res) != 0 ||
1197 		    res->ai_family != AF_INET6 ||
1198 		    res->ai_addrlen != sizeof(su->sin6)) {
1199 			(void) fprintf(stderr, "%s: bad value\n", s);
1200 			exit(1);
1201 		}
1202 		memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1203 #ifdef __KAME__
1204 		if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1205 		     IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1206 		    su->sin6.sin6_scope_id) {
1207 			*(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1208 				htons(su->sin6.sin6_scope_id);
1209 			su->sin6.sin6_scope_id = 0;
1210 		}
1211 #endif
1212 		if (which == RTA_DST)
1213 			inet6_makenetandmask(&su->sin6);
1214 		freeaddrinfo(res);
1215 		return 0;
1216 	    }
1217 #endif
1218 
1219 	case AF_NS:
1220 		if (which == RTA_DST) {
1221 			struct sockaddr_ns *sms = &(so_mask.sns);
1222 			memset(sms, 0, sizeof(*sms));
1223 			sms->sns_family = 0;
1224 			sms->sns_len = 6;
1225 			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
1226 			rtm_addrs |= RTA_NETMASK;
1227 		}
1228 		su->sns.sns_addr = ns_addr(s);
1229 		return (!ns_nullhost(su->sns.sns_addr));
1230 
1231 	case AF_OSI:
1232 		su->siso.siso_addr = *iso_addr(s);
1233 		if (which == RTA_NETMASK || which == RTA_GENMASK) {
1234 			char *cp = (char *)TSEL(&su->siso);
1235 			su->siso.siso_nlen = 0;
1236 			do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
1237 			su->siso.siso_len = 1 + cp - (char *)su;
1238 		}
1239 		return (1);
1240 
1241 	case AF_CCITT:
1242 		ccitt_addr(s, &su->sx25);
1243 		return (which == RTA_DST ? x25_makemask() : 1);
1244 #endif /* SMALL */
1245 
1246 	case PF_ROUTE:
1247 		su->sa.sa_len = sizeof(*su);
1248 		sockaddr(s, &su->sa);
1249 		return (1);
1250 
1251 	case AF_APPLETALK:
1252 		t = strchr (s, '.');
1253 		if (!t) {
1254 badataddr:
1255 			errx(1, "bad address: %s", s);
1256 		}
1257 		val = atoi (s);
1258 		if (val > 65535)
1259 			goto badataddr;
1260 		su->sat.sat_addr.s_net = val;
1261 		val = atoi (t);
1262 		if (val > 256)
1263 			goto badataddr;
1264 		su->sat.sat_addr.s_node = val;
1265 		rtm_addrs |= RTA_NETMASK;
1266 		return(forcehost || su->sat.sat_addr.s_node != 0);
1267 
1268 	case AF_LINK:
1269 		link_addr(s, &su->sdl);
1270 		return (1);
1271 
1272 	case AF_INET:
1273 	default:
1274 		break;
1275 	}
1276 
1277 	if (hpp == NULL)
1278 		hpp = &hp;
1279 	*hpp = NULL;
1280 	if (((val = inet_addr(s)) != INADDR_NONE) &&
1281 	    (which != RTA_DST || forcenet == 0)) {
1282 		su->sin.sin_addr.s_addr = val;
1283 		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1284 			return (1);
1285 		else {
1286 			val = ntohl(val);
1287 			goto netdone;
1288 		}
1289 	}
1290 	if ((val = inet_network(s)) != INADDR_NONE ||
1291 	    ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
1292 netdone:
1293 		if (which == RTA_DST)
1294 			inet_makenetandmask(val, &su->sin);
1295 		return (0);
1296 	}
1297 	hp = gethostbyname(s);
1298 	if (hp) {
1299 		*hpp = hp;
1300 		su->sin.sin_family = hp->h_addrtype;
1301 		memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
1302 		return (1);
1303 	}
1304 	errx(1, "bad value: %s", s);
1305 }
1306 
1307 int
1308 prefixlen(s)
1309 	char *s;
1310 {
1311 	int len = atoi(s), q, r;
1312 	int max;
1313 
1314 	switch (af) {
1315 	case AF_INET:
1316 		max = sizeof(struct in_addr) * 8;
1317 		break;
1318 #ifdef INET6
1319 	case AF_INET6:
1320 		max = sizeof(struct in6_addr) * 8;
1321 		break;
1322 #endif
1323 	default:
1324 		(void) fprintf(stderr,
1325 		    "prefixlen is not supported with af %d\n", af);
1326 		exit(1);
1327 	}
1328 
1329 	rtm_addrs |= RTA_NETMASK;
1330 	if (len < -1 || len > max) {
1331 		(void) fprintf(stderr, "%s: bad value\n", s);
1332 		exit(1);
1333 	}
1334 
1335 	q = len >> 3;
1336 	r = len & 7;
1337 	switch (af) {
1338 	case AF_INET:
1339 		memset(&so_mask, 0, sizeof(so_mask));
1340 		so_mask.sin.sin_family = AF_INET;
1341 		so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1342 		so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len));
1343 		break;
1344 #ifdef INET6
1345 	case AF_INET6:
1346 		so_mask.sin6.sin6_family = AF_INET6;
1347 		so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1348 		memset((void *)&so_mask.sin6.sin6_addr, 0,
1349 			sizeof(so_mask.sin6.sin6_addr));
1350 		if (q > 0)
1351 			memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1352 		if (r > 0)
1353 			*((u_char *)&so_mask.sin6.sin6_addr + q) =
1354 			    (0xff00 >> r) & 0xff;
1355 		break;
1356 #endif
1357 	}
1358 	return(len);
1359 }
1360 
1361 #ifndef SMALL
1362 int
1363 x25_makemask()
1364 {
1365 	char *cp;
1366 
1367 	if ((rtm_addrs & RTA_NETMASK) == 0) {
1368 		rtm_addrs |= RTA_NETMASK;
1369 		for (cp = (char *)&so_mask.sx25.x25_net;
1370 		     cp < &so_mask.sx25.x25_opts.op_flags; cp++)
1371 			*cp = -1;
1372 		so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
1373 	}
1374 	return 0;
1375 }
1376 
1377 
1378 char *
1379 ns_print(sns)
1380 	struct sockaddr_ns *sns;
1381 {
1382 	struct ns_addr work;
1383 	union { union ns_net net_e; u_int32_t int32_t_e; } net;
1384 	u_short port;
1385 	static char mybuf[50], cport[10], chost[25];
1386 	char *host = "";
1387 	char *p;
1388 	u_char *q;
1389 
1390 	work = sns->sns_addr;
1391 	port = ntohs(work.x_port);
1392 	work.x_port = 0;
1393 	net.net_e  = work.x_net;
1394 	if (ns_nullhost(work) && net.int32_t_e == 0) {
1395 		if (!port)
1396 			return ("*.*");
1397 		(void)snprintf(mybuf, sizeof mybuf, "*.%XH", port);
1398 		return (mybuf);
1399 	}
1400 
1401 	if (memcmp(ns_bh, work.x_host.c_host, 6) == 0)
1402 		host = "any";
1403 	else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0)
1404 		host = "*";
1405 	else {
1406 		q = work.x_host.c_host;
1407 		(void)snprintf(chost, sizeof chost, "%02X%02X%02X%02X%02X%02XH",
1408 			q[0], q[1], q[2], q[3], q[4], q[5]);
1409 		for (p = chost; *p == '0' && p < chost + 12; p++)
1410 			/* void */;
1411 		host = p;
1412 	}
1413 	if (port)
1414 		(void)snprintf(cport, sizeof cport, ".%XH", htons(port));
1415 	else
1416 		*cport = 0;
1417 
1418 	(void)snprintf(mybuf, sizeof mybuf, "%XH.%s%s",
1419 	    (u_int32_t)ntohl(net.int32_t_e), host, cport);
1420 	return (mybuf);
1421 }
1422 
1423 static void
1424 interfaces()
1425 {
1426 	size_t needed;
1427 	int mib[6];
1428 	char *buf, *lim, *next;
1429 	struct rt_msghdr *rtm;
1430 
1431 	mib[0] = CTL_NET;
1432 	mib[1] = PF_ROUTE;
1433 	mib[2] = 0;		/* protocol */
1434 	mib[3] = 0;		/* wildcard address family */
1435 	mib[4] = NET_RT_IFLIST;
1436 	mib[5] = 0;		/* no flags */
1437 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1438 		err(1, "route-sysctl-estimate");
1439 	if ((buf = malloc(needed)) == NULL)
1440 		err(1, "malloc");
1441 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1442 		err(1, "actual retrieval of interface table");
1443 	lim = buf + needed;
1444 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1445 		rtm = (struct rt_msghdr *)next;
1446 		print_rtmsg(rtm, rtm->rtm_msglen);
1447 	}
1448 }
1449 
1450 static void
1451 monitor()
1452 {
1453 	int n;
1454 	char msg[2048];
1455 
1456 	verbose = 1;
1457 	if (debugonly) {
1458 		interfaces();
1459 		exit(0);
1460 	}
1461 	for(;;) {
1462 		time_t now;
1463 		n = read(sock, msg, 2048);
1464 		now = time(NULL);
1465 		(void) printf("got message of size %d on %s", n, ctime(&now));
1466 		print_rtmsg((struct rt_msghdr *)msg, n);
1467 	}
1468 }
1469 
1470 #endif /* SMALL */
1471 
1472 
1473 struct {
1474 	struct	rt_msghdr m_rtm;
1475 	char	m_space[512];
1476 } m_rtmsg;
1477 
1478 static int
1479 rtmsg(cmd, flags)
1480 	int cmd, flags;
1481 {
1482 	static int seq;
1483 	int rlen;
1484 	char *cp = m_rtmsg.m_space;
1485 	int l;
1486 
1487 #define NEXTADDR(w, u) \
1488 	if (rtm_addrs & (w)) {\
1489 	    l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1490 	    if (verbose && ! shortoutput) sodump(&(u),"u");\
1491 	}
1492 
1493 	errno = 0;
1494 	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1495 	if (cmd == 'a')
1496 		cmd = RTM_ADD;
1497 	else if (cmd == 'c')
1498 		cmd = RTM_CHANGE;
1499 	else if (cmd == 'g') {
1500 #ifdef	SMALL
1501 		return (-1);
1502 #else	/* SMALL */
1503 		cmd = RTM_GET;
1504 		if (so_ifp.sa.sa_family == 0) {
1505 			so_ifp.sa.sa_family = AF_LINK;
1506 			so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1507 			rtm_addrs |= RTA_IFP;
1508 		}
1509 #endif	/* SMALL */
1510 	} else
1511 		cmd = RTM_DELETE;
1512 #define rtm m_rtmsg.m_rtm
1513 	rtm.rtm_type = cmd;
1514 	rtm.rtm_flags = flags;
1515 	rtm.rtm_version = RTM_VERSION;
1516 	rtm.rtm_seq = ++seq;
1517 	rtm.rtm_addrs = rtm_addrs;
1518 	rtm.rtm_rmx = rt_metrics;
1519 	rtm.rtm_inits = rtm_inits;
1520 
1521 	if (rtm_addrs & RTA_NETMASK)
1522 		mask_addr();
1523 	NEXTADDR(RTA_DST, so_dst);
1524 	NEXTADDR(RTA_GATEWAY, so_gate);
1525 	NEXTADDR(RTA_NETMASK, so_mask);
1526 	NEXTADDR(RTA_GENMASK, so_genmask);
1527 	NEXTADDR(RTA_IFP, so_ifp);
1528 	NEXTADDR(RTA_IFA, so_ifa);
1529 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1530 	if (verbose && ! shortoutput)
1531 		print_rtmsg(&rtm, l);
1532 	if (debugonly)
1533 		return (0);
1534 	if ((rlen = write(sock, (char *)&m_rtmsg, l)) < 0) {
1535 		perror("writing to routing socket");
1536 		return (-1);
1537 	}
1538 #ifndef	SMALL
1539 	if (cmd == RTM_GET) {
1540 		do {
1541 			l = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
1542 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1543 		if (l < 0)
1544 			err(1, "read from routing socket");
1545 		else
1546 			print_getmsg(&rtm, l);
1547 	}
1548 #endif	/* SMALL */
1549 #undef rtm
1550 	return (0);
1551 }
1552 
1553 static void
1554 mask_addr()
1555 {
1556 	int olen = so_mask.sa.sa_len;
1557 	char *cp1 = olen + (char *)&so_mask, *cp2;
1558 
1559 	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1560 		if (*--cp1 != 0) {
1561 			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1562 			break;
1563 		}
1564 	if ((rtm_addrs & RTA_DST) == 0)
1565 		return;
1566 	switch (so_dst.sa.sa_family) {
1567 	case AF_INET:
1568 #ifdef INET6
1569 	case AF_INET6:
1570 #endif
1571 	case AF_APPLETALK:
1572 #ifndef SMALL
1573 	case AF_NS:
1574 	case AF_CCITT:
1575 #endif /* SMALL */
1576 	case 0:
1577 		return;
1578 #ifndef SMALL
1579 	case AF_ISO:
1580 		olen = MIN(so_dst.siso.siso_nlen,
1581 			   MAX(so_mask.sa.sa_len - 6, 0));
1582 		break;
1583 #endif /* SMALL */
1584 	}
1585 	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1586 	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1587 	while (cp2 > cp1)
1588 		*--cp2 = 0;
1589 	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1590 	while (cp1 > so_dst.sa.sa_data)
1591 		*--cp1 &= *--cp2;
1592 #ifndef SMALL
1593 	switch (so_dst.sa.sa_family) {
1594 	case AF_ISO:
1595 		so_dst.siso.siso_nlen = olen;
1596 		break;
1597 	}
1598 #endif /* SMALL */
1599 }
1600 
1601 char *msgtypes[] = {
1602 	"",
1603 	"RTM_ADD: Add Route",
1604 	"RTM_DELETE: Delete Route",
1605 	"RTM_CHANGE: Change Metrics or flags",
1606 	"RTM_GET: Report Metrics",
1607 	"RTM_LOSING: Kernel Suspects Partitioning",
1608 	"RTM_REDIRECT: Told to use different route",
1609 	"RTM_MISS: Lookup failed on this address",
1610 	"RTM_LOCK: fix specified metrics",
1611 	"RTM_OLDADD: caused by SIOCADDRT",
1612 	"RTM_OLDDEL: caused by SIOCDELRT",
1613 	"RTM_RESOLVE: Route created by cloning",
1614 	"RTM_NEWADDR: address being added to iface",
1615 	"RTM_DELADDR: address being removed from iface",
1616 	"RTM_OIFINFO: iface status change (pre-1.5)",
1617 	"RTM_IFINFO: iface status change",
1618 	"RTM_IFANNOUNCE: iface arrival/departure",
1619 	0,
1620 };
1621 
1622 char metricnames[] =
1623 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1624 char routeflags[] =
1625 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1626 char ifnetflags[] =
1627 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1628 char addrnames[] =
1629 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1630 
1631 static void
1632 print_rtmsg(rtm, msglen)
1633 	struct rt_msghdr *rtm;
1634 	int msglen;
1635 {
1636 	struct if_msghdr *ifm;
1637 	struct ifa_msghdr *ifam;
1638 	struct if_announcemsghdr *ifan;
1639 
1640 	if (verbose == 0)
1641 		return;
1642 	if (rtm->rtm_version != RTM_VERSION) {
1643 		(void) printf("routing message version %d not understood\n",
1644 		    rtm->rtm_version);
1645 		return;
1646 	}
1647 	if (msgtypes[rtm->rtm_type])
1648 		(void)printf("%s: ", msgtypes[rtm->rtm_type]);
1649 	else
1650 		(void)printf("#%d: ", rtm->rtm_type);
1651 	(void)printf("len %d, ", rtm->rtm_msglen);
1652 	switch (rtm->rtm_type) {
1653 	case RTM_IFINFO:
1654 		ifm = (struct if_msghdr *)rtm;
1655 		(void) printf("if# %d, flags:", ifm->ifm_index);
1656 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1657 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1658 		break;
1659 	case RTM_NEWADDR:
1660 	case RTM_DELADDR:
1661 		ifam = (struct ifa_msghdr *)rtm;
1662 		(void) printf("metric %d, flags:", ifam->ifam_metric);
1663 		bprintf(stdout, ifam->ifam_flags, routeflags);
1664 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1665 		break;
1666 	case RTM_IFANNOUNCE:
1667 		ifan = (struct if_announcemsghdr *)rtm;
1668 		(void) printf("if# %d, what: ", ifan->ifan_index);
1669 		switch (ifan->ifan_what) {
1670 		case IFAN_ARRIVAL:
1671 			printf("arrival");
1672 			break;
1673 		case IFAN_DEPARTURE:
1674 			printf("departure");
1675 			break;
1676 		default:
1677 			printf("#%d", ifan->ifan_what);
1678 			break;
1679 		}
1680 		printf("\n");
1681 		break;
1682 	default:
1683 		(void) printf("pid: %d, seq %d, errno %d, flags:",
1684 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1685 		bprintf(stdout, rtm->rtm_flags, routeflags);
1686 		pmsg_common(rtm);
1687 	}
1688 }
1689 
1690 #ifndef	SMALL
1691 static void
1692 print_getmsg(rtm, msglen)
1693 	struct rt_msghdr *rtm;
1694 	int msglen;
1695 {
1696 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1697 	struct sockaddr_dl *ifp = NULL;
1698 	struct sockaddr *sa;
1699 	char *cp;
1700 	int i;
1701 
1702 	if (! shortoutput)
1703 		(void) printf("   route to: %s\n",
1704 		    routename((struct sockaddr *) &so_dst, NULL, RTF_HOST));
1705 	if (rtm->rtm_version != RTM_VERSION) {
1706 		warnx("routing message version %d not understood",
1707 		    rtm->rtm_version);
1708 		return;
1709 	}
1710 	if (rtm->rtm_msglen > msglen) {
1711 		warnx("message length mismatch, in packet %d, returned %d\n",
1712 		    rtm->rtm_msglen, msglen);
1713 	}
1714 	if (rtm->rtm_errno)  {
1715 		warn("RTM_GET");
1716 		return;
1717 	}
1718 	cp = ((char *)(rtm + 1));
1719 	if (rtm->rtm_addrs)
1720 		for (i = 1; i; i <<= 1)
1721 			if (i & rtm->rtm_addrs) {
1722 				sa = (struct sockaddr *)cp;
1723 				switch (i) {
1724 				case RTA_DST:
1725 					dst = sa;
1726 					break;
1727 				case RTA_GATEWAY:
1728 					gate = sa;
1729 					break;
1730 				case RTA_NETMASK:
1731 					mask = sa;
1732 					break;
1733 				case RTA_IFP:
1734 					if (sa->sa_family == AF_LINK &&
1735 					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1736 						ifp = (struct sockaddr_dl *)sa;
1737 					break;
1738 				case RTA_IFA:
1739 					ifa = sa;
1740 					break;
1741 				}
1742 				ADVANCE(cp, sa);
1743 			}
1744 	if (dst && mask)
1745 		mask->sa_family = dst->sa_family;	/* XXX */
1746 	if (dst && ! shortoutput)
1747 		(void)printf("destination: %s\n",
1748 		    routename(dst, mask, RTF_HOST));
1749 	if (mask && ! shortoutput) {
1750 		int savenflag = nflag;
1751 
1752 		nflag = 1;
1753 		(void)printf("       mask: %s\n",
1754 		    routename(mask, NULL, RTF_HOST));
1755 		nflag = savenflag;
1756 	}
1757 	if (gate && rtm->rtm_flags & RTF_GATEWAY && ! shortoutput)
1758 		(void)printf("    gateway: %s\n",
1759 		    routename(gate, NULL, RTF_HOST));
1760 	if (ifa && ! shortoutput)
1761 		(void)printf(" local addr: %s\n",
1762 		    routename(ifa, NULL, RTF_HOST));
1763 	if (ifp && ! shortoutput)
1764 		(void)printf("  interface: %.*s\n",
1765 		    ifp->sdl_nlen, ifp->sdl_data);
1766 	if (! shortoutput) {
1767 		(void)printf("      flags: ");
1768 		bprintf(stdout, rtm->rtm_flags, routeflags);
1769 	}
1770 
1771 #define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1772 #define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1773 
1774 	if (! shortoutput) {
1775 		(void) printf("\n%s\n", "\
1776  recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
1777 		printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1778 		printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1779 		printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1780 		printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1781 		printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1782 		printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1783 		printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1784 		if (rtm->rtm_rmx.rmx_expire)
1785 			rtm->rtm_rmx.rmx_expire -= time(0);
1786 		printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1787 	}
1788 #undef lock
1789 #undef msec
1790 #define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1791 
1792 	if ((rtm->rtm_addrs & RTF_GATEWAY) == 0)
1793 		rv = 1;
1794 	else {
1795 		char *name;
1796 		int addrs;
1797 
1798 		cp = (char *)(rtm + 1);
1799 		addrs = rtm->rtm_addrs;
1800 
1801 		for (i = 1; i; i <<= 1) {
1802 			sa = (struct sockaddr *)cp;
1803 			if (i == RTF_GATEWAY) {
1804 				name = routename(sa, NULL, RTF_HOST);
1805 				if (name[0] == '\0')
1806 					rv = 1;
1807 				else if (shortoutput)
1808 					printf("%s\n", name);
1809 			}
1810 			if (i & addrs)
1811 				ADVANCE(cp, sa);
1812 		}
1813 	}
1814 
1815 	if (shortoutput)
1816 		return;
1817 	else if (verbose)
1818 		pmsg_common(rtm);
1819 	else if (rtm->rtm_addrs &~ RTA_IGN) {
1820 		(void) printf("sockaddrs: ");
1821 		bprintf(stdout, rtm->rtm_addrs, addrnames);
1822 		putchar('\n');
1823 	}
1824 #undef	RTA_IGN
1825 }
1826 #endif	/* SMALL */
1827 
1828 void
1829 pmsg_common(rtm)
1830 	struct rt_msghdr *rtm;
1831 {
1832 	(void) printf("\nlocks: ");
1833 	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1834 	(void) printf(" inits: ");
1835 	bprintf(stdout, rtm->rtm_inits, metricnames);
1836 	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1837 }
1838 
1839 static void
1840 pmsg_addrs(cp, addrs)
1841 	char	*cp;
1842 	int	addrs;
1843 {
1844 	struct sockaddr *sa;
1845 	int i;
1846 
1847 	if (addrs != 0) {
1848 		(void) printf("\nsockaddrs: ");
1849 		bprintf(stdout, addrs, addrnames);
1850 		(void) putchar('\n');
1851 		for (i = 1; i; i <<= 1)
1852 			if (i & addrs) {
1853 				sa = (struct sockaddr *)cp;
1854 				(void) printf(" %s",
1855 				    routename(sa, NULL, RTF_HOST));
1856 				ADVANCE(cp, sa);
1857 			}
1858 	}
1859 	(void) putchar('\n');
1860 	(void) fflush(stdout);
1861 }
1862 
1863 static void
1864 bprintf(fp, b, s)
1865 	FILE *fp;
1866 	int b;
1867 	u_char *s;
1868 {
1869 	int i;
1870 	int gotsome = 0;
1871 
1872 	if (b == 0)
1873 		return;
1874 	while ((i = *s++) != 0) {
1875 		if (b & (1 << (i-1))) {
1876 			if (gotsome == 0)
1877 				i = '<';
1878 			else
1879 				i = ',';
1880 			(void) putc(i, fp);
1881 			gotsome = 1;
1882 			for (; (i = *s) > 32; s++)
1883 				(void) putc(i, fp);
1884 		} else
1885 			while (*s > 32)
1886 				s++;
1887 	}
1888 	if (gotsome)
1889 		(void) putc('>', fp);
1890 }
1891 
1892 static int
1893 keyword(cp)
1894 	char *cp;
1895 {
1896 	struct keytab *kt = keywords;
1897 
1898 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1899 		kt++;
1900 	return kt->kt_i;
1901 }
1902 
1903 static void
1904 sodump(su, which)
1905 	sup su;
1906 	char *which;
1907 {
1908 #ifdef INET6
1909 	char ntop_buf[NI_MAXHOST];
1910 #endif
1911 
1912 	switch (su->sa.sa_family) {
1913 	case AF_INET:
1914 		(void) printf("%s: inet %s; ",
1915 		    which, inet_ntoa(su->sin.sin_addr));
1916 		break;
1917 	case AF_APPLETALK:
1918 		(void) printf("%s: atalk %d.%d; ",
1919 		    which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
1920 		break;
1921 	case AF_LINK:
1922 		(void) printf("%s: link %s; ",
1923 		    which, link_ntoa(&su->sdl));
1924 		break;
1925 #ifndef SMALL
1926 #ifdef INET6
1927 	case AF_INET6:
1928 		(void) printf("%s: inet6 %s; ",
1929 		    which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1930 				     ntop_buf, sizeof(ntop_buf)));
1931 		break;
1932 #endif
1933 	case AF_ISO:
1934 		(void) printf("%s: iso %s; ",
1935 		    which, iso_ntoa(&su->siso.siso_addr));
1936 		break;
1937 	case AF_NS:
1938 		(void) printf("%s: xns %s; ",
1939 		    which, ns_ntoa(su->sns.sns_addr));
1940 		break;
1941 #endif /* SMALL */
1942 	default:
1943 		(void) printf("af %p: %s; ",
1944 			which, any_ntoa(&su->sa));
1945 	}
1946 	(void) fflush(stdout);
1947 }
1948 
1949 /* States*/
1950 #define VIRGIN	0
1951 #define GOTONE	1
1952 #define GOTTWO	2
1953 /* Inputs */
1954 #define	DIGIT	(4*0)
1955 #define	END	(4*1)
1956 #define DELIM	(4*2)
1957 
1958 static void
1959 sockaddr(addr, sa)
1960 	char *addr;
1961 	struct sockaddr *sa;
1962 {
1963 	char *cp = (char *)sa;
1964 	int size = sa->sa_len;
1965 	char *cplim = cp + size;
1966 	int byte = 0, state = VIRGIN, new = 0;
1967 
1968 	(void) memset(cp, 0, size);
1969 	cp++;
1970 	do {
1971 		if ((*addr >= '0') && (*addr <= '9')) {
1972 			new = *addr - '0';
1973 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
1974 			new = *addr - 'a' + 10;
1975 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
1976 			new = *addr - 'A' + 10;
1977 		} else if (*addr == 0)
1978 			state |= END;
1979 		else
1980 			state |= DELIM;
1981 		addr++;
1982 		switch (state /* | INPUT */) {
1983 		case GOTTWO | DIGIT:
1984 			*cp++ = byte; /*FALLTHROUGH*/
1985 		case VIRGIN | DIGIT:
1986 			state = GOTONE; byte = new; continue;
1987 		case GOTONE | DIGIT:
1988 			state = GOTTWO; byte = new + (byte << 4); continue;
1989 		default: /* | DELIM */
1990 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
1991 		case GOTONE | END:
1992 		case GOTTWO | END:
1993 			*cp++ = byte; /* FALLTHROUGH */
1994 		case VIRGIN | END:
1995 			break;
1996 		}
1997 		break;
1998 	} while (cp < cplim);
1999 	sa->sa_len = cp - (char *)sa;
2000 }
2001