111820Sjulian/* 211820Sjulian * Copyright (c) 1985, 1993 311820Sjulian * The Regents of the University of California. All rights reserved. 411820Sjulian * 511820Sjulian * Copyright (c) 1995 John Hay. All rights reserved. 611820Sjulian * 711820Sjulian * This file includes significant work done at Cornell University by 811820Sjulian * Bill Nesheim. That work included by permission. 911820Sjulian * 1011820Sjulian * Redistribution and use in source and binary forms, with or without 1111820Sjulian * modification, are permitted provided that the following conditions 1211820Sjulian * are met: 1311820Sjulian * 1. Redistributions of source code must retain the above copyright 1411820Sjulian * notice, this list of conditions and the following disclaimer. 1511820Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1611820Sjulian * notice, this list of conditions and the following disclaimer in the 1711820Sjulian * documentation and/or other materials provided with the distribution. 1811820Sjulian * 3. All advertising materials mentioning features or use of this software 1911820Sjulian * must display the following acknowledgement: 2011820Sjulian * This product includes software developed by the University of 2111820Sjulian * California, Berkeley and its contributors. 2211820Sjulian * 4. Neither the name of the University nor the names of its contributors 2311820Sjulian * may be used to endorse or promote products derived from this software 2411820Sjulian * without specific prior written permission. 2511820Sjulian * 2611820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2711820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2811820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2911820Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3011820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3111820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3211820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3311820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3411820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3511820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3611820Sjulian * SUCH DAMAGE. 3711820Sjulian * 3850479Speter * $FreeBSD$ 3911820Sjulian */ 4011820Sjulian 4111820Sjulian#ifndef lint 42122760Strhodesstatic const char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; 4311820Sjulian#endif /* not lint */ 4411820Sjulian 4511820Sjulian/* 4611820Sjulian * IPX Routing Table Management Daemon 4711820Sjulian */ 4811820Sjulian#include "defs.h" 4911820Sjulian 5011820Sjulianstruct sockaddr * 5111820Sjulianipx_nettosa(net) 5211820Sjulianunion ipx_net net; 5311820Sjulian{ 5411820Sjulian static struct sockaddr_ipx sxn; 5511820Sjulian 5611820Sjulian bzero(&sxn, sizeof (struct sockaddr_ipx)); 5711820Sjulian sxn.sipx_family = AF_IPX; 5811820Sjulian sxn.sipx_len = sizeof (sxn); 5911820Sjulian sxn.sipx_addr.x_net = net; 6011820Sjulian return( (struct sockaddr *)&sxn); 6111820Sjulian 6211820Sjulian} 6311820Sjulian 6411820Sjulian/* 6511820Sjulian * Process a newly received packet. 6611820Sjulian */ 6711820Sjulianvoid 6811820Sjulianrip_input(from, size) 6911820Sjulian struct sockaddr *from; 7011820Sjulian int size; 7111820Sjulian{ 7227244Sjhay int newsize; 7327244Sjhay int rtchanged = 0; 7411820Sjulian struct rt_entry *rt; 7511820Sjulian struct netinfo *n; 7611820Sjulian struct interface *ifp = 0; 7711820Sjulian struct afswitch *afp; 7811820Sjulian struct sockaddr_ipx *ipxp; 7911820Sjulian 8011820Sjulian ifp = if_ifwithnet(from); 8111820Sjulian ipxp = (struct sockaddr_ipx *)from; 8211820Sjulian if (ifp == 0) { 8311820Sjulian if(ftrace) { 8411820Sjulian fprintf(ftrace, "Received bogus packet from %s\n", 8511820Sjulian ipxdp_ntoa(&ipxp->sipx_addr)); 8611820Sjulian } 8711820Sjulian return; 8811820Sjulian } 8911820Sjulian 9011820Sjulian TRACE_INPUT(ifp, from, size); 9111820Sjulian if (from->sa_family >= AF_MAX) 9211820Sjulian return; 9311820Sjulian afp = &afswitch[from->sa_family]; 9411820Sjulian 9511820Sjulian size -= sizeof (u_short) /* command */; 9611820Sjulian n = msg->rip_nets; 9711820Sjulian 9811820Sjulian switch (ntohs(msg->rip_cmd)) { 9911820Sjulian 10011820Sjulian case RIPCMD_REQUEST: 10111820Sjulian if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr)) 10211820Sjulian return; 10311820Sjulian newsize = 0; 10411820Sjulian while (size > 0) { 10511820Sjulian if (size < sizeof (struct netinfo)) 10611820Sjulian break; 10711820Sjulian size -= sizeof (struct netinfo); 10811820Sjulian 10911820Sjulian /* 11011820Sjulian * A single entry with rip_dst == DSTNETS_ALL and 11111820Sjulian * metric ``infinity'' means ``all routes''. 11211820Sjulian * 11311820Sjulian * XXX According to the IPX RIP spec the metric 11411820Sjulian * and tick fields can be anything. So maybe we 11511820Sjulian * should not check the metric??? 11611820Sjulian */ 11711820Sjulian if (ipx_neteqnn(n->rip_dst, ipx_anynet) && 11811820Sjulian ntohs(n->rip_metric) == HOPCNT_INFINITY && 11911820Sjulian size == 0) { 12027244Sjhay supply(from, 0, ifp, 0); 12111820Sjulian return; 12211820Sjulian } 12311820Sjulian /* 12411820Sjulian * request for specific nets 12511820Sjulian */ 12611820Sjulian rt = rtlookup(ipx_nettosa(n->rip_dst)); 12711820Sjulian if (ftrace) { 12811820Sjulian fprintf(ftrace, 12911820Sjulian "specific request for %s", 13011820Sjulian ipxdp_nettoa(n->rip_dst)); 13111820Sjulian fprintf(ftrace, 132121552Speter " yields route %lx\n", 133121552Speter (u_long)rt); 13411820Sjulian } 13511820Sjulian /* 13611820Sjulian * XXX We break out on the first net that isn't 13711820Sjulian * found. The specs is a bit vague here. I'm not 13811820Sjulian * sure what we should do. 13911820Sjulian */ 14011820Sjulian if (rt == 0) 14111820Sjulian return; 14211820Sjulian /* XXX 14311820Sjulian * According to the spec we should not include 14411820Sjulian * information about networks for which the number 14511820Sjulian * of hops is 16. 14611820Sjulian */ 14711820Sjulian if (rt->rt_metric == (HOPCNT_INFINITY-1)) 14811820Sjulian return; 14911820Sjulian n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY : 15011820Sjulian min(rt->rt_metric+1, HOPCNT_INFINITY)); 15111820Sjulian n->rip_ticks = htons(rt->rt_ticks+1); 15211820Sjulian 15311820Sjulian /* 15411820Sjulian * We use split horizon with a twist. If the requested 15511820Sjulian * net is the directly connected net we supply an 15611820Sjulian * answer. This is so that the host can learn about 15711820Sjulian * the routers on its net. 15811820Sjulian */ 15911820Sjulian { 16011820Sjulian register struct rt_entry *trt = rt; 16111820Sjulian 16211820Sjulian while (trt) { 16311820Sjulian if ((trt->rt_ifp == ifp) && 16411820Sjulian !ipx_neteqnn(n->rip_dst, 16511820Sjulian satoipx_addr(ifp->int_addr).x_net)) 16611820Sjulian return; 16711820Sjulian trt = trt->rt_clone; 16811820Sjulian } 16911820Sjulian n++; 17011820Sjulian newsize += sizeof (struct netinfo); 17111820Sjulian } 17211820Sjulian } 17311820Sjulian if (newsize > 0) { 17411820Sjulian msg->rip_cmd = htons(RIPCMD_RESPONSE); 17511820Sjulian newsize += sizeof (u_short); 17611820Sjulian /* should check for if with dstaddr(from) first */ 17711820Sjulian (*afp->af_output)(ripsock, 0, from, newsize); 17811820Sjulian TRACE_OUTPUT(ifp, from, newsize); 17911820Sjulian if (ftrace) { 18011820Sjulian /* XXX This should not happen anymore. */ 18111820Sjulian if(ifp == 0) 18211820Sjulian fprintf(ftrace, "--- ifp = 0\n"); 18311820Sjulian else 18411820Sjulian fprintf(ftrace, 18511820Sjulian "request arrived on interface %s\n", 18611820Sjulian ifp->int_name); 18711820Sjulian } 18811820Sjulian } 18911820Sjulian return; 19011820Sjulian 19111820Sjulian case RIPCMD_RESPONSE: 19211820Sjulian /* verify message came from a router */ 19311820Sjulian if ((*afp->af_portmatch)(from) == 0) 19411820Sjulian return; 19511820Sjulian (*afp->af_canon)(from); 19611820Sjulian /* are we talking to ourselves? */ 19711820Sjulian if ((ifp = if_ifwithaddr(from)) != 0) { 19811820Sjulian rt = rtfind(from); 19927244Sjhay if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) { 20011820Sjulian addrouteforif(ifp); 20127244Sjhay rtchanged = 1; 20227244Sjhay } else 20311820Sjulian rt->rt_timer = 0; 20411820Sjulian return; 20511820Sjulian } 20611820Sjulian /* Update timer for interface on which the packet arrived. 20711820Sjulian * If from other end of a point-to-point link that isn't 20811820Sjulian * in the routing tables, (re-)add the route. 20911820Sjulian */ 21011820Sjulian if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) { 21111820Sjulian if(ftrace) fprintf(ftrace, "Got route\n"); 21211820Sjulian rt->rt_timer = 0; 21311820Sjulian } else if ((ifp = if_ifwithdstaddr(from)) != 0) { 21411820Sjulian if(ftrace) fprintf(ftrace, "Got partner\n"); 21511820Sjulian addrouteforif(ifp); 21627244Sjhay rtchanged = 1; 21711820Sjulian } 21811820Sjulian for (; size > 0; size -= sizeof (struct netinfo), n++) { 21911820Sjulian struct sockaddr *sa; 22011820Sjulian if (size < sizeof (struct netinfo)) 22111820Sjulian break; 22227244Sjhay if ((unsigned) ntohs(n->rip_metric) > HOPCNT_INFINITY) 22311820Sjulian continue; 22411820Sjulian rt = rtfind(sa = ipx_nettosa(n->rip_dst)); 22511820Sjulian if (rt == 0) { 22627244Sjhay if (ntohs(n->rip_metric) == HOPCNT_INFINITY) 22727244Sjhay continue; 22811820Sjulian rtadd(sa, from, ntohs(n->rip_metric), 22911820Sjulian ntohs(n->rip_ticks), 0); 23027244Sjhay rtchanged = 1; 23111820Sjulian continue; 23211820Sjulian } 23311820Sjulian 23411820Sjulian /* 23511820Sjulian * A clone is a different route to the same net 23611820Sjulian * with exactly the same cost (ticks and metric). 23711820Sjulian * They must all be recorded because those interfaces 23811820Sjulian * must be handled in the same way as the first route 23911820Sjulian * to that net. ie When using the split horizon 24011820Sjulian * algorithm we must look at these interfaces also. 24111820Sjulian * 24211820Sjulian * Update if from gateway and different, 24311820Sjulian * from anywhere and less ticks or 24411820Sjulian * if same ticks and shorter, 24511820Sjulian * or getting stale and equivalent. 24611820Sjulian */ 24711820Sjulian if (!equal(from, &rt->rt_router) && 24827244Sjhay ntohs(n->rip_ticks) == rt->rt_ticks && 24927244Sjhay ntohs(n->rip_metric) == rt->rt_metric && 25027244Sjhay ntohs(n->rip_metric) != HOPCNT_INFINITY) { 25111820Sjulian register struct rt_entry *trt = rt->rt_clone; 25211820Sjulian 25311820Sjulian while (trt) { 25411820Sjulian if (equal(from, &trt->rt_router)) { 25511820Sjulian trt->rt_timer = 0; 25611820Sjulian break; 25711820Sjulian } 25812620Sjulian trt = trt->rt_clone; 25911820Sjulian } 26011820Sjulian if (trt == NULL) { 26111820Sjulian rtadd_clone(rt, sa, from, 26211820Sjulian ntohs(n->rip_metric), 26311820Sjulian ntohs(n->rip_ticks), 0); 26411820Sjulian } 26511820Sjulian continue; 26611820Sjulian } 26711820Sjulian if ((equal(from, &rt->rt_router) && 26811820Sjulian ((ntohs(n->rip_ticks) != rt->rt_ticks) || 26911820Sjulian (ntohs(n->rip_metric) != rt->rt_metric))) || 27011820Sjulian (ntohs(n->rip_ticks) < rt->rt_ticks) || 27111820Sjulian ((ntohs(n->rip_ticks) == rt->rt_ticks) && 27211820Sjulian (ntohs(n->rip_metric) < rt->rt_metric)) || 27311820Sjulian (rt->rt_timer > (EXPIRE_TIME*2/3) && 27427244Sjhay rt->rt_metric == ntohs(n->rip_metric) && 27527244Sjhay ntohs(n->rip_metric) != HOPCNT_INFINITY)) { 27611820Sjulian rtchange(rt, from, ntohs(n->rip_metric), 27711820Sjulian ntohs(n->rip_ticks)); 27827244Sjhay if (ntohs(n->rip_metric) == HOPCNT_INFINITY) 27927244Sjhay rt->rt_timer = EXPIRE_TIME; 28027244Sjhay else 28127244Sjhay rt->rt_timer = 0; 28227244Sjhay rtchanged = 1; 28311820Sjulian } else if (equal(from, &rt->rt_router) && 28411820Sjulian (ntohs(n->rip_ticks) == rt->rt_ticks) && 28527244Sjhay (ntohs(n->rip_metric) == rt->rt_metric) && 28627244Sjhay (ntohs(n->rip_metric) != HOPCNT_INFINITY)) { 28711820Sjulian rt->rt_timer = 0; 28811820Sjulian } 28911820Sjulian } 29027244Sjhay if (rtchanged) { 29127244Sjhay register struct rthash *rh; 29227244Sjhay register struct rt_entry *rt; 29327244Sjhay 29427244Sjhay toall(supply, NULL, 1); 29527244Sjhay for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) 29627244Sjhay for (rt = rh->rt_forw; 29727244Sjhay rt != (struct rt_entry *)rh; 29827244Sjhay rt = rt->rt_forw) 29927244Sjhay rt->rt_state &= ~RTS_CHANGED; 30027244Sjhay } 30127244Sjhay 30211820Sjulian return; 30311820Sjulian } 30411820Sjulian} 305