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