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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [sys/] [net/] [route.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1254 phoenix
//==========================================================================
2
//
3
//      sys/net/route.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: route.c,v 1.16 1999/12/08 06:50:18 itojun Exp $       */
34
/*      $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $      */
35
 
36
/*
37
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
38
 * All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. Neither the name of the project nor the names of its contributors
49
 *    may be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
53
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
56
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62
 * SUCH DAMAGE.
63
 */
64
 
65
/*
66
 * Copyright (c) 1980, 1986, 1991, 1993
67
 *      The Regents of the University of California.  All rights reserved.
68
 *
69
 * Redistribution and use in source and binary forms, with or without
70
 * modification, are permitted provided that the following conditions
71
 * are met:
72
 * 1. Redistributions of source code must retain the above copyright
73
 *    notice, this list of conditions and the following disclaimer.
74
 * 2. Redistributions in binary form must reproduce the above copyright
75
 *    notice, this list of conditions and the following disclaimer in the
76
 *    documentation and/or other materials provided with the distribution.
77
 * 3. All advertising materials mentioning features or use of this software
78
 *    must display the following acknowledgement:
79
 *      This product includes software developed by the University of
80
 *      California, Berkeley and its contributors.
81
 * 4. Neither the name of the University nor the names of its contributors
82
 *    may be used to endorse or promote products derived from this software
83
 *    without specific prior written permission.
84
 *
85
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95
 * SUCH DAMAGE.
96
 *
97
 *      @(#)route.c     8.2 (Berkeley) 11/15/93
98
 */
99
 
100
/*
101
%%% portions-copyright-nrl-95
102
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
103
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
104
Reserved. All rights under this copyright have been assigned to the US
105
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
106
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
107
software.
108
You should have received a copy of the license with this software. If you
109
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
110
*/
111
 
112
#include <sys/param.h>
113
#ifdef __ECOS
114
struct proc {
115
    int __unused;
116
};
117
#else
118
#include <sys/systm.h>
119
#include <sys/proc.h>
120
#endif
121
#include <sys/mbuf.h>
122
#include <sys/socket.h>
123
#include <sys/socketvar.h>
124
#include <sys/domain.h>
125
#include <sys/protosw.h>
126
#include <sys/ioctl.h>
127
#include <sys/kernel.h>
128
 
129
#include <net/if.h>
130
#include <net/route.h>
131
#include <net/raw_cb.h>
132
 
133
#include <netinet/in.h>
134
#include <netinet/in_var.h>
135
 
136
#ifdef NS
137
#include <netns/ns.h>
138
#endif
139
 
140
#ifdef IPSEC
141
#include <netinet/ip_ipsp.h>
142
 
143
extern struct ifnet encif;
144
#endif
145
 
146
#define SA(p) ((struct sockaddr *)(p))
147
 
148
int     rttrash;                /* routes not in table but not freed */
149
struct  sockaddr wildcard;      /* zero valued cookie for wildcard searches */
150
 
151
static int okaytoclone __P((u_int, int));
152
 
153
#ifdef IPSEC
154
 
155
static struct ifaddr *
156
encap_findgwifa(struct sockaddr *gw)
157
{
158
        return encif.if_addrlist.tqh_first;
159
}
160
 
161
#endif
162
 
163
void
164
rtable_init(table)
165
        void **table;
166
{
167
        struct domain *dom;
168
        for (dom = domains; dom; dom = dom->dom_next)
169
                if (dom->dom_rtattach)
170
                        dom->dom_rtattach(&table[dom->dom_family],
171
                            dom->dom_rtoffset);
172
}
173
 
174
void
175
route_init()
176
{
177
        rn_init();      /* initialize all zeroes, all ones, mask table */
178
        rtable_init((void **)rt_tables);
179
}
180
 
181
// FIXME: This function is only here because BOOTP fails on a second interface.
182
//        This failure is due to the fact that a route to 0.0.0.0 seems to be
183
//        incredibly sticky, i.e. can't be deleted.  BOOTP uses this to
184
//        achieve a generic broadcast.  Sadly it seems that BOOTP servers will
185
//        only work this way, thus the hack.
186
//
187
//        This version enumerates all routes and deletes them - this leaks less
188
//        store than the previous version.
189
 
190
static int
191
rt_reinit_rtdelete( struct radix_node *rn, void *vifp )
192
{
193
    struct rtentry *rt = (struct rtentry *)rn;
194
    rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
195
              0, NULL);
196
    return (0);
197
}
198
 
199
void
200
cyg_route_reinit(void)
201
{
202
    int i;
203
    for (i = 0;  i < AF_MAX+1;  i++) {
204
        struct radix_node_head *rnh;
205
        rnh = rt_tables[i];
206
        if (rnh) {
207
            (*rnh->rnh_walktree)(rnh, rt_reinit_rtdelete, NULL);
208
        }
209
    }
210
}
211
 
212
void
213
rtalloc_noclone(ro, howstrict)
214
        register struct route *ro;
215
        int howstrict;
216
{
217
        if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
218
                return;         /* XXX */
219
        ro->ro_rt = rtalloc2(&ro->ro_dst, 1, howstrict);
220
}
221
 
222
static int
223
okaytoclone(flags, howstrict)
224
        u_int flags;
225
        int howstrict;
226
{
227
        if (howstrict == ALL_CLONING)
228
                return 1;
229
        if (howstrict == ONNET_CLONING && !(flags & (RTF_GATEWAY|RTF_TUNNEL)))
230
                return 1;
231
        return 0;
232
}
233
 
234
struct rtentry *
235
rtalloc2(dst, report,howstrict)
236
        register struct sockaddr *dst;
237
        int report,howstrict;
238
{
239
        register struct radix_node_head *rnh = rt_tables[dst->sa_family];
240
        register struct rtentry *rt;
241
        register struct radix_node *rn;
242
        struct rtentry *newrt = 0;
243
        struct rt_addrinfo info;
244
        int  s = splnet(), err = 0, msgtype = RTM_MISS;
245
 
246
        if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
247
            ((rn->rn_flags & RNF_ROOT) == 0)) {
248
                newrt = rt = (struct rtentry *)rn;
249
                if (report && (rt->rt_flags & RTF_CLONING) &&
250
                    okaytoclone(rt->rt_flags, howstrict)) {
251
                        err = rtrequest(RTM_RESOLVE, dst, SA(0), SA(0), 0,
252
                            &newrt);
253
                        if (err) {
254
                                newrt = rt;
255
                                rt->rt_refcnt++;
256
                                goto miss;
257
                        }
258
                        if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
259
                                msgtype = RTM_RESOLVE;
260
                                goto miss;
261
                        }
262
                } else
263
                        rt->rt_refcnt++;
264
        } else {
265
                rtstat.rts_unreach++;
266
miss:           if (report) {
267
                        bzero((caddr_t)&info, sizeof(info));
268
                        info.rti_info[RTAX_DST] = dst;
269
                        rt_missmsg(msgtype, &info, 0, err);
270
                }
271
        }
272
        splx(s);
273
        return (newrt);
274
}
275
 
276
/*
277
 * Packet routing routines.
278
 */
279
void
280
rtalloc(ro)
281
        register struct route *ro;
282
{
283
        if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
284
                return;                          /* XXX */
285
        ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
286
}
287
 
288
struct rtentry *
289
rtalloc1(dst, report)
290
        register struct sockaddr *dst;
291
        int report;
292
{
293
        register struct radix_node_head *rnh = rt_tables[dst->sa_family];
294
        register struct rtentry *rt;
295
        register struct radix_node *rn;
296
        struct rtentry *newrt = 0;
297
        struct rt_addrinfo info;
298
        int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
299
 
300
        if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
301
            ((rn->rn_flags & RNF_ROOT) == 0)) {
302
                newrt = rt = (struct rtentry *)rn;
303
                if (report && (rt->rt_flags & RTF_CLONING)) {
304
                        err = rtrequest(RTM_RESOLVE, dst, SA(NULL),
305
                            SA(NULL), 0, &newrt);
306
                        if (err) {
307
                                newrt = rt;
308
                                rt->rt_refcnt++;
309
                                goto miss;
310
                        }
311
                        if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
312
                                msgtype = RTM_RESOLVE;
313
                                goto miss;
314
                        }
315
                } else
316
                        rt->rt_refcnt++;
317
        } else {
318
                if (dst->sa_family != PF_KEY)
319
                        rtstat.rts_unreach++;
320
        /*
321
         * IP encapsulation does lots of lookups where we don't need nor want
322
         * the RTM_MISSes that would be generated.  It causes RTM_MISS storms
323
         * sent upward breaking user-level routing queries.
324
         */
325
        miss:   if (report && dst->sa_family != PF_KEY) {
326
                        bzero((caddr_t)&info, sizeof(info));
327
                        info.rti_info[RTAX_DST] = dst;
328
                        rt_missmsg(msgtype, &info, 0, err);
329
                }
330
        }
331
        splx(s);
332
        return (newrt);
333
}
334
 
335
void
336
rtfree(rt)
337
        register struct rtentry *rt;
338
{
339
        register struct ifaddr *ifa;
340
 
341
        if (rt == NULL)
342
                panic("rtfree");
343
        rt->rt_refcnt--;
344
        if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
345
                if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
346
                        panic ("rtfree 2");
347
                rttrash--;
348
                if (rt->rt_refcnt < 0) {
349
#ifdef __ECOS
350
                        diag_printf("rtfree: %x not freed (neg refs)\n", rt);
351
#else
352
                        printf("rtfree: %x not freed (neg refs)\n", rt);
353
#endif
354
                        return;
355
                }
356
                rt_timer_remove_all(rt);
357
                ifa = rt->rt_ifa;
358
                if (ifa)
359
                        IFAFREE(ifa);
360
                Free(rt_key(rt));
361
                Free(rt);
362
        }
363
}
364
 
365
void
366
ifafree(ifa)
367
        register struct ifaddr *ifa;
368
{
369
        if (ifa == NULL)
370
                panic("ifafree");
371
        if (ifa->ifa_refcnt == 0)
372
                free(ifa, M_IFADDR);
373
        else
374
                ifa->ifa_refcnt--;
375
}
376
 
377
/*
378
 * Force a routing table entry to the specified
379
 * destination to go through the given gateway.
380
 * Normally called as a result of a routing redirect
381
 * message from the network layer.
382
 *
383
 * N.B.: must be called at splsoftnet
384
 */
385
void
386
rtredirect(dst, gateway, netmask, flags, src, rtp)
387
        struct sockaddr *dst, *gateway, *netmask, *src;
388
        int flags;
389
        struct rtentry **rtp;
390
{
391
        register struct rtentry *rt;
392
        int error = 0;
393
        u_int32_t *stat = NULL;
394
        struct rt_addrinfo info;
395
        struct ifaddr *ifa;
396
 
397
        /* verify the gateway is directly reachable */
398
        if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
399
                error = ENETUNREACH;
400
                goto out;
401
        }
402
        rt = rtalloc1(dst, 0);
403
        /*
404
         * If the redirect isn't from our current router for this dst,
405
         * it's either old or wrong.  If it redirects us to ourselves,
406
         * we have a routing loop, perhaps as a result of an interface
407
         * going down recently.
408
         */
409
#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
410
        if (!(flags & RTF_DONE) && rt &&
411
             (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
412
                error = EINVAL;
413
        else if (ifa_ifwithaddr(gateway) != NULL)
414
                error = EHOSTUNREACH;
415
        if (error)
416
                goto done;
417
        /*
418
         * Create a new entry if we just got back a wildcard entry
419
         * or the the lookup failed.  This is necessary for hosts
420
         * which use routing redirects generated by smart gateways
421
         * to dynamically build the routing tables.
422
         */
423
        if ((rt == NULL) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
424
                goto create;
425
        /*
426
         * Don't listen to the redirect if it's
427
         * for a route to an interface.
428
         */
429
        if (rt->rt_flags & RTF_GATEWAY) {
430
                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
431
                        /*
432
                         * Changing from route to net => route to host.
433
                         * Create new route, rather than smashing route to net.
434
                         */
435
                create:
436
                        flags |=  RTF_GATEWAY | RTF_DYNAMIC;
437
                        error = rtrequest((int)RTM_ADD, dst, gateway,
438
                                    netmask, flags,
439
                                    (struct rtentry **)0);
440
                        stat = &rtstat.rts_dynamic;
441
                } else {
442
                        /*
443
                         * Smash the current notion of the gateway to
444
                         * this destination.  Should check about netmask!!!
445
                         */
446
                        rt->rt_flags |= RTF_MODIFIED;
447
                        flags |= RTF_MODIFIED;
448
                        stat = &rtstat.rts_newgateway;
449
                        rt_setgate(rt, rt_key(rt), gateway);
450
                }
451
        } else
452
                error = EHOSTUNREACH;
453
done:
454
        if (rt) {
455
                if (rtp && !error)
456
                        *rtp = rt;
457
                else
458
                        rtfree(rt);
459
        }
460
out:
461
        if (error)
462
                rtstat.rts_badredirect++;
463
        else if (stat != NULL)
464
                (*stat)++;
465
        bzero((caddr_t)&info, sizeof(info));
466
        info.rti_info[RTAX_DST] = dst;
467
        info.rti_info[RTAX_GATEWAY] = gateway;
468
        info.rti_info[RTAX_NETMASK] = netmask;
469
        info.rti_info[RTAX_AUTHOR] = src;
470
        rt_missmsg(RTM_REDIRECT, &info, flags, error);
471
}
472
 
473
/*
474
* Routing table ioctl interface.
475
*/
476
int
477
rtioctl(req, data, p)
478
        u_long req;
479
        caddr_t data;
480
        struct proc *p;
481
{
482
#ifdef __ECOS
483
    struct ecos_rtentry *rt;
484
    int res;
485
 
486
    switch (req) {
487
    case SIOCADDRT:
488
        rt = (struct ecos_rtentry *)data;
489
        res = rtrequest(RTM_ADD,
490
                        &rt->rt_dst,
491
                        &rt->rt_gateway,
492
                        &rt->rt_genmask,
493
                        rt->rt_flags,
494
                        NULL);
495
        return (res);
496
    case SIOCDELRT:
497
        rt = (struct ecos_rtentry *)data;
498
        res = rtrequest(RTM_DELETE,
499
                        &rt->rt_dst,
500
                        &rt->rt_gateway,
501
                        &rt->rt_genmask,
502
                        rt->rt_flags,
503
                        NULL);
504
        return (res);
505
    default:
506
        return (EOPNOTSUPP);
507
    }
508
#else
509
    return (EOPNOTSUPP);
510
#endif
511
}
512
 
513
struct ifaddr *
514
ifa_ifwithroute(flags, dst, gateway)
515
        int flags;
516
        struct sockaddr *dst, *gateway;
517
{
518
        register struct ifaddr *ifa;
519
 
520
#ifdef IPSEC
521
        /*
522
         * If the destination is a PF_KEY address, we'll look
523
         * for the existence of a encap interface number or address
524
         * in the options list of the gateway. By default, we'll return
525
         * enc0.
526
         */
527
        if (dst && (dst->sa_family == PF_KEY))
528
                return encap_findgwifa(gateway);
529
#endif
530
 
531
        if ((flags & RTF_GATEWAY) == 0) {
532
                /*
533
                 * If we are adding a route to an interface,
534
                 * and the interface is a pt to pt link
535
                 * we should search for the destination
536
                 * as our clue to the interface.  Otherwise
537
                 * we can use the local address.
538
                 */
539
                ifa = NULL;
540
                if (flags & RTF_HOST)
541
                        ifa = ifa_ifwithdstaddr(dst);
542
                if (ifa == NULL)
543
                        ifa = ifa_ifwithaddr(gateway);
544
        } else {
545
                /*
546
                 * If we are adding a route to a remote net
547
                 * or host, the gateway may still be on the
548
                 * other end of a pt to pt link.
549
                 */
550
                ifa = ifa_ifwithdstaddr(gateway);
551
        }
552
        if (ifa == NULL)
553
                ifa = ifa_ifwithnet(gateway);
554
        if (ifa == NULL) {
555
                struct rtentry *rt = rtalloc1(gateway, 0);
556
                if (rt == NULL)
557
                        return (NULL);
558
                rt->rt_refcnt--;
559
                /* The gateway must be local if the same address family. */
560
                if (!(flags & RTF_TUNNEL) && (rt->rt_flags & RTF_GATEWAY) &&
561
                    rt_key(rt)->sa_family == dst->sa_family)
562
                        return (0);
563
                if ((ifa = rt->rt_ifa) == NULL)
564
                        return (NULL);
565
        }
566
        if (ifa->ifa_addr->sa_family != dst->sa_family) {
567
                struct ifaddr *oifa = ifa;
568
                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
569
                if (ifa == NULL)
570
                        ifa = oifa;
571
        }
572
        return (ifa);
573
}
574
 
575
#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
576
 
577
const char *
578
_rt_cmd(int req)
579
{
580
    switch (req)
581
    {
582
    case RTM_DELETE:
583
        return "DELETE";
584
    case RTM_RESOLVE:
585
        return "RESOLVE";
586
    case RTM_ADD:
587
        return "ADD";
588
    default:
589
        return "???";
590
    }
591
}
592
 
593
int
594
rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
595
        int req, flags;
596
        struct sockaddr *dst, *gateway, *netmask;
597
        struct rtentry **ret_nrt;
598
{
599
        int s = splsoftnet(); int error = 0;
600
        register struct rtentry *rt;
601
        register struct radix_node *rn;
602
        register struct radix_node_head *rnh;
603
        struct ifaddr *ifa;
604
        struct sockaddr *ndst;
605
#define senderr(x) { error = x ; goto bad; }
606
 
607
        if ((rnh = rt_tables[dst->sa_family]) == 0)
608
                senderr(EAFNOSUPPORT);
609
        if (flags & RTF_HOST)
610
                netmask = 0;
611
        switch (req) {
612
        case RTM_DELETE:
613
                if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)
614
                        senderr(ESRCH);
615
                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
616
                        panic ("rtrequest delete");
617
                rt = (struct rtentry *)rn;
618
                rt->rt_flags &= ~RTF_UP;
619
                if (rt->rt_gwroute) {
620
                    if (rt != rt->rt_gwroute)
621
                        RTFREE( rt->rt_gwroute ); // Free it up as normal
622
                    else
623
                        rt->rt_refcnt--; // Just dec the refcount - freeing
624
                                         // it here would be premature
625
                    rt->rt_gwroute = NULL;
626
                }
627
                if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
628
                        ifa->ifa_rtrequest(RTM_DELETE, rt, SA(NULL));
629
                rttrash++;
630
                if (ret_nrt)
631
                        *ret_nrt = rt;
632
                else if (rt->rt_refcnt <= 0) {
633
                        rt->rt_refcnt++;
634
                        rtfree(rt);
635
                }
636
                break;
637
 
638
        case RTM_RESOLVE:
639
                if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
640
                        senderr(EINVAL);
641
                ifa = rt->rt_ifa;
642
                flags = rt->rt_flags & ~RTF_CLONING;
643
                gateway = rt->rt_gateway;
644
                if ((netmask = rt->rt_genmask) == NULL)
645
                        flags |= RTF_HOST;
646
                goto makeroute;
647
 
648
        case RTM_ADD:
649
                if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == NULL)
650
                        senderr(ENETUNREACH);
651
 
652
                /* The interface found in the previous statement may
653
                 * be overridden later by rt_setif.  See the code
654
                 * for case RTM_ADD in rtsock.c:route_output.
655
                 */
656
        makeroute:
657
                R_Malloc(rt, struct rtentry *, sizeof(*rt));
658
                if (rt == NULL)
659
                        senderr(ENOBUFS);
660
                Bzero(rt, sizeof(*rt));
661
                rt->rt_flags = RTF_UP | flags;
662
                LIST_INIT(&rt->rt_timer);
663
                if (rt_setgate(rt, dst, gateway)) {
664
                        Free(rt);
665
                        senderr(ENOBUFS);
666
                }
667
                ndst = rt_key(rt);
668
                if (netmask) {
669
                        rt_maskedcopy(dst, ndst, netmask);
670
                } else
671
                        Bcopy(dst, ndst, dst->sa_len);
672
if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { /* XXX */
673
  rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;
674
}
675
                rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
676
                                        rnh, rt->rt_nodes);
677
                if (rn == NULL) {
678
                        if (rt->rt_gwroute)
679
                                rtfree(rt->rt_gwroute);
680
                        Free(rt_key(rt));
681
                        Free(rt);
682
                        senderr(EEXIST);
683
                }
684
                ifa->ifa_refcnt++;
685
                rt->rt_ifa = ifa;
686
                rt->rt_ifp = ifa->ifa_ifp;
687
                if (req == RTM_RESOLVE) {
688
                        /*
689
                         * Copy both metrics and a back pointer to the cloned
690
                         * route's parent.
691
                         */
692
                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
693
                        rt->rt_parent = *ret_nrt;        /* Back ptr. to parent. */
694
                }
695
                if (ifa->ifa_rtrequest)
696
                        ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : NULL));
697
                if (ret_nrt) {
698
                        *ret_nrt = rt;
699
                        rt->rt_refcnt++;
700
                }
701
#ifdef INET6
702
                /* If we have a v4_in_v4 or a v4_in_v6 tunnel route
703
                 * then do some tunnel state (e.g. security state)
704
                 * initialization.
705
                 *
706
                 * Since IPV6 packets flow down this path, we don't
707
                 * want it using ipv4_tunnelsetup(rt) (since they
708
                 * have their own ipv6_tunnel_parent/child()
709
                 * routines which are called ipv6_rtrequest().)
710
                 *
711
                 * Thus, we check to see if the packet is to a v4
712
                 * destination.
713
                 */
714
                if (dst->sa_family == AF_INET && (rt->rt_flags & RTF_TUNNEL))
715
                        ipv4_tunnelsetup(rt);
716
#endif /* INET6 */
717
                break;
718
        }
719
bad:
720
        splx(s);
721
        return (error);
722
}
723
 
724
/*
725
 * Set up any tunnel states (e.g. security) information
726
 * for v4_in_v4 or v4_in_v6 tunnel routes.
727
 */
728
void
729
ipv4_tunnelsetup(rt)
730
        register struct rtentry *rt;
731
{
732
        /* XXX */
733
}
734
 
735
int
736
rt_setgate(rt0, dst, gate)
737
        struct rtentry *rt0;
738
        struct sockaddr *dst, *gate;
739
{
740
        caddr_t new, old;
741
        int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
742
        register struct rtentry *rt = rt0;
743
 
744
        if (rt->rt_gateway == NULL || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
745
                old = (caddr_t)rt_key(rt);
746
                R_Malloc(new, caddr_t, dlen + glen);
747
                if (new == NULL)
748
                        return 1;
749
                rt->rt_nodes->rn_key = new;
750
        } else {
751
                new = rt->rt_nodes->rn_key;
752
                old = NULL;
753
        }
754
        Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
755
        if (old) {
756
                Bcopy(dst, new, dlen);
757
                Free(old);
758
        }
759
        if (rt->rt_gwroute != NULL) {
760
                rt = rt->rt_gwroute;
761
                RTFREE(rt);
762
                rt = rt0;
763
                rt->rt_gwroute = NULL;
764
        }
765
        if (rt->rt_flags & RTF_GATEWAY) {
766
                rt->rt_gwroute = rtalloc1(gate, 1);
767
        }
768
        return 0;
769
}
770
 
771
void
772
rt_maskedcopy(src, dst, netmask)
773
        struct sockaddr *src, *dst, *netmask;
774
{
775
        register u_char *cp1 = (u_char *)src;
776
        register u_char *cp2 = (u_char *)dst;
777
        register u_char *cp3 = (u_char *)netmask;
778
        u_char *cplim = cp2 + *cp3;
779
        u_char *cplim2 = cp2 + *cp1;
780
 
781
        *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
782
        cp3 += 2;
783
        if (cplim > cplim2)
784
                cplim = cplim2;
785
        while (cp2 < cplim)
786
                *cp2++ = *cp1++ & *cp3++;
787
        if (cp2 < cplim2)
788
                bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
789
}
790
 
791
/*
792
 * Set up a routing table entry, normally
793
 * for an interface.
794
 */
795
int
796
rtinit(ifa, cmd, flags)
797
        register struct ifaddr *ifa;
798
        int cmd, flags;
799
{
800
        register struct rtentry *rt;
801
        register struct sockaddr *dst;
802
        register struct sockaddr *deldst;
803
        struct mbuf *m = NULL;
804
        struct rtentry *nrt = NULL;
805
        int error;
806
 
807
        dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
808
        if (cmd == RTM_DELETE) {
809
                if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
810
                        m = m_get(M_DONTWAIT, MT_SONAME);
811
                        if (m == NULL)
812
                                return(ENOBUFS);
813
                        deldst = mtod(m, struct sockaddr *);
814
                        rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
815
                        dst = deldst;
816
                }
817
                if ((rt = rtalloc1(dst, 0)) != NULL) {
818
                        rt->rt_refcnt--;
819
                        if (rt->rt_ifa != ifa) {
820
                                if (m != NULL)
821
                                        (void) m_free(m);
822
                                return (flags & RTF_HOST ? EHOSTUNREACH
823
                                                        : ENETUNREACH);
824
                        }
825
                }
826
        }
827
        error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
828
                        flags | ifa->ifa_flags, &nrt);
829
        if (m != NULL)
830
                (void) m_free(m);
831
        if (cmd == RTM_DELETE && error == 0 && (rt = nrt) != NULL) {
832
                rt_newaddrmsg(cmd, ifa, error, nrt);
833
                if (rt->rt_refcnt <= 0) {
834
                        rt->rt_refcnt++;
835
                        rtfree(rt);
836
                }
837
        }
838
        if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) {
839
                rt->rt_refcnt--;
840
#ifdef INET6
841
                /* Initialize Path MTU for IPv6 interface route */
842
                if (ifa->ifa_addr->sa_family == AF_INET6 &&
843
                    !rt->rt_rmx.rmx_mtu)
844
                        rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;
845
#endif /* INET6 */
846
                if (rt->rt_ifa != ifa) {
847
#ifdef __ECOS
848
                        diag_printf("rtinit: wrong ifa (%x) was (%x)\n",
849
                               ifa, rt->rt_ifa);
850
#else
851
                        printf("rtinit: wrong ifa (%x) was (%x)\n",
852
                               ifa, rt->rt_ifa);
853
#endif
854
                        if (rt->rt_ifa->ifa_rtrequest)
855
                                rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
856
                                    SA(NULL));
857
                        IFAFREE(rt->rt_ifa);
858
                        rt->rt_ifa = ifa;
859
                        rt->rt_ifp = ifa->ifa_ifp;
860
                        rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;      /*XXX*/
861
                        ifa->ifa_refcnt++;
862
                        if (ifa->ifa_rtrequest)
863
                                ifa->ifa_rtrequest(RTM_ADD, rt, SA(NULL));
864
                }
865
                rt_newaddrmsg(cmd, ifa, error, nrt);
866
        }
867
        return (error);
868
}
869
 
870
/*
871
 * Route timer routines.  These routes allow functions to be called
872
 * for various routes at any time.  This is useful in supporting
873
 * path MTU discovery and redirect route deletion.
874
 *
875
 * This is similar to some BSDI internal functions, but it provides
876
 * for multiple queues for efficiency's sake...
877
 */
878
 
879
LIST_HEAD(, rttimer_queue) rttimer_queue_head;
880
static int rt_init_done = 0;
881
 
882
#define RTTIMER_CALLOUT(r)      {                               \
883
        if (r->rtt_func != NULL) {                              \
884
                (*r->rtt_func)(r->rtt_rt, r);                   \
885
        } else {                                                \
886
                rtrequest((int) RTM_DELETE,                     \
887
                          (struct sockaddr *)rt_key(r->rtt_rt), \
888
                          0, 0, 0, 0);                              \
889
        }                                                       \
890
}
891
 
892
/*
893
 * Some subtle order problems with domain initialization mean that
894
 * we cannot count on this being run from rt_init before various
895
 * protocol initializations are done.  Therefore, we make sure
896
 * that this is run when the first queue is added...
897
 */
898
 
899
void
900
rt_timer_init()
901
{
902
#ifndef __ECOS
903
        assert(rt_init_done == 0);
904
#endif
905
 
906
#if 0
907
        pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",
908
            0, NULL, NULL, M_RTABLE);
909
#endif
910
 
911
        LIST_INIT(&rttimer_queue_head);
912
        timeout(rt_timer_timer, NULL, hz);  /* every second */
913
        rt_init_done = 1;
914
}
915
 
916
struct rttimer_queue *
917
rt_timer_queue_create(timeout)
918
        u_int   timeout;
919
{
920
        struct rttimer_queue *rtq;
921
 
922
        if (rt_init_done == 0)
923
                rt_timer_init();
924
 
925
        R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
926
        if (rtq == NULL)
927
                return (NULL);
928
 
929
        rtq->rtq_timeout = timeout;
930
        TAILQ_INIT(&rtq->rtq_head);
931
        LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
932
 
933
        return (rtq);
934
}
935
 
936
void
937
rt_timer_queue_change(rtq, timeout)
938
        struct rttimer_queue *rtq;
939
        long timeout;
940
{
941
 
942
        rtq->rtq_timeout = timeout;
943
}
944
 
945
 
946
void
947
rt_timer_queue_destroy(rtq, destroy)
948
        struct rttimer_queue *rtq;
949
        int destroy;
950
{
951
        struct rttimer *r;
952
 
953
        while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
954
                LIST_REMOVE(r, rtt_link);
955
                TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
956
                if (destroy)
957
                        RTTIMER_CALLOUT(r);
958
#if 0
959
                pool_put(&rttimer_pool, r);
960
#else
961
                free(r, M_RTABLE);
962
#endif
963
        }
964
 
965
        LIST_REMOVE(rtq, rtq_link);
966
 
967
        /*
968
         * Caller is responsible for freeing the rttimer_queue structure.
969
         */
970
}
971
 
972
void
973
rt_timer_remove_all(rt)
974
        struct rtentry *rt;
975
{
976
        struct rttimer *r;
977
 
978
        while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
979
                LIST_REMOVE(r, rtt_link);
980
                TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
981
#if 0
982
                pool_put(&rttimer_pool, r);
983
#else
984
                free(r, M_RTABLE);
985
#endif
986
        }
987
}
988
 
989
int
990
rt_timer_add(rt, func, queue)
991
        struct rtentry *rt;
992
        void(*func) __P((struct rtentry *, struct rttimer *));
993
        struct rttimer_queue *queue;
994
{
995
        struct rttimer *r;
996
        long current_time;
997
        int s;
998
 
999
        s = splclock();
1000
#ifdef __ECOS
1001
        get_mono_time();
1002
#endif
1003
        current_time = mono_time.tv_sec;
1004
        splx(s);
1005
 
1006
        /*
1007
         * If there's already a timer with this action, destroy it before
1008
         * we add a new one.
1009
         */
1010
        for (r = LIST_FIRST(&rt->rt_timer); r != NULL;
1011
             r = LIST_NEXT(r, rtt_link)) {
1012
                if (r->rtt_func == func) {
1013
                        LIST_REMOVE(r, rtt_link);
1014
                        TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1015
#if 0
1016
                        pool_put(&rttimer_pool, r);
1017
#else
1018
                        free(r, M_RTABLE);
1019
#endif
1020
                        break;  /* only one per list, so we can quit... */
1021
                }
1022
        }
1023
 
1024
#if 0
1025
        r = pool_get(&rttimer_pool, PR_NOWAIT);
1026
#else
1027
        r = (struct rttimer *)malloc(sizeof(*r), M_RTABLE, M_NOWAIT);
1028
#endif
1029
        if (r == NULL)
1030
                return (ENOBUFS);
1031
 
1032
        r->rtt_rt = rt;
1033
        r->rtt_time = current_time;
1034
        r->rtt_func = func;
1035
        r->rtt_queue = queue;
1036
        LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
1037
        TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1038
 
1039
        return (0);
1040
}
1041
 
1042
/* ARGSUSED */
1043
void
1044
rt_timer_timer(arg)
1045
        void *arg;
1046
{
1047
        struct rttimer_queue *rtq;
1048
        struct rttimer *r;
1049
        long current_time;
1050
        int s;
1051
 
1052
        s = splclock();
1053
#ifdef __ECOS
1054
        get_mono_time();
1055
#endif
1056
        current_time = mono_time.tv_sec;
1057
        splx(s);
1058
 
1059
        s = splsoftnet();
1060
        for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
1061
             rtq = LIST_NEXT(rtq, rtq_link)) {
1062
                while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1063
                    (r->rtt_time + rtq->rtq_timeout) < current_time) {
1064
                        LIST_REMOVE(r, rtt_link);
1065
                        TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1066
                        RTTIMER_CALLOUT(r);
1067
#if 0
1068
                        pool_put(&rttimer_pool, r);
1069
#else
1070
                        free(r, M_RTABLE);
1071
#endif
1072
                }
1073
        }
1074
        splx(s);
1075
 
1076
        timeout(rt_timer_timer, NULL, hz);  /* every second */
1077
}

powered by: WebSVN 2.1.0

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