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