xref: /original-bsd/sbin/route/route.c (revision 7bd39f15)
1 /*
2  *
3  * Copyright (c) 1983, 1989, 1991 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 char copyright[] =
11 "@(#) Copyright (c) 1983, 1989, 1991 The Regents of the University of California.\n\
12  All rights reserved.\n";
13 #endif /* not lint */
14 
15 #ifndef lint
16 static char sccsid[] = "@(#)route.c	5.44 (Berkeley) 02/20/92";
17 #endif /* not lint */
18 
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <sys/mbuf.h>
24 #include <sys/kinfo.h>
25 
26 #include <net/if.h>
27 #include <net/route.h>
28 #include <net/if_dl.h>
29 #include <netinet/in.h>
30 #include <netns/ns.h>
31 #include <netiso/iso.h>
32 #include <netccitt/x25.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
35 
36 #include <errno.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <paths.h>
43 
44 struct keytab {
45 	char	*kt_cp;
46 	int	kt_i;
47 } keywords[] = {
48 #include "keywords.h"
49 	{0, 0}
50 };
51 
52 struct	ortentry route;
53 union	sockunion {
54 	struct	sockaddr sa;
55 	struct	sockaddr_in sin;
56 	struct	sockaddr_ns sns;
57 	struct	sockaddr_iso siso;
58 	struct	sockaddr_dl sdl;
59 	struct	sockaddr_x25 sx25;
60 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
61 
62 typedef union sockunion *sup;
63 int	pid, rtm_addrs, uid;
64 int	s;
65 int	forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
66 int	iflag, verbose, aflen = sizeof (struct sockaddr_in);
67 int	locking, lockrest, debugonly;
68 struct	sockaddr_in sin = { sizeof(sin), AF_INET };
69 struct	rt_metrics rt_metrics;
70 u_long  rtm_inits;
71 struct	in_addr inet_makeaddr();
72 char	*routename(), *netname();
73 void	flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
74 void	print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs();
75 int	getaddr(), rtmsg(), x25_makemask();
76 extern	char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
77 
78 void
79 usage(cp)
80 	char *cp;
81 {
82 	if (cp)
83 		(void) fprintf(stderr, "route: botched keyword: %s\n", cp);
84 	(void) fprintf(stderr,
85 	    "usage: route [ -nqv ] cmd [[ -<qualifers> ] args ]\n");
86 	exit(1);
87 	/* NOTREACHED */
88 }
89 
90 void
91 quit(s)
92 	char *s;
93 {
94 	int sverrno = errno;
95 
96 	(void) fprintf(stderr, "route: ");
97 	if (s)
98 		(void) fprintf(stderr, "%s: ", s);
99 	(void) fprintf(stderr, "%s\n", strerror(sverrno));
100 	exit(1);
101 	/* NOTREACHED */
102 }
103 
104 #define ROUNDUP(a) \
105 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
106 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
107 
108 main(argc, argv)
109 	int argc;
110 	char **argv;
111 {
112 	extern int optind;
113 	int ch;
114 	char *argvp;
115 
116 	if (argc < 2)
117 		usage((char *)NULL);
118 
119 	while ((ch = getopt(argc, argv, "nqdtv")) != EOF)
120 		switch(ch) {
121 		case 'n':
122 			nflag = 1;
123 			break;
124 		case 'q':
125 			qflag = 1;
126 			break;
127 		case 'v':
128 			verbose = 1;
129 			break;
130 		case 't':
131 			tflag = 1;
132 			break;
133 		case 'd':
134 			debugonly = 1;
135 			break;
136 		case '?':
137 		default:
138 			usage();
139 		}
140 	argc -= optind;
141 	argv += optind;
142 
143 	pid = getpid();
144 	uid = getuid();
145 	if (tflag)
146 		s = open("/dev/null", O_WRONLY, 0);
147 	else
148 		s = socket(PF_ROUTE, SOCK_RAW, 0);
149 	if (s < 0)
150 		quit("socket");
151 	if (*argv)
152 		switch (keyword(*argv)) {
153 		case K_GET:
154 			uid = 0;
155 			/* FALLTHROUGH */
156 
157 		case K_CHANGE:
158 		case K_ADD:
159 		case K_DELETE:
160 			newroute(argc, argv);
161 			exit(0);
162 			/* NOTREACHED */
163 
164 		case K_MONITOR:
165 			monitor();
166 			/* NOTREACHED */
167 
168 		case K_FLUSH:
169 			flushroutes(argc, argv);
170 			exit(0);
171 			/* NOTREACHED */
172 		}
173 	usage(*argv);
174 	/* NOTREACHED */
175 }
176 
177 /*
178  * Purge all entries in the routing tables not
179  * associated with network interfaces.
180  */
181 void
182 flushroutes(argc, argv)
183 	int argc;
184 	char *argv[];
185 {
186 	int needed, seqno, rlen;
187 	char *buf, *next, *lim;
188 	register struct rt_msghdr *rtm;
189 
190 	if (uid)
191 		quit("must be root to alter routing table");
192 	shutdown(s, 0); /* Don't want to read back our messages */
193 	if (argc > 1) {
194 		argv++;
195 		if (argc == 2 && **argv == '-')
196 		    switch (keyword(*argv + 1)) {
197 			case K_INET:
198 				af = AF_INET;
199 				break;
200 			case K_XNS:
201 				af = AF_NS;
202 				break;
203 			case K_LINK:
204 				af = AF_LINK;
205 				break;
206 			case K_ISO:
207 			case K_OSI:
208 				af = AF_ISO;
209 				break;
210 			case K_X25:
211 				af = AF_CCITT;
212 			default:
213 				goto bad;
214 		} else
215 bad:			usage(*argv);
216 	}
217 	if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
218 		quit("route-getkerninfo-estimate");
219 	if ((buf = malloc(needed)) == NULL)
220 		quit("malloc");
221 	if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
222 		quit("actual retrieval of routing table");
223 	lim = buf + rlen;
224 	if (verbose)
225 		(void) printf("Examining routing table from getkerninfo\n");
226 	seqno = 0;		/* ??? */
227 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
228 		rtm = (struct rt_msghdr *)next;
229 		if (verbose)
230 			print_rtmsg(rtm, rtm->rtm_msglen);
231 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
232 			continue;
233 		if (af) {
234 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
235 
236 			if (sa->sa_family != af)
237 				continue;
238 		}
239 		if (debugonly)
240 			continue;
241 		rtm->rtm_type = RTM_DELETE;
242 		rtm->rtm_seq = seqno;
243 		rlen = write(s, next, rtm->rtm_msglen);
244 		if (rlen < (int)rtm->rtm_msglen) {
245 			(void) fprintf(stderr,
246 			    "route: write to routing socket: %s\n",
247 			    strerror(errno));
248 			(void) printf("got only %d for rlen\n", rlen);
249 			break;
250 		}
251 		seqno++;
252 		if (qflag)
253 			continue;
254 		if (verbose)
255 			print_rtmsg(rtm, rlen);
256 		else {
257 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
258 			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
259 			    routename(sa) : netname(sa));
260 			sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
261 			(void) printf("%-20.20s ", routename(sa));
262 			(void) printf("done\n");
263 		}
264 	}
265 }
266 
267 char *
268 routename(sa)
269 	struct sockaddr *sa;
270 {
271 	register char *cp;
272 	static char line[50];
273 	struct hostent *hp;
274 	static char domain[MAXHOSTNAMELEN + 1];
275 	static int first = 1;
276 	char *ns_print();
277 
278 	if (first) {
279 		first = 0;
280 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
281 		    (cp = index(domain, '.')))
282 			(void) strcpy(domain, cp + 1);
283 		else
284 			domain[0] = 0;
285 	}
286 
287 	if (sa->sa_len == 0)
288 		strcpy(line, "default");
289 	else switch (sa->sa_family) {
290 
291 	case AF_INET:
292 	    {	struct in_addr in;
293 		in = ((struct sockaddr_in *)sa)->sin_addr;
294 
295 		cp = 0;
296 		if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
297 			cp = "default";
298 		if (cp == 0 && !nflag) {
299 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
300 				AF_INET);
301 			if (hp) {
302 				if ((cp = index(hp->h_name, '.')) &&
303 				    !strcmp(cp + 1, domain))
304 					*cp = 0;
305 				cp = hp->h_name;
306 			}
307 		}
308 		if (cp)
309 			strcpy(line, cp);
310 		else {
311 #define C(x)	((x) & 0xff)
312 			in.s_addr = ntohl(in.s_addr);
313 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
314 			   C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
315 		}
316 		break;
317 	    }
318 
319 	case AF_NS:
320 		return (ns_print((struct sockaddr_ns *)sa));
321 
322 	case AF_LINK:
323 		return (link_ntoa((struct sockaddr_dl *)sa));
324 
325 	case AF_ISO:
326 		(void) sprintf(line, "iso %s",
327 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
328 		break;
329 
330 	default:
331 	    {	u_short *s = (u_short *)sa;
332 		u_short *slim = s + ((sa->sa_len + 1) >> 1);
333 		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
334 
335 		while (++s < slim) /* start with sa->sa_data */
336 			cp += sprintf(cp, " %x", *s);
337 		break;
338 	    }
339 	}
340 	return (line);
341 }
342 
343 /*
344  * Return the name of the network whose address is given.
345  * The address is assumed to be that of a net or subnet, not a host.
346  */
347 char *
348 netname(sa)
349 	struct sockaddr *sa;
350 {
351 	char *cp = 0;
352 	static char line[50];
353 	struct netent *np = 0;
354 	u_long net, mask;
355 	register u_long i;
356 	int subnetshift;
357 	char *ns_print();
358 
359 	switch (sa->sa_family) {
360 
361 	case AF_INET:
362 	    {	struct in_addr in;
363 		in = ((struct sockaddr_in *)sa)->sin_addr;
364 
365 		i = in.s_addr = ntohl(in.s_addr);
366 		if (in.s_addr == 0)
367 			cp = "default";
368 		else if (!nflag) {
369 			if (IN_CLASSA(i)) {
370 				mask = IN_CLASSA_NET;
371 				subnetshift = 8;
372 			} else if (IN_CLASSB(i)) {
373 				mask = IN_CLASSB_NET;
374 				subnetshift = 8;
375 			} else {
376 				mask = IN_CLASSC_NET;
377 				subnetshift = 4;
378 			}
379 			/*
380 			 * If there are more bits than the standard mask
381 			 * would suggest, subnets must be in use.
382 			 * Guess at the subnet mask, assuming reasonable
383 			 * width subnet fields.
384 			 */
385 			while (in.s_addr &~ mask)
386 				mask = (long)mask >> subnetshift;
387 			net = in.s_addr & mask;
388 			while ((mask & 1) == 0)
389 				mask >>= 1, net >>= 1;
390 			np = getnetbyaddr(net, AF_INET);
391 			if (np)
392 				cp = np->n_name;
393 		}
394 		if (cp)
395 			strcpy(line, cp);
396 		else if ((in.s_addr & 0xffffff) == 0)
397 			(void) sprintf(line, "%u", C(in.s_addr >> 24));
398 		else if ((in.s_addr & 0xffff) == 0)
399 			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
400 			    C(in.s_addr >> 16));
401 		else if ((in.s_addr & 0xff) == 0)
402 			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
403 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
404 		else
405 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
406 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
407 			    C(in.s_addr));
408 		break;
409 	    }
410 
411 	case AF_NS:
412 		return (ns_print((struct sockaddr_ns *)sa));
413 		break;
414 
415 	case AF_LINK:
416 		return (link_ntoa((struct sockaddr_dl *)sa));
417 
418 	case AF_ISO:
419 		(void) sprintf(line, "iso %s",
420 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
421 		break;
422 
423 	default:
424 	    {	u_short *s = (u_short *)sa->sa_data;
425 		u_short *slim = s + ((sa->sa_len + 1)>>1);
426 		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
427 
428 		while (s < slim)
429 			cp += sprintf(cp, " %x", *s++);
430 		break;
431 	    }
432 	}
433 	return (line);
434 }
435 
436 void
437 set_metric(value, key)
438 	char *value;
439 	int key;
440 {
441 	int flag = 0;
442 	u_long noval, *valp = &noval;
443 
444 	switch (key) {
445 #define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
446 	caseof(K_MTU, RTV_MTU, rmx_mtu);
447 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
448 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
449 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
450 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
451 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
452 	caseof(K_RTT, RTV_RTT, rmx_rtt);
453 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
454 	}
455 	rtm_inits |= flag;
456 	if (lockrest || locking)
457 		rt_metrics.rmx_locks |= flag;
458 	if (locking)
459 		locking = 0;
460 	*valp = atoi(value);
461 }
462 
463 void
464 newroute(argc, argv)
465 	int argc;
466 	register char **argv;
467 {
468 	char *cmd, *dest = "", *gateway = "", *err;
469 	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
470 	int key;
471 	struct hostent *hp = 0;
472 
473 	if (uid)
474 		quit("must be root to alter routing table");
475 	cmd = argv[0];
476 	if (*cmd != 'g')
477 		shutdown(s, 0); /* Don't want to read back our messages */
478 	while (--argc > 0) {
479 		if (**(++argv)== '-') {
480 			switch (key = keyword(1 + *argv)) {
481 			case K_LINK:
482 				af = AF_LINK;
483 				aflen = sizeof(struct sockaddr_dl);
484 				break;
485 			case K_OSI:
486 			case K_ISO:
487 				af = AF_ISO;
488 				aflen = sizeof(struct sockaddr_iso);
489 				break;
490 			case K_INET:
491 				af = AF_INET;
492 				aflen = sizeof(struct sockaddr_in);
493 				break;
494 			case K_X25:
495 				af = AF_CCITT;
496 				aflen = sizeof(struct sockaddr_x25);
497 				break;
498 			case K_SA:
499 				af = PF_ROUTE;
500 				aflen = sizeof(union sockunion);
501 				break;
502 			case K_XNS:
503 				af = AF_NS;
504 				aflen = sizeof(struct sockaddr_ns);
505 				break;
506 			case K_IFACE:
507 			case K_INTERFACE:
508 				iflag++;
509 			case K_NOSTATIC:
510 				flags &= ~RTF_STATIC;
511 				break;
512 			case K_LOCK:
513 				locking = 1;
514 				break;
515 			case K_LOCKREST:
516 				lockrest = 1;
517 				break;
518 			case K_HOST:
519 				forcehost++;
520 				break;
521 			case K_REJECT:
522 				flags |= RTF_REJECT;
523 				break;
524 			case K_PROTO1:
525 				flags |= RTF_PROTO1;
526 				break;
527 			case K_PROTO2:
528 				flags |= RTF_PROTO2;
529 				break;
530 			case K_CLONING:
531 				flags |= RTF_CLONING;
532 				break;
533 			case K_XRESOLVE:
534 				flags |= RTF_XRESOLVE;
535 				break;
536 			case K_STATIC:
537 				flags |= RTF_STATIC;
538 				break;
539 			case K_IFA:
540 				argc--;
541 				(void) getaddr(RTA_IFA, *++argv, 0);
542 				break;
543 			case K_IFP:
544 				argc--;
545 				(void) getaddr(RTA_IFP, *++argv, 0);
546 				break;
547 			case K_GENMASK:
548 				argc--;
549 				(void) getaddr(RTA_GENMASK, *++argv, 0);
550 				break;
551 			case K_GATEWAY:
552 				argc--;
553 				(void) getaddr(RTA_GATEWAY, *++argv, 0);
554 				break;
555 			case K_DST:
556 				argc--;
557 				ishost = getaddr(RTA_DST, *++argv, &hp);
558 				dest = *argv;
559 				break;
560 			case K_NETMASK:
561 				argc--;
562 				(void) getaddr(RTA_NETMASK, *++argv, 0);
563 				/* FALLTHROUGH */
564 			case K_NET:
565 				forcenet++;
566 				break;
567 			case K_MTU:
568 			case K_HOPCOUNT:
569 			case K_EXPIRE:
570 			case K_RECVPIPE:
571 			case K_SENDPIPE:
572 			case K_SSTHRESH:
573 			case K_RTT:
574 			case K_RTTVAR:
575 				argc--;
576 				set_metric(*++argv, key);
577 				break;
578 			default:
579 				usage(1+*argv);
580 			}
581 		} else {
582 			if ((rtm_addrs & RTA_DST) == 0) {
583 				dest = *argv;
584 				ishost = getaddr(RTA_DST, *argv, &hp);
585 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
586 				gateway = *argv;
587 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
588 			} else {
589 				int ret = atoi(*argv);
590 
591 				if (ret == 0) {
592 				    if (strcmp(*argv, "0") == 0)
593 				        printf("%s,%s",
594 					    "old usage of trailing 0",
595 					    "assuming route to if\n");
596 				    else
597 					usage(NULL);
598 				    iflag = 1;
599 				    continue;
600 				} else if (ret > 0 && ret < 10) {
601 				    printf("old usage of trailing digit, ");
602 				    printf("assuming route via gateway\n");
603 				    iflag = 0;
604 				    continue;
605 				}
606 				(void) getaddr(RTA_NETMASK, *argv, 0);
607 			}
608 		}
609 	}
610 	if (forcehost)
611 		ishost = 1;
612 	if (forcenet)
613 		ishost = 0;
614 	flags |= RTF_UP;
615 	if (ishost)
616 		flags |= RTF_HOST;
617 	if (iflag == 0)
618 		flags |= RTF_GATEWAY;
619 	for (attempts = 1; ; attempts++) {
620 		errno = 0;
621 		if ((ret = rtmsg(*cmd, flags)) == 0)
622 			break;
623 		if (errno != ENETUNREACH && errno != ESRCH)
624 			break;
625 		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
626 			hp->h_addr_list++;
627 			bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
628 			    hp->h_length);
629 		} else
630 			break;
631 	}
632 	if (*cmd == 'g')
633 		exit(0);
634 	oerrno = errno;
635 	(void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
636 	if (*gateway) {
637 		(void) printf(": gateway %s", gateway);
638 		if (attempts > 1 && ret == 0 && af == AF_INET)
639 		    (void) printf(" (%s)",
640 			inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
641 	}
642 	if (ret == 0)
643 		(void) printf("\n");
644 	else {
645 		switch (oerrno) {
646 		case ESRCH:
647 			err = "not in table";
648 			break;
649 		case EBUSY:
650 			err = "entry in use";
651 			break;
652 		case ENOBUFS:
653 			err = "routing table overflow";
654 			break;
655 		default:
656 			err = strerror(oerrno);
657 			break;
658 		}
659 		(void) printf(": %s\n", err);
660 	}
661 }
662 
663 void
664 inet_makenetandmask(net, sin)
665 	u_long net;
666 	register struct sockaddr_in *sin;
667 {
668 	u_long addr, mask = 0;
669 	register char *cp;
670 
671 	rtm_addrs |= RTA_NETMASK;
672 	if (net == 0)
673 		mask = addr = 0;
674 	else if (net < 128) {
675 		addr = net << IN_CLASSA_NSHIFT;
676 		mask = IN_CLASSA_NET;
677 	} else if (net < 65536) {
678 		addr = net << IN_CLASSB_NSHIFT;
679 		mask = IN_CLASSB_NET;
680 	} else if (net < 16777216L) {
681 		addr = net << IN_CLASSC_NSHIFT;
682 		mask = IN_CLASSC_NET;
683 	} else {
684 		addr = net;
685 		if ((addr & IN_CLASSA_HOST) == 0)
686 			mask =  IN_CLASSA_NET;
687 		else if ((addr & IN_CLASSB_HOST) == 0)
688 			mask =  IN_CLASSB_NET;
689 		else if ((addr & IN_CLASSC_HOST) == 0)
690 			mask =  IN_CLASSC_NET;
691 		else
692 			mask = -1;
693 	}
694 	sin->sin_addr.s_addr = htonl(addr);
695 	sin = &so_mask.sin;
696 	sin->sin_addr.s_addr = htonl(mask);
697 	sin->sin_len = 0;
698 	sin->sin_family = 0;
699 	cp = (char *)(&sin->sin_addr + 1);
700 	while (*--cp == 0 && cp > (char *)sin)
701 		;
702 	sin->sin_len = 1 + cp - (char *)sin;
703 }
704 
705 /*
706  * Interpret an argument as a network address of some kind,
707  * returning 1 if a host address, 0 if a network address.
708  */
709 int
710 getaddr(which, s, hpp)
711 	int which;
712 	char *s;
713 	struct hostent **hpp;
714 {
715 	register sup su;
716 	struct ns_addr ns_addr();
717 	struct iso_addr *iso_addr();
718 	struct hostent *hp;
719 	struct netent *np;
720 	u_long val;
721 
722 	if (af == 0) {
723 		af = AF_INET;
724 		aflen = sizeof(struct sockaddr_in);
725 	}
726 	rtm_addrs |= which;
727 	switch (which) {
728 	case RTA_DST:
729 		su = &so_dst;
730 		su->sa.sa_family = af;
731 		break;
732 	case RTA_GATEWAY:
733 		su = &so_gate;
734 		su->sa.sa_family = af;
735 		break;
736 	case RTA_NETMASK:
737 		su = &so_mask;
738 		break;
739 	case RTA_GENMASK:
740 		su = &so_genmask;
741 		break;
742 	case RTA_IFP:
743 		su = &so_ifp;
744 		su->sa.sa_family = af;
745 		break;
746 	case RTA_IFA:
747 		su = &so_ifa;
748 		su->sa.sa_family = af;
749 		break;
750 	default:
751 		usage("Internal Error");
752 		/*NOTREACHED*/
753 	}
754 	su->sa.sa_len = aflen;
755 	if (strcmp(s, "default") == 0) {
756 		switch (which) {
757 		case RTA_DST:
758 			forcenet++;
759 			(void) getaddr(RTA_NETMASK, s, 0);
760 			break;
761 		case RTA_NETMASK:
762 		case RTA_GENMASK:
763 			su->sa.sa_len = 0;
764 		}
765 		return (0);
766 	}
767 	switch (af) {
768 	case AF_NS:
769 		if (which == RTA_DST) {
770 			extern short ns_bh[3];
771 			struct sockaddr_ns *sms = &(so_mask.sns);
772 			bzero((char *)sms, sizeof(*sms));
773 			sms->sns_family = 0;
774 			sms->sns_len = 6;
775 			sms->sns_addr.x_net = *(union ns_net *)ns_bh;
776 			rtm_addrs |= RTA_NETMASK;
777 		}
778 		su->sns.sns_addr = ns_addr(s);
779 		return (!ns_nullhost(su->sns.sns_addr));
780 
781 	case AF_OSI:
782 		su->siso.siso_addr = *iso_addr(s);
783 		if (which == RTA_NETMASK || which == RTA_GENMASK) {
784 			register char *cp = (char *)TSEL(&su->siso);
785 			su->siso.siso_nlen = 0;
786 			do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
787 			su->siso.siso_len = 1 + cp - (char *)su;
788 		}
789 		return (1);
790 
791 	case AF_LINK:
792 		link_addr(s, &su->sdl);
793 		return (1);
794 
795 	case AF_CCITT:
796 		ccitt_addr(s, &su->sx25);
797 		return (which == RTA_DST ? x25_makemask() : 1);
798 
799 	case PF_ROUTE:
800 		su->sa.sa_len = sizeof(*su);
801 		sockaddr(s, &su->sa);
802 		return (1);
803 
804 	case AF_INET:
805 	default:
806 		break;
807 	}
808 
809 	if (hpp == NULL)
810 		hpp = &hp;
811 	*hpp = NULL;
812 	if (((val = inet_addr(s)) != -1) &&
813 	    (which != RTA_DST || forcenet == 0)) {
814 		su->sin.sin_addr.s_addr = val;
815 		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
816 			return (1);
817 		else {
818 			val = ntohl(val);
819 			goto netdone;
820 		}
821 	}
822 	if ((val = inet_network(s)) != -1 ||
823 	    ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
824 netdone:
825 		if (which == RTA_DST)
826 			inet_makenetandmask(val, &su->sin);
827 		return (0);
828 	}
829 	hp = gethostbyname(s);
830 	if (hp) {
831 		*hpp = hp;
832 		su->sin.sin_family = hp->h_addrtype;
833 		bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
834 		return (1);
835 	}
836 	(void) fprintf(stderr, "%s: bad value\n", s);
837 	exit(1);
838 }
839 
840 x25_makemask()
841 {
842 	register char *cp;
843 
844 	if ((rtm_addrs & RTA_NETMASK) == 0) {
845 		rtm_addrs |= RTA_NETMASK;
846 		for (cp = (char *)&so_mask.sx25.x25_net;
847 		     cp < &so_mask.sx25.x25_opts.op_flags; cp++)
848 			*cp = -1;
849 		so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
850 	}
851 	return 0;
852 }
853 
854 short ns_nullh[] = {0,0,0};
855 short ns_bh[] = {-1,-1,-1};
856 
857 char *
858 ns_print(sns)
859 	struct sockaddr_ns *sns;
860 {
861 	struct ns_addr work;
862 	union { union ns_net net_e; u_long long_e; } net;
863 	u_short port;
864 	static char mybuf[50], cport[10], chost[25];
865 	char *host = "";
866 	register char *p;
867 	register u_char *q;
868 
869 	work = sns->sns_addr;
870 	port = ntohs(work.x_port);
871 	work.x_port = 0;
872 	net.net_e  = work.x_net;
873 	if (ns_nullhost(work) && net.long_e == 0) {
874 		if (!port)
875 			return ("*.*");
876 		(void) sprintf(mybuf, "*.%XH", port);
877 		return (mybuf);
878 	}
879 
880 	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
881 		host = "any";
882 	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
883 		host = "*";
884 	else {
885 		q = work.x_host.c_host;
886 		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
887 			q[0], q[1], q[2], q[3], q[4], q[5]);
888 		for (p = chost; *p == '0' && p < chost + 12; p++)
889 			/* void */;
890 		host = p;
891 	}
892 	if (port)
893 		(void) sprintf(cport, ".%XH", htons(port));
894 	else
895 		*cport = 0;
896 
897 	(void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
898 	return (mybuf);
899 }
900 
901 void
902 interfaces()
903 {
904 	int needed, rlen, af;
905 	char *buf, *lim, *next;
906 	register struct rt_msghdr *rtm;
907 
908 	if ((needed = getkerninfo(KINFO_RT_IFLIST, 0, 0, 0)) < 0)
909 		quit("route-getkerninfo-estimate");
910 	if ((buf = malloc(needed)) == NULL)
911 		quit("malloc");
912 	if ((rlen = getkerninfo(KINFO_RT_IFLIST, buf, &needed, 0)) < 0)
913 		quit("actual retrieval of interface table");
914 	lim = buf + rlen;
915 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
916 		rtm = (struct rt_msghdr *)next;
917 		print_rtmsg(rtm, rtm->rtm_msglen);
918 	}
919 }
920 
921 void
922 monitor()
923 {
924 	int n;
925 	char msg[2048];
926 
927 	verbose = 1;
928 	if (debugonly) {
929 		interfaces();
930 		exit(0);
931 	}
932 	for(;;) {
933 		n = read(s, msg, 2048);
934 		(void) printf("got message of size %d\n", n);
935 		print_rtmsg((struct rt_msghdr *)msg, n);
936 	}
937 }
938 
939 struct {
940 	struct	rt_msghdr m_rtm;
941 	char	m_space[512];
942 } m_rtmsg;
943 
944 int
945 rtmsg(cmd, flags)
946 	int cmd, flags;
947 {
948 	static int seq;
949 	int rlen;
950 	register char *cp = m_rtmsg.m_space;
951 	register int l;
952 
953 #define NEXTADDR(w, u) \
954 	if (rtm_addrs & (w)) {\
955 	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
956 	    if (verbose) sodump(&(u),"u");\
957 	}
958 
959 	errno = 0;
960 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
961 	if (cmd == 'a')
962 		cmd = RTM_ADD;
963 	else if (cmd == 'c')
964 		cmd = RTM_CHANGE;
965 	else if (cmd == 'g') {
966 		cmd = RTM_GET;
967 		if (so_ifp.sa.sa_family == 0) {
968 			so_ifp.sa.sa_family == AF_LINK;
969 			so_ifp.sa.sa_len == sizeof(struct sockaddr_dl);
970 			rtm_addrs |= RTA_IFP;
971 		}
972 	} else
973 		cmd = RTM_DELETE;
974 #define rtm m_rtmsg.m_rtm
975 	rtm.rtm_type = cmd;
976 	rtm.rtm_flags = flags;
977 	rtm.rtm_version = RTM_VERSION;
978 	rtm.rtm_seq = ++seq;
979 	rtm.rtm_addrs = rtm_addrs;
980 	rtm.rtm_rmx = rt_metrics;
981 	rtm.rtm_inits = rtm_inits;
982 
983 	if (rtm_addrs & RTA_NETMASK)
984 		mask_addr();
985 	NEXTADDR(RTA_DST, so_dst);
986 	NEXTADDR(RTA_GATEWAY, so_gate);
987 	NEXTADDR(RTA_NETMASK, so_mask);
988 	NEXTADDR(RTA_GENMASK, so_genmask);
989 	NEXTADDR(RTA_IFP, so_ifp);
990 	NEXTADDR(RTA_IFA, so_ifa);
991 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
992 	if (verbose)
993 		print_rtmsg(&rtm, l);
994 	if (debugonly)
995 		return (0);
996 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
997 		perror("writing to routing socket");
998 		return (-1);
999 	}
1000 	if (cmd == RTM_GET) {
1001 		do {
1002 			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1003 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1004 		if (l < 0)
1005 			(void) fprintf(stderr,
1006 			    "route: read from routing socket: %s\n",
1007 			    strerror(errno));
1008 		else
1009 			print_getmsg(&rtm, l);
1010 	}
1011 #undef rtm
1012 	return (0);
1013 }
1014 
1015 mask_addr()
1016 {
1017 	int olen = so_mask.sa.sa_len;
1018 	register char *cp1 = olen + (char *)&so_mask, *cp2;
1019 
1020 	for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1021 		if (*--cp1 != 0) {
1022 			so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1023 			break;
1024 		}
1025 	if ((rtm_addrs & RTA_DST) == 0)
1026 		return;
1027 	switch (so_dst.sa.sa_family) {
1028 	case AF_NS:
1029 	case AF_INET:
1030 	case AF_CCITT:
1031 	case 0:
1032 		return;
1033 	case AF_ISO:
1034 		olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6);
1035 		break;
1036 	}
1037 	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1038 	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1039 	while (cp2 > cp1)
1040 		*--cp2 = 0;
1041 	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1042 	while (cp1 > so_dst.sa.sa_data)
1043 		*--cp1 &= *--cp2;
1044 	switch (so_dst.sa.sa_family) {
1045 	case AF_ISO:
1046 		so_dst.siso.siso_nlen = olen;
1047 		break;
1048 	}
1049 }
1050 
1051 char *msgtypes[] = {
1052 	"",
1053 	"RTM_ADD: Add Route",
1054 	"RTM_DELETE: Delete Route",
1055 	"RTM_CHANGE: Change Metrics or flags",
1056 	"RTM_GET: Report Metrics",
1057 	"RTM_LOSING: Kernel Suspects Partitioning",
1058 	"RTM_REDIRECT: Told to use different route",
1059 	"RTM_MISS: Lookup failed on this address",
1060 	"RTM_LOCK: fix specified metrics",
1061 	"RTM_OLDADD: caused by SIOCADDRT",
1062 	"RTM_OLDDEL: caused by SIOCDELRT",
1063 	"RTM_RESOLVE: Route created by cloning",
1064 	"RTM_NEWADDR: address being added to iface",
1065 	"RTM_DELADDR: address being removed from iface",
1066 	"RTM_IFINFO: iface status change",
1067 	0,
1068 };
1069 
1070 char metricnames[] =
1071 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1072 char routeflags[] =
1073 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\017PROTO2\020PROTO1";
1074 char ifnetflags[] =
1075 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2";
1076 char addrnames[] =
1077 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1078 
1079 void
1080 print_rtmsg(rtm, msglen)
1081 	register struct rt_msghdr *rtm;
1082 	int msglen;
1083 {
1084 	struct if_msghdr *ifm;
1085 	struct ifa_msghdr *ifam;
1086 
1087 	if (verbose == 0)
1088 		return;
1089 	if (rtm->rtm_version != RTM_VERSION) {
1090 		(void) printf("routing message version %d not understood\n",
1091 		    rtm->rtm_version);
1092 		return;
1093 	}
1094 	(void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
1095 	switch (rtm->rtm_type) {
1096 	case RTM_IFINFO:
1097 		ifm = (struct if_msghdr *)rtm;
1098 		(void) printf("if# %d, flags:", ifm->ifm_index);
1099 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1100 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1101 		break;
1102 	case RTM_NEWADDR:
1103 	case RTM_DELADDR:
1104 		ifam = (struct ifa_msghdr *)rtm;
1105 		(void) printf("metric %d, flags:", ifam->ifam_metric);
1106 		bprintf(stdout, ifam->ifam_flags, routeflags);
1107 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1108 		break;
1109 	default:
1110 		(void) printf("pid: %d, seq %d, errno %d, flags:",
1111 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1112 		bprintf(stdout, rtm->rtm_flags, routeflags);
1113 		pmsg_common(rtm);
1114 	}
1115 }
1116 
1117 void
1118 print_getmsg(rtm, msglen)
1119 	register struct rt_msghdr *rtm;
1120 	int msglen;
1121 {
1122 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1123 	struct sockaddr_dl *ifp = NULL;
1124 	register struct sockaddr *sa;
1125 	register char *cp;
1126 	register int i;
1127 
1128 	(void) printf("   route to: %s\n", routename(&so_dst));
1129 	if (rtm->rtm_version != RTM_VERSION) {
1130 		(void)fprintf(stderr,
1131 		    "routing message version %d not understood\n",
1132 		    rtm->rtm_version);
1133 		return;
1134 	}
1135 	if (rtm->rtm_msglen > msglen) {
1136 		(void)fprintf(stderr,
1137 		    "message length mismatch, in packet %d, returned %d\n",
1138 		    rtm->rtm_msglen, msglen);
1139 	}
1140 	if (rtm->rtm_errno)  {
1141 		(void) fprintf(stderr, "RTM_GET: %s (errno %d)\n",
1142 		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1143 		return;
1144 	}
1145 	cp = ((char *)(rtm + 1));
1146 	if (rtm->rtm_addrs)
1147 		for (i = 1; i; i <<= 1)
1148 			if (i & rtm->rtm_addrs) {
1149 				sa = (struct sockaddr *)cp;
1150 				switch (i) {
1151 				case RTA_DST:
1152 					dst = sa;
1153 					break;
1154 				case RTA_GATEWAY:
1155 					gate = sa;
1156 					break;
1157 				case RTA_NETMASK:
1158 					mask = sa;
1159 					break;
1160 				case RTA_IFP:
1161 					if (sa->sa_family == AF_LINK &&
1162 					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1163 						ifp = (struct sockaddr_dl *)sa;
1164 					break;
1165 				}
1166 				ADVANCE(cp, sa);
1167 			}
1168 	if (dst && mask)
1169 		mask->sa_family = dst->sa_family;	/* XXX */
1170 	if (dst)
1171 		(void)printf("destination: %s\n", routename(dst));
1172 	if (mask) {
1173 		int savenflag = nflag;
1174 
1175 		nflag = 1;
1176 		(void)printf("       mask: %s\n", routename(mask));
1177 		nflag = savenflag;
1178 	}
1179 	if (gate && rtm->rtm_flags & RTF_GATEWAY)
1180 		(void)printf("    gateway: %s\n", routename(gate));
1181 	if (ifp)
1182 		(void)printf("  interface: %.*s\n",
1183 		    ifp->sdl_nlen, ifp->sdl_data);
1184 	(void)printf("      flags: ");
1185 	bprintf(stdout, rtm->rtm_flags, routeflags);
1186 
1187 #define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1188 #define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1189 
1190 	(void) printf("\n%s\n", "\
1191  recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
1192 	printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1193 	printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1194 	printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1195 	printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1196 	printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1197 	printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1198 	printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1199 	if (rtm->rtm_rmx.rmx_expire)
1200 		rtm->rtm_rmx.rmx_expire -= time(0);
1201 	printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1202 #undef lock
1203 #undef msec
1204 #define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1205 	if (verbose)
1206 		pmsg_common(rtm);
1207 	else if (rtm->rtm_addrs &~ RTA_IGN) {
1208 		(void) printf("sockaddrs: ");
1209 		bprintf(stdout, rtm->rtm_addrs, addrnames);
1210 		putchar('\n');
1211 	}
1212 #undef	RTA_IGN
1213 }
1214 
1215 void
1216 pmsg_common(rtm)
1217 	register struct rt_msghdr *rtm;
1218 {
1219 	(void) printf("\nlocks: ");
1220 	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1221 	(void) printf(" inits: ");
1222 	bprintf(stdout, rtm->rtm_inits, metricnames);
1223 	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1224 }
1225 
1226 void
1227 pmsg_addrs(cp, addrs)
1228 	char	*cp;
1229 	int	addrs;
1230 {
1231 	register struct sockaddr *sa;
1232 	int i;
1233 
1234 	if (addrs == 0)
1235 		return;
1236 	(void) printf("\nsockaddrs: ");
1237 	bprintf(stdout, addrs, addrnames);
1238 	(void) putchar('\n');
1239 	for (i = 1; i; i <<= 1)
1240 		if (i & addrs) {
1241 			sa = (struct sockaddr *)cp;
1242 			(void) printf(" %s", routename(sa));
1243 			ADVANCE(cp, sa);
1244 		}
1245 	(void) putchar('\n');
1246 	(void) fflush(stdout);
1247 }
1248 
1249 void
1250 bprintf(fp, b, s)
1251 	register FILE *fp;
1252 	register int b;
1253 	register u_char *s;
1254 {
1255 	register int i;
1256 	int gotsome = 0;
1257 
1258 	if (b == 0)
1259 		return;
1260 	while (i = *s++) {
1261 		if (b & (1 << (i-1))) {
1262 			if (gotsome == 0)
1263 				i = '<';
1264 			else
1265 				i = ',';
1266 			(void) putc(i, fp);
1267 			gotsome = 1;
1268 			for (; (i = *s) > 32; s++)
1269 				(void) putc(i, fp);
1270 		} else
1271 			while (*s > 32)
1272 				s++;
1273 	}
1274 	if (gotsome)
1275 		(void) putc('>', fp);
1276 }
1277 
1278 int
1279 keyword(cp)
1280 	char *cp;
1281 {
1282 	register struct keytab *kt = keywords;
1283 
1284 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1285 		kt++;
1286 	return kt->kt_i;
1287 }
1288 
1289 void
1290 sodump(su, which)
1291 	register sup su;
1292 	char *which;
1293 {
1294 	switch (su->sa.sa_family) {
1295 	case AF_LINK:
1296 		(void) printf("%s: link %s; ",
1297 		    which, link_ntoa(&su->sdl));
1298 		break;
1299 	case AF_ISO:
1300 		(void) printf("%s: iso %s; ",
1301 		    which, iso_ntoa(&su->siso.siso_addr));
1302 		break;
1303 	case AF_INET:
1304 		(void) printf("%s: inet %s; ",
1305 		    which, inet_ntoa(su->sin.sin_addr));
1306 		break;
1307 	case AF_NS:
1308 		(void) printf("%s: xns %s; ",
1309 		    which, ns_ntoa(su->sns.sns_addr));
1310 		break;
1311 	}
1312 	(void) fflush(stdout);
1313 }
1314 
1315 /* States*/
1316 #define VIRGIN	0
1317 #define GOTONE	1
1318 #define GOTTWO	2
1319 /* Inputs */
1320 #define	DIGIT	(4*0)
1321 #define	END	(4*1)
1322 #define DELIM	(4*2)
1323 
1324 void
1325 sockaddr(addr, sa)
1326 	register char *addr;
1327 	register struct sockaddr *sa;
1328 {
1329 	register char *cp = (char *)sa;
1330 	int size = sa->sa_len;
1331 	char *cplim = cp + size;
1332 	register int byte = 0, state = VIRGIN, new;
1333 
1334 	bzero(cp, size);
1335 	cp++;
1336 	do {
1337 		if ((*addr >= '0') && (*addr <= '9')) {
1338 			new = *addr - '0';
1339 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
1340 			new = *addr - 'a' + 10;
1341 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
1342 			new = *addr - 'A' + 10;
1343 		} else if (*addr == 0)
1344 			state |= END;
1345 		else
1346 			state |= DELIM;
1347 		addr++;
1348 		switch (state /* | INPUT */) {
1349 		case GOTTWO | DIGIT:
1350 			*cp++ = byte; /*FALLTHROUGH*/
1351 		case VIRGIN | DIGIT:
1352 			state = GOTONE; byte = new; continue;
1353 		case GOTONE | DIGIT:
1354 			state = GOTTWO; byte = new + (byte << 4); continue;
1355 		default: /* | DELIM */
1356 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
1357 		case GOTONE | END:
1358 		case GOTTWO | END:
1359 			*cp++ = byte; /* FALLTHROUGH */
1360 		case VIRGIN | END:
1361 			break;
1362 		}
1363 		break;
1364 	} while (cp < cplim);
1365 	sa->sa_len = cp - (char *)sa;
1366 }
1367