17b6ab19dSGarrett Wollman /* 27b6ab19dSGarrett Wollman * Copyright (c) 1995 37b6ab19dSGarrett Wollman * The Regents of the University of California. All rights reserved. 47b6ab19dSGarrett Wollman * 57b6ab19dSGarrett Wollman * Redistribution and use in source and binary forms, with or without 67b6ab19dSGarrett Wollman * modification, are permitted provided that the following conditions 77b6ab19dSGarrett Wollman * are met: 87b6ab19dSGarrett Wollman * 1. Redistributions of source code must retain the above copyright 97b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer. 107b6ab19dSGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 117b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer in the 127b6ab19dSGarrett Wollman * documentation and/or other materials provided with the distribution. 137b6ab19dSGarrett Wollman * 3. All advertising materials mentioning features or use of this software 142c7a9781SMark Murray * must display the following acknowledgment: 157b6ab19dSGarrett Wollman * This product includes software developed by the University of 167b6ab19dSGarrett Wollman * California, Berkeley and its contributors. 177b6ab19dSGarrett Wollman * 4. Neither the name of the University nor the names of its contributors 187b6ab19dSGarrett Wollman * may be used to endorse or promote products derived from this software 197b6ab19dSGarrett Wollman * without specific prior written permission. 207b6ab19dSGarrett Wollman * 217b6ab19dSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 227b6ab19dSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 237b6ab19dSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 247b6ab19dSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 257b6ab19dSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 267b6ab19dSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 277b6ab19dSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 287b6ab19dSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 297b6ab19dSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 307b6ab19dSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317b6ab19dSGarrett Wollman * SUCH DAMAGE. 327b6ab19dSGarrett Wollman */ 337b6ab19dSGarrett Wollman 347b6ab19dSGarrett Wollman #include "defs.h" 357b6ab19dSGarrett Wollman #include <netinet/in_systm.h> 367b6ab19dSGarrett Wollman #include <netinet/ip.h> 377b6ab19dSGarrett Wollman #include <netinet/ip_icmp.h> 387b6ab19dSGarrett Wollman 392c7a9781SMark Murray #if !defined(sgi) && !defined(__NetBSD__) 402c7a9781SMark Murray static char sccsid[] __attribute__((unused)) = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; 412c7a9781SMark Murray #elif defined(__NetBSD__) 422c7a9781SMark Murray __RCSID"$NetBSD$"); 432c7a9781SMark Murray #endif 442c7a9781SMark Murray #ident "$Revision: 2.17 $" 452c7a9781SMark Murray 467b6ab19dSGarrett Wollman /* router advertisement ICMP packet */ 477b6ab19dSGarrett Wollman struct icmp_ad { 487b6ab19dSGarrett Wollman u_int8_t icmp_type; /* type of message */ 497b6ab19dSGarrett Wollman u_int8_t icmp_code; /* type sub code */ 507b6ab19dSGarrett Wollman u_int16_t icmp_cksum; /* ones complement cksum of struct */ 517b6ab19dSGarrett Wollman u_int8_t icmp_ad_num; /* # of following router addresses */ 527b6ab19dSGarrett Wollman u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 537b6ab19dSGarrett Wollman u_int16_t icmp_ad_life; /* seconds of validity */ 547b6ab19dSGarrett Wollman struct icmp_ad_info { 557b6ab19dSGarrett Wollman n_long icmp_ad_addr; 567b6ab19dSGarrett Wollman n_long icmp_ad_pref; 577b6ab19dSGarrett Wollman } icmp_ad_info[1]; 587b6ab19dSGarrett Wollman }; 597b6ab19dSGarrett Wollman 607b6ab19dSGarrett Wollman /* router solicitation ICMP packet */ 617b6ab19dSGarrett Wollman struct icmp_so { 627b6ab19dSGarrett Wollman u_int8_t icmp_type; /* type of message */ 637b6ab19dSGarrett Wollman u_int8_t icmp_code; /* type sub code */ 647b6ab19dSGarrett Wollman u_int16_t icmp_cksum; /* ones complement cksum of struct */ 657b6ab19dSGarrett Wollman n_long icmp_so_rsvd; 667b6ab19dSGarrett Wollman }; 677b6ab19dSGarrett Wollman 687b6ab19dSGarrett Wollman union ad_u { 697b6ab19dSGarrett Wollman struct icmp icmp; 707b6ab19dSGarrett Wollman struct icmp_ad ad; 717b6ab19dSGarrett Wollman struct icmp_so so; 727b6ab19dSGarrett Wollman }; 737b6ab19dSGarrett Wollman 747b6ab19dSGarrett Wollman 757b6ab19dSGarrett Wollman int rdisc_sock = -1; /* router-discovery raw socket */ 767b6ab19dSGarrett Wollman struct interface *rdisc_sock_mcast; /* current multicast interface */ 777b6ab19dSGarrett Wollman 787b6ab19dSGarrett Wollman struct timeval rdisc_timer; 797b6ab19dSGarrett Wollman int rdisc_ok; /* using solicited route */ 807b6ab19dSGarrett Wollman 817b6ab19dSGarrett Wollman 822c7a9781SMark Murray #define MAX_ADS 16 /* at least one per interface */ 837b6ab19dSGarrett Wollman struct dr { /* accumulated advertisements */ 847b6ab19dSGarrett Wollman struct interface *dr_ifp; 857b6ab19dSGarrett Wollman naddr dr_gate; /* gateway */ 867b6ab19dSGarrett Wollman time_t dr_ts; /* when received */ 877b6ab19dSGarrett Wollman time_t dr_life; /* lifetime */ 887b6ab19dSGarrett Wollman n_long dr_recv_pref; /* received but biased preference */ 897b6ab19dSGarrett Wollman n_long dr_pref; /* preference adjusted by metric */ 907b6ab19dSGarrett Wollman } *cur_drp, drs[MAX_ADS]; 917b6ab19dSGarrett Wollman 922c7a9781SMark Murray /* convert between signed, balanced around zero, 932c7a9781SMark Murray * and unsigned zero-based preferences */ 942c7a9781SMark Murray #define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) 952c7a9781SMark Murray #define UNSIGN_PREF(p) SIGN_PREF(p) 962c7a9781SMark Murray /* adjust unsigned preference by interface metric, 972c7a9781SMark Murray * without driving it to infinity */ 982c7a9781SMark Murray #define PREF(p, ifp) ((int)(p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ 997b6ab19dSGarrett Wollman : (p) - ((ifp)->int_metric)) 1007b6ab19dSGarrett Wollman 1017b6ab19dSGarrett Wollman static void rdisc_sort(void); 1027b6ab19dSGarrett Wollman 1037b6ab19dSGarrett Wollman 1047b6ab19dSGarrett Wollman /* dump an ICMP Router Discovery Advertisement Message 1057b6ab19dSGarrett Wollman */ 1067b6ab19dSGarrett Wollman static void 1072c7a9781SMark Murray trace_rdisc(const char *act, 1087b6ab19dSGarrett Wollman naddr from, 1097b6ab19dSGarrett Wollman naddr to, 1107b6ab19dSGarrett Wollman struct interface *ifp, 1117b6ab19dSGarrett Wollman union ad_u *p, 1127b6ab19dSGarrett Wollman u_int len) 1137b6ab19dSGarrett Wollman { 1147b6ab19dSGarrett Wollman int i; 1157b6ab19dSGarrett Wollman n_long *wp, *lim; 1167b6ab19dSGarrett Wollman 1177b6ab19dSGarrett Wollman 1187b6ab19dSGarrett Wollman if (!TRACEPACKETS || ftrace == 0) 1197b6ab19dSGarrett Wollman return; 1207b6ab19dSGarrett Wollman 1217b6ab19dSGarrett Wollman lastlog(); 1227b6ab19dSGarrett Wollman 1237b6ab19dSGarrett Wollman if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 1247b6ab19dSGarrett Wollman (void)fprintf(ftrace, "%s Router Ad" 1257b6ab19dSGarrett Wollman " from %s to %s via %s life=%d\n", 1267b6ab19dSGarrett Wollman act, naddr_ntoa(from), naddr_ntoa(to), 1277b6ab19dSGarrett Wollman ifp ? ifp->int_name : "?", 1287b6ab19dSGarrett Wollman ntohs(p->ad.icmp_ad_life)); 1297b6ab19dSGarrett Wollman if (!TRACECONTENTS) 1307b6ab19dSGarrett Wollman return; 1317b6ab19dSGarrett Wollman 1327b6ab19dSGarrett Wollman wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1337b6ab19dSGarrett Wollman lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 1347b6ab19dSGarrett Wollman for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 13571965874SGarrett Wollman (void)fprintf(ftrace, "\t%s preference=%d", 1367b6ab19dSGarrett Wollman naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 1377b6ab19dSGarrett Wollman wp += p->ad.icmp_ad_asize; 1387b6ab19dSGarrett Wollman } 1397b6ab19dSGarrett Wollman (void)fputc('\n',ftrace); 1407b6ab19dSGarrett Wollman 1417b6ab19dSGarrett Wollman } else { 142d5b718b3SGarrett Wollman trace_act("%s Router Solic. from %s to %s via %s value=%#x", 1437b6ab19dSGarrett Wollman act, naddr_ntoa(from), naddr_ntoa(to), 1447b6ab19dSGarrett Wollman ifp ? ifp->int_name : "?", 1452c7a9781SMark Murray (int)ntohl(p->so.icmp_so_rsvd)); 1467b6ab19dSGarrett Wollman } 1477b6ab19dSGarrett Wollman } 1487b6ab19dSGarrett Wollman 1497b6ab19dSGarrett Wollman /* prepare Router Discovery socket. 1507b6ab19dSGarrett Wollman */ 1517b6ab19dSGarrett Wollman static void 1527b6ab19dSGarrett Wollman get_rdisc_sock(void) 1537b6ab19dSGarrett Wollman { 1547b6ab19dSGarrett Wollman if (rdisc_sock < 0) { 1557b6ab19dSGarrett Wollman rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 1567b6ab19dSGarrett Wollman if (rdisc_sock < 0) 1577b6ab19dSGarrett Wollman BADERR(1,"rdisc_sock = socket()"); 1587b6ab19dSGarrett Wollman fix_sock(rdisc_sock,"rdisc_sock"); 1597b6ab19dSGarrett Wollman fix_select(); 1607b6ab19dSGarrett Wollman } 1617b6ab19dSGarrett Wollman } 1627b6ab19dSGarrett Wollman 1637b6ab19dSGarrett Wollman 1647b6ab19dSGarrett Wollman /* Pick multicast group for router-discovery socket 1657b6ab19dSGarrett Wollman */ 1667b6ab19dSGarrett Wollman void 1677b6ab19dSGarrett Wollman set_rdisc_mg(struct interface *ifp, 168d5b718b3SGarrett Wollman int on) /* 0=turn it off */ 169d5b718b3SGarrett Wollman { 1707b6ab19dSGarrett Wollman struct ip_mreq m; 1717b6ab19dSGarrett Wollman 1727b6ab19dSGarrett Wollman if (rdisc_sock < 0) { 1737b6ab19dSGarrett Wollman /* Create the raw socket so that we can hear at least 1747b6ab19dSGarrett Wollman * broadcast router discovery packets. 1757b6ab19dSGarrett Wollman */ 1767b6ab19dSGarrett Wollman if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 1777b6ab19dSGarrett Wollman || !on) 1787b6ab19dSGarrett Wollman return; 1797b6ab19dSGarrett Wollman get_rdisc_sock(); 1807b6ab19dSGarrett Wollman } 1817b6ab19dSGarrett Wollman 182d5b718b3SGarrett Wollman if (!(ifp->int_if_flags & IFF_MULTICAST)) { 1837b6ab19dSGarrett Wollman ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 1847b6ab19dSGarrett Wollman return; 1857b6ab19dSGarrett Wollman } 1867b6ab19dSGarrett Wollman 1877b6ab19dSGarrett Wollman #ifdef MCAST_PPP_BUG 1887b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_POINTOPOINT) 1897b6ab19dSGarrett Wollman return; 1907b6ab19dSGarrett Wollman #endif 1912c7a9781SMark Murray memset(&m, 0, sizeof(m)); 1927b6ab19dSGarrett Wollman m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 1937b6ab19dSGarrett Wollman ? ifp->int_dstaddr 1947b6ab19dSGarrett Wollman : ifp->int_addr); 1957b6ab19dSGarrett Wollman if (supplier 1967b6ab19dSGarrett Wollman || (ifp->int_state & IS_NO_ADV_IN) 1977b6ab19dSGarrett Wollman || !on) { 1987b6ab19dSGarrett Wollman /* stop listening to advertisements 1997b6ab19dSGarrett Wollman */ 2007b6ab19dSGarrett Wollman if (ifp->int_state & IS_ALL_HOSTS) { 2017b6ab19dSGarrett Wollman m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 2027b6ab19dSGarrett Wollman if (setsockopt(rdisc_sock, IPPROTO_IP, 2037b6ab19dSGarrett Wollman IP_DROP_MEMBERSHIP, 2047b6ab19dSGarrett Wollman &m, sizeof(m)) < 0) 2057b6ab19dSGarrett Wollman LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 2067b6ab19dSGarrett Wollman ifp->int_state &= ~IS_ALL_HOSTS; 2077b6ab19dSGarrett Wollman } 2087b6ab19dSGarrett Wollman 2097b6ab19dSGarrett Wollman } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 2107b6ab19dSGarrett Wollman /* start listening to advertisements 2117b6ab19dSGarrett Wollman */ 2127b6ab19dSGarrett Wollman m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 2137b6ab19dSGarrett Wollman if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2147b6ab19dSGarrett Wollman &m, sizeof(m)) < 0) { 2157b6ab19dSGarrett Wollman LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 2167b6ab19dSGarrett Wollman } else { 2177b6ab19dSGarrett Wollman ifp->int_state |= IS_ALL_HOSTS; 2187b6ab19dSGarrett Wollman } 2197b6ab19dSGarrett Wollman } 2207b6ab19dSGarrett Wollman 2217b6ab19dSGarrett Wollman if (!supplier 2227b6ab19dSGarrett Wollman || (ifp->int_state & IS_NO_ADV_OUT) 2237b6ab19dSGarrett Wollman || !on) { 2247b6ab19dSGarrett Wollman /* stop listening to solicitations 2257b6ab19dSGarrett Wollman */ 2267b6ab19dSGarrett Wollman if (ifp->int_state & IS_ALL_ROUTERS) { 2277b6ab19dSGarrett Wollman m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 2287b6ab19dSGarrett Wollman if (setsockopt(rdisc_sock, IPPROTO_IP, 2297b6ab19dSGarrett Wollman IP_DROP_MEMBERSHIP, 2307b6ab19dSGarrett Wollman &m, sizeof(m)) < 0) 2317b6ab19dSGarrett Wollman LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 2327b6ab19dSGarrett Wollman ifp->int_state &= ~IS_ALL_ROUTERS; 2337b6ab19dSGarrett Wollman } 2347b6ab19dSGarrett Wollman 2357b6ab19dSGarrett Wollman } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 2367b6ab19dSGarrett Wollman /* start hearing solicitations 2377b6ab19dSGarrett Wollman */ 2387b6ab19dSGarrett Wollman m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 2397b6ab19dSGarrett Wollman if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2407b6ab19dSGarrett Wollman &m, sizeof(m)) < 0) { 2417b6ab19dSGarrett Wollman LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 2427b6ab19dSGarrett Wollman } else { 2437b6ab19dSGarrett Wollman ifp->int_state |= IS_ALL_ROUTERS; 2447b6ab19dSGarrett Wollman } 2457b6ab19dSGarrett Wollman } 2467b6ab19dSGarrett Wollman } 2477b6ab19dSGarrett Wollman 2487b6ab19dSGarrett Wollman 2497b6ab19dSGarrett Wollman /* start supplying routes 2507b6ab19dSGarrett Wollman */ 2517b6ab19dSGarrett Wollman void 2527b6ab19dSGarrett Wollman set_supplier(void) 2537b6ab19dSGarrett Wollman { 2547b6ab19dSGarrett Wollman struct interface *ifp; 2557b6ab19dSGarrett Wollman struct dr *drp; 2567b6ab19dSGarrett Wollman 2577b6ab19dSGarrett Wollman if (supplier_set) 2587b6ab19dSGarrett Wollman return; 2597b6ab19dSGarrett Wollman 2602c7a9781SMark Murray trace_act("start supplying routes"); 2617b6ab19dSGarrett Wollman 2627b6ab19dSGarrett Wollman /* Forget discovered routes. 2637b6ab19dSGarrett Wollman */ 2647b6ab19dSGarrett Wollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 2657b6ab19dSGarrett Wollman drp->dr_recv_pref = 0; 2667b6ab19dSGarrett Wollman drp->dr_life = 0; 2677b6ab19dSGarrett Wollman } 2687b6ab19dSGarrett Wollman rdisc_age(0); 2697b6ab19dSGarrett Wollman 2707b6ab19dSGarrett Wollman supplier_set = 1; 2717b6ab19dSGarrett Wollman supplier = 1; 2727b6ab19dSGarrett Wollman 2737b6ab19dSGarrett Wollman /* Do not start advertising until we have heard some RIP routes */ 2747b6ab19dSGarrett Wollman LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 2757b6ab19dSGarrett Wollman 2767b6ab19dSGarrett Wollman /* Switch router discovery multicast groups from soliciting 2777b6ab19dSGarrett Wollman * to advertising. 2787b6ab19dSGarrett Wollman */ 2797b6ab19dSGarrett Wollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 2807b6ab19dSGarrett Wollman if (ifp->int_state & IS_BROKE) 2817b6ab19dSGarrett Wollman continue; 2827b6ab19dSGarrett Wollman ifp->int_rdisc_cnt = 0; 2837b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 2847b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 2857b6ab19dSGarrett Wollman set_rdisc_mg(ifp, 1); 2867b6ab19dSGarrett Wollman } 2877b6ab19dSGarrett Wollman 2887b6ab19dSGarrett Wollman /* get rid of any redirects */ 2897b6ab19dSGarrett Wollman del_redirects(0,0); 2907b6ab19dSGarrett Wollman } 2917b6ab19dSGarrett Wollman 2927b6ab19dSGarrett Wollman 2937b6ab19dSGarrett Wollman /* age discovered routes and find the best one 2947b6ab19dSGarrett Wollman */ 2957b6ab19dSGarrett Wollman void 2967b6ab19dSGarrett Wollman rdisc_age(naddr bad_gate) 2977b6ab19dSGarrett Wollman { 2987b6ab19dSGarrett Wollman time_t sec; 2997b6ab19dSGarrett Wollman struct dr *drp; 3007b6ab19dSGarrett Wollman 3017b6ab19dSGarrett Wollman 3022c7a9781SMark Murray /* If only advertising, then do only that. */ 3037b6ab19dSGarrett Wollman if (supplier) { 3042c7a9781SMark Murray /* If switching from client to server, get rid of old 3057b6ab19dSGarrett Wollman * default routes. 3067b6ab19dSGarrett Wollman */ 3077b6ab19dSGarrett Wollman if (cur_drp != 0) 3087b6ab19dSGarrett Wollman rdisc_sort(); 3097b6ab19dSGarrett Wollman rdisc_adv(); 3107b6ab19dSGarrett Wollman return; 3117b6ab19dSGarrett Wollman } 3127b6ab19dSGarrett Wollman 3137b6ab19dSGarrett Wollman /* If we are being told about a bad router, 3147b6ab19dSGarrett Wollman * then age the discovered default route, and if there is 3152c7a9781SMark Murray * no alternative, solicit a replacement. 3167b6ab19dSGarrett Wollman */ 3177b6ab19dSGarrett Wollman if (bad_gate != 0) { 3187b6ab19dSGarrett Wollman /* Look for the bad discovered default route. 3197b6ab19dSGarrett Wollman * Age it and note its interface. 3207b6ab19dSGarrett Wollman */ 3217b6ab19dSGarrett Wollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 3227b6ab19dSGarrett Wollman if (drp->dr_ts == 0) 3237b6ab19dSGarrett Wollman continue; 3247b6ab19dSGarrett Wollman 3257b6ab19dSGarrett Wollman /* When we find the bad router, then age the route 3267b6ab19dSGarrett Wollman * to at most SUPPLY_INTERVAL. 3277b6ab19dSGarrett Wollman * This is contrary to RFC 1256, but defends against 3287b6ab19dSGarrett Wollman * black holes. 3297b6ab19dSGarrett Wollman */ 3307b6ab19dSGarrett Wollman if (drp->dr_gate == bad_gate) { 3317b6ab19dSGarrett Wollman sec = (now.tv_sec - drp->dr_life 3327b6ab19dSGarrett Wollman + SUPPLY_INTERVAL); 3337b6ab19dSGarrett Wollman if (drp->dr_ts > sec) { 334d5b718b3SGarrett Wollman trace_act("age 0.0.0.0 --> %s via %s", 3357b6ab19dSGarrett Wollman naddr_ntoa(drp->dr_gate), 3367b6ab19dSGarrett Wollman drp->dr_ifp->int_name); 3377b6ab19dSGarrett Wollman drp->dr_ts = sec; 3387b6ab19dSGarrett Wollman } 3397b6ab19dSGarrett Wollman break; 3407b6ab19dSGarrett Wollman } 3417b6ab19dSGarrett Wollman } 3427b6ab19dSGarrett Wollman } 3437b6ab19dSGarrett Wollman 3447b6ab19dSGarrett Wollman rdisc_sol(); 3457b6ab19dSGarrett Wollman rdisc_sort(); 3462c7a9781SMark Murray 3472c7a9781SMark Murray /* Delete old redirected routes to keep the kernel table small, 3482c7a9781SMark Murray * and to prevent black holes. Check that the kernel table 3492c7a9781SMark Murray * matches the daemon table (i.e. has the default route). 3502c7a9781SMark Murray * But only if RIP is not running and we are not dealing with 3512c7a9781SMark Murray * a bad gateway, since otherwise age() will be called. 3522c7a9781SMark Murray */ 3532c7a9781SMark Murray if (rip_sock < 0 && bad_gate == 0) 3542c7a9781SMark Murray age(0); 3557b6ab19dSGarrett Wollman } 3567b6ab19dSGarrett Wollman 3577b6ab19dSGarrett Wollman 3587b6ab19dSGarrett Wollman /* Zap all routes discovered via an interface that has gone bad 3597b6ab19dSGarrett Wollman * This should only be called when !(ifp->int_state & IS_ALIAS) 3607b6ab19dSGarrett Wollman */ 3617b6ab19dSGarrett Wollman void 3627b6ab19dSGarrett Wollman if_bad_rdisc(struct interface *ifp) 3637b6ab19dSGarrett Wollman { 3647b6ab19dSGarrett Wollman struct dr *drp; 3657b6ab19dSGarrett Wollman 3667b6ab19dSGarrett Wollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 3677b6ab19dSGarrett Wollman if (drp->dr_ifp != ifp) 3687b6ab19dSGarrett Wollman continue; 3697b6ab19dSGarrett Wollman drp->dr_recv_pref = 0; 3702c7a9781SMark Murray drp->dr_ts = 0; 3717b6ab19dSGarrett Wollman drp->dr_life = 0; 3727b6ab19dSGarrett Wollman } 3737b6ab19dSGarrett Wollman 3742c7a9781SMark Murray /* make a note to re-solicit, turn RIP on or off, etc. */ 3752c7a9781SMark Murray rdisc_timer.tv_sec = 0; 3767b6ab19dSGarrett Wollman } 3777b6ab19dSGarrett Wollman 3787b6ab19dSGarrett Wollman 3797b6ab19dSGarrett Wollman /* mark an interface ok for router discovering. 3807b6ab19dSGarrett Wollman */ 3817b6ab19dSGarrett Wollman void 3827b6ab19dSGarrett Wollman if_ok_rdisc(struct interface *ifp) 3837b6ab19dSGarrett Wollman { 3847b6ab19dSGarrett Wollman set_rdisc_mg(ifp, 1); 3857b6ab19dSGarrett Wollman 3867b6ab19dSGarrett Wollman ifp->int_rdisc_cnt = 0; 3877b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 3887b6ab19dSGarrett Wollman ? MIN_WAITTIME 3897b6ab19dSGarrett Wollman : MAX_SOLICITATION_DELAY); 3907b6ab19dSGarrett Wollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 3917b6ab19dSGarrett Wollman rdisc_timer = ifp->int_rdisc_timer; 3927b6ab19dSGarrett Wollman } 3937b6ab19dSGarrett Wollman 3947b6ab19dSGarrett Wollman 3957b6ab19dSGarrett Wollman /* get rid of a dead discovered router 3967b6ab19dSGarrett Wollman */ 3977b6ab19dSGarrett Wollman static void 3987b6ab19dSGarrett Wollman del_rdisc(struct dr *drp) 3997b6ab19dSGarrett Wollman { 4007b6ab19dSGarrett Wollman struct interface *ifp; 4012c7a9781SMark Murray naddr gate; 4027b6ab19dSGarrett Wollman int i; 4037b6ab19dSGarrett Wollman 4047b6ab19dSGarrett Wollman 4052c7a9781SMark Murray del_redirects(gate = drp->dr_gate, 0); 4067b6ab19dSGarrett Wollman drp->dr_ts = 0; 4077b6ab19dSGarrett Wollman drp->dr_life = 0; 4087b6ab19dSGarrett Wollman 4097b6ab19dSGarrett Wollman 4107b6ab19dSGarrett Wollman /* Count the other discovered routes on the interface. 4117b6ab19dSGarrett Wollman */ 4127b6ab19dSGarrett Wollman i = 0; 4137b6ab19dSGarrett Wollman ifp = drp->dr_ifp; 4147b6ab19dSGarrett Wollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 4157b6ab19dSGarrett Wollman if (drp->dr_ts != 0 4167b6ab19dSGarrett Wollman && drp->dr_ifp == ifp) 4177b6ab19dSGarrett Wollman i++; 4187b6ab19dSGarrett Wollman } 4197b6ab19dSGarrett Wollman 4207b6ab19dSGarrett Wollman /* If that was the last good discovered router on the interface, 4217b6ab19dSGarrett Wollman * then solicit a new one. 4227b6ab19dSGarrett Wollman * This is contrary to RFC 1256, but defends against black holes. 4237b6ab19dSGarrett Wollman */ 4242c7a9781SMark Murray if (i != 0) { 4252c7a9781SMark Murray trace_act("discovered router %s via %s" 4262c7a9781SMark Murray " is bad--have %d remaining", 4272c7a9781SMark Murray naddr_ntoa(gate), ifp->int_name, i); 4282c7a9781SMark Murray } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 4292c7a9781SMark Murray trace_act("last discovered router %s via %s" 4302c7a9781SMark Murray " is bad--re-solicit", 4312c7a9781SMark Murray naddr_ntoa(gate), ifp->int_name); 4327b6ab19dSGarrett Wollman ifp->int_rdisc_cnt = 0; 4337b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_sec = 0; 4347b6ab19dSGarrett Wollman rdisc_sol(); 4352c7a9781SMark Murray } else { 4362c7a9781SMark Murray trace_act("last discovered router %s via %s" 4372c7a9781SMark Murray " is bad--wait to solicit", 4382c7a9781SMark Murray naddr_ntoa(gate), ifp->int_name); 4397b6ab19dSGarrett Wollman } 4407b6ab19dSGarrett Wollman } 4417b6ab19dSGarrett Wollman 4427b6ab19dSGarrett Wollman 4437b6ab19dSGarrett Wollman /* Find the best discovered route, 4447b6ab19dSGarrett Wollman * and discard stale routers. 4457b6ab19dSGarrett Wollman */ 4467b6ab19dSGarrett Wollman static void 4477b6ab19dSGarrett Wollman rdisc_sort(void) 4487b6ab19dSGarrett Wollman { 4497b6ab19dSGarrett Wollman struct dr *drp, *new_drp; 4507b6ab19dSGarrett Wollman struct rt_entry *rt; 4512c7a9781SMark Murray struct rt_spare new; 4527b6ab19dSGarrett Wollman struct interface *ifp; 4532c7a9781SMark Murray u_int new_st = 0; 4542c7a9781SMark Murray n_long new_pref = 0; 4557b6ab19dSGarrett Wollman 4567b6ab19dSGarrett Wollman 4577b6ab19dSGarrett Wollman /* Find the best discovered route. 4587b6ab19dSGarrett Wollman */ 4597b6ab19dSGarrett Wollman new_drp = 0; 4607b6ab19dSGarrett Wollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 4617b6ab19dSGarrett Wollman if (drp->dr_ts == 0) 4627b6ab19dSGarrett Wollman continue; 4637b6ab19dSGarrett Wollman ifp = drp->dr_ifp; 4647b6ab19dSGarrett Wollman 4657b6ab19dSGarrett Wollman /* Get rid of expired discovered routers. 4667b6ab19dSGarrett Wollman */ 4677b6ab19dSGarrett Wollman if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 4687b6ab19dSGarrett Wollman del_rdisc(drp); 4697b6ab19dSGarrett Wollman continue; 4707b6ab19dSGarrett Wollman } 4717b6ab19dSGarrett Wollman 4727b6ab19dSGarrett Wollman LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 4737b6ab19dSGarrett Wollman 4747b6ab19dSGarrett Wollman /* Update preference with possibly changed interface 4757b6ab19dSGarrett Wollman * metric. 4767b6ab19dSGarrett Wollman */ 4777b6ab19dSGarrett Wollman drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 4787b6ab19dSGarrett Wollman 4797b6ab19dSGarrett Wollman /* Prefer the current route to prevent thrashing. 4807b6ab19dSGarrett Wollman * Prefer shorter lifetimes to speed the detection of 4817b6ab19dSGarrett Wollman * bad routers. 4827b6ab19dSGarrett Wollman * Avoid sick interfaces. 4837b6ab19dSGarrett Wollman */ 4847b6ab19dSGarrett Wollman if (new_drp == 0 4857b6ab19dSGarrett Wollman || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 4867b6ab19dSGarrett Wollman && (new_pref < drp->dr_pref 4877b6ab19dSGarrett Wollman || (new_pref == drp->dr_pref 4887b6ab19dSGarrett Wollman && (drp == cur_drp 4897b6ab19dSGarrett Wollman || (new_drp != cur_drp 4907b6ab19dSGarrett Wollman && new_drp->dr_life > drp->dr_life))))) 4917b6ab19dSGarrett Wollman || ((new_st & IS_SICK) 4927b6ab19dSGarrett Wollman && !(drp->dr_ifp->int_state & IS_SICK))) { 4937b6ab19dSGarrett Wollman new_drp = drp; 4947b6ab19dSGarrett Wollman new_st = drp->dr_ifp->int_state; 4957b6ab19dSGarrett Wollman new_pref = drp->dr_pref; 4967b6ab19dSGarrett Wollman } 4977b6ab19dSGarrett Wollman } 4987b6ab19dSGarrett Wollman 4997b6ab19dSGarrett Wollman /* switch to a better default route 5007b6ab19dSGarrett Wollman */ 5017b6ab19dSGarrett Wollman if (new_drp != cur_drp) { 5027b6ab19dSGarrett Wollman rt = rtget(RIP_DEFAULT, 0); 5037b6ab19dSGarrett Wollman 5047b6ab19dSGarrett Wollman /* Stop using discovered routes if they are all bad 5057b6ab19dSGarrett Wollman */ 5067b6ab19dSGarrett Wollman if (new_drp == 0) { 507d5b718b3SGarrett Wollman trace_act("turn off Router Discovery client"); 5087b6ab19dSGarrett Wollman rdisc_ok = 0; 5097b6ab19dSGarrett Wollman 5107b6ab19dSGarrett Wollman if (rt != 0 5117b6ab19dSGarrett Wollman && (rt->rt_state & RS_RDISC)) { 5122c7a9781SMark Murray new = rt->rt_spares[0]; 5132c7a9781SMark Murray new.rts_metric = HOPCNT_INFINITY; 5142c7a9781SMark Murray new.rts_time = now.tv_sec - GARBAGE_TIME; 5157b6ab19dSGarrett Wollman rtchange(rt, rt->rt_state & ~RS_RDISC, 5162c7a9781SMark Murray &new, 0); 5177b6ab19dSGarrett Wollman rtswitch(rt, 0); 5187b6ab19dSGarrett Wollman } 5197b6ab19dSGarrett Wollman 5207b6ab19dSGarrett Wollman } else { 5217b6ab19dSGarrett Wollman if (cur_drp == 0) { 5227b6ab19dSGarrett Wollman trace_act("turn on Router Discovery client" 523d5b718b3SGarrett Wollman " using %s via %s", 5247b6ab19dSGarrett Wollman naddr_ntoa(new_drp->dr_gate), 5257b6ab19dSGarrett Wollman new_drp->dr_ifp->int_name); 5267b6ab19dSGarrett Wollman rdisc_ok = 1; 5277b6ab19dSGarrett Wollman 5287b6ab19dSGarrett Wollman } else { 5297b6ab19dSGarrett Wollman trace_act("switch Router Discovery from" 530d5b718b3SGarrett Wollman " %s via %s to %s via %s", 5317b6ab19dSGarrett Wollman naddr_ntoa(cur_drp->dr_gate), 5327b6ab19dSGarrett Wollman cur_drp->dr_ifp->int_name, 5337b6ab19dSGarrett Wollman naddr_ntoa(new_drp->dr_gate), 5347b6ab19dSGarrett Wollman new_drp->dr_ifp->int_name); 5357b6ab19dSGarrett Wollman } 5367b6ab19dSGarrett Wollman 5372c7a9781SMark Murray memset(&new, 0, sizeof(new)); 5382c7a9781SMark Murray new.rts_ifp = new_drp->dr_ifp; 5392c7a9781SMark Murray new.rts_gate = new_drp->dr_gate; 5402c7a9781SMark Murray new.rts_router = new_drp->dr_gate; 5412c7a9781SMark Murray new.rts_metric = HOPCNT_INFINITY-1; 5422c7a9781SMark Murray new.rts_time = now.tv_sec; 5437b6ab19dSGarrett Wollman if (rt != 0) { 5442c7a9781SMark Murray rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); 5457b6ab19dSGarrett Wollman } else { 5462c7a9781SMark Murray rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); 5477b6ab19dSGarrett Wollman } 5487b6ab19dSGarrett Wollman } 5497b6ab19dSGarrett Wollman 5507b6ab19dSGarrett Wollman cur_drp = new_drp; 5517b6ab19dSGarrett Wollman } 5522c7a9781SMark Murray 5532c7a9781SMark Murray /* turn RIP on or off */ 5542c7a9781SMark Murray if (!rdisc_ok || rip_interfaces > 1) { 5552c7a9781SMark Murray rip_on(0); 5562c7a9781SMark Murray } else { 5572c7a9781SMark Murray rip_off(); 5582c7a9781SMark Murray } 5597b6ab19dSGarrett Wollman } 5607b6ab19dSGarrett Wollman 5617b6ab19dSGarrett Wollman 5627b6ab19dSGarrett Wollman /* handle a single address in an advertisement 5637b6ab19dSGarrett Wollman */ 5647b6ab19dSGarrett Wollman static void 5657b6ab19dSGarrett Wollman parse_ad(naddr from, 5667b6ab19dSGarrett Wollman naddr gate, 5672c7a9781SMark Murray n_long pref, /* signed and in network order */ 5687b6ab19dSGarrett Wollman u_short life, 5697b6ab19dSGarrett Wollman struct interface *ifp) 5707b6ab19dSGarrett Wollman { 571d5b718b3SGarrett Wollman static struct msg_limit bad_gate; 5727b6ab19dSGarrett Wollman struct dr *drp, *new_drp; 5737b6ab19dSGarrett Wollman 5747b6ab19dSGarrett Wollman 5757b6ab19dSGarrett Wollman if (gate == RIP_DEFAULT 5767b6ab19dSGarrett Wollman || !check_dst(gate)) { 577d5b718b3SGarrett Wollman msglim(&bad_gate, from,"router %s advertising bad gateway %s", 5787b6ab19dSGarrett Wollman naddr_ntoa(from), 5797b6ab19dSGarrett Wollman naddr_ntoa(gate)); 5807b6ab19dSGarrett Wollman return; 5817b6ab19dSGarrett Wollman } 5827b6ab19dSGarrett Wollman 5837b6ab19dSGarrett Wollman /* ignore pointers to ourself and routes via unreachable networks 5847b6ab19dSGarrett Wollman */ 5857b6ab19dSGarrett Wollman if (ifwithaddr(gate, 1, 0) != 0) { 586d5b718b3SGarrett Wollman trace_pkt(" discard Router Discovery Ad pointing at us"); 5877b6ab19dSGarrett Wollman return; 5887b6ab19dSGarrett Wollman } 5897b6ab19dSGarrett Wollman if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 590d5b718b3SGarrett Wollman trace_pkt(" discard Router Discovery Ad" 591d5b718b3SGarrett Wollman " toward unreachable net"); 5927b6ab19dSGarrett Wollman return; 5937b6ab19dSGarrett Wollman } 5947b6ab19dSGarrett Wollman 5957b6ab19dSGarrett Wollman /* Convert preference to an unsigned value 5967b6ab19dSGarrett Wollman * and later bias it by the metric of the interface. 5977b6ab19dSGarrett Wollman */ 5982c7a9781SMark Murray pref = UNSIGN_PREF(ntohl(pref)); 5997b6ab19dSGarrett Wollman 6002c7a9781SMark Murray if (pref == 0 || life < MinMaxAdvertiseInterval) { 6017b6ab19dSGarrett Wollman pref = 0; 6027b6ab19dSGarrett Wollman life = 0; 6037b6ab19dSGarrett Wollman } 6047b6ab19dSGarrett Wollman 6057b6ab19dSGarrett Wollman for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { 6067b6ab19dSGarrett Wollman /* accept new info for a familiar entry 6077b6ab19dSGarrett Wollman */ 6087b6ab19dSGarrett Wollman if (drp->dr_gate == gate) { 6097b6ab19dSGarrett Wollman new_drp = drp; 6107b6ab19dSGarrett Wollman break; 6117b6ab19dSGarrett Wollman } 6127b6ab19dSGarrett Wollman 6137b6ab19dSGarrett Wollman if (life == 0) 6147b6ab19dSGarrett Wollman continue; /* do not worry about dead ads */ 6157b6ab19dSGarrett Wollman 6167b6ab19dSGarrett Wollman if (drp->dr_ts == 0) { 6177b6ab19dSGarrett Wollman new_drp = drp; /* use unused entry */ 6187b6ab19dSGarrett Wollman 6197b6ab19dSGarrett Wollman } else if (new_drp == 0) { 6207b6ab19dSGarrett Wollman /* look for an entry worse than the new one to 6217b6ab19dSGarrett Wollman * reuse. 6227b6ab19dSGarrett Wollman */ 6237b6ab19dSGarrett Wollman if ((!(ifp->int_state & IS_SICK) 6247b6ab19dSGarrett Wollman && (drp->dr_ifp->int_state & IS_SICK)) 6257b6ab19dSGarrett Wollman || (pref > drp->dr_pref 6267b6ab19dSGarrett Wollman && !((ifp->int_state ^ drp->dr_ifp->int_state) 6277b6ab19dSGarrett Wollman & IS_SICK))) 6287b6ab19dSGarrett Wollman new_drp = drp; 6297b6ab19dSGarrett Wollman 6307b6ab19dSGarrett Wollman } else if (new_drp->dr_ts != 0) { 6312c7a9781SMark Murray /* look for the least valuable entry to reuse 6327b6ab19dSGarrett Wollman */ 6337b6ab19dSGarrett Wollman if ((!(new_drp->dr_ifp->int_state & IS_SICK) 6347b6ab19dSGarrett Wollman && (drp->dr_ifp->int_state & IS_SICK)) 6357b6ab19dSGarrett Wollman || (new_drp->dr_pref > drp->dr_pref 6367b6ab19dSGarrett Wollman && !((new_drp->dr_ifp->int_state 6377b6ab19dSGarrett Wollman ^ drp->dr_ifp->int_state) 6387b6ab19dSGarrett Wollman & IS_SICK))) 6397b6ab19dSGarrett Wollman new_drp = drp; 6407b6ab19dSGarrett Wollman } 6417b6ab19dSGarrett Wollman } 6427b6ab19dSGarrett Wollman 6437b6ab19dSGarrett Wollman /* forget it if all of the current entries are better */ 6447b6ab19dSGarrett Wollman if (new_drp == 0) 6457b6ab19dSGarrett Wollman return; 6467b6ab19dSGarrett Wollman 6477b6ab19dSGarrett Wollman new_drp->dr_ifp = ifp; 6487b6ab19dSGarrett Wollman new_drp->dr_gate = gate; 6497b6ab19dSGarrett Wollman new_drp->dr_ts = now.tv_sec; 6507b6ab19dSGarrett Wollman new_drp->dr_life = ntohs(life); 6517b6ab19dSGarrett Wollman new_drp->dr_recv_pref = pref; 6527b6ab19dSGarrett Wollman /* bias functional preference by metric of the interface */ 6537b6ab19dSGarrett Wollman new_drp->dr_pref = PREF(pref,ifp); 6547b6ab19dSGarrett Wollman 6557b6ab19dSGarrett Wollman /* after hearing a good advertisement, stop asking 6567b6ab19dSGarrett Wollman */ 6577b6ab19dSGarrett Wollman if (!(ifp->int_state & IS_SICK)) 6587b6ab19dSGarrett Wollman ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 6597b6ab19dSGarrett Wollman } 6607b6ab19dSGarrett Wollman 6617b6ab19dSGarrett Wollman 6627b6ab19dSGarrett Wollman /* Compute the IP checksum 6637b6ab19dSGarrett Wollman * This assumes the packet is less than 32K long. 6647b6ab19dSGarrett Wollman */ 6657b6ab19dSGarrett Wollman static u_short 6667b6ab19dSGarrett Wollman in_cksum(u_short *p, 6677b6ab19dSGarrett Wollman u_int len) 6687b6ab19dSGarrett Wollman { 6697b6ab19dSGarrett Wollman u_int sum = 0; 6707b6ab19dSGarrett Wollman int nwords = len >> 1; 6717b6ab19dSGarrett Wollman 6727b6ab19dSGarrett Wollman while (nwords-- != 0) 6737b6ab19dSGarrett Wollman sum += *p++; 6747b6ab19dSGarrett Wollman 6757b6ab19dSGarrett Wollman if (len & 1) 6767b6ab19dSGarrett Wollman sum += *(u_char *)p; 6777b6ab19dSGarrett Wollman 6787b6ab19dSGarrett Wollman /* end-around-carry */ 6797b6ab19dSGarrett Wollman sum = (sum >> 16) + (sum & 0xffff); 6807b6ab19dSGarrett Wollman sum += (sum >> 16); 6817b6ab19dSGarrett Wollman return (~sum); 6827b6ab19dSGarrett Wollman } 6837b6ab19dSGarrett Wollman 6847b6ab19dSGarrett Wollman 6857b6ab19dSGarrett Wollman /* Send a router discovery advertisement or solicitation ICMP packet. 6867b6ab19dSGarrett Wollman */ 6877b6ab19dSGarrett Wollman static void 6887b6ab19dSGarrett Wollman send_rdisc(union ad_u *p, 6897b6ab19dSGarrett Wollman int p_size, 6907b6ab19dSGarrett Wollman struct interface *ifp, 6917b6ab19dSGarrett Wollman naddr dst, /* 0 or unicast destination */ 6927b6ab19dSGarrett Wollman int type) /* 0=unicast, 1=bcast, 2=mcast */ 6937b6ab19dSGarrett Wollman { 6947b6ab19dSGarrett Wollman struct sockaddr_in sin; 6957b6ab19dSGarrett Wollman int flags; 6962c7a9781SMark Murray const char *msg; 6977b6ab19dSGarrett Wollman naddr tgt_mcast; 6987b6ab19dSGarrett Wollman 6997b6ab19dSGarrett Wollman 7002c7a9781SMark Murray memset(&sin, 0, sizeof(sin)); 7017b6ab19dSGarrett Wollman sin.sin_addr.s_addr = dst; 7027b6ab19dSGarrett Wollman sin.sin_family = AF_INET; 7037b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 7047b6ab19dSGarrett Wollman sin.sin_len = sizeof(sin); 7057b6ab19dSGarrett Wollman #endif 7067b6ab19dSGarrett Wollman flags = MSG_DONTROUTE; 7077b6ab19dSGarrett Wollman 7087b6ab19dSGarrett Wollman switch (type) { 7097b6ab19dSGarrett Wollman case 0: /* unicast */ 71071965874SGarrett Wollman default: 7117b6ab19dSGarrett Wollman msg = "Send"; 7127b6ab19dSGarrett Wollman break; 7137b6ab19dSGarrett Wollman 7147b6ab19dSGarrett Wollman case 1: /* broadcast */ 7157b6ab19dSGarrett Wollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 7167b6ab19dSGarrett Wollman msg = "Send pt-to-pt"; 7177b6ab19dSGarrett Wollman sin.sin_addr.s_addr = ifp->int_dstaddr; 7187b6ab19dSGarrett Wollman } else { 7197b6ab19dSGarrett Wollman msg = "Send broadcast"; 7207b6ab19dSGarrett Wollman sin.sin_addr.s_addr = ifp->int_brdaddr; 7217b6ab19dSGarrett Wollman } 7227b6ab19dSGarrett Wollman break; 7237b6ab19dSGarrett Wollman 7247b6ab19dSGarrett Wollman case 2: /* multicast */ 7257b6ab19dSGarrett Wollman msg = "Send multicast"; 7267b6ab19dSGarrett Wollman if (ifp->int_state & IS_DUP) { 7277b6ab19dSGarrett Wollman trace_act("abort multicast output via %s" 728d5b718b3SGarrett Wollman " with duplicate address", 7297b6ab19dSGarrett Wollman ifp->int_name); 7307b6ab19dSGarrett Wollman return; 7317b6ab19dSGarrett Wollman } 7327b6ab19dSGarrett Wollman if (rdisc_sock_mcast != ifp) { 7337b6ab19dSGarrett Wollman /* select the right interface. */ 7347b6ab19dSGarrett Wollman #ifdef MCAST_PPP_BUG 7352c7a9781SMark Murray /* Do not specify the primary interface explicitly 7367b6ab19dSGarrett Wollman * if we have the multicast point-to-point kernel 7377b6ab19dSGarrett Wollman * bug, since the kernel will do the wrong thing 7387b6ab19dSGarrett Wollman * if the local address of a point-to-point link 7397b6ab19dSGarrett Wollman * is the same as the address of an ordinary 7407b6ab19dSGarrett Wollman * interface. 7417b6ab19dSGarrett Wollman */ 7427b6ab19dSGarrett Wollman if (ifp->int_addr == myaddr) { 7437b6ab19dSGarrett Wollman tgt_mcast = 0; 7447b6ab19dSGarrett Wollman } else 7457b6ab19dSGarrett Wollman #endif 7467b6ab19dSGarrett Wollman tgt_mcast = ifp->int_addr; 7477b6ab19dSGarrett Wollman if (0 > setsockopt(rdisc_sock, 7487b6ab19dSGarrett Wollman IPPROTO_IP, IP_MULTICAST_IF, 7497b6ab19dSGarrett Wollman &tgt_mcast, sizeof(tgt_mcast))) { 7507b6ab19dSGarrett Wollman LOGERR("setsockopt(rdisc_sock," 7517b6ab19dSGarrett Wollman "IP_MULTICAST_IF)"); 7527b6ab19dSGarrett Wollman rdisc_sock_mcast = 0; 7537b6ab19dSGarrett Wollman return; 7547b6ab19dSGarrett Wollman } 7557b6ab19dSGarrett Wollman rdisc_sock_mcast = ifp; 7567b6ab19dSGarrett Wollman } 7577b6ab19dSGarrett Wollman flags = 0; 7587b6ab19dSGarrett Wollman break; 7597b6ab19dSGarrett Wollman } 7607b6ab19dSGarrett Wollman 7617b6ab19dSGarrett Wollman if (rdisc_sock < 0) 7627b6ab19dSGarrett Wollman get_rdisc_sock(); 7637b6ab19dSGarrett Wollman 7647b6ab19dSGarrett Wollman trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, 7657b6ab19dSGarrett Wollman p, p_size); 7667b6ab19dSGarrett Wollman 7677b6ab19dSGarrett Wollman if (0 > sendto(rdisc_sock, p, p_size, flags, 7687b6ab19dSGarrett Wollman (struct sockaddr *)&sin, sizeof(sin))) { 7697b6ab19dSGarrett Wollman if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 7707b6ab19dSGarrett Wollman msglog("sendto(%s%s%s): %s", 7717b6ab19dSGarrett Wollman ifp != 0 ? ifp->int_name : "", 7727b6ab19dSGarrett Wollman ifp != 0 ? ", " : "", 7737b6ab19dSGarrett Wollman inet_ntoa(sin.sin_addr), 7747b6ab19dSGarrett Wollman strerror(errno)); 7757b6ab19dSGarrett Wollman if (ifp != 0) 7767b6ab19dSGarrett Wollman if_sick(ifp); 7777b6ab19dSGarrett Wollman } 7787b6ab19dSGarrett Wollman } 7797b6ab19dSGarrett Wollman 7807b6ab19dSGarrett Wollman 7817b6ab19dSGarrett Wollman /* Send an advertisement 7827b6ab19dSGarrett Wollman */ 7837b6ab19dSGarrett Wollman static void 7847b6ab19dSGarrett Wollman send_adv(struct interface *ifp, 7857b6ab19dSGarrett Wollman naddr dst, /* 0 or unicast destination */ 7867b6ab19dSGarrett Wollman int type) /* 0=unicast, 1=bcast, 2=mcast */ 7877b6ab19dSGarrett Wollman { 7887b6ab19dSGarrett Wollman union ad_u u; 7897b6ab19dSGarrett Wollman n_long pref; 7907b6ab19dSGarrett Wollman 7917b6ab19dSGarrett Wollman 7922c7a9781SMark Murray memset(&u, 0, sizeof(u.ad)); 7937b6ab19dSGarrett Wollman 7947b6ab19dSGarrett Wollman u.ad.icmp_type = ICMP_ROUTERADVERT; 7957b6ab19dSGarrett Wollman u.ad.icmp_ad_num = 1; 7967b6ab19dSGarrett Wollman u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 7977b6ab19dSGarrett Wollman 7987b6ab19dSGarrett Wollman u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 7992c7a9781SMark Murray 8002c7a9781SMark Murray /* Convert the configured preference to an unsigned value, 8012c7a9781SMark Murray * bias it by the interface metric, and then send it as a 8022c7a9781SMark Murray * signed, network byte order value. 8032c7a9781SMark Murray */ 8042c7a9781SMark Murray pref = UNSIGN_PREF(ifp->int_rdisc_pref); 8052c7a9781SMark Murray u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 8067b6ab19dSGarrett Wollman 8077b6ab19dSGarrett Wollman u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 8087b6ab19dSGarrett Wollman 8097b6ab19dSGarrett Wollman u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 8107b6ab19dSGarrett Wollman 8117b6ab19dSGarrett Wollman send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 8127b6ab19dSGarrett Wollman } 8137b6ab19dSGarrett Wollman 8147b6ab19dSGarrett Wollman 8157b6ab19dSGarrett Wollman /* Advertise for Router Discovery 8167b6ab19dSGarrett Wollman */ 8177b6ab19dSGarrett Wollman void 8187b6ab19dSGarrett Wollman rdisc_adv(void) 8197b6ab19dSGarrett Wollman { 8207b6ab19dSGarrett Wollman struct interface *ifp; 8217b6ab19dSGarrett Wollman 822d5b718b3SGarrett Wollman if (!supplier) 823d5b718b3SGarrett Wollman return; 8247b6ab19dSGarrett Wollman 8257b6ab19dSGarrett Wollman rdisc_timer.tv_sec = now.tv_sec + NEVER; 8267b6ab19dSGarrett Wollman 8277b6ab19dSGarrett Wollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 828d5b718b3SGarrett Wollman if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 8297b6ab19dSGarrett Wollman continue; 8307b6ab19dSGarrett Wollman 8317b6ab19dSGarrett Wollman if (!timercmp(&ifp->int_rdisc_timer, &now, >) 8327b6ab19dSGarrett Wollman || stopint) { 8337b6ab19dSGarrett Wollman send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 8347b6ab19dSGarrett Wollman (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 8357b6ab19dSGarrett Wollman ifp->int_rdisc_cnt++; 8367b6ab19dSGarrett Wollman 8377b6ab19dSGarrett Wollman intvl_random(&ifp->int_rdisc_timer, 8387b6ab19dSGarrett Wollman (ifp->int_rdisc_int*3)/4, 8397b6ab19dSGarrett Wollman ifp->int_rdisc_int); 8407b6ab19dSGarrett Wollman if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 8417b6ab19dSGarrett Wollman && (ifp->int_rdisc_timer.tv_sec 8427b6ab19dSGarrett Wollman > MAX_INITIAL_ADVERT_INTERVAL)) { 8437b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_sec 8447b6ab19dSGarrett Wollman = MAX_INITIAL_ADVERT_INTERVAL; 8457b6ab19dSGarrett Wollman } 8467b6ab19dSGarrett Wollman timevaladd(&ifp->int_rdisc_timer, &now); 8477b6ab19dSGarrett Wollman } 8487b6ab19dSGarrett Wollman 8497b6ab19dSGarrett Wollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 8507b6ab19dSGarrett Wollman rdisc_timer = ifp->int_rdisc_timer; 8517b6ab19dSGarrett Wollman } 8527b6ab19dSGarrett Wollman } 8537b6ab19dSGarrett Wollman 8547b6ab19dSGarrett Wollman 8557b6ab19dSGarrett Wollman /* Solicit for Router Discovery 8567b6ab19dSGarrett Wollman */ 8577b6ab19dSGarrett Wollman void 8587b6ab19dSGarrett Wollman rdisc_sol(void) 8597b6ab19dSGarrett Wollman { 8607b6ab19dSGarrett Wollman struct interface *ifp; 8617b6ab19dSGarrett Wollman union ad_u u; 8627b6ab19dSGarrett Wollman 8637b6ab19dSGarrett Wollman 864d5b718b3SGarrett Wollman if (supplier) 865d5b718b3SGarrett Wollman return; 866d5b718b3SGarrett Wollman 8677b6ab19dSGarrett Wollman rdisc_timer.tv_sec = now.tv_sec + NEVER; 8687b6ab19dSGarrett Wollman 8697b6ab19dSGarrett Wollman for (ifp = ifnet; ifp; ifp = ifp->int_next) { 870d5b718b3SGarrett Wollman if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 8717b6ab19dSGarrett Wollman || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 8727b6ab19dSGarrett Wollman continue; 8737b6ab19dSGarrett Wollman 8747b6ab19dSGarrett Wollman if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 8752c7a9781SMark Murray memset(&u, 0, sizeof(u.so)); 8767b6ab19dSGarrett Wollman u.so.icmp_type = ICMP_ROUTERSOLICIT; 8777b6ab19dSGarrett Wollman u.so.icmp_cksum = in_cksum((u_short*)&u.so, 8787b6ab19dSGarrett Wollman sizeof(u.so)); 8797b6ab19dSGarrett Wollman send_rdisc(&u, sizeof(u.so), ifp, 8807b6ab19dSGarrett Wollman htonl(INADDR_ALLROUTERS_GROUP), 8817b6ab19dSGarrett Wollman ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 8827b6ab19dSGarrett Wollman 8837b6ab19dSGarrett Wollman if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 8847b6ab19dSGarrett Wollman continue; 8857b6ab19dSGarrett Wollman 8867b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 8877b6ab19dSGarrett Wollman ifp->int_rdisc_timer.tv_usec = 0; 8887b6ab19dSGarrett Wollman timevaladd(&ifp->int_rdisc_timer, &now); 8897b6ab19dSGarrett Wollman } 8907b6ab19dSGarrett Wollman 8917b6ab19dSGarrett Wollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 8927b6ab19dSGarrett Wollman rdisc_timer = ifp->int_rdisc_timer; 8937b6ab19dSGarrett Wollman } 8947b6ab19dSGarrett Wollman } 8957b6ab19dSGarrett Wollman 8967b6ab19dSGarrett Wollman 8977b6ab19dSGarrett Wollman /* check the IP header of a possible Router Discovery ICMP packet */ 8987b6ab19dSGarrett Wollman static struct interface * /* 0 if bad */ 8992c7a9781SMark Murray ck_icmp(const char *act, 9007b6ab19dSGarrett Wollman naddr from, 901d5b718b3SGarrett Wollman struct interface *ifp, 9027b6ab19dSGarrett Wollman naddr to, 9037b6ab19dSGarrett Wollman union ad_u *p, 9047b6ab19dSGarrett Wollman u_int len) 9057b6ab19dSGarrett Wollman { 9062c7a9781SMark Murray const char *type; 9077b6ab19dSGarrett Wollman 9087b6ab19dSGarrett Wollman 9097b6ab19dSGarrett Wollman if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 9107b6ab19dSGarrett Wollman type = "advertisement"; 9117b6ab19dSGarrett Wollman } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 9127b6ab19dSGarrett Wollman type = "solicitation"; 9137b6ab19dSGarrett Wollman } else { 9147b6ab19dSGarrett Wollman return 0; 9157b6ab19dSGarrett Wollman } 9167b6ab19dSGarrett Wollman 9177b6ab19dSGarrett Wollman if (p->icmp.icmp_code != 0) { 918d5b718b3SGarrett Wollman trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 9197b6ab19dSGarrett Wollman type, p->icmp.icmp_code, 9207b6ab19dSGarrett Wollman naddr_ntoa(from), naddr_ntoa(to)); 9217b6ab19dSGarrett Wollman return 0; 9227b6ab19dSGarrett Wollman } 9237b6ab19dSGarrett Wollman 9247b6ab19dSGarrett Wollman trace_rdisc(act, from, to, ifp, p, len); 9257b6ab19dSGarrett Wollman 9267b6ab19dSGarrett Wollman if (ifp == 0) 9277b6ab19dSGarrett Wollman trace_pkt("unknown interface for router-discovery %s" 9287b6ab19dSGarrett Wollman " from %s to %s", 9297b6ab19dSGarrett Wollman type, naddr_ntoa(from), naddr_ntoa(to)); 9307b6ab19dSGarrett Wollman 9317b6ab19dSGarrett Wollman return ifp; 9327b6ab19dSGarrett Wollman } 9337b6ab19dSGarrett Wollman 9347b6ab19dSGarrett Wollman 9357b6ab19dSGarrett Wollman /* read packets from the router discovery socket 9367b6ab19dSGarrett Wollman */ 9377b6ab19dSGarrett Wollman void 9387b6ab19dSGarrett Wollman read_d(void) 9397b6ab19dSGarrett Wollman { 940d5b718b3SGarrett Wollman static struct msg_limit bad_asize, bad_len; 941337e72d0SGarrett Wollman #ifdef USE_PASSIFNAME 942337e72d0SGarrett Wollman static struct msg_limit bad_name; 943337e72d0SGarrett Wollman #endif 9447b6ab19dSGarrett Wollman struct sockaddr_in from; 9457b6ab19dSGarrett Wollman int n, fromlen, cc, hlen; 946d5b718b3SGarrett Wollman struct { 947d5b718b3SGarrett Wollman #ifdef USE_PASSIFNAME 948d5b718b3SGarrett Wollman char ifname[IFNAMSIZ]; 949d5b718b3SGarrett Wollman #endif 9507b6ab19dSGarrett Wollman union { 9517b6ab19dSGarrett Wollman struct ip ip; 9527b6ab19dSGarrett Wollman u_short s[512/2]; 9537b6ab19dSGarrett Wollman u_char b[512]; 9547b6ab19dSGarrett Wollman } pkt; 955d5b718b3SGarrett Wollman } buf; 9567b6ab19dSGarrett Wollman union ad_u *p; 9577b6ab19dSGarrett Wollman n_long *wp; 9587b6ab19dSGarrett Wollman struct interface *ifp; 9597b6ab19dSGarrett Wollman 9607b6ab19dSGarrett Wollman 9617b6ab19dSGarrett Wollman for (;;) { 9627b6ab19dSGarrett Wollman fromlen = sizeof(from); 963d5b718b3SGarrett Wollman cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 9647b6ab19dSGarrett Wollman (struct sockaddr*)&from, 9657b6ab19dSGarrett Wollman &fromlen); 9667b6ab19dSGarrett Wollman if (cc <= 0) { 9677b6ab19dSGarrett Wollman if (cc < 0 && errno != EWOULDBLOCK) 9687b6ab19dSGarrett Wollman LOGERR("recvfrom(rdisc_sock)"); 9697b6ab19dSGarrett Wollman break; 9707b6ab19dSGarrett Wollman } 9717b6ab19dSGarrett Wollman if (fromlen != sizeof(struct sockaddr_in)) 9727b6ab19dSGarrett Wollman logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 9737b6ab19dSGarrett Wollman fromlen); 974d5b718b3SGarrett Wollman #ifdef USE_PASSIFNAME 975d5b718b3SGarrett Wollman if ((cc -= sizeof(buf.ifname)) < 0) 976d5b718b3SGarrett Wollman logbad(0,"missing USE_PASSIFNAME; only %d bytes", 977d5b718b3SGarrett Wollman cc+sizeof(buf.ifname)); 978d5b718b3SGarrett Wollman #endif 9797b6ab19dSGarrett Wollman 980d5b718b3SGarrett Wollman hlen = buf.pkt.ip.ip_hl << 2; 9817b6ab19dSGarrett Wollman if (cc < hlen + ICMP_MINLEN) 9827b6ab19dSGarrett Wollman continue; 983d5b718b3SGarrett Wollman p = (union ad_u *)&buf.pkt.b[hlen]; 9847b6ab19dSGarrett Wollman cc -= hlen; 9857b6ab19dSGarrett Wollman 986d5b718b3SGarrett Wollman #ifdef USE_PASSIFNAME 987d5b718b3SGarrett Wollman ifp = ifwithname(buf.ifname, 0); 988337e72d0SGarrett Wollman if (ifp == 0) 989d5b718b3SGarrett Wollman msglim(&bad_name, from.sin_addr.s_addr, 990d5b718b3SGarrett Wollman "impossible rdisc if_ name %.*s", 991d5b718b3SGarrett Wollman IFNAMSIZ, buf.ifname); 992d5b718b3SGarrett Wollman #else 993d5b718b3SGarrett Wollman /* If we could tell the interface on which a packet from 994d5b718b3SGarrett Wollman * address 0 arrived, we could deal with such solicitations. 995d5b718b3SGarrett Wollman */ 996d5b718b3SGarrett Wollman ifp = ((from.sin_addr.s_addr == 0) 997d5b718b3SGarrett Wollman ? 0 : iflookup(from.sin_addr.s_addr)); 998d5b718b3SGarrett Wollman #endif 999337e72d0SGarrett Wollman ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 1000337e72d0SGarrett Wollman buf.pkt.ip.ip_dst.s_addr, p, cc); 10017b6ab19dSGarrett Wollman if (ifp == 0) 10027b6ab19dSGarrett Wollman continue; 10037b6ab19dSGarrett Wollman if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 1004337e72d0SGarrett Wollman trace_pkt(" " 1005337e72d0SGarrett Wollman "discard our own Router Discovery message"); 10067b6ab19dSGarrett Wollman continue; 10077b6ab19dSGarrett Wollman } 10087b6ab19dSGarrett Wollman 10097b6ab19dSGarrett Wollman switch (p->icmp.icmp_type) { 10107b6ab19dSGarrett Wollman case ICMP_ROUTERADVERT: 10117b6ab19dSGarrett Wollman if (p->ad.icmp_ad_asize*4 10122c7a9781SMark Murray < (int)sizeof(p->ad.icmp_ad_info[0])) { 1013d5b718b3SGarrett Wollman msglim(&bad_asize, from.sin_addr.s_addr, 1014d5b718b3SGarrett Wollman "intolerable rdisc address size=%d", 10157b6ab19dSGarrett Wollman p->ad.icmp_ad_asize); 10167b6ab19dSGarrett Wollman continue; 10177b6ab19dSGarrett Wollman } 10187b6ab19dSGarrett Wollman if (p->ad.icmp_ad_num == 0) { 1019d5b718b3SGarrett Wollman trace_pkt(" empty?"); 10207b6ab19dSGarrett Wollman continue; 10217b6ab19dSGarrett Wollman } 10222c7a9781SMark Murray if (cc != (int)(sizeof(p->ad) 10232c7a9781SMark Murray - sizeof(p->ad.icmp_ad_info) 10247b6ab19dSGarrett Wollman + (p->ad.icmp_ad_num 10257b6ab19dSGarrett Wollman * sizeof(p->ad.icmp_ad_info[0])))) { 1026d5b718b3SGarrett Wollman msglim(&bad_len, from.sin_addr.s_addr, 1027d5b718b3SGarrett Wollman "rdisc length %d does not match ad_num" 1028d5b718b3SGarrett Wollman " %d", cc, p->ad.icmp_ad_num); 10297b6ab19dSGarrett Wollman continue; 10307b6ab19dSGarrett Wollman } 10317b6ab19dSGarrett Wollman if (supplier) 10327b6ab19dSGarrett Wollman continue; 10337b6ab19dSGarrett Wollman if (ifp->int_state & IS_NO_ADV_IN) 10347b6ab19dSGarrett Wollman continue; 10357b6ab19dSGarrett Wollman 10367b6ab19dSGarrett Wollman wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 10377b6ab19dSGarrett Wollman for (n = 0; n < p->ad.icmp_ad_num; n++) { 10387b6ab19dSGarrett Wollman parse_ad(from.sin_addr.s_addr, 10397b6ab19dSGarrett Wollman wp[0], wp[1], 10407b6ab19dSGarrett Wollman ntohs(p->ad.icmp_ad_life), 10417b6ab19dSGarrett Wollman ifp); 10427b6ab19dSGarrett Wollman wp += p->ad.icmp_ad_asize; 10437b6ab19dSGarrett Wollman } 10447b6ab19dSGarrett Wollman break; 10457b6ab19dSGarrett Wollman 10467b6ab19dSGarrett Wollman 10477b6ab19dSGarrett Wollman case ICMP_ROUTERSOLICIT: 10487b6ab19dSGarrett Wollman if (!supplier) 10497b6ab19dSGarrett Wollman continue; 10507b6ab19dSGarrett Wollman if (ifp->int_state & IS_NO_ADV_OUT) 10517b6ab19dSGarrett Wollman continue; 10522c7a9781SMark Murray if (stopint) 10532c7a9781SMark Murray continue; 10547b6ab19dSGarrett Wollman 10557b6ab19dSGarrett Wollman /* XXX 10567b6ab19dSGarrett Wollman * We should handle messages from address 0. 10577b6ab19dSGarrett Wollman */ 10587b6ab19dSGarrett Wollman 10597b6ab19dSGarrett Wollman /* Respond with a point-to-point advertisement */ 10607b6ab19dSGarrett Wollman send_adv(ifp, from.sin_addr.s_addr, 0); 10617b6ab19dSGarrett Wollman break; 10627b6ab19dSGarrett Wollman } 10637b6ab19dSGarrett Wollman } 10647b6ab19dSGarrett Wollman 10657b6ab19dSGarrett Wollman rdisc_sort(); 10667b6ab19dSGarrett Wollman } 1067