output.c revision 22997
1/*
2 * Copyright (c) 1985, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Copyright (c) 1995 John Hay.  All rights reserved.
6 *
7 * This file includes significant work done at Cornell University by
8 * Bill Nesheim.  That work included by permission.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	$Id$
39 */
40
41#ifndef lint
42static char sccsid[] = "@(#)output.c	8.1 (Berkeley) 6/5/93";
43#endif /* not lint */
44
45/*
46 * Routing Table Management Daemon
47 */
48#include <unistd.h>
49#include "defs.h"
50
51/*
52 * Apply the function "f" to all non-passive
53 * interfaces.  If the interface supports the
54 * use of broadcasting use it, otherwise address
55 * the output to the known router.
56 */
57void
58toall(f, except)
59	void (*f)(struct sockaddr *, int, struct interface *);
60	struct rt_entry *except;
61{
62	register struct interface *ifp;
63	register struct sockaddr *dst;
64	register int flags;
65	register struct rt_entry *trt;
66	int onlist;
67	extern struct interface *ifnet;
68
69	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
70		if (ifp->int_flags & IFF_PASSIVE)
71			continue;
72
73		/*
74		 * Don't send it on interfaces in the except list.
75		 */
76		onlist = 0;
77		trt = except;
78		while(trt) {
79			if (ifp == trt->rt_ifp) {
80				onlist = 1;
81				break;
82			}
83			trt = trt->rt_clone;
84		}
85		if (onlist)
86			continue;
87
88		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
89		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
90		      &ifp->int_addr;
91		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
92		(*f)(dst, flags, ifp);
93	}
94}
95
96/*
97 * Output a preformed packet.
98 */
99void
100sndmsg(dst, flags, ifp)
101	struct sockaddr *dst;
102	int flags;
103	struct interface *ifp;
104{
105
106	(*afswitch[dst->sa_family].af_output)
107		(ripsock, flags, dst, sizeof (struct rip));
108	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
109}
110
111/*
112 * Supply dst with the contents of the routing tables.
113 * If this won't fit in one packet, chop it up into several.
114 *
115 * This must be done using the split horizon algorithm.
116 * 1. Don't send routing info to the interface from where it was received.
117 * 2. Don't publish an interface to itself.
118 * 3. If a route is received from more than one interface and the cost is
119 *    the same, don't publish it on either interface. I am calling this
120 *    clones.
121 */
122void
123supply(dst, flags, ifp)
124	struct sockaddr *dst;
125	int flags;
126	struct interface *ifp;
127{
128	register struct rt_entry *rt;
129	register struct rt_entry *crt; /* Clone route */
130	register struct rthash *rh;
131	register struct netinfo *nn;
132	register struct netinfo *n = msg->rip_nets;
133	struct rthash *base = hosthash;
134	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
135	af_output_t *output = afswitch[dst->sa_family].af_output;
136	int doinghost = 1, size, metric, ticks;
137	union ipx_net net;
138	int delay = 0;
139
140	if (sipx->sipx_port == 0)
141		sipx->sipx_port = htons(IPXPORT_RIP);
142
143	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
144again:
145	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
146	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
147		size = (char *)n - (char *)msg;
148		if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) +
149				sizeof (msg->rip_cmd))) {
150			(*output)(ripsock, flags, dst, size);
151			TRACE_OUTPUT(ifp, dst, size);
152			n = msg->rip_nets;
153			delay++;
154			if(delay == 2) {
155				usleep(20000);
156				delay = 0;
157			}
158		}
159
160		/*
161		 * This should do rule one and two of the split horizon
162		 * algorithm.
163		 */
164		if (rt->rt_ifp == ifp)
165			continue;
166
167		/*
168		 * Rule 3.
169		 * Look if we have clones (different routes to the same
170		 * place with exactly the same cost).
171		 *
172		 * We should not publish on any of the clone interfaces.
173		 */
174		crt = rt->rt_clone;
175		while (crt) {
176			if (crt->rt_ifp == ifp)
177				goto next;
178			crt = crt->rt_clone;
179		}
180
181		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
182	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
183			sipx = (struct sockaddr_ipx *)&rt->rt_router;
184		if (rt->rt_metric == HOPCNT_INFINITY)
185			metric = HOPCNT_INFINITY;
186		else {
187			metric = rt->rt_metric + 1;
188			/*
189			 * We don't advertize routes with more than 15 hops.
190			 */
191			if (metric >= HOPCNT_INFINITY)
192				continue;
193		}
194		/* XXX One day we should cater for slow interfaces also. */
195		ticks = rt->rt_ticks + 1;
196		net = sipx->sipx_addr.x_net;
197
198		/*
199		 * Make sure that we don't put out a two net entries
200		 * for a pt to pt link (one for the G route, one for the if)
201		 * This is a kludge, and won't work if there are lots of nets.
202		 */
203		for (nn = msg->rip_nets; nn < n; nn++) {
204			if (ipx_neteqnn(net, nn->rip_dst)) {
205				if (ticks < ntohs(nn->rip_ticks)) {
206					nn->rip_metric = htons(metric);
207					nn->rip_ticks = htons(ticks);
208				} else if ((ticks == ntohs(nn->rip_ticks)) &&
209					   (metric < ntohs(nn->rip_metric))) {
210					nn->rip_metric = htons(metric);
211					nn->rip_ticks = htons(ticks);
212				}
213				goto next;
214			}
215		}
216		n->rip_dst = net;
217		n->rip_metric = htons(metric);
218		n->rip_ticks = htons(ticks);
219		n++;
220	next:;
221	}
222	if (doinghost) {
223		doinghost = 0;
224		base = nethash;
225		goto again;
226	}
227	if (n != msg->rip_nets) {
228		size = (char *)n - (char *)msg;
229		(*output)(ripsock, flags, dst, size);
230		TRACE_OUTPUT(ifp, dst, size);
231	}
232}
233