input.c revision 12620
1255570Strasz/* 2255570Strasz * Copyright (c) 1985, 1993 3255570Strasz * The Regents of the University of California. All rights reserved. 4255570Strasz * 5255570Strasz * Copyright (c) 1995 John Hay. All rights reserved. 6255570Strasz * 7255570Strasz * This file includes significant work done at Cornell University by 8255570Strasz * Bill Nesheim. That work included by permission. 9255570Strasz * 10255570Strasz * Redistribution and use in source and binary forms, with or without 11255570Strasz * modification, are permitted provided that the following conditions 12255570Strasz * are met: 13255570Strasz * 1. Redistributions of source code must retain the above copyright 14255570Strasz * notice, this list of conditions and the following disclaimer. 15255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 16255570Strasz * notice, this list of conditions and the following disclaimer in the 17255570Strasz * documentation and/or other materials provided with the distribution. 18255570Strasz * 3. All advertising materials mentioning features or use of this software 19255570Strasz * must display the following acknowledgement: 20255570Strasz * This product includes software developed by the University of 21255570Strasz * California, Berkeley and its contributors. 22255570Strasz * 4. Neither the name of the University nor the names of its contributors 23255570Strasz * may be used to endorse or promote products derived from this software 24255570Strasz * without specific prior written permission. 25255570Strasz * 26255570Strasz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36265513Strasz * SUCH DAMAGE. 37265513Strasz * 38270137Smav * $Id: input.c,v 1.2 1995/11/13 21:01:30 julian Exp $ 39265513Strasz */ 40255570Strasz 41255570Strasz#ifndef lint 42255570Straszstatic char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; 43255570Strasz#endif /* not lint */ 44255570Strasz 45255570Strasz/* 46255570Strasz * IPX Routing Table Management Daemon 47255570Strasz */ 48255570Strasz#include "defs.h" 49255570Strasz 50255570Straszstruct sockaddr * 51255570Straszipx_nettosa(net) 52255570Straszunion ipx_net net; 53255570Strasz{ 54255570Strasz static struct sockaddr_ipx sxn; 55255570Strasz 56255570Strasz bzero(&sxn, sizeof (struct sockaddr_ipx)); 57255570Strasz sxn.sipx_family = AF_IPX; 58255570Strasz sxn.sipx_len = sizeof (sxn); 59255570Strasz sxn.sipx_addr.x_net = net; 60263720Strasz return( (struct sockaddr *)&sxn); 61263720Strasz 62263720Strasz} 63263720Strasz 64263720Strasz/* 65263720Strasz * Process a newly received packet. 66263720Strasz */ 67263720Straszvoid 68263720Straszrip_input(from, size) 69263720Strasz struct sockaddr *from; 70270137Smav int size; 71270137Smav{ 72263720Strasz struct rt_entry *rt; 73263720Strasz struct netinfo *n; 74255570Strasz struct interface *ifp = 0; 75263729Strasz int newsize; 76263729Strasz struct afswitch *afp; 77263729Strasz struct sockaddr_ipx *ipxp; 78263729Strasz 79255570Strasz ifp = if_ifwithnet(from); 80255570Strasz ipxp = (struct sockaddr_ipx *)from; 81255570Strasz if (ifp == 0) { 82255570Strasz if(ftrace) { 83255570Strasz fprintf(ftrace, "Received bogus packet from %s\n", 84255570Strasz ipxdp_ntoa(&ipxp->sipx_addr)); 85255570Strasz } 86255570Strasz return; 87263720Strasz } 88263720Strasz 89255570Strasz TRACE_INPUT(ifp, from, size); 90255570Strasz if (from->sa_family >= AF_MAX) 91255570Strasz return; 92255570Strasz afp = &afswitch[from->sa_family]; 93255570Strasz 94255570Strasz size -= sizeof (u_short) /* command */; 95255570Strasz n = msg->rip_nets; 96255570Strasz 97265509Strasz switch (ntohs(msg->rip_cmd)) { 98265509Strasz 99265509Strasz case RIPCMD_REQUEST: 100255570Strasz if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr)) 101255570Strasz return; 102255570Strasz newsize = 0; 103255570Strasz while (size > 0) { 104255570Strasz if (size < sizeof (struct netinfo)) 105255570Strasz break; 106255570Strasz size -= sizeof (struct netinfo); 107255570Strasz 108255570Strasz /* 109255570Strasz * A single entry with rip_dst == DSTNETS_ALL and 110255570Strasz * metric ``infinity'' means ``all routes''. 111255570Strasz * 112255570Strasz * XXX According to the IPX RIP spec the metric 113255570Strasz * and tick fields can be anything. So maybe we 114255570Strasz * should not check the metric??? 115255570Strasz */ 116255570Strasz if (ipx_neteqnn(n->rip_dst, ipx_anynet) && 117255570Strasz ntohs(n->rip_metric) == HOPCNT_INFINITY && 118255570Strasz size == 0) { 119255570Strasz supply(from, 0, ifp); 120255570Strasz return; 121255570Strasz } 122255570Strasz /* 123255570Strasz * request for specific nets 124255570Strasz */ 125255570Strasz rt = rtlookup(ipx_nettosa(n->rip_dst)); 126255570Strasz if (ftrace) { 127255570Strasz fprintf(ftrace, 128255570Strasz "specific request for %s", 129255570Strasz ipxdp_nettoa(n->rip_dst)); 130255570Strasz fprintf(ftrace, 131255570Strasz " yields route %x\n", 132255570Strasz (u_int)rt); 133255570Strasz } 134255570Strasz /* 135255570Strasz * XXX We break out on the first net that isn't 136255570Strasz * found. The specs is a bit vague here. I'm not 137255570Strasz * sure what we should do. 138255570Strasz */ 139255570Strasz if (rt == 0) 140255570Strasz return; 141255570Strasz /* XXX 142255570Strasz * According to the spec we should not include 143255570Strasz * information about networks for which the number 144263723Strasz * of hops is 16. 145255570Strasz */ 146255570Strasz if (rt->rt_metric == (HOPCNT_INFINITY-1)) 147255570Strasz return; 148255570Strasz n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : 149255570Strasz min(rt->rt_metric+1, HOPCNT_INFINITY)); 150255570Strasz n->rip_ticks = htons(rt->rt_ticks+1); 151255570Strasz 152255570Strasz /* 153255570Strasz * We use split horizon with a twist. If the requested 154255570Strasz * net is the directly connected net we supply an 155255570Strasz * answer. This is so that the host can learn about 156255570Strasz * the routers on its net. 157255570Strasz */ 158265509Strasz { 159265509Strasz register struct rt_entry *trt = rt; 160265509Strasz 161255570Strasz while (trt) { 162263725Strasz if ((trt->rt_ifp == ifp) && 163263725Strasz !ipx_neteqnn(n->rip_dst, 164263725Strasz satoipx_addr(ifp->int_addr).x_net)) 165265511Strasz return; 166255570Strasz trt = trt->rt_clone; 167255570Strasz } 168255570Strasz n++; 169255570Strasz newsize += sizeof (struct netinfo); 170255570Strasz } 171255570Strasz } 172255570Strasz if (newsize > 0) { 173255570Strasz msg->rip_cmd = htons(RIPCMD_RESPONSE); 174255570Strasz newsize += sizeof (u_short); 175255570Strasz /* should check for if with dstaddr(from) first */ 176255570Strasz (*afp->af_output)(ripsock, 0, from, newsize); 177255570Strasz TRACE_OUTPUT(ifp, from, newsize); 178255570Strasz if (ftrace) { 179255570Strasz /* XXX This should not happen anymore. */ 180255570Strasz if(ifp == 0) 181255570Strasz fprintf(ftrace, "--- ifp = 0\n"); 182255570Strasz else 183268684Smav fprintf(ftrace, 184270137Smav "request arrived on interface %s\n", 185255570Strasz ifp->int_name); 186255570Strasz } 187255570Strasz } 188255570Strasz return; 189255570Strasz 190255570Strasz case RIPCMD_RESPONSE: 191255570Strasz /* verify message came from a router */ 192255570Strasz if ((*afp->af_portmatch)(from) == 0) 193255570Strasz return; 194255570Strasz (*afp->af_canon)(from); 195255570Strasz /* are we talking to ourselves? */ 196255570Strasz if ((ifp = if_ifwithaddr(from)) != 0) { 197255570Strasz rt = rtfind(from); 198255570Strasz if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) 199255570Strasz addrouteforif(ifp); 200255570Strasz else 201255570Strasz rt->rt_timer = 0; 202255570Strasz return; 203255570Strasz } 204255570Strasz /* Update timer for interface on which the packet arrived. 205255570Strasz * If from other end of a point-to-point link that isn't 206255570Strasz * in the routing tables, (re-)add the route. 207255570Strasz */ 208255570Strasz if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) { 209255570Strasz if(ftrace) fprintf(ftrace, "Got route\n"); 210255570Strasz rt->rt_timer = 0; 211255570Strasz } else if ((ifp = if_ifwithdstaddr(from)) != 0) { 212255570Strasz if(ftrace) fprintf(ftrace, "Got partner\n"); 213255570Strasz addrouteforif(ifp); 214255570Strasz } 215255570Strasz for (; size > 0; size -= sizeof (struct netinfo), n++) { 216255570Strasz struct sockaddr *sa; 217255570Strasz if (size < sizeof (struct netinfo)) 218265514Strasz break; 219265514Strasz if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY) 220263724Strasz continue; 221263724Strasz rt = rtfind(sa = ipx_nettosa(n->rip_dst)); 222255570Strasz if (rt == 0) { 223255570Strasz rtadd(sa, from, ntohs(n->rip_metric), 224255570Strasz ntohs(n->rip_ticks), 0); 225255570Strasz continue; 226255570Strasz } 227255570Strasz 228265514Strasz /* 229255570Strasz * A clone is a different route to the same net 230255570Strasz * with exactly the same cost (ticks and metric). 231263720Strasz * They must all be recorded because those interfaces 232263720Strasz * must be handled in the same way as the first route 233263720Strasz * to that net. ie When using the split horizon 234263720Strasz * algorithm we must look at these interfaces also. 235263720Strasz * 236263720Strasz * Update if from gateway and different, 237263720Strasz * from anywhere and less ticks or 238263720Strasz * if same ticks and shorter, 239263720Strasz * or getting stale and equivalent. 240263720Strasz * 241270137Smav * XXX I don't think this is quite right. 242263720Strasz */ 243255570Strasz if (!equal(from, &rt->rt_router) && 244255570Strasz ntohs(n->rip_ticks == rt->rt_ticks) && 245265514Strasz ntohs(n->rip_metric == rt->rt_metric)) { 246265514Strasz register struct rt_entry *trt = rt->rt_clone; 247255570Strasz 248255570Strasz while (trt) { 249255570Strasz if (equal(from, &trt->rt_router)) { 250263723Strasz trt->rt_timer = 0; 251255570Strasz break; 252255570Strasz } 253263723Strasz trt = trt->rt_clone; 254255570Strasz } 255255570Strasz if (trt == NULL) { 256255570Strasz rtadd_clone(rt, sa, from, 257265514Strasz ntohs(n->rip_metric), 258255570Strasz ntohs(n->rip_ticks), 0); 259255570Strasz } 260255570Strasz continue; 261255570Strasz } 262255570Strasz if ((equal(from, &rt->rt_router) && 263255570Strasz ((ntohs(n->rip_ticks) != rt->rt_ticks) || 264255570Strasz (ntohs(n->rip_metric) != rt->rt_metric))) || 265255570Strasz (ntohs(n->rip_ticks) < rt->rt_ticks) || 266255570Strasz ((ntohs(n->rip_ticks) == rt->rt_ticks) && 267255570Strasz (ntohs(n->rip_metric) < rt->rt_metric)) || 268255570Strasz (rt->rt_timer > (EXPIRE_TIME*2/3) && 269265514Strasz rt->rt_metric == ntohs(n->rip_metric))) { 270265514Strasz rtchange(rt, from, ntohs(n->rip_metric), 271255570Strasz ntohs(n->rip_ticks)); 272255570Strasz rt->rt_timer = 0; 273255570Strasz } else if (equal(from, &rt->rt_router) && 274255570Strasz (ntohs(n->rip_ticks) == rt->rt_ticks) && 275255570Strasz (ntohs(n->rip_metric) == rt->rt_metric)) { 276255570Strasz rt->rt_timer = 0; 277255570Strasz } 278255570Strasz } 279268682Smav return; 280268682Smav } 281255570Strasz} 282255570Strasz