1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 * 5 * Copyright (c) 1995 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgment: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $FreeBSD: src/sbin/routed/rdisc.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $ 37 */ 38 39 #include "defs.h" 40 #include <netinet/in_systm.h> 41 #include <netinet/ip.h> 42 #include <netinet/ip_icmp.h> 43 #include <fcntl.h> 44 #include <strings.h> 45 46 /* 47 * The size of the control buffer passed to recvmsg() used to receive 48 * ancillary data. 49 */ 50 #define CONTROL_BUFSIZE 1024 51 52 /* router advertisement ICMP packet */ 53 struct icmp_ad { 54 uint8_t icmp_type; /* type of message */ 55 uint8_t icmp_code; /* type sub code */ 56 uint16_t icmp_cksum; /* ones complement cksum of struct */ 57 uint8_t icmp_ad_num; /* # of following router addresses */ 58 uint8_t icmp_ad_asize; /* 2--words in each advertisement */ 59 uint16_t icmp_ad_life; /* seconds of validity */ 60 struct icmp_ad_info { 61 in_addr_t icmp_ad_addr; 62 uint32_t icmp_ad_pref; 63 } icmp_ad_info[1]; 64 }; 65 66 /* router solicitation ICMP packet */ 67 struct icmp_so { 68 uint8_t icmp_type; /* type of message */ 69 uint8_t icmp_code; /* type sub code */ 70 uint16_t icmp_cksum; /* ones complement cksum of struct */ 71 uint32_t icmp_so_rsvd; 72 }; 73 74 union ad_u { 75 struct icmp icmp; 76 struct icmp_ad ad; 77 struct icmp_so so; 78 }; 79 80 81 int rdisc_sock = -1; /* router-discovery raw socket */ 82 int rdisc_mib_sock = -1; /* AF_UNIX mib info socket */ 83 static struct interface *rdisc_sock_interface; /* current rdisc interface */ 84 85 struct timeval rdisc_timer; 86 boolean_t rdisc_ok; /* using solicited route */ 87 88 #define MAX_ADS 16 89 int max_ads; /* at least one per interface */ 90 /* accumulated advertisements */ 91 static struct dr *cur_drp; 92 struct dr *drs; 93 94 /* 95 * adjust unsigned preference by interface metric, 96 * without driving it to infinity 97 */ 98 #define PREF(p, ifp) ((p) <= (uint32_t)(ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ 99 : (p) - ((ifp)->int_metric)) 100 101 static void rdisc_sort(void); 102 103 typedef enum { unicast, bcast, mcast } dstaddr_t; 104 105 /* dump an ICMP Router Discovery Advertisement Message */ 106 static void 107 trace_rdisc(const char *act, 108 uint32_t from, 109 uint32_t to, 110 struct interface *ifp, 111 union ad_u *p, 112 uint_t len) 113 { 114 int i; 115 n_long *wp, *lim; 116 117 118 if (!TRACEPACKETS || ftrace == 0) 119 return; 120 121 lastlog(); 122 123 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 124 (void) fprintf(ftrace, "%s Router Ad" 125 " from %s to %s via %s life=%d\n", 126 act, naddr_ntoa(from), naddr_ntoa(to), 127 ifp ? ifp->int_name : "?", 128 ntohs(p->ad.icmp_ad_life)); 129 if (!TRACECONTENTS) 130 return; 131 132 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 133 lim = &wp[(len - sizeof (p->ad)) / sizeof (*wp)]; 134 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 135 (void) fprintf(ftrace, "\t%s preference=%ld", 136 naddr_ntoa(wp[0]), (long)ntohl(wp[1])); 137 wp += p->ad.icmp_ad_asize; 138 } 139 (void) fputc('\n', ftrace); 140 141 } else { 142 trace_act("%s Router Solic. from %s to %s via %s rsvd=%#x", 143 act, naddr_ntoa(from), naddr_ntoa(to), 144 ifp ? ifp->int_name : "?", 145 ntohl(p->so.icmp_so_rsvd)); 146 } 147 } 148 149 /* 150 * Prepare Router Discovery socket. 151 */ 152 static void 153 get_rdisc_sock(void) 154 { 155 int on = 1; 156 unsigned char ttl = 1; 157 struct sockaddr_un laddr; 158 int len; 159 160 if (rdisc_sock < 0) { 161 max_ads = MAX_ADS; 162 drs = rtmalloc(max_ads * sizeof (struct dr), "get_rdisc_sock"); 163 (void) memset(drs, 0, max_ads * sizeof (struct dr)); 164 rdisc_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); 165 if (rdisc_sock < 0) 166 BADERR(_B_TRUE, "rdisc_sock = socket()"); 167 fix_sock(rdisc_sock, "rdisc_sock"); 168 169 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_RECVIF, &on, 170 sizeof (on))) 171 BADERR(_B_FALSE, "setsockopt(IP_RECVIF)"); 172 173 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_TTL, 174 &ttl, sizeof (ttl)) < 0) 175 DBGERR(_B_TRUE, 176 "rdisc_sock setsockopt(IP_MULTICAST_TTL)"); 177 178 /* 179 * On Solaris also open an AF_UNIX socket to 180 * pass default router information to mib agent 181 */ 182 183 rdisc_mib_sock = socket(AF_UNIX, SOCK_DGRAM, 0); 184 if (rdisc_mib_sock < 0) { 185 BADERR(_B_TRUE, "rdisc_mib_sock = socket()"); 186 } 187 188 bzero(&laddr, sizeof (laddr)); 189 laddr.sun_family = AF_UNIX; 190 191 (void) strncpy(laddr.sun_path, RDISC_SNMP_SOCKET, 192 sizeof (laddr.sun_path)); 193 len = sizeof (struct sockaddr_un); 194 195 (void) unlink(RDISC_SNMP_SOCKET); 196 197 if (bind(rdisc_mib_sock, (struct sockaddr *)&laddr, len) < 0) { 198 BADERR(_B_TRUE, "bind(rdisc_mib_sock)"); 199 } 200 201 if (fcntl(rdisc_mib_sock, F_SETFL, O_NONBLOCK) < 0) { 202 BADERR(_B_TRUE, "rdisc_mib_sock fcntl O_NONBLOCK"); 203 } 204 205 fix_select(); 206 } 207 } 208 209 210 /* 211 * Pick multicast group for router-discovery socket 212 */ 213 void 214 set_rdisc_mg(struct interface *ifp, 215 int on) /* 0=turn it off */ 216 { 217 struct ip_mreq m; 218 boolean_t dosupply; 219 220 if (rdisc_sock < 0) { 221 /* 222 * Create the raw socket so that we can hear at least 223 * broadcast router discovery packets. 224 */ 225 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC || 226 !on) 227 return; 228 get_rdisc_sock(); 229 } 230 231 if (!(ifp->int_if_flags & IFF_MULTICAST)) { 232 /* Can't multicast, so no groups could have been joined. */ 233 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 234 return; 235 } 236 237 dosupply = should_supply(ifp); 238 239 (void) memset(&m, 0, sizeof (m)); 240 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) && 241 (ifp->int_dstaddr != 0) ? ifp->int_dstaddr : ifp->int_addr); 242 if (dosupply || (ifp->int_state & IS_NO_ADV_IN) || !on) { 243 /* stop listening to advertisements */ 244 if (ifp->int_state & IS_ALL_HOSTS) { 245 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 246 if (setsockopt(rdisc_sock, IPPROTO_IP, 247 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 && 248 errno != EADDRNOTAVAIL && errno != ENOENT) 249 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 250 ifp->int_state &= ~IS_ALL_HOSTS; 251 } 252 253 } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 254 /* start listening to advertisements */ 255 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 256 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 257 &m, sizeof (m)) < 0) { 258 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 259 } else { 260 ifp->int_state |= IS_ALL_HOSTS; 261 } 262 } 263 264 if (!dosupply || (ifp->int_state & IS_NO_ADV_OUT) || 265 !IS_IFF_ROUTING(ifp->int_if_flags) || !on) { 266 /* stop listening to solicitations */ 267 if (ifp->int_state & IS_ALL_ROUTERS) { 268 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP); 269 if (setsockopt(rdisc_sock, IPPROTO_IP, 270 IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 && 271 errno != EADDRNOTAVAIL && errno != ENOENT) 272 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 273 ifp->int_state &= ~IS_ALL_ROUTERS; 274 } 275 276 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 277 /* start hearing solicitations */ 278 m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP); 279 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 280 &m, sizeof (m)) < 0) { 281 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 282 } else { 283 ifp->int_state |= IS_ALL_ROUTERS; 284 } 285 } 286 } 287 288 289 /* 290 * start or stop supplying routes to other systems. 291 */ 292 void 293 set_supplier(void) 294 { 295 struct interface *ifp; 296 struct dr *drp; 297 static boolean_t supplystate = _B_FALSE; 298 299 if (supplystate == (fwd_interfaces > 1)) 300 return; 301 supplystate = fwd_interfaces > 1; 302 303 trace_act("%d forwarding interfaces present; becoming %ssupplier", 304 fwd_interfaces, supplystate ? "" : "non-"); 305 306 if (supplystate) { 307 /* Forget discovered routes. */ 308 for (drp = drs; drp < &drs[max_ads]; drp++) { 309 drp->dr_recv_pref = DEF_PREFERENCELEVEL; 310 drp->dr_life = 0; 311 } 312 rdisc_age(0); 313 314 /* 315 * Do not start advertising until we have heard some 316 * RIP routes. 317 */ 318 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 319 320 /* get rid of any redirects */ 321 del_redirects(0, 0); 322 } else { 323 /* 324 * Flush out all those advertisements we had sent by sending 325 * one with lifetime=0. 326 */ 327 rdisc_adv(_B_TRUE); 328 } 329 330 /* 331 * Switch router discovery multicast groups from soliciting 332 * to advertising or back. 333 */ 334 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 335 if (ifp->int_state & IS_BROKE) 336 continue; 337 ifp->int_rdisc_cnt = 0; 338 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 339 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 340 set_rdisc_mg(ifp, 1); 341 } 342 } 343 344 345 /* 346 * Age discovered routes and find the best one 347 */ 348 void 349 rdisc_age(in_addr_t bad_gate) 350 { 351 time_t sec; 352 struct dr *drp; 353 struct rt_spare new; 354 struct rt_entry *rt; 355 356 /* 357 * If we are being told about a bad router, 358 * then age the discovered default route, and if there is 359 * no alternative, solicit a replacement. 360 */ 361 if (bad_gate != 0) { 362 /* 363 * Look for the bad discovered default route. 364 * Age it and note its interface. 365 */ 366 for (drp = drs; drp < &drs[max_ads]; drp++) { 367 if (drp->dr_ts == 0) 368 continue; 369 370 /* 371 * When we find the bad router, age the route 372 * to at most SUPPLY_INTERVAL. 373 * This is contrary to RFC 1256, but defends against 374 * black holes. 375 */ 376 if (drp->dr_gate == bad_gate) { 377 sec = (now.tv_sec - drp->dr_life + 378 SUPPLY_INTERVAL); 379 if (drp->dr_ts > sec) { 380 trace_act("age 0.0.0.0 --> %s via %s", 381 naddr_ntoa(drp->dr_gate), 382 drp->dr_ifp->int_name); 383 drp->dr_ts = sec; 384 } 385 break; 386 } 387 } 388 } else if (should_supply(NULL)) { 389 /* 390 * If switching from client to server, get rid of old 391 * default routes. 392 */ 393 if (cur_drp != NULL) { 394 rt = rtget(RIP_DEFAULT, 0); 395 /* 396 * If there is a current default router, and the 397 * there is no rt_spare entry, create one 398 * for cur_drp to prevent segmentation fault 399 * at rdisc_sort. 400 */ 401 if (rt == NULL) { 402 (void) memset(&new, 0, sizeof (new)); 403 new.rts_ifp = cur_drp->dr_ifp; 404 new.rts_gate = cur_drp->dr_gate; 405 new.rts_router = cur_drp->dr_gate; 406 new.rts_metric = HOPCNT_INFINITY-1; 407 new.rts_time = now.tv_sec; 408 new.rts_origin = RO_RDISC; 409 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 410 } 411 412 rdisc_sort(); 413 } 414 rdisc_adv(_B_FALSE); 415 } 416 417 rdisc_sol(); 418 if (cur_drp != NULL) { 419 rt = rtget(RIP_DEFAULT, 0); 420 if (rt == NULL) { 421 (void) memset(&new, 0, sizeof (new)); 422 new.rts_ifp = cur_drp->dr_ifp; 423 new.rts_gate = cur_drp->dr_gate; 424 new.rts_router = cur_drp->dr_gate; 425 new.rts_metric = HOPCNT_INFINITY-1; 426 new.rts_time = now.tv_sec; 427 new.rts_origin = RO_RDISC; 428 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 429 } 430 } 431 rdisc_sort(); 432 433 /* 434 * Delete old redirected routes to keep the kernel table small, 435 * and to prevent black holes. Check that the kernel table 436 * matches the daemon table (i.e. has the default route). 437 * But only if RIP is not running and we are not dealing with 438 * a bad gateway, since otherwise age() will be called. 439 */ 440 if (rip_sock < 0 && bad_gate == 0) 441 age(0); 442 } 443 444 445 /* 446 * Zap all routes discovered via an interface that has gone bad 447 * This should only be called when !(ifp->int_state & IS_DUP) 448 * This is called by if_del and if_bad, and the interface pointer 449 * might not be valid after this. 450 */ 451 void 452 if_bad_rdisc(struct interface *ifp) 453 { 454 struct dr *drp; 455 456 for (drp = drs; drp < &drs[max_ads]; drp++) { 457 if (drp->dr_ifp != ifp) 458 continue; 459 (void) memset(drp, 0, sizeof (*drp)); 460 } 461 462 /* make a note to re-solicit, turn RIP on or off, etc. */ 463 rdisc_timer.tv_sec = 0; 464 } 465 466 /* 467 * Rewire all routes discovered via an interface that has gone bad 468 * This is only called by if_del. 469 */ 470 void 471 if_rewire_rdisc(struct interface *oldifp, struct interface *newifp) 472 { 473 struct dr *drp; 474 475 for (drp = drs; drp < &drs[max_ads]; drp++) { 476 if (drp->dr_ifp != oldifp) 477 continue; 478 drp->dr_ifp = newifp; 479 drp->dr_pref += (newifp->int_metric - oldifp->int_metric); 480 drp->dr_flags |= DR_CHANGED; 481 } 482 483 /* make a note to re-solicit, turn RIP on or off, etc. */ 484 rdisc_timer.tv_sec = 0; 485 } 486 487 /* 488 * Mark an interface ok for router discovering. 489 * This is called by if_ok and ifinit. 490 */ 491 void 492 if_ok_rdisc(struct interface *ifp) 493 { 494 set_rdisc_mg(ifp, 1); 495 496 ifp->int_rdisc_cnt = 0; 497 ifp->int_rdisc_timer.tv_sec = now.tv_sec + 498 ((ifp->int_state & IS_NO_ADV_OUT) ? 499 MAX_SOLICITATION_DELAY : MIN_WAITTIME); 500 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, > /* cstyle */)) 501 rdisc_timer = ifp->int_rdisc_timer; 502 } 503 504 /* 505 * Get rid of a dead discovered router 506 */ 507 static void 508 del_rdisc(struct dr *drp) 509 { 510 struct interface *ifp; 511 uint32_t gate; 512 int i; 513 struct rt_entry *rt; 514 struct rt_spare *rts = NULL; 515 516 del_redirects(gate = drp->dr_gate, 0); 517 drp->dr_ts = 0; 518 drp->dr_life = 0; 519 520 rt = rtget(RIP_DEFAULT, 0); 521 if (rt == NULL) { 522 trace_act("could not find default route in table"); 523 } else { 524 for (i = 0; i < rt->rt_num_spares; i++) { 525 if ((rt->rt_spares[i].rts_gate == drp->dr_gate) && 526 (rt->rt_spares[i].rts_origin == RO_RDISC)) { 527 rts = &rt->rt_spares[i]; 528 break; 529 } 530 } 531 if (rts != NULL) 532 rts_delete(rt, rts); 533 else 534 trace_act("could not find default route " 535 "through %s in table", naddr_ntoa(drp->dr_gate)); 536 } 537 538 /* Count the other discovered routers on the interface. */ 539 i = 0; 540 ifp = drp->dr_ifp; 541 for (drp = drs; drp < &drs[max_ads]; drp++) { 542 if (drp->dr_ts != 0 && drp->dr_ifp == ifp) 543 i++; 544 } 545 546 /* 547 * If that was the last good discovered router on the interface, 548 * then solicit a new one. 549 * This is contrary to RFC 1256, but defends against black holes. 550 */ 551 if (i != 0) { 552 trace_act("discovered router %s via %s" 553 " is bad--have %d remaining", 554 naddr_ntoa(gate), ifp->int_name, i); 555 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 556 trace_act("last discovered router %s via %s" 557 " is bad--re-solicit", 558 naddr_ntoa(gate), ifp->int_name); 559 ifp->int_rdisc_cnt = 0; 560 ifp->int_rdisc_timer.tv_sec = 0; 561 rdisc_sol(); 562 } else { 563 trace_act("last discovered router %s via %s" 564 " is bad--wait to solicit", 565 naddr_ntoa(gate), ifp->int_name); 566 } 567 } 568 569 570 /* Find the best discovered route, and discard stale routers. */ 571 static void 572 rdisc_sort(void) 573 { 574 struct dr *drp, *new_drp; 575 struct rt_entry *rt; 576 struct rt_spare new, *rts; 577 struct interface *ifp; 578 uint_t new_st = 0; 579 uint32_t new_pref = DEF_PREFERENCELEVEL; 580 int first_rdisc_slot = 0; 581 int j; 582 boolean_t spares_avail; 583 void *ptr; 584 size_t ptrsize; 585 586 rt = rtget(RIP_DEFAULT, 0); 587 588 /* 589 * If all the rt_spare entries are taken up with with default routes 590 * learnt from RIP (ie rts_origin = RO_RIP), bail out. 591 * NOTE: 592 * We *always* prefer default routes learned via RIP 593 * (ie RO_RIP) over those learnt via RDISC (ie RO_RDISC). 594 * The rdisc machinery should not modify, replace or 595 * remove any existing default routes with RO_RIP set. 596 */ 597 if (rt != NULL) { 598 spares_avail = _B_FALSE; 599 for (j = 0; j < rt->rt_num_spares; j++) { 600 rts = &rt->rt_spares[j]; 601 if (rts->rts_gate == 0 || rts->rts_origin != RO_RIP || 602 rts->rts_ifp == &dummy_ifp) { 603 spares_avail = _B_TRUE; 604 break; 605 } 606 } 607 if (!spares_avail) { 608 ptrsize = (rt->rt_num_spares + SPARE_INC) * 609 sizeof (struct rt_spare); 610 ptr = realloc(rt->rt_spares, ptrsize); 611 if (ptr != NULL) { 612 struct rt_spare *tmprts; 613 614 rt->rt_spares = ptr; 615 rts = &rt->rt_spares[rt->rt_num_spares]; 616 (void) memset(rts, 0, 617 (SPARE_INC * sizeof (struct rt_spare))); 618 rt->rt_num_spares += SPARE_INC; 619 for (tmprts = rts, j = SPARE_INC; 620 j != 0; j--, tmprts++) 621 tmprts->rts_metric = HOPCNT_INFINITY; 622 spares_avail = _B_TRUE; 623 } else { 624 return; 625 } 626 } 627 } 628 /* Find the best RDISC advertiser */ 629 rt = NULL; 630 new_drp = NULL; 631 for (drp = drs; drp < &drs[max_ads]; drp++) { 632 if (drp->dr_ts == 0) 633 continue; 634 ifp = drp->dr_ifp; 635 636 /* Get rid of expired discovered routers. */ 637 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 638 del_rdisc(drp); 639 continue; 640 } 641 642 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life); 643 644 /* 645 * Update preference with possibly changed interface 646 * metric. 647 */ 648 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 649 650 /* 651 * Prefer the current route to prevent thrashing. 652 * Prefer shorter lifetimes to speed the detection of 653 * bad routers. 654 * Avoid sick interfaces. 655 */ 656 if (new_drp == NULL || 657 (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) && 658 (new_pref < drp->dr_pref || 659 (new_pref == drp->dr_pref && (drp == cur_drp || 660 (new_drp != cur_drp && 661 new_drp->dr_life > drp->dr_life))))) || 662 ((new_st & IS_SICK) && 663 !(drp->dr_ifp->int_state & IS_SICK))) { 664 new_drp = drp; 665 new_st = drp->dr_ifp->int_state; 666 new_pref = drp->dr_pref; 667 } 668 } 669 670 /* 671 * switch to a better RDISC advertiser 672 */ 673 if ((new_drp != cur_drp) || (rt == NULL)) { 674 rt = rtget(RIP_DEFAULT, 0); 675 676 /* 677 * Purge the table of all the default routes that were 678 * learnt via RDISC, while keeping an eye the first available 679 * slot for the spare entry of new_drp 680 */ 681 if (rt != NULL) { 682 int i; 683 for (i = 0; i < rt->rt_num_spares; i++) { 684 rts = &rt->rt_spares[i]; 685 if ((rts->rts_gate == 0 || 686 rts->rts_ifp == &dummy_ifp) && 687 first_rdisc_slot == 0) 688 first_rdisc_slot = i; 689 if (rts->rts_origin == RO_RDISC) { 690 rts_delete(rt, rts); 691 if (first_rdisc_slot == 0) { 692 first_rdisc_slot = i; 693 } 694 } 695 } 696 } 697 698 /* Stop using RDISC routes if they are all bad */ 699 if (new_drp == NULL) { 700 trace_act("turn off Router Discovery client"); 701 rdisc_ok = _B_FALSE; 702 703 } else { 704 if (cur_drp == NULL) { 705 trace_act("turn on Router Discovery client" 706 " using %s via %s", 707 naddr_ntoa(new_drp->dr_gate), 708 new_drp->dr_ifp->int_name); 709 rdisc_ok = _B_TRUE; 710 } 711 712 /* Prepare a spare entry for the new_drp */ 713 (void) memset(&new, 0, sizeof (new)); 714 new.rts_ifp = new_drp->dr_ifp; 715 new.rts_gate = new_drp->dr_gate; 716 new.rts_router = new_drp->dr_gate; 717 new.rts_metric = HOPCNT_INFINITY-1; 718 new.rts_time = now.tv_sec; 719 new.rts_origin = RO_RDISC; 720 /* 721 * If there is no existing default route, add it 722 * to rts_spare[0]. 723 */ 724 if (rt == NULL) { 725 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 726 } else { 727 728 /* 729 * Add the spare entry for the new_drp in 730 * the first available slot 731 */ 732 trace_act("Switching to " 733 "default router with better " 734 "preference %s via %s ", 735 naddr_ntoa(new_drp->dr_gate), 736 new_drp->dr_ifp->int_name); 737 rt->rt_spares[first_rdisc_slot] = new; 738 rt = NULL; /* redo rt_spares */ 739 } 740 } 741 742 /* 743 * Get ready to redo the entire table. The table should 744 * only include : 745 * a. empty rt_spare slots 746 * b. default routes learnt via RIP 747 * c. default route for the latest best RDISC advertiser 748 * d. default routes of other RDISC advertisers whose 749 * dr_pref == best RDISC advertiser->dr_pref 750 */ 751 cur_drp = new_drp; 752 } 753 754 /* Redo the entire spare table (without touching RO_RIP entries) */ 755 if (rdisc_ok && rt == NULL) { 756 int i; 757 /* 758 * We've either just turned on router discovery, 759 * or switched to a router with better preference. 760 * Find all other default routers whose 761 * pref == cur_drp->dr_pref and add them as spares 762 */ 763 764 rt = rtget(RIP_DEFAULT, 0); 765 766 for (drp = drs; drp < &drs[max_ads]; drp++) { 767 boolean_t dr_done = _B_FALSE; 768 int slot = -1; 769 770 if (drp->dr_ts == 0) 771 continue; 772 773 if (drp->dr_pref != cur_drp->dr_pref && 774 ((drp->dr_flags & DR_CHANGED) == 0)) 775 continue; 776 777 /* 778 * Either pref matches cur_drp->dr_pref, 779 * or something has changed in this drp. 780 * In the former case, we may need to add 781 * this to rt_spares. In the latter case, 782 * if the pref has changed, need to take it 783 * out of rt_spares and the kernel. 784 * 785 * First, find an empty slot in rt_spares 786 * in case we have to add this drp to kernel. 787 * Also check if it is already there. 788 */ 789 for (i = 0; i < rt->rt_num_spares; i++) { 790 if (rt->rt_spares[i].rts_gate == 0) { 791 if (slot < 0) 792 slot = i; 793 continue; 794 } 795 if ((rt->rt_spares[i].rts_gate == 796 drp->dr_gate) && 797 (rt->rt_spares[i].rts_origin == 798 RO_RDISC)) { 799 /* 800 * a spare entry for this RDISC 801 * advertiser already exists. We need 802 * to check if this entry still belongs 803 * in the table 804 */ 805 dr_done = _B_TRUE; 806 break; 807 } 808 } 809 810 drp->dr_flags &= ~DR_CHANGED; 811 812 if (drp->dr_pref != cur_drp->dr_pref) { 813 if (dr_done) { 814 /* 815 * The rt_spare of this RDISC advertiser 816 * needs to be removed as it no longer 817 * belongs in the table because its 818 * dr_pref is different than the latest 819 * RDISC advertiser's->dr_pref 820 */ 821 rts_delete(rt, &rt->rt_spares[i]); 822 } 823 continue; 824 } 825 826 if (slot < 0 && !dr_done) { 827 ptrsize = (rt->rt_num_spares + SPARE_INC) * 828 sizeof (struct rt_spare); 829 ptr = realloc(rt->rt_spares, ptrsize); 830 if (ptr != NULL) { 831 struct rt_spare *tmprts; 832 833 rt->rt_spares = ptr; 834 slot = rt->rt_num_spares; 835 rts = &rt->rt_spares[rt->rt_num_spares]; 836 (void) memset(rts, 0, (SPARE_INC * 837 sizeof (struct rt_spare))); 838 rt->rt_num_spares += SPARE_INC; 839 for (tmprts = rts, i = SPARE_INC; 840 i != 0; i--, tmprts++) 841 tmprts->rts_metric = 842 HOPCNT_INFINITY; 843 } 844 } 845 846 if (slot >= 0 && (dr_done != _B_TRUE)) { 847 (void) memset(&new, 0, sizeof (new)); 848 new.rts_ifp = drp->dr_ifp; 849 new.rts_gate = drp->dr_gate; 850 new.rts_router = drp->dr_gate; 851 new.rts_metric = HOPCNT_INFINITY-1; 852 new.rts_time = now.tv_sec; 853 new.rts_origin = RO_RDISC; 854 rt->rt_spares[slot] = new; 855 trace_act("spare default %s via %s", 856 naddr_ntoa(drp->dr_gate), 857 drp->dr_ifp->int_name); 858 } 859 } 860 } 861 862 /* turn RIP on or off */ 863 if (!rdisc_ok || rip_interfaces > 1) { 864 rip_on(0); 865 } else { 866 rip_off(); 867 } 868 } 869 870 871 /* Handle a single address in an advertisement */ 872 static void 873 parse_ad(uint32_t from, 874 in_addr_t gate, 875 uint32_t pref, /* signed and in network order */ 876 ushort_t life, /* in host byte order */ 877 struct interface *ifp) 878 { 879 static struct msg_limit bad_gate; 880 struct dr *drp, *new_drp; 881 void *ptr; 882 size_t ptrsize; 883 884 if (gate == RIP_DEFAULT || !check_dst(gate)) { 885 msglim(&bad_gate, from, "router %s advertising bad gateway %s", 886 naddr_ntoa(from), naddr_ntoa(gate)); 887 return; 888 } 889 890 /* 891 * ignore pointers to ourself and routes via unreachable networks 892 */ 893 if (ifwithaddr(gate, _B_TRUE, _B_FALSE) != 0) { 894 trace_pkt(" discard Router Discovery Ad pointing at us"); 895 return; 896 } 897 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 898 trace_pkt(" discard Router Discovery Ad" 899 " toward unreachable net"); 900 return; 901 } 902 /* 903 * Convert preference to an unsigned value 904 * and later bias it by the metric of the interface. 905 */ 906 pref = UNSIGN_PREF(ntohl(pref)); 907 908 if (pref == DEF_PREFERENCELEVEL || life < MIN_MAXADVERTISEINTERVAL) { 909 pref = DEF_PREFERENCELEVEL; 910 life = 0; 911 } 912 913 for (new_drp = NULL, drp = drs; drp < &drs[max_ads]; drp++) { 914 /* accept new info for a familiar entry */ 915 if ((drp->dr_gate == gate) && (drp->dr_ifp == ifp)) { 916 new_drp = drp; 917 drp->dr_flags |= DR_CHANGED; 918 break; 919 } 920 921 if (life == 0) 922 continue; /* do not worry about dead ads */ 923 924 if (drp->dr_ts == 0) { 925 new_drp = drp; /* use unused entry */ 926 927 } else if (new_drp == NULL) { 928 /* look for an entry worse than the new one to reuse. */ 929 if ((!(ifp->int_state & IS_SICK) && 930 (drp->dr_ifp->int_state & IS_SICK)) || 931 (pref > drp->dr_pref && 932 !((ifp->int_state ^ drp->dr_ifp->int_state) & 933 IS_SICK))) 934 new_drp = drp; 935 936 } else if (new_drp->dr_ts != 0) { 937 /* look for the least valuable entry to reuse */ 938 if ((!(new_drp->dr_ifp->int_state & IS_SICK) && 939 (drp->dr_ifp->int_state & IS_SICK)) || 940 (new_drp->dr_pref > drp->dr_pref && 941 !((new_drp->dr_ifp->int_state ^ 942 drp->dr_ifp->int_state) & IS_SICK))) 943 new_drp = drp; 944 } 945 } 946 947 /* if all of the current entries are better, add more drs[] */ 948 if (new_drp == NULL) { 949 ptrsize = (max_ads + MAX_ADS) * sizeof (struct dr); 950 ptr = realloc(drs, ptrsize); 951 if (ptr == NULL) 952 return; 953 drs = ptr; 954 (void) memset(&drs[max_ads], 0, MAX_ADS * sizeof (struct dr)); 955 new_drp = &drs[max_ads]; 956 max_ads += MAX_ADS; 957 } 958 959 /* 960 * Pointer copy is safe here because if_del 961 * calls if_bad_rdisc first, so a non-NULL df_ifp 962 * is always a valid pointer. 963 */ 964 new_drp->dr_ifp = ifp; 965 new_drp->dr_gate = gate; 966 new_drp->dr_ts = now.tv_sec; 967 new_drp->dr_life = life; 968 new_drp->dr_recv_pref = pref; 969 /* bias functional preference by metric of the interface */ 970 new_drp->dr_pref = PREF(pref, ifp); 971 972 /* after hearing a good advertisement, stop asking */ 973 if (!(ifp->int_state & IS_SICK)) 974 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 975 } 976 977 978 /* 979 * Compute the IP checksum. This assumes the packet is less than 32K long. 980 */ 981 static uint16_t 982 in_cksum(uint16_t *p, uint_t len) 983 { 984 uint32_t sum = 0; 985 int nwords = len >> 1; 986 987 while (nwords-- != 0) 988 sum += *p++; 989 990 if (len & 1) 991 sum += *(uchar_t *)p; 992 993 /* end-around-carry */ 994 sum = (sum >> 16) + (sum & 0xffff); 995 sum += (sum >> 16); 996 return (~sum); 997 } 998 999 1000 /* Send a router discovery advertisement or solicitation ICMP packet. */ 1001 static void 1002 send_rdisc(union ad_u *p, 1003 uint_t p_size, 1004 struct interface *ifp, 1005 in_addr_t dst, /* 0 or unicast destination */ 1006 dstaddr_t type) 1007 { 1008 struct sockaddr_in sin; 1009 int flags = 0; 1010 const char *msg; 1011 int ifindex = 0; 1012 struct in_addr addr; 1013 1014 /* 1015 * Don't send Rdisc packets on duplicate interfaces, we 1016 * don't want to generate duplicate packets. 1017 */ 1018 if (ifp->int_state & IS_DUP) 1019 return; 1020 1021 (void) memset(&sin, 0, sizeof (sin)); 1022 sin.sin_addr.s_addr = dst; 1023 sin.sin_family = AF_INET; 1024 1025 switch (type) { 1026 case unicast: /* unicast */ 1027 default: 1028 flags = MSG_DONTROUTE; 1029 msg = "Send"; 1030 break; 1031 1032 case bcast: /* broadcast */ 1033 if (ifp->int_if_flags & IFF_POINTOPOINT) { 1034 msg = "Send pt-to-pt"; 1035 if (ifp->int_dstaddr == 0) 1036 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); 1037 else 1038 sin.sin_addr.s_addr = ifp->int_dstaddr; 1039 } else { 1040 msg = "Send broadcast"; 1041 sin.sin_addr.s_addr = ifp->int_brdaddr; 1042 } 1043 break; 1044 1045 case mcast: /* multicast */ 1046 msg = "Send multicast"; 1047 break; 1048 } 1049 1050 if (rdisc_sock < 0) 1051 get_rdisc_sock(); 1052 1053 /* select the right interface. */ 1054 ifindex = (type != mcast && ifp->int_phys != NULL) ? 1055 ifp->int_phys->phyi_index : 0; 1056 1057 if (rdisc_sock_interface != ifp) { 1058 /* 1059 * For multicast, we have to choose the source 1060 * address. This is either the local address 1061 * (non-point-to-point) or the remote address. 1062 */ 1063 addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 1064 ifp->int_dstaddr : ifp->int_addr; 1065 if (type == mcast && 1066 setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, 1067 sizeof (addr)) == -1) { 1068 LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)"); 1069 return; 1070 } 1071 rdisc_sock_interface = ifp; 1072 } 1073 1074 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size); 1075 1076 if (0 > sendtoif(rdisc_sock, p, p_size, flags, &sin, ifindex)) { 1077 if (!(ifp->int_state & IS_BROKE)) 1078 writelog(LOG_WARNING, "sendto(%s%s%s): %s", 1079 ifp->int_name, ", ", 1080 inet_ntoa(sin.sin_addr), 1081 rip_strerror(errno)); 1082 if (ifp != NULL) 1083 if_sick(ifp, _B_FALSE); 1084 } 1085 } 1086 1087 1088 /* Send an advertisement */ 1089 static void 1090 send_adv(struct interface *ifp, 1091 in_addr_t dst, 1092 dstaddr_t type) 1093 { 1094 union ad_u u; 1095 1096 if ((ifp->int_state & (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC)) == 1097 IS_SUPPRESS_RDISC) 1098 return; 1099 1100 (void) memset(&u, 0, sizeof (u.ad)); 1101 1102 u.ad.icmp_type = ICMP_ROUTERADVERT; 1103 u.ad.icmp_code = ICMP_ROUTERADVERT_COMMON; 1104 u.ad.icmp_ad_num = 1; 1105 u.ad.icmp_ad_asize = sizeof (u.ad.icmp_ad_info[0])/4; 1106 1107 u.ad.icmp_ad_life = (stopint || !should_supply(ifp) || 1108 (ifp->int_state & IS_SUPPRESS_RDISC)) ? 0 : 1109 htons(ifp->int_rdisc_int*3); 1110 1111 /* Send the configured preference as a network byte order value */ 1112 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(ifp->int_rdisc_pref); 1113 1114 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 1115 1116 u.ad.icmp_cksum = in_cksum((uint16_t *)&u.ad, sizeof (u.ad)); 1117 1118 send_rdisc(&u, sizeof (u.ad), ifp, dst, type); 1119 1120 if (ifp->int_state & IS_SUPPRESS_RDISC) 1121 ifp->int_state &= ~IS_FLUSH_RDISC; 1122 } 1123 1124 1125 /* Advertise as a default router by way of router discovery. */ 1126 void 1127 rdisc_adv(boolean_t forceadv) 1128 { 1129 struct interface *ifp; 1130 1131 if (!forceadv && !should_supply(NULL)) 1132 return; 1133 1134 rdisc_timer.tv_sec = now.tv_sec + NEVER; 1135 1136 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 1137 if ((ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)) || 1138 (!forceadv && !IS_IFF_ROUTING(ifp->int_if_flags))) 1139 continue; 1140 1141 /* skip interfaces we shouldn't use */ 1142 if (IS_IFF_QUIET(ifp->int_if_flags)) 1143 continue; 1144 1145 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */) || 1146 stopint != 0 || forceadv) { 1147 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 1148 (ifp->int_state & IS_BCAST_RDISC) ? 1 : 2); 1149 ifp->int_rdisc_cnt++; 1150 1151 intvl_random(&ifp->int_rdisc_timer, 1152 (ifp->int_rdisc_int*3)/4, ifp->int_rdisc_int); 1153 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS && 1154 (ifp->int_rdisc_timer.tv_sec > 1155 MAX_INITIAL_ADVERT_INTERVAL)) { 1156 ifp->int_rdisc_timer.tv_sec = 1157 MAX_INITIAL_ADVERT_INTERVAL; 1158 } 1159 timevaladd(&ifp->int_rdisc_timer, &now); 1160 } 1161 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 1162 > /* cstyle */)) 1163 rdisc_timer = ifp->int_rdisc_timer; 1164 } 1165 } 1166 1167 1168 /* Solicit for Router Discovery */ 1169 void 1170 rdisc_sol(void) 1171 { 1172 struct interface *ifp; 1173 union ad_u u; 1174 1175 if (should_supply(NULL)) 1176 return; 1177 1178 rdisc_timer.tv_sec = now.tv_sec + NEVER; 1179 1180 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 1181 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) || 1182 ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 1183 continue; 1184 1185 /* skip interfaces we shouldn't use */ 1186 if (IS_IFF_QUIET(ifp->int_if_flags)) 1187 continue; 1188 1189 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */)) { 1190 (void) memset(&u, 0, sizeof (u.so)); 1191 u.so.icmp_type = ICMP_ROUTERSOLICIT; 1192 u.so.icmp_cksum = in_cksum((uint16_t *)&u.so, 1193 sizeof (u.so)); 1194 send_rdisc(&u, sizeof (u.so), ifp, 1195 htonl(INADDR_ALLRTRS_GROUP), 1196 ((ifp->int_state&IS_BCAST_RDISC) ? bcast : mcast)); 1197 1198 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 1199 continue; 1200 1201 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 1202 ifp->int_rdisc_timer.tv_usec = 0; 1203 timevaladd(&ifp->int_rdisc_timer, &now); 1204 } 1205 1206 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 1207 > /* cstyle */)) 1208 rdisc_timer = ifp->int_rdisc_timer; 1209 } 1210 } 1211 1212 1213 /* 1214 * check the IP header of a possible Router Discovery ICMP packet 1215 * Returns 0 if bad 1216 */ 1217 static struct interface * 1218 ck_icmp(const char *act, 1219 in_addr_t from, 1220 struct interface *ifp, 1221 in_addr_t to, 1222 union ad_u *p, 1223 uint_t len) 1224 { 1225 const char *type; 1226 1227 1228 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 1229 type = "advertisement"; 1230 if (p->icmp.icmp_code == ICMP_ROUTERADVERT_NOCOMMON) 1231 return (NULL); /* Mobile IP */ 1232 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 1233 type = "solicitation"; 1234 } else { 1235 return (NULL); 1236 } 1237 1238 if (p->icmp.icmp_code != ICMP_ROUTERADVERT_COMMON) { 1239 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 1240 type, p->icmp.icmp_code, naddr_ntoa(from), naddr_ntoa(to)); 1241 return (NULL); 1242 } 1243 1244 trace_rdisc(act, from, to, ifp, p, len); 1245 1246 if (ifp == NULL) 1247 trace_pkt("unknown interface for router-discovery %s from %s " 1248 "to %s", type, naddr_ntoa(from), naddr_ntoa(to)); 1249 1250 return (ifp); 1251 } 1252 1253 1254 /* Read packets from the router discovery socket */ 1255 void 1256 read_d(void) 1257 { 1258 #define PKTLEN 512 1259 static struct msg_limit bad_asize, bad_len; 1260 struct sockaddr_in from; 1261 int n, cc, hlen; 1262 struct { 1263 union { 1264 struct ip ip; 1265 uint16_t s[PKTLEN/sizeof (uint16_t)]; 1266 uint8_t b[PKTLEN/sizeof (uint8_t)]; 1267 } pkt; 1268 } buf; 1269 union ad_u *p; 1270 n_long *wp; 1271 struct interface *ifp; 1272 boolean_t needsort = _B_FALSE; 1273 struct msghdr msg; 1274 struct iovec iov; 1275 uint8_t ancillary_data[CONTROL_BUFSIZE]; 1276 1277 iov.iov_base = &buf; 1278 iov.iov_len = sizeof (buf); 1279 msg.msg_iov = &iov; 1280 msg.msg_iovlen = 1; 1281 msg.msg_name = &from; 1282 msg.msg_control = &ancillary_data; 1283 1284 for (;;) { 1285 msg.msg_namelen = sizeof (from); 1286 msg.msg_controllen = sizeof (ancillary_data); 1287 cc = recvmsg(rdisc_sock, &msg, 0); 1288 if (cc <= 0) { 1289 if (cc < 0 && errno != EWOULDBLOCK) 1290 LOGERR("recvmsg(rdisc_sock)"); 1291 break; 1292 } 1293 1294 hlen = buf.pkt.ip.ip_hl << 2; 1295 if (cc < hlen + ICMP_MINLEN) 1296 continue; 1297 /* LINTED [alignment will be lw aligned] */ 1298 p = (union ad_u *)&buf.pkt.b[hlen]; 1299 cc -= hlen; 1300 1301 /* 1302 * If we could tell the interface on which a packet from 1303 * address 0 arrived, we could deal with such solicitations. 1304 */ 1305 ifp = receiving_interface(&msg, _B_FALSE); 1306 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 1307 buf.pkt.ip.ip_dst.s_addr, p, cc); 1308 if (ifp == NULL) 1309 continue; 1310 1311 if (IS_IFF_QUIET(ifp->int_if_flags)) { 1312 trace_misc("discard RDISC packet received over %s, %X", 1313 ifp->int_name, ifp->int_if_flags); 1314 continue; 1315 } 1316 1317 if (from.sin_addr.s_addr != 0 && 1318 ifwithaddr(from.sin_addr.s_addr, _B_FALSE, _B_FALSE)) { 1319 trace_pkt(" " 1320 "discard our own Router Discovery message"); 1321 continue; 1322 } 1323 1324 /* The remote address *must* be directly connected. */ 1325 if (!remote_address_ok(ifp, from.sin_addr.s_addr)) { 1326 trace_misc("discard rdisc message; source %s not on " 1327 "interface %s", naddr_ntoa(from.sin_addr.s_addr), 1328 ifp->int_name); 1329 continue; 1330 } 1331 1332 switch (p->icmp.icmp_type) { 1333 case ICMP_ROUTERADVERT: 1334 if (ifp->int_state & IS_NO_ADV_IN) 1335 continue; 1336 1337 if (p->ad.icmp_ad_asize*2*sizeof (wp[0]) < 1338 sizeof (p->ad.icmp_ad_info[0])) { 1339 msglim(&bad_asize, from.sin_addr.s_addr, 1340 "intolerable rdisc address size=%d", 1341 p->ad.icmp_ad_asize); 1342 continue; 1343 } 1344 if (p->ad.icmp_ad_num == 0) { 1345 trace_pkt(" empty?"); 1346 continue; 1347 } 1348 if (cc < (sizeof (p->ad) - 1349 sizeof (p->ad.icmp_ad_info) + 1350 (p->ad.icmp_ad_num * 1351 sizeof (p->ad.icmp_ad_info[0])))) { 1352 msglim(&bad_len, from.sin_addr.s_addr, 1353 "rdisc length %d does not match ad_num" 1354 " %d", cc, p->ad.icmp_ad_num); 1355 continue; 1356 } 1357 1358 needsort = _B_TRUE; 1359 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1360 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1361 parse_ad(from.sin_addr.s_addr, 1362 wp[0], wp[1], 1363 ntohs(p->ad.icmp_ad_life), ifp); 1364 wp += p->ad.icmp_ad_asize; 1365 } 1366 break; 1367 1368 1369 case ICMP_ROUTERSOLICIT: 1370 if (!should_supply(ifp)) 1371 continue; 1372 if ((ifp->int_state & IS_NO_ADV_OUT) || 1373 !IS_IFF_ROUTING(ifp->int_if_flags)) 1374 continue; 1375 if (stopint != 0) 1376 continue; 1377 1378 /* 1379 * We should handle messages from address 0, 1380 * but cannot due to kernel limitations. 1381 */ 1382 1383 /* Respond with a point-to-point advertisement */ 1384 send_adv(ifp, from.sin_addr.s_addr, 0); 1385 break; 1386 } 1387 } 1388 1389 if (needsort) 1390 rdisc_sort(); 1391 } 1392 1393 void 1394 rdisc_dump(void) 1395 { 1396 struct dr *drp; 1397 1398 for (drp = drs; drp < &drs[max_ads]; drp++) 1399 if (drp->dr_ts != 0) 1400 trace_dr(drp); 1401 } 1402 1403 void 1404 rdisc_suppress(struct interface *ifp) 1405 { 1406 if (ifp->int_state & IS_ADV_OUT) { 1407 msglog("%s \"rdisc_adv\" specified, will not " 1408 "suppress rdisc adv", ifp->int_name); 1409 } else { 1410 if (ifp->int_state & IS_SUPPRESS_RDISC) 1411 return; 1412 ifp->int_state |= (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 1413 trace_misc("suppress rdisc adv on %s", ifp->int_name); 1414 rdisc_timer.tv_sec = 0; 1415 } 1416 } 1417 1418 void 1419 rdisc_restore(struct interface *ifp) 1420 { 1421 if ((ifp->int_state & IS_SUPPRESS_RDISC) == 0) 1422 return; 1423 ifp->int_state &= ~(IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 1424 trace_misc("restoring rdisc adv on %s", ifp->int_name); 1425 rdisc_timer.tv_sec = 0; 1426 } 1427 1428 void 1429 process_d_mib_sock(void) 1430 { 1431 1432 socklen_t fromlen; 1433 struct sockaddr_un from; 1434 ssize_t len; 1435 int command; 1436 struct dr *drp; 1437 rdisc_info_t rdisc_info; 1438 defr_t def_router; 1439 extern int max_ads; 1440 int num = 0; 1441 1442 fromlen = (socklen_t)sizeof (from); 1443 len = recvfrom(rdisc_mib_sock, &command, sizeof (int), 0, 1444 (struct sockaddr *)&from, &fromlen); 1445 1446 if (len < sizeof (int) || command != RDISC_SNMP_INFO_REQ) { 1447 trace_misc("Bad command on rdisc_mib_sock"); 1448 return; 1449 } 1450 1451 /* 1452 * Count number of good routers 1453 */ 1454 for (drp = drs; drp < &drs[max_ads]; drp++) { 1455 if (drp->dr_ts != 0) { 1456 num++; 1457 } 1458 } 1459 1460 rdisc_info.info_type = RDISC_SNMP_INFO_RESPONSE; 1461 rdisc_info.info_version = RDISC_SNMP_INFO_VER; 1462 rdisc_info.info_num_of_routers = num; 1463 1464 (void) sendto(rdisc_mib_sock, &rdisc_info, sizeof (rdisc_info_t), 0, 1465 (struct sockaddr *)&from, fromlen); 1466 1467 for (drp = drs; drp < &drs[max_ads]; drp++) { 1468 if (drp->dr_ts != 0) { 1469 def_router.defr_info_type = RDISC_DEF_ROUTER_INFO; 1470 def_router.defr_version = RDISC_DEF_ROUTER_VER; 1471 def_router.defr_index = 1472 drp->dr_ifp->int_phys->phyi_index; 1473 def_router.defr_life = drp->dr_life; 1474 def_router.defr_addr.s_addr = drp->dr_gate; 1475 def_router.defr_pref = drp->dr_pref; 1476 (void) sendto(rdisc_mib_sock, &def_router, 1477 sizeof (defr_t), 0, (struct sockaddr *)&from, 1478 fromlen); 1479 } 1480 } 1481 } 1482