1/* 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Copyright (c) 1995 John Hay. All rights reserved. 6 * 7 * This file includes significant work done at Cornell University by 8 * Bill Nesheim. That work included by permission. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * $FreeBSD$ 39 */ 40 41#ifndef lint 42static const char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; 43#endif /* not lint */ 44 45/* 46 * IPX Routing Table Management Daemon 47 */ 48#include "defs.h" 49 50struct sockaddr * 51ipx_nettosa(net) 52union ipx_net net; 53{ 54 static struct sockaddr_ipx sxn; 55 56 bzero(&sxn, sizeof (struct sockaddr_ipx)); 57 sxn.sipx_family = AF_IPX; 58 sxn.sipx_len = sizeof (sxn); 59 sxn.sipx_addr.x_net = net; 60 return( (struct sockaddr *)&sxn); 61 62} 63 64/* 65 * Process a newly received packet. 66 */ 67void 68rip_input(from, size) 69 struct sockaddr *from; 70 int size; 71{ 72 int newsize; 73 int rtchanged = 0; 74 struct rt_entry *rt; 75 struct netinfo *n; 76 struct interface *ifp = 0; 77 struct afswitch *afp; 78 struct sockaddr_ipx *ipxp; 79 80 ifp = if_ifwithnet(from); 81 ipxp = (struct sockaddr_ipx *)from; 82 if (ifp == 0) { 83 if(ftrace) { 84 fprintf(ftrace, "Received bogus packet from %s\n", 85 ipxdp_ntoa(&ipxp->sipx_addr)); 86 } 87 return; 88 } 89 90 TRACE_INPUT(ifp, from, size); 91 if (from->sa_family >= AF_MAX) 92 return; 93 afp = &afswitch[from->sa_family]; 94 95 size -= sizeof (u_short) /* command */; 96 n = msg->rip_nets; 97 98 switch (ntohs(msg->rip_cmd)) { 99 100 case RIPCMD_REQUEST: 101 if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr)) 102 return; 103 newsize = 0; 104 while (size > 0) { 105 if (size < sizeof (struct netinfo)) 106 break; 107 size -= sizeof (struct netinfo); 108 109 /* 110 * A single entry with rip_dst == DSTNETS_ALL and 111 * metric ``infinity'' means ``all routes''. 112 * 113 * XXX According to the IPX RIP spec the metric 114 * and tick fields can be anything. So maybe we 115 * should not check the metric??? 116 */ 117 if (ipx_neteqnn(n->rip_dst, ipx_anynet) && 118 ntohs(n->rip_metric) == HOPCNT_INFINITY && 119 size == 0) { 120 supply(from, 0, ifp, 0); 121 return; 122 } 123 /* 124 * request for specific nets 125 */ 126 rt = rtlookup(ipx_nettosa(n->rip_dst)); 127 if (ftrace) { 128 fprintf(ftrace, 129 "specific request for %s", 130 ipxdp_nettoa(n->rip_dst)); 131 fprintf(ftrace, 132 " yields route %lx\n", 133 (u_long)rt); 134 } 135 /* 136 * XXX We break out on the first net that isn't 137 * found. The specs is a bit vague here. I'm not 138 * sure what we should do. 139 */ 140 if (rt == 0) 141 return; 142 /* XXX 143 * According to the spec we should not include 144 * information about networks for which the number 145 * of hops is 16. 146 */ 147 if (rt->rt_metric == (HOPCNT_INFINITY-1)) 148 return; 149 n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : 150 min(rt->rt_metric+1, HOPCNT_INFINITY)); 151 n->rip_ticks = htons(rt->rt_ticks+1); 152 153 /* 154 * We use split horizon with a twist. If the requested 155 * net is the directly connected net we supply an 156 * answer. This is so that the host can learn about 157 * the routers on its net. 158 */ 159 { 160 register struct rt_entry *trt = rt; 161 162 while (trt) { 163 if ((trt->rt_ifp == ifp) && 164 !ipx_neteqnn(n->rip_dst, 165 satoipx_addr(ifp->int_addr).x_net)) 166 return; 167 trt = trt->rt_clone; 168 } 169 n++; 170 newsize += sizeof (struct netinfo); 171 } 172 } 173 if (newsize > 0) { 174 msg->rip_cmd = htons(RIPCMD_RESPONSE); 175 newsize += sizeof (u_short); 176 /* should check for if with dstaddr(from) first */ 177 (*afp->af_output)(ripsock, 0, from, newsize); 178 TRACE_OUTPUT(ifp, from, newsize); 179 if (ftrace) { 180 /* XXX This should not happen anymore. */ 181 if(ifp == 0) 182 fprintf(ftrace, "--- ifp = 0\n"); 183 else 184 fprintf(ftrace, 185 "request arrived on interface %s\n", 186 ifp->int_name); 187 } 188 } 189 return; 190 191 case RIPCMD_RESPONSE: 192 /* verify message came from a router */ 193 if ((*afp->af_portmatch)(from) == 0) 194 return; 195 (*afp->af_canon)(from); 196 /* are we talking to ourselves? */ 197 if ((ifp = if_ifwithaddr(from)) != 0) { 198 rt = rtfind(from); 199 if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) { 200 addrouteforif(ifp); 201 rtchanged = 1; 202 } else 203 rt->rt_timer = 0; 204 return; 205 } 206 /* Update timer for interface on which the packet arrived. 207 * If from other end of a point-to-point link that isn't 208 * in the routing tables, (re-)add the route. 209 */ 210 if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) { 211 if(ftrace) fprintf(ftrace, "Got route\n"); 212 rt->rt_timer = 0; 213 } else if ((ifp = if_ifwithdstaddr(from)) != 0) { 214 if(ftrace) fprintf(ftrace, "Got partner\n"); 215 addrouteforif(ifp); 216 rtchanged = 1; 217 } 218 for (; size > 0; size -= sizeof (struct netinfo), n++) { 219 struct sockaddr *sa; 220 if (size < sizeof (struct netinfo)) 221 break; 222 if ((unsigned) ntohs(n->rip_metric) > HOPCNT_INFINITY) 223 continue; 224 rt = rtfind(sa = ipx_nettosa(n->rip_dst)); 225 if (rt == 0) { 226 if (ntohs(n->rip_metric) == HOPCNT_INFINITY) 227 continue; 228 rtadd(sa, from, ntohs(n->rip_metric), 229 ntohs(n->rip_ticks), 0); 230 rtchanged = 1; 231 continue; 232 } 233 234 /* 235 * A clone is a different route to the same net 236 * with exactly the same cost (ticks and metric). 237 * They must all be recorded because those interfaces 238 * must be handled in the same way as the first route 239 * to that net. ie When using the split horizon 240 * algorithm we must look at these interfaces also. 241 * 242 * Update if from gateway and different, 243 * from anywhere and less ticks or 244 * if same ticks and shorter, 245 * or getting stale and equivalent. 246 */ 247 if (!equal(from, &rt->rt_router) && 248 ntohs(n->rip_ticks) == rt->rt_ticks && 249 ntohs(n->rip_metric) == rt->rt_metric && 250 ntohs(n->rip_metric) != HOPCNT_INFINITY) { 251 register struct rt_entry *trt = rt->rt_clone; 252 253 while (trt) { 254 if (equal(from, &trt->rt_router)) { 255 trt->rt_timer = 0; 256 break; 257 } 258 trt = trt->rt_clone; 259 } 260 if (trt == NULL) { 261 rtadd_clone(rt, sa, from, 262 ntohs(n->rip_metric), 263 ntohs(n->rip_ticks), 0); 264 } 265 continue; 266 } 267 if ((equal(from, &rt->rt_router) && 268 ((ntohs(n->rip_ticks) != rt->rt_ticks) || 269 (ntohs(n->rip_metric) != rt->rt_metric))) || 270 (ntohs(n->rip_ticks) < rt->rt_ticks) || 271 ((ntohs(n->rip_ticks) == rt->rt_ticks) && 272 (ntohs(n->rip_metric) < rt->rt_metric)) || 273 (rt->rt_timer > (EXPIRE_TIME*2/3) && 274 rt->rt_metric == ntohs(n->rip_metric) && 275 ntohs(n->rip_metric) != HOPCNT_INFINITY)) { 276 rtchange(rt, from, ntohs(n->rip_metric), 277 ntohs(n->rip_ticks)); 278 if (ntohs(n->rip_metric) == HOPCNT_INFINITY) 279 rt->rt_timer = EXPIRE_TIME; 280 else 281 rt->rt_timer = 0; 282 rtchanged = 1; 283 } else if (equal(from, &rt->rt_router) && 284 (ntohs(n->rip_ticks) == rt->rt_ticks) && 285 (ntohs(n->rip_metric) == rt->rt_metric) && 286 (ntohs(n->rip_metric) != HOPCNT_INFINITY)) { 287 rt->rt_timer = 0; 288 } 289 } 290 if (rtchanged) { 291 register struct rthash *rh; 292 register struct rt_entry *rt; 293 294 toall(supply, NULL, 1); 295 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 296 for (rt = rh->rt_forw; 297 rt != (struct rt_entry *)rh; 298 rt = rt->rt_forw) 299 rt->rt_state &= ~RTS_CHANGED; 300 } 301 302 return; 303 } 304} 305