tables.c revision 189369
111820Sjulian/*
211820Sjulian * Copyright (c) 1985, 1993
311820Sjulian *	The Regents of the University of California.  All rights reserved.
411820Sjulian *
511820Sjulian * Copyright (c) 1995 John Hay.  All rights reserved.
611820Sjulian *
711820Sjulian * Redistribution and use in source and binary forms, with or without
811820Sjulian * modification, are permitted provided that the following conditions
911820Sjulian * are met:
1011820Sjulian * 1. Redistributions of source code must retain the above copyright
1111820Sjulian *    notice, this list of conditions and the following disclaimer.
1211820Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1311820Sjulian *    notice, this list of conditions and the following disclaimer in the
1411820Sjulian *    documentation and/or other materials provided with the distribution.
1511820Sjulian * 3. All advertising materials mentioning features or use of this software
1611820Sjulian *    must display the following acknowledgement:
1711820Sjulian *	This product includes software developed by the University of
1811820Sjulian *	California, Berkeley and its contributors.
1911820Sjulian * 4. Neither the name of the University nor the names of its contributors
2011820Sjulian *    may be used to endorse or promote products derived from this software
2111820Sjulian *    without specific prior written permission.
2211820Sjulian *
2311820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2411820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2511820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2611820Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2711820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2811820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2911820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3011820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3111820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3211820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3311820Sjulian * SUCH DAMAGE.
3411820Sjulian *
3550479Speter * $FreeBSD: head/usr.sbin/IPXrouted/tables.c 189369 2009-03-04 18:36:48Z ed $
3611820Sjulian */
3711820Sjulian
3811820Sjulian#ifndef lint
39122760Strhodesstatic const char sccsid[] = "@(#)tables.c	8.1 (Berkeley) 6/5/93";
4011820Sjulian#endif /* not lint */
4111820Sjulian
4211820Sjulian/*
4311820Sjulian * Routing Table Management Daemon
4411820Sjulian */
4511820Sjulian#include "defs.h"
4611820Sjulian#include <sys/ioctl.h>
4711820Sjulian#include <errno.h>
48122760Strhodes#include <search.h>
4911820Sjulian#include <stdlib.h>
5011820Sjulian#include <unistd.h>
5111820Sjulian
5211820Sjulian#ifndef DEBUG
5311820Sjulian#define	DEBUG	0
5411820Sjulian#endif
5511820Sjulian
5611820Sjulian#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
5711820Sjulian
5811820Sjulianint	install = !DEBUG;		/* if 1 call kernel */
5911820Sjulianint	delete = 1;
6015248Sjhay
6115248Sjhaystruct  rthash nethash[ROUTEHASHSIZ];
6215248Sjhay
6311820Sjulian/*
6411820Sjulian * Lookup dst in the tables for an exact match.
6511820Sjulian */
6611820Sjulianstruct rt_entry *
67189369Sedrtlookup(struct sockaddr *dst)
6811820Sjulian{
6911820Sjulian	register struct rt_entry *rt;
7011820Sjulian	register struct rthash *rh;
7111820Sjulian	register u_int hash;
7211820Sjulian	struct afhash h;
7311820Sjulian
7411820Sjulian	if (dst->sa_family >= AF_MAX)
7511820Sjulian		return (0);
7611820Sjulian	(*afswitch[dst->sa_family].af_hash)(dst, &h);
7727244Sjhay	hash = h.afh_nethash;
7827244Sjhay	rh = &nethash[hash & ROUTEHASHMASK];
7911820Sjulian	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
8011820Sjulian		if (rt->rt_hash != hash)
8111820Sjulian			continue;
8211820Sjulian		if (equal(&rt->rt_dst, dst))
8311820Sjulian			return (rt);
8411820Sjulian	}
8511820Sjulian	return (0);
8611820Sjulian}
8711820Sjulian
8811820Sjulian/*
8911820Sjulian * Find a route to dst as the kernel would.
9011820Sjulian */
9111820Sjulianstruct rt_entry *
92189369Sedrtfind(struct sockaddr *dst)
9311820Sjulian{
9411820Sjulian	register struct rt_entry *rt;
9511820Sjulian	register struct rthash *rh;
9611820Sjulian	register u_int hash;
9711820Sjulian	struct afhash h;
9811820Sjulian	int af = dst->sa_family;
9927244Sjhay	int (*match)() = 0;
10011820Sjulian
10111820Sjulian	if (af >= AF_MAX)
10211820Sjulian		return (0);
10311820Sjulian	(*afswitch[af].af_hash)(dst, &h);
10411820Sjulian
10527244Sjhay	hash = h.afh_nethash;
10627244Sjhay	rh = &nethash[hash & ROUTEHASHMASK];
10727244Sjhay	match = afswitch[af].af_netmatch;
10811820Sjulian	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
10911820Sjulian		if (rt->rt_hash != hash)
11011820Sjulian			continue;
11127244Sjhay		if (rt->rt_dst.sa_family == af &&
11227244Sjhay		    (*match)(&rt->rt_dst, dst))
11327244Sjhay			return (rt);
11411820Sjulian	}
11511820Sjulian	return (0);
11611820Sjulian}
11711820Sjulian
11811820Sjulianvoid
119189369Sedrtadd(struct sockaddr *dst, struct sockaddr *gate, short metric,
120189369Sed    short ticks, int state)
12111820Sjulian{
12211820Sjulian	struct afhash h;
12311820Sjulian	register struct rt_entry *rt;
12411820Sjulian	struct rthash *rh;
12511820Sjulian	int af = dst->sa_family, flags;
12611820Sjulian	u_int hash;
12711820Sjulian
12811820Sjulian	FIXLEN(dst);
12911820Sjulian	FIXLEN(gate);
13011820Sjulian	if (af >= AF_MAX)
13111820Sjulian		return;
13211820Sjulian	(*afswitch[af].af_hash)(dst, &h);
13311820Sjulian	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
13427244Sjhay	hash = h.afh_nethash;
13527244Sjhay	rh = &nethash[hash & ROUTEHASHMASK];
13611820Sjulian	rt = (struct rt_entry *)malloc(sizeof (*rt));
13711820Sjulian	if (rt == 0)
13811820Sjulian		return;
13911820Sjulian	rt->rt_hash = hash;
14011820Sjulian	rt->rt_dst = *dst;
14111820Sjulian	rt->rt_router = *gate;
14211820Sjulian	rt->rt_metric = metric;
14311820Sjulian	rt->rt_ticks = ticks;
14411820Sjulian	rt->rt_timer = 0;
14511820Sjulian	rt->rt_flags = RTF_UP | flags;
14611820Sjulian	rt->rt_state = state | RTS_CHANGED;
14711820Sjulian	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
14811820Sjulian	rt->rt_clone = NULL;
14911820Sjulian	if (metric)
15011820Sjulian		rt->rt_flags |= RTF_GATEWAY;
15111820Sjulian	insque(rt, rh);
15227244Sjhay	TRACE_ACTION("ADD", rt);
15311820Sjulian	/*
15411820Sjulian	 * If the ioctl fails because the gateway is unreachable
15511820Sjulian	 * from this host, discard the entry.  This should only
15611820Sjulian	 * occur because of an incorrect entry in /etc/gateways.
15711820Sjulian	 */
15811820Sjulian	if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
15911820Sjulian		if (errno != EEXIST)
16011820Sjulian			perror("SIOCADDRT");
16111820Sjulian		if (errno == ENETUNREACH) {
16227244Sjhay			TRACE_ACTION("DELETE", rt);
16311820Sjulian			remque(rt);
16411820Sjulian			free((char *)rt);
16511820Sjulian		}
16611820Sjulian	}
16711820Sjulian}
16811820Sjulian
16911820Sjulianvoid
170189369Sedrtadd_clone(struct rt_entry *ort, struct sockaddr *dst,
171189369Sed    struct sockaddr *gate, short metric, short ticks, int state)
17211820Sjulian{
17311820Sjulian	struct afhash h;
17411820Sjulian	register struct rt_entry *rt;
17511820Sjulian	struct rthash *rh;
17611820Sjulian	int af = dst->sa_family, flags;
17711820Sjulian	u_int hash;
17811820Sjulian
17911820Sjulian	FIXLEN(dst);
18011820Sjulian	FIXLEN(gate);
18111820Sjulian	if (af >= AF_MAX)
18211820Sjulian		return;
18311820Sjulian	(*afswitch[af].af_hash)(dst, &h);
18411820Sjulian	flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
18527244Sjhay	hash = h.afh_nethash;
18627244Sjhay	rh = &nethash[hash & ROUTEHASHMASK];
18711820Sjulian	rt = (struct rt_entry *)malloc(sizeof (*rt));
18811820Sjulian	if (rt == 0)
18911820Sjulian		return;
19011820Sjulian	rt->rt_hash = hash;
19111820Sjulian	rt->rt_dst = *dst;
19211820Sjulian	rt->rt_router = *gate;
19311820Sjulian	rt->rt_metric = metric;
19411820Sjulian	rt->rt_ticks = ticks;
19511820Sjulian	rt->rt_timer = 0;
19611820Sjulian	rt->rt_flags = RTF_UP | flags;
19711820Sjulian	rt->rt_state = state | RTS_CHANGED;
19811820Sjulian	rt->rt_ifp = if_ifwithnet(&rt->rt_router);
19911820Sjulian	rt->rt_clone = NULL;
20011820Sjulian	rt->rt_forw = NULL;
20111820Sjulian	rt->rt_back = NULL;
20211820Sjulian	if (metric)
20311820Sjulian		rt->rt_flags |= RTF_GATEWAY;
20411820Sjulian
20511820Sjulian	while(ort->rt_clone != NULL)
20611820Sjulian		ort = ort->rt_clone;
20711820Sjulian	ort->rt_clone = rt;
20827244Sjhay	TRACE_ACTION("ADD_CLONE", rt);
20911820Sjulian}
21011820Sjulian
21111820Sjulianvoid
212189369Sedrtchange(struct rt_entry *rt, struct sockaddr *gate, short metric,
213189369Sed    short ticks)
21411820Sjulian{
21511820Sjulian	int doioctl = 0, metricchanged = 0;
21611820Sjulian	struct rtuentry oldroute;
21711820Sjulian
21811820Sjulian	FIXLEN(gate);
21911820Sjulian	/*
22011820Sjulian 	 * Handling of clones.
22111820Sjulian 	 * When the route changed and it had clones, handle it special.
22211820Sjulian 	 * 1. If the new route is cheaper than the clone(s), free the clones.
22311820Sjulian	 * 2. If the new route is the same cost, it may be one of the clones,
22411820Sjulian	 *    search for it and free it.
22511820Sjulian 	 * 3. If the new route is more expensive than the clone(s), use the
22611820Sjulian 	 *    values of the clone(s).
22711820Sjulian 	 */
22811820Sjulian	if (rt->rt_clone) {
22911820Sjulian		if ((ticks < rt->rt_clone->rt_ticks) ||
23011820Sjulian		    ((ticks == rt->rt_clone->rt_ticks) &&
23111820Sjulian		     (metric < rt->rt_clone->rt_metric))) {
23211820Sjulian			/*
23311820Sjulian			 * Free all clones.
23411820Sjulian			 */
23511820Sjulian			struct rt_entry *trt, *nrt;
23611820Sjulian
23711820Sjulian			trt = rt->rt_clone;
23811820Sjulian			rt->rt_clone = NULL;
23911820Sjulian			while(trt) {
24011820Sjulian				nrt = trt->rt_clone;
24111820Sjulian				free((char *)trt);
24211820Sjulian				trt = nrt;
24311820Sjulian			}
24411820Sjulian		} else if ((ticks == rt->rt_clone->rt_ticks) &&
24511820Sjulian		     (metric == rt->rt_clone->rt_metric)) {
24611820Sjulian			struct rt_entry *prt, *trt;
24711820Sjulian
24811820Sjulian			prt = rt;
24911820Sjulian			trt = rt->rt_clone;
25011820Sjulian
25111820Sjulian			while(trt) {
25211820Sjulian				if (equal(&trt->rt_router, gate)) {
25311820Sjulian					prt->rt_clone = trt->rt_clone;
25411820Sjulian					free(trt);
25511820Sjulian					trt = prt->rt_clone;
25611820Sjulian				} else {
25711820Sjulian					prt = trt;
25811820Sjulian					trt = trt->rt_clone;
25911820Sjulian				}
26011820Sjulian			}
26111820Sjulian		} else {
26211820Sjulian			/*
26311820Sjulian			 * Use the values of the first clone.
26411820Sjulian			 * Delete the corresponding clone.
26511820Sjulian			 */
26611820Sjulian			struct rt_entry *trt;
26711820Sjulian
26811820Sjulian			trt = rt->rt_clone;
26911820Sjulian			rt->rt_clone = rt->rt_clone->rt_clone;
27011820Sjulian			metric = trt->rt_metric;
27111820Sjulian			ticks = trt->rt_ticks;
27211820Sjulian			*gate = trt->rt_router;
27311820Sjulian			free((char *)trt);
27411820Sjulian		}
27511820Sjulian	}
27611820Sjulian
27711820Sjulian	if (!equal(&rt->rt_router, gate))
27811820Sjulian		doioctl++;
27911820Sjulian	if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
28011820Sjulian		metricchanged++;
28111820Sjulian	if (doioctl || metricchanged) {
28227244Sjhay		TRACE_ACTION("CHANGE FROM", rt);
28311820Sjulian		if (doioctl) {
28411820Sjulian			oldroute = rt->rt_rt;
28511820Sjulian			rt->rt_router = *gate;
28611820Sjulian		}
28711820Sjulian		rt->rt_metric = metric;
28811820Sjulian		rt->rt_ticks = ticks;
28911820Sjulian		if ((rt->rt_state & RTS_INTERFACE) && metric) {
29011820Sjulian			rt->rt_state &= ~RTS_INTERFACE;
29111820Sjulian			if(rt->rt_ifp)
29211820Sjulian				syslog(LOG_ERR,
29311820Sjulian				"changing route from interface %s (timed out)",
29411820Sjulian				rt->rt_ifp->int_name);
29511820Sjulian			else
29611820Sjulian				syslog(LOG_ERR,
29711820Sjulian				"changing route from interface ??? (timed out)");
29811820Sjulian		}
29911820Sjulian		if (metric)
30011820Sjulian			rt->rt_flags |= RTF_GATEWAY;
30111820Sjulian		else
30211820Sjulian			rt->rt_flags &= ~RTF_GATEWAY;
30327244Sjhay		rt->rt_ifp = if_ifwithnet(&rt->rt_router);
30411820Sjulian		rt->rt_state |= RTS_CHANGED;
30527244Sjhay		TRACE_ACTION("CHANGE TO", rt);
30611820Sjulian	}
30711820Sjulian	if (doioctl && install) {
30811820Sjulian#ifndef RTM_ADD
30911820Sjulian		if (rtioctl(ADD, &rt->rt_rt) < 0)
31011820Sjulian		  syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
31127244Sjhay		   ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
31227244Sjhay		   ipx_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
31311820Sjulian		if (delete && rtioctl(DELETE, &oldroute) < 0)
31411820Sjulian			perror("rtioctl DELETE");
31511820Sjulian#else
31611820Sjulian		if (delete == 0) {
31711820Sjulian			if (rtioctl(ADD, &rt->rt_rt) >= 0)
31811820Sjulian				return;
31911820Sjulian		} else {
32011820Sjulian			if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
32111820Sjulian				return;
32211820Sjulian		}
32311820Sjulian	        syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
32411820Sjulian		   ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
32511820Sjulian		   ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
32611820Sjulian#endif
32711820Sjulian	}
32811820Sjulian}
32911820Sjulian
33011820Sjulianvoid
331189369Sedrtdelete(struct rt_entry *rt)
33211820Sjulian{
33311820Sjulian
33411820Sjulian	struct sockaddr *sa = &(rt->rt_router);
33511820Sjulian	FIXLEN(sa);
33611820Sjulian	sa = &(rt->rt_dst);
33711820Sjulian	FIXLEN(sa);
33811820Sjulian	if (rt->rt_clone) {
33911820Sjulian		/*
34011820Sjulian		 * If there is a clone we just do a rt_change to it.
34111820Sjulian		 */
34211820Sjulian		struct rt_entry *trt = rt->rt_clone;
34311820Sjulian		rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
34411820Sjulian		return;
34511820Sjulian	}
34611820Sjulian	if (rt->rt_state & RTS_INTERFACE) {
34711820Sjulian		if (rt->rt_ifp)
34811820Sjulian			syslog(LOG_ERR,
34911820Sjulian				"deleting route to interface %s (timed out)",
35011820Sjulian				rt->rt_ifp->int_name);
35111820Sjulian		else
35211820Sjulian			syslog(LOG_ERR,
35311820Sjulian				"deleting route to interface ??? (timed out)");
35411820Sjulian	}
35527244Sjhay	TRACE_ACTION("DELETE", rt);
35611820Sjulian	if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
35711820Sjulian		perror("rtioctl DELETE");
35811820Sjulian	remque(rt);
35911820Sjulian	free((char *)rt);
36011820Sjulian}
36111820Sjulian
36211820Sjulianvoid
36311820Sjulianrtinit(void)
36411820Sjulian{
36511820Sjulian	register struct rthash *rh;
36611820Sjulian
36711820Sjulian	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
36811820Sjulian		rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
36911820Sjulian}
37011820Sjulianint seqno;
37111820Sjulian
37211820Sjulianint
373189369Sedrtioctl(int action, struct rtuentry *ort)
37411820Sjulian{
37511820Sjulian#ifndef RTM_ADD
37611820Sjulian	if (install == 0)
37711820Sjulian		return (errno = 0);
37811820Sjulian
37911820Sjulian	ort->rtu_rtflags = ort->rtu_flags;
38011820Sjulian
38111820Sjulian	switch (action) {
38211820Sjulian
38311820Sjulian	case ADD:
38411820Sjulian		return (ioctl(s, SIOCADDRT, (char *)ort));
38511820Sjulian
38611820Sjulian	case DELETE:
38711820Sjulian		return (ioctl(s, SIOCDELRT, (char *)ort));
38811820Sjulian
38911820Sjulian	default:
39011820Sjulian		return (-1);
39111820Sjulian	}
39211820Sjulian#else /* RTM_ADD */
39311820Sjulian	struct {
39411820Sjulian		struct rt_msghdr w_rtm;
39511820Sjulian		struct sockaddr w_dst;
39611820Sjulian		struct sockaddr w_gate;
39711820Sjulian		struct sockaddr_ipx w_netmask;
39811820Sjulian	} w;
39911820Sjulian#define rtm w.w_rtm
40011820Sjulian
40111820Sjulian	bzero((char *)&w, sizeof(w));
40211820Sjulian	rtm.rtm_msglen = sizeof(w);
40311820Sjulian	rtm.rtm_version = RTM_VERSION;
40411820Sjulian	rtm.rtm_type = (action == ADD ? RTM_ADD :
40511820Sjulian				(action == DELETE ? RTM_DELETE : RTM_CHANGE));
40611820Sjulian	rtm.rtm_flags = ort->rtu_flags;
40711820Sjulian	rtm.rtm_seq = ++seqno;
40811820Sjulian	rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
40911820Sjulian	bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
41011820Sjulian	bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
41111820Sjulian	w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
41211820Sjulian	w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
41311820Sjulian	if (rtm.rtm_flags & RTF_HOST) {
41411820Sjulian		rtm.rtm_msglen -= sizeof(w.w_netmask);
41511820Sjulian	} else {
41611820Sjulian		rtm.rtm_addrs |= RTA_NETMASK;
41711820Sjulian		w.w_netmask = ipx_netmask;
41811820Sjulian		rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
41911820Sjulian	}
42011820Sjulian	errno = 0;
42111820Sjulian	return write(r, (char *)&w, rtm.rtm_msglen);
42211820Sjulian#endif  /* RTM_ADD */
42311820Sjulian}
424