17c478bd9Sstevel@tonic-gate /* 2*e704a8f2Smeem * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * Copyright (c) 1995 67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 97c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 107c478bd9Sstevel@tonic-gate * are met: 117c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 127c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 137c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 147c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 157c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 167c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 177c478bd9Sstevel@tonic-gate * must display the following acknowledgment: 187c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 197c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 207c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 217c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 227c478bd9Sstevel@tonic-gate * without specific prior written permission. 237c478bd9Sstevel@tonic-gate * 247c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 257c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 267c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 277c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 287c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 297c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 307c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 317c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 327c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 337c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 347c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * $FreeBSD: src/sbin/routed/rdisc.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $ 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include "defs.h" 427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 437c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 447c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 453173664eSapersson #include <fcntl.h> 463173664eSapersson #include <strings.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * The size of the control buffer passed to recvmsg() used to receive 507c478bd9Sstevel@tonic-gate * ancillary data. 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate #define CONTROL_BUFSIZE 1024 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* router advertisement ICMP packet */ 557c478bd9Sstevel@tonic-gate struct icmp_ad { 567c478bd9Sstevel@tonic-gate uint8_t icmp_type; /* type of message */ 577c478bd9Sstevel@tonic-gate uint8_t icmp_code; /* type sub code */ 587c478bd9Sstevel@tonic-gate uint16_t icmp_cksum; /* ones complement cksum of struct */ 597c478bd9Sstevel@tonic-gate uint8_t icmp_ad_num; /* # of following router addresses */ 607c478bd9Sstevel@tonic-gate uint8_t icmp_ad_asize; /* 2--words in each advertisement */ 617c478bd9Sstevel@tonic-gate uint16_t icmp_ad_life; /* seconds of validity */ 627c478bd9Sstevel@tonic-gate struct icmp_ad_info { 637c478bd9Sstevel@tonic-gate in_addr_t icmp_ad_addr; 647c478bd9Sstevel@tonic-gate uint32_t icmp_ad_pref; 657c478bd9Sstevel@tonic-gate } icmp_ad_info[1]; 667c478bd9Sstevel@tonic-gate }; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* router solicitation ICMP packet */ 697c478bd9Sstevel@tonic-gate struct icmp_so { 707c478bd9Sstevel@tonic-gate uint8_t icmp_type; /* type of message */ 717c478bd9Sstevel@tonic-gate uint8_t icmp_code; /* type sub code */ 727c478bd9Sstevel@tonic-gate uint16_t icmp_cksum; /* ones complement cksum of struct */ 737c478bd9Sstevel@tonic-gate uint32_t icmp_so_rsvd; 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate union ad_u { 777c478bd9Sstevel@tonic-gate struct icmp icmp; 787c478bd9Sstevel@tonic-gate struct icmp_ad ad; 797c478bd9Sstevel@tonic-gate struct icmp_so so; 807c478bd9Sstevel@tonic-gate }; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate int rdisc_sock = -1; /* router-discovery raw socket */ 843173664eSapersson int rdisc_mib_sock = -1; /* AF_UNIX mib info socket */ 857c478bd9Sstevel@tonic-gate static struct interface *rdisc_sock_interface; /* current rdisc interface */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate struct timeval rdisc_timer; 887c478bd9Sstevel@tonic-gate boolean_t rdisc_ok; /* using solicited route */ 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #define MAX_ADS 16 917c478bd9Sstevel@tonic-gate int max_ads; /* at least one per interface */ 927c478bd9Sstevel@tonic-gate /* accumulated advertisements */ 933173664eSapersson static struct dr *cur_drp; 943173664eSapersson struct dr *drs; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * adjust unsigned preference by interface metric, 987c478bd9Sstevel@tonic-gate * without driving it to infinity 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate #define PREF(p, ifp) ((p) <= (uint32_t)(ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ 1017c478bd9Sstevel@tonic-gate : (p) - ((ifp)->int_metric)) 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate static void rdisc_sort(void); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate typedef enum { unicast, bcast, mcast } dstaddr_t; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* dump an ICMP Router Discovery Advertisement Message */ 1087c478bd9Sstevel@tonic-gate static void 1097c478bd9Sstevel@tonic-gate trace_rdisc(const char *act, 1107c478bd9Sstevel@tonic-gate uint32_t from, 1117c478bd9Sstevel@tonic-gate uint32_t to, 1127c478bd9Sstevel@tonic-gate struct interface *ifp, 1137c478bd9Sstevel@tonic-gate union ad_u *p, 1147c478bd9Sstevel@tonic-gate uint_t len) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate int i; 1177c478bd9Sstevel@tonic-gate n_long *wp, *lim; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (!TRACEPACKETS || ftrace == 0) 1217c478bd9Sstevel@tonic-gate return; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate lastlog(); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 1267c478bd9Sstevel@tonic-gate (void) fprintf(ftrace, "%s Router Ad" 1277c478bd9Sstevel@tonic-gate " from %s to %s via %s life=%d\n", 1287c478bd9Sstevel@tonic-gate act, naddr_ntoa(from), naddr_ntoa(to), 1297c478bd9Sstevel@tonic-gate ifp ? ifp->int_name : "?", 1307c478bd9Sstevel@tonic-gate ntohs(p->ad.icmp_ad_life)); 1317c478bd9Sstevel@tonic-gate if (!TRACECONTENTS) 1327c478bd9Sstevel@tonic-gate return; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1357c478bd9Sstevel@tonic-gate lim = &wp[(len - sizeof (p->ad)) / sizeof (*wp)]; 1367c478bd9Sstevel@tonic-gate for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 1377c478bd9Sstevel@tonic-gate (void) fprintf(ftrace, "\t%s preference=%ld", 1387c478bd9Sstevel@tonic-gate naddr_ntoa(wp[0]), (long)ntohl(wp[1])); 1397c478bd9Sstevel@tonic-gate wp += p->ad.icmp_ad_asize; 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate (void) fputc('\n', ftrace); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate } else { 1447c478bd9Sstevel@tonic-gate trace_act("%s Router Solic. from %s to %s via %s rsvd=%#x", 1457c478bd9Sstevel@tonic-gate act, naddr_ntoa(from), naddr_ntoa(to), 1467c478bd9Sstevel@tonic-gate ifp ? ifp->int_name : "?", 1477c478bd9Sstevel@tonic-gate ntohl(p->so.icmp_so_rsvd)); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * Prepare Router Discovery socket. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate static void 1557c478bd9Sstevel@tonic-gate get_rdisc_sock(void) 1567c478bd9Sstevel@tonic-gate { 1577c478bd9Sstevel@tonic-gate int on = 1; 1587c478bd9Sstevel@tonic-gate unsigned char ttl = 1; 1593173664eSapersson struct sockaddr_un laddr; 1603173664eSapersson int len; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate if (rdisc_sock < 0) { 1637c478bd9Sstevel@tonic-gate max_ads = MAX_ADS; 1647c478bd9Sstevel@tonic-gate drs = rtmalloc(max_ads * sizeof (struct dr), "get_rdisc_sock"); 1657c478bd9Sstevel@tonic-gate (void) memset(drs, 0, max_ads * sizeof (struct dr)); 1667c478bd9Sstevel@tonic-gate rdisc_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); 1677c478bd9Sstevel@tonic-gate if (rdisc_sock < 0) 1687c478bd9Sstevel@tonic-gate BADERR(_B_TRUE, "rdisc_sock = socket()"); 1697c478bd9Sstevel@tonic-gate fix_sock(rdisc_sock, "rdisc_sock"); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, IP_RECVIF, &on, 1727c478bd9Sstevel@tonic-gate sizeof (on))) 1737c478bd9Sstevel@tonic-gate BADERR(_B_FALSE, "setsockopt(IP_RECVIF)"); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_TTL, 1767c478bd9Sstevel@tonic-gate &ttl, sizeof (ttl)) < 0) 1777c478bd9Sstevel@tonic-gate DBGERR(_B_TRUE, 1787c478bd9Sstevel@tonic-gate "rdisc_sock setsockopt(IP_MULTICAST_TTL)"); 1797c478bd9Sstevel@tonic-gate 1803173664eSapersson /* 1813173664eSapersson * On Solaris also open an AF_UNIX socket to 1823173664eSapersson * pass default router information to mib agent 1833173664eSapersson */ 1843173664eSapersson 1853173664eSapersson rdisc_mib_sock = socket(AF_UNIX, SOCK_DGRAM, 0); 1863173664eSapersson if (rdisc_mib_sock < 0) { 1873173664eSapersson BADERR(_B_TRUE, "rdisc_mib_sock = socket()"); 1883173664eSapersson } 1893173664eSapersson 1903173664eSapersson bzero(&laddr, sizeof (laddr)); 1913173664eSapersson laddr.sun_family = AF_UNIX; 1923173664eSapersson 1933173664eSapersson (void) strncpy(laddr.sun_path, RDISC_SNMP_SOCKET, 1943173664eSapersson sizeof (laddr.sun_path)); 1953173664eSapersson len = sizeof (struct sockaddr_un); 1963173664eSapersson 1973173664eSapersson (void) unlink(RDISC_SNMP_SOCKET); 1983173664eSapersson 1993173664eSapersson if (bind(rdisc_mib_sock, (struct sockaddr *)&laddr, len) < 0) { 2003173664eSapersson BADERR(_B_TRUE, "bind(rdisc_mib_sock)"); 2013173664eSapersson } 2023173664eSapersson 2033173664eSapersson if (fcntl(rdisc_mib_sock, F_SETFL, O_NONBLOCK) < 0) { 2043173664eSapersson BADERR(_B_TRUE, "rdisc_mib_sock fcntl O_NONBLOCK"); 2053173664eSapersson } 2063173664eSapersson 2077c478bd9Sstevel@tonic-gate fix_select(); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * Pick multicast group for router-discovery socket 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate void 2167c478bd9Sstevel@tonic-gate set_rdisc_mg(struct interface *ifp, 2177c478bd9Sstevel@tonic-gate int on) /* 0=turn it off */ 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate struct ip_mreq m; 2207c478bd9Sstevel@tonic-gate boolean_t dosupply; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (rdisc_sock < 0) { 2237c478bd9Sstevel@tonic-gate /* 2247c478bd9Sstevel@tonic-gate * Create the raw socket so that we can hear at least 2257c478bd9Sstevel@tonic-gate * broadcast router discovery packets. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC || 2287c478bd9Sstevel@tonic-gate !on) 2297c478bd9Sstevel@tonic-gate return; 2307c478bd9Sstevel@tonic-gate get_rdisc_sock(); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (!(ifp->int_if_flags & IFF_MULTICAST)) { 2347c478bd9Sstevel@tonic-gate /* Can't multicast, so no groups could have been joined. */ 2357c478bd9Sstevel@tonic-gate ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 2367c478bd9Sstevel@tonic-gate return; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate dosupply = should_supply(ifp); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate (void) memset(&m, 0, sizeof (m)); 2427c478bd9Sstevel@tonic-gate m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) && 2437c478bd9Sstevel@tonic-gate (ifp->int_dstaddr != 0) ? ifp->int_dstaddr : ifp->int_addr); 2447c478bd9Sstevel@tonic-gate if (dosupply || (ifp->int_state & IS_NO_ADV_IN) || !on) { 2457c478bd9Sstevel@tonic-gate /* stop listening to advertisements */ 2467c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_ALL_HOSTS) { 2477c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 2487c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, 2497c478bd9Sstevel@tonic-gate IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 && 2507c478bd9Sstevel@tonic-gate errno != EADDRNOTAVAIL && errno != ENOENT) 2517c478bd9Sstevel@tonic-gate LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 2527c478bd9Sstevel@tonic-gate ifp->int_state &= ~IS_ALL_HOSTS; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 2567c478bd9Sstevel@tonic-gate /* start listening to advertisements */ 2577c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 2587c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2597c478bd9Sstevel@tonic-gate &m, sizeof (m)) < 0) { 2607c478bd9Sstevel@tonic-gate LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 2617c478bd9Sstevel@tonic-gate } else { 2627c478bd9Sstevel@tonic-gate ifp->int_state |= IS_ALL_HOSTS; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (!dosupply || (ifp->int_state & IS_NO_ADV_OUT) || 2677c478bd9Sstevel@tonic-gate !IS_IFF_ROUTING(ifp->int_if_flags) || !on) { 2687c478bd9Sstevel@tonic-gate /* stop listening to solicitations */ 2697c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_ALL_ROUTERS) { 2707c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP); 2717c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, 2727c478bd9Sstevel@tonic-gate IP_DROP_MEMBERSHIP, &m, sizeof (m)) < 0 && 2737c478bd9Sstevel@tonic-gate errno != EADDRNOTAVAIL && errno != ENOENT) 2747c478bd9Sstevel@tonic-gate LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 2757c478bd9Sstevel@tonic-gate ifp->int_state &= ~IS_ALL_ROUTERS; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 2797c478bd9Sstevel@tonic-gate /* start hearing solicitations */ 2807c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP); 2817c478bd9Sstevel@tonic-gate if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2827c478bd9Sstevel@tonic-gate &m, sizeof (m)) < 0) { 2837c478bd9Sstevel@tonic-gate LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 2847c478bd9Sstevel@tonic-gate } else { 2857c478bd9Sstevel@tonic-gate ifp->int_state |= IS_ALL_ROUTERS; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * start or stop supplying routes to other systems. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate void 2957c478bd9Sstevel@tonic-gate set_supplier(void) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate struct interface *ifp; 2987c478bd9Sstevel@tonic-gate struct dr *drp; 2997c478bd9Sstevel@tonic-gate static boolean_t supplystate = _B_FALSE; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate if (supplystate == (fwd_interfaces > 1)) 3027c478bd9Sstevel@tonic-gate return; 3037c478bd9Sstevel@tonic-gate supplystate = fwd_interfaces > 1; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate trace_act("%d forwarding interfaces present; becoming %ssupplier", 3067c478bd9Sstevel@tonic-gate fwd_interfaces, supplystate ? "" : "non-"); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if (supplystate) { 3097c478bd9Sstevel@tonic-gate /* Forget discovered routes. */ 3107c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 3117c478bd9Sstevel@tonic-gate drp->dr_recv_pref = DEF_PREFERENCELEVEL; 3127c478bd9Sstevel@tonic-gate drp->dr_life = 0; 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate rdisc_age(0); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * Do not start advertising until we have heard some 3187c478bd9Sstevel@tonic-gate * RIP routes. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* get rid of any redirects */ 3237c478bd9Sstevel@tonic-gate del_redirects(0, 0); 3247c478bd9Sstevel@tonic-gate } else { 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Flush out all those advertisements we had sent by sending 3277c478bd9Sstevel@tonic-gate * one with lifetime=0. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate rdisc_adv(_B_TRUE); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Switch router discovery multicast groups from soliciting 3347c478bd9Sstevel@tonic-gate * to advertising or back. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) { 3377c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_BROKE) 3387c478bd9Sstevel@tonic-gate continue; 3397c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt = 0; 3407c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 3417c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 3427c478bd9Sstevel@tonic-gate set_rdisc_mg(ifp, 1); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * Age discovered routes and find the best one 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate void 3517c478bd9Sstevel@tonic-gate rdisc_age(in_addr_t bad_gate) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate time_t sec; 3547c478bd9Sstevel@tonic-gate struct dr *drp; 3557c478bd9Sstevel@tonic-gate struct rt_spare new; 3567c478bd9Sstevel@tonic-gate struct rt_entry *rt; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * If we are being told about a bad router, 3607c478bd9Sstevel@tonic-gate * then age the discovered default route, and if there is 3617c478bd9Sstevel@tonic-gate * no alternative, solicit a replacement. 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate if (bad_gate != 0) { 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Look for the bad discovered default route. 3667c478bd9Sstevel@tonic-gate * Age it and note its interface. 3677c478bd9Sstevel@tonic-gate */ 3687c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 3697c478bd9Sstevel@tonic-gate if (drp->dr_ts == 0) 3707c478bd9Sstevel@tonic-gate continue; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * When we find the bad router, age the route 3747c478bd9Sstevel@tonic-gate * to at most SUPPLY_INTERVAL. 3757c478bd9Sstevel@tonic-gate * This is contrary to RFC 1256, but defends against 3767c478bd9Sstevel@tonic-gate * black holes. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate if (drp->dr_gate == bad_gate) { 3797c478bd9Sstevel@tonic-gate sec = (now.tv_sec - drp->dr_life + 3807c478bd9Sstevel@tonic-gate SUPPLY_INTERVAL); 3817c478bd9Sstevel@tonic-gate if (drp->dr_ts > sec) { 3827c478bd9Sstevel@tonic-gate trace_act("age 0.0.0.0 --> %s via %s", 3837c478bd9Sstevel@tonic-gate naddr_ntoa(drp->dr_gate), 3847c478bd9Sstevel@tonic-gate drp->dr_ifp->int_name); 3857c478bd9Sstevel@tonic-gate drp->dr_ts = sec; 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate break; 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate } else if (should_supply(NULL)) { 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * If switching from client to server, get rid of old 3937c478bd9Sstevel@tonic-gate * default routes. 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate if (cur_drp != NULL) { 3967c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * If there is a current default router, and the 3997c478bd9Sstevel@tonic-gate * there is no rt_spare entry, create one 4007c478bd9Sstevel@tonic-gate * for cur_drp to prevent segmentation fault 4017c478bd9Sstevel@tonic-gate * at rdisc_sort. 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate if (rt == NULL) { 4047c478bd9Sstevel@tonic-gate (void) memset(&new, 0, sizeof (new)); 4057c478bd9Sstevel@tonic-gate new.rts_ifp = cur_drp->dr_ifp; 4067c478bd9Sstevel@tonic-gate new.rts_gate = cur_drp->dr_gate; 4077c478bd9Sstevel@tonic-gate new.rts_router = cur_drp->dr_gate; 4087c478bd9Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY-1; 4097c478bd9Sstevel@tonic-gate new.rts_time = now.tv_sec; 4107c478bd9Sstevel@tonic-gate new.rts_origin = RO_RDISC; 4117c478bd9Sstevel@tonic-gate rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate rdisc_sort(); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate rdisc_adv(_B_FALSE); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate rdisc_sol(); 4207c478bd9Sstevel@tonic-gate if (cur_drp != NULL) { 4217c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 4227c478bd9Sstevel@tonic-gate if (rt == NULL) { 4237c478bd9Sstevel@tonic-gate (void) memset(&new, 0, sizeof (new)); 4247c478bd9Sstevel@tonic-gate new.rts_ifp = cur_drp->dr_ifp; 4257c478bd9Sstevel@tonic-gate new.rts_gate = cur_drp->dr_gate; 4267c478bd9Sstevel@tonic-gate new.rts_router = cur_drp->dr_gate; 4277c478bd9Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY-1; 4287c478bd9Sstevel@tonic-gate new.rts_time = now.tv_sec; 4297c478bd9Sstevel@tonic-gate new.rts_origin = RO_RDISC; 4307c478bd9Sstevel@tonic-gate rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate rdisc_sort(); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Delete old redirected routes to keep the kernel table small, 4377c478bd9Sstevel@tonic-gate * and to prevent black holes. Check that the kernel table 4387c478bd9Sstevel@tonic-gate * matches the daemon table (i.e. has the default route). 4397c478bd9Sstevel@tonic-gate * But only if RIP is not running and we are not dealing with 4407c478bd9Sstevel@tonic-gate * a bad gateway, since otherwise age() will be called. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate if (rip_sock < 0 && bad_gate == 0) 4437c478bd9Sstevel@tonic-gate age(0); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * Zap all routes discovered via an interface that has gone bad 4497c478bd9Sstevel@tonic-gate * This should only be called when !(ifp->int_state & IS_DUP) 4507c478bd9Sstevel@tonic-gate * This is called by if_del and if_bad, and the interface pointer 4517c478bd9Sstevel@tonic-gate * might not be valid after this. 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate void 4547c478bd9Sstevel@tonic-gate if_bad_rdisc(struct interface *ifp) 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate struct dr *drp; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 4597c478bd9Sstevel@tonic-gate if (drp->dr_ifp != ifp) 4607c478bd9Sstevel@tonic-gate continue; 4617c478bd9Sstevel@tonic-gate (void) memset(drp, 0, sizeof (*drp)); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* make a note to re-solicit, turn RIP on or off, etc. */ 4657c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = 0; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Rewire all routes discovered via an interface that has gone bad 4707c478bd9Sstevel@tonic-gate * This is only called by if_del. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate void 4737c478bd9Sstevel@tonic-gate if_rewire_rdisc(struct interface *oldifp, struct interface *newifp) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate struct dr *drp; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 4787c478bd9Sstevel@tonic-gate if (drp->dr_ifp != oldifp) 4797c478bd9Sstevel@tonic-gate continue; 4807c478bd9Sstevel@tonic-gate drp->dr_ifp = newifp; 4817c478bd9Sstevel@tonic-gate drp->dr_pref += (newifp->int_metric - oldifp->int_metric); 4827c478bd9Sstevel@tonic-gate drp->dr_flags |= DR_CHANGED; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* make a note to re-solicit, turn RIP on or off, etc. */ 4867c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = 0; 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * Mark an interface ok for router discovering. 4917c478bd9Sstevel@tonic-gate * This is called by if_ok and ifinit. 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate void 4947c478bd9Sstevel@tonic-gate if_ok_rdisc(struct interface *ifp) 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate set_rdisc_mg(ifp, 1); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt = 0; 4997c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_sec = now.tv_sec + 5007c478bd9Sstevel@tonic-gate ((ifp->int_state & IS_NO_ADV_OUT) ? 5017c478bd9Sstevel@tonic-gate MAX_SOLICITATION_DELAY : MIN_WAITTIME); 5027c478bd9Sstevel@tonic-gate if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, > /* cstyle */)) 5037c478bd9Sstevel@tonic-gate rdisc_timer = ifp->int_rdisc_timer; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Get rid of a dead discovered router 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate static void 5107c478bd9Sstevel@tonic-gate del_rdisc(struct dr *drp) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate struct interface *ifp; 5137c478bd9Sstevel@tonic-gate uint32_t gate; 5147c478bd9Sstevel@tonic-gate int i; 5157c478bd9Sstevel@tonic-gate struct rt_entry *rt; 5167c478bd9Sstevel@tonic-gate struct rt_spare *rts = NULL; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate del_redirects(gate = drp->dr_gate, 0); 5197c478bd9Sstevel@tonic-gate drp->dr_ts = 0; 5207c478bd9Sstevel@tonic-gate drp->dr_life = 0; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 5237c478bd9Sstevel@tonic-gate if (rt == NULL) { 5247c478bd9Sstevel@tonic-gate trace_act("could not find default route in table"); 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate for (i = 0; i < rt->rt_num_spares; i++) { 5277c478bd9Sstevel@tonic-gate if ((rt->rt_spares[i].rts_gate == drp->dr_gate) && 5287c478bd9Sstevel@tonic-gate (rt->rt_spares[i].rts_origin == RO_RDISC)) { 5297c478bd9Sstevel@tonic-gate rts = &rt->rt_spares[i]; 5307c478bd9Sstevel@tonic-gate break; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate if (rts != NULL) 5347c478bd9Sstevel@tonic-gate rts_delete(rt, rts); 5357c478bd9Sstevel@tonic-gate else 5367c478bd9Sstevel@tonic-gate trace_act("could not find default route " 5377c478bd9Sstevel@tonic-gate "through %s in table", naddr_ntoa(drp->dr_gate)); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* Count the other discovered routers on the interface. */ 5417c478bd9Sstevel@tonic-gate i = 0; 5427c478bd9Sstevel@tonic-gate ifp = drp->dr_ifp; 5437c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 5447c478bd9Sstevel@tonic-gate if (drp->dr_ts != 0 && drp->dr_ifp == ifp) 5457c478bd9Sstevel@tonic-gate i++; 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * If that was the last good discovered router on the interface, 5507c478bd9Sstevel@tonic-gate * then solicit a new one. 5517c478bd9Sstevel@tonic-gate * This is contrary to RFC 1256, but defends against black holes. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate if (i != 0) { 5547c478bd9Sstevel@tonic-gate trace_act("discovered router %s via %s" 5557c478bd9Sstevel@tonic-gate " is bad--have %d remaining", 5567c478bd9Sstevel@tonic-gate naddr_ntoa(gate), ifp->int_name, i); 5577c478bd9Sstevel@tonic-gate } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 5587c478bd9Sstevel@tonic-gate trace_act("last discovered router %s via %s" 5597c478bd9Sstevel@tonic-gate " is bad--re-solicit", 5607c478bd9Sstevel@tonic-gate naddr_ntoa(gate), ifp->int_name); 5617c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt = 0; 5627c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_sec = 0; 5637c478bd9Sstevel@tonic-gate rdisc_sol(); 5647c478bd9Sstevel@tonic-gate } else { 5657c478bd9Sstevel@tonic-gate trace_act("last discovered router %s via %s" 5667c478bd9Sstevel@tonic-gate " is bad--wait to solicit", 5677c478bd9Sstevel@tonic-gate naddr_ntoa(gate), ifp->int_name); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /* Find the best discovered route, and discard stale routers. */ 5737c478bd9Sstevel@tonic-gate static void 5747c478bd9Sstevel@tonic-gate rdisc_sort(void) 5757c478bd9Sstevel@tonic-gate { 5767c478bd9Sstevel@tonic-gate struct dr *drp, *new_drp; 5777c478bd9Sstevel@tonic-gate struct rt_entry *rt; 5787c478bd9Sstevel@tonic-gate struct rt_spare new, *rts; 5797c478bd9Sstevel@tonic-gate struct interface *ifp; 5807c478bd9Sstevel@tonic-gate uint_t new_st = 0; 5817c478bd9Sstevel@tonic-gate uint32_t new_pref = DEF_PREFERENCELEVEL; 5827c478bd9Sstevel@tonic-gate int first_rdisc_slot = 0; 5837c478bd9Sstevel@tonic-gate int j; 5847c478bd9Sstevel@tonic-gate boolean_t spares_avail; 5857c478bd9Sstevel@tonic-gate void *ptr; 5867c478bd9Sstevel@tonic-gate size_t ptrsize; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * If all the rt_spare entries are taken up with with default routes 5927c478bd9Sstevel@tonic-gate * learnt from RIP (ie rts_origin = RO_RIP), bail out. 5937c478bd9Sstevel@tonic-gate * NOTE: 5947c478bd9Sstevel@tonic-gate * We *always* prefer default routes learned via RIP 5957c478bd9Sstevel@tonic-gate * (ie RO_RIP) over those learnt via RDISC (ie RO_RDISC). 5967c478bd9Sstevel@tonic-gate * The rdisc machinery should not modify, replace or 5977c478bd9Sstevel@tonic-gate * remove any existing default routes with RO_RIP set. 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate if (rt != NULL) { 6007c478bd9Sstevel@tonic-gate spares_avail = _B_FALSE; 6017c478bd9Sstevel@tonic-gate for (j = 0; j < rt->rt_num_spares; j++) { 6027c478bd9Sstevel@tonic-gate rts = &rt->rt_spares[j]; 60309f979dcSsowmini if (rts->rts_gate == 0 || rts->rts_origin != RO_RIP || 60409f979dcSsowmini rts->rts_ifp == &dummy_ifp) { 6057c478bd9Sstevel@tonic-gate spares_avail = _B_TRUE; 6067c478bd9Sstevel@tonic-gate break; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate if (!spares_avail) { 6107c478bd9Sstevel@tonic-gate ptrsize = (rt->rt_num_spares + SPARE_INC) * 6117c478bd9Sstevel@tonic-gate sizeof (struct rt_spare); 6127c478bd9Sstevel@tonic-gate ptr = realloc(rt->rt_spares, ptrsize); 6137c478bd9Sstevel@tonic-gate if (ptr != NULL) { 6147c478bd9Sstevel@tonic-gate struct rt_spare *tmprts; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate rt->rt_spares = ptr; 6177c478bd9Sstevel@tonic-gate rts = &rt->rt_spares[rt->rt_num_spares]; 6187c478bd9Sstevel@tonic-gate (void) memset(rts, 0, 6197c478bd9Sstevel@tonic-gate (SPARE_INC * sizeof (struct rt_spare))); 6207c478bd9Sstevel@tonic-gate rt->rt_num_spares += SPARE_INC; 6217c478bd9Sstevel@tonic-gate for (tmprts = rts, j = SPARE_INC; 6227c478bd9Sstevel@tonic-gate j != 0; j--, tmprts++) 6237c478bd9Sstevel@tonic-gate tmprts->rts_metric = HOPCNT_INFINITY; 6247c478bd9Sstevel@tonic-gate spares_avail = _B_TRUE; 6257c478bd9Sstevel@tonic-gate } else { 6267c478bd9Sstevel@tonic-gate return; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate /* Find the best RDISC advertiser */ 6317c478bd9Sstevel@tonic-gate rt = NULL; 6327c478bd9Sstevel@tonic-gate new_drp = NULL; 6337c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 6347c478bd9Sstevel@tonic-gate if (drp->dr_ts == 0) 6357c478bd9Sstevel@tonic-gate continue; 6367c478bd9Sstevel@tonic-gate ifp = drp->dr_ifp; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* Get rid of expired discovered routers. */ 6397c478bd9Sstevel@tonic-gate if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 6407c478bd9Sstevel@tonic-gate del_rdisc(drp); 6417c478bd9Sstevel@tonic-gate continue; 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * Update preference with possibly changed interface 6487c478bd9Sstevel@tonic-gate * metric. 6497c478bd9Sstevel@tonic-gate */ 6507c478bd9Sstevel@tonic-gate drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate /* 6537c478bd9Sstevel@tonic-gate * Prefer the current route to prevent thrashing. 6547c478bd9Sstevel@tonic-gate * Prefer shorter lifetimes to speed the detection of 6557c478bd9Sstevel@tonic-gate * bad routers. 6567c478bd9Sstevel@tonic-gate * Avoid sick interfaces. 6577c478bd9Sstevel@tonic-gate */ 6587c478bd9Sstevel@tonic-gate if (new_drp == NULL || 6597c478bd9Sstevel@tonic-gate (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) && 6607c478bd9Sstevel@tonic-gate (new_pref < drp->dr_pref || 6617c478bd9Sstevel@tonic-gate (new_pref == drp->dr_pref && (drp == cur_drp || 6627c478bd9Sstevel@tonic-gate (new_drp != cur_drp && 6637c478bd9Sstevel@tonic-gate new_drp->dr_life > drp->dr_life))))) || 6647c478bd9Sstevel@tonic-gate ((new_st & IS_SICK) && 6657c478bd9Sstevel@tonic-gate !(drp->dr_ifp->int_state & IS_SICK))) { 6667c478bd9Sstevel@tonic-gate new_drp = drp; 6677c478bd9Sstevel@tonic-gate new_st = drp->dr_ifp->int_state; 6687c478bd9Sstevel@tonic-gate new_pref = drp->dr_pref; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * switch to a better RDISC advertiser 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate if ((new_drp != cur_drp) || (rt == NULL)) { 6767c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /* 6797c478bd9Sstevel@tonic-gate * Purge the table of all the default routes that were 6807c478bd9Sstevel@tonic-gate * learnt via RDISC, while keeping an eye the first available 6817c478bd9Sstevel@tonic-gate * slot for the spare entry of new_drp 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate if (rt != NULL) { 6847c478bd9Sstevel@tonic-gate int i; 6857c478bd9Sstevel@tonic-gate for (i = 0; i < rt->rt_num_spares; i++) { 6867c478bd9Sstevel@tonic-gate rts = &rt->rt_spares[i]; 68709f979dcSsowmini if ((rts->rts_gate == 0 || 68809f979dcSsowmini rts->rts_ifp == &dummy_ifp) && 68909f979dcSsowmini first_rdisc_slot == 0) 6907c478bd9Sstevel@tonic-gate first_rdisc_slot = i; 6917c478bd9Sstevel@tonic-gate if (rts->rts_origin == RO_RDISC) { 6927c478bd9Sstevel@tonic-gate rts_delete(rt, rts); 6937c478bd9Sstevel@tonic-gate if (first_rdisc_slot == 0) { 6947c478bd9Sstevel@tonic-gate first_rdisc_slot = i; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* Stop using RDISC routes if they are all bad */ 7017c478bd9Sstevel@tonic-gate if (new_drp == NULL) { 7027c478bd9Sstevel@tonic-gate trace_act("turn off Router Discovery client"); 7037c478bd9Sstevel@tonic-gate rdisc_ok = _B_FALSE; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate } else { 7067c478bd9Sstevel@tonic-gate if (cur_drp == NULL) { 7077c478bd9Sstevel@tonic-gate trace_act("turn on Router Discovery client" 7087c478bd9Sstevel@tonic-gate " using %s via %s", 7097c478bd9Sstevel@tonic-gate naddr_ntoa(new_drp->dr_gate), 7107c478bd9Sstevel@tonic-gate new_drp->dr_ifp->int_name); 7117c478bd9Sstevel@tonic-gate rdisc_ok = _B_TRUE; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* Prepare a spare entry for the new_drp */ 7157c478bd9Sstevel@tonic-gate (void) memset(&new, 0, sizeof (new)); 7167c478bd9Sstevel@tonic-gate new.rts_ifp = new_drp->dr_ifp; 7177c478bd9Sstevel@tonic-gate new.rts_gate = new_drp->dr_gate; 7187c478bd9Sstevel@tonic-gate new.rts_router = new_drp->dr_gate; 7197c478bd9Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY-1; 7207c478bd9Sstevel@tonic-gate new.rts_time = now.tv_sec; 7217c478bd9Sstevel@tonic-gate new.rts_origin = RO_RDISC; 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * If there is no existing default route, add it 7247c478bd9Sstevel@tonic-gate * to rts_spare[0]. 7257c478bd9Sstevel@tonic-gate */ 7267c478bd9Sstevel@tonic-gate if (rt == NULL) { 7277c478bd9Sstevel@tonic-gate rtadd(RIP_DEFAULT, 0, RS_NOPROPAGATE, &new); 7287c478bd9Sstevel@tonic-gate } else { 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * Add the spare entry for the new_drp in 7327c478bd9Sstevel@tonic-gate * the first available slot 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate trace_act("Switching to " 7357c478bd9Sstevel@tonic-gate "default router with better " 7367c478bd9Sstevel@tonic-gate "preference %s via %s ", 7377c478bd9Sstevel@tonic-gate naddr_ntoa(new_drp->dr_gate), 7387c478bd9Sstevel@tonic-gate new_drp->dr_ifp->int_name); 7397c478bd9Sstevel@tonic-gate rt->rt_spares[first_rdisc_slot] = new; 7407c478bd9Sstevel@tonic-gate rt = NULL; /* redo rt_spares */ 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* 7457c478bd9Sstevel@tonic-gate * Get ready to redo the entire table. The table should 7467c478bd9Sstevel@tonic-gate * only include : 7477c478bd9Sstevel@tonic-gate * a. empty rt_spare slots 7487c478bd9Sstevel@tonic-gate * b. default routes learnt via RIP 7497c478bd9Sstevel@tonic-gate * c. default route for the latest best RDISC advertiser 7507c478bd9Sstevel@tonic-gate * d. default routes of other RDISC advertisers whose 7517c478bd9Sstevel@tonic-gate * dr_pref == best RDISC advertiser->dr_pref 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate cur_drp = new_drp; 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate /* Redo the entire spare table (without touching RO_RIP entries) */ 7577c478bd9Sstevel@tonic-gate if (rdisc_ok && rt == NULL) { 7587c478bd9Sstevel@tonic-gate int i; 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate * We've either just turned on router discovery, 7617c478bd9Sstevel@tonic-gate * or switched to a router with better preference. 7627c478bd9Sstevel@tonic-gate * Find all other default routers whose 7637c478bd9Sstevel@tonic-gate * pref == cur_drp->dr_pref and add them as spares 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate rt = rtget(RIP_DEFAULT, 0); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) { 7697c478bd9Sstevel@tonic-gate boolean_t dr_done = _B_FALSE; 7707c478bd9Sstevel@tonic-gate int slot = -1; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate if (drp->dr_ts == 0) 7737c478bd9Sstevel@tonic-gate continue; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (drp->dr_pref != cur_drp->dr_pref && 7767c478bd9Sstevel@tonic-gate ((drp->dr_flags & DR_CHANGED) == 0)) 7777c478bd9Sstevel@tonic-gate continue; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * Either pref matches cur_drp->dr_pref, 7817c478bd9Sstevel@tonic-gate * or something has changed in this drp. 7827c478bd9Sstevel@tonic-gate * In the former case, we may need to add 7837c478bd9Sstevel@tonic-gate * this to rt_spares. In the latter case, 7847c478bd9Sstevel@tonic-gate * if the pref has changed, need to take it 7857c478bd9Sstevel@tonic-gate * out of rt_spares and the kernel. 7867c478bd9Sstevel@tonic-gate * 7877c478bd9Sstevel@tonic-gate * First, find an empty slot in rt_spares 7887c478bd9Sstevel@tonic-gate * in case we have to add this drp to kernel. 7897c478bd9Sstevel@tonic-gate * Also check if it is already there. 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate for (i = 0; i < rt->rt_num_spares; i++) { 7927c478bd9Sstevel@tonic-gate if (rt->rt_spares[i].rts_gate == 0) { 7937c478bd9Sstevel@tonic-gate if (slot < 0) 7947c478bd9Sstevel@tonic-gate slot = i; 7957c478bd9Sstevel@tonic-gate continue; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate if ((rt->rt_spares[i].rts_gate == 7987c478bd9Sstevel@tonic-gate drp->dr_gate) && 7997c478bd9Sstevel@tonic-gate (rt->rt_spares[i].rts_origin == 8007c478bd9Sstevel@tonic-gate RO_RDISC)) { 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * a spare entry for this RDISC 8037c478bd9Sstevel@tonic-gate * advertiser already exists. We need 8047c478bd9Sstevel@tonic-gate * to check if this entry still belongs 8057c478bd9Sstevel@tonic-gate * in the table 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate dr_done = _B_TRUE; 8087c478bd9Sstevel@tonic-gate break; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate drp->dr_flags &= ~DR_CHANGED; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (drp->dr_pref != cur_drp->dr_pref) { 8157c478bd9Sstevel@tonic-gate if (dr_done) { 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate * The rt_spare of this RDISC advertiser 8187c478bd9Sstevel@tonic-gate * needs to be removed as it no longer 8197c478bd9Sstevel@tonic-gate * belongs in the table because its 8207c478bd9Sstevel@tonic-gate * dr_pref is different than the latest 8217c478bd9Sstevel@tonic-gate * RDISC advertiser's->dr_pref 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate rts_delete(rt, &rt->rt_spares[i]); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate continue; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 82809f979dcSsowmini if (slot < 0 && !dr_done) { 8297c478bd9Sstevel@tonic-gate ptrsize = (rt->rt_num_spares + SPARE_INC) * 8307c478bd9Sstevel@tonic-gate sizeof (struct rt_spare); 8317c478bd9Sstevel@tonic-gate ptr = realloc(rt->rt_spares, ptrsize); 8327c478bd9Sstevel@tonic-gate if (ptr != NULL) { 8337c478bd9Sstevel@tonic-gate struct rt_spare *tmprts; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate rt->rt_spares = ptr; 8367c478bd9Sstevel@tonic-gate slot = rt->rt_num_spares; 8377c478bd9Sstevel@tonic-gate rts = &rt->rt_spares[rt->rt_num_spares]; 8387c478bd9Sstevel@tonic-gate (void) memset(rts, 0, (SPARE_INC * 8397c478bd9Sstevel@tonic-gate sizeof (struct rt_spare))); 8407c478bd9Sstevel@tonic-gate rt->rt_num_spares += SPARE_INC; 8417c478bd9Sstevel@tonic-gate for (tmprts = rts, i = SPARE_INC; 8427c478bd9Sstevel@tonic-gate i != 0; i--, tmprts++) 8437c478bd9Sstevel@tonic-gate tmprts->rts_metric = 8447c478bd9Sstevel@tonic-gate HOPCNT_INFINITY; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (slot >= 0 && (dr_done != _B_TRUE)) { 8497c478bd9Sstevel@tonic-gate (void) memset(&new, 0, sizeof (new)); 8507c478bd9Sstevel@tonic-gate new.rts_ifp = drp->dr_ifp; 8517c478bd9Sstevel@tonic-gate new.rts_gate = drp->dr_gate; 8527c478bd9Sstevel@tonic-gate new.rts_router = drp->dr_gate; 8537c478bd9Sstevel@tonic-gate new.rts_metric = HOPCNT_INFINITY-1; 8547c478bd9Sstevel@tonic-gate new.rts_time = now.tv_sec; 8557c478bd9Sstevel@tonic-gate new.rts_origin = RO_RDISC; 8567c478bd9Sstevel@tonic-gate rt->rt_spares[slot] = new; 8577c478bd9Sstevel@tonic-gate trace_act("spare default %s via %s", 8587c478bd9Sstevel@tonic-gate naddr_ntoa(drp->dr_gate), 8597c478bd9Sstevel@tonic-gate drp->dr_ifp->int_name); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* turn RIP on or off */ 8657c478bd9Sstevel@tonic-gate if (!rdisc_ok || rip_interfaces > 1) { 8667c478bd9Sstevel@tonic-gate rip_on(0); 8677c478bd9Sstevel@tonic-gate } else { 8687c478bd9Sstevel@tonic-gate rip_off(); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* Handle a single address in an advertisement */ 8747c478bd9Sstevel@tonic-gate static void 8757c478bd9Sstevel@tonic-gate parse_ad(uint32_t from, 8767c478bd9Sstevel@tonic-gate in_addr_t gate, 8777c478bd9Sstevel@tonic-gate uint32_t pref, /* signed and in network order */ 8787c478bd9Sstevel@tonic-gate ushort_t life, /* in host byte order */ 8797c478bd9Sstevel@tonic-gate struct interface *ifp) 8807c478bd9Sstevel@tonic-gate { 8817c478bd9Sstevel@tonic-gate static struct msg_limit bad_gate; 8827c478bd9Sstevel@tonic-gate struct dr *drp, *new_drp; 8837c478bd9Sstevel@tonic-gate void *ptr; 8847c478bd9Sstevel@tonic-gate size_t ptrsize; 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate if (gate == RIP_DEFAULT || !check_dst(gate)) { 8877c478bd9Sstevel@tonic-gate msglim(&bad_gate, from, "router %s advertising bad gateway %s", 8887c478bd9Sstevel@tonic-gate naddr_ntoa(from), naddr_ntoa(gate)); 8897c478bd9Sstevel@tonic-gate return; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * ignore pointers to ourself and routes via unreachable networks 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate if (ifwithaddr(gate, _B_TRUE, _B_FALSE) != 0) { 8967c478bd9Sstevel@tonic-gate trace_pkt(" discard Router Discovery Ad pointing at us"); 8977c478bd9Sstevel@tonic-gate return; 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 9007c478bd9Sstevel@tonic-gate trace_pkt(" discard Router Discovery Ad" 9017c478bd9Sstevel@tonic-gate " toward unreachable net"); 9027c478bd9Sstevel@tonic-gate return; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Convert preference to an unsigned value 9067c478bd9Sstevel@tonic-gate * and later bias it by the metric of the interface. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate pref = UNSIGN_PREF(ntohl(pref)); 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate if (pref == DEF_PREFERENCELEVEL || life < MIN_MAXADVERTISEINTERVAL) { 9117c478bd9Sstevel@tonic-gate pref = DEF_PREFERENCELEVEL; 9127c478bd9Sstevel@tonic-gate life = 0; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate for (new_drp = NULL, drp = drs; drp < &drs[max_ads]; drp++) { 9167c478bd9Sstevel@tonic-gate /* accept new info for a familiar entry */ 9177c478bd9Sstevel@tonic-gate if ((drp->dr_gate == gate) && (drp->dr_ifp == ifp)) { 9187c478bd9Sstevel@tonic-gate new_drp = drp; 9197c478bd9Sstevel@tonic-gate drp->dr_flags |= DR_CHANGED; 9207c478bd9Sstevel@tonic-gate break; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (life == 0) 9247c478bd9Sstevel@tonic-gate continue; /* do not worry about dead ads */ 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate if (drp->dr_ts == 0) { 9277c478bd9Sstevel@tonic-gate new_drp = drp; /* use unused entry */ 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate } else if (new_drp == NULL) { 9307c478bd9Sstevel@tonic-gate /* look for an entry worse than the new one to reuse. */ 9317c478bd9Sstevel@tonic-gate if ((!(ifp->int_state & IS_SICK) && 9327c478bd9Sstevel@tonic-gate (drp->dr_ifp->int_state & IS_SICK)) || 9337c478bd9Sstevel@tonic-gate (pref > drp->dr_pref && 9347c478bd9Sstevel@tonic-gate !((ifp->int_state ^ drp->dr_ifp->int_state) & 9357c478bd9Sstevel@tonic-gate IS_SICK))) 9367c478bd9Sstevel@tonic-gate new_drp = drp; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate } else if (new_drp->dr_ts != 0) { 9397c478bd9Sstevel@tonic-gate /* look for the least valuable entry to reuse */ 9407c478bd9Sstevel@tonic-gate if ((!(new_drp->dr_ifp->int_state & IS_SICK) && 9417c478bd9Sstevel@tonic-gate (drp->dr_ifp->int_state & IS_SICK)) || 9427c478bd9Sstevel@tonic-gate (new_drp->dr_pref > drp->dr_pref && 9437c478bd9Sstevel@tonic-gate !((new_drp->dr_ifp->int_state ^ 9447c478bd9Sstevel@tonic-gate drp->dr_ifp->int_state) & IS_SICK))) 9457c478bd9Sstevel@tonic-gate new_drp = drp; 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* if all of the current entries are better, add more drs[] */ 9507c478bd9Sstevel@tonic-gate if (new_drp == NULL) { 9517c478bd9Sstevel@tonic-gate ptrsize = (max_ads + MAX_ADS) * sizeof (struct dr); 9527c478bd9Sstevel@tonic-gate ptr = realloc(drs, ptrsize); 9537c478bd9Sstevel@tonic-gate if (ptr == NULL) 9547c478bd9Sstevel@tonic-gate return; 9557c478bd9Sstevel@tonic-gate drs = ptr; 9567c478bd9Sstevel@tonic-gate (void) memset(&drs[max_ads], 0, MAX_ADS * sizeof (struct dr)); 9577c478bd9Sstevel@tonic-gate new_drp = &drs[max_ads]; 9587c478bd9Sstevel@tonic-gate max_ads += MAX_ADS; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Pointer copy is safe here because if_del 9637c478bd9Sstevel@tonic-gate * calls if_bad_rdisc first, so a non-NULL df_ifp 9647c478bd9Sstevel@tonic-gate * is always a valid pointer. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate new_drp->dr_ifp = ifp; 9677c478bd9Sstevel@tonic-gate new_drp->dr_gate = gate; 9687c478bd9Sstevel@tonic-gate new_drp->dr_ts = now.tv_sec; 9697c478bd9Sstevel@tonic-gate new_drp->dr_life = life; 9707c478bd9Sstevel@tonic-gate new_drp->dr_recv_pref = pref; 9717c478bd9Sstevel@tonic-gate /* bias functional preference by metric of the interface */ 9727c478bd9Sstevel@tonic-gate new_drp->dr_pref = PREF(pref, ifp); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* after hearing a good advertisement, stop asking */ 9757c478bd9Sstevel@tonic-gate if (!(ifp->int_state & IS_SICK)) 9767c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Compute the IP checksum. This assumes the packet is less than 32K long. 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate static uint16_t 9847c478bd9Sstevel@tonic-gate in_cksum(uint16_t *p, uint_t len) 9857c478bd9Sstevel@tonic-gate { 9867c478bd9Sstevel@tonic-gate uint32_t sum = 0; 9877c478bd9Sstevel@tonic-gate int nwords = len >> 1; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate while (nwords-- != 0) 9907c478bd9Sstevel@tonic-gate sum += *p++; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate if (len & 1) 9937c478bd9Sstevel@tonic-gate sum += *(uchar_t *)p; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* end-around-carry */ 9967c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); 9977c478bd9Sstevel@tonic-gate sum += (sum >> 16); 9987c478bd9Sstevel@tonic-gate return (~sum); 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* Send a router discovery advertisement or solicitation ICMP packet. */ 10037c478bd9Sstevel@tonic-gate static void 10047c478bd9Sstevel@tonic-gate send_rdisc(union ad_u *p, 10057c478bd9Sstevel@tonic-gate uint_t p_size, 10067c478bd9Sstevel@tonic-gate struct interface *ifp, 10077c478bd9Sstevel@tonic-gate in_addr_t dst, /* 0 or unicast destination */ 10087c478bd9Sstevel@tonic-gate dstaddr_t type) 10097c478bd9Sstevel@tonic-gate { 10107c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 10117c478bd9Sstevel@tonic-gate int flags = 0; 10127c478bd9Sstevel@tonic-gate const char *msg; 1013*e704a8f2Smeem int ifindex = 0; 10147c478bd9Sstevel@tonic-gate struct in_addr addr; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * Don't send Rdisc packets on duplicate interfaces, we 10187c478bd9Sstevel@tonic-gate * don't want to generate duplicate packets. 10197c478bd9Sstevel@tonic-gate */ 10207c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_DUP) 10217c478bd9Sstevel@tonic-gate return; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (sin)); 10247c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = dst; 10257c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate switch (type) { 10287c478bd9Sstevel@tonic-gate case unicast: /* unicast */ 10297c478bd9Sstevel@tonic-gate default: 10307c478bd9Sstevel@tonic-gate flags = MSG_DONTROUTE; 10317c478bd9Sstevel@tonic-gate msg = "Send"; 10327c478bd9Sstevel@tonic-gate break; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate case bcast: /* broadcast */ 10357c478bd9Sstevel@tonic-gate if (ifp->int_if_flags & IFF_POINTOPOINT) { 10367c478bd9Sstevel@tonic-gate msg = "Send pt-to-pt"; 10377c478bd9Sstevel@tonic-gate if (ifp->int_dstaddr == 0) 10387c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); 10397c478bd9Sstevel@tonic-gate else 10407c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = ifp->int_dstaddr; 10417c478bd9Sstevel@tonic-gate } else { 10427c478bd9Sstevel@tonic-gate msg = "Send broadcast"; 10437c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = ifp->int_brdaddr; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate break; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate case mcast: /* multicast */ 10487c478bd9Sstevel@tonic-gate msg = "Send multicast"; 10497c478bd9Sstevel@tonic-gate break; 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate if (rdisc_sock < 0) 10537c478bd9Sstevel@tonic-gate get_rdisc_sock(); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* select the right interface. */ 10567c478bd9Sstevel@tonic-gate ifindex = (type != mcast && ifp->int_phys != NULL) ? 10577c478bd9Sstevel@tonic-gate ifp->int_phys->phyi_index : 0; 1058*e704a8f2Smeem 1059*e704a8f2Smeem if (rdisc_sock_interface != ifp) { 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * For multicast, we have to choose the source 10627c478bd9Sstevel@tonic-gate * address. This is either the local address 10637c478bd9Sstevel@tonic-gate * (non-point-to-point) or the remote address. 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 10667c478bd9Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 10677c478bd9Sstevel@tonic-gate if (type == mcast && 10687c478bd9Sstevel@tonic-gate setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, 10697c478bd9Sstevel@tonic-gate sizeof (addr)) == -1) { 10707c478bd9Sstevel@tonic-gate LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)"); 10717c478bd9Sstevel@tonic-gate return; 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate rdisc_sock_interface = ifp; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size); 10777c478bd9Sstevel@tonic-gate 1078*e704a8f2Smeem if (0 > sendtoif(rdisc_sock, p, p_size, flags, &sin, ifindex)) { 10797c478bd9Sstevel@tonic-gate if (!(ifp->int_state & IS_BROKE)) 10807c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, "sendto(%s%s%s): %s", 10817c478bd9Sstevel@tonic-gate ifp->int_name, ", ", 10827c478bd9Sstevel@tonic-gate inet_ntoa(sin.sin_addr), 10837c478bd9Sstevel@tonic-gate rip_strerror(errno)); 10847c478bd9Sstevel@tonic-gate if (ifp != NULL) 10857c478bd9Sstevel@tonic-gate if_sick(ifp, _B_FALSE); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate /* Send an advertisement */ 10917c478bd9Sstevel@tonic-gate static void 10927c478bd9Sstevel@tonic-gate send_adv(struct interface *ifp, 10937c478bd9Sstevel@tonic-gate in_addr_t dst, 10947c478bd9Sstevel@tonic-gate dstaddr_t type) 10957c478bd9Sstevel@tonic-gate { 10967c478bd9Sstevel@tonic-gate union ad_u u; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate if ((ifp->int_state & (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC)) == 10997c478bd9Sstevel@tonic-gate IS_SUPPRESS_RDISC) 11007c478bd9Sstevel@tonic-gate return; 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate (void) memset(&u, 0, sizeof (u.ad)); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate u.ad.icmp_type = ICMP_ROUTERADVERT; 11057c478bd9Sstevel@tonic-gate u.ad.icmp_code = ICMP_ROUTERADVERT_COMMON; 11067c478bd9Sstevel@tonic-gate u.ad.icmp_ad_num = 1; 11077c478bd9Sstevel@tonic-gate u.ad.icmp_ad_asize = sizeof (u.ad.icmp_ad_info[0])/4; 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate u.ad.icmp_ad_life = (stopint || !should_supply(ifp) || 11107c478bd9Sstevel@tonic-gate (ifp->int_state & IS_SUPPRESS_RDISC)) ? 0 : 11117c478bd9Sstevel@tonic-gate htons(ifp->int_rdisc_int*3); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* Send the configured preference as a network byte order value */ 11147c478bd9Sstevel@tonic-gate u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(ifp->int_rdisc_pref); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate u.ad.icmp_cksum = in_cksum((uint16_t *)&u.ad, sizeof (u.ad)); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate send_rdisc(&u, sizeof (u.ad), ifp, dst, type); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_SUPPRESS_RDISC) 11237c478bd9Sstevel@tonic-gate ifp->int_state &= ~IS_FLUSH_RDISC; 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* Advertise as a default router by way of router discovery. */ 11287c478bd9Sstevel@tonic-gate void 11297c478bd9Sstevel@tonic-gate rdisc_adv(boolean_t forceadv) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate struct interface *ifp; 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate if (!forceadv && !should_supply(NULL)) 11347c478bd9Sstevel@tonic-gate return; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = now.tv_sec + NEVER; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) { 11397c478bd9Sstevel@tonic-gate if ((ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE)) || 11407c478bd9Sstevel@tonic-gate (!forceadv && !IS_IFF_ROUTING(ifp->int_if_flags))) 11417c478bd9Sstevel@tonic-gate continue; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 11447c478bd9Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 11457c478bd9Sstevel@tonic-gate continue; 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */) || 11487c478bd9Sstevel@tonic-gate stopint != 0 || forceadv) { 11497c478bd9Sstevel@tonic-gate send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 11507c478bd9Sstevel@tonic-gate (ifp->int_state & IS_BCAST_RDISC) ? 1 : 2); 11517c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt++; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate intvl_random(&ifp->int_rdisc_timer, 11547c478bd9Sstevel@tonic-gate (ifp->int_rdisc_int*3)/4, ifp->int_rdisc_int); 11557c478bd9Sstevel@tonic-gate if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS && 11567c478bd9Sstevel@tonic-gate (ifp->int_rdisc_timer.tv_sec > 11577c478bd9Sstevel@tonic-gate MAX_INITIAL_ADVERT_INTERVAL)) { 11587c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_sec = 11597c478bd9Sstevel@tonic-gate MAX_INITIAL_ADVERT_INTERVAL; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate timevaladd(&ifp->int_rdisc_timer, &now); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 11647c478bd9Sstevel@tonic-gate > /* cstyle */)) 11657c478bd9Sstevel@tonic-gate rdisc_timer = ifp->int_rdisc_timer; 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* Solicit for Router Discovery */ 11717c478bd9Sstevel@tonic-gate void 11727c478bd9Sstevel@tonic-gate rdisc_sol(void) 11737c478bd9Sstevel@tonic-gate { 11747c478bd9Sstevel@tonic-gate struct interface *ifp; 11757c478bd9Sstevel@tonic-gate union ad_u u; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if (should_supply(NULL)) 11787c478bd9Sstevel@tonic-gate return; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = now.tv_sec + NEVER; 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) { 11837c478bd9Sstevel@tonic-gate if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) || 11847c478bd9Sstevel@tonic-gate ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 11857c478bd9Sstevel@tonic-gate continue; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 11887c478bd9Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 11897c478bd9Sstevel@tonic-gate continue; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate if (!timercmp(&ifp->int_rdisc_timer, &now, > /* cstyle */)) { 11927c478bd9Sstevel@tonic-gate (void) memset(&u, 0, sizeof (u.so)); 11937c478bd9Sstevel@tonic-gate u.so.icmp_type = ICMP_ROUTERSOLICIT; 11947c478bd9Sstevel@tonic-gate u.so.icmp_cksum = in_cksum((uint16_t *)&u.so, 11957c478bd9Sstevel@tonic-gate sizeof (u.so)); 11967c478bd9Sstevel@tonic-gate send_rdisc(&u, sizeof (u.so), ifp, 11977c478bd9Sstevel@tonic-gate htonl(INADDR_ALLRTRS_GROUP), 11987c478bd9Sstevel@tonic-gate ((ifp->int_state&IS_BCAST_RDISC) ? bcast : mcast)); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 12017c478bd9Sstevel@tonic-gate continue; 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 12047c478bd9Sstevel@tonic-gate ifp->int_rdisc_timer.tv_usec = 0; 12057c478bd9Sstevel@tonic-gate timevaladd(&ifp->int_rdisc_timer, &now); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, 12097c478bd9Sstevel@tonic-gate > /* cstyle */)) 12107c478bd9Sstevel@tonic-gate rdisc_timer = ifp->int_rdisc_timer; 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* 12167c478bd9Sstevel@tonic-gate * check the IP header of a possible Router Discovery ICMP packet 12177c478bd9Sstevel@tonic-gate * Returns 0 if bad 12187c478bd9Sstevel@tonic-gate */ 12197c478bd9Sstevel@tonic-gate static struct interface * 12207c478bd9Sstevel@tonic-gate ck_icmp(const char *act, 12217c478bd9Sstevel@tonic-gate in_addr_t from, 12227c478bd9Sstevel@tonic-gate struct interface *ifp, 12237c478bd9Sstevel@tonic-gate in_addr_t to, 12247c478bd9Sstevel@tonic-gate union ad_u *p, 12257c478bd9Sstevel@tonic-gate uint_t len) 12267c478bd9Sstevel@tonic-gate { 12277c478bd9Sstevel@tonic-gate const char *type; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 12317c478bd9Sstevel@tonic-gate type = "advertisement"; 12327c478bd9Sstevel@tonic-gate if (p->icmp.icmp_code == ICMP_ROUTERADVERT_NOCOMMON) 12337c478bd9Sstevel@tonic-gate return (NULL); /* Mobile IP */ 12347c478bd9Sstevel@tonic-gate } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 12357c478bd9Sstevel@tonic-gate type = "solicitation"; 12367c478bd9Sstevel@tonic-gate } else { 12377c478bd9Sstevel@tonic-gate return (NULL); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate if (p->icmp.icmp_code != ICMP_ROUTERADVERT_COMMON) { 12417c478bd9Sstevel@tonic-gate trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 12427c478bd9Sstevel@tonic-gate type, p->icmp.icmp_code, naddr_ntoa(from), naddr_ntoa(to)); 12437c478bd9Sstevel@tonic-gate return (NULL); 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate trace_rdisc(act, from, to, ifp, p, len); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate if (ifp == NULL) 12497c478bd9Sstevel@tonic-gate trace_pkt("unknown interface for router-discovery %s from %s " 12507c478bd9Sstevel@tonic-gate "to %s", type, naddr_ntoa(from), naddr_ntoa(to)); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate return (ifp); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* Read packets from the router discovery socket */ 12577c478bd9Sstevel@tonic-gate void 12587c478bd9Sstevel@tonic-gate read_d(void) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate #define PKTLEN 512 12617c478bd9Sstevel@tonic-gate static struct msg_limit bad_asize, bad_len; 12627c478bd9Sstevel@tonic-gate struct sockaddr_in from; 12637c478bd9Sstevel@tonic-gate int n, cc, hlen; 12647c478bd9Sstevel@tonic-gate struct { 12657c478bd9Sstevel@tonic-gate union { 12667c478bd9Sstevel@tonic-gate struct ip ip; 12677c478bd9Sstevel@tonic-gate uint16_t s[PKTLEN/sizeof (uint16_t)]; 12687c478bd9Sstevel@tonic-gate uint8_t b[PKTLEN/sizeof (uint8_t)]; 12697c478bd9Sstevel@tonic-gate } pkt; 12707c478bd9Sstevel@tonic-gate } buf; 12717c478bd9Sstevel@tonic-gate union ad_u *p; 12727c478bd9Sstevel@tonic-gate n_long *wp; 12737c478bd9Sstevel@tonic-gate struct interface *ifp; 12747c478bd9Sstevel@tonic-gate boolean_t needsort = _B_FALSE; 12757c478bd9Sstevel@tonic-gate struct msghdr msg; 12767c478bd9Sstevel@tonic-gate struct iovec iov; 12777c478bd9Sstevel@tonic-gate uint8_t ancillary_data[CONTROL_BUFSIZE]; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate iov.iov_base = &buf; 12807c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (buf); 12817c478bd9Sstevel@tonic-gate msg.msg_iov = &iov; 12827c478bd9Sstevel@tonic-gate msg.msg_iovlen = 1; 12837c478bd9Sstevel@tonic-gate msg.msg_name = &from; 12847c478bd9Sstevel@tonic-gate msg.msg_control = &ancillary_data; 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate for (;;) { 12877c478bd9Sstevel@tonic-gate msg.msg_namelen = sizeof (from); 12887c478bd9Sstevel@tonic-gate msg.msg_controllen = sizeof (ancillary_data); 12897c478bd9Sstevel@tonic-gate cc = recvmsg(rdisc_sock, &msg, 0); 12907c478bd9Sstevel@tonic-gate if (cc <= 0) { 12917c478bd9Sstevel@tonic-gate if (cc < 0 && errno != EWOULDBLOCK) 12927c478bd9Sstevel@tonic-gate LOGERR("recvmsg(rdisc_sock)"); 12937c478bd9Sstevel@tonic-gate break; 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate hlen = buf.pkt.ip.ip_hl << 2; 12977c478bd9Sstevel@tonic-gate if (cc < hlen + ICMP_MINLEN) 12987c478bd9Sstevel@tonic-gate continue; 12997c478bd9Sstevel@tonic-gate /* LINTED [alignment will be lw aligned] */ 13007c478bd9Sstevel@tonic-gate p = (union ad_u *)&buf.pkt.b[hlen]; 13017c478bd9Sstevel@tonic-gate cc -= hlen; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * If we could tell the interface on which a packet from 13057c478bd9Sstevel@tonic-gate * address 0 arrived, we could deal with such solicitations. 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate ifp = receiving_interface(&msg, _B_FALSE); 13087c478bd9Sstevel@tonic-gate ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 13097c478bd9Sstevel@tonic-gate buf.pkt.ip.ip_dst.s_addr, p, cc); 13107c478bd9Sstevel@tonic-gate if (ifp == NULL) 13117c478bd9Sstevel@tonic-gate continue; 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) { 13147c478bd9Sstevel@tonic-gate trace_misc("discard RDISC packet received over %s, %X", 13157c478bd9Sstevel@tonic-gate ifp->int_name, ifp->int_if_flags); 13167c478bd9Sstevel@tonic-gate continue; 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (from.sin_addr.s_addr != 0 && 13207c478bd9Sstevel@tonic-gate ifwithaddr(from.sin_addr.s_addr, _B_FALSE, _B_FALSE)) { 13217c478bd9Sstevel@tonic-gate trace_pkt(" " 13227c478bd9Sstevel@tonic-gate "discard our own Router Discovery message"); 13237c478bd9Sstevel@tonic-gate continue; 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate /* The remote address *must* be directly connected. */ 13277c478bd9Sstevel@tonic-gate if (!remote_address_ok(ifp, from.sin_addr.s_addr)) { 13287c478bd9Sstevel@tonic-gate trace_misc("discard rdisc message; source %s not on " 13297c478bd9Sstevel@tonic-gate "interface %s", naddr_ntoa(from.sin_addr.s_addr), 13307c478bd9Sstevel@tonic-gate ifp->int_name); 13317c478bd9Sstevel@tonic-gate continue; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate switch (p->icmp.icmp_type) { 13357c478bd9Sstevel@tonic-gate case ICMP_ROUTERADVERT: 13367c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_NO_ADV_IN) 13377c478bd9Sstevel@tonic-gate continue; 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate if (p->ad.icmp_ad_asize*2*sizeof (wp[0]) < 13407c478bd9Sstevel@tonic-gate sizeof (p->ad.icmp_ad_info[0])) { 13417c478bd9Sstevel@tonic-gate msglim(&bad_asize, from.sin_addr.s_addr, 13427c478bd9Sstevel@tonic-gate "intolerable rdisc address size=%d", 13437c478bd9Sstevel@tonic-gate p->ad.icmp_ad_asize); 13447c478bd9Sstevel@tonic-gate continue; 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate if (p->ad.icmp_ad_num == 0) { 13477c478bd9Sstevel@tonic-gate trace_pkt(" empty?"); 13487c478bd9Sstevel@tonic-gate continue; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate if (cc < (sizeof (p->ad) - 13517c478bd9Sstevel@tonic-gate sizeof (p->ad.icmp_ad_info) + 13527c478bd9Sstevel@tonic-gate (p->ad.icmp_ad_num * 13537c478bd9Sstevel@tonic-gate sizeof (p->ad.icmp_ad_info[0])))) { 13547c478bd9Sstevel@tonic-gate msglim(&bad_len, from.sin_addr.s_addr, 13557c478bd9Sstevel@tonic-gate "rdisc length %d does not match ad_num" 13567c478bd9Sstevel@tonic-gate " %d", cc, p->ad.icmp_ad_num); 13577c478bd9Sstevel@tonic-gate continue; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate needsort = _B_TRUE; 13617c478bd9Sstevel@tonic-gate wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 13627c478bd9Sstevel@tonic-gate for (n = 0; n < p->ad.icmp_ad_num; n++) { 13637c478bd9Sstevel@tonic-gate parse_ad(from.sin_addr.s_addr, 13647c478bd9Sstevel@tonic-gate wp[0], wp[1], 13657c478bd9Sstevel@tonic-gate ntohs(p->ad.icmp_ad_life), ifp); 13667c478bd9Sstevel@tonic-gate wp += p->ad.icmp_ad_asize; 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate break; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate case ICMP_ROUTERSOLICIT: 13727c478bd9Sstevel@tonic-gate if (!should_supply(ifp)) 13737c478bd9Sstevel@tonic-gate continue; 13747c478bd9Sstevel@tonic-gate if ((ifp->int_state & IS_NO_ADV_OUT) || 13757c478bd9Sstevel@tonic-gate !IS_IFF_ROUTING(ifp->int_if_flags)) 13767c478bd9Sstevel@tonic-gate continue; 13777c478bd9Sstevel@tonic-gate if (stopint != 0) 13787c478bd9Sstevel@tonic-gate continue; 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * We should handle messages from address 0, 13827c478bd9Sstevel@tonic-gate * but cannot due to kernel limitations. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* Respond with a point-to-point advertisement */ 13867c478bd9Sstevel@tonic-gate send_adv(ifp, from.sin_addr.s_addr, 0); 13877c478bd9Sstevel@tonic-gate break; 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate if (needsort) 13927c478bd9Sstevel@tonic-gate rdisc_sort(); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate void 13967c478bd9Sstevel@tonic-gate rdisc_dump(void) 13977c478bd9Sstevel@tonic-gate { 13987c478bd9Sstevel@tonic-gate struct dr *drp; 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate for (drp = drs; drp < &drs[max_ads]; drp++) 14017c478bd9Sstevel@tonic-gate if (drp->dr_ts != 0) 14027c478bd9Sstevel@tonic-gate trace_dr(drp); 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate void 14067c478bd9Sstevel@tonic-gate rdisc_suppress(struct interface *ifp) 14077c478bd9Sstevel@tonic-gate { 14087c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_ADV_OUT) { 14097c478bd9Sstevel@tonic-gate msglog("%s \"rdisc_adv\" specified, will not " 14107c478bd9Sstevel@tonic-gate "suppress rdisc adv", ifp->int_name); 14117c478bd9Sstevel@tonic-gate } else { 14127c478bd9Sstevel@tonic-gate if (ifp->int_state & IS_SUPPRESS_RDISC) 14137c478bd9Sstevel@tonic-gate return; 14147c478bd9Sstevel@tonic-gate ifp->int_state |= (IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 14157c478bd9Sstevel@tonic-gate trace_misc("suppress rdisc adv on %s", ifp->int_name); 14167c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = 0; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate void 14217c478bd9Sstevel@tonic-gate rdisc_restore(struct interface *ifp) 14227c478bd9Sstevel@tonic-gate { 14237c478bd9Sstevel@tonic-gate if ((ifp->int_state & IS_SUPPRESS_RDISC) == 0) 14247c478bd9Sstevel@tonic-gate return; 14257c478bd9Sstevel@tonic-gate ifp->int_state &= ~(IS_SUPPRESS_RDISC|IS_FLUSH_RDISC); 14267c478bd9Sstevel@tonic-gate trace_misc("restoring rdisc adv on %s", ifp->int_name); 14277c478bd9Sstevel@tonic-gate rdisc_timer.tv_sec = 0; 14287c478bd9Sstevel@tonic-gate } 14293173664eSapersson 14303173664eSapersson void 14313173664eSapersson process_d_mib_sock(void) 14323173664eSapersson { 14333173664eSapersson 14343173664eSapersson socklen_t fromlen; 14353173664eSapersson struct sockaddr_un from; 14363173664eSapersson ssize_t len; 14373173664eSapersson int command; 14383173664eSapersson struct dr *drp; 14393173664eSapersson rdisc_info_t rdisc_info; 14403173664eSapersson defr_t def_router; 14413173664eSapersson extern int max_ads; 14423173664eSapersson int num = 0; 14433173664eSapersson 14443173664eSapersson fromlen = (socklen_t)sizeof (from); 14453173664eSapersson len = recvfrom(rdisc_mib_sock, &command, sizeof (int), 0, 14463173664eSapersson (struct sockaddr *)&from, &fromlen); 14473173664eSapersson 14483173664eSapersson if (len < sizeof (int) || command != RDISC_SNMP_INFO_REQ) { 14493173664eSapersson trace_misc("Bad command on rdisc_mib_sock"); 14503173664eSapersson return; 14513173664eSapersson } 14523173664eSapersson 14533173664eSapersson /* 14543173664eSapersson * Count number of good routers 14553173664eSapersson */ 14563173664eSapersson for (drp = drs; drp < &drs[max_ads]; drp++) { 14573173664eSapersson if (drp->dr_ts != 0) { 14583173664eSapersson num++; 14593173664eSapersson } 14603173664eSapersson } 14613173664eSapersson 14623173664eSapersson rdisc_info.info_type = RDISC_SNMP_INFO_RESPONSE; 14633173664eSapersson rdisc_info.info_version = RDISC_SNMP_INFO_VER; 14643173664eSapersson rdisc_info.info_num_of_routers = num; 14653173664eSapersson 14663173664eSapersson (void) sendto(rdisc_mib_sock, &rdisc_info, sizeof (rdisc_info_t), 0, 14673173664eSapersson (struct sockaddr *)&from, fromlen); 14683173664eSapersson 14693173664eSapersson for (drp = drs; drp < &drs[max_ads]; drp++) { 14703173664eSapersson if (drp->dr_ts != 0) { 14713173664eSapersson def_router.defr_info_type = RDISC_DEF_ROUTER_INFO; 14723173664eSapersson def_router.defr_version = RDISC_DEF_ROUTER_VER; 14733173664eSapersson def_router.defr_index = 14743173664eSapersson drp->dr_ifp->int_phys->phyi_index; 14753173664eSapersson def_router.defr_life = drp->dr_life; 14763173664eSapersson def_router.defr_addr.s_addr = drp->dr_gate; 14773173664eSapersson def_router.defr_pref = drp->dr_pref; 14783173664eSapersson (void) sendto(rdisc_mib_sock, &def_router, 14793173664eSapersson sizeof (defr_t), 0, (struct sockaddr *)&from, 14803173664eSapersson fromlen); 14813173664eSapersson } 14823173664eSapersson } 14833173664eSapersson } 1484