OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [net/] [route.c] - Blame information for rev 173

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.