1 /* 2 * Copyright (c) 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 35 static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; 36 #elif defined(__NetBSD__) 37 static char rcsid[] = "$NetBSD$"; 38 #endif 39 #ident "$Revision: 1.16 $" 40 41 #include "defs.h" 42 #include <netinet/in_systm.h> 43 #include <netinet/ip.h> 44 #include <netinet/ip_icmp.h> 45 46 /* router advertisement ICMP packet */ 47 struct icmp_ad { 48 u_int8_t icmp_type; /* type of message */ 49 u_int8_t icmp_code; /* type sub code */ 50 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 51 u_int8_t icmp_ad_num; /* # of following router addresses */ 52 u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 53 u_int16_t icmp_ad_life; /* seconds of validity */ 54 struct icmp_ad_info { 55 n_long icmp_ad_addr; 56 n_long icmp_ad_pref; 57 } icmp_ad_info[1]; 58 }; 59 60 /* router solicitation ICMP packet */ 61 struct icmp_so { 62 u_int8_t icmp_type; /* type of message */ 63 u_int8_t icmp_code; /* type sub code */ 64 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 65 n_long icmp_so_rsvd; 66 }; 67 68 union ad_u { 69 struct icmp icmp; 70 struct icmp_ad ad; 71 struct icmp_so so; 72 }; 73 74 75 int rdisc_sock = -1; /* router-discovery raw socket */ 76 struct interface *rdisc_sock_mcast; /* current multicast interface */ 77 78 struct timeval rdisc_timer; 79 int rdisc_ok; /* using solicited route */ 80 81 82 #define MAX_ADS 5 83 struct dr { /* accumulated advertisements */ 84 struct interface *dr_ifp; 85 naddr dr_gate; /* gateway */ 86 time_t dr_ts; /* when received */ 87 time_t dr_life; /* lifetime */ 88 n_long dr_recv_pref; /* received but biased preference */ 89 n_long dr_pref; /* preference adjusted by metric */ 90 } *cur_drp, drs[MAX_ADS]; 91 92 /* adjust preference by interface metric without driving it to infinity */ 93 #define PREF(p, ifp) ((p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ 94 : (p) - ((ifp)->int_metric)) 95 96 static void rdisc_sort(void); 97 98 99 /* dump an ICMP Router Discovery Advertisement Message 100 */ 101 static void 102 trace_rdisc(char *act, 103 naddr from, 104 naddr to, 105 struct interface *ifp, 106 union ad_u *p, 107 u_int len) 108 { 109 int i; 110 n_long *wp, *lim; 111 112 113 if (!TRACEPACKETS || ftrace == 0) 114 return; 115 116 lastlog(); 117 118 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 119 (void)fprintf(ftrace, "%s Router Ad" 120 " from %s to %s via %s life=%d\n", 121 act, naddr_ntoa(from), naddr_ntoa(to), 122 ifp ? ifp->int_name : "?", 123 ntohs(p->ad.icmp_ad_life)); 124 if (!TRACECONTENTS) 125 return; 126 127 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 128 lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 129 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 130 (void)fprintf(ftrace, "\t%s preference=%#x", 131 naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 132 wp += p->ad.icmp_ad_asize; 133 } 134 (void)fputc('\n',ftrace); 135 136 } else { 137 trace_act("%s Router Solic. from %s to %s via %s" 138 " value=%#x\n", 139 act, naddr_ntoa(from), naddr_ntoa(to), 140 ifp ? ifp->int_name : "?", 141 ntohl(p->so.icmp_so_rsvd)); 142 } 143 } 144 145 /* prepare Router Discovery socket. 146 */ 147 static void 148 get_rdisc_sock(void) 149 { 150 if (rdisc_sock < 0) { 151 rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 152 if (rdisc_sock < 0) 153 BADERR(1,"rdisc_sock = socket()"); 154 fix_sock(rdisc_sock,"rdisc_sock"); 155 fix_select(); 156 } 157 } 158 159 160 /* Pick multicast group for router-discovery socket 161 */ 162 void 163 set_rdisc_mg(struct interface *ifp, 164 int on) { /* 0=turn it off */ 165 struct ip_mreq m; 166 167 if (rdisc_sock < 0) { 168 /* Create the raw socket so that we can hear at least 169 * broadcast router discovery packets. 170 */ 171 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 172 || !on) 173 return; 174 get_rdisc_sock(); 175 } 176 177 if (!(ifp->int_if_flags & IFF_MULTICAST) 178 || (ifp->int_state & IS_ALIAS)) { 179 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 180 return; 181 } 182 183 #ifdef MCAST_PPP_BUG 184 if (ifp->int_if_flags & IFF_POINTOPOINT) 185 return; 186 #endif 187 bzero(&m, sizeof(m)); 188 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 189 ? ifp->int_dstaddr 190 : ifp->int_addr); 191 if (supplier 192 || (ifp->int_state & IS_NO_ADV_IN) 193 || !on) { 194 /* stop listening to advertisements 195 */ 196 if (ifp->int_state & IS_ALL_HOSTS) { 197 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 198 if (setsockopt(rdisc_sock, IPPROTO_IP, 199 IP_DROP_MEMBERSHIP, 200 &m, sizeof(m)) < 0) 201 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 202 ifp->int_state &= ~IS_ALL_HOSTS; 203 } 204 205 } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 206 /* start listening to advertisements 207 */ 208 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 209 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 210 &m, sizeof(m)) < 0) { 211 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 212 } else { 213 ifp->int_state |= IS_ALL_HOSTS; 214 } 215 } 216 217 if (!supplier 218 || (ifp->int_state & IS_NO_ADV_OUT) 219 || !on) { 220 /* stop listening to solicitations 221 */ 222 if (ifp->int_state & IS_ALL_ROUTERS) { 223 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 224 if (setsockopt(rdisc_sock, IPPROTO_IP, 225 IP_DROP_MEMBERSHIP, 226 &m, sizeof(m)) < 0) 227 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 228 ifp->int_state &= ~IS_ALL_ROUTERS; 229 } 230 231 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 232 /* start hearing solicitations 233 */ 234 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 235 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 236 &m, sizeof(m)) < 0) { 237 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 238 } else { 239 ifp->int_state |= IS_ALL_ROUTERS; 240 } 241 } 242 } 243 244 245 /* start supplying routes 246 */ 247 void 248 set_supplier(void) 249 { 250 struct interface *ifp; 251 struct dr *drp; 252 253 if (supplier_set) 254 return; 255 256 trace_act("start suppying routes\n"); 257 258 /* Forget discovered routes. 259 */ 260 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 261 drp->dr_recv_pref = 0; 262 drp->dr_life = 0; 263 } 264 rdisc_age(0); 265 266 supplier_set = 1; 267 supplier = 1; 268 269 /* Do not start advertising until we have heard some RIP routes */ 270 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 271 272 /* Switch router discovery multicast groups from soliciting 273 * to advertising. 274 */ 275 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 276 if (ifp->int_state & IS_BROKE) 277 continue; 278 ifp->int_rdisc_cnt = 0; 279 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 280 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 281 set_rdisc_mg(ifp, 1); 282 } 283 284 /* get rid of any redirects */ 285 del_redirects(0,0); 286 } 287 288 289 /* age discovered routes and find the best one 290 */ 291 void 292 rdisc_age(naddr bad_gate) 293 { 294 time_t sec; 295 struct dr *drp; 296 297 298 /* If only adverising, then do only that. */ 299 if (supplier) { 300 /* if switching from client to server, get rid of old 301 * default routes. 302 */ 303 if (cur_drp != 0) 304 rdisc_sort(); 305 rdisc_adv(); 306 return; 307 } 308 309 /* If we are being told about a bad router, 310 * then age the discovered default route, and if there is 311 * no alternative, solicite a replacement. 312 */ 313 if (bad_gate != 0) { 314 /* Look for the bad discovered default route. 315 * Age it and note its interface. 316 */ 317 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 318 if (drp->dr_ts == 0) 319 continue; 320 321 /* When we find the bad router, then age the route 322 * to at most SUPPLY_INTERVAL. 323 * This is contrary to RFC 1256, but defends against 324 * black holes. 325 */ 326 if (drp->dr_gate == bad_gate) { 327 sec = (now.tv_sec - drp->dr_life 328 + SUPPLY_INTERVAL); 329 if (drp->dr_ts > sec) { 330 trace_act("age 0.0.0.0 --> %s" 331 " via %s\n", 332 naddr_ntoa(drp->dr_gate), 333 drp->dr_ifp->int_name); 334 drp->dr_ts = sec; 335 } 336 break; 337 } 338 } 339 } 340 341 /* delete old redirected routes to keep the kernel table small 342 */ 343 sec = (cur_drp == 0) ? MaxMaxAdvertiseInterval : cur_drp->dr_life; 344 del_redirects(bad_gate, now.tv_sec-sec); 345 346 rdisc_sol(); 347 348 rdisc_sort(); 349 } 350 351 352 /* Zap all routes discovered via an interface that has gone bad 353 * This should only be called when !(ifp->int_state & IS_ALIAS) 354 */ 355 void 356 if_bad_rdisc(struct interface *ifp) 357 { 358 struct dr *drp; 359 360 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 361 if (drp->dr_ifp != ifp) 362 continue; 363 drp->dr_recv_pref = 0; 364 drp->dr_life = 0; 365 } 366 367 rdisc_sort(); 368 } 369 370 371 /* mark an interface ok for router discovering. 372 */ 373 void 374 if_ok_rdisc(struct interface *ifp) 375 { 376 set_rdisc_mg(ifp, 1); 377 378 ifp->int_rdisc_cnt = 0; 379 ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 380 ? MIN_WAITTIME 381 : MAX_SOLICITATION_DELAY); 382 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 383 rdisc_timer = ifp->int_rdisc_timer; 384 } 385 386 387 /* get rid of a dead discovered router 388 */ 389 static void 390 del_rdisc(struct dr *drp) 391 { 392 struct interface *ifp; 393 int i; 394 395 396 del_redirects(drp->dr_gate, 0); 397 drp->dr_ts = 0; 398 drp->dr_life = 0; 399 400 401 /* Count the other discovered routes on the interface. 402 */ 403 i = 0; 404 ifp = drp->dr_ifp; 405 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 406 if (drp->dr_ts != 0 407 && drp->dr_ifp == ifp) 408 i++; 409 } 410 411 /* If that was the last good discovered router on the interface, 412 * then solicit a new one. 413 * This is contrary to RFC 1256, but defends against black holes. 414 */ 415 if (i == 0 416 && ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 417 trace_act("discovered route is bad" 418 "--re-solicit routers via %s\n", ifp->int_name); 419 ifp->int_rdisc_cnt = 0; 420 ifp->int_rdisc_timer.tv_sec = 0; 421 rdisc_sol(); 422 } 423 } 424 425 426 /* Find the best discovered route, 427 * and discard stale routers. 428 */ 429 static void 430 rdisc_sort(void) 431 { 432 struct dr *drp, *new_drp; 433 struct rt_entry *rt; 434 struct interface *ifp; 435 u_int new_st; 436 n_long new_pref; 437 438 439 /* Find the best discovered route. 440 */ 441 new_drp = 0; 442 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 443 if (drp->dr_ts == 0) 444 continue; 445 ifp = drp->dr_ifp; 446 447 /* Get rid of expired discovered routers. 448 */ 449 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 450 del_rdisc(drp); 451 continue; 452 } 453 454 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 455 456 /* Update preference with possibly changed interface 457 * metric. 458 */ 459 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 460 461 /* Prefer the current route to prevent thrashing. 462 * Prefer shorter lifetimes to speed the detection of 463 * bad routers. 464 * Avoid sick interfaces. 465 */ 466 if (new_drp == 0 467 || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 468 && (new_pref < drp->dr_pref 469 || (new_pref == drp->dr_pref 470 && (drp == cur_drp 471 || (new_drp != cur_drp 472 && new_drp->dr_life > drp->dr_life))))) 473 || ((new_st & IS_SICK) 474 && !(drp->dr_ifp->int_state & IS_SICK))) { 475 new_drp = drp; 476 new_st = drp->dr_ifp->int_state; 477 new_pref = drp->dr_pref; 478 } 479 } 480 481 /* switch to a better default route 482 */ 483 if (new_drp != cur_drp) { 484 rt = rtget(RIP_DEFAULT, 0); 485 486 /* Stop using discovered routes if they are all bad 487 */ 488 if (new_drp == 0) { 489 trace_act("turn off Router Discovery client\n"); 490 rdisc_ok = 0; 491 492 if (rt != 0 493 && (rt->rt_state & RS_RDISC)) { 494 rtchange(rt, rt->rt_state & ~RS_RDISC, 495 rt->rt_gate, rt->rt_router, 496 HOPCNT_INFINITY, 0, rt->rt_ifp, 497 now.tv_sec - GARBAGE_TIME, 0); 498 rtswitch(rt, 0); 499 } 500 501 /* turn on RIP if permitted */ 502 rip_on(0); 503 504 } else { 505 if (cur_drp == 0) { 506 trace_act("turn on Router Discovery client" 507 " using %s via %s\n", 508 naddr_ntoa(new_drp->dr_gate), 509 new_drp->dr_ifp->int_name); 510 511 rdisc_ok = 1; 512 513 } else { 514 trace_act("switch Router Discovery from" 515 " %s via %s to %s via %s\n", 516 naddr_ntoa(cur_drp->dr_gate), 517 cur_drp->dr_ifp->int_name, 518 naddr_ntoa(new_drp->dr_gate), 519 new_drp->dr_ifp->int_name); 520 } 521 522 if (rt != 0) { 523 rtchange(rt, rt->rt_state | RS_RDISC, 524 new_drp->dr_gate, new_drp->dr_gate, 525 0,0, new_drp->dr_ifp, 526 now.tv_sec, 0); 527 } else { 528 rtadd(RIP_DEFAULT, 0, 529 new_drp->dr_gate, new_drp->dr_gate, 530 0, 0, RS_RDISC, new_drp->dr_ifp); 531 } 532 533 /* Now turn off RIP and delete RIP routes, 534 * which might otherwise include the default 535 * we just modified. 536 */ 537 rip_off(); 538 } 539 540 cur_drp = new_drp; 541 } 542 } 543 544 545 /* handle a single address in an advertisement 546 */ 547 static void 548 parse_ad(naddr from, 549 naddr gate, 550 n_long pref, 551 u_short life, 552 struct interface *ifp) 553 { 554 static naddr bad_gate; 555 struct dr *drp, *new_drp; 556 557 558 if (gate == RIP_DEFAULT 559 || !check_dst(gate)) { 560 if (bad_gate != from) { 561 msglog("router %s advertising bad gateway %s", 562 naddr_ntoa(from), 563 naddr_ntoa(gate)); 564 bad_gate = from; 565 } 566 return; 567 } 568 569 /* ignore pointers to ourself and routes via unreachable networks 570 */ 571 if (ifwithaddr(gate, 1, 0) != 0) { 572 trace_pkt("\tdiscard Router Discovery Ad pointing at us\n"); 573 return; 574 } 575 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 576 trace_pkt("\tdiscard Router Discovery Ad" 577 " toward unreachable net\n"); 578 return; 579 } 580 581 /* Convert preference to an unsigned value 582 * and later bias it by the metric of the interface. 583 */ 584 pref = ntohl(pref) ^ MIN_PreferenceLevel; 585 586 if (pref == 0 || life == 0) { 587 pref = 0; 588 life = 0; 589 } 590 591 for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { 592 /* accept new info for a familiar entry 593 */ 594 if (drp->dr_gate == gate) { 595 new_drp = drp; 596 break; 597 } 598 599 if (life == 0) 600 continue; /* do not worry about dead ads */ 601 602 if (drp->dr_ts == 0) { 603 new_drp = drp; /* use unused entry */ 604 605 } else if (new_drp == 0) { 606 /* look for an entry worse than the new one to 607 * reuse. 608 */ 609 if ((!(ifp->int_state & IS_SICK) 610 && (drp->dr_ifp->int_state & IS_SICK)) 611 || (pref > drp->dr_pref 612 && !((ifp->int_state ^ drp->dr_ifp->int_state) 613 & IS_SICK))) 614 new_drp = drp; 615 616 } else if (new_drp->dr_ts != 0) { 617 /* look for the least valueable entry to reuse 618 */ 619 if ((!(new_drp->dr_ifp->int_state & IS_SICK) 620 && (drp->dr_ifp->int_state & IS_SICK)) 621 || (new_drp->dr_pref > drp->dr_pref 622 && !((new_drp->dr_ifp->int_state 623 ^ drp->dr_ifp->int_state) 624 & IS_SICK))) 625 new_drp = drp; 626 } 627 } 628 629 /* forget it if all of the current entries are better */ 630 if (new_drp == 0) 631 return; 632 633 new_drp->dr_ifp = ifp; 634 new_drp->dr_gate = gate; 635 new_drp->dr_ts = now.tv_sec; 636 new_drp->dr_life = ntohs(life); 637 new_drp->dr_recv_pref = pref; 638 /* bias functional preference by metric of the interface */ 639 new_drp->dr_pref = PREF(pref,ifp); 640 641 /* after hearing a good advertisement, stop asking 642 */ 643 if (!(ifp->int_state & IS_SICK)) 644 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 645 } 646 647 648 /* Compute the IP checksum 649 * This assumes the packet is less than 32K long. 650 */ 651 static u_short 652 in_cksum(u_short *p, 653 u_int len) 654 { 655 u_int sum = 0; 656 int nwords = len >> 1; 657 658 while (nwords-- != 0) 659 sum += *p++; 660 661 if (len & 1) 662 sum += *(u_char *)p; 663 664 /* end-around-carry */ 665 sum = (sum >> 16) + (sum & 0xffff); 666 sum += (sum >> 16); 667 return (~sum); 668 } 669 670 671 /* Send a router discovery advertisement or solicitation ICMP packet. 672 */ 673 static void 674 send_rdisc(union ad_u *p, 675 int p_size, 676 struct interface *ifp, 677 naddr dst, /* 0 or unicast destination */ 678 int type) /* 0=unicast, 1=bcast, 2=mcast */ 679 { 680 struct sockaddr_in sin; 681 int flags; 682 char *msg; 683 naddr tgt_mcast; 684 685 686 bzero(&sin, sizeof(sin)); 687 sin.sin_addr.s_addr = dst; 688 sin.sin_family = AF_INET; 689 #ifdef _HAVE_SIN_LEN 690 sin.sin_len = sizeof(sin); 691 #endif 692 flags = MSG_DONTROUTE; 693 694 switch (type) { 695 case 0: /* unicast */ 696 msg = "Send"; 697 break; 698 699 case 1: /* broadcast */ 700 if (ifp->int_if_flags & IFF_POINTOPOINT) { 701 msg = "Send pt-to-pt"; 702 sin.sin_addr.s_addr = ifp->int_dstaddr; 703 } else { 704 msg = "Send broadcast"; 705 sin.sin_addr.s_addr = ifp->int_brdaddr; 706 } 707 break; 708 709 case 2: /* multicast */ 710 msg = "Send multicast"; 711 if (ifp->int_state & IS_DUP) { 712 trace_act("abort multicast output via %s" 713 " with duplicate address\n", 714 ifp->int_name); 715 return; 716 } 717 if (rdisc_sock_mcast != ifp) { 718 /* select the right interface. */ 719 #ifdef MCAST_PPP_BUG 720 /* Do not specifiy the primary interface explicitly 721 * if we have the multicast point-to-point kernel 722 * bug, since the kernel will do the wrong thing 723 * if the local address of a point-to-point link 724 * is the same as the address of an ordinary 725 * interface. 726 */ 727 if (ifp->int_addr == myaddr) { 728 tgt_mcast = 0; 729 } else 730 #endif 731 tgt_mcast = ifp->int_addr; 732 if (0 > setsockopt(rdisc_sock, 733 IPPROTO_IP, IP_MULTICAST_IF, 734 &tgt_mcast, sizeof(tgt_mcast))) { 735 LOGERR("setsockopt(rdisc_sock," 736 "IP_MULTICAST_IF)"); 737 rdisc_sock_mcast = 0; 738 return; 739 } 740 rdisc_sock_mcast = ifp; 741 } 742 flags = 0; 743 break; 744 } 745 746 if (rdisc_sock < 0) 747 get_rdisc_sock(); 748 749 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, 750 p, p_size); 751 752 if (0 > sendto(rdisc_sock, p, p_size, flags, 753 (struct sockaddr *)&sin, sizeof(sin))) { 754 if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 755 msglog("sendto(%s%s%s): %s", 756 ifp != 0 ? ifp->int_name : "", 757 ifp != 0 ? ", " : "", 758 inet_ntoa(sin.sin_addr), 759 strerror(errno)); 760 if (ifp != 0) 761 if_sick(ifp); 762 } 763 } 764 765 766 /* Send an advertisement 767 */ 768 static void 769 send_adv(struct interface *ifp, 770 naddr dst, /* 0 or unicast destination */ 771 int type) /* 0=unicast, 1=bcast, 2=mcast */ 772 { 773 union ad_u u; 774 n_long pref; 775 776 777 bzero(&u,sizeof(u.ad)); 778 779 u.ad.icmp_type = ICMP_ROUTERADVERT; 780 u.ad.icmp_ad_num = 1; 781 u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 782 783 u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 784 pref = ifp->int_rdisc_pref ^ MIN_PreferenceLevel; 785 pref = PREF(pref, ifp) ^ MIN_PreferenceLevel; 786 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(pref); 787 788 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 789 790 u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 791 792 send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 793 } 794 795 796 /* Advertise for Router Discovery 797 */ 798 void 799 rdisc_adv(void) 800 { 801 struct interface *ifp; 802 803 804 rdisc_timer.tv_sec = now.tv_sec + NEVER; 805 806 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 807 if (0 != (ifp->int_state & (IS_NO_ADV_OUT 808 | IS_PASSIVE 809 | IS_ALIAS 810 | IS_BROKE))) 811 continue; 812 813 if (!timercmp(&ifp->int_rdisc_timer, &now, >) 814 || stopint) { 815 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 816 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 817 ifp->int_rdisc_cnt++; 818 819 intvl_random(&ifp->int_rdisc_timer, 820 (ifp->int_rdisc_int*3)/4, 821 ifp->int_rdisc_int); 822 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 823 && (ifp->int_rdisc_timer.tv_sec 824 > MAX_INITIAL_ADVERT_INTERVAL)) { 825 ifp->int_rdisc_timer.tv_sec 826 = MAX_INITIAL_ADVERT_INTERVAL; 827 } 828 timevaladd(&ifp->int_rdisc_timer, &now); 829 } 830 831 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 832 rdisc_timer = ifp->int_rdisc_timer; 833 } 834 } 835 836 837 /* Solicit for Router Discovery 838 */ 839 void 840 rdisc_sol(void) 841 { 842 struct interface *ifp; 843 union ad_u u; 844 845 846 rdisc_timer.tv_sec = now.tv_sec + NEVER; 847 848 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 849 if (0 != (ifp->int_state & (IS_NO_SOL_OUT 850 | IS_PASSIVE 851 | IS_ALIAS 852 | IS_BROKE)) 853 || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 854 continue; 855 856 if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 857 bzero(&u,sizeof(u.so)); 858 u.so.icmp_type = ICMP_ROUTERSOLICIT; 859 u.so.icmp_cksum = in_cksum((u_short*)&u.so, 860 sizeof(u.so)); 861 send_rdisc(&u, sizeof(u.so), ifp, 862 htonl(INADDR_ALLROUTERS_GROUP), 863 ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 864 865 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 866 continue; 867 868 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 869 ifp->int_rdisc_timer.tv_usec = 0; 870 timevaladd(&ifp->int_rdisc_timer, &now); 871 } 872 873 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 874 rdisc_timer = ifp->int_rdisc_timer; 875 } 876 } 877 878 879 /* check the IP header of a possible Router Discovery ICMP packet */ 880 static struct interface * /* 0 if bad */ 881 ck_icmp(char *act, 882 naddr from, 883 naddr to, 884 union ad_u *p, 885 u_int len) 886 { 887 struct interface *ifp; 888 char *type; 889 890 891 /* If we could tell the interface on which a packet from address 0 892 * arrived, we could deal with such solicitations. 893 */ 894 895 ifp = ((from == 0) ? 0 : iflookup(from)); 896 897 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 898 type = "advertisement"; 899 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 900 type = "solicitation"; 901 } else { 902 return 0; 903 } 904 905 if (p->icmp.icmp_code != 0) { 906 trace_pkt("unrecognized ICMP Router" 907 " %s code=%d from %s to %s\n", 908 type, p->icmp.icmp_code, 909 naddr_ntoa(from), naddr_ntoa(to)); 910 return 0; 911 } 912 913 trace_rdisc(act, from, to, ifp, p, len); 914 915 if (ifp == 0) 916 trace_pkt("unknown interface for router-discovery %s" 917 " from %s to %s", 918 type, naddr_ntoa(from), naddr_ntoa(to)); 919 920 return ifp; 921 } 922 923 924 /* read packets from the router discovery socket 925 */ 926 void 927 read_d(void) 928 { 929 static naddr bad_asize, bad_len; 930 struct sockaddr_in from; 931 int n, fromlen, cc, hlen; 932 union { 933 struct ip ip; 934 u_short s[512/2]; 935 u_char b[512]; 936 } pkt; 937 union ad_u *p; 938 n_long *wp; 939 struct interface *ifp; 940 941 942 for (;;) { 943 fromlen = sizeof(from); 944 cc = recvfrom(rdisc_sock, &pkt, sizeof(pkt), 0, 945 (struct sockaddr*)&from, 946 &fromlen); 947 if (cc <= 0) { 948 if (cc < 0 && errno != EWOULDBLOCK) 949 LOGERR("recvfrom(rdisc_sock)"); 950 break; 951 } 952 if (fromlen != sizeof(struct sockaddr_in)) 953 logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 954 fromlen); 955 956 hlen = pkt.ip.ip_hl << 2; 957 if (cc < hlen + ICMP_MINLEN) 958 continue; 959 p = (union ad_u *)&pkt.b[hlen]; 960 cc -= hlen; 961 962 ifp = ck_icmp("Recv", 963 from.sin_addr.s_addr, pkt.ip.ip_dst.s_addr, 964 p, cc); 965 if (ifp == 0) 966 continue; 967 if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 968 trace_pkt("\tdiscard our own Router Discovery msg\n"); 969 continue; 970 } 971 972 switch (p->icmp.icmp_type) { 973 case ICMP_ROUTERADVERT: 974 if (p->ad.icmp_ad_asize*4 975 < sizeof(p->ad.icmp_ad_info[0])) { 976 if (bad_asize != from.sin_addr.s_addr) { 977 msglog("intolerable rdisc address" 978 " size=%d", 979 p->ad.icmp_ad_asize); 980 bad_asize = from.sin_addr.s_addr; 981 } 982 continue; 983 } 984 if (p->ad.icmp_ad_num == 0) { 985 trace_pkt("\tempty?\n"); 986 continue; 987 } 988 if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info) 989 + (p->ad.icmp_ad_num 990 * sizeof(p->ad.icmp_ad_info[0])))) { 991 if (bad_len != from.sin_addr.s_addr) { 992 msglog("rdisc length %d does not" 993 " match ad_num %d", 994 cc, p->ad.icmp_ad_num); 995 bad_len = from.sin_addr.s_addr; 996 } 997 continue; 998 } 999 if (supplier) 1000 continue; 1001 if (ifp->int_state & IS_NO_ADV_IN) 1002 continue; 1003 1004 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1005 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1006 parse_ad(from.sin_addr.s_addr, 1007 wp[0], wp[1], 1008 ntohs(p->ad.icmp_ad_life), 1009 ifp); 1010 wp += p->ad.icmp_ad_asize; 1011 } 1012 break; 1013 1014 1015 case ICMP_ROUTERSOLICIT: 1016 if (!supplier) 1017 continue; 1018 if (ifp->int_state & IS_NO_ADV_OUT) 1019 continue; 1020 1021 /* XXX 1022 * We should handle messages from address 0. 1023 */ 1024 1025 /* Respond with a point-to-point advertisement */ 1026 send_adv(ifp, from.sin_addr.s_addr, 0); 1027 break; 1028 } 1029 } 1030 1031 rdisc_sort(); 1032 } 1033