source: rtems/cpukit/libnetworking/net/route.c @ 65c6425

4.115
Last change on this file since 65c6425 was 65c6425, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 17:24:46

Remove CVS Id Strings (manual edits after script)

These modifications were required by hand after running the script.
In some cases, the file names did not match patterns. In others,
the format of the file did not match any common patterns.

  • Property mode set to 100644
File size: 24.8 KB
Line 
1/*
2 * Copyright (c) 1980, 1986, 1991, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)route.c     8.2 (Berkeley) 11/15/93
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "opt_mrouting.h"
37
38#include <sys/param.h>
39#include <sys/queue.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/proc.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/domain.h>
47#include <sys/protosw.h>
48#include <sys/ioctl.h>
49
50#include <net/if.h>
51#include <net/route.h>
52#include <net/raw_cb.h>
53
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/ip_mroute.h>
57
58#define SA(p) ((struct sockaddr *)(p))
59
60struct route_cb route_cb;
61static struct rtstat rtstat;
62struct radix_node_head *rt_tables[AF_MAX+1];
63
64static int      rttrash;                /* routes not in table but not freed */
65
66static void rt_maskedcopy(struct sockaddr *,
67            struct sockaddr *, struct sockaddr *);
68static void rtable_init(struct radix_node_head **);
69
70/* compare two sockaddr structures */
71#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0)
72
73static void
74rtable_init(struct radix_node_head **table)
75{
76        struct domain *dom;
77        for (dom = domains; dom; dom = dom->dom_next)
78                if (dom->dom_rtattach)
79                        dom->dom_rtattach((void *)&table[dom->dom_family],
80                            dom->dom_rtoffset);
81}
82
83void
84route_init(void)
85{
86        rn_init();      /* initialize all zeroes, all ones, mask table */
87        rtable_init(rt_tables);
88}
89
90/*
91 * Packet routing routines.
92 */
93void
94rtalloc(struct route *ro)
95{
96        if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
97                return;                          /* XXX */
98        ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL);
99}
100
101void
102rtalloc_ign(struct route *ro, u_long ignore)
103{
104        if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
105                return;                          /* XXX */
106        ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
107}
108
109/*
110 * Look up the route that matches the address given
111 * Or, at least try.. Create a cloned route if needed.
112 */
113struct rtentry *
114rtalloc1(struct sockaddr *dst, int report, u_long ignflags)
115{
116        struct radix_node_head *rnh = rt_tables[dst->sa_family];
117        struct rtentry *rt;
118        struct radix_node *rn;
119        struct rtentry *newrt;
120        struct rt_addrinfo info;
121        u_long nflags;
122        int  s = splnet();
123        int err = 0, msgtype = RTM_MISS;
124
125        newrt = NULL;
126        /*
127         * Look up the address in the table for that Address Family
128         */
129        if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
130            ((rn->rn_flags & RNF_ROOT) == 0)) {
131                /*
132                 * If we find it and it's not the root node, then
133                 * get a refernce on the rtentry associated.
134                 */
135                newrt = rt = (struct rtentry *)rn;
136                nflags = rt->rt_flags & ~ignflags;
137                if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) {
138                        /*
139                         * We are apparently adding (report = 0 in delete).
140                         * If it requires that it be cloned, do so.
141                         * (This implies it wasn't a HOST route.)
142                         */
143                        err = rtrequest(RTM_RESOLVE, dst, SA(0),
144                                              SA(0), 0, &newrt);
145                        if (err) {
146                                /*
147                                 * If the cloning didn't succeed, maybe
148                                 * what we have will do. Return that.
149                                 */
150                                newrt = rt;
151                                rt->rt_refcnt++;
152                                goto miss;
153                        }
154                        if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
155                                /*
156                                 * If the new route specifies it be
157                                 * externally resolved, then go do that.
158                                 */
159                                msgtype = RTM_RESOLVE;
160                                goto miss;
161                        }
162                } else
163                        rt->rt_refcnt++;
164        } else {
165                /*
166                 * Either we hit the root or couldn't find any match,
167                 * Which basically means
168                 * "caint get there frm here"
169                 */
170                rtstat.rts_unreach++;
171        miss:   if (report) {
172                        /*
173                         * If required, report the failure to the supervising
174                         * Authorities.
175                         * For a delete, this is not an error. (report == 0)
176                         */
177                        bzero(&info, sizeof(info));
178                        info.rti_info[RTAX_DST] = dst;
179                        rt_missmsg(msgtype, &info, 0, err);
180                }
181        }
182        splx(s);
183        return (newrt);
184}
185
186/*
187 * Remove a reference count from an rtentry.
188 * If the count gets low enough, take it out of the routing table
189 */
190void
191rtfree(struct rtentry *rt)
192{
193        register struct radix_node_head *rnh =
194                rt_tables[rt_key(rt)->sa_family];
195        register struct ifaddr *ifa;
196
197        if (rt == 0 || rnh == 0)
198                panic("rtfree");
199        rt->rt_refcnt--;
200        if(rnh->rnh_close && rt->rt_refcnt == 0) {
201                rnh->rnh_close((struct radix_node *)rt, rnh);
202        }
203        if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
204                if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
205                        panic ("rtfree 2");
206                rttrash--;
207                if (rt->rt_refcnt < 0) {
208                        printf("rtfree: %p not freed (neg refs)\n", rt);
209                        return;
210                }
211                ifa = rt->rt_ifa;
212                IFAFREE(ifa);
213                if (rt->rt_parent) {
214                        RTFREE(rt->rt_parent);
215                }
216                Free(rt_key(rt));
217                Free(rt);
218        }
219}
220
221void
222ifafree(struct ifaddr *ifa)
223{
224        if (ifa == NULL)
225                panic("ifafree");
226        if (ifa->ifa_refcnt == 0)
227                free(ifa, M_IFADDR);
228        else
229                ifa->ifa_refcnt--;
230}
231
232/*
233 * Force a routing table entry to the specified
234 * destination to go through the given gateway.
235 * Normally called as a result of a routing redirect
236 * message from the network layer.
237 *
238 * N.B.: must be called at splnet
239 *
240 */
241void
242rtredirect(struct sockaddr *dst, struct sockaddr *gateway,
243    struct sockaddr *netmask, int flags, struct sockaddr *src,
244    struct rtentry **rtp)
245{
246        struct rtentry *rt;
247        int error = 0;
248        short *stat = NULL;
249        struct rt_addrinfo info;
250        struct ifaddr *ifa;
251
252        /* verify the gateway is directly reachable */
253        if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
254                error = ENETUNREACH;
255                goto out;
256        }
257        rt = rtalloc1(dst, 0, 0UL);
258        /*
259         * If the redirect isn't from our current router for this dst,
260         * it's either old or wrong.  If it redirects us to ourselves,
261         * we have a routing loop, perhaps as a result of an interface
262         * going down recently.
263         */
264#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
265        if (!(flags & RTF_DONE) && rt &&
266             (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
267                error = EINVAL;
268        else if (ifa_ifwithaddr(gateway))
269                error = EHOSTUNREACH;
270        if (error)
271                goto done;
272        /*
273         * Create a new entry if we just got back a wildcard entry
274         * or the the lookup failed.  This is necessary for hosts
275         * which use routing redirects generated by smart gateways
276         * to dynamically build the routing tables.
277         */
278        if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
279                goto create;
280        /*
281         * Don't listen to the redirect if it's
282         * for a route to an interface.
283         */
284        if (rt->rt_flags & RTF_GATEWAY) {
285                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
286                        /*
287                         * Changing from route to net => route to host.
288                         * Create new route, rather than smashing route to net.
289                         */
290                create:
291                        flags |=  RTF_GATEWAY | RTF_DYNAMIC;
292                        error = rtrequest((int)RTM_ADD, dst, gateway,
293                                    netmask, flags,
294                                    (struct rtentry **)0);
295                        stat = &rtstat.rts_dynamic;
296                } else {
297                        /*
298                         * Smash the current notion of the gateway to
299                         * this destination.  Should check about netmask!!!
300                         */
301                        rt->rt_flags |= RTF_MODIFIED;
302                        flags |= RTF_MODIFIED;
303                        stat = &rtstat.rts_newgateway;
304                        rt_setgate(rt, rt_key(rt), gateway);
305                }
306        } else
307                error = EHOSTUNREACH;
308done:
309        if (rt) {
310                if (rtp && !error)
311                        *rtp = rt;
312                else
313                        rtfree(rt);
314        }
315out:
316        if (error)
317                rtstat.rts_badredirect++;
318        else if (stat != NULL)
319                (*stat)++;
320        bzero(&info, sizeof(info));
321        info.rti_info[RTAX_DST] = dst;
322        info.rti_info[RTAX_GATEWAY] = gateway;
323        info.rti_info[RTAX_NETMASK] = netmask;
324        info.rti_info[RTAX_AUTHOR] = src;
325        rt_missmsg(RTM_REDIRECT, &info, flags, error);
326}
327
328/*
329* Routing table ioctl interface.
330*/
331int
332rtioctl(int req, caddr_t data, struct proc *p)
333{
334#ifdef INET
335        /* Multicast goop, grrr... */
336#ifdef MROUTING
337        return mrt_ioctl(req, data);
338#else
339        return mrt_ioctl(req, data, p);
340#endif
341#else /* INET */
342        return ENXIO;
343#endif /* INET */
344}
345
346struct ifaddr *
347ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway)
348{
349        register struct ifaddr *ifa;
350        if ((flags & RTF_GATEWAY) == 0) {
351                /*
352                 * If we are adding a route to an interface,
353                 * and the interface is a pt to pt link
354                 * we should search for the destination
355                 * as our clue to the interface.  Otherwise
356                 * we can use the local address.
357                 */
358                ifa = NULL;
359                if (flags & RTF_HOST) {
360                        ifa = ifa_ifwithdstaddr(dst);
361                }
362                if (ifa == NULL)
363                        ifa = ifa_ifwithaddr(gateway);
364        } else {
365                /*
366                 * If we are adding a route to a remote net
367                 * or host, the gateway may still be on the
368                 * other end of a pt to pt link.
369                 */
370                ifa = ifa_ifwithdstaddr(gateway);
371        }
372        if (ifa == 0)
373                ifa = ifa_ifwithnet(gateway);
374        if (ifa == 0) {
375                struct rtentry *rt = rtalloc1(dst, 0, 0UL);
376                if (rt == 0)
377                        return (0);
378                rt->rt_refcnt--;
379                if ((ifa = rt->rt_ifa) == 0)
380                        return (0);
381        }
382        if (ifa->ifa_addr->sa_family != dst->sa_family) {
383                struct ifaddr *oifa = ifa;
384                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
385                if (ifa == 0)
386                        ifa = oifa;
387        }
388        return (ifa);
389}
390
391#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
392
393static int rt_fixdelete(struct radix_node *, void *);
394static int rt_fixchange(struct radix_node *, void *);
395
396struct rtfc_arg {
397        struct rtentry *rt0;
398        struct radix_node_head *rnh;
399};
400
401/*
402 * Do appropriate manipulations of a routing tree given
403 * all the bits of info needed
404 */
405int
406rtrequest(int req, struct sockaddr *dst, struct sockaddr *gateway,
407    struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
408{
409        int s = splnet(); int error = 0;
410        register struct rtentry *rt;
411        register struct radix_node *rn;
412        register struct radix_node_head *rnh;
413        struct ifaddr *ifa;
414        struct sockaddr *ndst;
415#define senderr(x) { error = x ; goto bad; }
416
417        /*
418         * Find the correct routing tree to use for this Address Family
419         */
420        if ((rnh = rt_tables[dst->sa_family]) == 0)
421                senderr(ESRCH);
422        /*
423         * If we are adding a host route then we don't want to put
424         * a netmask in the tree
425         */
426        if (flags & RTF_HOST)
427                netmask = 0;
428        switch (req) {
429        case RTM_DELETE:
430                /*
431                 * Remove the item from the tree and return it.
432                 * Complain if it is not there and do no more processing.
433                 */
434                if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
435                        senderr(ESRCH);
436                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
437                        panic ("rtrequest delete");
438                rt = (struct rtentry *)rn;
439
440                /*
441                 * Now search what's left of the subtree for any cloned
442                 * routes which might have been formed from this node.
443                 */
444                if ((rt->rt_flags & RTF_PRCLONING) && netmask) {
445                        rnh->rnh_walktree_from(rnh, dst, netmask,
446                                               rt_fixdelete, rt);
447                }
448
449                /*
450                 * Remove any external references we may have.
451                 * This might result in another rtentry being freed if
452                 * we held it's last reference.
453                 */
454                if (rt->rt_gwroute) {
455                        rt = rt->rt_gwroute;
456                        RTFREE(rt);
457                        (rt = (struct rtentry *)rn)->rt_gwroute = 0;
458                }
459
460                /*
461                 * NB: RTF_UP must be set during the search above,
462                 * because we might delete the last ref, causing
463                 * rt to get freed prematurely.
464                 */
465                rt->rt_flags &= ~RTF_UP;
466
467                /*
468                 * If there is llinfo or similar associated with the
469                 * route, give the interface a chance to deal with it..
470                 */
471                if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
472                        ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
473                rttrash++;
474                /*
475                 * If the caller wants it, then it can have it, but it's up to it
476                 * to free the rtentry as we won't be doing it.
477                 */
478                if (ret_nrt)
479                        *ret_nrt = rt;
480                else if (rt->rt_refcnt <= 0) {
481                        rt->rt_refcnt++; /* make a 1->0 transition */
482                        rtfree(rt);
483                }
484                break;
485
486        case RTM_RESOLVE:
487                if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
488                        senderr(EINVAL);
489                ifa = rt->rt_ifa;
490                flags = rt->rt_flags &
491                    ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC);
492                flags |= RTF_WASCLONED;
493                gateway = rt->rt_gateway;
494                if ((netmask = rt->rt_genmask) == 0)
495                        flags |= RTF_HOST;
496                goto makeroute;
497
498        case RTM_ADD:
499                if ((flags & RTF_GATEWAY) && !gateway)
500                        panic("rtrequest: GATEWAY but no gateway");
501
502                if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
503                        senderr(ENETUNREACH);
504
505        makeroute:
506                R_Malloc(rt, struct rtentry *, sizeof(*rt));
507                if (rt == 0)
508                        senderr(ENOBUFS);
509                Bzero(rt, sizeof(*rt));
510                rt->rt_flags = RTF_UP | flags;
511                if ((error = rt_setgate(rt, dst, gateway))) {
512                        Free(rt);
513                        senderr(error);
514                }
515                ndst = rt_key(rt);
516                if (netmask) {
517                        rt_maskedcopy(dst, ndst, netmask);
518                } else
519                        Bcopy(dst, ndst, dst->sa_len);
520
521                /*
522                 * This moved from below so that rnh->rnh_addaddr() can
523                 * examine the ifa and ifp if it so desires.
524                 */
525                ifa->ifa_refcnt++;
526                rt->rt_ifa = ifa;
527                rt->rt_ifp = ifa->ifa_ifp;
528
529                rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
530                                        rnh, rt->rt_nodes);
531                if (rn == 0) {
532                        struct rtentry *rt2;
533                        /*
534                         * Uh-oh, we already have one of these in the tree.
535                         * We do a special hack: if the route that's already
536                         * there was generated by the protocol-cloning
537                         * mechanism, then we just blow it away and retry
538                         * the insertion of the new one.
539                         */
540                        rt2 = rtalloc1(dst, 0, RTF_PRCLONING);
541                        if (rt2 && rt2->rt_parent) {
542                                rtrequest(RTM_DELETE,
543                                          (struct sockaddr *)rt_key(rt2),
544                                          rt2->rt_gateway,
545                                          rt_mask(rt2), rt2->rt_flags, 0);
546                                RTFREE(rt2);
547                                rn = rnh->rnh_addaddr((caddr_t)ndst,
548                                                      (caddr_t)netmask,
549                                                      rnh, rt->rt_nodes);
550                        } else if (rt2) {
551                                RTFREE(rt2);
552                        }
553                }
554
555                if (rn == 0) {
556                        if (rt->rt_gwroute)
557                                rtfree(rt->rt_gwroute);
558                        if (rt->rt_ifa) {
559                                IFAFREE(rt->rt_ifa);
560                        }
561                        Free(rt_key(rt));
562                        Free(rt);
563                        senderr(EEXIST);
564                }
565                rt->rt_parent = 0;
566
567                if (req == RTM_RESOLVE) {
568                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
569                        if ((*ret_nrt)->rt_flags & RTF_PRCLONING) {
570                                rt->rt_parent = (*ret_nrt);
571                                (*ret_nrt)->rt_refcnt++;
572                        }
573                }
574                if (ifa->ifa_rtrequest)
575                        ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
576                /*
577                 * We repeat the same procedure from rt_setgate() here because
578                 * it doesn't fire when we call it there because the node
579                 * hasn't been added to the tree yet.
580                 */
581                if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
582                        struct rtfc_arg arg;
583                        arg.rnh = rnh;
584                        arg.rt0 = rt;
585                        rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
586                                               rt_fixchange, &arg);
587                }
588
589                if (ret_nrt) {
590                        *ret_nrt = rt;
591                        rt->rt_refcnt++;
592                }
593                break;
594        }
595bad:
596        splx(s);
597        return (error);
598}
599
600/*
601 * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family''
602 * (i.e., the routes related to it by the operation of cloning).  This
603 * routine is iterated over all potential former-child-routes by way of
604 * rnh->rnh_walktree_from() above, and those that actually are children of
605 * the late parent (passed in as VP here) are themselves deleted.
606 */
607static int
608rt_fixdelete(struct radix_node *rn, void *vp)
609{
610        struct rtentry *rt = (struct rtentry *)rn;
611        struct rtentry *rt0 = vp;
612
613        if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {
614                return rtrequest(RTM_DELETE, rt_key(rt),
615                                 (struct sockaddr *)0, rt_mask(rt),
616                                 rt->rt_flags, (struct rtentry **)0);
617        }
618        return 0;
619}
620
621/*
622 * This routine is called from rt_setgate() to do the analogous thing for
623 * adds and changes.  There is the added complication in this case of a
624 * middle insert; i.e., insertion of a new network route between an older
625 * network route and (cloned) host routes.  For this reason, a simple check
626 * of rt->rt_parent is insufficient; each candidate route must be tested
627 * against the (mask, value) of the new route (passed as before in vp)
628 * to see if the new route matches it.  Unfortunately, this has the obnoxious
629 * property of also triggering for insertion /above/ a pre-existing network
630 * route and clones.  Sigh.  This may be fixed some day.
631 *
632 * XXX - it may be possible to do fixdelete() for changes and reserve this
633 * routine just for adds.  I'm not sure why I thought it was necessary to do
634 * changes this way.
635 */
636#ifdef DEBUG
637int rtfcdebug = 0;
638#endif
639
640static int
641rt_fixchange(struct radix_node *rn, void *vp)
642{
643        struct rtentry *rt = (struct rtentry *)rn;
644        struct rtfc_arg *ap = vp;
645        struct rtentry *rt0 = ap->rt0;
646        struct radix_node_head *rnh = ap->rnh;
647        u_char *xk1, *xm1, *xk2;
648        int i, len;
649
650#ifdef DEBUG
651        if (rtfcdebug)
652                printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
653#endif
654
655        if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
656#ifdef DEBUG
657                if(rtfcdebug) printf("no parent or pinned\n");
658#endif
659                return 0;
660        }
661
662        if (rt->rt_parent == rt0) {
663#ifdef DEBUG
664                if(rtfcdebug) printf("parent match\n");
665#endif
666                return rtrequest(RTM_DELETE, rt_key(rt),
667                                 (struct sockaddr *)0, rt_mask(rt),
668                                 rt->rt_flags, (struct rtentry **)0);
669        }
670
671        /*
672         * There probably is a function somewhere which does this...
673         * if not, there should be.
674         */
675        len = imin(((struct sockaddr *)rt_key(rt0))->sa_len,
676                   ((struct sockaddr *)rt_key(rt))->sa_len);
677
678        xk1 = (u_char *)rt_key(rt0);
679        xm1 = (u_char *)rt_mask(rt0);
680        xk2 = (u_char *)rt_key(rt);
681
682        for (i = rnh->rnh_treetop->rn_offset; i < len; i++) {
683                if ((xk2[i] & xm1[i]) != xk1[i]) {
684#ifdef DEBUG
685                        if(rtfcdebug) printf("no match\n");
686#endif
687                        return 0;
688                }
689        }
690
691        /*
692         * OK, this node is a clone, and matches the node currently being
693         * changed/added under the node's mask.  So, get rid of it.
694         */
695#ifdef DEBUG
696        if(rtfcdebug) printf("deleting\n");
697#endif
698        return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
699                         rt_mask(rt), rt->rt_flags, (struct rtentry **)0);
700}
701
702int
703rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate)
704{
705        caddr_t new, old;
706        int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
707        register struct rtentry *rt = rt0;
708        struct radix_node_head *rnh = rt_tables[dst->sa_family];
709
710        /*
711         * A host route with the destination equal to the gateway
712         * will interfere with keeping LLINFO in the routing
713         * table, so disallow it.
714         */
715        if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) ==
716                                        (RTF_HOST|RTF_GATEWAY)) &&
717            (dst->sa_len == gate->sa_len) &&
718            (bcmp(dst, gate, dst->sa_len) == 0)) {
719                /*
720                 * The route might already exist if this is an RTM_CHANGE
721                 * or a routing redirect, so try to delete it.
722                 */
723                if (rt_key(rt0))
724                        rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0),
725                            rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0);
726                return EADDRNOTAVAIL;
727        }
728
729        if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
730                old = (caddr_t)rt_key(rt);
731                R_Malloc(new, caddr_t, dlen + glen);
732                if (new == 0)
733                        return ENOBUFS;
734                rt->rt_nodes->rn_key = new;
735        } else {
736                new = rt->rt_nodes->rn_key;
737                old = 0;
738        }
739        Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
740        if (old) {
741                Bcopy(dst, new, dlen);
742                Free(old);
743        }
744        if (rt->rt_gwroute) {
745                rt = rt->rt_gwroute; RTFREE(rt);
746                rt = rt0; rt->rt_gwroute = 0;
747        }
748        /*
749         * Cloning loop avoidance:
750         * In the presence of protocol-cloning and bad configuration,
751         * it is possible to get stuck in bottomless mutual recursion
752         * (rtrequest rt_setgate rtalloc1).  We avoid this by not allowing
753         * protocol-cloning to operate for gateways (which is probably the
754         * correct choice anyway), and avoid the resulting reference loops
755         * by disallowing any route to run through itself as a gateway.
756         * This is obviuosly mandatory when we get rt->rt_output().
757         */
758        if (rt->rt_flags & RTF_GATEWAY) {
759                rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING);
760                if (rt->rt_gwroute == rt) {
761                        RTFREE(rt->rt_gwroute);
762                        rt->rt_gwroute = 0;
763                        return EDQUOT; /* failure */
764                }
765        }
766
767        /*
768         * This isn't going to do anything useful for host routes, so
769         * don't bother.  Also make sure we have a reasonable mask
770         * (we don't yet have one during adds).
771         */
772        if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
773                struct rtfc_arg arg;
774                arg.rnh = rnh;
775                arg.rt0 = rt;
776                rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
777                                       rt_fixchange, &arg);
778        }
779
780        return 0;
781}
782
783static void
784rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
785    struct sockaddr *netmask)
786{
787        register u_char *cp1 = (u_char *)src;
788        register u_char *cp2 = (u_char *)dst;
789        register u_char *cp3 = (u_char *)netmask;
790        u_char *cplim = cp2 + *cp3;
791        u_char *cplim2 = cp2 + *cp1;
792
793        *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
794        cp3 += 2;
795        if (cplim > cplim2)
796                cplim = cplim2;
797        while (cp2 < cplim)
798                *cp2++ = *cp1++ & *cp3++;
799        if (cp2 < cplim2)
800                bzero(cp2, (unsigned)(cplim2 - cp2));
801}
802
803/*
804 * Set up a routing table entry, normally
805 * for an interface.
806 */
807int
808rtinit(struct ifaddr *ifa, int cmd, int flags)
809{
810        register struct rtentry *rt;
811        register struct sockaddr *dst;
812        register struct sockaddr *deldst;
813        struct mbuf *m = 0;
814        struct rtentry *nrt = 0;
815        int error;
816
817        dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
818        /*
819         * If it's a delete, check that if it exists, it's on the correct
820         * interface or we might scrub a route to another ifa which would
821         * be confusing at best and possibly worse.
822         */
823        if (cmd == RTM_DELETE) {
824                /*
825                 * It's a delete, so it should already exist..
826                 * If it's a net, mask off the host bits
827                 * (Assuming we have a mask)
828                 */
829                if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
830                        m = m_get(M_WAIT, MT_SONAME);
831                        deldst = mtod(m, struct sockaddr *);
832                        rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
833                        dst = deldst;
834                }
835                /*
836                 * Get an rtentry that is in the routing tree and
837                 * contains the correct info. (if this fails we can't get there).
838                 * We set "report" to FALSE so that if it doesn't exist,
839                 * it doesn't report an error or clone a route, etc. etc.
840                 */
841                rt = rtalloc1(dst, 0, 0UL);
842                if (rt) {
843                        /*
844                         * Ok so we found the rtentry. it has an extra reference
845                         * for us at this stage. we won't need that so
846                         * lop that off now.
847                         */
848                        rt->rt_refcnt--;
849                        if (rt->rt_ifa != ifa) {
850                                /*
851                                 * If the interface in the rtentry doesn't match
852                                 * the interface we are using, then we don't
853                                 * want to delete it, so return an error.
854                                 * This seems to be the only point of
855                                 * this whole RTM_DELETE clause.
856                                 */
857                                if (m)
858                                        (void) m_free(m);
859                                return (flags & RTF_HOST ? EHOSTUNREACH
860                                                        : ENETUNREACH);
861                        }
862                }
863                /* XXX */
864#if 0
865                else {
866                        /*
867                         * One would think that as we are deleting, and we know
868                         * it doesn't exist, we could just return at this point
869                         * with an "ELSE" clause, but apparently not..
870                         */
871                        return (flags & RTF_HOST ? EHOSTUNREACH
872                                                        : ENETUNREACH);
873                }
874#endif
875        }
876        /*
877         * Do the actual request
878         */
879        error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
880                        flags | ifa->ifa_flags, &nrt);
881        if (m)
882                (void) m_free(m);
883        /*
884         * If we are deleting, and we found an entry, then
885         * it's been removed from the tree.. now throw it away.
886         */
887        if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
888                /*
889                 * notify any listenning routing agents of the change
890                 */
891                rt_newaddrmsg(cmd, ifa, error, nrt);
892                if (rt->rt_refcnt <= 0) {
893                        rt->rt_refcnt++; /* need a 1->0 transition to free */
894                        rtfree(rt);
895                }
896        }
897
898        /*
899         * We are adding, and we have a returned routing entry.
900         * We need to sanity check the result.
901         */
902        if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
903                /*
904                 * We just wanted to add it.. we don't actually need a reference
905                 */
906                rt->rt_refcnt--;
907                /*
908                 * If it came back with an unexpected interface, then it must
909                 * have already existed or something. (XXX)
910                 */
911                if (rt->rt_ifa != ifa) {
912                        printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
913                                rt->rt_ifa);
914                        /*
915                         * Ask that the route we got back be removed
916                         * from the routing tables as we are trying
917                         * to supersede it.
918                         */
919                        if (rt->rt_ifa->ifa_rtrequest)
920                            rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
921                        /*
922                         * Remove the referenve to the it's ifaddr.
923                         */
924                        IFAFREE(rt->rt_ifa);
925                        /*
926                         * And substitute in references to the ifaddr
927                         * we are adding.
928                         */
929                        rt->rt_ifa = ifa;
930                        rt->rt_ifp = ifa->ifa_ifp;
931                        ifa->ifa_refcnt++;
932                        /*
933                         * Now add it to the routing table
934                         * XXX could we have just left it?
935                         * as it might have been in the right place..
936                         */
937                        if (ifa->ifa_rtrequest)
938                            ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
939                }
940                /*
941                 * notify any listenning routing agents of the change
942                 */
943                rt_newaddrmsg(cmd, ifa, error, nrt);
944        }
945        return (error);
946}
Note: See TracBrowser for help on using the repository browser.