input.c revision 11820
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 *
3811820Sjulian *	$Id: input.c,v 1.9 1995/10/11 18:57:17 jhay Exp $
3911820Sjulian */
4011820Sjulian
4111820Sjulian#ifndef lint
4211820Sjulianstatic 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	extern char ether_broadcast_addr[6];
5611820Sjulian
5711820Sjulian	bzero(&sxn, sizeof (struct sockaddr_ipx));
5811820Sjulian	sxn.sipx_family = AF_IPX;
5911820Sjulian	sxn.sipx_len = sizeof (sxn);
6011820Sjulian	sxn.sipx_addr.x_net = net;
6111820Sjulian	sxn.sipx_addr.x_host = *(union ipx_host *)ether_broadcast_addr;
6211820Sjulian	return( (struct sockaddr *)&sxn);
6311820Sjulian
6411820Sjulian}
6511820Sjulian
6611820Sjulian/*
6711820Sjulian * Process a newly received packet.
6811820Sjulian */
6911820Sjulianvoid
7011820Sjulianrip_input(from, size)
7111820Sjulian	struct sockaddr *from;
7211820Sjulian	int size;
7311820Sjulian{
7411820Sjulian	struct rt_entry *rt;
7511820Sjulian	struct netinfo *n;
7611820Sjulian	struct interface *ifp = 0;
7711820Sjulian	int newsize;
7811820Sjulian	struct afswitch *afp;
7911820Sjulian	struct sockaddr_ipx *ipxp;
8011820Sjulian
8111820Sjulian	ifp = if_ifwithnet(from);
8211820Sjulian	ipxp = (struct sockaddr_ipx *)from;
8311820Sjulian	if (ifp == 0) {
8411820Sjulian		if(ftrace) {
8511820Sjulian			fprintf(ftrace, "Received bogus packet from %s\n",
8611820Sjulian				ipxdp_ntoa(&ipxp->sipx_addr));
8711820Sjulian		}
8811820Sjulian		return;
8911820Sjulian	}
9011820Sjulian
9111820Sjulian	TRACE_INPUT(ifp, from, size);
9211820Sjulian	if (from->sa_family >= AF_MAX)
9311820Sjulian		return;
9411820Sjulian	afp = &afswitch[from->sa_family];
9511820Sjulian
9611820Sjulian	size -= sizeof (u_short)	/* command */;
9711820Sjulian	n = msg->rip_nets;
9811820Sjulian
9911820Sjulian	switch (ntohs(msg->rip_cmd)) {
10011820Sjulian
10111820Sjulian	case RIPCMD_REQUEST:
10211820Sjulian		if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr))
10311820Sjulian			return;
10411820Sjulian		newsize = 0;
10511820Sjulian		while (size > 0) {
10611820Sjulian			if (size < sizeof (struct netinfo))
10711820Sjulian				break;
10811820Sjulian			size -= sizeof (struct netinfo);
10911820Sjulian
11011820Sjulian			/*
11111820Sjulian			 * A single entry with rip_dst == DSTNETS_ALL and
11211820Sjulian			 * metric ``infinity'' means ``all routes''.
11311820Sjulian			 *
11411820Sjulian			 * XXX According to the IPX RIP spec the metric
11511820Sjulian			 * and tick fields can be anything. So maybe we
11611820Sjulian			 * should not check the metric???
11711820Sjulian			 */
11811820Sjulian			if (ipx_neteqnn(n->rip_dst, ipx_anynet) &&
11911820Sjulian		            ntohs(n->rip_metric) == HOPCNT_INFINITY &&
12011820Sjulian			    size == 0) {
12111820Sjulian				supply(from, 0, ifp);
12211820Sjulian				return;
12311820Sjulian			}
12411820Sjulian			/*
12511820Sjulian			 * request for specific nets
12611820Sjulian			 */
12711820Sjulian			rt = rtlookup(ipx_nettosa(n->rip_dst));
12811820Sjulian			if (ftrace) {
12911820Sjulian				fprintf(ftrace,
13011820Sjulian					"specific request for %s",
13111820Sjulian					ipxdp_nettoa(n->rip_dst));
13211820Sjulian				fprintf(ftrace,
13311820Sjulian					" yields route %x\n",
13411820Sjulian					(u_int)rt);
13511820Sjulian			}
13611820Sjulian			/*
13711820Sjulian			 * XXX We break out on the first net that isn't
13811820Sjulian			 * found. The specs is a bit vague here. I'm not
13911820Sjulian			 * sure what we should do.
14011820Sjulian			 */
14111820Sjulian			if (rt == 0)
14211820Sjulian				return;
14311820Sjulian			/* XXX
14411820Sjulian			 * According to the spec we should not include
14511820Sjulian			 * information about networks for which the number
14611820Sjulian			 * of hops is 16.
14711820Sjulian			 */
14811820Sjulian			if (rt->rt_metric == (HOPCNT_INFINITY-1))
14911820Sjulian				return;
15011820Sjulian			n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY :
15111820Sjulian				min(rt->rt_metric+1, HOPCNT_INFINITY));
15211820Sjulian			n->rip_ticks = htons(rt->rt_ticks+1);
15311820Sjulian
15411820Sjulian			/*
15511820Sjulian			 * We use split horizon with a twist. If the requested
15611820Sjulian			 * net is the directly connected net we supply an
15711820Sjulian			 * answer. This is so that the host can learn about
15811820Sjulian			 * the routers on its net.
15911820Sjulian			 */
16011820Sjulian			{
16111820Sjulian				register struct rt_entry *trt = rt;
16211820Sjulian
16311820Sjulian				while (trt) {
16411820Sjulian					if ((trt->rt_ifp == ifp) &&
16511820Sjulian					    !ipx_neteqnn(n->rip_dst,
16611820Sjulian						satoipx_addr(ifp->int_addr).x_net))
16711820Sjulian						return;
16811820Sjulian					trt = trt->rt_clone;
16911820Sjulian				}
17011820Sjulian				n++;
17111820Sjulian		        	newsize += sizeof (struct netinfo);
17211820Sjulian			}
17311820Sjulian		}
17411820Sjulian		if (newsize > 0) {
17511820Sjulian			msg->rip_cmd = htons(RIPCMD_RESPONSE);
17611820Sjulian			newsize += sizeof (u_short);
17711820Sjulian			/* should check for if with dstaddr(from) first */
17811820Sjulian			(*afp->af_output)(ripsock, 0, from, newsize);
17911820Sjulian			TRACE_OUTPUT(ifp, from, newsize);
18011820Sjulian			if (ftrace) {
18111820Sjulian				/* XXX This should not happen anymore. */
18211820Sjulian				if(ifp == 0)
18311820Sjulian					fprintf(ftrace, "--- ifp = 0\n");
18411820Sjulian				else
18511820Sjulian					fprintf(ftrace,
18611820Sjulian						"request arrived on interface %s\n",
18711820Sjulian						ifp->int_name);
18811820Sjulian			}
18911820Sjulian		}
19011820Sjulian		return;
19111820Sjulian
19211820Sjulian	case RIPCMD_RESPONSE:
19311820Sjulian		/* verify message came from a router */
19411820Sjulian		if ((*afp->af_portmatch)(from) == 0)
19511820Sjulian			return;
19611820Sjulian		(*afp->af_canon)(from);
19711820Sjulian		/* are we talking to ourselves? */
19811820Sjulian		if ((ifp = if_ifwithaddr(from)) != 0) {
19911820Sjulian			rt = rtfind(from);
20011820Sjulian			if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0)
20111820Sjulian				addrouteforif(ifp);
20211820Sjulian			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);
21611820Sjulian		}
21711820Sjulian		for (; size > 0; size -= sizeof (struct netinfo), n++) {
21811820Sjulian			struct sockaddr *sa;
21911820Sjulian			if (size < sizeof (struct netinfo))
22011820Sjulian				break;
22111820Sjulian			if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY)
22211820Sjulian				continue;
22311820Sjulian			rt = rtfind(sa = ipx_nettosa(n->rip_dst));
22411820Sjulian			if (rt == 0) {
22511820Sjulian				rtadd(sa, from, ntohs(n->rip_metric),
22611820Sjulian					ntohs(n->rip_ticks), 0);
22711820Sjulian				continue;
22811820Sjulian			}
22911820Sjulian
23011820Sjulian			/*
23111820Sjulian			 * A clone is a different route to the same net
23211820Sjulian			 * with exactly the same cost (ticks and metric).
23311820Sjulian			 * They must all be recorded because those interfaces
23411820Sjulian			 * must be handled in the same way as the first route
23511820Sjulian			 * to that net. ie When using the split horizon
23611820Sjulian			 * algorithm we must look at these interfaces also.
23711820Sjulian			 *
23811820Sjulian			 * Update if from gateway and different,
23911820Sjulian			 * from anywhere and less ticks or
24011820Sjulian			 * if same ticks and shorter,
24111820Sjulian			 * or getting stale and equivalent.
24211820Sjulian			 *
24311820Sjulian			 * XXX I don't think this is quite right.
24411820Sjulian			 */
24511820Sjulian			if (!equal(from, &rt->rt_router) &&
24611820Sjulian			    ntohs(n->rip_ticks == rt->rt_ticks) &&
24711820Sjulian			    ntohs(n->rip_metric == rt->rt_metric)) {
24811820Sjulian				register struct rt_entry *trt = rt->rt_clone;
24911820Sjulian
25011820Sjulian				while (trt) {
25111820Sjulian					if (equal(from, &trt->rt_router)) {
25211820Sjulian						trt->rt_timer = 0;
25311820Sjulian						break;
25411820Sjulian					}
25511820Sjulian				}
25611820Sjulian				if (trt == NULL) {
25711820Sjulian					rtadd_clone(rt, sa, from,
25811820Sjulian						    ntohs(n->rip_metric),
25911820Sjulian						    ntohs(n->rip_ticks), 0);
26011820Sjulian				}
26111820Sjulian				continue;
26211820Sjulian			}
26311820Sjulian			if ((equal(from, &rt->rt_router) &&
26411820Sjulian			    ((ntohs(n->rip_ticks) != rt->rt_ticks) ||
26511820Sjulian			    (ntohs(n->rip_metric) != rt->rt_metric))) ||
26611820Sjulian			    (ntohs(n->rip_ticks) < rt->rt_ticks) ||
26711820Sjulian			    ((ntohs(n->rip_ticks) == rt->rt_ticks) &&
26811820Sjulian			    (ntohs(n->rip_metric) < rt->rt_metric)) ||
26911820Sjulian			    (rt->rt_timer > (EXPIRE_TIME*2/3) &&
27011820Sjulian			    rt->rt_metric == ntohs(n->rip_metric))) {
27111820Sjulian				rtchange(rt, from, ntohs(n->rip_metric),
27211820Sjulian					ntohs(n->rip_ticks));
27311820Sjulian				rt->rt_timer = 0;
27411820Sjulian			} else if (equal(from, &rt->rt_router) &&
27511820Sjulian				   (ntohs(n->rip_ticks) == rt->rt_ticks) &&
27611820Sjulian				   (ntohs(n->rip_metric) == rt->rt_metric)) {
27711820Sjulian				rt->rt_timer = 0;
27811820Sjulian			}
27911820Sjulian		}
28011820Sjulian		return;
28111820Sjulian	}
28211820Sjulian}
283