output.c revision 15248
1132216Snjl/*
2131767Simp * Copyright (c) 1985, 1993
3131767Simp *	The Regents of the University of California.  All rights reserved.
4131767Simp *
5131767Simp * Copyright (c) 1995 John Hay.  All rights reserved.
6131767Simp *
7131767Simp * This file includes significant work done at Cornell University by
8131767Simp * Bill Nesheim.  That work included by permission.
9140040Simp *
10131767Simp * Redistribution and use in source and binary forms, with or without
11140040Simp * modification, are permitted provided that the following conditions
12140040Simp * are met:
13131767Simp * 1. Redistributions of source code must retain the above copyright
14131767Simp *    notice, this list of conditions and the following disclaimer.
15131767Simp * 2. Redistributions in binary form must reproduce the above copyright
16131767Simp *    notice, this list of conditions and the following disclaimer in the
17140040Simp *    documentation and/or other materials provided with the distribution.
18140040Simp * 3. All advertising materials mentioning features or use of this software
19131767Simp *    must display the following acknowledgement:
20131767Simp *	This product includes software developed by the University of
21131767Simp *	California, Berkeley and its contributors.
22131767Simp * 4. Neither the name of the University nor the names of its contributors
23131767Simp *    may be used to endorse or promote products derived from this software
24131767Simp *    without specific prior written permission.
25131767Simp *
26131767Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27131767Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28131767Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29131767Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30131767Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31131767Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32131767Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33131767Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34134081Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35131767Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36134081Sphk * SUCH DAMAGE.
37131767Simp *
38131767Simp *	$Id: output.c,v 1.2 1995/12/05 04:59:54 julian Exp $
39131767Simp */
40132080Simp
41132080Simp#ifndef lint
42131767Simpstatic char sccsid[] = "@(#)output.c	8.1 (Berkeley) 6/5/93";
43131767Simp#endif /* not lint */
44131767Simp
45131767Simp/*
46131767Simp * Routing Table Management Daemon
47131767Simp */
48131767Simp#include "defs.h"
49131767Simp
50131767Simp/*
51131767Simp * Apply the function "f" to all non-passive
52131767Simp * interfaces.  If the interface supports the
53131767Simp * use of broadcasting use it, otherwise address
54131767Simp * the output to the known router.
55132216Snjl */
56132137Simpvoid
57132137Simptoall(f, except)
58135212Simp	void (*f)(struct sockaddr *, int, struct interface *);
59132137Simp	struct rt_entry *except;
60132139Simp{
61132137Simp	register struct interface *ifp;
62132137Simp	register struct sockaddr *dst;
63132137Simp	register int flags;
64132137Simp	register struct rt_entry *trt;
65132137Simp	int onlist;
66132137Simp	extern struct interface *ifnet;
67132137Simp
68132137Simp	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
69135212Simp		if (ifp->int_flags & IFF_PASSIVE)
70135212Simp			continue;
71135212Simp
72135212Simp		/*
73135212Simp		 * Don't send it on interfaces in the except list.
74132137Simp		 */
75135212Simp		onlist = 0;
76135212Simp		trt = except;
77135212Simp		while(trt) {
78135212Simp			if (ifp == trt->rt_ifp) {
79135212Simp				onlist = 1;
80135212Simp				break;
81135212Simp			}
82135504Simp			trt = trt->rt_clone;
83136138Simp		}
84135212Simp		if (onlist)
85135212Simp			continue;
86132137Simp
87132137Simp		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
88132137Simp		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
89135212Simp		      &ifp->int_addr;
90135212Simp		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
91135212Simp		(*f)(dst, flags, ifp);
92132137Simp	}
93135504Simp}
94132137Simp
95132137Simp/*
96132137Simp * Output a preformed packet.
97135212Simp */
98135212Simpvoid
99135212Simpsndmsg(dst, flags, ifp)
100132137Simp	struct sockaddr *dst;
101136138Simp	int flags;
102135504Simp	struct interface *ifp;
103135504Simp{
104135504Simp
105135504Simp	(*afswitch[dst->sa_family].af_output)
106135504Simp		(ripsock, flags, dst, sizeof (struct rip));
107135504Simp	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
108132137Simp}
109132137Simp
110132137Simp/*
111132137Simp * Supply dst with the contents of the routing tables.
112135504Simp * If this won't fit in one packet, chop it up into several.
113132137Simp *
114135212Simp * This must be done using the split horizon algorithm.
115132137Simp * 1. Don't send routing info to the interface from where it was received.
116132137Simp * 2. Don't publish an interface to itself.
117136138Simp * 3. If a route is received from more than one interface and the cost is
118132137Simp *    the same, don't publish it on either interface. I am calling this
119136138Simp *    clones.
120135504Simp */
121135212Simpvoid
122135212Simpsupply(dst, flags, ifp)
123135212Simp	struct sockaddr *dst;
124135212Simp	int flags;
125135212Simp	struct interface *ifp;
126135212Simp{
127135212Simp	register struct rt_entry *rt;
128135212Simp	register struct rt_entry *crt; /* Clone route */
129135212Simp	register struct rthash *rh;
130135212Simp	register struct netinfo *nn;
131135212Simp	register struct netinfo *n = msg->rip_nets;
132135212Simp	struct rthash *base = hosthash;
133135212Simp	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
134135212Simp	af_output_t *output = afswitch[dst->sa_family].af_output;
135135212Simp	int doinghost = 1, size, metric, ticks;
136132137Simp	union ipx_net net;
137132137Simp
138132137Simp	if (sipx->sipx_port == 0)
139135212Simp		sipx->sipx_port = htons(IPXPORT_RIP);
140135212Simp
141135212Simp	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
142132137Simpagain:
143135504Simp	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
144132137Simp	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
145132137Simp		size = (char *)n - (char *)msg;
146135212Simp		if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) +
147135212Simp				sizeof (msg->rip_cmd))) {
148135212Simp			(*output)(ripsock, flags, dst, size);
149135212Simp			TRACE_OUTPUT(ifp, dst, size);
150135212Simp			n = msg->rip_nets;
151135212Simp		}
152135212Simp
153135212Simp		/*
154135212Simp		 * This should do rule one and two of the split horizon
155132137Simp		 * algorithm.
156132137Simp		 */
157132137Simp		if (rt->rt_ifp == ifp)
158135212Simp			continue;
159132137Simp
160132137Simp		/*
161135212Simp		 * Rule 3.
162132137Simp		 * Look if we have clones (different routes to the same
163132137Simp		 * place with exactly the same cost).
164132137Simp		 *
165132137Simp		 * We should not publish on any of the clone interfaces.
166132137Simp		 */
167132137Simp		crt = rt->rt_clone;
168132137Simp		while (crt) {
169135212Simp			if (crt->rt_ifp == ifp)
170132137Simp				goto next;
171132137Simp			crt = crt->rt_clone;
172132137Simp		}
173132137Simp
174132137Simp		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
175135212Simp	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
176132137Simp			sipx = (struct sockaddr_ipx *)&rt->rt_router;
177132137Simp		if (rt->rt_metric == HOPCNT_INFINITY)
178132137Simp			metric = HOPCNT_INFINITY;
179131767Simp		else {
180131767Simp			metric = rt->rt_metric + 1;
181134081Sphk			/*
182131767Simp			 * We don't advertize routes with more than 15 hops.
183131767Simp			 */
184131767Simp			if (metric >= HOPCNT_INFINITY)
185131767Simp				continue;
186131767Simp		}
187131767Simp		/* XXX One day we should cater for slow interfaces also. */
188131767Simp		ticks = rt->rt_ticks + 1;
189131767Simp		net = sipx->sipx_addr.x_net;
190132137Simp
191131767Simp		/*
192131767Simp		 * Make sure that we don't put out a two net entries
193132137Simp		 * for a pt to pt link (one for the G route, one for the if)
194134081Sphk		 * This is a kludge, and won't work if there are lots of nets.
195134081Sphk		 */
196131767Simp		for (nn = msg->rip_nets; nn < n; nn++) {
197131767Simp			if (ipx_neteqnn(net, nn->rip_dst)) {
198131767Simp				if (ticks < ntohs(nn->rip_ticks)) {
199131767Simp					nn->rip_metric = htons(metric);
200131767Simp					nn->rip_ticks = htons(ticks);
201132137Simp				} else if ((ticks == ntohs(nn->rip_ticks)) &&
202132137Simp					   (metric < ntohs(nn->rip_metric))) {
203132137Simp					nn->rip_metric = htons(metric);
204132137Simp					nn->rip_ticks = htons(ticks);
205132137Simp				}
206132137Simp				goto next;
207132137Simp			}
208134580Simp		}
209134081Sphk		n->rip_dst = net;
210134081Sphk		n->rip_metric = htons(metric);
211134081Sphk		n->rip_ticks = htons(ticks);
212134081Sphk		n++;
213132216Snjl	next:;
214132216Snjl	}
215132216Snjl	if (doinghost) {
216132137Simp		doinghost = 0;
217132137Simp		base = nethash;
218131767Simp		goto again;
219131767Simp	}
220131767Simp	if (n != msg->rip_nets) {
221132137Simp		size = (char *)n - (char *)msg;
222131767Simp		(*output)(ripsock, flags, dst, size);
223131767Simp		TRACE_OUTPUT(ifp, dst, size);
224131767Simp	}
225131767Simp}
226131767Simp