xref: /csrg-svn/sys/net/route.c (revision 68437)
123163Smckusick /*
263268Sbostic  * Copyright (c) 1980, 1986, 1991, 1993
363268Sbostic  *	The Regents of the University of California.  All rights reserved.
423163Smckusick  *
544465Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*68437Ssklower  *	@(#)route.c	8.3.1.1 (Berkeley) 02/23/95
823163Smckusick  */
963267Ssklower 
1056529Sbostic #include <sys/param.h>
1156529Sbostic #include <sys/systm.h>
1256529Sbostic #include <sys/proc.h>
1356529Sbostic #include <sys/mbuf.h>
1456529Sbostic #include <sys/socket.h>
1556529Sbostic #include <sys/socketvar.h>
1656529Sbostic #include <sys/domain.h>
1756529Sbostic #include <sys/protosw.h>
1856529Sbostic #include <sys/ioctl.h>
1910890Ssam 
2056529Sbostic #include <net/if.h>
2156529Sbostic #include <net/route.h>
2256529Sbostic #include <net/raw_cb.h>
2348452Skarels 
2456529Sbostic #include <netinet/in.h>
2556529Sbostic #include <netinet/in_var.h>
2636209Skarels 
2749139Swilliam #ifdef NS
2856529Sbostic #include <netns/ns.h>
2949139Swilliam #endif
3048452Skarels 
3143073Ssklower #define	SA(p) ((struct sockaddr *)(p))
3236355Skarels 
337156Swnj int	rttrash;		/* routes not in table but not freed */
3412832Ssam struct	sockaddr wildcard;	/* zero valued cookie for wildcard searches */
3512832Ssam 
3661351Sbostic void
rtable_init(table)3754824Ssklower rtable_init(table)
3861351Sbostic 	void **table;
3954824Ssklower {
4054824Ssklower 	struct domain *dom;
4154824Ssklower 	for (dom = domains; dom; dom = dom->dom_next)
4254824Ssklower 		if (dom->dom_rtattach)
4354824Ssklower 			dom->dom_rtattach(&table[dom->dom_family],
4461351Sbostic 			    dom->dom_rtoffset);
4554824Ssklower }
4648452Skarels 
4761351Sbostic void
route_init()4854824Ssklower route_init()
4936209Skarels {
5054824Ssklower 	rn_init();	/* initialize all zeroes, all ones, mask table */
5154824Ssklower 	rtable_init((void **)rt_tables);
5236209Skarels }
5336209Skarels 
546331Ssam /*
556331Ssam  * Packet routing routines.
566331Ssam  */
5761351Sbostic void
rtalloc(ro)586368Ssam rtalloc(ro)
596331Ssam 	register struct route *ro;
606331Ssam {
6136355Skarels 	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
6236355Skarels 		return;				 /* XXX */
6336355Skarels 	ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
6436355Skarels }
6536355Skarels 
6636355Skarels struct rtentry *
rtalloc1(dst,report)6736355Skarels rtalloc1(dst, report)
6843073Ssklower 	register struct sockaddr *dst;
6961351Sbostic 	int report;
7036355Skarels {
7150691Ssklower 	register struct radix_node_head *rnh = rt_tables[dst->sa_family];
7243073Ssklower 	register struct rtentry *rt;
7336209Skarels 	register struct radix_node *rn;
7443073Ssklower 	struct rtentry *newrt = 0;
7552565Ssklower 	struct rt_addrinfo info;
7646461Ssklower 	int  s = splnet(), err = 0, msgtype = RTM_MISS;
776331Ssam 
7859007Ssklower 	if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
7936209Skarels 	    ((rn->rn_flags & RNF_ROOT) == 0)) {
8043073Ssklower 		newrt = rt = (struct rtentry *)rn;
8140785Ssklower 		if (report && (rt->rt_flags & RTF_CLONING)) {
8268168Scgd 			err = rtrequest(RTM_RESOLVE, dst, SA(0),
8368168Scgd 					      SA(0), 0, &newrt);
8455901Ssklower 			if (err) {
8555901Ssklower 				newrt = rt;
8655901Ssklower 				rt->rt_refcnt++;
8755901Ssklower 				goto miss;
8855901Ssklower 			}
8968168Scgd 			if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
9055901Ssklower 				msgtype = RTM_RESOLVE;
9155901Ssklower 				goto miss;
9255901Ssklower 			}
9340785Ssklower 		} else
9440785Ssklower 			rt->rt_refcnt++;
9536355Skarels 	} else {
9636209Skarels 		rtstat.rts_unreach++;
9752565Ssklower 	miss:	if (report) {
9868168Scgd 			bzero((caddr_t)&info, sizeof(info));
9968168Scgd 			info.rti_info[RTAX_DST] = dst;
10052565Ssklower 			rt_missmsg(msgtype, &info, 0, err);
10152565Ssklower 		}
10236355Skarels 	}
10317167Skarels 	splx(s);
10443073Ssklower 	return (newrt);
1056331Ssam }
1066331Ssam 
10761351Sbostic void
rtfree(rt)1086368Ssam rtfree(rt)
1096351Ssam 	register struct rtentry *rt;
1106351Ssam {
11140785Ssklower 	register struct ifaddr *ifa;
11255901Ssklower 
1136351Ssam 	if (rt == 0)
1148636Sroot 		panic("rtfree");
1156351Ssam 	rt->rt_refcnt--;
11640785Ssklower 	if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
11755901Ssklower 		if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
11855901Ssklower 			panic ("rtfree 2");
1197156Swnj 		rttrash--;
12055901Ssklower 		if (rt->rt_refcnt < 0) {
12155901Ssklower 			printf("rtfree: %x not freed (neg refs)\n", rt);
12255901Ssklower 			return;
12355901Ssklower 		}
12452027Ssklower 		ifa = rt->rt_ifa;
12555901Ssklower 		IFAFREE(ifa);
12650227Ssklower 		Free(rt_key(rt));
12750227Ssklower 		Free(rt);
1287156Swnj 	}
1296351Ssam }
13055901Ssklower 
13152027Ssklower void
ifafree(ifa)13252027Ssklower ifafree(ifa)
13352027Ssklower 	register struct ifaddr *ifa;
13452027Ssklower {
13563267Ssklower 	if (ifa == NULL)
13652027Ssklower 		panic("ifafree");
13763267Ssklower 	if (ifa->ifa_refcnt == 0)
13863267Ssklower 		free(ifa, M_IFADDR);
13963267Ssklower 	else
14063267Ssklower 		ifa->ifa_refcnt--;
14152027Ssklower }
14252027Ssklower 
1436331Ssam /*
14411551Ssam  * Force a routing table entry to the specified
14511551Ssam  * destination to go through the given gateway.
14611551Ssam  * Normally called as a result of a routing redirect
14711551Ssam  * message from the network layer.
14811551Ssam  *
14936209Skarels  * N.B.: must be called at splnet
15011551Ssam  *
15111551Ssam  */
15261351Sbostic int
rtredirect(dst,gateway,netmask,flags,src,rtp)15337472Ssklower rtredirect(dst, gateway, netmask, flags, src, rtp)
15437472Ssklower 	struct sockaddr *dst, *gateway, *netmask, *src;
15515717Skarels 	int flags;
15637472Ssklower 	struct rtentry **rtp;
15711551Ssam {
15811551Ssam 	register struct rtentry *rt;
15937472Ssklower 	int error = 0;
16037472Ssklower 	short *stat = 0;
16152565Ssklower 	struct rt_addrinfo info;
16259007Ssklower 	struct ifaddr *ifa;
16311551Ssam 
16411551Ssam 	/* verify the gateway is directly reachable */
16559007Ssklower 	if ((ifa = ifa_ifwithnet(gateway)) == 0) {
16637472Ssklower 		error = ENETUNREACH;
16752282Ssklower 		goto out;
16812832Ssam 	}
16937472Ssklower 	rt = rtalloc1(dst, 0);
17011551Ssam 	/*
17124775Skarels 	 * If the redirect isn't from our current router for this dst,
17226183Skarels 	 * it's either old or wrong.  If it redirects us to ourselves,
17326183Skarels 	 * we have a routing loop, perhaps as a result of an interface
17426183Skarels 	 * going down recently.
17524775Skarels 	 */
17637472Ssklower #define	equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
17759007Ssklower 	if (!(flags & RTF_DONE) && rt &&
17859007Ssklower 	     (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
17937472Ssklower 		error = EINVAL;
18037472Ssklower 	else if (ifa_ifwithaddr(gateway))
18137472Ssklower 		error = EHOSTUNREACH;
18237472Ssklower 	if (error)
18337472Ssklower 		goto done;
18424775Skarels 	/*
18513452Ssam 	 * Create a new entry if we just got back a wildcard entry
18613452Ssam 	 * or the the lookup failed.  This is necessary for hosts
18713452Ssam 	 * which use routing redirects generated by smart gateways
18813452Ssam 	 * to dynamically build the routing tables.
18936209Skarels 	 */
19037472Ssklower 	if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
19137472Ssklower 		goto create;
19212832Ssam 	/*
19311551Ssam 	 * Don't listen to the redirect if it's
19411551Ssam 	 * for a route to an interface.
19511551Ssam 	 */
19612832Ssam 	if (rt->rt_flags & RTF_GATEWAY) {
19715717Skarels 		if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
19815717Skarels 			/*
19916379Skarels 			 * Changing from route to net => route to host.
20015717Skarels 			 * Create new route, rather than smashing route to net.
20115717Skarels 			 */
20237472Ssklower 		create:
20337472Ssklower 			flags |=  RTF_GATEWAY | RTF_DYNAMIC;
20437472Ssklower 			error = rtrequest((int)RTM_ADD, dst, gateway,
20559007Ssklower 				    netmask, flags,
20637472Ssklower 				    (struct rtentry **)0);
20737472Ssklower 			stat = &rtstat.rts_dynamic;
20815717Skarels 		} else {
20915717Skarels 			/*
21015717Skarels 			 * Smash the current notion of the gateway to
21137472Ssklower 			 * this destination.  Should check about netmask!!!
21215717Skarels 			 */
21350227Ssklower 			rt->rt_flags |= RTF_MODIFIED;
21450227Ssklower 			flags |= RTF_MODIFIED;
21550227Ssklower 			stat = &rtstat.rts_newgateway;
21650227Ssklower 			rt_setgate(rt, rt_key(rt), gateway);
21715717Skarels 		}
21824775Skarels 	} else
21937472Ssklower 		error = EHOSTUNREACH;
22037472Ssklower done:
22137472Ssklower 	if (rt) {
22237472Ssklower 		if (rtp && !error)
22337472Ssklower 			*rtp = rt;
22437472Ssklower 		else
22537472Ssklower 			rtfree(rt);
22637472Ssklower 	}
22752282Ssklower out:
22837472Ssklower 	if (error)
22924775Skarels 		rtstat.rts_badredirect++;
23052282Ssklower 	else if (stat != NULL)
23152282Ssklower 		(*stat)++;
23252565Ssklower 	bzero((caddr_t)&info, sizeof(info));
23352565Ssklower 	info.rti_info[RTAX_DST] = dst;
23452565Ssklower 	info.rti_info[RTAX_GATEWAY] = gateway;
23552565Ssklower 	info.rti_info[RTAX_NETMASK] = netmask;
23652565Ssklower 	info.rti_info[RTAX_AUTHOR] = src;
23752565Ssklower 	rt_missmsg(RTM_REDIRECT, &info, flags, error);
23811551Ssam }
23911551Ssam 
24011551Ssam /*
24137472Ssklower * Routing table ioctl interface.
24237472Ssklower */
24361351Sbostic int
rtioctl(req,data,p)24448452Skarels rtioctl(req, data, p)
24568168Scgd 	u_long req;
24613049Ssam 	caddr_t data;
24748452Skarels 	struct proc *p;
24813049Ssam {
24936355Skarels 	return (EOPNOTSUPP);
25036355Skarels }
25143335Ssklower 
25243335Ssklower struct ifaddr *
ifa_ifwithroute(flags,dst,gateway)25343335Ssklower ifa_ifwithroute(flags, dst, gateway)
25461351Sbostic 	int flags;
25561351Sbostic 	struct sockaddr	*dst, *gateway;
25643335Ssklower {
25750226Ssklower 	register struct ifaddr *ifa;
25843335Ssklower 	if ((flags & RTF_GATEWAY) == 0) {
25943335Ssklower 		/*
26043335Ssklower 		 * If we are adding a route to an interface,
26143335Ssklower 		 * and the interface is a pt to pt link
26243335Ssklower 		 * we should search for the destination
26343335Ssklower 		 * as our clue to the interface.  Otherwise
26443335Ssklower 		 * we can use the local address.
26543335Ssklower 		 */
26643335Ssklower 		ifa = 0;
26743335Ssklower 		if (flags & RTF_HOST)
26843335Ssklower 			ifa = ifa_ifwithdstaddr(dst);
26943335Ssklower 		if (ifa == 0)
27043335Ssklower 			ifa = ifa_ifwithaddr(gateway);
27143335Ssklower 	} else {
27243335Ssklower 		/*
27343335Ssklower 		 * If we are adding a route to a remote net
27443335Ssklower 		 * or host, the gateway may still be on the
27543335Ssklower 		 * other end of a pt to pt link.
27643335Ssklower 		 */
27743335Ssklower 		ifa = ifa_ifwithdstaddr(gateway);
27843335Ssklower 	}
27943335Ssklower 	if (ifa == 0)
28043335Ssklower 		ifa = ifa_ifwithnet(gateway);
28143335Ssklower 	return (ifa);
28243335Ssklower }
28343335Ssklower 
28461351Sbostic int
rtrequest(req,dst,gateway,netmask,flags,ret_nrt)28568168Scgd rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
28668168Scgd 	int req, flags;
28768168Scgd 	struct sockaddr *dst, *gateway, *netmask;
28836355Skarels 	struct rtentry **ret_nrt;
28936355Skarels {
290*68437Ssklower 	struct rt_addrinfo info;
291*68437Ssklower 
292*68437Ssklower 	bzero((caddr_t)&info, sizeof(info));
293*68437Ssklower 	info.rti_flags = flags;
294*68437Ssklower 	info.rti_info[RTAX_DST] = dst;
295*68437Ssklower 	info.rti_info[RTAX_GATEWAY] = gateway;
296*68437Ssklower 	info.rti_info[RTAX_NETMASK] = netmask;
297*68437Ssklower 	return rtrequest1(req, &info, ret_nrt);
298*68437Ssklower }
299*68437Ssklower 
300*68437Ssklower /*
301*68437Ssklower  * These (questionable) definitions of apparent local variables apply
302*68437Ssklower  * to the next two functions.  XXXXXX!!!
303*68437Ssklower  */
304*68437Ssklower #define dst	info->rti_info[RTAX_DST]
305*68437Ssklower #define gateway	info->rti_info[RTAX_GATEWAY]
306*68437Ssklower #define netmask	info->rti_info[RTAX_NETMASK]
307*68437Ssklower #define ifaaddr	info->rti_info[RTAX_IFA]
308*68437Ssklower #define ifpaddr	info->rti_info[RTAX_IFP]
309*68437Ssklower #define flags	info->rti_flags
310*68437Ssklower 
311*68437Ssklower int
rt_getifa(info)312*68437Ssklower rt_getifa(info)
313*68437Ssklower 	register struct rt_addrinfo *info;
314*68437Ssklower {
315*68437Ssklower 	struct ifaddr *ifa;
316*68437Ssklower 	int error = 0;
317*68437Ssklower 
318*68437Ssklower 	/* ifp may be specified by sockaddr_dl
319*68437Ssklower 		   when protocol address is ambiguous */
320*68437Ssklower 	if (info->rti_ifp == 0 && ifpaddr && ifpaddr->sa_family == AF_LINK) {
321*68437Ssklower 		ifa = ifa_ifwithnet(ifpaddr);
322*68437Ssklower 		info->rti_ifp = ifa ? ifa->ifa_ifp : 0;
323*68437Ssklower 	}
324*68437Ssklower 	if (info->rti_ifa == 0) {
325*68437Ssklower 		struct sockaddr *sa;
326*68437Ssklower 
327*68437Ssklower 		sa = ifaaddr ? ifaaddr : (gateway ? gateway : dst);
328*68437Ssklower 		if (sa && info->rti_ifp)
329*68437Ssklower 			info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
330*68437Ssklower 		else if (dst && gateway)
331*68437Ssklower 			info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
332*68437Ssklower 		else if (sa)
333*68437Ssklower 			info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
334*68437Ssklower 	}
335*68437Ssklower 	if (ifa = info->rti_ifa) {
336*68437Ssklower 		if (info->rti_ifp == 0)
337*68437Ssklower 			info->rti_ifp = ifa->ifa_ifp;
338*68437Ssklower 	} else
339*68437Ssklower 		error = ENETUNREACH;
340*68437Ssklower 	return error;
341*68437Ssklower }
342*68437Ssklower 
343*68437Ssklower int
rtrequest1(req,info,ret_nrt)344*68437Ssklower rtrequest1(req, info, ret_nrt)
345*68437Ssklower 	int req;
346*68437Ssklower 	register struct rt_addrinfo *info;
347*68437Ssklower 	struct rtentry **ret_nrt;
348*68437Ssklower {
34950227Ssklower 	int s = splnet(); int error = 0;
35036355Skarels 	register struct rtentry *rt;
35136355Skarels 	register struct radix_node *rn;
35236355Skarels 	register struct radix_node_head *rnh;
35368168Scgd 	struct ifaddr *ifa;
35440785Ssklower 	struct sockaddr *ndst;
35540785Ssklower #define senderr(x) { error = x ; goto bad; }
35636355Skarels 
35750691Ssklower 	if ((rnh = rt_tables[dst->sa_family]) == 0)
358*68437Ssklower 		senderr(EAFNOSUPPORT);
35940785Ssklower 	if (flags & RTF_HOST)
36040785Ssklower 		netmask = 0;
3616331Ssam 	switch (req) {
362*68437Ssklower 	case RTM_DELPKT:
363*68437Ssklower 		if (rnh->rnh_deladdr == 0)
364*68437Ssklower 			senderr(EOPNOTSUPP);
365*68437Ssklower 		rn = rnh->rnh_delpkt(info->rti_pkthdr, (caddr_t)info, rnh);
366*68437Ssklower 		goto delete;
36736355Skarels 	case RTM_DELETE:
368*68437Ssklower 		rn = rnh->rnh_deladdr(dst, netmask, rnh);
369*68437Ssklower 	delete:
370*68437Ssklower 		if (rn == 0)
37140785Ssklower 			senderr(ESRCH);
37236209Skarels 		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
37336209Skarels 			panic ("rtrequest delete");
37468168Scgd 		rt = (struct rtentry *)rn;
37536355Skarels 		rt->rt_flags &= ~RTF_UP;
37650227Ssklower 		if (rt->rt_gwroute) {
37750227Ssklower 			rt = rt->rt_gwroute; RTFREE(rt);
37868168Scgd 			(rt = (struct rtentry *)rn)->rt_gwroute = 0;
37950227Ssklower 		}
38040785Ssklower 		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
381*68437Ssklower 			ifa->ifa_rtrequest(req, rt, info);
38240785Ssklower 		rttrash++;
38352565Ssklower 		if (ret_nrt)
38452565Ssklower 			*ret_nrt = rt;
38555901Ssklower 		else if (rt->rt_refcnt <= 0) {
38655901Ssklower 			rt->rt_refcnt++;
38740785Ssklower 			rtfree(rt);
38855901Ssklower 		}
3896331Ssam 		break;
3906331Ssam 
39168168Scgd 	case RTM_RESOLVE:
39268168Scgd 		if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
39368168Scgd 			senderr(EINVAL);
39468168Scgd 		ifa = rt->rt_ifa;
39568168Scgd 		flags = rt->rt_flags & ~RTF_CLONING;
39668168Scgd 		gateway = rt->rt_gateway;
39768168Scgd 		if ((netmask = rt->rt_genmask) == 0)
39868168Scgd 			flags |= RTF_HOST;
39968168Scgd 		goto makeroute;
40043073Ssklower 
401*68437Ssklower 	case RTM_ADDPKT:
402*68437Ssklower 		if (rnh->rnh_addpkt == 0)
403*68437Ssklower 			senderr(EOPNOTSUPP);
404*68437Ssklower 		/*FALLTHROUGH*/
40536355Skarels 	case RTM_ADD:
406*68437Ssklower 		if (info->rti_ifa == 0 && (error = rt_getifa(info)))
407*68437Ssklower 			senderr(error);
408*68437Ssklower 		ifa = info->rti_ifa;
40968168Scgd 	makeroute:
41050227Ssklower 		R_Malloc(rt, struct rtentry *, sizeof(*rt));
41140785Ssklower 		if (rt == 0)
41240785Ssklower 			senderr(ENOBUFS);
41350227Ssklower 		Bzero(rt, sizeof(*rt));
41450227Ssklower 		rt->rt_flags = RTF_UP | flags;
41550227Ssklower 		if (rt_setgate(rt, dst, gateway)) {
41650227Ssklower 			Free(rt);
41750227Ssklower 			senderr(ENOBUFS);
41850227Ssklower 		}
419*68437Ssklower 		if (req == RTM_ADDPKT) {
420*68437Ssklower 			rn = rnh->rnh_addpkt(info->rti_pkthdr, (caddr_t)info,
421*68437Ssklower 						rnh, rt->rt_nodes);
422*68437Ssklower 			goto add; /* addpkt() must allocate space */
423*68437Ssklower 		}
42450227Ssklower 		ndst = rt_key(rt);
42540785Ssklower 		if (netmask) {
42640785Ssklower 			rt_maskedcopy(dst, ndst, netmask);
42740785Ssklower 		} else
42840785Ssklower 			Bcopy(dst, ndst, dst->sa_len);
42959007Ssklower 		rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
43059007Ssklower 					rnh, rt->rt_nodes);
431*68437Ssklower 	add:
43236209Skarels 		if (rn == 0) {
43350227Ssklower 			if (rt->rt_gwroute)
43450227Ssklower 				rtfree(rt->rt_gwroute);
43551205Ssklower 			Free(rt_key(rt));
43650227Ssklower 			Free(rt);
43740785Ssklower 			senderr(EEXIST);
4386351Ssam 		}
43952027Ssklower 		ifa->ifa_refcnt++;
44043073Ssklower 		rt->rt_ifa = ifa;
44136355Skarels 		rt->rt_ifp = ifa->ifa_ifp;
44268168Scgd 		if (req == RTM_RESOLVE)
44368168Scgd 			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
44440785Ssklower 		if (ifa->ifa_rtrequest)
445*68437Ssklower 			ifa->ifa_rtrequest(req, rt, info);
44643073Ssklower 		if (ret_nrt) {
44743073Ssklower 			*ret_nrt = rt;
44843073Ssklower 			rt->rt_refcnt++;
44943073Ssklower 		}
4506331Ssam 		break;
451*68437Ssklower 	default:
452*68437Ssklower 		error = EOPNOTSUPP;
4536331Ssam 	}
4546351Ssam bad:
4556351Ssam 	splx(s);
4566351Ssam 	return (error);
457*68437Ssklower #undef dst
458*68437Ssklower #undef gateway
459*68437Ssklower #undef netmask
460*68437Ssklower #undef ifaaddr
461*68437Ssklower #undef ifpaddr
462*68437Ssklower #undef flags
4636331Ssam }
464*68437Ssklower #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
46540785Ssklower 
46661351Sbostic int
rt_setgate(rt0,dst,gate)46750227Ssklower rt_setgate(rt0, dst, gate)
46861351Sbostic 	struct rtentry *rt0;
46961351Sbostic 	struct sockaddr *dst, *gate;
47050227Ssklower {
47150227Ssklower 	caddr_t new, old;
47250227Ssklower 	int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
47350227Ssklower 	register struct rtentry *rt = rt0;
47450227Ssklower 
47550227Ssklower 	if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
47650227Ssklower 		old = (caddr_t)rt_key(rt);
47750227Ssklower 		R_Malloc(new, caddr_t, dlen + glen);
47850227Ssklower 		if (new == 0)
47950227Ssklower 			return 1;
48050227Ssklower 		rt->rt_nodes->rn_key = new;
48150227Ssklower 	} else {
48250227Ssklower 		new = rt->rt_nodes->rn_key;
48350227Ssklower 		old = 0;
48450227Ssklower 	}
48550227Ssklower 	Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
48650227Ssklower 	if (old) {
48750227Ssklower 		Bcopy(dst, new, dlen);
48850227Ssklower 		Free(old);
48950227Ssklower 	}
49050227Ssklower 	if (rt->rt_gwroute) {
49150227Ssklower 		rt = rt->rt_gwroute; RTFREE(rt);
49250227Ssklower 		rt = rt0; rt->rt_gwroute = 0;
49350227Ssklower 	}
49450227Ssklower 	return 0;
49550227Ssklower }
49650227Ssklower 
49761351Sbostic void
rt_maskedcopy(src,dst,netmask)49840785Ssklower rt_maskedcopy(src, dst, netmask)
49961351Sbostic 	struct sockaddr *src, *dst, *netmask;
50040785Ssklower {
50141922Ssklower 	register u_char *cp1 = (u_char *)src;
50241922Ssklower 	register u_char *cp2 = (u_char *)dst;
50341922Ssklower 	register u_char *cp3 = (u_char *)netmask;
50441922Ssklower 	u_char *cplim = cp2 + *cp3;
50541922Ssklower 	u_char *cplim2 = cp2 + *cp1;
50640785Ssklower 
50740785Ssklower 	*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
50841922Ssklower 	cp3 += 2;
50941922Ssklower 	if (cplim > cplim2)
51041922Ssklower 		cplim = cplim2;
51141922Ssklower 	while (cp2 < cplim)
51240785Ssklower 		*cp2++ = *cp1++ & *cp3++;
51341922Ssklower 	if (cp2 < cplim2)
51441922Ssklower 		bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
51540785Ssklower }
51663267Ssklower 
5176368Ssam /*
5186368Ssam  * Set up a routing table entry, normally
5196368Ssam  * for an interface.
5206368Ssam  */
52161351Sbostic int
rtinit(ifa,cmd,flags)52236355Skarels rtinit(ifa, cmd, flags)
52336355Skarels 	register struct ifaddr *ifa;
52425451Ssklower 	int cmd, flags;
5256368Ssam {
52646461Ssklower 	register struct rtentry *rt;
52746461Ssklower 	register struct sockaddr *dst;
52846461Ssklower 	register struct sockaddr *deldst;
52946461Ssklower 	struct mbuf *m = 0;
53052565Ssklower 	struct rtentry *nrt = 0;
531*68437Ssklower 	struct radix_node_head *rnh;
532*68437Ssklower 	struct radix_node *rn;
53346461Ssklower 	int error;
534*68437Ssklower 	struct rt_addrinfo info;
53546461Ssklower 
53646461Ssklower 	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
53746461Ssklower 	if (cmd == RTM_DELETE) {
53846461Ssklower 		if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
53946461Ssklower 			m = m_get(M_WAIT, MT_SONAME);
54046461Ssklower 			deldst = mtod(m, struct sockaddr *);
54146461Ssklower 			rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
54246461Ssklower 			dst = deldst;
54346461Ssklower 		}
544*68437Ssklower 		if ((rnh = rt_tables[dst->sa_family]) == 0 ||
545*68437Ssklower 		    (rn = rnh->rnh_lookup(dst, ifa->ifa_netmask, rnh)) == 0 ||
546*68437Ssklower 		    (rn->rn_flags & RNF_ROOT) != 0 ||
547*68437Ssklower 		    ((struct rtentry *)rn)->rt_ifa != ifa ||
548*68437Ssklower 		    !equal(rt_key(rt), dst))
549*68437Ssklower 		     {
550*68437Ssklower 			if (m)
551*68437Ssklower 				(void) m_free(m);
552*68437Ssklower 			return (flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
55346461Ssklower 		}
55446461Ssklower 	}
555*68437Ssklower 	bzero((caddr_t)&info, sizeof(info));
556*68437Ssklower 	info.rti_ifa = ifa;
557*68437Ssklower 	info.rti_flags = flags | ifa->ifa_flags;
558*68437Ssklower 	info.rti_info[RTAX_DST] = dst;
559*68437Ssklower 	info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
560*68437Ssklower 	info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
561*68437Ssklower 	error = rtrequest1(cmd, &info, &nrt);
562*68437Ssklower 
563*68437Ssklower 	if (error == 0 && (rt = nrt)) {
564*68437Ssklower 		rt_newaddrmsg(cmd, ifa, error, rt);
565*68437Ssklower 		if (cmd == RTM_DELETE) {
566*68437Ssklower 			if (rt->rt_refcnt <= 0) {
567*68437Ssklower 				rt->rt_refcnt++;
568*68437Ssklower 				rtfree(rt);
569*68437Ssklower 			}
570*68437Ssklower 		} else if (cmd == RTM_ADD)
571*68437Ssklower 			rt->rt_refcnt--;
572*68437Ssklower 	}
57346461Ssklower 	if (m)
57446461Ssklower 		(void) m_free(m);
57546461Ssklower 	return (error);
5766368Ssam }
577