output.c revision 50479
11603Smhaupt/*
21603Smhaupt * Copyright (c) 1985, 1993
31603Smhaupt *	The Regents of the University of California.  All rights reserved.
41603Smhaupt *
51603Smhaupt * Copyright (c) 1995 John Hay.  All rights reserved.
61603Smhaupt *
71603Smhaupt * This file includes significant work done at Cornell University by
81603Smhaupt * Bill Nesheim.  That work included by permission.
91603Smhaupt *
101603Smhaupt * Redistribution and use in source and binary forms, with or without
111603Smhaupt * modification, are permitted provided that the following conditions
121603Smhaupt * are met:
131603Smhaupt * 1. Redistributions of source code must retain the above copyright
141603Smhaupt *    notice, this list of conditions and the following disclaimer.
151603Smhaupt * 2. Redistributions in binary form must reproduce the above copyright
161603Smhaupt *    notice, this list of conditions and the following disclaimer in the
171603Smhaupt *    documentation and/or other materials provided with the distribution.
181603Smhaupt * 3. All advertising materials mentioning features or use of this software
191603Smhaupt *    must display the following acknowledgement:
201603Smhaupt *	This product includes software developed by the University of
211603Smhaupt *	California, Berkeley and its contributors.
221603Smhaupt * 4. Neither the name of the University nor the names of its contributors
231603Smhaupt *    may be used to endorse or promote products derived from this software
241603Smhaupt *    without specific prior written permission.
251603Smhaupt *
261603Smhaupt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271603Smhaupt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281603Smhaupt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291648Ssdama * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301648Ssdama * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311648Ssdama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321648Ssdama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331648Ssdama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341648Ssdama * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351648Ssdama * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361648Ssdama * SUCH DAMAGE.
371603Smhaupt *
381648Ssdama * $FreeBSD: head/usr.sbin/IPXrouted/output.c 50479 1999-08-28 01:35:59Z peter $
391648Ssdama */
401648Ssdama
411648Ssdama#ifndef lint
421648Ssdamastatic char sccsid[] = "@(#)output.c	8.1 (Berkeley) 6/5/93";
431648Ssdama#endif /* not lint */
441648Ssdama
451648Ssdama/*
461648Ssdama * Routing Table Management Daemon
471648Ssdama */
481648Ssdama#include <unistd.h>
491648Ssdama#include "defs.h"
501648Ssdama
511648Ssdama/*
521603Smhaupt * Apply the function "f" to all non-passive
531603Smhaupt * interfaces.  If the interface supports the
541603Smhaupt * use of broadcasting use it, otherwise address
551603Smhaupt * the output to the known router.
561603Smhaupt */
571603Smhauptvoid
581603Smhaupttoall(f, except, changesonly)
591603Smhaupt	void (*f)(struct sockaddr *, int, struct interface *, int);
601603Smhaupt	struct rt_entry *except;
611603Smhaupt	int changesonly;
621603Smhaupt{
631603Smhaupt	register struct interface *ifp;
641603Smhaupt	register struct sockaddr *dst;
651603Smhaupt	register int flags;
661603Smhaupt	register struct rt_entry *trt;
671603Smhaupt	int onlist;
681603Smhaupt	extern struct interface *ifnet;
691603Smhaupt
701603Smhaupt	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
711603Smhaupt		if (ifp->int_flags & IFF_PASSIVE)
721603Smhaupt			continue;
731603Smhaupt
741603Smhaupt		/*
751603Smhaupt		 * Don't send it on interfaces in the except list.
761603Smhaupt		 */
771603Smhaupt		onlist = 0;
781603Smhaupt		trt = except;
791648Ssdama		while(trt) {
801603Smhaupt			if (ifp == trt->rt_ifp) {
811603Smhaupt				onlist = 1;
821603Smhaupt				break;
831648Ssdama			}
841603Smhaupt			trt = trt->rt_clone;
851603Smhaupt		}
861603Smhaupt		if (onlist)
871603Smhaupt			continue;
881603Smhaupt
891603Smhaupt		dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
901603Smhaupt		      ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
911603Smhaupt		      &ifp->int_addr;
921603Smhaupt		flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
931603Smhaupt		(*f)(dst, flags, ifp, changesonly);
941603Smhaupt	}
951603Smhaupt}
961603Smhaupt
971603Smhaupt/*
981648Ssdama * Output a preformed packet.
991603Smhaupt */
1001603Smhauptvoid
1011603Smhauptsndmsg(dst, flags, ifp, changesonly)
1021603Smhaupt	struct sockaddr *dst;
1031648Ssdama	int flags;
1041603Smhaupt	struct interface *ifp;
1051603Smhaupt	int changesonly;
1061603Smhaupt{
1071603Smhaupt
1081603Smhaupt	(*afswitch[dst->sa_family].af_output)
1091603Smhaupt		(ripsock, flags, dst, sizeof (struct rip));
1101603Smhaupt	TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
1111603Smhaupt}
1121603Smhaupt
1131603Smhaupt/*
1141603Smhaupt * Supply dst with the contents of the routing tables.
1151603Smhaupt * If this won't fit in one packet, chop it up into several.
1161603Smhaupt *
1171603Smhaupt * This must be done using the split horizon algorithm.
1181603Smhaupt * 1. Don't send routing info to the interface from where it was received.
1191603Smhaupt * 2. Don't publish an interface to itself.
1201603Smhaupt * 3. If a route is received from more than one interface and the cost is
1211603Smhaupt *    the same, don't publish it on either interface. I am calling this
1221648Ssdama *    clones.
1231603Smhaupt */
1241603Smhauptvoid
1251603Smhauptsupply(dst, flags, ifp, changesonly)
1261603Smhaupt	struct sockaddr *dst;
1271603Smhaupt	int flags;
1281603Smhaupt	struct interface *ifp;
1291603Smhaupt	int changesonly;
1301603Smhaupt{
1311603Smhaupt	register struct rt_entry *rt;
1321603Smhaupt	register struct rt_entry *crt; /* Clone route */
1331603Smhaupt	register struct rthash *rh;
1341603Smhaupt	register struct netinfo *nn;
1351603Smhaupt	register struct netinfo *n = msg->rip_nets;
1361603Smhaupt	struct sockaddr_ipx *sipx =  (struct sockaddr_ipx *) dst;
1371603Smhaupt	af_output_t *output = afswitch[dst->sa_family].af_output;
1381603Smhaupt	int size, metric, ticks;
1391603Smhaupt	union ipx_net net;
1401603Smhaupt	int delay = 0;
1411603Smhaupt
1421603Smhaupt	if (sipx->sipx_port == 0)
1431603Smhaupt		sipx->sipx_port = htons(IPXPORT_RIP);
1441603Smhaupt
1451603Smhaupt	msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
1461603Smhaupt	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
1471603Smhaupt	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
1481603Smhaupt		size = (char *)n - (char *)msg;
1491603Smhaupt		if (size >= ((MAXRIPNETS * sizeof (struct netinfo)) +
1501603Smhaupt				sizeof (msg->rip_cmd))) {
1511603Smhaupt			(*output)(ripsock, flags, dst, size);
1521603Smhaupt			TRACE_OUTPUT(ifp, dst, size);
1531603Smhaupt			n = msg->rip_nets;
1541603Smhaupt			delay++;
1551603Smhaupt			if(delay == 2) {
1561603Smhaupt				usleep(50000);
1571603Smhaupt				delay = 0;
1581603Smhaupt			}
1591603Smhaupt		}
1601603Smhaupt
1611603Smhaupt		if (changesonly && !(rt->rt_state & RTS_CHANGED))
1621603Smhaupt			continue;
1631603Smhaupt
1641603Smhaupt		/*
1651603Smhaupt		 * This should do rule one and two of the split horizon
1661603Smhaupt		 * algorithm.
1671603Smhaupt		 */
1681603Smhaupt		if (rt->rt_ifp == ifp)
1691603Smhaupt			continue;
1701603Smhaupt
1711603Smhaupt		/*
1721648Ssdama		 * Rule 3.
1731648Ssdama		 * Look if we have clones (different routes to the same
1741603Smhaupt		 * place with exactly the same cost).
1751603Smhaupt		 *
1761603Smhaupt		 * We should not publish on any of the clone interfaces.
1771603Smhaupt		 */
1781603Smhaupt		crt = rt->rt_clone;
1791603Smhaupt		while (crt) {
1801603Smhaupt			if (crt->rt_ifp == ifp)
1811603Smhaupt				goto next;
1821603Smhaupt			crt = crt->rt_clone;
1831603Smhaupt		}
1841603Smhaupt
1851603Smhaupt		sipx = (struct sockaddr_ipx *)&rt->rt_dst;
1861603Smhaupt	        if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
1871648Ssdama			sipx = (struct sockaddr_ipx *)&rt->rt_router;
1881603Smhaupt		if (rt->rt_metric == HOPCNT_INFINITY)
1891603Smhaupt			metric = HOPCNT_INFINITY;
1901603Smhaupt		else {
1911603Smhaupt			metric = rt->rt_metric + 1;
1921603Smhaupt			/*
1931603Smhaupt			 * We don't advertize routes with more than 15 hops.
1941603Smhaupt			 */
1951603Smhaupt			if (metric >= HOPCNT_INFINITY)
1961603Smhaupt				continue;
1971603Smhaupt		}
1981603Smhaupt		/* XXX One day we should cater for slow interfaces also. */
1991603Smhaupt		ticks = rt->rt_ticks + 1;
2001603Smhaupt		net = sipx->sipx_addr.x_net;
2011648Ssdama
2021603Smhaupt		/*
2031603Smhaupt		 * Make sure that we don't put out a two net entries
204		 * for a pt to pt link (one for the G route, one for the if)
205		 * This is a kludge, and won't work if there are lots of nets.
206		 */
207		for (nn = msg->rip_nets; nn < n; nn++) {
208			if (ipx_neteqnn(net, nn->rip_dst)) {
209				if (ticks < ntohs(nn->rip_ticks)) {
210					nn->rip_metric = htons(metric);
211					nn->rip_ticks = htons(ticks);
212				} else if ((ticks == ntohs(nn->rip_ticks)) &&
213					   (metric < ntohs(nn->rip_metric))) {
214					nn->rip_metric = htons(metric);
215					nn->rip_ticks = htons(ticks);
216				}
217				goto next;
218			}
219		}
220		n->rip_dst = net;
221		n->rip_metric = htons(metric);
222		n->rip_ticks = htons(ticks);
223		n++;
224	next:;
225	}
226	if (n != msg->rip_nets) {
227		size = (char *)n - (char *)msg;
228		(*output)(ripsock, flags, dst, size);
229		TRACE_OUTPUT(ifp, dst, size);
230	}
231}
232