1 /* 2 * Copyright 2005 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 rts->rts_ifp == &dummy_ifp) { 572 spares_avail = _B_TRUE; 573 break; 574 } 575 } 576 if (!spares_avail) { 577 ptrsize = (rt->rt_num_spares + SPARE_INC) * 578 sizeof (struct rt_spare); 579 ptr = realloc(rt->rt_spares, ptrsize); 580 if (ptr != NULL) { 581 struct rt_spare *tmprts; 582 583 rt->rt_spares = ptr; 584 rts = &rt->rt_spares[rt->rt_num_spares]; 585 (void) memset(rts, 0, 586 (SPARE_INC * sizeof (struct rt_spare))); 587 rt->rt_num_spares += SPARE_INC; 588 for (tmprts = rts, j = SPARE_INC; 589 j != 0; j--, tmprts++) 590 tmprts->rts_metric = HOPCNT_INFINITY; 591 spares_avail = _B_TRUE; 592 } else { 593 return; 594 } 595 } 596 } 597 /* Find the best RDISC advertiser */ 598 rt = NULL; 599 new_drp = NULL; 600 for (drp = drs; drp < &drs[max_ads]; drp++) { 601 if (drp->dr_ts == 0) 602 continue; 603 ifp = drp->dr_ifp; 604 605 /* Get rid of expired discovered routers. */ 606 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 607 del_rdisc(drp); 608 continue; 609 } 610 611 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life); 612 613 /* 614 * Update preference with possibly changed interface 615 * metric. 616 */ 617 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 618 619 /* 620 * Prefer the current route to prevent thrashing. 621 * Prefer shorter lifetimes to speed the detection of 622 * bad routers. 623 * Avoid sick interfaces. 624 */ 625 if (new_drp == NULL || 626 (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) && 627 (new_pref < drp->dr_pref || 628 (new_pref == drp->dr_pref && (drp == cur_drp || 629 (new_drp != cur_drp && 630 new_drp->dr_life > drp->dr_life))))) || 631 ((new_st & IS_SICK) && 632 !(drp->dr_ifp->int_state & IS_SICK))) { 633 new_drp = drp; 634 new_st = drp->dr_ifp->int_state; 635 new_pref = drp->dr_pref; 636 } 637 } 638 639 /* 640 * switch to a better RDISC advertiser 641 */ 642 if ((new_drp != cur_drp) || (rt == NULL)) { 643 rt = rtget(RIP_DEFAULT, 0); 644 645 /* 646 * Purge the table of all the default routes that were 647 * learnt via RDISC, while keeping an eye the first available 648 * slot for the spare entry of new_drp 649 */ 650 if (rt != NULL) { 651 int i; 652 for (i = 0; i < rt->rt_num_spares; i++) { 653 rts = &rt->rt_spares[i]; 654 if ((rts->rts_gate == 0 || 655 rts->rts_ifp == &dummy_ifp) && 656 first_rdisc_slot == 0) 657 first_rdisc_slot = i; 658 if (rts->rts_origin == RO_RDISC) { 659 rts_delete(rt, rts); 660 if (first_rdisc_slot == 0) { 661 first_rdisc_slot = i; 662 } 663 } 664 } 665 } 666 667 /* Stop using RDISC routes if they are all bad */ 668 if (new_drp == NULL) { 669 trace_act("turn off Router Discovery client"); 670 rdisc_ok = _B_FALSE; 671 672 } else { 673 if (cur_drp == NULL) { 674 trace_act("turn on Router Discovery client" 675 " using %s via %s", 676 naddr_ntoa(new_drp->dr_gate), 677 new_drp->dr_ifp->int_name); 678 rdisc_ok = _B_TRUE; 679 } 680 681 /* Prepare a spare entry for the new_drp */ 682 (void) memset(&new, 0, sizeof (new)); 683 new.rts_ifp = new_drp->dr_ifp; 684 new.rts_gate = new_drp->dr_gate; 685 new.rts_router = new_drp->dr_gate; 686 new.rts_metric = HOPCNT_INFINITY-1; 687 new.rts_time = now.tv_sec; 688 new.rts_origin = RO_RDISC; 689 /* 690 * If there is no existing default route, add it 691 * to rts_spare[0]. 692 */ 693 if (rt == NULL) { 694 rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 695 } else { 696 697 /* 698 * Add the spare entry for the new_drp in 699 * the first available slot 700 */ 701 trace_act("Switching to " 702 "default router with better " 703 "preference %s via %s ", 704 naddr_ntoa(new_drp->dr_gate), 705 new_drp->dr_ifp->int_name); 706 rt->rt_spares[first_rdisc_slot] = new; 707 rt = NULL; /* redo rt_spares */ 708 } 709 } 710 711 /* 712 * Get ready to redo the entire table. The table should 713 * only include : 714 * a. empty rt_spare slots 715 * b. default routes learnt via RIP 716 * c. default route for the latest best RDISC advertiser 717 * d. default routes of other RDISC advertisers whose 718 * dr_pref == best RDISC advertiser->dr_pref 719 */ 720 cur_drp = new_drp; 721 } 722 723 /* Redo the entire spare table (without touching RO_RIP entries) */ 724 if (rdisc_ok && rt == NULL) { 725 int i; 726 /* 727 * We've either just turned on router discovery, 728 * or switched to a router with better preference. 729 * Find all other default routers whose 730 * pref == cur_drp->dr_pref and add them as spares 731 */ 732 733 rt = rtget(RIP_DEFAULT, 0); 734 735 for (drp = drs; drp < &drs[max_ads]; drp++) { 736 boolean_t dr_done = _B_FALSE; 737 int slot = -1; 738 739 if (drp->dr_ts == 0) 740 continue; 741 742 if (drp->dr_pref != cur_drp->dr_pref && 743 ((drp->dr_flags & DR_CHANGED) == 0)) 744 continue; 745 746 /* 747 * Either pref matches cur_drp->dr_pref, 748 * or something has changed in this drp. 749 * In the former case, we may need to add 750 * this to rt_spares. In the latter case, 751 * if the pref has changed, need to take it 752 * out of rt_spares and the kernel. 753 * 754 * First, find an empty slot in rt_spares 755 * in case we have to add this drp to kernel. 756 * Also check if it is already there. 757 */ 758 for (i = 0; i < rt->rt_num_spares; i++) { 759 if (rt->rt_spares[i].rts_gate == 0) { 760 if (slot < 0) 761 slot = i; 762 continue; 763 } 764 if ((rt->rt_spares[i].rts_gate == 765 drp->dr_gate) && 766 (rt->rt_spares[i].rts_origin == 767 RO_RDISC)) { 768 /* 769 * a spare entry for this RDISC 770 * advertiser already exists. We need 771 * to check if this entry still belongs 772 * in the table 773 */ 774 dr_done = _B_TRUE; 775 break; 776 } 777 } 778 779 drp->dr_flags &= ~DR_CHANGED; 780 781 if (drp->dr_pref != cur_drp->dr_pref) { 782 if (dr_done) { 783 /* 784 * The rt_spare of this RDISC advertiser 785 * needs to be removed as it no longer 786 * belongs in the table because its 787 * dr_pref is different than the latest 788 * RDISC advertiser's->dr_pref 789 */ 790 rts_delete(rt, &rt->rt_spares[i]); 791 } 792 continue; 793 } 794 795 if (slot < 0 && !dr_done) { 796 ptrsize = (rt->rt_num_spares + SPARE_INC) * 797 sizeof (struct rt_spare); 798 ptr = realloc(rt->rt_spares, ptrsize); 799 if (ptr != NULL) { 800 struct rt_spare *tmprts; 801 802 rt->rt_spares = ptr; 803 slot = rt->rt_num_spares; 804 rts = &rt->rt_spares[rt->rt_num_spares]; 805 (void) memset(rts, 0, (SPARE_INC * 806 sizeof (struct rt_spare))); 807 rt->rt_num_spares += SPARE_INC; 808 for (tmprts = rts, i = SPARE_INC; 809 i != 0; i--, tmprts++) 810 tmprts->rts_metric = 811 HOPCNT_INFINITY; 812 } 813 } 814 815 if (slot >= 0 && (dr_done != _B_TRUE)) { 816 (void) memset(&new, 0, sizeof (new)); 817 new.rts_ifp = drp->dr_ifp; 818 new.rts_gate = drp->dr_gate; 819 new.rts_router = drp->dr_gate; 820 new.rts_metric = HOPCNT_INFINITY-1; 821 new.rts_time = now.tv_sec; 822 new.rts_origin = RO_RDISC; 823 rt->rt_spares[slot] = new; 824 trace_act("spare default %s via %s", 825 naddr_ntoa(drp->dr_gate), 826 drp->dr_ifp->int_name); 827 } 828 } 829 } 830 831 /* turn RIP on or off */ 832 if (!rdisc_ok || rip_interfaces > 1) { 833 rip_on(0); 834 } else { 835 rip_off(); 836 } 837 } 838 839 840 /* Handle a single address in an advertisement */ 841 static void 842 parse_ad(uint32_t from, 843 in_addr_t gate, 844 uint32_t pref, /* signed and in network order */ 845 ushort_t life, /* in host byte order */ 846 struct interface *ifp) 847 { 848 static struct msg_limit bad_gate; 849 struct dr *drp, *new_drp; 850 void *ptr; 851 size_t ptrsize; 852 853 if (gate == RIP_DEFAULT || !check_dst(gate)) { 854 msglim(&bad_gate, from, "router %s advertising bad gateway %s", 855 naddr_ntoa(from), naddr_ntoa(gate)); 856 return; 857 } 858 859 /* 860 * ignore pointers to ourself and routes via unreachable networks 861 */ 862 if (ifwithaddr(gate, _B_TRUE, _B_FALSE) != 0) { 863 trace_pkt(" discard Router Discovery Ad pointing at us"); 864 return; 865 } 866 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 867 trace_pkt(" discard Router Discovery Ad" 868 " toward unreachable net"); 869 return; 870 } 871 /* 872 * Convert preference to an unsigned value 873 * and later bias it by the metric of the interface. 874 */ 875 pref = UNSIGN_PREF(ntohl(pref)); 876 877 if (pref == DEF_PREFERENCELEVEL || life < MIN_MAXADVERTISEINTERVAL) { 878 pref = DEF_PREFERENCELEVEL; 879 life = 0; 880 } 881 882 for (new_drp = NULL, drp = drs; drp < &drs[max_ads]; drp++) { 883 /* accept new info for a familiar entry */ 884 if ((drp->dr_gate == gate) && (drp->dr_ifp == ifp)) { 885 new_drp = drp; 886 drp->dr_flags |= DR_CHANGED; 887 break; 888 } 889 890 if (life == 0) 891 continue; /* do not worry about dead ads */ 892 893 if (drp->dr_ts == 0) { 894 new_drp = drp; /* use unused entry */ 895 896 } else if (new_drp == NULL) { 897 /* look for an entry worse than the new one to reuse. */ 898 if ((!(ifp->int_state & IS_SICK) && 899 (drp->dr_ifp->int_state & IS_SICK)) || 900 (pref > drp->dr_pref && 901 !((ifp->int_state ^ drp->dr_ifp->int_state) & 902 IS_SICK))) 903 new_drp = drp; 904 905 } else if (new_drp->dr_ts != 0) { 906 /* look for the least valuable entry to reuse */ 907 if ((!(new_drp->dr_ifp->int_state & IS_SICK) && 908 (drp->dr_ifp->int_state & IS_SICK)) || 909 (new_drp->dr_pref > drp->dr_pref && 910 !((new_drp->dr_ifp->int_state ^ 911 drp->dr_ifp->int_state) & IS_SICK))) 912 new_drp = drp; 913 } 914 } 915 916 /* if all of the current entries are better, add more drs[] */ 917 if (new_drp == NULL) { 918 ptrsize = (max_ads + MAX_ADS) * sizeof (struct dr); 919 ptr = realloc(drs, ptrsize); 920 if (ptr == NULL) 921 return; 922 drs = ptr; 923 (void) memset(&drs[max_ads], 0, MAX_ADS * sizeof (struct dr)); 924 new_drp = &drs[max_ads]; 925 max_ads += MAX_ADS; 926 } 927 928 /* 929 * Pointer copy is safe here because if_del 930 * calls if_bad_rdisc first, so a non-NULL df_ifp 931 * is always a valid pointer. 932 */ 933 new_drp->dr_ifp = ifp; 934 new_drp->dr_gate = gate; 935 new_drp->dr_ts = now.tv_sec; 936 new_drp->dr_life = life; 937 new_drp->dr_recv_pref = pref; 938 /* bias functional preference by metric of the interface */ 939 new_drp->dr_pref = PREF(pref, ifp); 940 941 /* after hearing a good advertisement, stop asking */ 942 if (!(ifp->int_state & IS_SICK)) 943 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 944 } 945 946 947 /* 948 * Compute the IP checksum. This assumes the packet is less than 32K long. 949 */ 950 static uint16_t 951 in_cksum(uint16_t *p, uint_t len) 952 { 953 uint32_t sum = 0; 954 int nwords = len >> 1; 955 956 while (nwords-- != 0) 957 sum += *p++; 958 959 if (len & 1) 960 sum += *(uchar_t *)p; 961 962 /* end-around-carry */ 963 sum = (sum >> 16) + (sum & 0xffff); 964 sum += (sum >> 16); 965 return (~sum); 966 } 967 968 969 /* Send a router discovery advertisement or solicitation ICMP packet. */ 970 static void 971 send_rdisc(union ad_u *p, 972 uint_t p_size, 973 struct interface *ifp, 974 in_addr_t dst, /* 0 or unicast destination */ 975 dstaddr_t type) 976 { 977 struct sockaddr_in sin; 978 int flags = 0; 979 const char *msg; 980 int ifindex; 981 struct in_addr addr; 982 983 /* 984 * Don't send Rdisc packets on duplicate interfaces, we 985 * don't want to generate duplicate packets. 986 */ 987 if (ifp->int_state & IS_DUP) 988 return; 989 990 (void) memset(&sin, 0, sizeof (sin)); 991 sin.sin_addr.s_addr = dst; 992 sin.sin_family = AF_INET; 993 994 switch (type) { 995 case unicast: /* unicast */ 996 default: 997 flags = MSG_DONTROUTE; 998 msg = "Send"; 999 break; 1000 1001 case bcast: /* broadcast */ 1002 if (ifp->int_if_flags & IFF_POINTOPOINT) { 1003 msg = "Send pt-to-pt"; 1004 if (ifp->int_dstaddr == 0) 1005 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); 1006 else 1007 sin.sin_addr.s_addr = ifp->int_dstaddr; 1008 } else { 1009 msg = "Send broadcast"; 1010 sin.sin_addr.s_addr = ifp->int_brdaddr; 1011 } 1012 break; 1013 1014 case mcast: /* multicast */ 1015 msg = "Send multicast"; 1016 break; 1017 } 1018 1019 if (rdisc_sock < 0) 1020 get_rdisc_sock(); 1021 1022 if (rdisc_sock_interface != ifp) { 1023 /* select the right interface. */ 1024 ifindex = (type != mcast && ifp->int_phys != NULL) ? 1025 ifp->int_phys->phyi_index : 0; 1026 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_XMIT_IF, &ifindex, 1027 sizeof (ifindex)) == -1) { 1028 LOGERR("setsockopt(rdisc_sock, IP_XMIT_IF)"); 1029 return; 1030 } 1031 /* 1032 * For multicast, we have to choose the source 1033 * address. This is either the local address 1034 * (non-point-to-point) or the remote address. 1035 */ 1036 addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 1037 ifp->int_dstaddr : ifp->int_addr; 1038 if (type == mcast && 1039 setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, 1040 sizeof (addr)) == -1) { 1041 LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)"); 1042 return; 1043 } 1044 rdisc_sock_interface = ifp; 1045 } 1046 1047 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size); 1048 1049 if (0 > sendto(rdisc_sock, p, p_size, flags, 1050 (struct sockaddr *)&sin, sizeof (sin))) { 1051 if (!(ifp->int_state & IS_BROKE)) 1052 writelog(LOG_WARNING, "sendto(%s%s%s): %s", 1053 ifp->int_name, ", ", 1054 inet_ntoa(sin.sin_addr), 1055 rip_strerror(errno)); 1056 if (ifp != NULL) 1057 if_sick(ifp, _B_FALSE); 1058 } 1059 } 1060 1061 1062 /* Send an advertisement */ 1063 static void 1064 send_adv(struct interface *ifp, 1065 in_addr_t dst, 1066 dstaddr_t type) 1067 { 1068 union ad_u u; 1069 1070 if ((ifp->int_state & (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC)) == 1071 IS_SUPPRESS_RDISC) 1072 return; 1073 1074 (void) memset(&u, 0, sizeof (u.ad)); 1075 1076 u.ad.icmp_type = ICMP_ROUTERADVERT; 1077 u.ad.icmp_code = ICMP_ROUTERADVERT_COMMON; 1078 u.ad.icmp_ad_num = 1; 1079 u.ad.icmp_ad_asize = sizeof (u.ad.icmp_ad_info[0])/4; 1080 1081 u.ad.icmp_ad_life = (stopint || !should_supply(ifp) || 1082 (ifp->int_state & IS_SUPPRESS_RDISC)) ? 0 : 1083 htons(ifp->int_rdisc_int*3); 1084 1085 /* Send the configured preference as a network byte order value */ 1086 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(ifp->int_rdisc_pref); 1087 1088 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 1089 1090 u.ad.icmp_cksum = in_cksum((uint16_t *)&u.ad, sizeof (u.ad)); 1091 1092 send_rdisc(&u, sizeof (u.ad), ifp, dst, type); 1093 1094 if (ifp->int_state & IS_SUPPRESS_RDISC) 1095 ifp->int_state &= ~IS_FLUSH_RDISC; 1096 } 1097 1098 1099 /* Advertise as a default router by way of router discovery. */ 1100 void 1101 rdisc_adv(boolean_t forceadv) 1102 { 1103 struct interface *ifp; 1104 1105 if (!forceadv && !should_supply(NULL)) 1106 return; 1107 1108 rdisc_timer.tv_sec = now.tv_sec + NEVER; 1109 1110 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 1111 if ((ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)) || 1112 (!forceadv && !IS_IFF_ROUTING(ifp->int_if_flags))) 1113 continue; 1114 1115 /* skip interfaces we shouldn't use */ 1116 if (IS_IFF_QUIET(ifp->int_if_flags)) 1117 continue; 1118 1119 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */) || 1120 stopint != 0 || forceadv) { 1121 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 1122 (ifp->int_state & IS_BCAST_RDISC) ? 1 : 2); 1123 ifp->int_rdisc_cnt++; 1124 1125 intvl_random(&ifp->int_rdisc_timer, 1126 (ifp->int_rdisc_int*3)/4, ifp->int_rdisc_int); 1127 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS && 1128 (ifp->int_rdisc_timer.tv_sec > 1129 MAX_INITIAL_ADVERT_INTERVAL)) { 1130 ifp->int_rdisc_timer.tv_sec = 1131 MAX_INITIAL_ADVERT_INTERVAL; 1132 } 1133 timevaladd(&ifp->int_rdisc_timer, &now); 1134 } 1135 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 1136 > /* cstyle */)) 1137 rdisc_timer = ifp->int_rdisc_timer; 1138 } 1139 } 1140 1141 1142 /* Solicit for Router Discovery */ 1143 void 1144 rdisc_sol(void) 1145 { 1146 struct interface *ifp; 1147 union ad_u u; 1148 1149 if (should_supply(NULL)) 1150 return; 1151 1152 rdisc_timer.tv_sec = now.tv_sec + NEVER; 1153 1154 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 1155 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) || 1156 ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 1157 continue; 1158 1159 /* skip interfaces we shouldn't use */ 1160 if (IS_IFF_QUIET(ifp->int_if_flags)) 1161 continue; 1162 1163 if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */)) { 1164 (void) memset(&u, 0, sizeof (u.so)); 1165 u.so.icmp_type = ICMP_ROUTERSOLICIT; 1166 u.so.icmp_cksum = in_cksum((uint16_t *)&u.so, 1167 sizeof (u.so)); 1168 send_rdisc(&u, sizeof (u.so), ifp, 1169 htonl(INADDR_ALLRTRS_GROUP), 1170 ((ifp->int_state&IS_BCAST_RDISC) ? bcast : mcast)); 1171 1172 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 1173 continue; 1174 1175 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 1176 ifp->int_rdisc_timer.tv_usec = 0; 1177 timevaladd(&ifp->int_rdisc_timer, &now); 1178 } 1179 1180 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 1181 > /* cstyle */)) 1182 rdisc_timer = ifp->int_rdisc_timer; 1183 } 1184 } 1185 1186 1187 /* 1188 * check the IP header of a possible Router Discovery ICMP packet 1189 * Returns 0 if bad 1190 */ 1191 static struct interface * 1192 ck_icmp(const char *act, 1193 in_addr_t from, 1194 struct interface *ifp, 1195 in_addr_t to, 1196 union ad_u *p, 1197 uint_t len) 1198 { 1199 const char *type; 1200 1201 1202 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 1203 type = "advertisement"; 1204 if (p->icmp.icmp_code == ICMP_ROUTERADVERT_NOCOMMON) 1205 return (NULL); /* Mobile IP */ 1206 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 1207 type = "solicitation"; 1208 } else { 1209 return (NULL); 1210 } 1211 1212 if (p->icmp.icmp_code != ICMP_ROUTERADVERT_COMMON) { 1213 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 1214 type, p->icmp.icmp_code, naddr_ntoa(from), naddr_ntoa(to)); 1215 return (NULL); 1216 } 1217 1218 trace_rdisc(act, from, to, ifp, p, len); 1219 1220 if (ifp == NULL) 1221 trace_pkt("unknown interface for router-discovery %s from %s " 1222 "to %s", type, naddr_ntoa(from), naddr_ntoa(to)); 1223 1224 return (ifp); 1225 } 1226 1227 1228 /* Read packets from the router discovery socket */ 1229 void 1230 read_d(void) 1231 { 1232 #define PKTLEN 512 1233 static struct msg_limit bad_asize, bad_len; 1234 struct sockaddr_in from; 1235 int n, cc, hlen; 1236 struct { 1237 union { 1238 struct ip ip; 1239 uint16_t s[PKTLEN/sizeof (uint16_t)]; 1240 uint8_t b[PKTLEN/sizeof (uint8_t)]; 1241 } pkt; 1242 } buf; 1243 union ad_u *p; 1244 n_long *wp; 1245 struct interface *ifp; 1246 boolean_t needsort = _B_FALSE; 1247 struct msghdr msg; 1248 struct iovec iov; 1249 uint8_t ancillary_data[CONTROL_BUFSIZE]; 1250 1251 iov.iov_base = &buf; 1252 iov.iov_len = sizeof (buf); 1253 msg.msg_iov = &iov; 1254 msg.msg_iovlen = 1; 1255 msg.msg_name = &from; 1256 msg.msg_control = &ancillary_data; 1257 1258 for (;;) { 1259 msg.msg_namelen = sizeof (from); 1260 msg.msg_controllen = sizeof (ancillary_data); 1261 cc = recvmsg(rdisc_sock, &msg, 0); 1262 if (cc <= 0) { 1263 if (cc < 0 && errno != EWOULDBLOCK) 1264 LOGERR("recvmsg(rdisc_sock)"); 1265 break; 1266 } 1267 1268 hlen = buf.pkt.ip.ip_hl << 2; 1269 if (cc < hlen + ICMP_MINLEN) 1270 continue; 1271 /* LINTED [alignment will be lw aligned] */ 1272 p = (union ad_u *)&buf.pkt.b[hlen]; 1273 cc -= hlen; 1274 1275 /* 1276 * If we could tell the interface on which a packet from 1277 * address 0 arrived, we could deal with such solicitations. 1278 */ 1279 ifp = receiving_interface(&msg, _B_FALSE); 1280 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 1281 buf.pkt.ip.ip_dst.s_addr, p, cc); 1282 if (ifp == NULL) 1283 continue; 1284 1285 if (IS_IFF_QUIET(ifp->int_if_flags)) { 1286 trace_misc("discard RDISC packet received over %s, %X", 1287 ifp->int_name, ifp->int_if_flags); 1288 continue; 1289 } 1290 1291 if (from.sin_addr.s_addr != 0 && 1292 ifwithaddr(from.sin_addr.s_addr, _B_FALSE, _B_FALSE)) { 1293 trace_pkt(" " 1294 "discard our own Router Discovery message"); 1295 continue; 1296 } 1297 1298 /* The remote address *must* be directly connected. */ 1299 if (!remote_address_ok(ifp, from.sin_addr.s_addr)) { 1300 trace_misc("discard rdisc message; source %s not on " 1301 "interface %s", naddr_ntoa(from.sin_addr.s_addr), 1302 ifp->int_name); 1303 continue; 1304 } 1305 1306 switch (p->icmp.icmp_type) { 1307 case ICMP_ROUTERADVERT: 1308 if (ifp->int_state & IS_NO_ADV_IN) 1309 continue; 1310 1311 if (p->ad.icmp_ad_asize*2*sizeof (wp[0]) < 1312 sizeof (p->ad.icmp_ad_info[0])) { 1313 msglim(&bad_asize, from.sin_addr.s_addr, 1314 "intolerable rdisc address size=%d", 1315 p->ad.icmp_ad_asize); 1316 continue; 1317 } 1318 if (p->ad.icmp_ad_num == 0) { 1319 trace_pkt(" empty?"); 1320 continue; 1321 } 1322 if (cc < (sizeof (p->ad) - 1323 sizeof (p->ad.icmp_ad_info) + 1324 (p->ad.icmp_ad_num * 1325 sizeof (p->ad.icmp_ad_info[0])))) { 1326 msglim(&bad_len, from.sin_addr.s_addr, 1327 "rdisc length %d does not match ad_num" 1328 " %d", cc, p->ad.icmp_ad_num); 1329 continue; 1330 } 1331 1332 needsort = _B_TRUE; 1333 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1334 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1335 parse_ad(from.sin_addr.s_addr, 1336 wp[0], wp[1], 1337 ntohs(p->ad.icmp_ad_life), ifp); 1338 wp += p->ad.icmp_ad_asize; 1339 } 1340 break; 1341 1342 1343 case ICMP_ROUTERSOLICIT: 1344 if (!should_supply(ifp)) 1345 continue; 1346 if ((ifp->int_state & IS_NO_ADV_OUT) || 1347 !IS_IFF_ROUTING(ifp->int_if_flags)) 1348 continue; 1349 if (stopint != 0) 1350 continue; 1351 1352 /* 1353 * We should handle messages from address 0, 1354 * but cannot due to kernel limitations. 1355 */ 1356 1357 /* Respond with a point-to-point advertisement */ 1358 send_adv(ifp, from.sin_addr.s_addr, 0); 1359 break; 1360 } 1361 } 1362 1363 if (needsort) 1364 rdisc_sort(); 1365 } 1366 1367 void 1368 rdisc_dump(void) 1369 { 1370 struct dr *drp; 1371 1372 for (drp = drs; drp < &drs[max_ads]; drp++) 1373 if (drp->dr_ts != 0) 1374 trace_dr(drp); 1375 } 1376 1377 void 1378 rdisc_suppress(struct interface *ifp) 1379 { 1380 if (ifp->int_state & IS_ADV_OUT) { 1381 msglog("%s \"rdisc_adv\" specified, will not " 1382 "suppress rdisc adv", ifp->int_name); 1383 } else { 1384 if (ifp->int_state & IS_SUPPRESS_RDISC) 1385 return; 1386 ifp->int_state |= (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 1387 trace_misc("suppress rdisc adv on %s", ifp->int_name); 1388 rdisc_timer.tv_sec = 0; 1389 } 1390 } 1391 1392 void 1393 rdisc_restore(struct interface *ifp) 1394 { 1395 if ((ifp->int_state & IS_SUPPRESS_RDISC) == 0) 1396 return; 1397 ifp->int_state &= ~(IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 1398 trace_misc("restoring rdisc adv on %s", ifp->int_name); 1399 rdisc_timer.tv_sec = 0; 1400 } 1401