output.c revision 19948
1122940Speter/*
240003Skato * Copyright (c) 1985, 1993
324113Skato *	The Regents of the University of California.  All rights reserved.
424113Skato *
524113Skato * Copyright (c) 1995 John Hay.  All rights reserved.
624113Skato *
724113Skato * This file includes significant work done at Cornell University by
824113Skato * Bill Nesheim.  That work included by permission.
924113Skato *
1024113Skato * Redistribution and use in source and binary forms, with or without
1124113Skato * modification, are permitted provided that the following conditions
1224113Skato * are met:
1324113Skato * 1. Redistributions of source code must retain the above copyright
1424113Skato *    notice, this list of conditions and the following disclaimer.
1524113Skato * 2. Redistributions in binary form must reproduce the above copyright
1624113Skato *    notice, this list of conditions and the following disclaimer in the
1724113Skato *    documentation and/or other materials provided with the distribution.
1824113Skato * 3. All advertising materials mentioning features or use of this software
1924113Skato *    must display the following acknowledgement:
2024113Skato *	This product includes software developed by the University of
2124113Skato *	California, Berkeley and its contributors.
2224113Skato * 4. Neither the name of the University nor the names of its contributors
2324113Skato *    may be used to endorse or promote products derived from this software
2424113Skato *    without specific prior written permission.
2524113Skato *
2624113Skato * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2724113Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2824113Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2924113Skato * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30118031Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31118031Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32118031Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3324113Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3424113Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3524113Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3624113Skato * SUCH DAMAGE.
37243848Skib *
3824113Skato *	$Id: output.c,v 1.3 1996/04/13 15:13:20 jhay Exp $
3979609Speter */
4024113Skato
4124113Skato#ifndef lint
4224113Skatostatic char sccsid[] = "@(#)output.c	8.1 (Berkeley) 6/5/93";
4324113Skato#endif /* not lint */
4424113Skato
45130224Speter/*
46130224Speter * Routing Table Management Daemon
4740003Skato */
48109700Sjhb#include <unistd.h>
4979609Speter#include "defs.h"
50109700Sjhb
51199067Skuriyama/*
52199067Skuriyama * Apply the function "f" to all non-passive
53199067Skuriyama * interfaces.  If the interface supports the
54199067Skuriyama * use of broadcasting use it, otherwise address
55199067Skuriyama * the output to the known router.
56199067Skuriyama */
5779609Spetervoid
58114349Spetertoall(f, except)
59114349Speter	void (*f)(struct sockaddr *, int, struct interface *);
60130224Speter	struct rt_entry *except;
61151348Sjkim{
62151348Sjkim	register struct interface *ifp;
63184101Sjkim	register struct sockaddr *dst;
64187109Sjkim	register int flags;
65187109Sjkim	register struct rt_entry *trt;
66114349Speter	int onlist;
67130224Speter	extern struct interface *ifnet;
68114349Speter
69114349Speter	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
70151348Sjkim		if (ifp->int_flags & IFF_PASSIVE)
71114349Speter			continue;
72185341Sjkim
73109700Sjhb		/*
74159783Sdavidxu		 * Don't send it on interfaces in the except list.
75195820Skib		 */
76243139Skib		onlist = 0;
77231979Skib		trt = except;
7882261Speter		while(trt) {
79187109Sjkim			if (ifp == trt->rt_ifp) {
80220018Sjkim				onlist = 1;
81187109Sjkim				break;
82220018Sjkim			}
83187109Sjkim			trt = trt->rt_clone;
84233798Sjkim		}
85233798Sjkim		if (onlist)
86233798Sjkim			continue;
87233798Sjkim
88233798Sjkim		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
89233798Sjkim		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
90233798Sjkim		      &ifp->int_addr;
91233798Sjkim		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
92233798Sjkim		(*f)(dst, flags, ifp);
93233798Sjkim	}
94233798Sjkim}
95233798Sjkim
96239560Skib/*
97239560Skib * Output a preformed packet.
98239560Skib */
99239560Skibvoid
100239560Skibsndmsg(dst, flags, ifp)
101233798Sjkim	struct sockaddr *dst;
102233798Sjkim	int flags;
103233798Sjkim	struct interface *ifp;
104233798Sjkim{
105239560Skib
106239560Skib	(*afswitch[dst->sa_family].af_output)
107233798Sjkim		(ripsock, flags, dst, sizeof (struct rip));
108233798Sjkim	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
109233798Sjkim}
110233798Sjkim
11124113Skato/*
112220018Sjkim * Supply dst with the contents of the routing tables.
113187109Sjkim * If this won't fit in one packet, chop it up into several.
114187109Sjkim *
115187109Sjkim * This must be done using the split horizon algorithm.
116187109Sjkim * 1. Don't send routing info to the interface from where it was received.
117187109Sjkim * 2. Don't publish an interface to itself.
118187109Sjkim * 3. If a route is received from more than one interface and the cost is
119220018Sjkim *    the same, don't publish it on either interface. I am calling this
120220018Sjkim *    clones.
121220018Sjkim */
122220018Sjkimvoid
123220018Sjkimsupply(dst, flags, ifp)
124187109Sjkim	struct sockaddr *dst;
125220018Sjkim	int flags;
126187109Sjkim	struct interface *ifp;
127187109Sjkim{
128187109Sjkim	register struct rt_entry *rt;
129220018Sjkim	register struct rt_entry *crt; /* Clone route */
130187109Sjkim	register struct rthash *rh;
131220018Sjkim	register struct netinfo *nn;
132220018Sjkim	register struct netinfo *n = msg->rip_nets;
133187109Sjkim	struct rthash *base = hosthash;
134220018Sjkim	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
135187109Sjkim	af_output_t *output = afswitch[dst->sa_family].af_output;
136220018Sjkim	int doinghost = 1, size, metric, ticks;
137220018Sjkim	union ipx_net net;
138220018Sjkim	int delay = 0;
139187109Sjkim
140220018Sjkim	if (sipx->sipx_port == 0)
141187109Sjkim		sipx->sipx_port = htons(IPXPORT_RIP);
142220018Sjkim
143187109Sjkim	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
144220018Sjkimagain:
145187109Sjkim	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
146220018Sjkim	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
147220018Sjkim		size = (char *)n - (char *)msg;
148187109Sjkim		if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) +
149187109Sjkim				sizeof (msg->rip_cmd))) {
150187109Sjkim			(*output)(ripsock, flags, dst, size);
151130224Speter			TRACE_OUTPUT(ifp, dst, size);
15279609Speter			n = msg->rip_nets;
15379609Speter			delay++;
154130224Speter			if(delay == 2) {
15579609Speter				usleep(20000);
156130224Speter				delay = 0;
157243848Skib			}
158130224Speter		}
159243848Skib
16079609Speter		/*
161243848Skib		 * This should do rule one and two of the split horizon
16279609Speter		 * algorithm.
16379609Speter		 */
164243848Skib		if (rt->rt_ifp == ifp)
165243848Skib			continue;
166243848Skib
167243848Skib		/*
168243848Skib		 * Rule 3.
169243848Skib		 * Look if we have clones (different routes to the same
170243848Skib		 * place with exactly the same cost).
171243848Skib		 *
172243848Skib		 * We should not publish on any of the clone interfaces.
173243848Skib		 */
174243848Skib		crt = rt->rt_clone;
175243848Skib		while (crt) {
176130224Speter			if (crt->rt_ifp == ifp)
177130224Speter				goto next;
178130224Speter			crt = crt->rt_clone;
179130224Speter		}
18024113Skato
181233798Sjkim		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
182233798Sjkim	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
183233798Sjkim			sipx = (struct sockaddr_ipx *)&rt->rt_router;
184233798Sjkim		if (rt->rt_metric == HOPCNT_INFINITY)
185233798Sjkim			metric = HOPCNT_INFINITY;
186187109Sjkim		else {
187233798Sjkim			metric = rt->rt_metric + 1;
188233798Sjkim			/*
189199253Skib			 * We don't advertize routes with more than 15 hops.
190195820Skib			 */
191199253Skib			if (metric >= HOPCNT_INFINITY)
192199253Skib				continue;
193199253Skib		}
194199253Skib		/* XXX One day we should cater for slow interfaces also. */
195195820Skib		ticks = rt->rt_ticks + 1;
196195820Skib		net = sipx->sipx_addr.x_net;
197195820Skib
198195820Skib		/*
199195820Skib		 * Make sure that we don't put out a two net entries
200195820Skib		 * for a pt to pt link (one for the G route, one for the if)
201195820Skib		 * This is a kludge, and won't work if there are lots of nets.
202197663Skib		 */
203210774Sjhb		for (nn = msg->rip_nets; nn < n; nn++) {
204210774Sjhb			if (ipx_neteqnn(net, nn->rip_dst)) {
205210774Sjhb				if (ticks < ntohs(nn->rip_ticks)) {
206210774Sjhb					nn->rip_metric = htons(metric);
207197663Skib					nn->rip_ticks = htons(ticks);
208199067Skuriyama				} else if ((ticks == ntohs(nn->rip_ticks)) &&
209210774Sjhb					   (metric < ntohs(nn->rip_metric))) {
210197663Skib					nn->rip_metric = htons(metric);
211199067Skuriyama					nn->rip_ticks = htons(ticks);
212199067Skuriyama				}
213210774Sjhb				goto next;
214199067Skuriyama			}
215199215Skuriyama		}
216199067Skuriyama		n->rip_dst = net;
21724113Skato		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