output.c revision 11820
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: output.c,v 1.6 1995/10/11 18:57:22 jhay Exp $
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 "defs.h"
49
50/*
51 * Apply the function "f" to all non-passive
52 * interfaces.  If the interface supports the
53 * use of broadcasting use it, otherwise address
54 * the output to the known router.
55 */
56void
57toall(f, except)
58	void (*f)(struct sockaddr *, int, struct interface *);
59	struct rt_entry *except;
60{
61	register struct interface *ifp;
62	register struct sockaddr *dst;
63	register int flags;
64	register struct rt_entry *trt;
65	int onlist;
66	extern struct interface *ifnet;
67
68	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
69		if (ifp->int_flags & IFF_PASSIVE)
70			continue;
71
72		/*
73		 * Don't send it on interfaces in the except list.
74		 */
75		onlist = 0;
76		trt = except;
77		while(trt) {
78			if (ifp == trt->rt_ifp) {
79				onlist = 1;
80				break;
81			}
82			trt = trt->rt_clone;
83		}
84		if (onlist)
85			continue;
86
87		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
88		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
89		      &ifp->int_addr;
90		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
91		(*f)(dst, flags, ifp);
92	}
93}
94
95/*
96 * Output a preformed packet.
97 */
98void
99sndmsg(dst, flags, ifp)
100	struct sockaddr *dst;
101	int flags;
102	struct interface *ifp;
103{
104
105	(*afswitch[dst->sa_family].af_output)
106		(ripsock, flags, dst, sizeof (struct rip));
107	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
108}
109
110/*
111 * Supply dst with the contents of the routing tables.
112 * If this won't fit in one packet, chop it up into several.
113 *
114 * This must be done using the split horizon algorithm.
115 * 1. Don't send routing info to the interface from where it was received.
116 * 2. Don't publish an interface to itself.
117 * 3. If a route is received from more than one interface and the cost is
118 *    the same, don't publish it on either interface. I am calling this
119 *    clones.
120 */
121void
122supply(dst, flags, ifp)
123	struct sockaddr *dst;
124	int flags;
125	struct interface *ifp;
126{
127	register struct rt_entry *rt;
128	register struct rt_entry *crt; /* Clone route */
129	register struct rthash *rh;
130	register struct netinfo *nn;
131	register struct netinfo *n = msg->rip_nets;
132	struct rthash *base = hosthash;
133	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
134	af_output_t *output = afswitch[dst->sa_family].af_output;
135	int doinghost = 1, size, metric, ticks;
136	union ipx_net net;
137
138	if (sipx->sipx_port == 0)
139		sipx->sipx_port = htons(IPXPORT_RIP);
140
141	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
142again:
143	for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
144	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
145		size = (char *)n - (char *)msg;
146		if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
147			(*output)(ripsock, flags, dst, size);
148			TRACE_OUTPUT(ifp, dst, size);
149			n = msg->rip_nets;
150		}
151
152		/*
153		 * This should do rule one and two of the split horizon
154		 * algorithm.
155		 */
156		if (rt->rt_ifp == ifp)
157			continue;
158
159		/*
160		 * Rule 3.
161		 * Look if we have clones (different routes to the same
162		 * place with exactly the same cost).
163		 *
164		 * We should not publish on any of the clone interfaces.
165		 */
166		crt = rt->rt_clone;
167		while (crt) {
168			if (crt->rt_ifp == ifp)
169				continue;
170			crt = crt->rt_clone;
171		}
172
173		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
174	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
175			sipx = (struct sockaddr_ipx *)&rt->rt_router;
176		if (rt->rt_metric == HOPCNT_INFINITY)
177			metric = HOPCNT_INFINITY;
178		else {
179			metric = rt->rt_metric + 1;
180			/*
181			 * We don't advertize routes with more than 15 hops.
182			 */
183			if (metric >= HOPCNT_INFINITY)
184				continue;
185		}
186		/* XXX One day we should cater for slow interfaces also. */
187		ticks = rt->rt_ticks + 1;
188		net = sipx->sipx_addr.x_net;
189
190		/*
191		 * Make sure that we don't put out a two net entries
192		 * for a pt to pt link (one for the G route, one for the if)
193		 * This is a kludge, and won't work if there are lots of nets.
194		 */
195		for (nn = msg->rip_nets; nn < n; nn++) {
196			if (ipx_neteqnn(net, nn->rip_dst)) {
197				if (ticks < ntohs(nn->rip_ticks)) {
198					nn->rip_metric = htons(metric);
199					nn->rip_ticks = htons(ticks);
200				} else if ((ticks == ntohs(nn->rip_ticks)) &&
201					   (metric < ntohs(nn->rip_metric))) {
202					nn->rip_metric = htons(metric);
203					nn->rip_ticks = htons(ticks);
204				}
205				goto next;
206			}
207		}
208		n->rip_dst = net;
209		n->rip_metric = htons(metric);
210		n->rip_ticks = htons(ticks);
211		n++;
212	next:;
213	}
214	if (doinghost) {
215		doinghost = 0;
216		base = nethash;
217		goto again;
218	}
219	if (n != msg->rip_nets) {
220		size = (char *)n - (char *)msg;
221		(*output)(ripsock, flags, dst, size);
222		TRACE_OUTPUT(ifp, dst, size);
223	}
224}
225