118316Swollman/* 218316Swollman * Copyright (c) 1995 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD$ 3018316Swollman */ 3118316Swollman 3218316Swollman#include "defs.h" 3318316Swollman#include <netinet/in_systm.h> 3418316Swollman#include <netinet/ip.h> 3518316Swollman#include <netinet/ip_icmp.h> 3618316Swollman 37126250Sbms#ifdef __NetBSD__ 3864483Ssheldonh__RCSID("$NetBSD$"); 39126250Sbms#elif defined(__FreeBSD__) 40126250Sbms__RCSID("$FreeBSD$"); 41126250Sbms#else 42126250Sbms__RCSID("$Revision: 2.27 $"); 43126250Sbms#ident "$Revision: 2.27 $" 4446303Smarkm#endif 4546303Smarkm 4618316Swollman/* router advertisement ICMP packet */ 4718316Swollmanstruct icmp_ad { 4818316Swollman u_int8_t icmp_type; /* type of message */ 4918316Swollman u_int8_t icmp_code; /* type sub code */ 5018316Swollman u_int16_t icmp_cksum; /* ones complement cksum of struct */ 5118316Swollman u_int8_t icmp_ad_num; /* # of following router addresses */ 5218316Swollman u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 5318316Swollman u_int16_t icmp_ad_life; /* seconds of validity */ 5418316Swollman struct icmp_ad_info { 5518316Swollman n_long icmp_ad_addr; 5618316Swollman n_long icmp_ad_pref; 5718316Swollman } icmp_ad_info[1]; 5818316Swollman}; 5918316Swollman 6018316Swollman/* router solicitation ICMP packet */ 6118316Swollmanstruct icmp_so { 6218316Swollman u_int8_t icmp_type; /* type of message */ 6318316Swollman u_int8_t icmp_code; /* type sub code */ 6418316Swollman u_int16_t icmp_cksum; /* ones complement cksum of struct */ 6518316Swollman n_long icmp_so_rsvd; 6618316Swollman}; 6718316Swollman 6818316Swollmanunion ad_u { 6918316Swollman struct icmp icmp; 7018316Swollman struct icmp_ad ad; 7118316Swollman struct icmp_so so; 7218316Swollman}; 7318316Swollman 7418316Swollman 7518316Swollmanint rdisc_sock = -1; /* router-discovery raw socket */ 76190716Sphkstatic const struct interface *rdisc_sock_mcast; /* current multicast interface */ 7718316Swollman 7818316Swollmanstruct timeval rdisc_timer; 7918316Swollmanint rdisc_ok; /* using solicited route */ 8018316Swollman 8118316Swollman 8246303Smarkm#define MAX_ADS 16 /* at least one per interface */ 83190716Sphkstruct dr { /* accumulated advertisements */ 8418316Swollman struct interface *dr_ifp; 8518316Swollman naddr dr_gate; /* gateway */ 8618316Swollman time_t dr_ts; /* when received */ 8764131Ssheldonh time_t dr_life; /* lifetime in host byte order */ 8818316Swollman n_long dr_recv_pref; /* received but biased preference */ 8918316Swollman n_long dr_pref; /* preference adjusted by metric */ 90190716Sphk}; 91190716Sphkstatic const struct dr *cur_drp; 92190716Sphkstatic struct dr drs[MAX_ADS]; 9318316Swollman 9446303Smarkm/* convert between signed, balanced around zero, 9546303Smarkm * and unsigned zero-based preferences */ 9646303Smarkm#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) 9746303Smarkm#define UNSIGN_PREF(p) SIGN_PREF(p) 9846303Smarkm/* adjust unsigned preference by interface metric, 9946303Smarkm * without driving it to infinity */ 100126250Sbms#define PREF(p, ifp) ((int)(p) <= ((ifp)->int_metric+(ifp)->int_adj_outmetric)\ 101126250Sbms ? ((p) != 0 ? 1 : 0) \ 102126250Sbms : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric)) 10318316Swollman 10418316Swollmanstatic void rdisc_sort(void); 10518316Swollman 10618316Swollman 10718316Swollman/* dump an ICMP Router Discovery Advertisement Message 10818316Swollman */ 10918316Swollmanstatic void 11046303Smarkmtrace_rdisc(const char *act, 11118316Swollman naddr from, 11218316Swollman naddr to, 11318316Swollman struct interface *ifp, 11418316Swollman union ad_u *p, 11518316Swollman u_int len) 11618316Swollman{ 11718316Swollman int i; 11818316Swollman n_long *wp, *lim; 11918316Swollman 12018316Swollman 12118316Swollman if (!TRACEPACKETS || ftrace == 0) 12218316Swollman return; 12318316Swollman 12418316Swollman lastlog(); 12518316Swollman 12618316Swollman if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 12718316Swollman (void)fprintf(ftrace, "%s Router Ad" 12818316Swollman " from %s to %s via %s life=%d\n", 12918316Swollman act, naddr_ntoa(from), naddr_ntoa(to), 13018316Swollman ifp ? ifp->int_name : "?", 13118316Swollman ntohs(p->ad.icmp_ad_life)); 13218316Swollman if (!TRACECONTENTS) 13318316Swollman return; 13418316Swollman 13518316Swollman wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 13618316Swollman lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 13718316Swollman for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 13820339Swollman (void)fprintf(ftrace, "\t%s preference=%d", 13918316Swollman naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 14018316Swollman wp += p->ad.icmp_ad_asize; 14118316Swollman } 14218316Swollman (void)fputc('\n',ftrace); 14318316Swollman 14418316Swollman } else { 14519880Swollman trace_act("%s Router Solic. from %s to %s via %s value=%#x", 14618316Swollman act, naddr_ntoa(from), naddr_ntoa(to), 14718316Swollman ifp ? ifp->int_name : "?", 14846303Smarkm (int)ntohl(p->so.icmp_so_rsvd)); 14918316Swollman } 15018316Swollman} 15118316Swollman 15218316Swollman/* prepare Router Discovery socket. 15318316Swollman */ 15418316Swollmanstatic void 15518316Swollmanget_rdisc_sock(void) 15618316Swollman{ 15718316Swollman if (rdisc_sock < 0) { 15818316Swollman rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 15918316Swollman if (rdisc_sock < 0) 16018316Swollman BADERR(1,"rdisc_sock = socket()"); 16118316Swollman fix_sock(rdisc_sock,"rdisc_sock"); 16218316Swollman fix_select(); 16318316Swollman } 16418316Swollman} 16518316Swollman 16618316Swollman 16718316Swollman/* Pick multicast group for router-discovery socket 16818316Swollman */ 16918316Swollmanvoid 17018316Swollmanset_rdisc_mg(struct interface *ifp, 17119880Swollman int on) /* 0=turn it off */ 17219880Swollman{ 173180993Sphk struct group_req gr; 174180993Sphk struct sockaddr_in *sin; 17518316Swollman 176190718Sphk assert(ifp != NULL); 177190718Sphk 17818316Swollman if (rdisc_sock < 0) { 17918316Swollman /* Create the raw socket so that we can hear at least 18018316Swollman * broadcast router discovery packets. 18118316Swollman */ 18218316Swollman if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 18318316Swollman || !on) 18418316Swollman return; 18518316Swollman get_rdisc_sock(); 18618316Swollman } 18718316Swollman 18819880Swollman if (!(ifp->int_if_flags & IFF_MULTICAST)) { 18918316Swollman ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 19018316Swollman return; 19118316Swollman } 19218316Swollman 193180993Sphk memset(&gr, 0, sizeof(gr)); 194180993Sphk gr.gr_interface = ifp->int_index; 195180993Sphk sin = (struct sockaddr_in *)&gr.gr_group; 196180993Sphk sin->sin_family = AF_INET; 197180993Sphk#ifdef _HAVE_SIN_LEN 198180993Sphk sin->sin_len = sizeof(struct sockaddr_in); 19918316Swollman#endif 200180993Sphk 20118316Swollman if (supplier 20218316Swollman || (ifp->int_state & IS_NO_ADV_IN) 20318316Swollman || !on) { 20418316Swollman /* stop listening to advertisements 20518316Swollman */ 20618316Swollman if (ifp->int_state & IS_ALL_HOSTS) { 207180993Sphk sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 20818316Swollman if (setsockopt(rdisc_sock, IPPROTO_IP, 209180993Sphk MCAST_LEAVE_GROUP, 210180993Sphk &gr, sizeof(gr)) < 0) 211180993Sphk LOGERR("MCAST_LEAVE_GROUP ALLHOSTS"); 21218316Swollman ifp->int_state &= ~IS_ALL_HOSTS; 21318316Swollman } 21418316Swollman 21518316Swollman } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 21618316Swollman /* start listening to advertisements 21718316Swollman */ 218180993Sphk sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 219180993Sphk if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 220180993Sphk &gr, sizeof(gr)) < 0) { 221180993Sphk LOGERR("MCAST_JOIN_GROUP ALLHOSTS"); 22218316Swollman } else { 22318316Swollman ifp->int_state |= IS_ALL_HOSTS; 22418316Swollman } 22518316Swollman } 22618316Swollman 22718316Swollman if (!supplier 22818316Swollman || (ifp->int_state & IS_NO_ADV_OUT) 22918316Swollman || !on) { 23018316Swollman /* stop listening to solicitations 23118316Swollman */ 23218316Swollman if (ifp->int_state & IS_ALL_ROUTERS) { 233180993Sphk sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 23418316Swollman if (setsockopt(rdisc_sock, IPPROTO_IP, 235180993Sphk MCAST_LEAVE_GROUP, 236180993Sphk &gr, sizeof(gr)) < 0) 237180993Sphk LOGERR("MCAST_LEAVE_GROUP ALLROUTERS"); 23818316Swollman ifp->int_state &= ~IS_ALL_ROUTERS; 23918316Swollman } 24018316Swollman 24118316Swollman } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 24218316Swollman /* start hearing solicitations 24318316Swollman */ 244180993Sphk sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 245180993Sphk if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 246180993Sphk &gr, sizeof(gr)) < 0) { 247180993Sphk LOGERR("MCAST_JOIN_GROUP ALLROUTERS"); 24818316Swollman } else { 24918316Swollman ifp->int_state |= IS_ALL_ROUTERS; 25018316Swollman } 25118316Swollman } 25218316Swollman} 25318316Swollman 25418316Swollman 25518316Swollman/* start supplying routes 25618316Swollman */ 25718316Swollmanvoid 25818316Swollmanset_supplier(void) 25918316Swollman{ 26018316Swollman struct interface *ifp; 26118316Swollman struct dr *drp; 26218316Swollman 26318316Swollman if (supplier_set) 26418316Swollman return; 26518316Swollman 26637908Scharnier trace_act("start supplying routes"); 26718316Swollman 26818316Swollman /* Forget discovered routes. 26918316Swollman */ 27018316Swollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 27118316Swollman drp->dr_recv_pref = 0; 27218316Swollman drp->dr_life = 0; 27318316Swollman } 27418316Swollman rdisc_age(0); 27518316Swollman 27618316Swollman supplier_set = 1; 27718316Swollman supplier = 1; 27818316Swollman 27918316Swollman /* Do not start advertising until we have heard some RIP routes */ 28018316Swollman LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 28118316Swollman 28218316Swollman /* Switch router discovery multicast groups from soliciting 28318316Swollman * to advertising. 28418316Swollman */ 285190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 28618316Swollman if (ifp->int_state & IS_BROKE) 28718316Swollman continue; 28818316Swollman ifp->int_rdisc_cnt = 0; 28918316Swollman ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 29018316Swollman ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 29118316Swollman set_rdisc_mg(ifp, 1); 29218316Swollman } 29318316Swollman 29418316Swollman /* get rid of any redirects */ 29518316Swollman del_redirects(0,0); 29618316Swollman} 29718316Swollman 29818316Swollman 29918316Swollman/* age discovered routes and find the best one 30018316Swollman */ 30118316Swollmanvoid 30218316Swollmanrdisc_age(naddr bad_gate) 30318316Swollman{ 30418316Swollman time_t sec; 30518316Swollman struct dr *drp; 30618316Swollman 30718316Swollman 30837908Scharnier /* If only advertising, then do only that. */ 30918316Swollman if (supplier) { 31046303Smarkm /* If switching from client to server, get rid of old 31118316Swollman * default routes. 31218316Swollman */ 31318316Swollman if (cur_drp != 0) 31418316Swollman rdisc_sort(); 31518316Swollman rdisc_adv(); 31618316Swollman return; 31718316Swollman } 31818316Swollman 31918316Swollman /* If we are being told about a bad router, 32018316Swollman * then age the discovered default route, and if there is 32137908Scharnier * no alternative, solicit a replacement. 32218316Swollman */ 32318316Swollman if (bad_gate != 0) { 32418316Swollman /* Look for the bad discovered default route. 32518316Swollman * Age it and note its interface. 32618316Swollman */ 32718316Swollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 32818316Swollman if (drp->dr_ts == 0) 32918316Swollman continue; 33018316Swollman 33118316Swollman /* When we find the bad router, then age the route 33218316Swollman * to at most SUPPLY_INTERVAL. 33318316Swollman * This is contrary to RFC 1256, but defends against 33418316Swollman * black holes. 33518316Swollman */ 33618316Swollman if (drp->dr_gate == bad_gate) { 33718316Swollman sec = (now.tv_sec - drp->dr_life 33818316Swollman + SUPPLY_INTERVAL); 33918316Swollman if (drp->dr_ts > sec) { 34019880Swollman trace_act("age 0.0.0.0 --> %s via %s", 34118316Swollman naddr_ntoa(drp->dr_gate), 34218316Swollman drp->dr_ifp->int_name); 34318316Swollman drp->dr_ts = sec; 34418316Swollman } 34518316Swollman break; 34618316Swollman } 34718316Swollman } 34818316Swollman } 34918316Swollman 35018316Swollman rdisc_sol(); 35146303Smarkm rdisc_sort(); 35218316Swollman 35346303Smarkm /* Delete old redirected routes to keep the kernel table small, 35446303Smarkm * and to prevent black holes. Check that the kernel table 35546303Smarkm * matches the daemon table (i.e. has the default route). 35646303Smarkm * But only if RIP is not running and we are not dealing with 35746303Smarkm * a bad gateway, since otherwise age() will be called. 35846303Smarkm */ 35946303Smarkm if (rip_sock < 0 && bad_gate == 0) 36046303Smarkm age(0); 36118316Swollman} 36218316Swollman 36318316Swollman 36418316Swollman/* Zap all routes discovered via an interface that has gone bad 36518316Swollman * This should only be called when !(ifp->int_state & IS_ALIAS) 36618316Swollman */ 36718316Swollmanvoid 36818316Swollmanif_bad_rdisc(struct interface *ifp) 36918316Swollman{ 37018316Swollman struct dr *drp; 37118316Swollman 37218316Swollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 37318316Swollman if (drp->dr_ifp != ifp) 37418316Swollman continue; 37518316Swollman drp->dr_recv_pref = 0; 37646303Smarkm drp->dr_ts = 0; 37718316Swollman drp->dr_life = 0; 37818316Swollman } 37918316Swollman 38046303Smarkm /* make a note to re-solicit, turn RIP on or off, etc. */ 38146303Smarkm rdisc_timer.tv_sec = 0; 38218316Swollman} 38318316Swollman 38418316Swollman 38518316Swollman/* mark an interface ok for router discovering. 38618316Swollman */ 38718316Swollmanvoid 38818316Swollmanif_ok_rdisc(struct interface *ifp) 38918316Swollman{ 39018316Swollman set_rdisc_mg(ifp, 1); 39118316Swollman 39218316Swollman ifp->int_rdisc_cnt = 0; 39318316Swollman ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 39418316Swollman ? MIN_WAITTIME 39518316Swollman : MAX_SOLICITATION_DELAY); 39618316Swollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 39718316Swollman rdisc_timer = ifp->int_rdisc_timer; 39818316Swollman} 39918316Swollman 40018316Swollman 40118316Swollman/* get rid of a dead discovered router 40218316Swollman */ 40318316Swollmanstatic void 40418316Swollmandel_rdisc(struct dr *drp) 40518316Swollman{ 40618316Swollman struct interface *ifp; 40746303Smarkm naddr gate; 40818316Swollman int i; 40918316Swollman 41018316Swollman 41146303Smarkm del_redirects(gate = drp->dr_gate, 0); 41218316Swollman drp->dr_ts = 0; 41318316Swollman drp->dr_life = 0; 41418316Swollman 41518316Swollman 41618316Swollman /* Count the other discovered routes on the interface. 41718316Swollman */ 41818316Swollman i = 0; 41918316Swollman ifp = drp->dr_ifp; 42018316Swollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 42118316Swollman if (drp->dr_ts != 0 42218316Swollman && drp->dr_ifp == ifp) 42318316Swollman i++; 42418316Swollman } 42518316Swollman 42618316Swollman /* If that was the last good discovered router on the interface, 42718316Swollman * then solicit a new one. 42818316Swollman * This is contrary to RFC 1256, but defends against black holes. 42918316Swollman */ 43046303Smarkm if (i != 0) { 43146303Smarkm trace_act("discovered router %s via %s" 43246303Smarkm " is bad--have %d remaining", 43346303Smarkm naddr_ntoa(gate), ifp->int_name, i); 43446303Smarkm } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 43546303Smarkm trace_act("last discovered router %s via %s" 43646303Smarkm " is bad--re-solicit", 43746303Smarkm naddr_ntoa(gate), ifp->int_name); 43818316Swollman ifp->int_rdisc_cnt = 0; 43918316Swollman ifp->int_rdisc_timer.tv_sec = 0; 44018316Swollman rdisc_sol(); 44146303Smarkm } else { 44246303Smarkm trace_act("last discovered router %s via %s" 44346303Smarkm " is bad--wait to solicit", 44446303Smarkm naddr_ntoa(gate), ifp->int_name); 44518316Swollman } 44618316Swollman} 44718316Swollman 44818316Swollman 44918316Swollman/* Find the best discovered route, 45018316Swollman * and discard stale routers. 45118316Swollman */ 45218316Swollmanstatic void 45318316Swollmanrdisc_sort(void) 45418316Swollman{ 45518316Swollman struct dr *drp, *new_drp; 45618316Swollman struct rt_entry *rt; 45746303Smarkm struct rt_spare new; 45818316Swollman struct interface *ifp; 45946303Smarkm u_int new_st = 0; 46046303Smarkm n_long new_pref = 0; 46118316Swollman 46218316Swollman 46318316Swollman /* Find the best discovered route. 46418316Swollman */ 46518316Swollman new_drp = 0; 46618316Swollman for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 46718316Swollman if (drp->dr_ts == 0) 46818316Swollman continue; 46918316Swollman ifp = drp->dr_ifp; 47018316Swollman 47118316Swollman /* Get rid of expired discovered routers. 47218316Swollman */ 47318316Swollman if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 47418316Swollman del_rdisc(drp); 47518316Swollman continue; 47618316Swollman } 47718316Swollman 47818316Swollman LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 47918316Swollman 48018316Swollman /* Update preference with possibly changed interface 48118316Swollman * metric. 48218316Swollman */ 48318316Swollman drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 48418316Swollman 48518316Swollman /* Prefer the current route to prevent thrashing. 48618316Swollman * Prefer shorter lifetimes to speed the detection of 48718316Swollman * bad routers. 48818316Swollman * Avoid sick interfaces. 48918316Swollman */ 49018316Swollman if (new_drp == 0 49118316Swollman || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 49218316Swollman && (new_pref < drp->dr_pref 49318316Swollman || (new_pref == drp->dr_pref 49418316Swollman && (drp == cur_drp 49518316Swollman || (new_drp != cur_drp 49618316Swollman && new_drp->dr_life > drp->dr_life))))) 49718316Swollman || ((new_st & IS_SICK) 49818316Swollman && !(drp->dr_ifp->int_state & IS_SICK))) { 49918316Swollman new_drp = drp; 50018316Swollman new_st = drp->dr_ifp->int_state; 50118316Swollman new_pref = drp->dr_pref; 50218316Swollman } 50318316Swollman } 50418316Swollman 50518316Swollman /* switch to a better default route 50618316Swollman */ 50718316Swollman if (new_drp != cur_drp) { 50818316Swollman rt = rtget(RIP_DEFAULT, 0); 50918316Swollman 51018316Swollman /* Stop using discovered routes if they are all bad 51118316Swollman */ 51218316Swollman if (new_drp == 0) { 51319880Swollman trace_act("turn off Router Discovery client"); 51418316Swollman rdisc_ok = 0; 51518316Swollman 51618316Swollman if (rt != 0 51718316Swollman && (rt->rt_state & RS_RDISC)) { 51846303Smarkm new = rt->rt_spares[0]; 51946303Smarkm new.rts_metric = HOPCNT_INFINITY; 52046303Smarkm new.rts_time = now.tv_sec - GARBAGE_TIME; 52118316Swollman rtchange(rt, rt->rt_state & ~RS_RDISC, 52246303Smarkm &new, 0); 52318316Swollman rtswitch(rt, 0); 52418316Swollman } 52518316Swollman 52618316Swollman } else { 52718316Swollman if (cur_drp == 0) { 52818316Swollman trace_act("turn on Router Discovery client" 52919880Swollman " using %s via %s", 53018316Swollman naddr_ntoa(new_drp->dr_gate), 53118316Swollman new_drp->dr_ifp->int_name); 53218316Swollman rdisc_ok = 1; 53318316Swollman 53418316Swollman } else { 53518316Swollman trace_act("switch Router Discovery from" 53619880Swollman " %s via %s to %s via %s", 53718316Swollman naddr_ntoa(cur_drp->dr_gate), 53818316Swollman cur_drp->dr_ifp->int_name, 53918316Swollman naddr_ntoa(new_drp->dr_gate), 54018316Swollman new_drp->dr_ifp->int_name); 54118316Swollman } 54218316Swollman 54346303Smarkm memset(&new, 0, sizeof(new)); 54446303Smarkm new.rts_ifp = new_drp->dr_ifp; 54546303Smarkm new.rts_gate = new_drp->dr_gate; 54646303Smarkm new.rts_router = new_drp->dr_gate; 54746303Smarkm new.rts_metric = HOPCNT_INFINITY-1; 54846303Smarkm new.rts_time = now.tv_sec; 54918316Swollman if (rt != 0) { 55046303Smarkm rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); 55118316Swollman } else { 55246303Smarkm rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); 55318316Swollman } 55418316Swollman } 55518316Swollman 55618316Swollman cur_drp = new_drp; 55718316Swollman } 55846303Smarkm 55946303Smarkm /* turn RIP on or off */ 56046303Smarkm if (!rdisc_ok || rip_interfaces > 1) { 56146303Smarkm rip_on(0); 56246303Smarkm } else { 56346303Smarkm rip_off(); 56446303Smarkm } 56518316Swollman} 56618316Swollman 56718316Swollman 56818316Swollman/* handle a single address in an advertisement 56918316Swollman */ 57018316Swollmanstatic void 57118316Swollmanparse_ad(naddr from, 57218316Swollman naddr gate, 57346303Smarkm n_long pref, /* signed and in network order */ 57464131Ssheldonh u_short life, /* in host byte order */ 57518316Swollman struct interface *ifp) 57618316Swollman{ 57719880Swollman static struct msg_limit bad_gate; 57818316Swollman struct dr *drp, *new_drp; 57918316Swollman 58018316Swollman 58118316Swollman if (gate == RIP_DEFAULT 58218316Swollman || !check_dst(gate)) { 58319880Swollman msglim(&bad_gate, from,"router %s advertising bad gateway %s", 58419880Swollman naddr_ntoa(from), 58519880Swollman naddr_ntoa(gate)); 58618316Swollman return; 58718316Swollman } 58818316Swollman 58918316Swollman /* ignore pointers to ourself and routes via unreachable networks 59018316Swollman */ 59118316Swollman if (ifwithaddr(gate, 1, 0) != 0) { 59219880Swollman trace_pkt(" discard Router Discovery Ad pointing at us"); 59318316Swollman return; 59418316Swollman } 59518316Swollman if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 59619880Swollman trace_pkt(" discard Router Discovery Ad" 59719880Swollman " toward unreachable net"); 59818316Swollman return; 59918316Swollman } 60018316Swollman 60118316Swollman /* Convert preference to an unsigned value 60218316Swollman * and later bias it by the metric of the interface. 60318316Swollman */ 60446303Smarkm pref = UNSIGN_PREF(ntohl(pref)); 60518316Swollman 60646303Smarkm if (pref == 0 || life < MinMaxAdvertiseInterval) { 60718316Swollman pref = 0; 60818316Swollman life = 0; 60918316Swollman } 61018316Swollman 61118316Swollman for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { 61218316Swollman /* accept new info for a familiar entry 61318316Swollman */ 61418316Swollman if (drp->dr_gate == gate) { 61518316Swollman new_drp = drp; 61618316Swollman break; 61718316Swollman } 61818316Swollman 61918316Swollman if (life == 0) 62018316Swollman continue; /* do not worry about dead ads */ 62118316Swollman 62218316Swollman if (drp->dr_ts == 0) { 62318316Swollman new_drp = drp; /* use unused entry */ 62418316Swollman 62518316Swollman } else if (new_drp == 0) { 62618316Swollman /* look for an entry worse than the new one to 62718316Swollman * reuse. 62818316Swollman */ 62918316Swollman if ((!(ifp->int_state & IS_SICK) 63018316Swollman && (drp->dr_ifp->int_state & IS_SICK)) 63118316Swollman || (pref > drp->dr_pref 63218316Swollman && !((ifp->int_state ^ drp->dr_ifp->int_state) 63318316Swollman & IS_SICK))) 63418316Swollman new_drp = drp; 63518316Swollman 63618316Swollman } else if (new_drp->dr_ts != 0) { 63737908Scharnier /* look for the least valuable entry to reuse 63818316Swollman */ 63918316Swollman if ((!(new_drp->dr_ifp->int_state & IS_SICK) 64018316Swollman && (drp->dr_ifp->int_state & IS_SICK)) 64118316Swollman || (new_drp->dr_pref > drp->dr_pref 64218316Swollman && !((new_drp->dr_ifp->int_state 64318316Swollman ^ drp->dr_ifp->int_state) 64418316Swollman & IS_SICK))) 64518316Swollman new_drp = drp; 64618316Swollman } 64718316Swollman } 64818316Swollman 64918316Swollman /* forget it if all of the current entries are better */ 65018316Swollman if (new_drp == 0) 65118316Swollman return; 65218316Swollman 65318316Swollman new_drp->dr_ifp = ifp; 65418316Swollman new_drp->dr_gate = gate; 65518316Swollman new_drp->dr_ts = now.tv_sec; 65664131Ssheldonh new_drp->dr_life = life; 65718316Swollman new_drp->dr_recv_pref = pref; 65818316Swollman /* bias functional preference by metric of the interface */ 65918316Swollman new_drp->dr_pref = PREF(pref,ifp); 66018316Swollman 66118316Swollman /* after hearing a good advertisement, stop asking 66218316Swollman */ 66318316Swollman if (!(ifp->int_state & IS_SICK)) 66418316Swollman ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 66518316Swollman} 66618316Swollman 66718316Swollman 66818316Swollman/* Compute the IP checksum 66918316Swollman * This assumes the packet is less than 32K long. 67018316Swollman */ 67118316Swollmanstatic u_short 67218316Swollmanin_cksum(u_short *p, 67318316Swollman u_int len) 67418316Swollman{ 67518316Swollman u_int sum = 0; 67618316Swollman int nwords = len >> 1; 67718316Swollman 67818316Swollman while (nwords-- != 0) 67918316Swollman sum += *p++; 68018316Swollman 68118316Swollman if (len & 1) 68218316Swollman sum += *(u_char *)p; 68318316Swollman 68418316Swollman /* end-around-carry */ 68518316Swollman sum = (sum >> 16) + (sum & 0xffff); 68618316Swollman sum += (sum >> 16); 68718316Swollman return (~sum); 68818316Swollman} 68918316Swollman 69018316Swollman 69118316Swollman/* Send a router discovery advertisement or solicitation ICMP packet. 69218316Swollman */ 69318316Swollmanstatic void 69418316Swollmansend_rdisc(union ad_u *p, 69518316Swollman int p_size, 69618316Swollman struct interface *ifp, 69746303Smarkm naddr dst, /* 0 or unicast destination */ 69818316Swollman int type) /* 0=unicast, 1=bcast, 2=mcast */ 69918316Swollman{ 700126250Sbms struct sockaddr_in rsin; 70118316Swollman int flags; 70246303Smarkm const char *msg; 70318316Swollman 70418316Swollman 705126250Sbms memset(&rsin, 0, sizeof(rsin)); 706126250Sbms rsin.sin_addr.s_addr = dst; 707126250Sbms rsin.sin_family = AF_INET; 70818316Swollman#ifdef _HAVE_SIN_LEN 709126250Sbms rsin.sin_len = sizeof(rsin); 71018316Swollman#endif 71118316Swollman flags = MSG_DONTROUTE; 71218316Swollman 71318316Swollman switch (type) { 71446303Smarkm case 0: /* unicast */ 71520339Swollman default: 71618316Swollman msg = "Send"; 71718316Swollman break; 71818316Swollman 71918316Swollman case 1: /* broadcast */ 72018316Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 72118316Swollman msg = "Send pt-to-pt"; 722126250Sbms rsin.sin_addr.s_addr = ifp->int_dstaddr; 72318316Swollman } else { 72418316Swollman msg = "Send broadcast"; 725126250Sbms rsin.sin_addr.s_addr = ifp->int_brdaddr; 72618316Swollman } 72718316Swollman break; 72818316Swollman 72918316Swollman case 2: /* multicast */ 73018316Swollman msg = "Send multicast"; 73118316Swollman if (ifp->int_state & IS_DUP) { 73218316Swollman trace_act("abort multicast output via %s" 73319880Swollman " with duplicate address", 73418316Swollman ifp->int_name); 73518316Swollman return; 73618316Swollman } 73718316Swollman if (rdisc_sock_mcast != ifp) { 73818316Swollman /* select the right interface. */ 739180993Sphk struct ip_mreqn mreqn; 740180993Sphk 741180993Sphk memset(&mreqn, 0, sizeof(struct ip_mreqn)); 742180993Sphk mreqn.imr_ifindex = ifp->int_index; 74318316Swollman if (0 > setsockopt(rdisc_sock, 74418316Swollman IPPROTO_IP, IP_MULTICAST_IF, 745180993Sphk &mreqn, 746180993Sphk sizeof(mreqn))) { 74718316Swollman LOGERR("setsockopt(rdisc_sock," 74818316Swollman "IP_MULTICAST_IF)"); 74918316Swollman rdisc_sock_mcast = 0; 75018316Swollman return; 75118316Swollman } 75218316Swollman rdisc_sock_mcast = ifp; 75318316Swollman } 75418316Swollman flags = 0; 75518316Swollman break; 75618316Swollman } 75718316Swollman 75818316Swollman if (rdisc_sock < 0) 75918316Swollman get_rdisc_sock(); 76018316Swollman 761126250Sbms trace_rdisc(msg, ifp->int_addr, rsin.sin_addr.s_addr, ifp, 76218316Swollman p, p_size); 76318316Swollman 76418316Swollman if (0 > sendto(rdisc_sock, p, p_size, flags, 765126250Sbms (struct sockaddr *)&rsin, sizeof(rsin))) { 76618316Swollman if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 76718316Swollman msglog("sendto(%s%s%s): %s", 76818316Swollman ifp != 0 ? ifp->int_name : "", 76918316Swollman ifp != 0 ? ", " : "", 770126250Sbms inet_ntoa(rsin.sin_addr), 77118316Swollman strerror(errno)); 77218316Swollman if (ifp != 0) 77318316Swollman if_sick(ifp); 77418316Swollman } 77518316Swollman} 77618316Swollman 77718316Swollman 77818316Swollman/* Send an advertisement 77918316Swollman */ 78018316Swollmanstatic void 78118316Swollmansend_adv(struct interface *ifp, 78246303Smarkm naddr dst, /* 0 or unicast destination */ 78318316Swollman int type) /* 0=unicast, 1=bcast, 2=mcast */ 78418316Swollman{ 78518316Swollman union ad_u u; 78618316Swollman n_long pref; 78718316Swollman 78818316Swollman 78946303Smarkm memset(&u, 0, sizeof(u.ad)); 79018316Swollman 79118316Swollman u.ad.icmp_type = ICMP_ROUTERADVERT; 79218316Swollman u.ad.icmp_ad_num = 1; 79318316Swollman u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 79418316Swollman 79518316Swollman u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 79618316Swollman 79746303Smarkm /* Convert the configured preference to an unsigned value, 79846303Smarkm * bias it by the interface metric, and then send it as a 79946303Smarkm * signed, network byte order value. 80046303Smarkm */ 80146303Smarkm pref = UNSIGN_PREF(ifp->int_rdisc_pref); 80246303Smarkm u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 80346303Smarkm 80418316Swollman u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 80518316Swollman 80618316Swollman u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 80718316Swollman 80818316Swollman send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 80918316Swollman} 81018316Swollman 81118316Swollman 81218316Swollman/* Advertise for Router Discovery 81318316Swollman */ 81418316Swollmanvoid 81518316Swollmanrdisc_adv(void) 81618316Swollman{ 81718316Swollman struct interface *ifp; 81818316Swollman 81919880Swollman if (!supplier) 82019880Swollman return; 82118316Swollman 82218316Swollman rdisc_timer.tv_sec = now.tv_sec + NEVER; 82318316Swollman 824190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 82519880Swollman if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 82618316Swollman continue; 82718316Swollman 82818316Swollman if (!timercmp(&ifp->int_rdisc_timer, &now, >) 82918316Swollman || stopint) { 83018316Swollman send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 83118316Swollman (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 83218316Swollman ifp->int_rdisc_cnt++; 83318316Swollman 83418316Swollman intvl_random(&ifp->int_rdisc_timer, 83518316Swollman (ifp->int_rdisc_int*3)/4, 83618316Swollman ifp->int_rdisc_int); 83718316Swollman if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 83818316Swollman && (ifp->int_rdisc_timer.tv_sec 83918316Swollman > MAX_INITIAL_ADVERT_INTERVAL)) { 84018316Swollman ifp->int_rdisc_timer.tv_sec 84118316Swollman = MAX_INITIAL_ADVERT_INTERVAL; 84218316Swollman } 84318316Swollman timevaladd(&ifp->int_rdisc_timer, &now); 84418316Swollman } 84518316Swollman 84618316Swollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 84718316Swollman rdisc_timer = ifp->int_rdisc_timer; 84818316Swollman } 84918316Swollman} 85018316Swollman 85118316Swollman 85218316Swollman/* Solicit for Router Discovery 85318316Swollman */ 85418316Swollmanvoid 85518316Swollmanrdisc_sol(void) 85618316Swollman{ 85718316Swollman struct interface *ifp; 85818316Swollman union ad_u u; 85918316Swollman 86018316Swollman 86119880Swollman if (supplier) 86219880Swollman return; 86319880Swollman 86418316Swollman rdisc_timer.tv_sec = now.tv_sec + NEVER; 86518316Swollman 866190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 86719880Swollman if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 86818316Swollman || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 86918316Swollman continue; 87018316Swollman 87118316Swollman if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 87246303Smarkm memset(&u, 0, sizeof(u.so)); 87318316Swollman u.so.icmp_type = ICMP_ROUTERSOLICIT; 87418316Swollman u.so.icmp_cksum = in_cksum((u_short*)&u.so, 87518316Swollman sizeof(u.so)); 87618316Swollman send_rdisc(&u, sizeof(u.so), ifp, 87718316Swollman htonl(INADDR_ALLROUTERS_GROUP), 87818316Swollman ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 87918316Swollman 88018316Swollman if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 88118316Swollman continue; 88218316Swollman 88318316Swollman ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 88418316Swollman ifp->int_rdisc_timer.tv_usec = 0; 88518316Swollman timevaladd(&ifp->int_rdisc_timer, &now); 88618316Swollman } 88718316Swollman 88818316Swollman if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 88918316Swollman rdisc_timer = ifp->int_rdisc_timer; 89018316Swollman } 89118316Swollman} 89218316Swollman 89318316Swollman 89418316Swollman/* check the IP header of a possible Router Discovery ICMP packet */ 89518316Swollmanstatic struct interface * /* 0 if bad */ 89646303Smarkmck_icmp(const char *act, 89718316Swollman naddr from, 89819880Swollman struct interface *ifp, 89918316Swollman naddr to, 90018316Swollman union ad_u *p, 90118316Swollman u_int len) 90218316Swollman{ 90346303Smarkm const char *type; 90418316Swollman 90518316Swollman 90618316Swollman if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 90718316Swollman type = "advertisement"; 90818316Swollman } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 90918316Swollman type = "solicitation"; 91018316Swollman } else { 91118316Swollman return 0; 91218316Swollman } 91318316Swollman 91418316Swollman if (p->icmp.icmp_code != 0) { 91519880Swollman trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 91618316Swollman type, p->icmp.icmp_code, 91718316Swollman naddr_ntoa(from), naddr_ntoa(to)); 91818316Swollman return 0; 91918316Swollman } 92018316Swollman 92118316Swollman trace_rdisc(act, from, to, ifp, p, len); 92218316Swollman 92318316Swollman if (ifp == 0) 92418316Swollman trace_pkt("unknown interface for router-discovery %s" 92518316Swollman " from %s to %s", 92618316Swollman type, naddr_ntoa(from), naddr_ntoa(to)); 92718316Swollman 92818316Swollman return ifp; 92918316Swollman} 93018316Swollman 93118316Swollman 93218316Swollman/* read packets from the router discovery socket 93318316Swollman */ 93418316Swollmanvoid 93518316Swollmanread_d(void) 93618316Swollman{ 93719880Swollman static struct msg_limit bad_asize, bad_len; 93820606Swollman#ifdef USE_PASSIFNAME 93920606Swollman static struct msg_limit bad_name; 94020606Swollman#endif 94118316Swollman struct sockaddr_in from; 94218316Swollman int n, fromlen, cc, hlen; 94319880Swollman struct { 94419880Swollman#ifdef USE_PASSIFNAME 94519880Swollman char ifname[IFNAMSIZ]; 94619880Swollman#endif 94719880Swollman union { 94819880Swollman struct ip ip; 94919880Swollman u_char b[512]; 95019880Swollman } pkt; 95119880Swollman } buf; 95218316Swollman union ad_u *p; 95318316Swollman n_long *wp; 95418316Swollman struct interface *ifp; 95518316Swollman 95618316Swollman 95718316Swollman for (;;) { 95818316Swollman fromlen = sizeof(from); 95919880Swollman cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 96018316Swollman (struct sockaddr*)&from, 96118316Swollman &fromlen); 96218316Swollman if (cc <= 0) { 96318316Swollman if (cc < 0 && errno != EWOULDBLOCK) 96418316Swollman LOGERR("recvfrom(rdisc_sock)"); 96518316Swollman break; 96618316Swollman } 96718316Swollman if (fromlen != sizeof(struct sockaddr_in)) 96818316Swollman logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 96918316Swollman fromlen); 97019880Swollman#ifdef USE_PASSIFNAME 97119880Swollman if ((cc -= sizeof(buf.ifname)) < 0) 97219880Swollman logbad(0,"missing USE_PASSIFNAME; only %d bytes", 97319880Swollman cc+sizeof(buf.ifname)); 97419880Swollman#endif 97518316Swollman 97619880Swollman hlen = buf.pkt.ip.ip_hl << 2; 97718316Swollman if (cc < hlen + ICMP_MINLEN) 97818316Swollman continue; 97919880Swollman p = (union ad_u *)&buf.pkt.b[hlen]; 98018316Swollman cc -= hlen; 98118316Swollman 98219880Swollman#ifdef USE_PASSIFNAME 98319880Swollman ifp = ifwithname(buf.ifname, 0); 98420606Swollman if (ifp == 0) 98520606Swollman msglim(&bad_name, from.sin_addr.s_addr, 98620606Swollman "impossible rdisc if_ name %.*s", 98720606Swollman IFNAMSIZ, buf.ifname); 98819880Swollman#else 98919880Swollman /* If we could tell the interface on which a packet from 99019880Swollman * address 0 arrived, we could deal with such solicitations. 99119880Swollman */ 99219880Swollman ifp = ((from.sin_addr.s_addr == 0) 99319880Swollman ? 0 : iflookup(from.sin_addr.s_addr)); 99419880Swollman#endif 99520606Swollman ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 99620606Swollman buf.pkt.ip.ip_dst.s_addr, p, cc); 99718316Swollman if (ifp == 0) 99818316Swollman continue; 99918316Swollman if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 100020606Swollman trace_pkt(" " 100120606Swollman "discard our own Router Discovery message"); 100218316Swollman continue; 100318316Swollman } 100418316Swollman 100518316Swollman switch (p->icmp.icmp_type) { 100618316Swollman case ICMP_ROUTERADVERT: 100718316Swollman if (p->ad.icmp_ad_asize*4 100846303Smarkm < (int)sizeof(p->ad.icmp_ad_info[0])) { 100919880Swollman msglim(&bad_asize, from.sin_addr.s_addr, 101019880Swollman "intolerable rdisc address size=%d", 101119880Swollman p->ad.icmp_ad_asize); 101218316Swollman continue; 101318316Swollman } 101418316Swollman if (p->ad.icmp_ad_num == 0) { 101519880Swollman trace_pkt(" empty?"); 101618316Swollman continue; 101718316Swollman } 101846303Smarkm if (cc != (int)(sizeof(p->ad) 101946303Smarkm - sizeof(p->ad.icmp_ad_info) 102046303Smarkm + (p->ad.icmp_ad_num 102146303Smarkm * sizeof(p->ad.icmp_ad_info[0])))) { 102219880Swollman msglim(&bad_len, from.sin_addr.s_addr, 102319880Swollman "rdisc length %d does not match ad_num" 102419880Swollman " %d", cc, p->ad.icmp_ad_num); 102518316Swollman continue; 102618316Swollman } 102718316Swollman if (supplier) 102818316Swollman continue; 102918316Swollman if (ifp->int_state & IS_NO_ADV_IN) 103018316Swollman continue; 103118316Swollman 103218316Swollman wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 103318316Swollman for (n = 0; n < p->ad.icmp_ad_num; n++) { 103418316Swollman parse_ad(from.sin_addr.s_addr, 103518316Swollman wp[0], wp[1], 103618316Swollman ntohs(p->ad.icmp_ad_life), 103718316Swollman ifp); 103818316Swollman wp += p->ad.icmp_ad_asize; 103918316Swollman } 104018316Swollman break; 104118316Swollman 104218316Swollman 104318316Swollman case ICMP_ROUTERSOLICIT: 104418316Swollman if (!supplier) 104518316Swollman continue; 104618316Swollman if (ifp->int_state & IS_NO_ADV_OUT) 104718316Swollman continue; 104846303Smarkm if (stopint) 104946303Smarkm continue; 105018316Swollman 105118316Swollman /* XXX 105218316Swollman * We should handle messages from address 0. 105318316Swollman */ 105418316Swollman 105518316Swollman /* Respond with a point-to-point advertisement */ 105618316Swollman send_adv(ifp, from.sin_addr.s_addr, 0); 105718316Swollman break; 105818316Swollman } 105918316Swollman } 106018316Swollman 106118316Swollman rdisc_sort(); 106218316Swollman} 1063