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