1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * Routing Table Management Daemon 39 */ 40 #include "defs.h" 41 42 boolean_t install = _B_TRUE; /* update kernel routing table */ 43 struct rthash *net_hashes[IPV6_ABITS + 1]; 44 45 /* 46 * Size of routing socket message used by in.ripngd which includes the header, 47 * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6) 48 * plus space for the RTA_IFP (a sockaddr_dl). 49 */ 50 #define RIPNG_RTM_MSGLEN sizeof (struct rt_msghdr) + \ 51 sizeof (struct sockaddr_in6) + \ 52 sizeof (struct sockaddr_in6) + \ 53 sizeof (struct sockaddr_in6) + \ 54 sizeof (struct sockaddr_dl) 55 56 static int rtmseq; /* rtm_seq sequence number */ 57 static int rtsock; /* Routing socket */ 58 static struct rt_msghdr *rt_msg; /* Routing socket message */ 59 static struct sockaddr_in6 *rta_dst; /* RTA_DST sockaddr */ 60 static struct sockaddr_in6 *rta_gateway; /* RTA_GATEWAY sockaddr */ 61 static struct sockaddr_in6 *rta_netmask; /* RTA_NETMASK sockaddr */ 62 static struct sockaddr_dl *rta_ifp; /* RTA_IFP sockaddr */ 63 64 /* simulate vax insque and remque instructions. */ 65 66 typedef struct vq { 67 caddr_t fwd, back; 68 } vq_t; 69 70 #define insque(e, p) ((vq_t *)(e))->back = (caddr_t)(p); \ 71 ((vq_t *)(e))->fwd = \ 72 (caddr_t)((vq_t *)((vq_t *)(p))->fwd); \ 73 ((vq_t *)((vq_t *)(p))->fwd)->back = (caddr_t)(e); \ 74 ((vq_t *)(p))->fwd = (caddr_t)(e); 75 76 #define remque(e) ((vq_t *)((vq_t *)(e))->back)->fwd = \ 77 (caddr_t)((vq_t *)(e))->fwd; \ 78 ((vq_t *)((vq_t *)(e))->fwd)->back = \ 79 (caddr_t)((vq_t *)(e))->back; \ 80 ((vq_t *)(e))->fwd = NULL; \ 81 ((vq_t *)(e))->back = NULL; 82 83 static void 84 log_change(int level, struct rt_entry *orig, struct rt_entry *new) 85 { 86 char buf1[INET6_ADDRSTRLEN]; 87 char buf2[INET6_ADDRSTRLEN]; 88 char buf3[INET6_ADDRSTRLEN]; 89 90 (void) inet_ntop(AF_INET6, (void *) &new->rt_dst, buf1, sizeof (buf1)); 91 (void) inet_ntop(AF_INET6, (void *) &orig->rt_router, buf2, 92 sizeof (buf2)); 93 (void) inet_ntop(AF_INET6, (void *) &new->rt_router, buf3, 94 sizeof (buf3)); 95 96 syslog(level, "\tdst %s from gw %s if %s to gw %s if %s metric %d", 97 buf1, buf2, 98 (orig->rt_ifp != NULL && orig->rt_ifp->int_name != NULL) ? 99 orig->rt_ifp->int_name : "(noname)", 100 buf3, 101 (new->rt_ifp != NULL && new->rt_ifp->int_name != NULL) ? 102 new->rt_ifp->int_name : "(noname)", new->rt_metric); 103 } 104 105 static void 106 log_single(int level, struct rt_entry *rt) 107 { 108 char buf1[INET6_ADDRSTRLEN]; 109 char buf2[INET6_ADDRSTRLEN]; 110 111 (void) inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1)); 112 (void) inet_ntop(AF_INET6, (void *)&rt->rt_router, buf2, sizeof (buf2)); 113 114 syslog(level, "\tdst %s gw %s if %s metric %d", 115 buf1, buf2, 116 (rt->rt_ifp != NULL && rt->rt_ifp->int_name != NULL) ? 117 rt->rt_ifp->int_name : "(noname)", 118 rt->rt_metric); 119 } 120 121 /* 122 * Computes a hash by XOR-ing the (up to sixteen) octets that make up an IPv6 123 * address. This function assumes that that there are no one-bits in the 124 * address beyond the prefix length. 125 */ 126 static uint8_t 127 rthash(struct in6_addr *dst, int prefix_length) 128 { 129 uint8_t val = 0; 130 int i; 131 132 for (i = 0; prefix_length > 0; prefix_length -= 8, i++) 133 val ^= dst->s6_addr[i]; 134 return (val); 135 } 136 137 /* 138 * Given a prefix length, fill in the struct in6_addr representing an IPv6 139 * netmask. 140 */ 141 static void 142 rtmask_to_bits(uint_t prefix_length, struct in6_addr *prefix) 143 { 144 uint_t mask = 0xff; 145 int i; 146 147 bzero((caddr_t)prefix, sizeof (struct in6_addr)); 148 for (i = 0; prefix_length >= 8; prefix_length -= 8, i++) 149 prefix->s6_addr[i] = 0xff; 150 mask = (mask << (8 - prefix_length)); 151 if (mask != 0) 152 prefix->s6_addr[i] = mask; 153 } 154 155 void 156 rtcreate_prefix(struct in6_addr *p1, struct in6_addr *dst, int bits) 157 { 158 uchar_t mask; 159 int j; 160 161 for (j = 0; bits >= 8; bits -= 8, j++) 162 dst->s6_addr[j] = p1->s6_addr[j]; 163 164 if (bits != 0) { 165 mask = 0xff << (8 - bits); 166 dst->s6_addr[j] = p1->s6_addr[j] & mask; 167 j++; 168 } 169 170 for (; j < 16; j++) 171 dst->s6_addr[j] = 0; 172 } 173 174 /* 175 * Lookup dst in the tables for an exact match. 176 */ 177 struct rt_entry * 178 rtlookup(struct in6_addr *dst, int prefix_length) 179 { 180 struct rt_entry *rt; 181 struct rthash *rh; 182 uint_t hash; 183 184 if (net_hashes[prefix_length] == NULL) 185 return (NULL); 186 187 hash = rthash(dst, prefix_length); 188 189 rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK]; 190 191 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { 192 if (rt->rt_hash != hash) 193 continue; 194 if (IN6_ARE_ADDR_EQUAL(&rt->rt_dst, dst) && 195 rt->rt_prefix_length == prefix_length) 196 return (rt); 197 } 198 return (NULL); 199 } 200 201 /* 202 * Given an IPv6 prefix (destination and prefix length), a gateway, an 203 * interface name and route flags, send down the requested command returning 204 * the return value and errno (in the case of error) from the write() on the 205 * routing socket. 206 */ 207 static int 208 rtcmd(uchar_t type, struct in6_addr *dst, struct in6_addr *gateway, 209 uint_t prefix_length, char *name, int flags) 210 { 211 int rlen; 212 213 rta_ifp->sdl_index = if_nametoindex(name); 214 if (rta_ifp->sdl_index == 0) 215 return (-1); 216 217 rta_dst->sin6_addr = *dst; 218 rta_gateway->sin6_addr = *gateway; 219 rtmask_to_bits(prefix_length, &rta_netmask->sin6_addr); 220 221 rt_msg->rtm_type = type; 222 rt_msg->rtm_flags = flags; 223 rt_msg->rtm_seq = ++rtmseq; 224 rlen = write(rtsock, rt_msg, RIPNG_RTM_MSGLEN); 225 if (rlen >= 0 && rlen < RIPNG_RTM_MSGLEN) { 226 syslog(LOG_ERR, 227 "rtcmd: write to routing socket got only %d for rlen\n", 228 rlen); 229 } 230 return (rlen); 231 } 232 233 void 234 rtadd(struct in6_addr *dst, struct in6_addr *gate, int prefix_length, 235 int metric, int tag, boolean_t ifroute, struct interface *ifp) 236 { 237 struct rt_entry *rt; 238 struct rthash *rh; 239 uint_t hash; 240 struct in6_addr pdst; 241 int rlen; 242 243 if (metric >= HOPCNT_INFINITY) 244 return; 245 246 if (net_hashes[prefix_length] == NULL) { 247 struct rthash *trh; 248 249 rh = (struct rthash *) 250 calloc(ROUTEHASHSIZ, sizeof (struct rt_entry)); 251 if (rh == NULL) 252 return; 253 for (trh = rh; trh < &rh[ROUTEHASHSIZ]; trh++) 254 trh->rt_forw = trh->rt_back = (struct rt_entry *)trh; 255 net_hashes[prefix_length] = rh; 256 } 257 rtcreate_prefix(dst, &pdst, prefix_length); 258 259 hash = rthash(&pdst, prefix_length); 260 rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK]; 261 rt = (struct rt_entry *)malloc(sizeof (*rt)); 262 if (rt == NULL) { 263 /* 264 * In the event of an allocation failure, log the error and 265 * continue since on the next update another attempt will be 266 * made. 267 */ 268 syslog(LOG_ERR, "rtadd: malloc: %m"); 269 return; 270 } 271 rt->rt_hash = hash; 272 rt->rt_dst = pdst; 273 rt->rt_prefix_length = prefix_length; 274 rt->rt_router = *gate; 275 rt->rt_metric = metric; 276 rt->rt_tag = tag; 277 rt->rt_timer = 0; 278 rt->rt_flags = RTF_UP; 279 if (prefix_length == IPV6_ABITS) 280 rt->rt_flags |= RTF_HOST; 281 rt->rt_state = RTS_CHANGED; 282 if (ifroute) { 283 rt->rt_state |= RTS_INTERFACE; 284 if (ifp->int_flags & RIP6_IFF_PRIVATE) 285 rt->rt_state |= RTS_PRIVATE; 286 } else { 287 rt->rt_flags |= RTF_GATEWAY; 288 } 289 rt->rt_ifp = ifp; 290 291 insque(rt, rh); 292 TRACE_ACTION("ADD", rt); 293 /* 294 * If the RTM_ADD fails because the gateway is unreachable 295 * from this host, discard the entry. This should never 296 * happen. 297 */ 298 if (install && (rt->rt_state & RTS_INTERFACE) == 0) { 299 rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router, 300 prefix_length, ifp->int_name, rt->rt_flags); 301 if (rlen < 0) { 302 if (errno != EEXIST) { 303 syslog(LOG_ERR, "rtadd: RTM_ADD: %m"); 304 log_single(LOG_ERR, rt); 305 } 306 if (errno == ENETUNREACH) { 307 TRACE_ACTION("DELETE", rt); 308 remque(rt); 309 free((char *)rt); 310 } 311 } else if (rlen < RIPNG_RTM_MSGLEN) { 312 log_single(LOG_ERR, rt); 313 } 314 } 315 } 316 317 /* 318 * Handle the case when the metric changes but the gateway is the same (or the 319 * interface index associated with the gateway changes), or when both gateway 320 * and metric changes, or when only the gateway changes but the existing route 321 * is more than one-half of EXPIRE_TIME in age. Note that routes with metric >= 322 * HOPCNT_INFINITY are not in the kernel. 323 */ 324 void 325 rtchange(struct rt_entry *rt, struct in6_addr *gate, short metric, 326 struct interface *ifp) 327 { 328 boolean_t dokern = _B_FALSE; 329 boolean_t dokerndelete; 330 boolean_t metricchanged = _B_FALSE; 331 int oldmetric; 332 struct rt_entry oldroute; 333 int rlen; 334 335 if (metric >= HOPCNT_INFINITY) { 336 rtdown(rt); 337 return; 338 } 339 340 if (!IN6_ARE_ADDR_EQUAL(&rt->rt_router, gate) || rt->rt_ifp != ifp) 341 dokern = _B_TRUE; 342 oldmetric = rt->rt_metric; 343 if (oldmetric >= HOPCNT_INFINITY) 344 dokerndelete = _B_FALSE; 345 else 346 dokerndelete = dokern; 347 if (metric != rt->rt_metric) 348 metricchanged = _B_TRUE; 349 rt->rt_timer = 0; 350 if (dokern || metricchanged) { 351 TRACE_ACTION("CHANGE FROM", rt); 352 if ((rt->rt_state & RTS_INTERFACE) && metric != 0) { 353 rt->rt_state &= ~RTS_INTERFACE; 354 if (rt->rt_ifp != NULL) { 355 syslog(LOG_ERR, 356 "rtchange: changing route from " 357 "interface %s (timed out)", 358 (rt->rt_ifp->int_name != NULL) ? 359 rt->rt_ifp->int_name : "(noname)"); 360 } else { 361 syslog(LOG_ERR, 362 "rtchange: " 363 "changing route no interface for route"); 364 } 365 } 366 if (dokern) { 367 oldroute = *rt; 368 rt->rt_router = *gate; 369 rt->rt_ifp = ifp; 370 } 371 rt->rt_metric = metric; 372 if (!(rt->rt_state & RTS_INTERFACE)) 373 rt->rt_flags |= RTF_GATEWAY; 374 else 375 rt->rt_flags &= ~RTF_GATEWAY; 376 rt->rt_state |= RTS_CHANGED; 377 TRACE_ACTION("CHANGE TO", rt); 378 } 379 if (install && (rt->rt_state & RTS_INTERFACE) == 0) { 380 if (dokerndelete) { 381 rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router, 382 rt->rt_prefix_length, rt->rt_ifp->int_name, 383 rt->rt_flags); 384 if (rlen < 0) { 385 if (errno != EEXIST) { 386 syslog(LOG_ERR, 387 "rtchange: RTM_ADD: %m"); 388 log_change(LOG_ERR, rt, 389 (struct rt_entry *)&oldroute); 390 } 391 } else if (rlen < RIPNG_RTM_MSGLEN) { 392 log_change(LOG_ERR, rt, 393 (struct rt_entry *)&oldroute); 394 } 395 396 rlen = rtcmd(RTM_DELETE, &oldroute.rt_dst, 397 &oldroute.rt_router, oldroute.rt_prefix_length, 398 oldroute.rt_ifp->int_name, oldroute.rt_flags); 399 if (rlen < 0) { 400 syslog(LOG_ERR, "rtchange: RTM_DELETE: %m"); 401 log_change(LOG_ERR, rt, 402 (struct rt_entry *)&oldroute); 403 } else if (rlen < RIPNG_RTM_MSGLEN) { 404 log_change(LOG_ERR, rt, 405 (struct rt_entry *)&oldroute); 406 } 407 } else if (dokern || oldmetric >= HOPCNT_INFINITY) { 408 rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router, 409 rt->rt_prefix_length, ifp->int_name, rt->rt_flags); 410 if (rlen < 0 && errno != EEXIST) { 411 syslog(LOG_ERR, "rtchange: RTM_ADD: %m"); 412 log_change(LOG_ERR, rt, 413 (struct rt_entry *)&oldroute); 414 } else if (rlen < RIPNG_RTM_MSGLEN) { 415 log_change(LOG_ERR, rt, 416 (struct rt_entry *)&oldroute); 417 } 418 } 419 } 420 } 421 422 void 423 rtdown(struct rt_entry *rt) 424 { 425 int rlen; 426 427 if (rt->rt_metric != HOPCNT_INFINITY) { 428 TRACE_ACTION("DELETE", rt); 429 if (install && (rt->rt_state & RTS_INTERFACE) == 0) { 430 rlen = rtcmd(RTM_DELETE, &rt->rt_dst, 431 &rt->rt_router, rt->rt_prefix_length, 432 rt->rt_ifp->int_name, rt->rt_flags); 433 if (rlen < 0) { 434 syslog(LOG_ERR, "rtdown: RTM_DELETE: %m"); 435 log_single(LOG_ERR, rt); 436 } else if (rlen < RIPNG_RTM_MSGLEN) { 437 log_single(LOG_ERR, rt); 438 } 439 } 440 rt->rt_metric = HOPCNT_INFINITY; 441 rt->rt_state |= RTS_CHANGED; 442 } 443 if (rt->rt_timer < EXPIRE_TIME) 444 rt->rt_timer = EXPIRE_TIME; 445 } 446 447 void 448 rtdelete(struct rt_entry *rt) 449 { 450 451 if (rt->rt_state & RTS_INTERFACE) { 452 if (rt->rt_ifp != NULL) { 453 syslog(LOG_ERR, 454 "rtdelete: " 455 "deleting route to interface %s (timed out)", 456 (rt->rt_ifp->int_name != NULL) ? 457 rt->rt_ifp->int_name : "(noname)"); 458 log_single(LOG_ERR, rt); 459 } 460 } 461 rtdown(rt); 462 remque(rt); 463 free((char *)rt); 464 } 465 466 /* 467 * Mark all the routes heard off a particular interface "down". Unlike the 468 * routes managed by in.routed, all of these routes have an interface associated 469 * with them. 470 */ 471 void 472 rtpurgeif(struct interface *ifp) 473 { 474 struct rthash *rh; 475 struct rt_entry *rt; 476 int i; 477 478 for (i = IPV6_ABITS; i >= 0; i--) { 479 if (net_hashes[i] == NULL) 480 continue; 481 482 for (rh = net_hashes[i]; 483 rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) { 484 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; 485 rt = rt->rt_forw) { 486 if (rt->rt_ifp == ifp) { 487 rtdown(rt); 488 rt->rt_ifp = NULL; 489 rt->rt_state &= ~RTS_INTERFACE; 490 } 491 } 492 } 493 } 494 } 495 496 /* 497 * Called when the subnetmask has changed on one or more interfaces. 498 * Re-evaluates all non-interface routes by doing a rtchange so that 499 * routes that were believed to be host routes before the netmask change 500 * can be converted to network routes and vice versa. 501 */ 502 void 503 rtchangeall(void) 504 { 505 struct rthash *rh; 506 struct rt_entry *rt; 507 int i; 508 509 for (i = IPV6_ABITS; i >= 0; i--) { 510 if (net_hashes[i] == NULL) 511 continue; 512 513 for (rh = net_hashes[i]; 514 rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) { 515 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; 516 rt = rt->rt_forw) { 517 if ((rt->rt_state & RTS_INTERFACE) == 0) { 518 rtchange(rt, &rt->rt_router, 519 rt->rt_metric, rt->rt_ifp); 520 } 521 } 522 } 523 } 524 } 525 526 static void 527 rtdumpentry(FILE *fp, struct rt_entry *rt) 528 { 529 char buf1[INET6_ADDRSTRLEN]; 530 static struct bits { 531 ulong_t t_bits; 532 char *t_name; 533 } flagbits[] = { 534 /* BEGIN CSTYLED */ 535 { RTF_UP, "UP" }, 536 { RTF_GATEWAY, "GATEWAY" }, 537 { RTF_HOST, "HOST" }, 538 { 0, NULL } 539 /* END CSTYLED */ 540 }, statebits[] = { 541 /* BEGIN CSTYLED */ 542 { RTS_INTERFACE, "INTERFACE" }, 543 { RTS_CHANGED, "CHANGED" }, 544 { RTS_PRIVATE, "PRIVATE" }, 545 { 0, NULL } 546 /* END CSTYLED */ 547 }; 548 struct bits *p; 549 boolean_t first; 550 char c; 551 552 (void) fprintf(fp, "prefix %s/%d ", 553 inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1)), 554 rt->rt_prefix_length); 555 (void) fprintf(fp, "via %s metric %d timer %d", 556 inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1, sizeof (buf1)), 557 rt->rt_metric, rt->rt_timer); 558 if (rt->rt_ifp != NULL) { 559 (void) fprintf(fp, " if %s", 560 (rt->rt_ifp->int_name != NULL) ? 561 rt->rt_ifp->int_name : "(noname)"); 562 } 563 (void) fprintf(fp, " state"); 564 c = ' '; 565 for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) { 566 if ((rt->rt_state & p->t_bits) == 0) 567 continue; 568 (void) fprintf(fp, "%c%s", c, p->t_name); 569 if (first) { 570 c = '|'; 571 first = _B_FALSE; 572 } 573 } 574 if (first) 575 (void) fprintf(fp, " 0"); 576 if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) { 577 c = ' '; 578 for (first = _B_TRUE, p = flagbits; p->t_bits > 0; p++) { 579 if ((rt->rt_flags & p->t_bits) == 0) 580 continue; 581 (void) fprintf(fp, "%c%s", c, p->t_name); 582 if (first) { 583 c = '|'; 584 first = _B_FALSE; 585 } 586 } 587 } 588 (void) putc('\n', fp); 589 (void) fflush(fp); 590 } 591 592 static void 593 rtdump2(FILE *fp) 594 { 595 struct rthash *rh; 596 struct rt_entry *rt; 597 int i; 598 599 for (i = IPV6_ABITS; i >= 0; i--) { 600 if (net_hashes[i] == NULL) 601 continue; 602 603 for (rh = net_hashes[i]; 604 rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) { 605 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; 606 rt = rt->rt_forw) { 607 rtdumpentry(fp, rt); 608 } 609 } 610 } 611 } 612 613 void 614 rtdump(void) 615 { 616 if (ftrace != NULL) 617 rtdump2(ftrace); 618 else 619 rtdump2(stderr); 620 } 621 622 /* 623 * Create a routing socket for sending RTM_ADD and RTM_DELETE messages and 624 * initialize the routing socket message header and as much of the sockaddrs 625 * as possible. 626 */ 627 void 628 setup_rtsock(void) 629 { 630 char *cp; 631 int off = 0; 632 633 rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6); 634 if (rtsock < 0) { 635 syslog(LOG_ERR, "setup_rtsock: socket: %m"); 636 exit(EXIT_FAILURE); 637 } 638 639 /* We don't want to listen to our own messages */ 640 if (setsockopt(rtsock, SOL_SOCKET, SO_USELOOPBACK, (char *)&off, 641 sizeof (off)) < 0) { 642 syslog(LOG_ERR, "setup_rtsock: setsockopt: SO_USELOOPBACK: %m"); 643 exit(EXIT_FAILURE); 644 } 645 646 /* 647 * Allocate storage for the routing socket message. 648 */ 649 rt_msg = (struct rt_msghdr *)malloc(RIPNG_RTM_MSGLEN); 650 if (rt_msg == NULL) { 651 syslog(LOG_ERR, "setup_rtsock: malloc: %m"); 652 exit(EXIT_FAILURE); 653 } 654 655 /* 656 * Initialize the routing socket message by zero-filling it and then 657 * setting the fields where are constant through the lifetime of the 658 * process. 659 */ 660 bzero(rt_msg, RIPNG_RTM_MSGLEN); 661 rt_msg->rtm_msglen = RIPNG_RTM_MSGLEN; 662 rt_msg->rtm_version = RTM_VERSION; 663 rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP; 664 rt_msg->rtm_pid = getpid(); 665 if (rt_msg->rtm_pid < 0) { 666 syslog(LOG_ERR, "setup_rtsock: getpid: %m"); 667 exit(EXIT_FAILURE); 668 } 669 670 /* 671 * Initialize the constant portion of the RTA_DST sockaddr. 672 */ 673 cp = (char *)rt_msg + sizeof (struct rt_msghdr); 674 rta_dst = (struct sockaddr_in6 *)cp; 675 rta_dst->sin6_family = AF_INET6; 676 677 /* 678 * Initialize the constant portion of the RTA_GATEWAY sockaddr. 679 */ 680 cp += sizeof (struct sockaddr_in6); 681 rta_gateway = (struct sockaddr_in6 *)cp; 682 rta_gateway->sin6_family = AF_INET6; 683 684 /* 685 * Initialize the constant portion of the RTA_NETMASK sockaddr. 686 */ 687 cp += sizeof (struct sockaddr_in6); 688 rta_netmask = (struct sockaddr_in6 *)cp; 689 rta_netmask->sin6_family = AF_INET6; 690 691 /* 692 * Initialize the constant portion of the RTA_IFP sockaddr. 693 */ 694 cp += sizeof (struct sockaddr_in6); 695 rta_ifp = (struct sockaddr_dl *)cp; 696 rta_ifp->sdl_family = AF_LINK; 697 } 698