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