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