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) 1983, 1988, 1993 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/output.c,v 1.7 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 <md5.h> 43*e704a8f2Smeem #include <alloca.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate uint_t update_seqno; 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * walk the tree of routes with this for output 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate static struct { 527c478bd9Sstevel@tonic-gate struct sockaddr_in to; 537c478bd9Sstevel@tonic-gate in_addr_t to_mask; 547c478bd9Sstevel@tonic-gate in_addr_t to_net; 557c478bd9Sstevel@tonic-gate in_addr_t to_std_mask; 567c478bd9Sstevel@tonic-gate in_addr_t to_std_net; 577c478bd9Sstevel@tonic-gate struct interface *ifp; /* usually output interface */ 587c478bd9Sstevel@tonic-gate struct auth *a; 597c478bd9Sstevel@tonic-gate uint8_t metric; /* adjust metrics by interface */ 607c478bd9Sstevel@tonic-gate uint32_t npackets; 617c478bd9Sstevel@tonic-gate uint32_t gen_limit; 627c478bd9Sstevel@tonic-gate #define WS_GEN_LIMIT_MAX 1024 637c478bd9Sstevel@tonic-gate uint16_t state; 647c478bd9Sstevel@tonic-gate #define WS_ST_FLASH 0x001 /* send only changed routes */ 657c478bd9Sstevel@tonic-gate #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ 667c478bd9Sstevel@tonic-gate #define WS_ST_AG 0x004 /* ok to aggregate subnets */ 677c478bd9Sstevel@tonic-gate #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ 687c478bd9Sstevel@tonic-gate #define WS_ST_QUERY 0x010 /* responding to a query */ 697c478bd9Sstevel@tonic-gate #define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ 707c478bd9Sstevel@tonic-gate #define WS_ST_DEFAULT 0x040 /* faking a default */ 717c478bd9Sstevel@tonic-gate } ws; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ 747c478bd9Sstevel@tonic-gate struct ws_buf v12buf; 757c478bd9Sstevel@tonic-gate static union pkt_buf ripv12_buf; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* Another for only RIPv2 listeners */ 787c478bd9Sstevel@tonic-gate static struct ws_buf v2buf; 797c478bd9Sstevel@tonic-gate static union pkt_buf rip_v2_buf; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate void 847c478bd9Sstevel@tonic-gate bufinit(void) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; 877c478bd9Sstevel@tonic-gate v12buf.buf = &ripv12_buf.rip; 887c478bd9Sstevel@tonic-gate v12buf.base = &v12buf.buf->rip_nets[0]; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; 917c478bd9Sstevel@tonic-gate rip_v2_buf.rip.rip_vers = RIPv2; 927c478bd9Sstevel@tonic-gate v2buf.buf = &rip_v2_buf.rip; 937c478bd9Sstevel@tonic-gate v2buf.base = &v2buf.buf->rip_nets[0]; 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * Send the contents of the global buffer via the non-multicast socket 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate int /* <0 on failure */ 1017c478bd9Sstevel@tonic-gate output(enum output_type type, 1027c478bd9Sstevel@tonic-gate struct sockaddr_in *dst, /* send to here */ 1037c478bd9Sstevel@tonic-gate struct interface *ifp, 1047c478bd9Sstevel@tonic-gate struct rip *buf, 1057c478bd9Sstevel@tonic-gate int size) /* this many bytes */ 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 1087c478bd9Sstevel@tonic-gate int flags; 1097c478bd9Sstevel@tonic-gate const char *msg; 1107c478bd9Sstevel@tonic-gate int res; 1117c478bd9Sstevel@tonic-gate int ifindex; 1127c478bd9Sstevel@tonic-gate struct in_addr addr; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate sin = *dst; 1157c478bd9Sstevel@tonic-gate if (sin.sin_port == 0) 1167c478bd9Sstevel@tonic-gate sin.sin_port = htons(RIP_PORT); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate flags = 0; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate if (ifp == NULL && type == OUT_MULTICAST) { 1217c478bd9Sstevel@tonic-gate msglog("Cannot send RIP message to %s", 1227c478bd9Sstevel@tonic-gate inet_ntoa(sin.sin_addr)); 1237c478bd9Sstevel@tonic-gate return (-1); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate switch (type) { 1277c478bd9Sstevel@tonic-gate case OUT_QUERY: 1287c478bd9Sstevel@tonic-gate msg = "Answer Query"; 1297c478bd9Sstevel@tonic-gate break; 1307c478bd9Sstevel@tonic-gate case OUT_UNICAST: 1317c478bd9Sstevel@tonic-gate msg = "Send"; 1327c478bd9Sstevel@tonic-gate flags = MSG_DONTROUTE; 1337c478bd9Sstevel@tonic-gate break; 1347c478bd9Sstevel@tonic-gate case OUT_BROADCAST: 1357c478bd9Sstevel@tonic-gate msg = "Send bcast"; 1367c478bd9Sstevel@tonic-gate break; 1377c478bd9Sstevel@tonic-gate case OUT_MULTICAST: 1387c478bd9Sstevel@tonic-gate msg = "Send mcast"; 1397c478bd9Sstevel@tonic-gate break; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate case NO_OUT_MULTICAST: 1427c478bd9Sstevel@tonic-gate case NO_OUT_RIPV2: 1437c478bd9Sstevel@tonic-gate default: 1447c478bd9Sstevel@tonic-gate #ifdef DEBUG 1457c478bd9Sstevel@tonic-gate abort(); 1467c478bd9Sstevel@tonic-gate #endif 1477c478bd9Sstevel@tonic-gate return (-1); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 151*e704a8f2Smeem * IP_PKTINFO overrides IP_MULTICAST_IF, so we don't set ifindex 152*e704a8f2Smeem * for multicast traffic. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate ifindex = (type != OUT_MULTICAST && type != OUT_QUERY && 1557c478bd9Sstevel@tonic-gate ifp != NULL && ifp->int_phys != NULL) ? 1567c478bd9Sstevel@tonic-gate ifp->int_phys->phyi_index : 0; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (rip_sock_interface != ifp) { 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * For multicast, we have to choose the source 1617c478bd9Sstevel@tonic-gate * address. This is either the local address 1627c478bd9Sstevel@tonic-gate * (non-point-to-point) or the remote address. 1637c478bd9Sstevel@tonic-gate */ 1647c478bd9Sstevel@tonic-gate if (ifp != NULL) { 1657c478bd9Sstevel@tonic-gate addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 1667c478bd9Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 1677c478bd9Sstevel@tonic-gate if (type == OUT_MULTICAST && 1687c478bd9Sstevel@tonic-gate setsockopt(rip_sock, IPPROTO_IP, 1697c478bd9Sstevel@tonic-gate IP_MULTICAST_IF, &addr, sizeof (addr)) == -1) { 1707c478bd9Sstevel@tonic-gate LOGERR("setsockopt(rip_sock, IP_MULTICAST_IF)"); 1717c478bd9Sstevel@tonic-gate return (-1); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate rip_sock_interface = ifp; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate trace_rip(msg, "to", &sin, ifp, buf, size); 1787c478bd9Sstevel@tonic-gate 179*e704a8f2Smeem res = sendtoif(rip_sock, buf, size, flags, &sin, ifindex); 180*e704a8f2Smeem if (res < 0 && (ifp == NULL || !(ifp->int_state & IS_BROKE))) { 1817c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, "%s sendto(%s%s%s.%d): %s", msg, 1827c478bd9Sstevel@tonic-gate ifp != NULL ? ifp->int_name : "", 1837c478bd9Sstevel@tonic-gate ifp != NULL ? ", " : "", 1847c478bd9Sstevel@tonic-gate inet_ntoa(sin.sin_addr), 1857c478bd9Sstevel@tonic-gate ntohs(sin.sin_port), 1867c478bd9Sstevel@tonic-gate rip_strerror(errno)); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate return (res); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 192*e704a8f2Smeem /* 193*e704a8f2Smeem * Semantically identical to sendto(), but sends the message through a 194*e704a8f2Smeem * specific interface (if ifindex is non-zero) using IP_PKTINFO. 195*e704a8f2Smeem */ 196*e704a8f2Smeem int 197*e704a8f2Smeem sendtoif(int fd, const void *buf, uint_t bufsize, uint_t flags, 198*e704a8f2Smeem struct sockaddr_in *sinp, uint_t ifindex) 199*e704a8f2Smeem { 200*e704a8f2Smeem struct iovec iov; 201*e704a8f2Smeem struct msghdr msg; 202*e704a8f2Smeem struct cmsghdr *cmsgp; 203*e704a8f2Smeem struct in_pktinfo *ipip; 204*e704a8f2Smeem 205*e704a8f2Smeem iov.iov_base = (void *)buf; 206*e704a8f2Smeem iov.iov_len = bufsize; 207*e704a8f2Smeem 208*e704a8f2Smeem (void) memset(&msg, 0, sizeof (struct msghdr)); 209*e704a8f2Smeem msg.msg_name = (struct sockaddr *)sinp; 210*e704a8f2Smeem msg.msg_namelen = sizeof (struct sockaddr_in); 211*e704a8f2Smeem msg.msg_iov = &iov; 212*e704a8f2Smeem msg.msg_iovlen = 1; 213*e704a8f2Smeem 214*e704a8f2Smeem if (ifindex != 0) { 215*e704a8f2Smeem /* 216*e704a8f2Smeem * We can't precisely predict the alignment padding we'll 217*e704a8f2Smeem * need, so we allocate the maximum alignment and then 218*e704a8f2Smeem * use CMSG_NXTHDR() to fix it up at the end. 219*e704a8f2Smeem */ 220*e704a8f2Smeem msg.msg_controllen = sizeof (*cmsgp) + _MAX_ALIGNMENT + 221*e704a8f2Smeem sizeof (*ipip) + _MAX_ALIGNMENT + sizeof (*cmsgp); 222*e704a8f2Smeem msg.msg_control = alloca(msg.msg_controllen); 223*e704a8f2Smeem 224*e704a8f2Smeem cmsgp = CMSG_FIRSTHDR(&msg); 225*e704a8f2Smeem ipip = (void *)CMSG_DATA(cmsgp); 226*e704a8f2Smeem (void) memset(ipip, 0, sizeof (struct in_pktinfo)); 227*e704a8f2Smeem ipip->ipi_ifindex = ifindex; 228*e704a8f2Smeem cmsgp->cmsg_len = (caddr_t)(ipip + 1) - (caddr_t)cmsgp; 229*e704a8f2Smeem cmsgp->cmsg_type = IP_PKTINFO; 230*e704a8f2Smeem cmsgp->cmsg_level = IPPROTO_IP; 231*e704a8f2Smeem 232*e704a8f2Smeem /* 233*e704a8f2Smeem * Correct the control message length. 234*e704a8f2Smeem */ 235*e704a8f2Smeem cmsgp = CMSG_NXTHDR(&msg, cmsgp); 236*e704a8f2Smeem msg.msg_controllen = (caddr_t)cmsgp - (caddr_t)msg.msg_control; 237*e704a8f2Smeem } 238*e704a8f2Smeem 239*e704a8f2Smeem return (sendmsg(fd, &msg, flags)); 240*e704a8f2Smeem } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * Find the first key for a packet to send. 2447c478bd9Sstevel@tonic-gate * Try for a key that is eligible and has not expired, but settle for 2457c478bd9Sstevel@tonic-gate * the last key if they have all expired. 2467c478bd9Sstevel@tonic-gate * If no key is ready yet, give up. 2477c478bd9Sstevel@tonic-gate */ 2487c478bd9Sstevel@tonic-gate struct auth * 2497c478bd9Sstevel@tonic-gate find_auth(struct interface *ifp) 2507c478bd9Sstevel@tonic-gate { 2517c478bd9Sstevel@tonic-gate struct auth *ap, *res = NULL; 2527c478bd9Sstevel@tonic-gate int i; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate if (ifp == NULL) 2567c478bd9Sstevel@tonic-gate return (NULL); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if ((ap = ifp->int_auth) == NULL) 2597c478bd9Sstevel@tonic-gate return (NULL); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { 2627c478bd9Sstevel@tonic-gate /* stop looking after the last key */ 2637c478bd9Sstevel@tonic-gate if (ap->type == RIP_AUTH_NONE) 2647c478bd9Sstevel@tonic-gate break; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* ignore keys that are not ready yet */ 2677c478bd9Sstevel@tonic-gate if ((ulong_t)ap->start > (ulong_t)clk.tv_sec) 2687c478bd9Sstevel@tonic-gate continue; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if ((ulong_t)ap->end < (ulong_t)clk.tv_sec) { 2717c478bd9Sstevel@tonic-gate /* note best expired password as a fall-back */ 2727c478bd9Sstevel@tonic-gate if (res == NULL || 2737c478bd9Sstevel@tonic-gate (((ulong_t)ap->end > (ulong_t)res->end)) && 2747c478bd9Sstevel@tonic-gate ((ulong_t)res->end < (ulong_t)clk.tv_sec)) 2757c478bd9Sstevel@tonic-gate res = ap; 2767c478bd9Sstevel@tonic-gate continue; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* note key with the best future */ 2807c478bd9Sstevel@tonic-gate if (res == NULL || (ulong_t)res->end < (ulong_t)ap->end) 2817c478bd9Sstevel@tonic-gate res = ap; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate return (res); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate void 2887c478bd9Sstevel@tonic-gate clr_ws_buf(struct ws_buf *wb, struct auth *ap) 2897c478bd9Sstevel@tonic-gate { 2907c478bd9Sstevel@tonic-gate struct netauth *na; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate wb->lim = wb->base + NETS_LEN; 2937c478bd9Sstevel@tonic-gate wb->n = wb->base; 2947c478bd9Sstevel@tonic-gate (void) memset(wb->n, 0, NETS_LEN*sizeof (*wb->n)); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * (start to) install authentication if appropriate 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate if (ap == NULL) 3007c478bd9Sstevel@tonic-gate return; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate na = (struct netauth *)wb->n; 3037c478bd9Sstevel@tonic-gate if (ap->type == RIP_AUTH_PW) { 3047c478bd9Sstevel@tonic-gate na->a_family = RIP_AF_AUTH; 3057c478bd9Sstevel@tonic-gate na->a_type = RIP_AUTH_PW; 3067c478bd9Sstevel@tonic-gate (void) memcpy(na->au.au_pw, ap->key, sizeof (na->au.au_pw)); 3077c478bd9Sstevel@tonic-gate wb->n++; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate } else if (ap->type == RIP_AUTH_MD5) { 3107c478bd9Sstevel@tonic-gate na->a_family = RIP_AF_AUTH; 3117c478bd9Sstevel@tonic-gate na->a_type = RIP_AUTH_MD5; 3127c478bd9Sstevel@tonic-gate na->au.a_md5.md5_keyid = ap->keyid; 3137c478bd9Sstevel@tonic-gate na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; 3147c478bd9Sstevel@tonic-gate na->au.a_md5.md5_seqno = htonl(clk.tv_sec); 3157c478bd9Sstevel@tonic-gate wb->n++; 3167c478bd9Sstevel@tonic-gate wb->lim--; /* make room for trailer */ 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate void 3227c478bd9Sstevel@tonic-gate end_md5_auth(struct ws_buf *wb, struct auth *ap) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate struct netauth *na, *na2; 3257c478bd9Sstevel@tonic-gate MD5_CTX md5_ctx; 3267c478bd9Sstevel@tonic-gate int len; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate na = (struct netauth *)wb->base; 3297c478bd9Sstevel@tonic-gate na2 = (struct netauth *)wb->n; 3307c478bd9Sstevel@tonic-gate len = (char *)na2-(char *)wb->buf; 3317c478bd9Sstevel@tonic-gate na2->a_family = RIP_AF_AUTH; 3327c478bd9Sstevel@tonic-gate na2->a_type = RIP_AUTH_TRAILER; 3337c478bd9Sstevel@tonic-gate na->au.a_md5.md5_pkt_len = htons(len); 3347c478bd9Sstevel@tonic-gate MD5Init(&md5_ctx); 3357c478bd9Sstevel@tonic-gate /* len+4 to include auth trailer's family/type in MD5 sum */ 3367c478bd9Sstevel@tonic-gate MD5Update(&md5_ctx, (uchar_t *)wb->buf, len + 4); 3377c478bd9Sstevel@tonic-gate MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); 3387c478bd9Sstevel@tonic-gate MD5Final(na2->au.au_pw, &md5_ctx); 3397c478bd9Sstevel@tonic-gate wb->n++; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * Send the buffer 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate static void 3477c478bd9Sstevel@tonic-gate supply_write(struct ws_buf *wb) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * Output multicast only if legal. 3517c478bd9Sstevel@tonic-gate * If we would multicast and it would be illegal, then discard the 3527c478bd9Sstevel@tonic-gate * packet. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate switch (wb->type) { 3557c478bd9Sstevel@tonic-gate case NO_OUT_MULTICAST: 3567c478bd9Sstevel@tonic-gate trace_pkt("skip multicast to %s because impossible", 3577c478bd9Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr)); 3587c478bd9Sstevel@tonic-gate break; 3597c478bd9Sstevel@tonic-gate case NO_OUT_RIPV2: 3607c478bd9Sstevel@tonic-gate break; 3617c478bd9Sstevel@tonic-gate default: 3627c478bd9Sstevel@tonic-gate if (ws.a != NULL && ws.a->type == RIP_AUTH_MD5) 3637c478bd9Sstevel@tonic-gate end_md5_auth(wb, ws.a); 3647c478bd9Sstevel@tonic-gate if (output(wb->type, &ws.to, ws.ifp, wb->buf, 3657c478bd9Sstevel@tonic-gate ((char *)wb->n - (char *)wb->buf)) < 0 && ws.ifp != NULL) 3667c478bd9Sstevel@tonic-gate if_sick(ws.ifp, _B_FALSE); 3677c478bd9Sstevel@tonic-gate ws.npackets++; 3687c478bd9Sstevel@tonic-gate break; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate clr_ws_buf(wb, ws.a); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * Put an entry into the packet 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate static void 3797c478bd9Sstevel@tonic-gate supply_out(struct ag_info *ag) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate uint32_t dstcount; 3827c478bd9Sstevel@tonic-gate in_addr_t mask, v1_mask, dst_h, ddst_h = 0; 3837c478bd9Sstevel@tonic-gate struct ws_buf *wb; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Skip this route if doing a flash update and it and the routes 3887c478bd9Sstevel@tonic-gate * it aggregates have not changed recently. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate if (ag->ag_seqno < update_seqno && (ws.state & WS_ST_FLASH)) 3917c478bd9Sstevel@tonic-gate return; 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate dst_h = ag->ag_dst_h; 3947c478bd9Sstevel@tonic-gate mask = ag->ag_mask; 3957c478bd9Sstevel@tonic-gate v1_mask = ripv1_mask_host(htonl(dst_h), 3967c478bd9Sstevel@tonic-gate (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : NULL); 3977c478bd9Sstevel@tonic-gate dstcount = 0; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * If we are sending RIPv2 packets that cannot (or must not) be 4017c478bd9Sstevel@tonic-gate * heard by RIPv1 listeners, do not worry about sub- or supernets. 4027c478bd9Sstevel@tonic-gate * Subnets (from other networks) can only be sent via multicast. 4037c478bd9Sstevel@tonic-gate * A pair of subnet routes might have been promoted so that they 4047c478bd9Sstevel@tonic-gate * are legal to send by RIPv1. 4057c478bd9Sstevel@tonic-gate * If RIPv1 is off, use the multicast buffer. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate if ((ws.state & WS_ST_RIP2_ALL) || 4087c478bd9Sstevel@tonic-gate ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { 4097c478bd9Sstevel@tonic-gate /* use the RIPv2-only buffer */ 4107c478bd9Sstevel@tonic-gate wb = &v2buf; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate } else { 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * use the RIPv1-or-RIPv2 buffer 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate wb = &v12buf; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Convert supernet route into corresponding set of network 4207c478bd9Sstevel@tonic-gate * routes for RIPv1, but leave non-contiguous netmasks 4217c478bd9Sstevel@tonic-gate * to ag_check(). 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate if (v1_mask > mask && 4247c478bd9Sstevel@tonic-gate mask + (mask & -mask) == 0) { 4257c478bd9Sstevel@tonic-gate ddst_h = v1_mask & -v1_mask; 4267c478bd9Sstevel@tonic-gate dstcount = (v1_mask & ~mask)/ddst_h; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate if (dstcount > ws.gen_limit) { 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Punt if we would have to generate an 4317c478bd9Sstevel@tonic-gate * unreasonable number of routes. 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate if (TRACECONTENTS) 4347c478bd9Sstevel@tonic-gate trace_misc("sending %s-->%s as 1" 4357c478bd9Sstevel@tonic-gate " instead of %d routes", 4367c478bd9Sstevel@tonic-gate addrname(htonl(dst_h), mask, 1), 4377c478bd9Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr), 4387c478bd9Sstevel@tonic-gate dstcount + 1); 4397c478bd9Sstevel@tonic-gate dstcount = 0; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate } else { 4427c478bd9Sstevel@tonic-gate mask = v1_mask; 4437c478bd9Sstevel@tonic-gate ws.gen_limit -= dstcount; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate do { 4497c478bd9Sstevel@tonic-gate wb->n->n_family = RIP_AF_INET; 4507c478bd9Sstevel@tonic-gate wb->n->n_dst = htonl(dst_h); 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * If the route is from router-discovery or we are 4537c478bd9Sstevel@tonic-gate * shutting down, or this is a broken/sick interface, 4547c478bd9Sstevel@tonic-gate * admit only a bad metric. 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate wb->n->n_metric = ((stopint || ag->ag_metric < 1 || 4577c478bd9Sstevel@tonic-gate (ag->ag_ifp && (ag->ag_ifp->int_state & 4587c478bd9Sstevel@tonic-gate (IS_BROKE|IS_SICK)))) ? HOPCNT_INFINITY : ag->ag_metric); 4597c478bd9Sstevel@tonic-gate wb->n->n_metric = htonl(wb->n->n_metric); 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Any non-zero bits in the supposedly unused RIPv1 fields 4627c478bd9Sstevel@tonic-gate * cause the old `routed` to ignore the route. 4637c478bd9Sstevel@tonic-gate * That means the mask and so forth cannot be sent 4647c478bd9Sstevel@tonic-gate * in the hybrid RIPv1/RIPv2 mode. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate if (ws.state & WS_ST_RIP2_ALL) { 4677c478bd9Sstevel@tonic-gate if (ag->ag_nhop != 0 && 4687c478bd9Sstevel@tonic-gate ((ws.state & WS_ST_QUERY) || 4697c478bd9Sstevel@tonic-gate (ag->ag_nhop != ws.ifp->int_addr && 4707c478bd9Sstevel@tonic-gate on_net(ag->ag_nhop, ws.ifp->int_net, 4717c478bd9Sstevel@tonic-gate ws.ifp->int_mask)) && 4727c478bd9Sstevel@tonic-gate ifwithaddr(ag->ag_nhop, _B_FALSE, _B_FALSE) == 4737c478bd9Sstevel@tonic-gate NULL)) 4747c478bd9Sstevel@tonic-gate wb->n->n_nhop = ag->ag_nhop; 4757c478bd9Sstevel@tonic-gate wb->n->n_mask = htonl(mask); 4767c478bd9Sstevel@tonic-gate wb->n->n_tag = ag->ag_tag; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate dst_h += ddst_h; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (++wb->n >= wb->lim) 4817c478bd9Sstevel@tonic-gate supply_write(wb); 4827c478bd9Sstevel@tonic-gate } while (dstcount-- > 0); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Supply one route from the table 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4907c478bd9Sstevel@tonic-gate static int 4917c478bd9Sstevel@tonic-gate walk_supply(struct radix_node *rn, void *argp) 4927c478bd9Sstevel@tonic-gate { 4937c478bd9Sstevel@tonic-gate #define RT ((struct rt_entry *)rn) 4947c478bd9Sstevel@tonic-gate ushort_t ags; 4957c478bd9Sstevel@tonic-gate uint8_t metric, pref; 4967c478bd9Sstevel@tonic-gate in_addr_t dst, nhop; 4977c478bd9Sstevel@tonic-gate struct rt_spare *rts; 4987c478bd9Sstevel@tonic-gate uint_t sparecount; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Do not advertise external remote interfaces or passive interfaces. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate if ((RT->rt_state & RS_IF) && RT->rt_ifp != NULL && 5057c478bd9Sstevel@tonic-gate (RT->rt_ifp->int_state & IS_PASSIVE) && 5067c478bd9Sstevel@tonic-gate !(RT->rt_state & RS_MHOME)) 5077c478bd9Sstevel@tonic-gate return (0); 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * Do not advertise routes learnt from /etc/gateways. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate if (RT->rt_spares[0].rts_origin == RO_FILE) 5127c478bd9Sstevel@tonic-gate return (0); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Do not advertise routes which would lead to forwarding on a 5167c478bd9Sstevel@tonic-gate * non-forwarding interface. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate if (RT->rt_state & RS_NOPROPAGATE) 5197c478bd9Sstevel@tonic-gate return (0); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * If being quiet about our ability to forward, then 5237c478bd9Sstevel@tonic-gate * do not say anything unless responding to a query, 5247c478bd9Sstevel@tonic-gate * except about our main interface. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate if (!should_supply(NULL) && !(ws.state & WS_ST_QUERY) && 5277c478bd9Sstevel@tonic-gate !(RT->rt_state & RS_MHOME)) 5287c478bd9Sstevel@tonic-gate return (0); 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate dst = RT->rt_dst; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * do not collide with the fake default route 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate if (dst == RIP_DEFAULT && (ws.state & WS_ST_DEFAULT)) 5367c478bd9Sstevel@tonic-gate return (0); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate if (RT->rt_state & RS_NET_SYN) { 5397c478bd9Sstevel@tonic-gate if (RT->rt_state & RS_NET_INT) { 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Do not send manual synthetic network routes 5427c478bd9Sstevel@tonic-gate * into the subnet. 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, 5457c478bd9Sstevel@tonic-gate ntohl(dst), RT->rt_mask)) 5467c478bd9Sstevel@tonic-gate return (0); 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate } else { 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * Do not send automatic synthetic network routes 5517c478bd9Sstevel@tonic-gate * if they are not needed because no RIPv1 listeners 5527c478bd9Sstevel@tonic-gate * can hear them. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate if (ws.state & WS_ST_RIP2_ALL) 5557c478bd9Sstevel@tonic-gate return (0); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Do not send automatic synthetic network routes to 5597c478bd9Sstevel@tonic-gate * the real subnet. 5607c478bd9Sstevel@tonic-gate */ 5617c478bd9Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, 5627c478bd9Sstevel@tonic-gate ntohl(dst), RT->rt_mask)) 5637c478bd9Sstevel@tonic-gate return (0); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate nhop = 0; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate } else { 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * Advertise the next hop if this is not a route for one 5707c478bd9Sstevel@tonic-gate * of our interfaces and the next hop is on the same 5717c478bd9Sstevel@tonic-gate * network as the target. 5727c478bd9Sstevel@tonic-gate * The final determination is made by supply_out(). 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate if (!(RT->rt_state & RS_IF) && !(RT->rt_state & RS_MHOME) && 5757c478bd9Sstevel@tonic-gate RT->rt_gate != loopaddr) 5767c478bd9Sstevel@tonic-gate nhop = RT->rt_gate; 5777c478bd9Sstevel@tonic-gate else 5787c478bd9Sstevel@tonic-gate nhop = 0; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate metric = RT->rt_metric; 5827c478bd9Sstevel@tonic-gate ags = 0; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if (!RT_ISHOST(RT)) { 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Always suppress network routes into other, existing 5877c478bd9Sstevel@tonic-gate * network routes 5887c478bd9Sstevel@tonic-gate */ 5897c478bd9Sstevel@tonic-gate ags |= AGS_SUPPRESS; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * Generate supernets if allowed. 5937c478bd9Sstevel@tonic-gate * If we can be heard by RIPv1 systems, we will 5947c478bd9Sstevel@tonic-gate * later convert back to ordinary nets. 5957c478bd9Sstevel@tonic-gate * This unifies dealing with received supernets. 5967c478bd9Sstevel@tonic-gate */ 5977c478bd9Sstevel@tonic-gate if ((ws.state & WS_ST_AG) && ((RT->rt_state & RS_SUBNET) || 5987c478bd9Sstevel@tonic-gate (ws.state & WS_ST_SUPER_AG))) 5997c478bd9Sstevel@tonic-gate ags |= AGS_AGGREGATE; 6007c478bd9Sstevel@tonic-gate } else if (!(RT->rt_state & RS_MHOME)) { 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * We should always suppress (into existing network routes) 6037c478bd9Sstevel@tonic-gate * the host routes for the local end of our point-to-point 6047c478bd9Sstevel@tonic-gate * links. 6057c478bd9Sstevel@tonic-gate * If we are suppressing host routes in general, then do so. 6067c478bd9Sstevel@tonic-gate * Avoid advertising host routes onto their own network, 6077c478bd9Sstevel@tonic-gate * where they should be handled by proxy-ARP. 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate if ((RT->rt_state & RS_LOCAL) || ridhosts || 6107c478bd9Sstevel@tonic-gate on_net(dst, ws.to_net, ws.to_mask)) 6117c478bd9Sstevel@tonic-gate ags |= AGS_SUPPRESS; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * Aggregate stray host routes into network routes if allowed. 6157c478bd9Sstevel@tonic-gate * We cannot aggregate host routes into small network routes 6167c478bd9Sstevel@tonic-gate * without confusing RIPv1 listeners into thinking the 6177c478bd9Sstevel@tonic-gate * network routes are host routes. 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate if ((ws.state & WS_ST_AG) && (ws.state & WS_ST_RIP2_ALL)) 6207c478bd9Sstevel@tonic-gate ags |= AGS_AGGREGATE; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * Do not send RIPv1 advertisements of subnets to other 6257c478bd9Sstevel@tonic-gate * networks. If possible, multicast them by RIPv2. 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate if ((RT->rt_state & RS_SUBNET) && !(ws.state & WS_ST_RIP2_ALL) && 6287c478bd9Sstevel@tonic-gate !on_net(dst, ws.to_std_net, ws.to_std_mask)) 6297c478bd9Sstevel@tonic-gate ags |= AGS_RIPV2 | AGS_AGGREGATE; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * Do not send a route back to where it came from, except in 6347c478bd9Sstevel@tonic-gate * response to a query. This is "split-horizon". That means not 6357c478bd9Sstevel@tonic-gate * advertising back to the same network and so via the same interface. 6367c478bd9Sstevel@tonic-gate * 6377c478bd9Sstevel@tonic-gate * We want to suppress routes that might have been fragmented 6387c478bd9Sstevel@tonic-gate * from this route by a RIPv1 router and sent back to us, and so we 6397c478bd9Sstevel@tonic-gate * cannot forget this route here. Let the split-horizon route 6407c478bd9Sstevel@tonic-gate * suppress the fragmented routes and then itself be forgotten. 6417c478bd9Sstevel@tonic-gate * 6427c478bd9Sstevel@tonic-gate * Include the routes for both ends of point-to-point interfaces 6437c478bd9Sstevel@tonic-gate * among those suppressed by split-horizon, since the other side 6447c478bd9Sstevel@tonic-gate * should knows them as well as we do. 6457c478bd9Sstevel@tonic-gate * 6467c478bd9Sstevel@tonic-gate * Notice spare routes with the same metric that we are about to 6477c478bd9Sstevel@tonic-gate * advertise, to split the horizon on redundant, inactive paths. 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate if (ws.ifp != NULL && !(ws.state & WS_ST_QUERY) && 6507c478bd9Sstevel@tonic-gate (ws.state & WS_ST_TO_ON_NET) && (!(RT->rt_state & RS_IF) || 6517c478bd9Sstevel@tonic-gate (ws.ifp->int_if_flags & IFF_POINTOPOINT))) { 6527c478bd9Sstevel@tonic-gate for (rts = RT->rt_spares, sparecount = 0; 6537c478bd9Sstevel@tonic-gate sparecount < RT->rt_num_spares; sparecount++, rts++) { 6547c478bd9Sstevel@tonic-gate if (rts->rts_metric > metric || rts->rts_ifp != ws.ifp) 6557c478bd9Sstevel@tonic-gate continue; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* 6587c478bd9Sstevel@tonic-gate * If we do not mark the route with AGS_SPLIT_HZ here, 6597c478bd9Sstevel@tonic-gate * it will be poisoned-reverse, or advertised back 6607c478bd9Sstevel@tonic-gate * toward its source with an infinite metric. 6617c478bd9Sstevel@tonic-gate * If we have recently advertised the route with a 6627c478bd9Sstevel@tonic-gate * better metric than we now have, then we should 6637c478bd9Sstevel@tonic-gate * poison-reverse the route before suppressing it for 6647c478bd9Sstevel@tonic-gate * split-horizon. 6657c478bd9Sstevel@tonic-gate * 6667c478bd9Sstevel@tonic-gate * In almost all cases, if there is no spare for the 6677c478bd9Sstevel@tonic-gate * route then it is either old and dead or a brand 6687c478bd9Sstevel@tonic-gate * new route. If it is brand new, there is no need 6697c478bd9Sstevel@tonic-gate * for poison-reverse. If it is old and dead, it 6707c478bd9Sstevel@tonic-gate * is already poisoned. 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate if (RT->rt_poison_time < now_expire || 6737c478bd9Sstevel@tonic-gate RT->rt_poison_metric >= metric || 6747c478bd9Sstevel@tonic-gate RT->rt_spares[1].rts_gate == 0) { 6757c478bd9Sstevel@tonic-gate ags |= AGS_SPLIT_HZ; 6767c478bd9Sstevel@tonic-gate ags &= ~AGS_SUPPRESS; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate metric = HOPCNT_INFINITY; 6797c478bd9Sstevel@tonic-gate break; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * Keep track of the best metric with which the 6857c478bd9Sstevel@tonic-gate * route has been advertised recently. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate if (RT->rt_poison_metric >= metric || 6887c478bd9Sstevel@tonic-gate RT->rt_poison_time < now_expire) { 6897c478bd9Sstevel@tonic-gate RT->rt_poison_time = now.tv_sec; 6907c478bd9Sstevel@tonic-gate RT->rt_poison_metric = metric; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Adjust the outgoing metric by the cost of the link. 6957c478bd9Sstevel@tonic-gate * Avoid aggregation when a route is counting to infinity. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate pref = RT->rt_poison_metric + ws.metric; 6987c478bd9Sstevel@tonic-gate metric += ws.metric; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * If this is a static route pointing to the same interface 7027c478bd9Sstevel@tonic-gate * upon which we are sending out the RIP RESPONSE 7037c478bd9Sstevel@tonic-gate * adjust the preference so that we don't aggregate into this 7047c478bd9Sstevel@tonic-gate * route. Note that the maximum possible hop count on a route 7057c478bd9Sstevel@tonic-gate * per RFC 2453 is 16 (HOPCNT_INFINITY) 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate if ((RT->rt_state & RS_STATIC) && (ws.ifp == RT->rt_ifp)) 7087c478bd9Sstevel@tonic-gate pref = (HOPCNT_INFINITY+1); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * Do not advertise stable routes that will be ignored, 7127c478bd9Sstevel@tonic-gate * unless we are answering a query. 7137c478bd9Sstevel@tonic-gate * If the route recently was advertised with a metric that 7147c478bd9Sstevel@tonic-gate * would have been less than infinity through this interface, 7157c478bd9Sstevel@tonic-gate * we need to continue to advertise it in order to poison it. 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate if (metric >= HOPCNT_INFINITY) { 7187c478bd9Sstevel@tonic-gate if (!(ws.state & WS_ST_QUERY) && (pref >= HOPCNT_INFINITY || 7197c478bd9Sstevel@tonic-gate RT->rt_poison_time < now_garbage)) 7207c478bd9Sstevel@tonic-gate return (0); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate metric = HOPCNT_INFINITY; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * supply this route out on the wire- we only care about dest/mask 7277c478bd9Sstevel@tonic-gate * and so can ignore all rt_spares[i] with i > 0 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate ag_check(dst, RT->rt_mask, 0, RT->rt_ifp, nhop, metric, pref, 7307c478bd9Sstevel@tonic-gate RT->rt_seqno, RT->rt_tag, ags, supply_out); 7317c478bd9Sstevel@tonic-gate return (0); 7327c478bd9Sstevel@tonic-gate #undef RT 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate /* 7377c478bd9Sstevel@tonic-gate * Supply dst with the contents of the routing tables. 7387c478bd9Sstevel@tonic-gate * If this won't fit in one packet, chop it up into several. 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate void 7417c478bd9Sstevel@tonic-gate supply(struct sockaddr_in *dst, 7427c478bd9Sstevel@tonic-gate struct interface *ifp, /* output interface */ 7437c478bd9Sstevel@tonic-gate enum output_type type, 7447c478bd9Sstevel@tonic-gate int flash, /* 1=flash update */ 7457c478bd9Sstevel@tonic-gate int vers, /* RIP version */ 7467c478bd9Sstevel@tonic-gate boolean_t passwd_ok) /* OK to include cleartext password */ 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate struct rt_entry *rt; 7497c478bd9Sstevel@tonic-gate uint8_t def_metric; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate ws.state = 0; 7537c478bd9Sstevel@tonic-gate ws.gen_limit = WS_GEN_LIMIT_MAX; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate ws.to = *dst; 7567c478bd9Sstevel@tonic-gate ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); 7577c478bd9Sstevel@tonic-gate ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate if (ifp != NULL) { 7607c478bd9Sstevel@tonic-gate ws.to_mask = ifp->int_mask; 7617c478bd9Sstevel@tonic-gate ws.to_net = ifp->int_net; 7627c478bd9Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask) || 7637c478bd9Sstevel@tonic-gate type == OUT_MULTICAST) 7647c478bd9Sstevel@tonic-gate ws.state |= WS_ST_TO_ON_NET; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate } else { 7677c478bd9Sstevel@tonic-gate ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, NULL); 7687c478bd9Sstevel@tonic-gate ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; 7697c478bd9Sstevel@tonic-gate rt = rtfind(dst->sin_addr.s_addr); 7707c478bd9Sstevel@tonic-gate if (rt != NULL) 7717c478bd9Sstevel@tonic-gate ifp = rt->rt_ifp; 7727c478bd9Sstevel@tonic-gate else 7737c478bd9Sstevel@tonic-gate return; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate ws.npackets = 0; 7777c478bd9Sstevel@tonic-gate if (flash) 7787c478bd9Sstevel@tonic-gate ws.state |= WS_ST_FLASH; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate ws.ifp = ifp; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * Routes in the table were already adjusted by their respective 7847c478bd9Sstevel@tonic-gate * destination interface costs (which are zero by default) on 7857c478bd9Sstevel@tonic-gate * input. The following is the value by which each route's metric 7867c478bd9Sstevel@tonic-gate * will be bumped up on output. 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate ws.metric = 1; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate ripv12_buf.rip.rip_vers = vers; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate switch (type) { 7937c478bd9Sstevel@tonic-gate case OUT_MULTICAST: 7947c478bd9Sstevel@tonic-gate if (ifp->int_if_flags & IFF_MULTICAST) 7957c478bd9Sstevel@tonic-gate v2buf.type = OUT_MULTICAST; 7967c478bd9Sstevel@tonic-gate else 7977c478bd9Sstevel@tonic-gate v2buf.type = NO_OUT_MULTICAST; 7987c478bd9Sstevel@tonic-gate v12buf.type = OUT_BROADCAST; 7997c478bd9Sstevel@tonic-gate break; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate case OUT_QUERY: 8027c478bd9Sstevel@tonic-gate ws.state |= WS_ST_QUERY; 8037c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 8047c478bd9Sstevel@tonic-gate case OUT_BROADCAST: 8057c478bd9Sstevel@tonic-gate case OUT_UNICAST: 8067c478bd9Sstevel@tonic-gate v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; 8077c478bd9Sstevel@tonic-gate v12buf.type = type; 8087c478bd9Sstevel@tonic-gate break; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate case NO_OUT_MULTICAST: 8117c478bd9Sstevel@tonic-gate case NO_OUT_RIPV2: 8127c478bd9Sstevel@tonic-gate return; /* no output */ 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (vers == RIPv2) { 8167c478bd9Sstevel@tonic-gate /* full RIPv2 only if cannot be heard by RIPv1 listeners */ 8177c478bd9Sstevel@tonic-gate if (type != OUT_BROADCAST) 8187c478bd9Sstevel@tonic-gate ws.state |= WS_ST_RIP2_ALL; 8197c478bd9Sstevel@tonic-gate if ((ws.state & WS_ST_QUERY) || !(ws.state & WS_ST_TO_ON_NET)) { 8207c478bd9Sstevel@tonic-gate ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); 8217c478bd9Sstevel@tonic-gate } else if (ifp == NULL || !(ifp->int_state & IS_NO_AG)) { 8227c478bd9Sstevel@tonic-gate ws.state |= WS_ST_AG; 8237c478bd9Sstevel@tonic-gate if (type != OUT_BROADCAST && (ifp == NULL || 8247c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_NO_SUPER_AG))) 8257c478bd9Sstevel@tonic-gate ws.state |= WS_ST_SUPER_AG; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* See if this packet needs authenticating */ 8297c478bd9Sstevel@tonic-gate ws.a = find_auth(ifp); 8307c478bd9Sstevel@tonic-gate if (!passwd_ok && ws.a != NULL && ws.a->type == RIP_AUTH_PW) 8317c478bd9Sstevel@tonic-gate ws.a = NULL; 8327c478bd9Sstevel@tonic-gate if (ws.a != NULL && (ulong_t)ws.a->end < (ulong_t)clk.tv_sec && 8337c478bd9Sstevel@tonic-gate !ws.a->warnedflag) { 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * If the best key is an expired one, we may as 8367c478bd9Sstevel@tonic-gate * well use it. Log this event. 8377c478bd9Sstevel@tonic-gate */ 8387c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, 8397c478bd9Sstevel@tonic-gate "Using expired auth while transmitting to %s", 8407c478bd9Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr)); 8417c478bd9Sstevel@tonic-gate ws.a->warnedflag = 1; 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate } else { 8447c478bd9Sstevel@tonic-gate ws.a = NULL; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate clr_ws_buf(&v12buf, ws.a); 8487c478bd9Sstevel@tonic-gate clr_ws_buf(&v2buf, ws.a); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate /* 8517c478bd9Sstevel@tonic-gate * Fake a default route if asked and if there is not already 8527c478bd9Sstevel@tonic-gate * a better, real default route. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate if (should_supply(NULL) && (def_metric = ifp->int_d_metric) != 0) { 8557c478bd9Sstevel@tonic-gate if (NULL == (rt = rtget(RIP_DEFAULT, 0)) || 8567c478bd9Sstevel@tonic-gate rt->rt_metric+ws.metric >= def_metric) { 8577c478bd9Sstevel@tonic-gate ws.state |= WS_ST_DEFAULT; 8587c478bd9Sstevel@tonic-gate ag_check(0, 0, 0, NULL, 0, def_metric, def_metric, 8597c478bd9Sstevel@tonic-gate 0, 0, 0, supply_out); 8607c478bd9Sstevel@tonic-gate } else { 8617c478bd9Sstevel@tonic-gate def_metric = rt->rt_metric+ws.metric; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * If both RIPv2 and the poor-man's router discovery 8667c478bd9Sstevel@tonic-gate * kludge are on, arrange to advertise an extra 8677c478bd9Sstevel@tonic-gate * default route via RIPv1. 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate if ((ws.state & WS_ST_RIP2_ALL) && 8707c478bd9Sstevel@tonic-gate (ifp->int_state & IS_PM_RDISC)) { 8717c478bd9Sstevel@tonic-gate ripv12_buf.rip.rip_vers = RIPv1; 8727c478bd9Sstevel@tonic-gate v12buf.n->n_family = RIP_AF_INET; 8737c478bd9Sstevel@tonic-gate v12buf.n->n_dst = htonl(RIP_DEFAULT); 8747c478bd9Sstevel@tonic-gate v12buf.n->n_metric = htonl(def_metric); 8757c478bd9Sstevel@tonic-gate v12buf.n++; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate (void) rn_walktree(rhead, walk_supply, NULL); 8807c478bd9Sstevel@tonic-gate ag_flush(0, 0, supply_out); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * Flush the packet buffers, provided they are not empty and 8847c478bd9Sstevel@tonic-gate * do not contain only the password. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate if (v12buf.n != v12buf.base && 8877c478bd9Sstevel@tonic-gate (v12buf.n > v12buf.base+1 || 8887c478bd9Sstevel@tonic-gate v12buf.base->n_family != RIP_AF_AUTH)) 8897c478bd9Sstevel@tonic-gate supply_write(&v12buf); 8907c478bd9Sstevel@tonic-gate if (v2buf.n != v2buf.base && (v2buf.n > v2buf.base+1 || 8917c478bd9Sstevel@tonic-gate v2buf.base->n_family != RIP_AF_AUTH)) 8927c478bd9Sstevel@tonic-gate supply_write(&v2buf); 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* 8957c478bd9Sstevel@tonic-gate * If we sent nothing and this is an answer to a query, send 8967c478bd9Sstevel@tonic-gate * an empty buffer. 8977c478bd9Sstevel@tonic-gate */ 8987c478bd9Sstevel@tonic-gate if (ws.npackets == 0 && (ws.state & WS_ST_QUERY)) { 8997c478bd9Sstevel@tonic-gate supply_write(&v2buf); 9007c478bd9Sstevel@tonic-gate if (ws.npackets == 0) 9017c478bd9Sstevel@tonic-gate supply_write(&v12buf); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * send all of the routing table or just do a flash update 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate void 9107c478bd9Sstevel@tonic-gate rip_bcast(int flash) 9117c478bd9Sstevel@tonic-gate { 9127c478bd9Sstevel@tonic-gate static struct sockaddr_in dst = {AF_INET}; 9137c478bd9Sstevel@tonic-gate struct interface *ifp; 9147c478bd9Sstevel@tonic-gate enum output_type type; 9157c478bd9Sstevel@tonic-gate int vers; 9167c478bd9Sstevel@tonic-gate struct timeval rtime; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate need_flash = _B_FALSE; 9207c478bd9Sstevel@tonic-gate intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); 9217c478bd9Sstevel@tonic-gate no_flash = rtime; 9227c478bd9Sstevel@tonic-gate timevaladd(&no_flash, &now); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate if (!rip_enabled) 9257c478bd9Sstevel@tonic-gate return; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate trace_act("send %s and inhibit dynamic updates for %.3f sec", 9287c478bd9Sstevel@tonic-gate flash ? "dynamic update" : "all routes", 9297c478bd9Sstevel@tonic-gate rtime.tv_sec + ((double)rtime.tv_usec)/1000000.0); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * Skip interfaces not doing RIP or for which IP 9347c478bd9Sstevel@tonic-gate * forwarding isn't turned on. Skip duplicate 9357c478bd9Sstevel@tonic-gate * interfaces, we don't want to generate duplicate 9367c478bd9Sstevel@tonic-gate * packets. Do try broken interfaces to see if they 9377c478bd9Sstevel@tonic-gate * have healed. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate if (IS_RIP_OUT_OFF(ifp->int_state) || 9407c478bd9Sstevel@tonic-gate (ifp->int_state & IS_DUP) || 9417c478bd9Sstevel@tonic-gate !IS_IFF_ROUTING(ifp->int_if_flags)) 9427c478bd9Sstevel@tonic-gate continue; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* skip turned off interfaces */ 9457c478bd9Sstevel@tonic-gate if (!IS_IFF_UP(ifp->int_if_flags)) 9467c478bd9Sstevel@tonic-gate continue; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 9497c478bd9Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 9507c478bd9Sstevel@tonic-gate continue; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; 9537c478bd9Sstevel@tonic-gate dst.sin_addr.s_addr = ifp->int_ripout_addr; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * Ignore the interface if it's not broadcast, 9577c478bd9Sstevel@tonic-gate * point-to-point, or remote. It must be non-broadcast 9587c478bd9Sstevel@tonic-gate * multiaccess, and therefore unsupported. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate if (!(ifp->int_if_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) && 9617c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_REMOTE)) 9627c478bd9Sstevel@tonic-gate continue; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate type = (ifp->int_if_flags & IFF_BROADCAST) ? 9657c478bd9Sstevel@tonic-gate OUT_BROADCAST : OUT_UNICAST; 9667c478bd9Sstevel@tonic-gate if (vers == RIPv2 && (ifp->int_if_flags & IFF_MULTICAST) && 9677c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_NO_RIP_MCAST)) 9687c478bd9Sstevel@tonic-gate type = OUT_MULTICAST; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate supply(&dst, ifp, type, flash, vers, _B_TRUE); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate update_seqno++; /* all routes are up to date */ 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * Ask for routes 9797c478bd9Sstevel@tonic-gate * Do it only once to an interface, and not even after the interface 9807c478bd9Sstevel@tonic-gate * was broken and recovered. 9817c478bd9Sstevel@tonic-gate */ 9827c478bd9Sstevel@tonic-gate void 9837c478bd9Sstevel@tonic-gate rip_query(void) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate static struct sockaddr_in dst = {AF_INET}; 9867c478bd9Sstevel@tonic-gate struct interface *ifp; 9877c478bd9Sstevel@tonic-gate struct rip buf; 9887c478bd9Sstevel@tonic-gate enum output_type type; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate if (!rip_enabled) 9927c478bd9Sstevel@tonic-gate return; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate (void) memset(&buf, 0, sizeof (buf)); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) { 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * Skip interfaces those already queried. Do not ask 9997c478bd9Sstevel@tonic-gate * via interfaces through which we don't accept input. 10007c478bd9Sstevel@tonic-gate * Do not ask via interfaces that cannot send RIP 10017c478bd9Sstevel@tonic-gate * packets. Don't send queries on duplicate 10027c478bd9Sstevel@tonic-gate * interfaces, that would generate duplicate packets 10037c478bd9Sstevel@tonic-gate * on link. Do try broken interfaces to see if they 10047c478bd9Sstevel@tonic-gate * have healed. 10057c478bd9Sstevel@tonic-gate */ 10067c478bd9Sstevel@tonic-gate if (IS_RIP_IN_OFF(ifp->int_state) || 10077c478bd9Sstevel@tonic-gate (ifp->int_state & IS_DUP) || 10087c478bd9Sstevel@tonic-gate ifp->int_query_time != NEVER) 10097c478bd9Sstevel@tonic-gate continue; 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate /* skip turned off interfaces */ 10127c478bd9Sstevel@tonic-gate if (!IS_IFF_UP(ifp->int_if_flags)) 10137c478bd9Sstevel@tonic-gate continue; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 10167c478bd9Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 10177c478bd9Sstevel@tonic-gate continue; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * Ignore the interface if it's not broadcast, 10217c478bd9Sstevel@tonic-gate * point-to-point, or remote. It must be non-broadcast 10227c478bd9Sstevel@tonic-gate * multiaccess, and therefore unsupported. 10237c478bd9Sstevel@tonic-gate */ 10247c478bd9Sstevel@tonic-gate if (!(ifp->int_if_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) && 10257c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_REMOTE)) 10267c478bd9Sstevel@tonic-gate continue; 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate buf.rip_cmd = RIPCMD_REQUEST; 10297c478bd9Sstevel@tonic-gate buf.rip_nets[0].n_family = RIP_AF_UNSPEC; 10307c478bd9Sstevel@tonic-gate buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * Send a RIPv1 query only if allowed and if we will 10347c478bd9Sstevel@tonic-gate * listen to RIPv1 routers. 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate if ((ifp->int_state & IS_NO_RIPV1_OUT) || 10377c478bd9Sstevel@tonic-gate (ifp->int_state & IS_NO_RIPV1_IN)) { 10387c478bd9Sstevel@tonic-gate buf.rip_vers = RIPv2; 10397c478bd9Sstevel@tonic-gate } else { 10407c478bd9Sstevel@tonic-gate buf.rip_vers = RIPv1; 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate dst.sin_addr.s_addr = ifp->int_ripout_addr; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate type = (ifp->int_if_flags & IFF_BROADCAST) ? 10467c478bd9Sstevel@tonic-gate OUT_BROADCAST : OUT_UNICAST; 10477c478bd9Sstevel@tonic-gate if (buf.rip_vers == RIPv2 && 10487c478bd9Sstevel@tonic-gate (ifp->int_if_flags & IFF_MULTICAST) && 10497c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_NO_RIP_MCAST)) 10507c478bd9Sstevel@tonic-gate type = OUT_MULTICAST; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; 10537c478bd9Sstevel@tonic-gate if (output(type, &dst, ifp, &buf, sizeof (buf)) < 0) 10547c478bd9Sstevel@tonic-gate if_sick(ifp, _B_FALSE); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate } 1057