input.c revision 12268
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 * $Id: input.c,v 1.1 1995/10/26 21:28:16 julian Exp $ 39 */ 40 41#ifndef lint 42static 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 struct rt_entry *rt; 73 struct netinfo *n; 74 struct interface *ifp = 0; 75 int newsize; 76 struct afswitch *afp; 77 struct sockaddr_ipx *ipxp; 78 79 ifp = if_ifwithnet(from); 80 ipxp = (struct sockaddr_ipx *)from; 81 if (ifp == 0) { 82 if(ftrace) { 83 fprintf(ftrace, "Received bogus packet from %s\n", 84 ipxdp_ntoa(&ipxp->sipx_addr)); 85 } 86 return; 87 } 88 89 TRACE_INPUT(ifp, from, size); 90 if (from->sa_family >= AF_MAX) 91 return; 92 afp = &afswitch[from->sa_family]; 93 94 size -= sizeof (u_short) /* command */; 95 n = msg->rip_nets; 96 97 switch (ntohs(msg->rip_cmd)) { 98 99 case RIPCMD_REQUEST: 100 if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr)) 101 return; 102 newsize = 0; 103 while (size > 0) { 104 if (size < sizeof (struct netinfo)) 105 break; 106 size -= sizeof (struct netinfo); 107 108 /* 109 * A single entry with rip_dst == DSTNETS_ALL and 110 * metric ``infinity'' means ``all routes''. 111 * 112 * XXX According to the IPX RIP spec the metric 113 * and tick fields can be anything. So maybe we 114 * should not check the metric??? 115 */ 116 if (ipx_neteqnn(n->rip_dst, ipx_anynet) && 117 ntohs(n->rip_metric) == HOPCNT_INFINITY && 118 size == 0) { 119 supply(from, 0, ifp); 120 return; 121 } 122 /* 123 * request for specific nets 124 */ 125 rt = rtlookup(ipx_nettosa(n->rip_dst)); 126 if (ftrace) { 127 fprintf(ftrace, 128 "specific request for %s", 129 ipxdp_nettoa(n->rip_dst)); 130 fprintf(ftrace, 131 " yields route %x\n", 132 (u_int)rt); 133 } 134 /* 135 * XXX We break out on the first net that isn't 136 * found. The specs is a bit vague here. I'm not 137 * sure what we should do. 138 */ 139 if (rt == 0) 140 return; 141 /* XXX 142 * According to the spec we should not include 143 * information about networks for which the number 144 * of hops is 16. 145 */ 146 if (rt->rt_metric == (HOPCNT_INFINITY-1)) 147 return; 148 n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : 149 min(rt->rt_metric+1, HOPCNT_INFINITY)); 150 n->rip_ticks = htons(rt->rt_ticks+1); 151 152 /* 153 * We use split horizon with a twist. If the requested 154 * net is the directly connected net we supply an 155 * answer. This is so that the host can learn about 156 * the routers on its net. 157 */ 158 { 159 register struct rt_entry *trt = rt; 160 161 while (trt) { 162 if ((trt->rt_ifp == ifp) && 163 !ipx_neteqnn(n->rip_dst, 164 satoipx_addr(ifp->int_addr).x_net)) 165 return; 166 trt = trt->rt_clone; 167 } 168 n++; 169 newsize += sizeof (struct netinfo); 170 } 171 } 172 if (newsize > 0) { 173 msg->rip_cmd = htons(RIPCMD_RESPONSE); 174 newsize += sizeof (u_short); 175 /* should check for if with dstaddr(from) first */ 176 (*afp->af_output)(ripsock, 0, from, newsize); 177 TRACE_OUTPUT(ifp, from, newsize); 178 if (ftrace) { 179 /* XXX This should not happen anymore. */ 180 if(ifp == 0) 181 fprintf(ftrace, "--- ifp = 0\n"); 182 else 183 fprintf(ftrace, 184 "request arrived on interface %s\n", 185 ifp->int_name); 186 } 187 } 188 return; 189 190 case RIPCMD_RESPONSE: 191 /* verify message came from a router */ 192 if ((*afp->af_portmatch)(from) == 0) 193 return; 194 (*afp->af_canon)(from); 195 /* are we talking to ourselves? */ 196 if ((ifp = if_ifwithaddr(from)) != 0) { 197 rt = rtfind(from); 198 if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) 199 addrouteforif(ifp); 200 else 201 rt->rt_timer = 0; 202 return; 203 } 204 /* Update timer for interface on which the packet arrived. 205 * If from other end of a point-to-point link that isn't 206 * in the routing tables, (re-)add the route. 207 */ 208 if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) { 209 if(ftrace) fprintf(ftrace, "Got route\n"); 210 rt->rt_timer = 0; 211 } else if ((ifp = if_ifwithdstaddr(from)) != 0) { 212 if(ftrace) fprintf(ftrace, "Got partner\n"); 213 addrouteforif(ifp); 214 } 215 for (; size > 0; size -= sizeof (struct netinfo), n++) { 216 struct sockaddr *sa; 217 if (size < sizeof (struct netinfo)) 218 break; 219 if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY) 220 continue; 221 rt = rtfind(sa = ipx_nettosa(n->rip_dst)); 222 if (rt == 0) { 223 rtadd(sa, from, ntohs(n->rip_metric), 224 ntohs(n->rip_ticks), 0); 225 continue; 226 } 227 228 /* 229 * A clone is a different route to the same net 230 * with exactly the same cost (ticks and metric). 231 * They must all be recorded because those interfaces 232 * must be handled in the same way as the first route 233 * to that net. ie When using the split horizon 234 * algorithm we must look at these interfaces also. 235 * 236 * Update if from gateway and different, 237 * from anywhere and less ticks or 238 * if same ticks and shorter, 239 * or getting stale and equivalent. 240 * 241 * XXX I don't think this is quite right. 242 */ 243 if (!equal(from, &rt->rt_router) && 244 ntohs(n->rip_ticks == rt->rt_ticks) && 245 ntohs(n->rip_metric == rt->rt_metric)) { 246 register struct rt_entry *trt = rt->rt_clone; 247 248 while (trt) { 249 if (equal(from, &trt->rt_router)) { 250 trt->rt_timer = 0; 251 break; 252 } 253 } 254 if (trt == NULL) { 255 rtadd_clone(rt, sa, from, 256 ntohs(n->rip_metric), 257 ntohs(n->rip_ticks), 0); 258 } 259 continue; 260 } 261 if ((equal(from, &rt->rt_router) && 262 ((ntohs(n->rip_ticks) != rt->rt_ticks) || 263 (ntohs(n->rip_metric) != rt->rt_metric))) || 264 (ntohs(n->rip_ticks) < rt->rt_ticks) || 265 ((ntohs(n->rip_ticks) == rt->rt_ticks) && 266 (ntohs(n->rip_metric) < rt->rt_metric)) || 267 (rt->rt_timer > (EXPIRE_TIME*2/3) && 268 rt->rt_metric == ntohs(n->rip_metric))) { 269 rtchange(rt, from, ntohs(n->rip_metric), 270 ntohs(n->rip_ticks)); 271 rt->rt_timer = 0; 272 } else if (equal(from, &rt->rt_router) && 273 (ntohs(n->rip_ticks) == rt->rt_ticks) && 274 (ntohs(n->rip_metric) == rt->rt_metric)) { 275 rt->rt_timer = 0; 276 } 277 } 278 return; 279 } 280} 281