OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [net/] [route.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/net/route.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*
23
 * Copyright (c) 1980, 1986, 1991, 1993
24
 *      The Regents of the University of California.  All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. All advertising materials mentioning features or use of this software
35
 *    must display the following acknowledgement:
36
 *      This product includes software developed by the University of
37
 *      California, Berkeley and its contributors.
38
 * 4. Neither the name of the University nor the names of its contributors
39
 *    may be used to endorse or promote products derived from this software
40
 *    without specific prior written permission.
41
 *
42
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52
 * SUCH DAMAGE.
53
 *
54
 *      @(#)route.c     8.2 (Berkeley) 11/15/93
55
 * $FreeBSD: src/sys/net/route.c,v 1.59.2.3 2001/07/29 19:18:02 ume Exp $
56
 */
57
 
58
#include <sys/param.h>
59
#include <sys/malloc.h>
60
#include <sys/mbuf.h>
61
#include <sys/socket.h>
62
#include <sys/domain.h>
63
 
64
#include <net/if.h>
65
#include <net/route.h>
66
 
67
#include <netinet/in.h>
68
#include <netinet/ip_mroute.h>
69
 
70
#include <sys/sockio.h>  // for eCos routing protocols
71
 
72
#define SA(p) ((struct sockaddr *)(p))
73
 
74
struct route_cb route_cb;
75
static struct rtstat rtstat;
76
struct radix_node_head *rt_tables[AF_MAX+1];
77
 
78
static int      rttrash;                /* routes not in table but not freed */
79
 
80
static void rt_maskedcopy __P((struct sockaddr *,
81
            struct sockaddr *, struct sockaddr *));
82
static void rtable_init __P((void **));
83
 
84
static void
85
rtable_init(table)
86
        void **table;
87
{
88
        struct domain *dom;
89
        for (dom = domains; dom; dom = dom->dom_next)
90
                if (dom->dom_rtattach)
91
                        dom->dom_rtattach(&table[dom->dom_family],
92
                            dom->dom_rtoffset);
93
}
94
 
95
void
96
route_init()
97
{
98
        rn_init();      /* initialize all zeroes, all ones, mask table */
99
        rtable_init((void **)rt_tables);
100
}
101
 
102
// FIXME: This function is only here because BOOTP fails on a second interface.
103
//        This failure is due to the fact that a route to 0.0.0.0 seems to be
104
//        incredibly sticky, i.e. can't be deleted.  BOOTP uses this to
105
//        achieve a generic broadcast.  Sadly it seems that BOOTP servers will
106
//        only work this way, thus the hack.
107
//
108
//        This version enumerates all routes and deletes them - this leaks less
109
//        store than the previous version.
110
 
111
static int
112
rt_reinit_rtdelete( struct radix_node *rn, void *vifp )
113
{
114
    struct rtentry *rt = (struct rtentry *)rn;
115
    rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
116
              0, NULL);
117
    return (0);
118
}
119
 
120
void
121
cyg_route_reinit(void)
122
{
123
    int i;
124
    for (i = 0;  i < AF_MAX+1;  i++) {
125
        struct radix_node_head *rnh;
126
        rnh = rt_tables[i];
127
        if (rnh) {
128
            (*rnh->rnh_walktree)(rnh, rt_reinit_rtdelete, NULL);
129
        }
130
    }
131
}
132
 
133
/*
134
 * Packet routing routines.
135
 */
136
void
137
rtalloc(ro)
138
        register struct route *ro;
139
{
140
        rtalloc_ign(ro, 0UL);
141
}
142
 
143
void
144
rtalloc_ign(ro, ignore)
145
        register struct route *ro;
146
        u_long ignore;
147
{
148
        struct rtentry *rt;
149
        int s;
150
 
151
        if ((rt = ro->ro_rt) != NULL) {
152
                if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP)
153
                        return;
154
                /* XXX - We are probably always at splnet here already. */
155
                s = splnet();
156
                RTFREE(rt);
157
                ro->ro_rt = NULL;
158
                splx(s);
159
        }
160
        ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
161
}
162
 
163
/*
164
 * Look up the route that matches the address given
165
 * Or, at least try.. Create a cloned route if needed.
166
 */
167
struct rtentry *
168
rtalloc1(dst, report, ignflags)
169
        register struct sockaddr *dst;
170
        int report;
171
        u_long ignflags;
172
{
173
        register struct radix_node_head *rnh = rt_tables[dst->sa_family];
174
        register struct rtentry *rt;
175
        register struct radix_node *rn;
176
        struct rtentry *newrt = 0;
177
        struct rt_addrinfo info;
178
        u_long nflags;
179
        int  s = splnet(), err = 0, msgtype = RTM_MISS;
180
 
181
        /*
182
         * Look up the address in the table for that Address Family
183
         */
184
        if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
185
            ((rn->rn_flags & RNF_ROOT) == 0)) {
186
                /*
187
                 * If we find it and it's not the root node, then
188
                 * get a refernce on the rtentry associated.
189
                 */
190
                newrt = rt = (struct rtentry *)rn;
191
                nflags = rt->rt_flags & ~ignflags;
192
                if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) {
193
                        /*
194
                         * We are apparently adding (report = 0 in delete).
195
                         * If it requires that it be cloned, do so.
196
                         * (This implies it wasn't a HOST route.)
197
                         */
198
                        err = rtrequest(RTM_RESOLVE, dst, SA(0),
199
                                              SA(0), 0, &newrt);
200
                        if (err) {
201
                                /*
202
                                 * If the cloning didn't succeed, maybe
203
                                 * what we have will do. Return that.
204
                                 */
205
                                newrt = rt;
206
                                rt->rt_refcnt++;
207
                                goto miss;
208
                        }
209
                        if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
210
                                /*
211
                                 * If the new route specifies it be
212
                                 * externally resolved, then go do that.
213
                                 */
214
                                msgtype = RTM_RESOLVE;
215
                                goto miss;
216
                        }
217
                } else
218
                        rt->rt_refcnt++;
219
        } else {
220
                /*
221
                 * Either we hit the root or couldn't find any match,
222
                 * Which basically means
223
                 * "caint get there frm here"
224
                 */
225
                rtstat.rts_unreach++;
226
        miss:   if (report) {
227
                        /*
228
                         * If required, report the failure to the supervising
229
                         * Authorities.
230
                         * For a delete, this is not an error. (report == 0)
231
                         */
232
                        bzero((caddr_t)&info, sizeof(info));
233
                        info.rti_info[RTAX_DST] = dst;
234
                        rt_missmsg(msgtype, &info, 0, err);
235
                }
236
        }
237
        splx(s);
238
        return (newrt);
239
}
240
 
241
/*
242
 * Remove a reference count from an rtentry.
243
 * If the count gets low enough, take it out of the routing table
244
 */
245
void
246
rtfree(rt)
247
        register struct rtentry *rt;
248
{
249
        /*
250
         * find the tree for that address family
251
         */
252
        register struct radix_node_head *rnh =
253
                rt_tables[rt_key(rt)->sa_family];
254
        register struct ifaddr *ifa;
255
 
256
        if (rt == 0 || rnh == 0)
257
                panic("rtfree");
258
 
259
        /*
260
         * decrement the reference count by one and if it reaches 0,
261
         * and there is a close function defined, call the close function
262
         */
263
        rt->rt_refcnt--;
264
        if(rnh->rnh_close && rt->rt_refcnt == 0) {
265
                rnh->rnh_close((struct radix_node *)rt, rnh);
266
        }
267
 
268
        /*
269
         * If we are no longer "up" (and ref == 0)
270
         * then we can free the resources associated
271
         * with the route.
272
         */
273
        if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
274
                if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
275
                        panic ("rtfree 2");
276
                /*
277
                 * the rtentry must have been removed from the routing table
278
                 * so it is represented in rttrash.. remove that now.
279
                 */
280
                rttrash--;
281
 
282
#ifdef  DIAGNOSTIC
283
                if (rt->rt_refcnt < 0) {
284
                        printf("rtfree: %p not freed (neg refs)\n", rt);
285
                        return;
286
                }
287
#endif
288
 
289
                /*
290
                 * release references on items we hold them on..
291
                 * e.g other routes and ifaddrs.
292
                 */
293
                if((ifa = rt->rt_ifa))
294
                        IFAFREE(ifa);
295
                if (rt->rt_parent) {
296
                        RTFREE(rt->rt_parent);
297
                }
298
 
299
                /*
300
                 * The key is separatly alloc'd so free it (see rt_setgate()).
301
                 * This also frees the gateway, as they are always malloc'd
302
                 * together.
303
                 */
304
                Free(rt_key(rt));
305
 
306
                /*
307
                 * and the rtentry itself of course
308
                 */
309
                Free(rt);
310
        }
311
}
312
 
313
void
314
ifafree(ifa)
315
        register struct ifaddr *ifa;
316
{
317
        if (ifa == NULL)
318
                panic("ifafree");
319
        if (ifa->ifa_refcnt == 0)
320
                free(ifa, M_IFADDR);
321
        else
322
                ifa->ifa_refcnt--;
323
}
324
 
325
/*
326
 * Force a routing table entry to the specified
327
 * destination to go through the given gateway.
328
 * Normally called as a result of a routing redirect
329
 * message from the network layer.
330
 *
331
 * N.B.: must be called at splnet
332
 *
333
 */
334
void
335
rtredirect(dst, gateway, netmask, flags, src, rtp)
336
        struct sockaddr *dst, *gateway, *netmask, *src;
337
        int flags;
338
        struct rtentry **rtp;
339
{
340
        register struct rtentry *rt;
341
        int error = 0;
342
        short *stat = 0;
343
        struct rt_addrinfo info;
344
        struct ifaddr *ifa;
345
 
346
        /* verify the gateway is directly reachable */
347
        if ((ifa = ifa_ifwithnet(gateway)) == 0) {
348
                error = ENETUNREACH;
349
                goto out;
350
        }
351
        rt = rtalloc1(dst, 0, 0UL);
352
        /*
353
         * If the redirect isn't from our current router for this dst,
354
         * it's either old or wrong.  If it redirects us to ourselves,
355
         * we have a routing loop, perhaps as a result of an interface
356
         * going down recently.
357
         */
358
#define equal(a1, a2) \
359
        ((a1)->sa_len == (a2)->sa_len && \
360
         bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
361
        if (!(flags & RTF_DONE) && rt &&
362
             (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
363
                error = EINVAL;
364
        else if (ifa_ifwithaddr(gateway))
365
                error = EHOSTUNREACH;
366
        if (error)
367
                goto done;
368
        /*
369
         * Create a new entry if we just got back a wildcard entry
370
         * or the the lookup failed.  This is necessary for hosts
371
         * which use routing redirects generated by smart gateways
372
         * to dynamically build the routing tables.
373
         */
374
        if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
375
                goto create;
376
        /*
377
         * Don't listen to the redirect if it's
378
         * for a route to an interface.
379
         */
380
        if (rt->rt_flags & RTF_GATEWAY) {
381
                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
382
                        /*
383
                         * Changing from route to net => route to host.
384
                         * Create new route, rather than smashing route to net.
385
                         */
386
                create:
387
                        flags |=  RTF_GATEWAY | RTF_DYNAMIC;
388
                        error = rtrequest((int)RTM_ADD, dst, gateway,
389
                                    netmask, flags,
390
                                    (struct rtentry **)0);
391
                        stat = &rtstat.rts_dynamic;
392
                } else {
393
                        /*
394
                         * Smash the current notion of the gateway to
395
                         * this destination.  Should check about netmask!!!
396
                         */
397
                        rt->rt_flags |= RTF_MODIFIED;
398
                        flags |= RTF_MODIFIED;
399
                        stat = &rtstat.rts_newgateway;
400
                        /*
401
                         * add the key and gateway (in one malloc'd chunk).
402
                         */
403
                        rt_setgate(rt, rt_key(rt), gateway);
404
                }
405
        } else
406
                error = EHOSTUNREACH;
407
done:
408
        if (rt) {
409
                if (rtp && !error)
410
                        *rtp = rt;
411
                else
412
                        rtfree(rt);
413
        }
414
out:
415
        if (error)
416
                rtstat.rts_badredirect++;
417
        else if (stat != NULL)
418
                (*stat)++;
419
        bzero((caddr_t)&info, sizeof(info));
420
        info.rti_info[RTAX_DST] = dst;
421
        info.rti_info[RTAX_GATEWAY] = gateway;
422
        info.rti_info[RTAX_NETMASK] = netmask;
423
        info.rti_info[RTAX_AUTHOR] = src;
424
        rt_missmsg(RTM_REDIRECT, &info, flags, error);
425
}
426
 
427
/*
428
* Routing table ioctl interface.
429
*/
430
int
431
rtioctl(req, data, p)
432
        int req;
433
        caddr_t data;
434
        struct proc *p;
435
{
436
#ifdef INET
437
    struct ecos_rtentry *rt;
438
    int res;
439
 
440
    switch (req) {
441
    case SIOCADDRT:
442
        rt = (struct ecos_rtentry *)data;
443
        res = rtrequest(RTM_ADD,
444
                        &rt->rt_dst,
445
                        &rt->rt_gateway,
446
                        &rt->rt_genmask,
447
                        rt->rt_flags,
448
                        NULL);
449
        return (res);
450
    case SIOCDELRT:
451
        rt = (struct ecos_rtentry *)data;
452
        res = rtrequest(RTM_DELETE,
453
                        &rt->rt_dst,
454
                        &rt->rt_gateway,
455
                        &rt->rt_genmask,
456
                        rt->rt_flags,
457
                        NULL);
458
        return (res);
459
    default:
460
        break;
461
    }
462
        /* Multicast goop, grrr... */
463
#ifdef MROUTING
464
        return mrt_ioctl(req, data);
465
#else
466
        return mrt_ioctl(req, data, p);
467
#endif
468
#else /* INET */
469
        return ENXIO;
470
#endif /* INET */
471
}
472
 
473
struct ifaddr *
474
ifa_ifwithroute(flags, dst, gateway)
475
        int flags;
476
        struct sockaddr *dst, *gateway;
477
{
478
        register struct ifaddr *ifa;
479
        if ((flags & RTF_GATEWAY) == 0) {
480
                /*
481
                 * If we are adding a route to an interface,
482
                 * and the interface is a pt to pt link
483
                 * we should search for the destination
484
                 * as our clue to the interface.  Otherwise
485
                 * we can use the local address.
486
                 */
487
                ifa = 0;
488
                if (flags & RTF_HOST) {
489
                        ifa = ifa_ifwithdstaddr(dst);
490
                }
491
                if (ifa == 0)
492
                        ifa = ifa_ifwithaddr(gateway);
493
        } else {
494
                /*
495
                 * If we are adding a route to a remote net
496
                 * or host, the gateway may still be on the
497
                 * other end of a pt to pt link.
498
                 */
499
                ifa = ifa_ifwithdstaddr(gateway);
500
        }
501
        if (ifa == 0)
502
                ifa = ifa_ifwithnet(gateway);
503
        if (ifa == 0) {
504
                struct rtentry *rt = rtalloc1(dst, 0, 0UL);
505
                if (rt == 0)
506
                        return (0);
507
                rt->rt_refcnt--;
508
                if ((ifa = rt->rt_ifa) == 0)
509
                        return (0);
510
        }
511
        if (ifa->ifa_addr->sa_family != dst->sa_family) {
512
                struct ifaddr *oifa = ifa;
513
                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
514
                if (ifa == 0)
515
                        ifa = oifa;
516
        }
517
        return (ifa);
518
}
519
 
520
#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
521
 
522
static int rt_fixdelete __P((struct radix_node *, void *));
523
static int rt_fixchange __P((struct radix_node *, void *));
524
 
525
struct rtfc_arg {
526
        struct rtentry *rt0;
527
        struct radix_node_head *rnh;
528
};
529
 
530
/*
531
 * Do appropriate manipulations of a routing tree given
532
 * all the bits of info needed
533
 */
534
int
535
rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
536
        int req, flags;
537
        struct sockaddr *dst, *gateway, *netmask;
538
        struct rtentry **ret_nrt;
539
{
540
        int s = splnet(); int error = 0;
541
        register struct rtentry *rt;
542
        register struct radix_node *rn;
543
        register struct radix_node_head *rnh;
544
        struct ifaddr *ifa;
545
        struct sockaddr *ndst;
546
#define senderr(x) { error = x ; goto bad; }
547
 
548
        /*
549
         * Find the correct routing tree to use for this Address Family
550
         */
551
        if ((rnh = rt_tables[dst->sa_family]) == 0)
552
                senderr(ESRCH);
553
        /*
554
         * If we are adding a host route then we don't want to put
555
         * a netmask in the tree
556
         */
557
        if (flags & RTF_HOST)
558
                netmask = 0;
559
        switch (req) {
560
        case RTM_DELETE:
561
                /*
562
                 * Remove the item from the tree and return it.
563
                 * Complain if it is not there and do no more processing.
564
                 */
565
                if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
566
                        senderr(ESRCH);
567
                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
568
                        panic ("rtrequest delete");
569
                rt = (struct rtentry *)rn;
570
 
571
                /*
572
                 * Now search what's left of the subtree for any cloned
573
                 * routes which might have been formed from this node.
574
                 */
575
                if ((rt->rt_flags & (RTF_CLONING | RTF_PRCLONING)) &&
576
                    rt_mask(rt)) {
577
                        rnh->rnh_walktree_from(rnh, dst, rt_mask(rt),
578
                                               rt_fixdelete, rt);
579
                }
580
 
581
                /*
582
                 * Remove any external references we may have.
583
                 * This might result in another rtentry being freed if
584
                 * we held its last reference.
585
                 */
586
                if (rt->rt_gwroute) {
587
                    if (rt != rt->rt_gwroute)
588
                        RTFREE( rt->rt_gwroute ); // Free it up as normal
589
                    else
590
                        rt->rt_refcnt--; // Just dec the refcount - freeing
591
                                         // it here would be premature
592
                    rt->rt_gwroute = NULL;
593
                }
594
 
595
                /*
596
                 * NB: RTF_UP must be set during the search above,
597
                 * because we might delete the last ref, causing
598
                 * rt to get freed prematurely.
599
                 *  eh? then why not just add a reference?
600
                 * I'm not sure how RTF_UP helps matters. (JRE)
601
                 */
602
                rt->rt_flags &= ~RTF_UP;
603
 
604
                /*
605
                 * give the protocol a chance to keep things in sync.
606
                 */
607
                if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
608
                        ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
609
 
610
                /*
611
                 * one more rtentry floating around that is not
612
                 * linked to the routing table.
613
                 */
614
                rttrash++;
615
 
616
                /*
617
                 * If the caller wants it, then it can have it,
618
                 * but it's up to it to free the rtentry as we won't be
619
                 * doing it.
620
                 */
621
                if (ret_nrt)
622
                        *ret_nrt = rt;
623
                else if (rt->rt_refcnt <= 0) {
624
                        rt->rt_refcnt++; /* make a 1->0 transition */
625
                        rtfree(rt);
626
                }
627
                break;
628
 
629
        case RTM_RESOLVE:
630
                if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
631
                        senderr(EINVAL);
632
                ifa = rt->rt_ifa;
633
                flags = rt->rt_flags &
634
                    ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC);
635
                flags |= RTF_WASCLONED;
636
                gateway = rt->rt_gateway;
637
                if ((netmask = rt->rt_genmask) == 0)
638
                        flags |= RTF_HOST;
639
                goto makeroute;
640
 
641
        case RTM_ADD:
642
                if ((flags & RTF_GATEWAY) && !gateway)
643
                        panic("rtrequest: GATEWAY but no gateway");
644
 
645
                if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
646
                        senderr(ENETUNREACH);
647
 
648
        makeroute:
649
                R_Malloc(rt, struct rtentry *, sizeof(*rt));
650
                if (rt == 0)
651
                        senderr(ENOBUFS);
652
                Bzero(rt, sizeof(*rt));
653
                rt->rt_flags = RTF_UP | flags;
654
                /*
655
                 * Add the gateway. Possibly re-malloc-ing the storage for it
656
                 * also add the rt_gwroute if possible.
657
                 */
658
                if ((error = rt_setgate(rt, dst, gateway)) != 0) {
659
                        Free(rt);
660
                        senderr(error);
661
                }
662
 
663
                /*
664
                 * point to the (possibly newly malloc'd) dest address.
665
                 */
666
                ndst = rt_key(rt);
667
 
668
                /*
669
                 * make sure it contains the value we want (masked if needed).
670
                 */
671
                if (netmask) {
672
                        rt_maskedcopy(dst, ndst, netmask);
673
                } else
674
                        Bcopy(dst, ndst, dst->sa_len);
675
 
676
                /*
677
                 * Note that we now have a reference to the ifa.
678
                 * This moved from below so that rnh->rnh_addaddr() can
679
                 * examine the ifa and  ifa->ifa_ifp if it so desires.
680
                 */
681
                ifa->ifa_refcnt++;
682
                rt->rt_ifa = ifa;
683
                rt->rt_ifp = ifa->ifa_ifp;
684
                /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
685
 
686
                rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
687
                                        rnh, rt->rt_nodes);
688
                if (rn == 0) {
689
                        struct rtentry *rt2;
690
                        /*
691
                         * Uh-oh, we already have one of these in the tree.
692
                         * We do a special hack: if the route that's already
693
                         * there was generated by the protocol-cloning
694
                         * mechanism, then we just blow it away and retry
695
                         * the insertion of the new one.
696
                         */
697
                        rt2 = rtalloc1(dst, 0, RTF_PRCLONING);
698
                        if (rt2 && rt2->rt_parent) {
699
                                rtrequest(RTM_DELETE,
700
                                          (struct sockaddr *)rt_key(rt2),
701
                                          rt2->rt_gateway,
702
                                          rt_mask(rt2), rt2->rt_flags, 0);
703
                                RTFREE(rt2);
704
                                rn = rnh->rnh_addaddr((caddr_t)ndst,
705
                                                      (caddr_t)netmask,
706
                                                      rnh, rt->rt_nodes);
707
                        } else if (rt2) {
708
                                /* undo the extra ref we got */
709
                                RTFREE(rt2);
710
                        }
711
                }
712
 
713
                /*
714
                 * If it still failed to go into the tree,
715
                 * then un-make it (this should be a function)
716
                 */
717
                if (rn == 0) {
718
                        if (rt->rt_gwroute)
719
                                rtfree(rt->rt_gwroute);
720
                        if (rt->rt_ifa) {
721
                                IFAFREE(rt->rt_ifa);
722
                        }
723
                        Free(rt_key(rt));
724
                        Free(rt);
725
                        senderr(EEXIST);
726
                }
727
 
728
                rt->rt_parent = 0;
729
 
730
                /*
731
                 * If we got here from RESOLVE, then we are cloning
732
                 * so clone the rest, and note that we
733
                 * are a clone (and increment the parent's references)
734
                 */
735
                if (req == RTM_RESOLVE) {
736
                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
737
                        if ((*ret_nrt)->rt_flags & (RTF_CLONING | RTF_PRCLONING)) {
738
                                rt->rt_parent = (*ret_nrt);
739
                                (*ret_nrt)->rt_refcnt++;
740
                        }
741
                }
742
 
743
                /*
744
                 * if this protocol has something to add to this then
745
                 * allow it to do that as well.
746
                 */
747
                if (ifa->ifa_rtrequest)
748
                        ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
749
 
750
                /*
751
                 * We repeat the same procedure from rt_setgate() here because
752
                 * it doesn't fire when we call it there because the node
753
                 * hasn't been added to the tree yet.
754
                 */
755
                if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
756
                        struct rtfc_arg arg;
757
                        arg.rnh = rnh;
758
                        arg.rt0 = rt;
759
                        rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
760
                                               rt_fixchange, &arg);
761
                }
762
 
763
                /*
764
                 * actually return a resultant rtentry and
765
                 * give the caller a single reference.
766
                 */
767
                if (ret_nrt) {
768
                        *ret_nrt = rt;
769
                        rt->rt_refcnt++;
770
                }
771
                break;
772
        }
773
bad:
774
        splx(s);
775
        return (error);
776
}
777
 
778
/*
779
 * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family''
780
 * (i.e., the routes related to it by the operation of cloning).  This
781
 * routine is iterated over all potential former-child-routes by way of
782
 * rnh->rnh_walktree_from() above, and those that actually are children of
783
 * the late parent (passed in as VP here) are themselves deleted.
784
 */
785
static int
786
rt_fixdelete(rn, vp)
787
        struct radix_node *rn;
788
        void *vp;
789
{
790
        struct rtentry *rt = (struct rtentry *)rn;
791
        struct rtentry *rt0 = vp;
792
 
793
        if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {
794
                return rtrequest(RTM_DELETE, rt_key(rt),
795
                                 (struct sockaddr *)0, rt_mask(rt),
796
                                 rt->rt_flags, (struct rtentry **)0);
797
        }
798
        return 0;
799
}
800
 
801
/*
802
 * This routine is called from rt_setgate() to do the analogous thing for
803
 * adds and changes.  There is the added complication in this case of a
804
 * middle insert; i.e., insertion of a new network route between an older
805
 * network route and (cloned) host routes.  For this reason, a simple check
806
 * of rt->rt_parent is insufficient; each candidate route must be tested
807
 * against the (mask, value) of the new route (passed as before in vp)
808
 * to see if the new route matches it.
809
 *
810
 * XXX - it may be possible to do fixdelete() for changes and reserve this
811
 * routine just for adds.  I'm not sure why I thought it was necessary to do
812
 * changes this way.
813
 */
814
#ifdef DEBUG
815
static int rtfcdebug = 0;
816
#endif
817
 
818
static int
819
rt_fixchange(rn, vp)
820
        struct radix_node *rn;
821
        void *vp;
822
{
823
        struct rtentry *rt = (struct rtentry *)rn;
824
        struct rtfc_arg *ap = vp;
825
        struct rtentry *rt0 = ap->rt0;
826
        struct radix_node_head *rnh = ap->rnh;
827
        u_char *xk1, *xm1, *xk2, *xmp;
828
        int i, len, mlen;
829
 
830
#ifdef DEBUG
831
        if (rtfcdebug)
832
                printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
833
#endif
834
 
835
        if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
836
#ifdef DEBUG
837
                if(rtfcdebug) printf("no parent or pinned\n");
838
#endif
839
                return 0;
840
        }
841
 
842
        if (rt->rt_parent == rt0) {
843
#ifdef DEBUG
844
                if(rtfcdebug) printf("parent match\n");
845
#endif
846
                return rtrequest(RTM_DELETE, rt_key(rt),
847
                                 (struct sockaddr *)0, rt_mask(rt),
848
                                 rt->rt_flags, (struct rtentry **)0);
849
        }
850
 
851
        /*
852
         * There probably is a function somewhere which does this...
853
         * if not, there should be.
854
         */
855
        len = imin(((struct sockaddr *)rt_key(rt0))->sa_len,
856
                   ((struct sockaddr *)rt_key(rt))->sa_len);
857
 
858
        xk1 = (u_char *)rt_key(rt0);
859
        xm1 = (u_char *)rt_mask(rt0);
860
        xk2 = (u_char *)rt_key(rt);
861
 
862
        /* avoid applying a less specific route */
863
        xmp = (u_char *)rt_mask(rt->rt_parent);
864
        mlen = ((struct sockaddr *)rt_key(rt->rt_parent))->sa_len;
865
        if (mlen > ((struct sockaddr *)rt_key(rt0))->sa_len) {
866
#ifdef DEBUG
867
                if (rtfcdebug)
868
                        printf("rt_fixchange: inserting a less "
869
                               "specific route\n");
870
#endif
871
                return 0;
872
        }
873
        for (i = rnh->rnh_treetop->rn_offset; i < mlen; i++) {
874
                if ((xmp[i] & ~(xmp[i] ^ xm1[i])) != xmp[i]) {
875
#ifdef DEBUG
876
                        if (rtfcdebug)
877
                                printf("rt_fixchange: inserting a less "
878
                                       "specific route\n");
879
#endif
880
                        return 0;
881
                }
882
        }
883
 
884
        for (i = rnh->rnh_treetop->rn_offset; i < len; i++) {
885
                if ((xk2[i] & xm1[i]) != xk1[i]) {
886
#ifdef DEBUG
887
                        if(rtfcdebug) printf("no match\n");
888
#endif
889
                        return 0;
890
                }
891
        }
892
 
893
        /*
894
         * OK, this node is a clone, and matches the node currently being
895
         * changed/added under the node's mask.  So, get rid of it.
896
         */
897
#ifdef DEBUG
898
        if(rtfcdebug) printf("deleting\n");
899
#endif
900
        return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
901
                         rt_mask(rt), rt->rt_flags, (struct rtentry **)0);
902
}
903
 
904
int
905
rt_setgate(rt0, dst, gate)
906
        struct rtentry *rt0;
907
        struct sockaddr *dst, *gate;
908
{
909
        caddr_t new, old;
910
        int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
911
        register struct rtentry *rt = rt0;
912
        struct radix_node_head *rnh = rt_tables[dst->sa_family];
913
 
914
        /*
915
         * A host route with the destination equal to the gateway
916
         * will interfere with keeping LLINFO in the routing
917
         * table, so disallow it.
918
         */
919
        if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) ==
920
                                        (RTF_HOST|RTF_GATEWAY)) &&
921
            (dst->sa_len == gate->sa_len) &&
922
            (bcmp(dst, gate, dst->sa_len) == 0)) {
923
                /*
924
                 * The route might already exist if this is an RTM_CHANGE
925
                 * or a routing redirect, so try to delete it.
926
                 */
927
                if (rt_key(rt0))
928
                        rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0),
929
                            rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0);
930
                return EADDRNOTAVAIL;
931
        }
932
 
933
        /*
934
         * Both dst and gateway are stored in the same malloc'd chunk
935
         * (If I ever get my hands on....)
936
         * if we need to malloc a new chunk, then keep the old one around
937
         * till we don't need it any more.
938
         */
939
        if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
940
                old = (caddr_t)rt_key(rt);
941
                R_Malloc(new, caddr_t, dlen + glen);
942
                if (new == 0)
943
                        return ENOBUFS;
944
                rt->rt_nodes->rn_key = new;
945
        } else {
946
                /*
947
                 * otherwise just overwrite the old one
948
                 */
949
                new = rt->rt_nodes->rn_key;
950
                old = 0;
951
        }
952
 
953
        /*
954
         * copy the new gateway value into the memory chunk
955
         */
956
        Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
957
 
958
        /*
959
         * if we are replacing the chunk (or it's new) we need to
960
         * replace the dst as well
961
         */
962
        if (old) {
963
                Bcopy(dst, new, dlen);
964
                Free(old);
965
        }
966
 
967
        /*
968
         * If there is already a gwroute, it's now almost definitly wrong
969
         * so drop it.
970
         */
971
        if (rt->rt_gwroute) {
972
                rt = rt->rt_gwroute; RTFREE(rt);
973
                rt = rt0; rt->rt_gwroute = 0;
974
        }
975
        /*
976
         * Cloning loop avoidance:
977
         * In the presence of protocol-cloning and bad configuration,
978
         * it is possible to get stuck in bottomless mutual recursion
979
         * (rtrequest rt_setgate rtalloc1).  We avoid this by not allowing
980
         * protocol-cloning to operate for gateways (which is probably the
981
         * correct choice anyway), and avoid the resulting reference loops
982
         * by disallowing any route to run through itself as a gateway.
983
         * This is obviously mandatory when we get rt->rt_output().
984
         */
985
        if (rt->rt_flags & RTF_GATEWAY) {
986
                rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING);
987
                if (rt->rt_gwroute == rt) {
988
                        RTFREE(rt->rt_gwroute);
989
                        rt->rt_gwroute = 0;
990
#define EDQUOT ENFILE
991
                        return EDQUOT; /* failure */
992
                }
993
        }
994
 
995
        /*
996
         * This isn't going to do anything useful for host routes, so
997
         * don't bother.  Also make sure we have a reasonable mask
998
         * (we don't yet have one during adds).
999
         */
1000
        if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
1001
                struct rtfc_arg arg;
1002
                arg.rnh = rnh;
1003
                arg.rt0 = rt;
1004
                rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
1005
                                       rt_fixchange, &arg);
1006
        }
1007
 
1008
        return 0;
1009
}
1010
 
1011
static void
1012
rt_maskedcopy(src, dst, netmask)
1013
        struct sockaddr *src, *dst, *netmask;
1014
{
1015
        register u_char *cp1 = (u_char *)src;
1016
        register u_char *cp2 = (u_char *)dst;
1017
        register u_char *cp3 = (u_char *)netmask;
1018
        u_char *cplim = cp2 + *cp3;
1019
        u_char *cplim2 = cp2 + *cp1;
1020
 
1021
        *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
1022
        cp3 += 2;
1023
        if (cplim > cplim2)
1024
                cplim = cplim2;
1025
        while (cp2 < cplim)
1026
                *cp2++ = *cp1++ & *cp3++;
1027
        if (cp2 < cplim2)
1028
                bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
1029
}
1030
 
1031
/*
1032
 * Set up a routing table entry, normally
1033
 * for an interface.
1034
 */
1035
int
1036
rtinit(ifa, cmd, flags)
1037
        register struct ifaddr *ifa;
1038
        int cmd, flags;
1039
{
1040
        register struct rtentry *rt;
1041
        register struct sockaddr *dst;
1042
        register struct sockaddr *deldst;
1043
        struct mbuf *m = 0;
1044
        struct rtentry *nrt = 0;
1045
        int error;
1046
 
1047
        dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
1048
        /*
1049
         * If it's a delete, check that if it exists, it's on the correct
1050
         * interface or we might scrub a route to another ifa which would
1051
         * be confusing at best and possibly worse.
1052
         */
1053
        if (cmd == RTM_DELETE) {
1054
                /*
1055
                 * It's a delete, so it should already exist..
1056
                 * If it's a net, mask off the host bits
1057
                 * (Assuming we have a mask)
1058
                 */
1059
                if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1060
                        m = m_get(M_DONTWAIT, MT_SONAME);
1061
                        if (m == NULL)
1062
                                return(ENOBUFS);
1063
                        deldst = mtod(m, struct sockaddr *);
1064
                        rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
1065
                        dst = deldst;
1066
                }
1067
                /*
1068
                 * Get an rtentry that is in the routing tree and
1069
                 * contains the correct info. (if this fails, can't get there).
1070
                 * We set "report" to FALSE so that if it doesn't exist,
1071
                 * it doesn't report an error or clone a route, etc. etc.
1072
                 */
1073
                rt = rtalloc1(dst, 0, 0UL);
1074
                if (rt) {
1075
                        /*
1076
                         * Ok so we found the rtentry. it has an extra reference
1077
                         * for us at this stage. we won't need that so
1078
                         * lop that off now.
1079
                         */
1080
                        rt->rt_refcnt--;
1081
                        if (rt->rt_ifa != ifa) {
1082
                                /*
1083
                                 * If the interface in the rtentry doesn't match
1084
                                 * the interface we are using, then we don't
1085
                                 * want to delete it, so return an error.
1086
                                 * This seems to be the only point of
1087
                                 * this whole RTM_DELETE clause.
1088
                                 */
1089
                                if (m)
1090
                                        (void) m_free(m);
1091
                                return (flags & RTF_HOST ? EHOSTUNREACH
1092
                                                        : ENETUNREACH);
1093
                        }
1094
                }
1095
                /* XXX */
1096
#if 0
1097
                else {
1098
                        /*
1099
                         * One would think that as we are deleting, and we know
1100
                         * it doesn't exist, we could just return at this point
1101
                         * with an "ELSE" clause, but apparently not..
1102
                         */
1103
                        return (flags & RTF_HOST ? EHOSTUNREACH
1104
                                                        : ENETUNREACH);
1105
                }
1106
#endif
1107
        }
1108
        /*
1109
         * Do the actual request
1110
         */
1111
        error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
1112
                        flags | ifa->ifa_flags, &nrt);
1113
        if (m)
1114
                (void) m_free(m);
1115
        /*
1116
         * If we are deleting, and we found an entry, then
1117
         * it's been removed from the tree.. now throw it away.
1118
         */
1119
        if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
1120
                /*
1121
                 * notify any listenning routing agents of the change
1122
                 */
1123
                rt_newaddrmsg(cmd, ifa, error, nrt);
1124
                if (rt->rt_refcnt <= 0) {
1125
                        rt->rt_refcnt++; /* need a 1->0 transition to free */
1126
                        rtfree(rt);
1127
                }
1128
        }
1129
 
1130
        /*
1131
         * We are adding, and we have a returned routing entry.
1132
         * We need to sanity check the result.
1133
         */
1134
        if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
1135
                /*
1136
                 * We just wanted to add it.. we don't actually need a reference
1137
                 */
1138
                rt->rt_refcnt--;
1139
                /*
1140
                 * If it came back with an unexpected interface, then it must
1141
                 * have already existed or something. (XXX)
1142
                 */
1143
                if (rt->rt_ifa != ifa) {
1144
                        if (!(rt->rt_ifa->ifa_ifp->if_flags &
1145
                            (IFF_POINTOPOINT|IFF_LOOPBACK)))
1146
                                printf("rtinit: wrong ifa (%p) was (%p)\n",
1147
                                    ifa, rt->rt_ifa);
1148
                        /*
1149
                         * Ask that the protocol in question
1150
                         * remove anything it has associated with
1151
                         * this route and ifaddr.
1152
                         */
1153
                        if (rt->rt_ifa->ifa_rtrequest)
1154
                            rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
1155
                        /*
1156
                         * Remove the reference to its ifaddr.
1157
                         */
1158
                        IFAFREE(rt->rt_ifa);
1159
                        /*
1160
                         * And substitute in references to the ifaddr
1161
                         * we are adding.
1162
                         */
1163
                        rt->rt_ifa = ifa;
1164
                        rt->rt_ifp = ifa->ifa_ifp;
1165
                        rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;      /*XXX*/
1166
                        ifa->ifa_refcnt++;
1167
                        /*
1168
                         * Now ask the protocol to check if it needs
1169
                         * any special processing in its new form.
1170
                         */
1171
                        if (ifa->ifa_rtrequest)
1172
                            ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
1173
                }
1174
                /*
1175
                 * notify any listenning routing agents of the change
1176
                 */
1177
                rt_newaddrmsg(cmd, ifa, error, nrt);
1178
        }
1179
        return (error);
1180
}
1181
 
1182
/* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */
1183
SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0);

powered by: WebSVN 2.1.0

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