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