output.c revision 122760
1155192Srwatson/*
2155192Srwatson * Copyright (c) 1985, 1993
3155192Srwatson *	The Regents of the University of California.  All rights reserved.
4155192Srwatson *
5155192Srwatson * Copyright (c) 1995 John Hay.  All rights reserved.
6155192Srwatson *
7155192Srwatson * This file includes significant work done at Cornell University by
8155192Srwatson * Bill Nesheim.  That work included by permission.
9155192Srwatson *
10155192Srwatson * Redistribution and use in source and binary forms, with or without
11155192Srwatson * modification, are permitted provided that the following conditions
12155192Srwatson * are met:
13155192Srwatson * 1. Redistributions of source code must retain the above copyright
14155192Srwatson *    notice, this list of conditions and the following disclaimer.
15155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright
16155192Srwatson *    notice, this list of conditions and the following disclaimer in the
17155192Srwatson *    documentation and/or other materials provided with the distribution.
18155192Srwatson * 3. All advertising materials mentioning features or use of this software
19155192Srwatson *    must display the following acknowledgement:
20155192Srwatson *	This product includes software developed by the University of
21155192Srwatson *	California, Berkeley and its contributors.
22155192Srwatson * 4. Neither the name of the University nor the names of its contributors
23155192Srwatson *    may be used to endorse or promote products derived from this software
24155192Srwatson *    without specific prior written permission.
25155192Srwatson *
26155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29155192Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36155192Srwatson * SUCH DAMAGE.
37155192Srwatson *
38159259Srwatson * $FreeBSD: head/usr.sbin/IPXrouted/output.c 122760 2003-11-15 17:10:56Z trhodes $
39155192Srwatson */
40155192Srwatson
41155192Srwatson#ifndef lint
42155192Srwatsonstatic const char sccsid[] = "@(#)output.c	8.1 (Berkeley) 6/5/93";
43155192Srwatson#endif /* not lint */
44155192Srwatson
45155192Srwatson/*
46155192Srwatson * Routing Table Management Daemon
47155192Srwatson */
48155192Srwatson#include <unistd.h>
49155192Srwatson#include "defs.h"
50155192Srwatson
51155192Srwatson/*
52155192Srwatson * Apply the function "f" to all non-passive
53155192Srwatson * interfaces.  If the interface supports the
54155192Srwatson * use of broadcasting use it, otherwise address
55155192Srwatson * the output to the known router.
56155192Srwatson */
57155192Srwatsonvoid
58155192Srwatsontoall(f, except, changesonly)
59155192Srwatson	void (*f)(struct sockaddr *, int, struct interface *, int);
60155192Srwatson	struct rt_entry *except;
61155192Srwatson	int changesonly;
62155192Srwatson{
63155192Srwatson	register struct interface *ifp;
64155192Srwatson	register struct sockaddr *dst;
65155192Srwatson	register int flags;
66155192Srwatson	register struct rt_entry *trt;
67155192Srwatson	int onlist;
68155192Srwatson	extern struct interface *ifnet;
69155192Srwatson
70155192Srwatson	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
71155192Srwatson		if (ifp->int_flags & IFF_PASSIVE)
72155192Srwatson			continue;
73155192Srwatson
74155192Srwatson		/*
75155192Srwatson		 * Don't send it on interfaces in the except list.
76155192Srwatson		 */
77155192Srwatson		onlist = 0;
78155192Srwatson		trt = except;
79155192Srwatson		while(trt) {
80155192Srwatson			if (ifp == trt->rt_ifp) {
81155192Srwatson				onlist = 1;
82155192Srwatson				break;
83155192Srwatson			}
84155192Srwatson			trt = trt->rt_clone;
85155192Srwatson		}
86155192Srwatson		if (onlist)
87155192Srwatson			continue;
88155192Srwatson
89155192Srwatson		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
90155192Srwatson		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
91155192Srwatson		      &ifp->int_addr;
92155192Srwatson		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
93155192Srwatson		(*f)(dst, flags, ifp, changesonly);
94155192Srwatson	}
95155192Srwatson}
96155192Srwatson
97155192Srwatson/*
98155192Srwatson * Output a preformed packet.
99155192Srwatson */
100155192Srwatsonvoid
101155192Srwatsonsndmsg(dst, flags, ifp, changesonly)
102155192Srwatson	struct sockaddr *dst;
103155192Srwatson	int flags;
104155192Srwatson	struct interface *ifp;
105155192Srwatson	int changesonly;
106155192Srwatson{
107155192Srwatson
108155192Srwatson	(*afswitch[dst->sa_family].af_output)
109155192Srwatson		(ripsock, flags, dst, sizeof (struct rip));
110155192Srwatson	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
111155192Srwatson}
112155192Srwatson
113155192Srwatson/*
114155192Srwatson * Supply dst with the contents of the routing tables.
115155192Srwatson * If this won't fit in one packet, chop it up into several.
116155192Srwatson *
117155192Srwatson * This must be done using the split horizon algorithm.
118155192Srwatson * 1. Don't send routing info to the interface from where it was received.
119155192Srwatson * 2. Don't publish an interface to itself.
120155192Srwatson * 3. If a route is received from more than one interface and the cost is
121155192Srwatson *    the same, don't publish it on either interface. I am calling this
122155192Srwatson *    clones.
123155192Srwatson */
124155192Srwatsonvoid
125155192Srwatsonsupply(dst, flags, ifp, changesonly)
126155192Srwatson	struct sockaddr *dst;
127155192Srwatson	int flags;
128155192Srwatson	struct interface *ifp;
129155192Srwatson	int changesonly;
130155192Srwatson{
131155192Srwatson	register struct rt_entry *rt;
132155192Srwatson	register struct rt_entry *crt; /* Clone route */
133155192Srwatson	register struct rthash *rh;
134155192Srwatson	register struct netinfo *nn;
135155192Srwatson	register struct netinfo *n = msg->rip_nets;
136155192Srwatson	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
137155192Srwatson	af_output_t *output = afswitch[dst->sa_family].af_output;
138155192Srwatson	int size, metric, ticks;
139155192Srwatson	union ipx_net net;
140155192Srwatson	int delay = 0;
141155192Srwatson
142155192Srwatson	if (sipx->sipx_port == 0)
143155192Srwatson		sipx->sipx_port = htons(IPXPORT_RIP);
144155192Srwatson
145155192Srwatson	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
146155192Srwatson	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
147155192Srwatson	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
148155192Srwatson		size = (char *)n - (char *)msg;
149155192Srwatson		if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) +
150155192Srwatson				sizeof (msg->rip_cmd))) {
151155192Srwatson			(*output)(ripsock, flags, dst, size);
152155192Srwatson			TRACE_OUTPUT(ifp, dst, size);
153155192Srwatson			n = msg->rip_nets;
154155192Srwatson			delay++;
155155192Srwatson			if(delay == 2) {
156155192Srwatson				usleep(50000);
157155192Srwatson				delay = 0;
158155192Srwatson			}
159155192Srwatson		}
160155192Srwatson
161155192Srwatson		if (changesonly && !(rt->rt_state & RTS_CHANGED))
162155192Srwatson			continue;
163155192Srwatson
164155192Srwatson		/*
165155192Srwatson		 * This should do rule one and two of the split horizon
166155192Srwatson		 * algorithm.
167155192Srwatson		 */
168155192Srwatson		if (rt->rt_ifp == ifp)
169155192Srwatson			continue;
170155192Srwatson
171155192Srwatson		/*
172155192Srwatson		 * Rule 3.
173155192Srwatson		 * Look if we have clones (different routes to the same
174155192Srwatson		 * place with exactly the same cost).
175155192Srwatson		 *
176155192Srwatson		 * We should not publish on any of the clone interfaces.
177155192Srwatson		 */
178155192Srwatson		crt = rt->rt_clone;
179155192Srwatson		while (crt) {
180155192Srwatson			if (crt->rt_ifp == ifp)
181168783Srwatson				goto next;
182168783Srwatson			crt = crt->rt_clone;
183168783Srwatson		}
184168783Srwatson
185155192Srwatson		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
186168783Srwatson	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
187168783Srwatson			sipx = (struct sockaddr_ipx *)&rt->rt_router;
188168783Srwatson		if (rt->rt_metric == HOPCNT_INFINITY)
189168783Srwatson			metric = HOPCNT_INFINITY;
190168783Srwatson		else {
191168783Srwatson			metric = rt->rt_metric + 1;
192168783Srwatson			/*
193168783Srwatson			 * We don't advertize routes with more than 15 hops.
194168783Srwatson			 */
195168783Srwatson			if (metric >= HOPCNT_INFINITY)
196168783Srwatson				continue;
197168783Srwatson		}
198168783Srwatson		/* XXX One day we should cater for slow interfaces also. */
199168783Srwatson		ticks = rt->rt_ticks + 1;
200168783Srwatson		net = sipx->sipx_addr.x_net;
201168783Srwatson
202168783Srwatson		/*
203168783Srwatson		 * Make sure that we don't put out a two net entries
204168783Srwatson		 * for a pt to pt link (one for the G route, one for the if)
205168783Srwatson		 * This is a kludge, and won't work if there are lots of nets.
206168783Srwatson		 */
207168783Srwatson		for (nn = msg->rip_nets; nn < n; nn++) {
208168783Srwatson			if (ipx_neteqnn(net, nn->rip_dst)) {
209168783Srwatson				if (ticks < ntohs(nn->rip_ticks)) {
210168783Srwatson					nn->rip_metric = htons(metric);
211168783Srwatson					nn->rip_ticks = htons(ticks);
212168783Srwatson				} else if ((ticks == ntohs(nn->rip_ticks)) &&
213168783Srwatson					   (metric < ntohs(nn->rip_metric))) {
214168783Srwatson					nn->rip_metric = htons(metric);
215168783Srwatson					nn->rip_ticks = htons(ticks);
216168783Srwatson				}
217168783Srwatson				goto next;
218168783Srwatson			}
219155192Srwatson		}
220155192Srwatson		n->rip_dst = net;
221155192Srwatson		n->rip_metric = htons(metric);
222155192Srwatson		n->rip_ticks = htons(ticks);
223155192Srwatson		n++;
224155192Srwatson	next:;
225155192Srwatson	}
226155192Srwatson	if (n != msg->rip_nets) {
227155192Srwatson		size = (char *)n - (char *)msg;
228155192Srwatson		(*output)(ripsock, flags, dst, size);
229155192Srwatson		TRACE_OUTPUT(ifp, dst, size);
230155192Srwatson	}
231155192Srwatson}
232155192Srwatson