118334Speter/* 290277Sobrien * Copyright (c) 1995 390277Sobrien * The Regents of the University of California. All rights reserved. 418334Speter * 590277Sobrien * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 790277Sobrien * are met: 890277Sobrien * 1. Redistributions of source code must retain the above copyright 990277Sobrien * notice, this list of conditions and the following disclaimer. 1090277Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1290277Sobrien * documentation and/or other materials provided with the distribution. 1390277Sobrien * 4. Neither the name of the University nor the names of its contributors 1490277Sobrien * may be used to endorse or promote products derived from this software 1590277Sobrien * without specific prior written permission. 1618334Speter * 1718334Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1890277Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1990277Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2090277Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2551232Sbde * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2651232Sbde * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718334Speter * SUCH DAMAGE. 2818334Speter * 2918334Speter * $FreeBSD: releng/10.2/sbin/routed/rdisc.c 190718 2009-04-05 17:33:07Z phk $ 3018334Speter */ 3118334Speter 3218334Speter#include "defs.h" 3318334Speter#include <netinet/in_systm.h> 3418334Speter#include <netinet/ip.h> 3518334Speter#include <netinet/ip_icmp.h> 3690277Sobrien 3790277Sobrien#ifdef __NetBSD__ 3890277Sobrien__RCSID("$NetBSD$"); 3990277Sobrien#elif defined(__FreeBSD__) 4090277Sobrien__RCSID("$FreeBSD: releng/10.2/sbin/routed/rdisc.c 190718 2009-04-05 17:33:07Z phk $"); 4190277Sobrien#else 4290277Sobrien__RCSID("$Revision: 2.27 $"); 4390277Sobrien#ident "$Revision: 2.27 $" 4490277Sobrien#endif 4590277Sobrien 4690277Sobrien/* router advertisement ICMP packet */ 4790277Sobrienstruct icmp_ad { 4890277Sobrien u_int8_t icmp_type; /* type of message */ 4990277Sobrien u_int8_t icmp_code; /* type sub code */ 5090277Sobrien u_int16_t icmp_cksum; /* ones complement cksum of struct */ 5190277Sobrien u_int8_t icmp_ad_num; /* # of following router addresses */ 5290277Sobrien u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 5390277Sobrien u_int16_t icmp_ad_life; /* seconds of validity */ 5490277Sobrien struct icmp_ad_info { 5590277Sobrien n_long icmp_ad_addr; 5690277Sobrien n_long icmp_ad_pref; 5790277Sobrien } icmp_ad_info[1]; 5890277Sobrien}; 5990277Sobrien 6090277Sobrien/* router solicitation ICMP packet */ 6190277Sobrienstruct icmp_so { 6290277Sobrien u_int8_t icmp_type; /* type of message */ 6390277Sobrien u_int8_t icmp_code; /* type sub code */ 6490277Sobrien u_int16_t icmp_cksum; /* ones complement cksum of struct */ 6590277Sobrien n_long icmp_so_rsvd; 6690277Sobrien}; 6790277Sobrien 6890277Sobrienunion ad_u { 6990277Sobrien struct icmp icmp; 7090277Sobrien struct icmp_ad ad; 7190277Sobrien struct icmp_so so; 7290277Sobrien}; 7390277Sobrien 7490277Sobrien 7550599Sobrienint rdisc_sock = -1; /* router-discovery raw socket */ 7650599Sobrienstatic const struct interface *rdisc_sock_mcast; /* current multicast interface */ 7750599Sobrien 7890277Sobrienstruct timeval rdisc_timer; 7990277Sobrienint rdisc_ok; /* using solicited route */ 8090277Sobrien 8150599Sobrien 8252520Sobrien#define MAX_ADS 16 /* at least one per interface */ 8352520Sobrienstruct dr { /* accumulated advertisements */ 8490277Sobrien struct interface *dr_ifp; 8590277Sobrien naddr dr_gate; /* gateway */ 8618334Speter time_t dr_ts; /* when received */ 8790277Sobrien time_t dr_life; /* lifetime in host byte order */ 8890277Sobrien n_long dr_recv_pref; /* received but biased preference */ 8918334Speter n_long dr_pref; /* preference adjusted by metric */ 9090277Sobrien}; 9190277Sobrienstatic const struct dr *cur_drp; 9290277Sobrienstatic struct dr drs[MAX_ADS]; 9318334Speter 9490277Sobrien/* convert between signed, balanced around zero, 9590277Sobrien * and unsigned zero-based preferences */ 9690277Sobrien#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) 9790277Sobrien#define UNSIGN_PREF(p) SIGN_PREF(p) 9818334Speter/* adjust unsigned preference by interface metric, 9918334Speter * without driving it to infinity */ 10090277Sobrien#define PREF(p, ifp) ((int)(p) <= ((ifp)->int_metric+(ifp)->int_adj_outmetric)\ 10190277Sobrien ? ((p) != 0 ? 1 : 0) \ 10290277Sobrien : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric)) 10318334Speter 10490277Sobrienstatic void rdisc_sort(void); 10518334Speter 10618334Speter 10790277Sobrien/* dump an ICMP Router Discovery Advertisement Message 10890277Sobrien */ 10990277Sobrienstatic void 11090277Sobrientrace_rdisc(const char *act, 11190277Sobrien naddr from, 11218334Speter naddr to, 11318334Speter struct interface *ifp, 11490277Sobrien union ad_u *p, 11590277Sobrien u_int len) 11690277Sobrien{ 11790277Sobrien int i; 11890277Sobrien n_long *wp, *lim; 11990277Sobrien 12090277Sobrien 12118334Speter if (!TRACEPACKETS || ftrace == 0) 12290277Sobrien return; 12352520Sobrien 12490277Sobrien lastlog(); 12590277Sobrien 12690277Sobrien if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 12790277Sobrien (void)fprintf(ftrace, "%s Router Ad" 12890277Sobrien " from %s to %s via %s life=%d\n", 12950599Sobrien act, naddr_ntoa(from), naddr_ntoa(to), 13050599Sobrien ifp ? ifp->int_name : "?", 13118334Speter ntohs(p->ad.icmp_ad_life)); 13218334Speter if (!TRACECONTENTS) 13318334Speter return; 13418334Speter 13518334Speter wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 13618334Speter lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 13718334Speter for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 13890277Sobrien (void)fprintf(ftrace, "\t%s preference=%d", 13990277Sobrien naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 14090277Sobrien wp += p->ad.icmp_ad_asize; 14190277Sobrien } 14290277Sobrien (void)fputc('\n',ftrace); 14390277Sobrien 14490277Sobrien } else { 14590277Sobrien trace_act("%s Router Solic. from %s to %s via %s value=%#x", 14690277Sobrien act, naddr_ntoa(from), naddr_ntoa(to), 14790277Sobrien ifp ? ifp->int_name : "?", 14818334Speter (int)ntohl(p->so.icmp_so_rsvd)); 14918334Speter } 15018334Speter} 15118334Speter 15218334Speter/* prepare Router Discovery socket. 15318334Speter */ 15418334Speterstatic void 15518334Speterget_rdisc_sock(void) 15652520Sobrien{ 15718334Speter if (rdisc_sock < 0) { 15850599Sobrien rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 15918334Speter if (rdisc_sock < 0) 16052520Sobrien BADERR(1,"rdisc_sock = socket()"); 16118334Speter fix_sock(rdisc_sock,"rdisc_sock"); 16218334Speter fix_select(); 16318334Speter } 16418334Speter} 16518334Speter 16618334Speter 167104763Skan/* Pick multicast group for router-discovery socket 168104763Skan */ 169104763Skanvoid 170104763Skanset_rdisc_mg(struct interface *ifp, 171104763Skan int on) /* 0=turn it off */ 17218334Speter{ 17318334Speter struct group_req gr; 17418334Speter struct sockaddr_in *sin; 17518334Speter 17618334Speter assert(ifp != NULL); 17750599Sobrien 17850599Sobrien if (rdisc_sock < 0) { 17950599Sobrien /* Create the raw socket so that we can hear at least 18050599Sobrien * broadcast router discovery packets. 18150599Sobrien */ 18218334Speter if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 18318334Speter || !on) 18418334Speter return; 18518334Speter get_rdisc_sock(); 18690277Sobrien } 18790277Sobrien 18890277Sobrien if (!(ifp->int_if_flags & IFF_MULTICAST)) { 18990277Sobrien ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 19090277Sobrien return; 19190277Sobrien } 19290277Sobrien 19390277Sobrien memset(&gr, 0, sizeof(gr)); 19490277Sobrien gr.gr_interface = ifp->int_index; 19590277Sobrien sin = (struct sockaddr_in *)&gr.gr_group; 19690277Sobrien sin->sin_family = AF_INET; 19790277Sobrien#ifdef _HAVE_SIN_LEN 19890277Sobrien sin->sin_len = sizeof(struct sockaddr_in); 19990277Sobrien#endif 20090277Sobrien 20190277Sobrien if (supplier 20218334Speter || (ifp->int_state & IS_NO_ADV_IN) 20318334Speter || !on) { 20418334Speter /* stop listening to advertisements 20518334Speter */ 20618334Speter if (ifp->int_state & IS_ALL_HOSTS) { 20718334Speter sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 20818334Speter if (setsockopt(rdisc_sock, IPPROTO_IP, 20990277Sobrien MCAST_LEAVE_GROUP, 21018334Speter &gr, sizeof(gr)) < 0) 21118334Speter LOGERR("MCAST_LEAVE_GROUP ALLHOSTS"); 21218334Speter ifp->int_state &= ~IS_ALL_HOSTS; 213117413Skan } 21418334Speter 21518334Speter } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 21618334Speter /* start listening to advertisements 21752520Sobrien */ 21818334Speter sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 21918334Speter if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 22018334Speter &gr, sizeof(gr)) < 0) { 22118334Speter LOGERR("MCAST_JOIN_GROUP ALLHOSTS"); 22218334Speter } else { 22390277Sobrien ifp->int_state |= IS_ALL_HOSTS; 22418334Speter } 22590277Sobrien } 22618334Speter 22718334Speter if (!supplier 22890277Sobrien || (ifp->int_state & IS_NO_ADV_OUT) 22990277Sobrien || !on) { 23090277Sobrien /* stop listening to solicitations 23190277Sobrien */ 23290277Sobrien if (ifp->int_state & IS_ALL_ROUTERS) { 23390277Sobrien sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 23490277Sobrien if (setsockopt(rdisc_sock, IPPROTO_IP, 23590277Sobrien MCAST_LEAVE_GROUP, 23690277Sobrien &gr, sizeof(gr)) < 0) 23790277Sobrien LOGERR("MCAST_LEAVE_GROUP ALLROUTERS"); 23890277Sobrien ifp->int_state &= ~IS_ALL_ROUTERS; 23990277Sobrien } 24090277Sobrien 24190277Sobrien } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 242117413Skan /* start hearing solicitations 24318334Speter */ 244117413Skan sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); 24518334Speter if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 24618334Speter &gr, sizeof(gr)) < 0) { 24790277Sobrien LOGERR("MCAST_JOIN_GROUP ALLROUTERS"); 24890277Sobrien } else { 24990277Sobrien ifp->int_state |= IS_ALL_ROUTERS; 25090277Sobrien } 25118334Speter } 25218334Speter} 25318334Speter 25418334Speter 25518334Speter/* start supplying routes 25618334Speter */ 25718334Spetervoid 25818334Speterset_supplier(void) 25918334Speter{ 26018334Speter struct interface *ifp; 26118334Speter struct dr *drp; 26290277Sobrien 26390277Sobrien if (supplier_set) 26490277Sobrien return; 26590277Sobrien 26690277Sobrien trace_act("start supplying routes"); 26718334Speter 26818334Speter /* Forget discovered routes. 26918334Speter */ 27018334Speter for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 27190277Sobrien drp->dr_recv_pref = 0; 27290277Sobrien drp->dr_life = 0; 27390277Sobrien } 27490277Sobrien rdisc_age(0); 27590277Sobrien 27690277Sobrien supplier_set = 1; 27790277Sobrien supplier = 1; 27890277Sobrien 27990277Sobrien /* Do not start advertising until we have heard some RIP routes */ 280104763Skan LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 281104763Skan 28290277Sobrien /* Switch router discovery multicast groups from soliciting 283104763Skan * to advertising. 28490277Sobrien */ 28590277Sobrien LIST_FOREACH(ifp, &ifnet, int_list) { 28690277Sobrien if (ifp->int_state & IS_BROKE) 28790277Sobrien continue; 28890277Sobrien ifp->int_rdisc_cnt = 0; 28990277Sobrien ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 29090277Sobrien ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 29190277Sobrien set_rdisc_mg(ifp, 1); 292117413Skan } 293117413Skan 294117413Skan /* get rid of any redirects */ 29590277Sobrien del_redirects(0,0); 29690277Sobrien} 29790277Sobrien 298117413Skan 299117413Skan/* age discovered routes and find the best one 30090277Sobrien */ 30190277Sobrienvoid 30290277Sobrienrdisc_age(naddr bad_gate) 30390277Sobrien{ 30490277Sobrien time_t sec; 30590277Sobrien struct dr *drp; 30690277Sobrien 30790277Sobrien 30890277Sobrien /* If only advertising, then do only that. */ 30990277Sobrien if (supplier) { 31090277Sobrien /* If switching from client to server, get rid of old 31152520Sobrien * default routes. 31290277Sobrien */ 31352520Sobrien if (cur_drp != 0) 31490277Sobrien rdisc_sort(); 31590277Sobrien rdisc_adv(); 31690277Sobrien return; 31790277Sobrien } 31890277Sobrien 31990277Sobrien /* If we are being told about a bad router, 320117413Skan * then age the discovered default route, and if there is 32190277Sobrien * no alternative, solicit a replacement. 32290277Sobrien */ 32390277Sobrien if (bad_gate != 0) { 32490277Sobrien /* Look for the bad discovered default route. 32590277Sobrien * Age it and note its interface. 32690277Sobrien */ 32790277Sobrien for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 32890277Sobrien if (drp->dr_ts == 0) 32990277Sobrien continue; 33090277Sobrien 331117413Skan /* When we find the bad router, then age the route 332117413Skan * to at most SUPPLY_INTERVAL. 333117413Skan * This is contrary to RFC 1256, but defends against 33490277Sobrien * black holes. 33590277Sobrien */ 33618334Speter if (drp->dr_gate == bad_gate) { 33790277Sobrien sec = (now.tv_sec - drp->dr_life 33818334Speter + SUPPLY_INTERVAL); 33918334Speter if (drp->dr_ts > sec) { 34018334Speter trace_act("age 0.0.0.0 --> %s via %s", 34118334Speter naddr_ntoa(drp->dr_gate), 34218334Speter drp->dr_ifp->int_name); 34318334Speter drp->dr_ts = sec; 34418334Speter } 34518334Speter break; 34618334Speter } 34718334Speter } 34818334Speter } 34918334Speter 35018334Speter rdisc_sol(); 35118334Speter rdisc_sort(); 35218334Speter 35318334Speter /* Delete old redirected routes to keep the kernel table small, 35418334Speter * and to prevent black holes. Check that the kernel table 35590277Sobrien * matches the daemon table (i.e. has the default route). 35650599Sobrien * But only if RIP is not running and we are not dealing with 35750599Sobrien * a bad gateway, since otherwise age() will be called. 35850599Sobrien */ 35950599Sobrien if (rip_sock < 0 && bad_gate == 0) 36050599Sobrien age(0); 36150599Sobrien} 36250599Sobrien 36390277Sobrien 36490277Sobrien/* Zap all routes discovered via an interface that has gone bad 36590277Sobrien * This should only be called when !(ifp->int_state & IS_ALIAS) 36690277Sobrien */ 36790277Sobrienvoid 36850599Sobrienif_bad_rdisc(struct interface *ifp) 36950599Sobrien{ 37050599Sobrien struct dr *drp; 37150599Sobrien 37250599Sobrien for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 37350599Sobrien if (drp->dr_ifp != ifp) 37450599Sobrien continue; 37550599Sobrien drp->dr_recv_pref = 0; 37650599Sobrien drp->dr_ts = 0; 37750599Sobrien drp->dr_life = 0; 37850599Sobrien } 37950599Sobrien 38090277Sobrien /* make a note to re-solicit, turn RIP on or off, etc. */ 38190277Sobrien rdisc_timer.tv_sec = 0; 38290277Sobrien} 38390277Sobrien 38490277Sobrien 38590277Sobrien/* mark an interface ok for router discovering. 38690277Sobrien */ 38790277Sobrienvoid 38890277Sobrienif_ok_rdisc(struct interface *ifp) 38990277Sobrien{ 39018334Speter set_rdisc_mg(ifp, 1); 39118334Speter 39218334Speter ifp->int_rdisc_cnt = 0; 39318334Speter ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 39418334Speter ? MIN_WAITTIME 39518334Speter : MAX_SOLICITATION_DELAY); 39618334Speter if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 39718334Speter rdisc_timer = ifp->int_rdisc_timer; 39818334Speter} 39918334Speter 40018334Speter 40118334Speter/* get rid of a dead discovered router 40218334Speter */ 40318334Speterstatic void 40418334Speterdel_rdisc(struct dr *drp) 40518334Speter{ 40650599Sobrien struct interface *ifp; 40790277Sobrien naddr gate; 40890277Sobrien int i; 40990277Sobrien 41090277Sobrien 41190277Sobrien del_redirects(gate = drp->dr_gate, 0); 41290277Sobrien drp->dr_ts = 0; 41390277Sobrien drp->dr_life = 0; 41418334Speter 41518334Speter 41618334Speter /* Count the other discovered routes on the interface. 41718334Speter */ 41818334Speter i = 0; 41918334Speter ifp = drp->dr_ifp; 42018334Speter for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 42118334Speter if (drp->dr_ts != 0 42218334Speter && drp->dr_ifp == ifp) 42318334Speter i++; 42418334Speter } 425117413Skan 42618334Speter /* If that was the last good discovered router on the interface, 42718334Speter * then solicit a new one. 42818334Speter * This is contrary to RFC 1256, but defends against black holes. 42918334Speter */ 43018334Speter if (i != 0) { 43190277Sobrien trace_act("discovered router %s via %s" 43218334Speter " is bad--have %d remaining", 43390277Sobrien naddr_ntoa(gate), ifp->int_name, i); 43490277Sobrien } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 43590277Sobrien trace_act("last discovered router %s via %s" 43618334Speter " is bad--re-solicit", 43718334Speter naddr_ntoa(gate), ifp->int_name); 43818334Speter ifp->int_rdisc_cnt = 0; 43918334Speter ifp->int_rdisc_timer.tv_sec = 0; 44050599Sobrien rdisc_sol(); 44118334Speter } else { 44218334Speter trace_act("last discovered router %s via %s" 44318334Speter " is bad--wait to solicit", 44418334Speter naddr_ntoa(gate), ifp->int_name); 44518334Speter } 44690277Sobrien} 44790277Sobrien 44818334Speter 44918334Speter/* Find the best discovered route, 45090277Sobrien * and discard stale routers. 45118334Speter */ 45218334Speterstatic void 45318334Speterrdisc_sort(void) 45418334Speter{ 45518334Speter struct dr *drp, *new_drp; 45618334Speter struct rt_entry *rt; 457117413Skan struct rt_spare new; 458117413Skan struct interface *ifp; 459117413Skan u_int new_st = 0; 460117413Skan n_long new_pref = 0; 461117413Skan 462117413Skan 46318334Speter /* Find the best discovered route. 46418334Speter */ 46518334Speter new_drp = 0; 46618334Speter for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 46790277Sobrien if (drp->dr_ts == 0) 46818334Speter continue; 46918334Speter ifp = drp->dr_ifp; 47018334Speter 47150599Sobrien /* Get rid of expired discovered routers. 47290277Sobrien */ 47390277Sobrien if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 47490277Sobrien del_rdisc(drp); 47590277Sobrien continue; 47618334Speter } 47718334Speter 47818334Speter LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 47918334Speter 48090277Sobrien /* Update preference with possibly changed interface 48190277Sobrien * metric. 48290277Sobrien */ 48390277Sobrien drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 48418334Speter 48518334Speter /* Prefer the current route to prevent thrashing. 48618334Speter * Prefer shorter lifetimes to speed the detection of 48718334Speter * bad routers. 48818334Speter * Avoid sick interfaces. 48918334Speter */ 49050599Sobrien if (new_drp == 0 49150599Sobrien || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 49218334Speter && (new_pref < drp->dr_pref 49318334Speter || (new_pref == drp->dr_pref 49418334Speter && (drp == cur_drp 49518334Speter || (new_drp != cur_drp 49618334Speter && new_drp->dr_life > drp->dr_life))))) 49718334Speter || ((new_st & IS_SICK) 49818334Speter && !(drp->dr_ifp->int_state & IS_SICK))) { 49918334Speter new_drp = drp; 50018334Speter new_st = drp->dr_ifp->int_state; 50118334Speter new_pref = drp->dr_pref; 50218334Speter } 50318334Speter } 50418334Speter 50550599Sobrien /* switch to a better default route 50650599Sobrien */ 50750599Sobrien if (new_drp != cur_drp) { 50818334Speter rt = rtget(RIP_DEFAULT, 0); 50918334Speter 51018334Speter /* Stop using discovered routes if they are all bad 51118334Speter */ 51218334Speter if (new_drp == 0) { 51318334Speter trace_act("turn off Router Discovery client"); 51418334Speter rdisc_ok = 0; 51518334Speter 51618334Speter if (rt != 0 51718334Speter && (rt->rt_state & RS_RDISC)) { 51818334Speter new = rt->rt_spares[0]; 51918334Speter new.rts_metric = HOPCNT_INFINITY; 52018334Speter new.rts_time = now.tv_sec - GARBAGE_TIME; 52196285Sobrien rtchange(rt, rt->rt_state & ~RS_RDISC, 52218334Speter &new, 0); 52318334Speter rtswitch(rt, 0); 52418334Speter } 52518334Speter 52618334Speter } else { 52718334Speter if (cur_drp == 0) { 52818334Speter trace_act("turn on Router Discovery client" 52918334Speter " using %s via %s", 53018334Speter naddr_ntoa(new_drp->dr_gate), 53118334Speter new_drp->dr_ifp->int_name); 53218334Speter rdisc_ok = 1; 53318334Speter 53418334Speter } else { 53518334Speter trace_act("switch Router Discovery from" 53618334Speter " %s via %s to %s via %s", 53718334Speter naddr_ntoa(cur_drp->dr_gate), 53818334Speter cur_drp->dr_ifp->int_name, 53918334Speter naddr_ntoa(new_drp->dr_gate), 54018334Speter new_drp->dr_ifp->int_name); 54118334Speter } 54218334Speter 54318334Speter memset(&new, 0, sizeof(new)); 54418334Speter new.rts_ifp = new_drp->dr_ifp; 54518334Speter new.rts_gate = new_drp->dr_gate; 54618334Speter new.rts_router = new_drp->dr_gate; 54718334Speter new.rts_metric = HOPCNT_INFINITY-1; 54818334Speter new.rts_time = now.tv_sec; 54918334Speter if (rt != 0) { 55018334Speter rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); 55118334Speter } else { 55218334Speter rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); 55318334Speter } 55418334Speter } 55518334Speter 55618334Speter cur_drp = new_drp; 55718334Speter } 55818334Speter 55918334Speter /* turn RIP on or off */ 56018334Speter if (!rdisc_ok || rip_interfaces > 1) { 56118334Speter rip_on(0); 56218334Speter } else { 56318334Speter rip_off(); 56418334Speter } 56518334Speter} 56618334Speter 56718334Speter 56818334Speter/* handle a single address in an advertisement 56950599Sobrien */ 57018334Speterstatic void 57150599Sobrienparse_ad(naddr from, 57218334Speter naddr gate, 57318334Speter n_long pref, /* signed and in network order */ 57418334Speter u_short life, /* in host byte order */ 57518334Speter struct interface *ifp) 57618334Speter{ 57718334Speter static struct msg_limit bad_gate; 57818334Speter struct dr *drp, *new_drp; 57918334Speter 58018334Speter 58150599Sobrien if (gate == RIP_DEFAULT 58250599Sobrien || !check_dst(gate)) { 58318334Speter msglim(&bad_gate, from,"router %s advertising bad gateway %s", 58418334Speter naddr_ntoa(from), 58518334Speter naddr_ntoa(gate)); 58618334Speter return; 58718334Speter } 58818334Speter 58918334Speter /* ignore pointers to ourself and routes via unreachable networks 59018334Speter */ 59118334Speter if (ifwithaddr(gate, 1, 0) != 0) { 59250599Sobrien trace_pkt(" discard Router Discovery Ad pointing at us"); 59350599Sobrien return; 59418334Speter } 59518334Speter if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 59690277Sobrien trace_pkt(" discard Router Discovery Ad" 59790277Sobrien " toward unreachable net"); 59890277Sobrien return; 59990277Sobrien } 60090277Sobrien 60190277Sobrien /* Convert preference to an unsigned value 60290277Sobrien * and later bias it by the metric of the interface. 60390277Sobrien */ 60490277Sobrien pref = UNSIGN_PREF(ntohl(pref)); 60590277Sobrien 60690277Sobrien if (pref == 0 || life < MinMaxAdvertiseInterval) { 60790277Sobrien pref = 0; 60890277Sobrien life = 0; 60990277Sobrien } 61090277Sobrien 61190277Sobrien for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { 61290277Sobrien /* accept new info for a familiar entry 61390277Sobrien */ 61490277Sobrien if (drp->dr_gate == gate) { 61590277Sobrien new_drp = drp; 61690277Sobrien break; 61718334Speter } 61890277Sobrien 61990277Sobrien if (life == 0) 62096285Sobrien continue; /* do not worry about dead ads */ 62196285Sobrien 62296285Sobrien if (drp->dr_ts == 0) { 62396285Sobrien new_drp = drp; /* use unused entry */ 62496285Sobrien 62596285Sobrien } else if (new_drp == 0) { 62696285Sobrien /* look for an entry worse than the new one to 62790277Sobrien * reuse. 62890277Sobrien */ 62990277Sobrien if ((!(ifp->int_state & IS_SICK) 63090277Sobrien && (drp->dr_ifp->int_state & IS_SICK)) 63190277Sobrien || (pref > drp->dr_pref 63290277Sobrien && !((ifp->int_state ^ drp->dr_ifp->int_state) 63390277Sobrien & IS_SICK))) 63490277Sobrien new_drp = drp; 63590277Sobrien 63690277Sobrien } else if (new_drp->dr_ts != 0) { 63790277Sobrien /* look for the least valuable entry to reuse 63896285Sobrien */ 63990277Sobrien if ((!(new_drp->dr_ifp->int_state & IS_SICK) 64090277Sobrien && (drp->dr_ifp->int_state & IS_SICK)) 64190277Sobrien || (new_drp->dr_pref > drp->dr_pref 64290277Sobrien && !((new_drp->dr_ifp->int_state 64390277Sobrien ^ drp->dr_ifp->int_state) 64490277Sobrien & IS_SICK))) 64590277Sobrien new_drp = drp; 64690277Sobrien } 64790277Sobrien } 64890277Sobrien 64990277Sobrien /* forget it if all of the current entries are better */ 65090277Sobrien if (new_drp == 0) 65190277Sobrien return; 652117413Skan 653117413Skan new_drp->dr_ifp = ifp; 654117413Skan new_drp->dr_gate = gate; 655117413Skan new_drp->dr_ts = now.tv_sec; 656117413Skan new_drp->dr_life = life; 65790277Sobrien new_drp->dr_recv_pref = pref; 65890277Sobrien /* bias functional preference by metric of the interface */ 65990277Sobrien new_drp->dr_pref = PREF(pref,ifp); 66090277Sobrien 66196285Sobrien /* after hearing a good advertisement, stop asking 66290277Sobrien */ 66390277Sobrien if (!(ifp->int_state & IS_SICK)) 66490277Sobrien ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 66590277Sobrien} 66690277Sobrien 66790277Sobrien 66890277Sobrien/* Compute the IP checksum 66990277Sobrien * This assumes the packet is less than 32K long. 67090277Sobrien */ 67190277Sobrienstatic u_short 67290277Sobrienin_cksum(u_short *p, 673117413Skan u_int len) 67490277Sobrien{ 67590277Sobrien u_int sum = 0; 67690277Sobrien int nwords = len >> 1; 67790277Sobrien 67890277Sobrien while (nwords-- != 0) 67990277Sobrien sum += *p++; 68090277Sobrien 681117413Skan if (len & 1) 682117413Skan sum += *(u_char *)p; 683117413Skan 68490277Sobrien /* end-around-carry */ 685117413Skan sum = (sum >> 16) + (sum & 0xffff); 68690277Sobrien sum += (sum >> 16); 687107594Sobrien return (~sum); 688107594Sobrien} 689107594Sobrien 69090277Sobrien 69190277Sobrien/* Send a router discovery advertisement or solicitation ICMP packet. 692117413Skan */ 693117413Skanstatic void 694107594Sobriensend_rdisc(union ad_u *p, 695107594Sobrien int p_size, 696107594Sobrien struct interface *ifp, 69796285Sobrien naddr dst, /* 0 or unicast destination */ 698117413Skan int type) /* 0=unicast, 1=bcast, 2=mcast */ 69990277Sobrien{ 700117413Skan struct sockaddr_in rsin; 70196285Sobrien int flags; 70290277Sobrien const char *msg; 70390277Sobrien 704117413Skan 705117413Skan memset(&rsin, 0, sizeof(rsin)); 706117413Skan rsin.sin_addr.s_addr = dst; 707117413Skan rsin.sin_family = AF_INET; 70890277Sobrien#ifdef _HAVE_SIN_LEN 709117413Skan rsin.sin_len = sizeof(rsin); 710117413Skan#endif 71190277Sobrien flags = MSG_DONTROUTE; 712117413Skan 713117413Skan switch (type) { 714117413Skan case 0: /* unicast */ 715117413Skan default: 71690277Sobrien msg = "Send"; 71790277Sobrien break; 71890277Sobrien 71990277Sobrien case 1: /* broadcast */ 720117413Skan if (ifp->int_if_flags & IFF_POINTOPOINT) { 721117413Skan msg = "Send pt-to-pt"; 722117413Skan rsin.sin_addr.s_addr = ifp->int_dstaddr; 72390277Sobrien } else { 72490277Sobrien msg = "Send broadcast"; 72590277Sobrien rsin.sin_addr.s_addr = ifp->int_brdaddr; 72690277Sobrien } 72790277Sobrien break; 72890277Sobrien 72990277Sobrien case 2: /* multicast */ 73090277Sobrien msg = "Send multicast"; 73190277Sobrien if (ifp->int_state & IS_DUP) { 73290277Sobrien trace_act("abort multicast output via %s" 73390277Sobrien " with duplicate address", 73450599Sobrien ifp->int_name); 73550599Sobrien return; 73650599Sobrien } 73750599Sobrien if (rdisc_sock_mcast != ifp) { 73890277Sobrien /* select the right interface. */ 73990277Sobrien struct ip_mreqn mreqn; 74090277Sobrien 74190277Sobrien memset(&mreqn, 0, sizeof(struct ip_mreqn)); 74250599Sobrien mreqn.imr_ifindex = ifp->int_index; 74350599Sobrien if (0 > setsockopt(rdisc_sock, 74450599Sobrien IPPROTO_IP, IP_MULTICAST_IF, 74550599Sobrien &mreqn, 74650599Sobrien sizeof(mreqn))) { 74750599Sobrien LOGERR("setsockopt(rdisc_sock," 74850599Sobrien "IP_MULTICAST_IF)"); 74950599Sobrien rdisc_sock_mcast = 0; 75090277Sobrien return; 75150599Sobrien } 752117413Skan rdisc_sock_mcast = ifp; 753117413Skan } 754117413Skan flags = 0; 755117413Skan break; 756117413Skan } 757117413Skan 75890277Sobrien if (rdisc_sock < 0) 75990277Sobrien get_rdisc_sock(); 76050599Sobrien 76152520Sobrien trace_rdisc(msg, ifp->int_addr, rsin.sin_addr.s_addr, ifp, 76250599Sobrien p, p_size); 76350599Sobrien 76450599Sobrien if (0 > sendto(rdisc_sock, p, p_size, flags, 76550599Sobrien (struct sockaddr *)&rsin, sizeof(rsin))) { 76650599Sobrien if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 76750599Sobrien msglog("sendto(%s%s%s): %s", 76818334Speter ifp != 0 ? ifp->int_name : "", 76918334Speter ifp != 0 ? ", " : "", 77018334Speter inet_ntoa(rsin.sin_addr), 77118334Speter strerror(errno)); 77218334Speter if (ifp != 0) 77318334Speter if_sick(ifp); 77490277Sobrien } 77550599Sobrien} 77650599Sobrien 77750599Sobrien 77850599Sobrien/* Send an advertisement 77950599Sobrien */ 78050599Sobrienstatic void 78150599Sobriensend_adv(struct interface *ifp, 78250599Sobrien naddr dst, /* 0 or unicast destination */ 78350599Sobrien int type) /* 0=unicast, 1=bcast, 2=mcast */ 78450599Sobrien{ 78518334Speter union ad_u u; 78618334Speter n_long pref; 78718334Speter 78818334Speter 78952520Sobrien memset(&u, 0, sizeof(u.ad)); 79018334Speter 79118334Speter u.ad.icmp_type = ICMP_ROUTERADVERT; 79290277Sobrien u.ad.icmp_ad_num = 1; 79390277Sobrien u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 79490277Sobrien 79590277Sobrien u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 79690277Sobrien 79718334Speter /* Convert the configured preference to an unsigned value, 79818334Speter * bias it by the interface metric, and then send it as a 79918334Speter * signed, network byte order value. 80018334Speter */ 80118334Speter pref = UNSIGN_PREF(ifp->int_rdisc_pref); 80218334Speter u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 80318334Speter 80418334Speter u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 80518334Speter 80618334Speter u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 80718334Speter 80818334Speter send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 80918334Speter} 81018334Speter 81118334Speter 81218334Speter/* Advertise for Router Discovery 81318334Speter */ 81418334Spetervoid 81518334Speterrdisc_adv(void) 81690277Sobrien{ 81718334Speter struct interface *ifp; 81850599Sobrien 81950599Sobrien if (!supplier) 82050599Sobrien return; 82150599Sobrien 82290277Sobrien rdisc_timer.tv_sec = now.tv_sec + NEVER; 82390277Sobrien 82490277Sobrien LIST_FOREACH(ifp, &ifnet, int_list) { 82590277Sobrien if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 82690277Sobrien continue; 82790277Sobrien 82890277Sobrien if (!timercmp(&ifp->int_rdisc_timer, &now, >) 82990277Sobrien || stopint) { 83090277Sobrien send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 83190277Sobrien (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 83290277Sobrien ifp->int_rdisc_cnt++; 83350599Sobrien 83490277Sobrien intvl_random(&ifp->int_rdisc_timer, 83518334Speter (ifp->int_rdisc_int*3)/4, 83690277Sobrien ifp->int_rdisc_int); 837117413Skan if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 838117413Skan && (ifp->int_rdisc_timer.tv_sec 83990277Sobrien > MAX_INITIAL_ADVERT_INTERVAL)) { 840117413Skan ifp->int_rdisc_timer.tv_sec 841117413Skan = MAX_INITIAL_ADVERT_INTERVAL; 842117413Skan } 84396285Sobrien timevaladd(&ifp->int_rdisc_timer, &now); 84496285Sobrien } 845117413Skan 846117413Skan if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 84790277Sobrien rdisc_timer = ifp->int_rdisc_timer; 84818334Speter } 84990277Sobrien} 850117413Skan 85190277Sobrien 85218334Speter/* Solicit for Router Discovery 85390277Sobrien */ 854117413Skanvoid 855117413Skanrdisc_sol(void) 85690277Sobrien{ 85718334Speter struct interface *ifp; 85890277Sobrien union ad_u u; 85990277Sobrien 86018334Speter 86190277Sobrien if (supplier) 86290277Sobrien return; 86318334Speter 86490277Sobrien rdisc_timer.tv_sec = now.tv_sec + NEVER; 865117413Skan 86690277Sobrien LIST_FOREACH(ifp, &ifnet, int_list) { 86790277Sobrien if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 86818334Speter || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 86918334Speter continue; 87090277Sobrien 87118334Speter if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 87218334Speter memset(&u, 0, sizeof(u.so)); 87318334Speter u.so.icmp_type = ICMP_ROUTERSOLICIT; 87418334Speter u.so.icmp_cksum = in_cksum((u_short*)&u.so, 875117413Skan sizeof(u.so)); 87618334Speter send_rdisc(&u, sizeof(u.so), ifp, 87718334Speter htonl(INADDR_ALLROUTERS_GROUP), 87818334Speter ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 87918334Speter 88018334Speter if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 88118334Speter continue; 88218334Speter 88318334Speter ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 88418334Speter ifp->int_rdisc_timer.tv_usec = 0; 88518334Speter timevaladd(&ifp->int_rdisc_timer, &now); 88618334Speter } 88718334Speter 88818334Speter if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 88918334Speter rdisc_timer = ifp->int_rdisc_timer; 89018334Speter } 89118334Speter} 89218334Speter 89318334Speter 89418334Speter/* check the IP header of a possible Router Discovery ICMP packet */ 89518334Speterstatic struct interface * /* 0 if bad */ 89618334Speterck_icmp(const char *act, 89718334Speter naddr from, 89818334Speter struct interface *ifp, 89918334Speter naddr to, 90018334Speter union ad_u *p, 90190277Sobrien u_int len) 90218334Speter{ 90390277Sobrien const char *type; 90418334Speter 90518334Speter 90618334Speter if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 90718334Speter type = "advertisement"; 90818334Speter } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 90990277Sobrien type = "solicitation"; 91018334Speter } else { 91118334Speter return 0; 91218334Speter } 91318334Speter 91418334Speter if (p->icmp.icmp_code != 0) { 91590277Sobrien trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 91618334Speter type, p->icmp.icmp_code, 91718334Speter naddr_ntoa(from), naddr_ntoa(to)); 91818334Speter return 0; 91918334Speter } 92018334Speter 92152520Sobrien trace_rdisc(act, from, to, ifp, p, len); 92296285Sobrien 92396285Sobrien if (ifp == 0) 92418334Speter trace_pkt("unknown interface for router-discovery %s" 925117413Skan " from %s to %s", 92618334Speter type, naddr_ntoa(from), naddr_ntoa(to)); 92718334Speter 92850599Sobrien return ifp; 92918334Speter} 93018334Speter 93118334Speter 93218334Speter/* read packets from the router discovery socket 93318334Speter */ 93418334Spetervoid 93518334Speterread_d(void) 93618334Speter{ 93718334Speter static struct msg_limit bad_asize, bad_len; 93818334Speter#ifdef USE_PASSIFNAME 93918334Speter static struct msg_limit bad_name; 94050599Sobrien#endif 94118334Speter struct sockaddr_in from; 94218334Speter int n, fromlen, cc, hlen; 94318334Speter struct { 94418334Speter#ifdef USE_PASSIFNAME 94518334Speter char ifname[IFNAMSIZ]; 94618334Speter#endif 94718334Speter union { 94818334Speter struct ip ip; 94918334Speter u_char b[512]; 95096285Sobrien } pkt; 95118334Speter } buf; 95218334Speter union ad_u *p; 95318334Speter n_long *wp; 95418334Speter struct interface *ifp; 95518334Speter 95618334Speter 95718334Speter for (;;) { 95852520Sobrien fromlen = sizeof(from); 95990277Sobrien cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 96018334Speter (struct sockaddr*)&from, 96118334Speter &fromlen); 96218334Speter if (cc <= 0) { 96318334Speter if (cc < 0 && errno != EWOULDBLOCK) 96418334Speter LOGERR("recvfrom(rdisc_sock)"); 96518334Speter break; 96618334Speter } 96718334Speter if (fromlen != sizeof(struct sockaddr_in)) 96818334Speter logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 96918334Speter fromlen); 97018334Speter#ifdef USE_PASSIFNAME 971104763Skan if ((cc -= sizeof(buf.ifname)) < 0) 97218334Speter logbad(0,"missing USE_PASSIFNAME; only %d bytes", 97318334Speter cc+sizeof(buf.ifname)); 97418334Speter#endif 97518334Speter 97696285Sobrien hlen = buf.pkt.ip.ip_hl << 2; 97718334Speter if (cc < hlen + ICMP_MINLEN) 97818334Speter continue; 97918334Speter p = (union ad_u *)&buf.pkt.b[hlen]; 98050599Sobrien cc -= hlen; 98118334Speter 98252520Sobrien#ifdef USE_PASSIFNAME 98318334Speter ifp = ifwithname(buf.ifname, 0); 98418334Speter if (ifp == 0) 98590277Sobrien msglim(&bad_name, from.sin_addr.s_addr, 98618334Speter "impossible rdisc if_ name %.*s", 98718334Speter IFNAMSIZ, buf.ifname); 98818334Speter#else 98918334Speter /* If we could tell the interface on which a packet from 99050599Sobrien * address 0 arrived, we could deal with such solicitations. 99118334Speter */ 99218334Speter ifp = ((from.sin_addr.s_addr == 0) 99318334Speter ? 0 : iflookup(from.sin_addr.s_addr)); 99418334Speter#endif 99518334Speter ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 99618334Speter buf.pkt.ip.ip_dst.s_addr, p, cc); 99718334Speter if (ifp == 0) 99818334Speter continue; 99918334Speter if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 100090277Sobrien trace_pkt(" " 100190277Sobrien "discard our own Router Discovery message"); 100290277Sobrien continue; 100390277Sobrien } 100490277Sobrien 100590277Sobrien switch (p->icmp.icmp_type) { 100690277Sobrien case ICMP_ROUTERADVERT: 100790277Sobrien if (p->ad.icmp_ad_asize*4 100890277Sobrien < (int)sizeof(p->ad.icmp_ad_info[0])) { 100990277Sobrien msglim(&bad_asize, from.sin_addr.s_addr, 101090277Sobrien "intolerable rdisc address size=%d", 101190277Sobrien p->ad.icmp_ad_asize); 101218334Speter continue; 101318334Speter } 101418334Speter if (p->ad.icmp_ad_num == 0) { 101518334Speter trace_pkt(" empty?"); 101618334Speter continue; 101718334Speter } 101818334Speter if (cc != (int)(sizeof(p->ad) 101990277Sobrien - sizeof(p->ad.icmp_ad_info) 102018334Speter + (p->ad.icmp_ad_num 102152520Sobrien * sizeof(p->ad.icmp_ad_info[0])))) { 102218334Speter msglim(&bad_len, from.sin_addr.s_addr, 102390277Sobrien "rdisc length %d does not match ad_num" 102490277Sobrien " %d", cc, p->ad.icmp_ad_num); 102552520Sobrien continue; 102690277Sobrien } 102718334Speter if (supplier) 102818334Speter continue; 102918334Speter if (ifp->int_state & IS_NO_ADV_IN) 103018334Speter continue; 103118334Speter 103218334Speter wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 103318334Speter for (n = 0; n < p->ad.icmp_ad_num; n++) { 103490277Sobrien parse_ad(from.sin_addr.s_addr, 103590277Sobrien wp[0], wp[1], 103690277Sobrien ntohs(p->ad.icmp_ad_life), 103790277Sobrien ifp); 103890277Sobrien wp += p->ad.icmp_ad_asize; 103990277Sobrien } 104090277Sobrien break; 104190277Sobrien 104290277Sobrien 104390277Sobrien case ICMP_ROUTERSOLICIT: 104490277Sobrien if (!supplier) 104590277Sobrien continue; 104690277Sobrien if (ifp->int_state & IS_NO_ADV_OUT) 104790277Sobrien continue; 104890277Sobrien if (stopint) 104990277Sobrien continue; 105090277Sobrien 105190277Sobrien /* XXX 105290277Sobrien * We should handle messages from address 0. 105390277Sobrien */ 105490277Sobrien 105590277Sobrien /* Respond with a point-to-point advertisement */ 105690277Sobrien send_adv(ifp, from.sin_addr.s_addr, 0); 105790277Sobrien break; 105890277Sobrien } 105990277Sobrien } 106090277Sobrien 106190277Sobrien rdisc_sort(); 106290277Sobrien} 106390277Sobrien