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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [net/] [route.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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