source: rtems-libbsd/freebsd/sys/net/route.c @ 09bbedc

55-freebsd-126-freebsd-12
Last change on this file since 09bbedc was 0237319, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/17 at 11:18:31

Update due to Newlib 2017-06-07 changes

The following files are now provided by Newlib:

  • arpa/inet.h
  • net/if.h
  • netinet/in.h
  • netinet/tcp.h
  • sys/socket.h
  • sys/uio.h
  • sys/un.h

The <sys/param.h> and <sys/cpuset.h> are now compatible enough to be
used directly.

Update #2833.

  • Property mode set to 100644
File size: 55.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 1980, 1986, 1991, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)route.c     8.3.1.1 (Berkeley) 2/23/95
32 * $FreeBSD$
33 */
34/************************************************************************
35 * Note: In this file a 'fib' is a "forwarding information base"        *
36 * Which is the new name for an in kernel routing (next hop) table.     *
37 ***********************************************************************/
38
39#include <rtems/bsd/local/opt_inet.h>
40#include <rtems/bsd/local/opt_inet6.h>
41#include <rtems/bsd/local/opt_route.h>
42#include <rtems/bsd/local/opt_sctp.h>
43#include <rtems/bsd/local/opt_mrouting.h>
44#include <rtems/bsd/local/opt_mpath.h>
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/socket.h>
51#include <sys/sysctl.h>
52#include <sys/syslog.h>
53#include <sys/sysproto.h>
54#include <sys/proc.h>
55#include <sys/domain.h>
56#include <sys/kernel.h>
57
58#include <net/if.h>
59#include <net/if_var.h>
60#include <net/if_dl.h>
61#include <net/route.h>
62#include <net/route_var.h>
63#include <net/vnet.h>
64#include <net/flowtable.h>
65
66#ifdef RADIX_MPATH
67#include <net/radix_mpath.h>
68#endif
69
70#include <netinet/in.h>
71#include <netinet/ip_mroute.h>
72
73#include <vm/uma.h>
74#ifdef __rtems__
75#include <machine/rtems-bsd-syscall-api.h>
76#include <sys/file.h>
77#endif /* __rtems__ */
78
79#define RT_MAXFIBS      UINT16_MAX
80
81/* Kernel config default option. */
82#ifdef ROUTETABLES
83#if ROUTETABLES <= 0
84#error "ROUTETABLES defined too low"
85#endif
86#if ROUTETABLES > RT_MAXFIBS
87#error "ROUTETABLES defined too big"
88#endif
89#define RT_NUMFIBS      ROUTETABLES
90#endif /* ROUTETABLES */
91/* Initialize to default if not otherwise set. */
92#ifndef RT_NUMFIBS
93#define RT_NUMFIBS      1
94#endif
95
96#if defined(INET) || defined(INET6)
97#ifdef SCTP
98extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
99#endif /* SCTP */
100#endif
101
102
103/* This is read-only.. */
104u_int rt_numfibs = RT_NUMFIBS;
105SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RDTUN, &rt_numfibs, 0, "");
106
107/*
108 * By default add routes to all fibs for new interfaces.
109 * Once this is set to 0 then only allocate routes on interface
110 * changes for the FIB of the caller when adding a new set of addresses
111 * to an interface.  XXX this is a shotgun aproach to a problem that needs
112 * a more fine grained solution.. that will come.
113 * XXX also has the problems getting the FIB from curthread which will not
114 * always work given the fib can be overridden and prefixes can be added
115 * from the network stack context.
116 */
117VNET_DEFINE(u_int, rt_add_addr_allfibs) = 1;
118SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET,
119    &VNET_NAME(rt_add_addr_allfibs), 0, "");
120
121VNET_DEFINE(struct rtstat, rtstat);
122#define V_rtstat        VNET(rtstat)
123
124VNET_DEFINE(struct rib_head *, rt_tables);
125#define V_rt_tables     VNET(rt_tables)
126
127VNET_DEFINE(int, rttrash);              /* routes not in table but not freed */
128#define V_rttrash       VNET(rttrash)
129
130
131/*
132 * Convert a 'struct radix_node *' to a 'struct rtentry *'.
133 * The operation can be done safely (in this code) because a
134 * 'struct rtentry' starts with two 'struct radix_node''s, the first
135 * one representing leaf nodes in the routing tree, which is
136 * what the code in radix.c passes us as a 'struct radix_node'.
137 *
138 * But because there are a lot of assumptions in this conversion,
139 * do not cast explicitly, but always use the macro below.
140 */
141#define RNTORT(p)       ((struct rtentry *)(p))
142
143static VNET_DEFINE(uma_zone_t, rtzone);         /* Routing table UMA zone. */
144#define V_rtzone        VNET(rtzone)
145
146static int rtrequest1_fib_change(struct rib_head *, struct rt_addrinfo *,
147    struct rtentry **, u_int);
148static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *);
149static int rt_ifdelroute(const struct rtentry *rt, void *arg);
150static struct rtentry *rt_unlinkrte(struct rib_head *rnh,
151    struct rt_addrinfo *info, int *perror);
152static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info);
153#ifdef RADIX_MPATH
154static struct radix_node *rt_mpath_unlink(struct rib_head *rnh,
155    struct rt_addrinfo *info, struct rtentry *rto, int *perror);
156#endif
157static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info,
158    int flags);
159
160struct if_mtuinfo
161{
162        struct ifnet    *ifp;
163        int             mtu;
164};
165
166static int      if_updatemtu_cb(struct radix_node *, void *);
167
168/*
169 * handler for net.my_fibnum
170 */
171static int
172sysctl_my_fibnum(SYSCTL_HANDLER_ARGS)
173{
174        int fibnum;
175        int error;
176 
177#ifndef __rtems__
178        fibnum = curthread->td_proc->p_fibnum;
179#else /* __rtems__ */
180        fibnum = BSD_DEFAULT_FIB;
181#endif /* __rtems__ */
182        error = sysctl_handle_int(oidp, &fibnum, 0, req);
183        return (error);
184}
185
186SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD,
187            NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller");
188
189static __inline struct rib_head **
190rt_tables_get_rnh_ptr(int table, int fam)
191{
192        struct rib_head **rnh;
193
194        KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.",
195            __func__));
196        KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.",
197            __func__));
198
199        /* rnh is [fib=0][af=0]. */
200        rnh = (struct rib_head **)V_rt_tables;
201        /* Get the offset to the requested table and fam. */
202        rnh += table * (AF_MAX+1) + fam;
203
204        return (rnh);
205}
206
207struct rib_head *
208rt_tables_get_rnh(int table, int fam)
209{
210
211        return (*rt_tables_get_rnh_ptr(table, fam));
212}
213
214u_int
215rt_tables_get_gen(int table, int fam)
216{
217        struct rib_head *rnh;
218
219        rnh = *rt_tables_get_rnh_ptr(table, fam);
220        KASSERT(rnh != NULL, ("%s: NULL rib_head pointer table %d fam %d",
221            __func__, table, fam));
222        return (rnh->rnh_gen);
223}
224
225
226/*
227 * route initialization must occur before ip6_init2(), which happenas at
228 * SI_ORDER_MIDDLE.
229 */
230static void
231route_init(void)
232{
233
234        /* whack the tunable ints into  line. */
235        if (rt_numfibs > RT_MAXFIBS)
236                rt_numfibs = RT_MAXFIBS;
237        if (rt_numfibs == 0)
238                rt_numfibs = 1;
239}
240SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0);
241
242static int
243rtentry_zinit(void *mem, int size, int how)
244{
245        struct rtentry *rt = mem;
246
247        rt->rt_pksent = counter_u64_alloc(how);
248        if (rt->rt_pksent == NULL)
249                return (ENOMEM);
250
251        RT_LOCK_INIT(rt);
252
253        return (0);
254}
255
256static void
257rtentry_zfini(void *mem, int size)
258{
259        struct rtentry *rt = mem;
260
261        RT_LOCK_DESTROY(rt);
262        counter_u64_free(rt->rt_pksent);
263}
264
265static int
266rtentry_ctor(void *mem, int size, void *arg, int how)
267{
268        struct rtentry *rt = mem;
269
270        bzero(rt, offsetof(struct rtentry, rt_endzero));
271        counter_u64_zero(rt->rt_pksent);
272        rt->rt_chain = NULL;
273
274        return (0);
275}
276
277static void
278rtentry_dtor(void *mem, int size, void *arg)
279{
280        struct rtentry *rt = mem;
281
282        RT_UNLOCK_COND(rt);
283}
284
285static void
286vnet_route_init(const void *unused __unused)
287{
288        struct domain *dom;
289        struct rib_head **rnh;
290        int table;
291        int fam;
292
293        V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) *
294            sizeof(struct rib_head *), M_RTABLE, M_WAITOK|M_ZERO);
295
296        V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry),
297            rtentry_ctor, rtentry_dtor,
298            rtentry_zinit, rtentry_zfini, UMA_ALIGN_PTR, 0);
299        for (dom = domains; dom; dom = dom->dom_next) {
300                if (dom->dom_rtattach == NULL)
301                        continue;
302
303                for  (table = 0; table < rt_numfibs; table++) {
304                        fam = dom->dom_family;
305                        if (table != 0 && fam != AF_INET6 && fam != AF_INET)
306                                break;
307
308                        rnh = rt_tables_get_rnh_ptr(table, fam);
309                        if (rnh == NULL)
310                                panic("%s: rnh NULL", __func__);
311                        dom->dom_rtattach((void **)rnh, 0);
312                }
313        }
314}
315VNET_SYSINIT(vnet_route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH,
316    vnet_route_init, 0);
317
318#ifdef VIMAGE
319static void
320vnet_route_uninit(const void *unused __unused)
321{
322        int table;
323        int fam;
324        struct domain *dom;
325        struct rib_head **rnh;
326
327        for (dom = domains; dom; dom = dom->dom_next) {
328                if (dom->dom_rtdetach == NULL)
329                        continue;
330
331                for (table = 0; table < rt_numfibs; table++) {
332                        fam = dom->dom_family;
333
334                        if (table != 0 && fam != AF_INET6 && fam != AF_INET)
335                                break;
336
337                        rnh = rt_tables_get_rnh_ptr(table, fam);
338                        if (rnh == NULL)
339                                panic("%s: rnh NULL", __func__);
340                        dom->dom_rtdetach((void **)rnh, 0);
341                }
342        }
343
344        free(V_rt_tables, M_RTABLE);
345        uma_zdestroy(V_rtzone);
346}
347VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
348    vnet_route_uninit, 0);
349#endif
350
351struct rib_head *
352rt_table_init(int offset)
353{
354        struct rib_head *rh;
355
356        rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO);
357
358        /* TODO: These details should be hidded inside radix.c */
359        /* Init masks tree */
360        rn_inithead_internal(&rh->head, rh->rnh_nodes, offset);
361        rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0);
362        rh->head.rnh_masks = &rh->rmhead;
363
364        /* Init locks */
365        RIB_LOCK_INIT(rh);
366
367        /* Finally, set base callbacks */
368        rh->rnh_addaddr = rn_addroute;
369        rh->rnh_deladdr = rn_delete;
370        rh->rnh_matchaddr = rn_match;
371        rh->rnh_lookup = rn_lookup;
372        rh->rnh_walktree = rn_walktree;
373        rh->rnh_walktree_from = rn_walktree_from;
374
375        return (rh);
376}
377
378static int
379rt_freeentry(struct radix_node *rn, void *arg)
380{
381        struct radix_head * const rnh = arg;
382        struct radix_node *x;
383
384        x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh);
385        if (x != NULL)
386                R_Free(x);
387        return (0);
388}
389
390void
391rt_table_destroy(struct rib_head *rh)
392{
393
394        rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head);
395
396        /* Assume table is already empty */
397        RIB_LOCK_DESTROY(rh);
398        free(rh, M_RTABLE);
399}
400
401
402#ifndef _SYS_SYSPROTO_H_
403struct setfib_args {
404        int     fibnum;
405};
406#endif
407#ifdef __rtems__
408static
409#endif /* __rtems__ */
410int
411sys_setfib(struct thread *td, struct setfib_args *uap)
412{
413        if (uap->fibnum < 0 || uap->fibnum >= rt_numfibs)
414                return EINVAL;
415#ifndef __rtems__
416        td->td_proc->p_fibnum = uap->fibnum;
417#else /* __rtems__ */
418        if (uap->fibnum != BSD_DEFAULT_FIB)
419                return EINVAL;
420#endif /* __rtems__ */
421        return (0);
422}
423#ifdef __rtems__
424int
425setfib(int fibnum)
426{
427        struct setfib_args ua = {
428                .fibnum = fibnum
429        };
430        int error;
431
432        error = sys_setfib(NULL, &ua);
433
434        return rtems_bsd_error_to_status_and_errno(error);
435}
436#endif /* __rtems__ */
437
438/*
439 * Packet routing routines.
440 */
441void
442rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum)
443{
444        struct rtentry *rt;
445
446        if ((rt = ro->ro_rt) != NULL) {
447                if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP)
448                        return;
449                RTFREE(rt);
450                ro->ro_rt = NULL;
451        }
452        ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, fibnum);
453        if (ro->ro_rt)
454                RT_UNLOCK(ro->ro_rt);
455}
456
457/*
458 * Look up the route that matches the address given
459 * Or, at least try.. Create a cloned route if needed.
460 *
461 * The returned route, if any, is locked.
462 */
463struct rtentry *
464rtalloc1(struct sockaddr *dst, int report, u_long ignflags)
465{
466
467        return (rtalloc1_fib(dst, report, ignflags, RT_DEFAULT_FIB));
468}
469
470struct rtentry *
471rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags,
472                    u_int fibnum)
473{
474        struct rib_head *rh;
475        struct radix_node *rn;
476        struct rtentry *newrt;
477        struct rt_addrinfo info;
478        int err = 0, msgtype = RTM_MISS;
479
480        KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum"));
481        rh = rt_tables_get_rnh(fibnum, dst->sa_family);
482        newrt = NULL;
483        if (rh == NULL)
484                goto miss;
485
486        /*
487         * Look up the address in the table for that Address Family
488         */
489        RIB_RLOCK(rh);
490        rn = rh->rnh_matchaddr(dst, &rh->head);
491        if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
492                newrt = RNTORT(rn);
493                RT_LOCK(newrt);
494                RT_ADDREF(newrt);
495                RIB_RUNLOCK(rh);
496                return (newrt);
497
498        } else
499                RIB_RUNLOCK(rh);
500       
501        /*
502         * Either we hit the root or could not find any match,
503         * which basically means: "cannot get there from here".
504         */
505miss:
506        V_rtstat.rts_unreach++;
507
508        if (report) {
509                /*
510                 * If required, report the failure to the supervising
511                 * Authorities.
512                 * For a delete, this is not an error. (report == 0)
513                 */
514                bzero(&info, sizeof(info));
515                info.rti_info[RTAX_DST] = dst;
516                rt_missmsg_fib(msgtype, &info, 0, err, fibnum);
517        }
518        return (newrt);
519}
520
521/*
522 * Remove a reference count from an rtentry.
523 * If the count gets low enough, take it out of the routing table
524 */
525void
526rtfree(struct rtentry *rt)
527{
528        struct rib_head *rnh;
529
530        KASSERT(rt != NULL,("%s: NULL rt", __func__));
531        rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family);
532        KASSERT(rnh != NULL,("%s: NULL rnh", __func__));
533
534        RT_LOCK_ASSERT(rt);
535
536        /*
537         * The callers should use RTFREE_LOCKED() or RTFREE(), so
538         * we should come here exactly with the last reference.
539         */
540        RT_REMREF(rt);
541        if (rt->rt_refcnt > 0) {
542                log(LOG_DEBUG, "%s: %p has %d refs\n", __func__, rt, rt->rt_refcnt);
543                goto done;
544        }
545
546        /*
547         * On last reference give the "close method" a chance
548         * to cleanup private state.  This also permits (for
549         * IPv4 and IPv6) a chance to decide if the routing table
550         * entry should be purged immediately or at a later time.
551         * When an immediate purge is to happen the close routine
552         * typically calls rtexpunge which clears the RTF_UP flag
553         * on the entry so that the code below reclaims the storage.
554         */
555        if (rt->rt_refcnt == 0 && rnh->rnh_close)
556                rnh->rnh_close((struct radix_node *)rt, &rnh->head);
557
558        /*
559         * If we are no longer "up" (and ref == 0)
560         * then we can free the resources associated
561         * with the route.
562         */
563        if ((rt->rt_flags & RTF_UP) == 0) {
564                if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
565                        panic("rtfree 2");
566                /*
567                 * the rtentry must have been removed from the routing table
568                 * so it is represented in rttrash.. remove that now.
569                 */
570                V_rttrash--;
571#ifdef  DIAGNOSTIC
572                if (rt->rt_refcnt < 0) {
573                        printf("rtfree: %p not freed (neg refs)\n", rt);
574                        goto done;
575                }
576#endif
577                /*
578                 * release references on items we hold them on..
579                 * e.g other routes and ifaddrs.
580                 */
581                if (rt->rt_ifa)
582                        ifa_free(rt->rt_ifa);
583                /*
584                 * The key is separatly alloc'd so free it (see rt_setgate()).
585                 * This also frees the gateway, as they are always malloc'd
586                 * together.
587                 */
588                R_Free(rt_key(rt));
589
590                /*
591                 * and the rtentry itself of course
592                 */
593                uma_zfree(V_rtzone, rt);
594                return;
595        }
596done:
597        RT_UNLOCK(rt);
598}
599
600
601/*
602 * Force a routing table entry to the specified
603 * destination to go through the given gateway.
604 * Normally called as a result of a routing redirect
605 * message from the network layer.
606 */
607void
608rtredirect_fib(struct sockaddr *dst,
609        struct sockaddr *gateway,
610        struct sockaddr *netmask,
611        int flags,
612        struct sockaddr *src,
613        u_int fibnum)
614{
615        struct rtentry *rt;
616        int error = 0;
617        short *stat = NULL;
618        struct rt_addrinfo info;
619        struct ifaddr *ifa;
620        struct rib_head *rnh;
621
622        ifa = NULL;
623        rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
624        if (rnh == NULL) {
625                error = EAFNOSUPPORT;
626                goto out;
627        }
628
629        /* verify the gateway is directly reachable */
630        if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) {
631                error = ENETUNREACH;
632                goto out;
633        }
634        rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */
635        /*
636         * If the redirect isn't from our current router for this dst,
637         * it's either old or wrong.  If it redirects us to ourselves,
638         * we have a routing loop, perhaps as a result of an interface
639         * going down recently.
640         */
641        if (!(flags & RTF_DONE) && rt) {
642                if (!sa_equal(src, rt->rt_gateway)) {
643                        error = EINVAL;
644                        goto done;
645                }
646                if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) {
647                        error = EINVAL;
648                        goto done;
649                }
650        }
651        if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) {
652                error = EHOSTUNREACH;
653                goto done;
654        }
655        /*
656         * Create a new entry if we just got back a wildcard entry
657         * or the lookup failed.  This is necessary for hosts
658         * which use routing redirects generated by smart gateways
659         * to dynamically build the routing tables.
660         */
661        if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
662                goto create;
663        /*
664         * Don't listen to the redirect if it's
665         * for a route to an interface.
666         */
667        if (rt->rt_flags & RTF_GATEWAY) {
668                if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
669                        /*
670                         * Changing from route to net => route to host.
671                         * Create new route, rather than smashing route to net.
672                         */
673                create:
674                        if (rt != NULL)
675                                RTFREE_LOCKED(rt);
676               
677                        flags |= RTF_DYNAMIC;
678                        bzero((caddr_t)&info, sizeof(info));
679                        info.rti_info[RTAX_DST] = dst;
680                        info.rti_info[RTAX_GATEWAY] = gateway;
681                        info.rti_info[RTAX_NETMASK] = netmask;
682                        info.rti_ifa = ifa;
683                        info.rti_flags = flags;
684                        error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
685                        if (rt != NULL) {
686                                RT_LOCK(rt);
687                                flags = rt->rt_flags;
688                        }
689                       
690                        stat = &V_rtstat.rts_dynamic;
691                } else {
692
693                        /*
694                         * Smash the current notion of the gateway to
695                         * this destination.  Should check about netmask!!!
696                         */
697                        if ((flags & RTF_GATEWAY) == 0)
698                                rt->rt_flags &= ~RTF_GATEWAY;
699                        rt->rt_flags |= RTF_MODIFIED;
700                        flags |= RTF_MODIFIED;
701                        stat = &V_rtstat.rts_newgateway;
702                        /*
703                         * add the key and gateway (in one malloc'd chunk).
704                         */
705                        RT_UNLOCK(rt);
706                        RIB_WLOCK(rnh);
707                        RT_LOCK(rt);
708                        rt_setgate(rt, rt_key(rt), gateway);
709                        RIB_WUNLOCK(rnh);
710                }
711        } else
712                error = EHOSTUNREACH;
713done:
714        if (rt)
715                RTFREE_LOCKED(rt);
716out:
717        if (error)
718                V_rtstat.rts_badredirect++;
719        else if (stat != NULL)
720                (*stat)++;
721        bzero((caddr_t)&info, sizeof(info));
722        info.rti_info[RTAX_DST] = dst;
723        info.rti_info[RTAX_GATEWAY] = gateway;
724        info.rti_info[RTAX_NETMASK] = netmask;
725        info.rti_info[RTAX_AUTHOR] = src;
726        rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum);
727        if (ifa != NULL)
728                ifa_free(ifa);
729}
730
731/*
732 * Routing table ioctl interface.
733 */
734int
735rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
736{
737
738        /*
739         * If more ioctl commands are added here, make sure the proper
740         * super-user checks are being performed because it is possible for
741         * prison-root to make it this far if raw sockets have been enabled
742         * in jails.
743         */
744#ifdef INET
745        /* Multicast goop, grrr... */
746        return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP;
747#else /* INET */
748        return ENXIO;
749#endif /* INET */
750}
751
752struct ifaddr *
753ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway,
754                                u_int fibnum)
755{
756        struct ifaddr *ifa;
757        int not_found = 0;
758
759        if ((flags & RTF_GATEWAY) == 0) {
760                /*
761                 * If we are adding a route to an interface,
762                 * and the interface is a pt to pt link
763                 * we should search for the destination
764                 * as our clue to the interface.  Otherwise
765                 * we can use the local address.
766                 */
767                ifa = NULL;
768                if (flags & RTF_HOST)
769                        ifa = ifa_ifwithdstaddr(dst, fibnum);
770                if (ifa == NULL)
771                        ifa = ifa_ifwithaddr(gateway);
772        } else {
773                /*
774                 * If we are adding a route to a remote net
775                 * or host, the gateway may still be on the
776                 * other end of a pt to pt link.
777                 */
778                ifa = ifa_ifwithdstaddr(gateway, fibnum);
779        }
780        if (ifa == NULL)
781                ifa = ifa_ifwithnet(gateway, 0, fibnum);
782        if (ifa == NULL) {
783                struct rtentry *rt = rtalloc1_fib(gateway, 0, 0, fibnum);
784                if (rt == NULL)
785                        return (NULL);
786                /*
787                 * dismiss a gateway that is reachable only
788                 * through the default router
789                 */
790                switch (gateway->sa_family) {
791                case AF_INET:
792                        if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY)
793                                not_found = 1;
794                        break;
795                case AF_INET6:
796                        if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr))
797                                not_found = 1;
798                        break;
799                default:
800                        break;
801                }
802                if (!not_found && rt->rt_ifa != NULL) {
803                        ifa = rt->rt_ifa;
804                        ifa_ref(ifa);
805                }
806                RT_REMREF(rt);
807                RT_UNLOCK(rt);
808                if (not_found || ifa == NULL)
809                        return (NULL);
810        }
811        if (ifa->ifa_addr->sa_family != dst->sa_family) {
812                struct ifaddr *oifa = ifa;
813                ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
814                if (ifa == NULL)
815                        ifa = oifa;
816                else
817                        ifa_free(oifa);
818        }
819        return (ifa);
820}
821
822/*
823 * Do appropriate manipulations of a routing tree given
824 * all the bits of info needed
825 */
826int
827rtrequest_fib(int req,
828        struct sockaddr *dst,
829        struct sockaddr *gateway,
830        struct sockaddr *netmask,
831        int flags,
832        struct rtentry **ret_nrt,
833        u_int fibnum)
834{
835        struct rt_addrinfo info;
836
837        if (dst->sa_len == 0)
838                return(EINVAL);
839
840        bzero((caddr_t)&info, sizeof(info));
841        info.rti_flags = flags;
842        info.rti_info[RTAX_DST] = dst;
843        info.rti_info[RTAX_GATEWAY] = gateway;
844        info.rti_info[RTAX_NETMASK] = netmask;
845        return rtrequest1_fib(req, &info, ret_nrt, fibnum);
846}
847
848
849/*
850 * Copy most of @rt data into @info.
851 *
852 * If @flags contains NHR_COPY, copies dst,netmask and gw to the
853 * pointers specified by @info structure. Assume such pointers
854 * are zeroed sockaddr-like structures with sa_len field initialized
855 * to reflect size of the provided buffer. if no NHR_COPY is specified,
856 * point dst,netmask and gw @info fields to appropriate @rt values.
857 *
858 * if @flags contains NHR_REF, do refcouting on rt_ifp.
859 *
860 * Returns 0 on success.
861 */
862int
863rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags)
864{
865        struct rt_metrics *rmx;
866        struct sockaddr *src, *dst;
867        int sa_len;
868
869        if (flags & NHR_COPY) {
870                /* Copy destination if dst is non-zero */
871                src = rt_key(rt);
872                dst = info->rti_info[RTAX_DST];
873                sa_len = src->sa_len;
874                if (dst != NULL) {
875                        if (src->sa_len > dst->sa_len)
876                                return (ENOMEM);
877                        memcpy(dst, src, src->sa_len);
878                        info->rti_addrs |= RTA_DST;
879                }
880
881                /* Copy mask if set && dst is non-zero */
882                src = rt_mask(rt);
883                dst = info->rti_info[RTAX_NETMASK];
884                if (src != NULL && dst != NULL) {
885
886                        /*
887                         * Radix stores different value in sa_len,
888                         * assume rt_mask() to have the same length
889                         * as rt_key()
890                         */
891                        if (sa_len > dst->sa_len)
892                                return (ENOMEM);
893                        memcpy(dst, src, src->sa_len);
894                        info->rti_addrs |= RTA_NETMASK;
895                }
896
897                /* Copy gateway is set && dst is non-zero */
898                src = rt->rt_gateway;
899                dst = info->rti_info[RTAX_GATEWAY];
900                if ((rt->rt_flags & RTF_GATEWAY) && src != NULL && dst != NULL){
901                        if (src->sa_len > dst->sa_len)
902                                return (ENOMEM);
903                        memcpy(dst, src, src->sa_len);
904                        info->rti_addrs |= RTA_GATEWAY;
905                }
906        } else {
907                info->rti_info[RTAX_DST] = rt_key(rt);
908                info->rti_addrs |= RTA_DST;
909                if (rt_mask(rt) != NULL) {
910                        info->rti_info[RTAX_NETMASK] = rt_mask(rt);
911                        info->rti_addrs |= RTA_NETMASK;
912                }
913                if (rt->rt_flags & RTF_GATEWAY) {
914                        info->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
915                        info->rti_addrs |= RTA_GATEWAY;
916                }
917        }
918
919        rmx = info->rti_rmx;
920        if (rmx != NULL) {
921                info->rti_mflags |= RTV_MTU;
922                rmx->rmx_mtu = rt->rt_mtu;
923        }
924
925        info->rti_flags = rt->rt_flags;
926        info->rti_ifp = rt->rt_ifp;
927        info->rti_ifa = rt->rt_ifa;
928
929        if (flags & NHR_REF) {
930                /* Do 'traditional' refcouting */
931                if_ref(info->rti_ifp);
932        }
933
934        return (0);
935}
936
937/*
938 * Lookups up route entry for @dst in RIB database for fib @fibnum.
939 * Exports entry data to @info using rt_exportinfo().
940 *
941 * if @flags contains NHR_REF, refcouting is performed on rt_ifp.
942 *   All references can be released later by calling rib_free_info()
943 *
944 * Returns 0 on success.
945 * Returns ENOENT for lookup failure, ENOMEM for export failure.
946 */
947int
948rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags,
949    uint32_t flowid, struct rt_addrinfo *info)
950{
951        struct rib_head *rh;
952        struct radix_node *rn;
953        struct rtentry *rt;
954        int error;
955
956        KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum"));
957        rh = rt_tables_get_rnh(fibnum, dst->sa_family);
958        if (rh == NULL)
959                return (ENOENT);
960
961        RIB_RLOCK(rh);
962        rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head);
963        if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
964                rt = RNTORT(rn);
965                /* Ensure route & ifp is UP */
966                if (RT_LINK_IS_UP(rt->rt_ifp)) {
967                        flags = (flags & NHR_REF) | NHR_COPY;
968                        error = rt_exportinfo(rt, info, flags);
969                        RIB_RUNLOCK(rh);
970
971                        return (error);
972                }
973        }
974        RIB_RUNLOCK(rh);
975
976        return (ENOENT);
977}
978
979/*
980 * Releases all references acquired by rib_lookup_info() when
981 * called with NHR_REF flags.
982 */
983void
984rib_free_info(struct rt_addrinfo *info)
985{
986
987        if_rele(info->rti_ifp);
988}
989
990/*
991 * Iterates over all existing fibs in system calling
992 *  @setwa_f function prior to traversing each fib.
993 *  Calls @wa_f function for each element in current fib.
994 * If af is not AF_UNSPEC, iterates over fibs in particular
995 * address family.
996 */
997void
998rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f,
999    void *arg)
1000{
1001        struct rib_head *rnh;
1002        uint32_t fibnum;
1003        int i;
1004
1005        for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
1006                /* Do we want some specific family? */
1007                if (af != AF_UNSPEC) {
1008                        rnh = rt_tables_get_rnh(fibnum, af);
1009                        if (rnh == NULL)
1010                                continue;
1011                        if (setwa_f != NULL)
1012                                setwa_f(rnh, fibnum, af, arg);
1013
1014                        RIB_WLOCK(rnh);
1015                        rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg);
1016                        RIB_WUNLOCK(rnh);
1017                        continue;
1018                }
1019
1020                for (i = 1; i <= AF_MAX; i++) {
1021                        rnh = rt_tables_get_rnh(fibnum, i);
1022                        if (rnh == NULL)
1023                                continue;
1024                        if (setwa_f != NULL)
1025                                setwa_f(rnh, fibnum, i, arg);
1026
1027                        RIB_WLOCK(rnh);
1028                        rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg);
1029                        RIB_WUNLOCK(rnh);
1030                }
1031        }
1032}
1033
1034struct rt_delinfo
1035{
1036        struct rt_addrinfo info;
1037        struct rib_head *rnh;
1038        struct rtentry *head;
1039};
1040
1041/*
1042 * Conditionally unlinks @rn from radix tree based
1043 * on info data passed in @arg.
1044 */
1045static int
1046rt_checkdelroute(struct radix_node *rn, void *arg)
1047{
1048        struct rt_delinfo *di;
1049        struct rt_addrinfo *info;
1050        struct rtentry *rt;
1051        int error;
1052
1053        di = (struct rt_delinfo *)arg;
1054        rt = (struct rtentry *)rn;
1055        info = &di->info;
1056        error = 0;
1057
1058        info->rti_info[RTAX_DST] = rt_key(rt);
1059        info->rti_info[RTAX_NETMASK] = rt_mask(rt);
1060        info->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1061
1062        rt = rt_unlinkrte(di->rnh, info, &error);
1063        if (rt == NULL) {
1064                /* Either not allowed or not matched. Skip entry */
1065                return (0);
1066        }
1067
1068        /* Entry was unlinked. Add to the list and return */
1069        rt->rt_chain = di->head;
1070        di->head = rt;
1071
1072        return (0);
1073}
1074
1075/*
1076 * Iterates over all existing fibs in system.
1077 * Deletes each element for which @filter_f function returned
1078 * non-zero value.
1079 * If @af is not AF_UNSPEC, iterates over fibs in particular
1080 * address family.
1081 */
1082void
1083rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg)
1084{
1085        struct rib_head *rnh;
1086        struct rt_delinfo di;
1087        struct rtentry *rt;
1088        uint32_t fibnum;
1089        int i, start, end;
1090
1091        bzero(&di, sizeof(di));
1092        di.info.rti_filter = filter_f;
1093        di.info.rti_filterdata = arg;
1094
1095        for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
1096                /* Do we want some specific family? */
1097                if (af != AF_UNSPEC) {
1098                        start = af;
1099                        end = af;
1100                } else {
1101                        start = 1;
1102                        end = AF_MAX;
1103                }
1104
1105                for (i = start; i <= end; i++) {
1106                        rnh = rt_tables_get_rnh(fibnum, i);
1107                        if (rnh == NULL)
1108                                continue;
1109                        di.rnh = rnh;
1110
1111                        RIB_WLOCK(rnh);
1112                        rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
1113                        RIB_WUNLOCK(rnh);
1114
1115                        if (di.head == NULL)
1116                                continue;
1117
1118                        /* We might have something to reclaim */
1119                        while (di.head != NULL) {
1120                                rt = di.head;
1121                                di.head = rt->rt_chain;
1122                                rt->rt_chain = NULL;
1123
1124                                /* TODO std rt -> rt_addrinfo export */
1125                                di.info.rti_info[RTAX_DST] = rt_key(rt);
1126                                di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
1127
1128                                rt_notifydelete(rt, &di.info);
1129                                RTFREE_LOCKED(rt);
1130                        }
1131
1132                }
1133        }
1134}
1135
1136/*
1137 * Delete Routes for a Network Interface
1138 *
1139 * Called for each routing entry via the rnh->rnh_walktree() call above
1140 * to delete all route entries referencing a detaching network interface.
1141 *
1142 * Arguments:
1143 *      rt      pointer to rtentry
1144 *      arg     argument passed to rnh->rnh_walktree() - detaching interface
1145 *
1146 * Returns:
1147 *      0       successful
1148 *      errno   failed - reason indicated
1149 */
1150static int
1151rt_ifdelroute(const struct rtentry *rt, void *arg)
1152{
1153        struct ifnet    *ifp = arg;
1154
1155        if (rt->rt_ifp != ifp)
1156                return (0);
1157
1158        /*
1159         * Protect (sorta) against walktree recursion problems
1160         * with cloned routes
1161         */
1162        if ((rt->rt_flags & RTF_UP) == 0)
1163                return (0);
1164
1165        return (1);
1166}
1167
1168/*
1169 * Delete all remaining routes using this interface
1170 * Unfortuneatly the only way to do this is to slog through
1171 * the entire routing table looking for routes which point
1172 * to this interface...oh well...
1173 */
1174void
1175rt_flushifroutes_af(struct ifnet *ifp, int af)
1176{
1177        KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d",
1178            __func__, af, AF_MAX));
1179
1180        rt_foreach_fib_walk_del(af, rt_ifdelroute, ifp);
1181}
1182
1183void
1184rt_flushifroutes(struct ifnet *ifp)
1185{
1186
1187        rt_foreach_fib_walk_del(AF_UNSPEC, rt_ifdelroute, ifp);
1188}
1189
1190/*
1191 * Conditionally unlinks rtentry matching data inside @info from @rnh.
1192 * Returns unlinked, locked and referenced @rtentry on success,
1193 * Returns NULL and sets @perror to:
1194 * ESRCH - if prefix was not found,
1195 * EADDRINUSE - if trying to delete PINNED route without appropriate flag.
1196 * ENOENT - if supplied filter function returned 0 (not matched).
1197 */
1198static struct rtentry *
1199rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, int *perror)
1200{
1201        struct sockaddr *dst, *netmask;
1202        struct rtentry *rt;
1203        struct radix_node *rn;
1204
1205        dst = info->rti_info[RTAX_DST];
1206        netmask = info->rti_info[RTAX_NETMASK];
1207
1208        rt = (struct rtentry *)rnh->rnh_lookup(dst, netmask, &rnh->head);
1209        if (rt == NULL) {
1210                *perror = ESRCH;
1211                return (NULL);
1212        }
1213
1214        if ((info->rti_flags & RTF_PINNED) == 0) {
1215                /* Check if target route can be deleted */
1216                if (rt->rt_flags & RTF_PINNED) {
1217                        *perror = EADDRINUSE;
1218                        return (NULL);
1219                }
1220        }
1221
1222        if (info->rti_filter != NULL) {
1223                if (info->rti_filter(rt, info->rti_filterdata) == 0) {
1224                        /* Not matched */
1225                        *perror = ENOENT;
1226                        return (NULL);
1227                }
1228
1229                /*
1230                 * Filter function requested rte deletion.
1231                 * Ease the caller work by filling in remaining info
1232                 * from that particular entry.
1233                 */
1234                info->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1235        }
1236
1237        /*
1238         * Remove the item from the tree and return it.
1239         * Complain if it is not there and do no more processing.
1240         */
1241        *perror = ESRCH;
1242#ifdef RADIX_MPATH
1243        if (rt_mpath_capable(rnh))
1244                rn = rt_mpath_unlink(rnh, info, rt, perror);
1245        else
1246#endif
1247        rn = rnh->rnh_deladdr(dst, netmask, &rnh->head);
1248        if (rn == NULL)
1249                return (NULL);
1250
1251        if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
1252                panic ("rtrequest delete");
1253
1254        rt = RNTORT(rn);
1255        RT_LOCK(rt);
1256        RT_ADDREF(rt);
1257        rt->rt_flags &= ~RTF_UP;
1258
1259        *perror = 0;
1260
1261        return (rt);
1262}
1263
1264static void
1265rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info)
1266{
1267        struct ifaddr *ifa;
1268
1269        /*
1270         * give the protocol a chance to keep things in sync.
1271         */
1272        ifa = rt->rt_ifa;
1273        if (ifa != NULL && ifa->ifa_rtrequest != NULL)
1274                ifa->ifa_rtrequest(RTM_DELETE, rt, info);
1275
1276        /*
1277         * One more rtentry floating around that is not
1278         * linked to the routing table. rttrash will be decremented
1279         * when RTFREE(rt) is eventually called.
1280         */
1281        V_rttrash++;
1282}
1283
1284
1285/*
1286 * These (questionable) definitions of apparent local variables apply
1287 * to the next two functions.  XXXXXX!!!
1288 */
1289#define dst     info->rti_info[RTAX_DST]
1290#define gateway info->rti_info[RTAX_GATEWAY]
1291#define netmask info->rti_info[RTAX_NETMASK]
1292#define ifaaddr info->rti_info[RTAX_IFA]
1293#define ifpaddr info->rti_info[RTAX_IFP]
1294#define flags   info->rti_flags
1295
1296/*
1297 * Look up rt_addrinfo for a specific fib.  Note that if rti_ifa is defined,
1298 * it will be referenced so the caller must free it.
1299 */
1300int
1301rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum)
1302{
1303        struct ifaddr *ifa;
1304        int error = 0;
1305
1306        /*
1307         * ifp may be specified by sockaddr_dl
1308         * when protocol address is ambiguous.
1309         */
1310        if (info->rti_ifp == NULL && ifpaddr != NULL &&
1311            ifpaddr->sa_family == AF_LINK &&
1312            (ifa = ifa_ifwithnet(ifpaddr, 0, fibnum)) != NULL) {
1313                info->rti_ifp = ifa->ifa_ifp;
1314                ifa_free(ifa);
1315        }
1316        if (info->rti_ifa == NULL && ifaaddr != NULL)
1317                info->rti_ifa = ifa_ifwithaddr(ifaaddr);
1318        if (info->rti_ifa == NULL) {
1319                struct sockaddr *sa;
1320
1321                sa = ifaaddr != NULL ? ifaaddr :
1322                    (gateway != NULL ? gateway : dst);
1323                if (sa != NULL && info->rti_ifp != NULL)
1324                        info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
1325                else if (dst != NULL && gateway != NULL)
1326                        info->rti_ifa = ifa_ifwithroute(flags, dst, gateway,
1327                                                        fibnum);
1328                else if (sa != NULL)
1329                        info->rti_ifa = ifa_ifwithroute(flags, sa, sa,
1330                                                        fibnum);
1331        }
1332        if ((ifa = info->rti_ifa) != NULL) {
1333                if (info->rti_ifp == NULL)
1334                        info->rti_ifp = ifa->ifa_ifp;
1335        } else
1336                error = ENETUNREACH;
1337        return (error);
1338}
1339
1340static int
1341if_updatemtu_cb(struct radix_node *rn, void *arg)
1342{
1343        struct rtentry *rt;
1344        struct if_mtuinfo *ifmtu;
1345
1346        rt = (struct rtentry *)rn;
1347        ifmtu = (struct if_mtuinfo *)arg;
1348
1349        if (rt->rt_ifp != ifmtu->ifp)
1350                return (0);
1351
1352        if (rt->rt_mtu >= ifmtu->mtu) {
1353                /* We have to decrease mtu regardless of flags */
1354                rt->rt_mtu = ifmtu->mtu;
1355                return (0);
1356        }
1357
1358        /*
1359         * New MTU is bigger. Check if are allowed to alter it
1360         */
1361        if ((rt->rt_flags & (RTF_FIXEDMTU | RTF_GATEWAY | RTF_HOST)) != 0) {
1362
1363                /*
1364                 * Skip routes with user-supplied MTU and
1365                 * non-interface routes
1366                 */
1367                return (0);
1368        }
1369
1370        /* We are safe to update route MTU */
1371        rt->rt_mtu = ifmtu->mtu;
1372
1373        return (0);
1374}
1375
1376void
1377rt_updatemtu(struct ifnet *ifp)
1378{
1379        struct if_mtuinfo ifmtu;
1380        struct rib_head *rnh;
1381        int i, j;
1382
1383        ifmtu.ifp = ifp;
1384
1385        /*
1386         * Try to update rt_mtu for all routes using this interface
1387         * Unfortunately the only way to do this is to traverse all
1388         * routing tables in all fibs/domains.
1389         */
1390        for (i = 1; i <= AF_MAX; i++) {
1391                ifmtu.mtu = if_getmtu_family(ifp, i);
1392                for (j = 0; j < rt_numfibs; j++) {
1393                        rnh = rt_tables_get_rnh(j, i);
1394                        if (rnh == NULL)
1395                                continue;
1396                        RIB_WLOCK(rnh);
1397                        rnh->rnh_walktree(&rnh->head, if_updatemtu_cb, &ifmtu);
1398                        RIB_WUNLOCK(rnh);
1399                }
1400        }
1401}
1402
1403
1404#if 0
1405int p_sockaddr(char *buf, int buflen, struct sockaddr *s);
1406int rt_print(char *buf, int buflen, struct rtentry *rt);
1407
1408int
1409p_sockaddr(char *buf, int buflen, struct sockaddr *s)
1410{
1411        void *paddr = NULL;
1412
1413        switch (s->sa_family) {
1414        case AF_INET:
1415                paddr = &((struct sockaddr_in *)s)->sin_addr;
1416                break;
1417        case AF_INET6:
1418                paddr = &((struct sockaddr_in6 *)s)->sin6_addr;
1419                break;
1420        }
1421
1422        if (paddr == NULL)
1423                return (0);
1424
1425        if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL)
1426                return (0);
1427       
1428        return (strlen(buf));
1429}
1430
1431int
1432rt_print(char *buf, int buflen, struct rtentry *rt)
1433{
1434        struct sockaddr *addr, *mask;
1435        int i = 0;
1436
1437        addr = rt_key(rt);
1438        mask = rt_mask(rt);
1439
1440        i = p_sockaddr(buf, buflen, addr);
1441        if (!(rt->rt_flags & RTF_HOST)) {
1442                buf[i++] = '/';
1443                i += p_sockaddr(buf + i, buflen - i, mask);
1444        }
1445
1446        if (rt->rt_flags & RTF_GATEWAY) {
1447                buf[i++] = '>';
1448                i += p_sockaddr(buf + i, buflen - i, rt->rt_gateway);
1449        }
1450
1451        return (i);
1452}
1453#endif
1454
1455#ifdef RADIX_MPATH
1456/*
1457 * Deletes key for single-path routes, unlinks rtentry with
1458 * gateway specified in @info from multi-path routes.
1459 *
1460 * Returnes unlinked entry. In case of failure, returns NULL
1461 * and sets @perror to ESRCH.
1462 */
1463static struct radix_node *
1464rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info,
1465    struct rtentry *rto, int *perror)
1466{
1467        /*
1468         * if we got multipath routes, we require users to specify
1469         * a matching RTAX_GATEWAY.
1470         */
1471        struct rtentry *rt; // *rto = NULL;
1472        struct radix_node *rn;
1473        struct sockaddr *gw;
1474
1475        gw = info->rti_info[RTAX_GATEWAY];
1476        rt = rt_mpath_matchgate(rto, gw);
1477        if (rt == NULL) {
1478                *perror = ESRCH;
1479                return (NULL);
1480        }
1481
1482        /*
1483         * this is the first entry in the chain
1484         */
1485        if (rto == rt) {
1486                rn = rn_mpath_next((struct radix_node *)rt);
1487                /*
1488                 * there is another entry, now it's active
1489                 */
1490                if (rn) {
1491                        rto = RNTORT(rn);
1492                        RT_LOCK(rto);
1493                        rto->rt_flags |= RTF_UP;
1494                        RT_UNLOCK(rto);
1495                } else if (rt->rt_flags & RTF_GATEWAY) {
1496                        /*
1497                         * For gateway routes, we need to
1498                         * make sure that we we are deleting
1499                         * the correct gateway.
1500                         * rt_mpath_matchgate() does not
1501                         * check the case when there is only
1502                         * one route in the chain. 
1503                         */
1504                        if (gw &&
1505                            (rt->rt_gateway->sa_len != gw->sa_len ||
1506                                memcmp(rt->rt_gateway, gw, gw->sa_len))) {
1507                                *perror = ESRCH;
1508                                return (NULL);
1509                        }
1510                }
1511
1512                /*
1513                 * use the normal delete code to remove
1514                 * the first entry
1515                 */
1516                rn = rnh->rnh_deladdr(dst, netmask, &rnh->head);
1517                *perror = 0;
1518                return (rn);
1519        }
1520               
1521        /*
1522         * if the entry is 2nd and on up
1523         */
1524        if (rt_mpath_deldup(rto, rt) == 0)
1525                panic ("rtrequest1: rt_mpath_deldup");
1526        *perror = 0;
1527        rn = (struct radix_node *)rt;
1528        return (rn);
1529}
1530#endif
1531
1532#ifdef FLOWTABLE
1533static struct rtentry *
1534rt_flowtable_check_route(struct rib_head *rnh, struct rt_addrinfo *info)
1535{
1536#if defined(INET6) || defined(INET)
1537        struct radix_node *rn;
1538#endif
1539        struct rtentry *rt0;
1540
1541        rt0 = NULL;
1542        /* "flow-table" only supports IPv6 and IPv4 at the moment. */
1543        switch (dst->sa_family) {
1544#ifdef INET6
1545        case AF_INET6:
1546#endif
1547#ifdef INET
1548        case AF_INET:
1549#endif
1550#if defined(INET6) || defined(INET)
1551                rn = rnh->rnh_matchaddr(dst, &rnh->head);
1552                if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
1553                        struct sockaddr *mask;
1554                        u_char *m, *n;
1555                        int len;
1556
1557                        /*
1558                         * compare mask to see if the new route is
1559                         * more specific than the existing one
1560                         */
1561                        rt0 = RNTORT(rn);
1562                        RT_LOCK(rt0);
1563                        RT_ADDREF(rt0);
1564                        RT_UNLOCK(rt0);
1565                        /*
1566                         * A host route is already present, so
1567                         * leave the flow-table entries as is.
1568                         */
1569                        if (rt0->rt_flags & RTF_HOST) {
1570                                RTFREE(rt0);
1571                                rt0 = NULL;
1572                        } else if (!(flags & RTF_HOST) && netmask) {
1573                                mask = rt_mask(rt0);
1574                                len = mask->sa_len;
1575                                m = (u_char *)mask;
1576                                n = (u_char *)netmask;
1577                                while (len-- > 0) {
1578                                        if (*n != *m)
1579                                                break;
1580                                        n++;
1581                                        m++;
1582                                }
1583                                if (len == 0 || (*n < *m)) {
1584                                        RTFREE(rt0);
1585                                        rt0 = NULL;
1586                                }
1587                        }
1588                }
1589#endif/* INET6 || INET */
1590        }
1591
1592        return (rt0);
1593}
1594#endif
1595
1596int
1597rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
1598                                u_int fibnum)
1599{
1600        int error = 0;
1601        struct rtentry *rt, *rt_old;
1602#ifdef FLOWTABLE
1603        struct rtentry *rt0;
1604#endif
1605        struct radix_node *rn;
1606        struct rib_head *rnh;
1607        struct ifaddr *ifa;
1608        struct sockaddr *ndst;
1609        struct sockaddr_storage mdst;
1610
1611        KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum"));
1612        KASSERT((flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked"));
1613        switch (dst->sa_family) {
1614        case AF_INET6:
1615        case AF_INET:
1616                /* We support multiple FIBs. */
1617                break;
1618        default:
1619                fibnum = RT_DEFAULT_FIB;
1620                break;
1621        }
1622
1623        /*
1624         * Find the correct routing tree to use for this Address Family
1625         */
1626        rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
1627        if (rnh == NULL)
1628                return (EAFNOSUPPORT);
1629
1630        /*
1631         * If we are adding a host route then we don't want to put
1632         * a netmask in the tree, nor do we want to clone it.
1633         */
1634        if (flags & RTF_HOST)
1635                netmask = NULL;
1636
1637        switch (req) {
1638        case RTM_DELETE:
1639                if (netmask) {
1640                        rt_maskedcopy(dst, (struct sockaddr *)&mdst, netmask);
1641                        dst = (struct sockaddr *)&mdst;
1642                }
1643
1644                RIB_WLOCK(rnh);
1645                rt = rt_unlinkrte(rnh, info, &error);
1646                RIB_WUNLOCK(rnh);
1647                if (error != 0)
1648                        return (error);
1649
1650                rt_notifydelete(rt, info);
1651
1652                /*
1653                 * If the caller wants it, then it can have it,
1654                 * but it's up to it to free the rtentry as we won't be
1655                 * doing it.
1656                 */
1657                if (ret_nrt) {
1658                        *ret_nrt = rt;
1659                        RT_UNLOCK(rt);
1660                } else
1661                        RTFREE_LOCKED(rt);
1662                break;
1663        case RTM_RESOLVE:
1664                /*
1665                 * resolve was only used for route cloning
1666                 * here for compat
1667                 */
1668                break;
1669        case RTM_ADD:
1670                if ((flags & RTF_GATEWAY) && !gateway)
1671                        return (EINVAL);
1672                if (dst && gateway && (dst->sa_family != gateway->sa_family) &&
1673                    (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK))
1674                        return (EINVAL);
1675
1676                if (info->rti_ifa == NULL) {
1677                        error = rt_getifa_fib(info, fibnum);
1678                        if (error)
1679                                return (error);
1680                } else
1681                        ifa_ref(info->rti_ifa);
1682                ifa = info->rti_ifa;
1683                rt = uma_zalloc(V_rtzone, M_NOWAIT);
1684                if (rt == NULL) {
1685                        ifa_free(ifa);
1686                        return (ENOBUFS);
1687                }
1688                rt->rt_flags = RTF_UP | flags;
1689                rt->rt_fibnum = fibnum;
1690                /*
1691                 * Add the gateway. Possibly re-malloc-ing the storage for it.
1692                 */
1693                if ((error = rt_setgate(rt, dst, gateway)) != 0) {
1694                        ifa_free(ifa);
1695                        uma_zfree(V_rtzone, rt);
1696                        return (error);
1697                }
1698
1699                /*
1700                 * point to the (possibly newly malloc'd) dest address.
1701                 */
1702                ndst = (struct sockaddr *)rt_key(rt);
1703
1704                /*
1705                 * make sure it contains the value we want (masked if needed).
1706                 */
1707                if (netmask) {
1708                        rt_maskedcopy(dst, ndst, netmask);
1709                } else
1710                        bcopy(dst, ndst, dst->sa_len);
1711
1712                /*
1713                 * We use the ifa reference returned by rt_getifa_fib().
1714                 * This moved from below so that rnh->rnh_addaddr() can
1715                 * examine the ifa and  ifa->ifa_ifp if it so desires.
1716                 */
1717                rt->rt_ifa = ifa;
1718                rt->rt_ifp = ifa->ifa_ifp;
1719                rt->rt_weight = 1;
1720
1721                rt_setmetrics(info, rt);
1722
1723                RIB_WLOCK(rnh);
1724                RT_LOCK(rt);
1725#ifdef RADIX_MPATH
1726                /* do not permit exactly the same dst/mask/gw pair */
1727                if (rt_mpath_capable(rnh) &&
1728                        rt_mpath_conflict(rnh, rt, netmask)) {
1729                        RIB_WUNLOCK(rnh);
1730
1731                        ifa_free(rt->rt_ifa);
1732                        R_Free(rt_key(rt));
1733                        uma_zfree(V_rtzone, rt);
1734                        return (EEXIST);
1735                }
1736#endif
1737
1738#ifdef FLOWTABLE
1739                rt0 = rt_flowtable_check_route(rnh, info);
1740#endif /* FLOWTABLE */
1741
1742                /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
1743                rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
1744
1745                rt_old = NULL;
1746                if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) {
1747
1748                        /*
1749                         * Force removal and re-try addition
1750                         * TODO: better multipath&pinned support
1751                         */
1752                        struct sockaddr *info_dst = info->rti_info[RTAX_DST];
1753                        info->rti_info[RTAX_DST] = ndst;
1754                        /* Do not delete existing PINNED(interface) routes */
1755                        info->rti_flags &= ~RTF_PINNED;
1756                        rt_old = rt_unlinkrte(rnh, info, &error);
1757                        info->rti_flags |= RTF_PINNED;
1758                        info->rti_info[RTAX_DST] = info_dst;
1759                        if (rt_old != NULL)
1760                                rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head,
1761                                    rt->rt_nodes);
1762                }
1763                RIB_WUNLOCK(rnh);
1764
1765                if (rt_old != NULL)
1766                        RT_UNLOCK(rt_old);
1767
1768                /*
1769                 * If it still failed to go into the tree,
1770                 * then un-make it (this should be a function)
1771                 */
1772                if (rn == NULL) {
1773                        ifa_free(rt->rt_ifa);
1774                        R_Free(rt_key(rt));
1775                        uma_zfree(V_rtzone, rt);
1776#ifdef FLOWTABLE
1777                        if (rt0 != NULL)
1778                                RTFREE(rt0);
1779#endif
1780                        return (EEXIST);
1781                }
1782#ifdef FLOWTABLE
1783                else if (rt0 != NULL) {
1784                        flowtable_route_flush(dst->sa_family, rt0);
1785                        RTFREE(rt0);
1786                }
1787#endif
1788
1789                if (rt_old != NULL) {
1790                        rt_notifydelete(rt_old, info);
1791                        RTFREE(rt_old);
1792                }
1793
1794                /*
1795                 * If this protocol has something to add to this then
1796                 * allow it to do that as well.
1797                 */
1798                if (ifa->ifa_rtrequest)
1799                        ifa->ifa_rtrequest(req, rt, info);
1800
1801                /*
1802                 * actually return a resultant rtentry and
1803                 * give the caller a single reference.
1804                 */
1805                if (ret_nrt) {
1806                        *ret_nrt = rt;
1807                        RT_ADDREF(rt);
1808                }
1809                rnh->rnh_gen++;         /* Routing table updated */
1810                RT_UNLOCK(rt);
1811                break;
1812        case RTM_CHANGE:
1813                RIB_WLOCK(rnh);
1814                error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum);
1815                RIB_WUNLOCK(rnh);
1816                break;
1817        default:
1818                error = EOPNOTSUPP;
1819        }
1820
1821        return (error);
1822}
1823
1824#undef dst
1825#undef gateway
1826#undef netmask
1827#undef ifaaddr
1828#undef ifpaddr
1829#undef flags
1830
1831static int
1832rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info,
1833    struct rtentry **ret_nrt, u_int fibnum)
1834{
1835        struct rtentry *rt = NULL;
1836        int error = 0;
1837        int free_ifa = 0;
1838        int family, mtu;
1839        struct if_mtuinfo ifmtu;
1840
1841        rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST],
1842            info->rti_info[RTAX_NETMASK], &rnh->head);
1843
1844        if (rt == NULL)
1845                return (ESRCH);
1846
1847#ifdef RADIX_MPATH
1848        /*
1849         * If we got multipath routes,
1850         * we require users to specify a matching RTAX_GATEWAY.
1851         */
1852        if (rt_mpath_capable(rnh)) {
1853                rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]);
1854                if (rt == NULL)
1855                        return (ESRCH);
1856        }
1857#endif
1858
1859        RT_LOCK(rt);
1860
1861        rt_setmetrics(info, rt);
1862
1863        /*
1864         * New gateway could require new ifaddr, ifp;
1865         * flags may also be different; ifp may be specified
1866         * by ll sockaddr when protocol address is ambiguous
1867         */
1868        if (((rt->rt_flags & RTF_GATEWAY) &&
1869            info->rti_info[RTAX_GATEWAY] != NULL) ||
1870            info->rti_info[RTAX_IFP] != NULL ||
1871            (info->rti_info[RTAX_IFA] != NULL &&
1872             !sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) {
1873
1874                error = rt_getifa_fib(info, fibnum);
1875                if (info->rti_ifa != NULL)
1876                        free_ifa = 1;
1877
1878                if (error != 0)
1879                        goto bad;
1880        }
1881
1882        /* Check if outgoing interface has changed */
1883        if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa &&
1884            rt->rt_ifa != NULL && rt->rt_ifa->ifa_rtrequest != NULL) {
1885                rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info);
1886                ifa_free(rt->rt_ifa);
1887        }
1888        /* Update gateway address */
1889        if (info->rti_info[RTAX_GATEWAY] != NULL) {
1890                error = rt_setgate(rt, rt_key(rt), info->rti_info[RTAX_GATEWAY]);
1891                if (error != 0)
1892                        goto bad;
1893
1894                rt->rt_flags &= ~RTF_GATEWAY;
1895                rt->rt_flags |= (RTF_GATEWAY & info->rti_flags);
1896        }
1897
1898        if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa) {
1899                ifa_ref(info->rti_ifa);
1900                rt->rt_ifa = info->rti_ifa;
1901                rt->rt_ifp = info->rti_ifp;
1902        }
1903        /* Allow some flags to be toggled on change. */
1904        rt->rt_flags &= ~RTF_FMASK;
1905        rt->rt_flags |= info->rti_flags & RTF_FMASK;
1906
1907        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL)
1908               rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info);
1909
1910        /* Alter route MTU if necessary */
1911        if (rt->rt_ifp != NULL) {
1912                family = info->rti_info[RTAX_DST]->sa_family;
1913                mtu = if_getmtu_family(rt->rt_ifp, family);
1914                /* Set default MTU */
1915                if (rt->rt_mtu == 0)
1916                        rt->rt_mtu = mtu;
1917                if (rt->rt_mtu != mtu) {
1918                        /* Check if we really need to update */
1919                        ifmtu.ifp = rt->rt_ifp;
1920                        ifmtu.mtu = mtu;
1921                        if_updatemtu_cb(rt->rt_nodes, &ifmtu);
1922                }
1923        }
1924
1925        if (ret_nrt) {
1926                *ret_nrt = rt;
1927                RT_ADDREF(rt);
1928        }
1929bad:
1930        RT_UNLOCK(rt);
1931        if (free_ifa != 0)
1932                ifa_free(info->rti_ifa);
1933        return (error);
1934}
1935
1936static void
1937rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt)
1938{
1939
1940        if (info->rti_mflags & RTV_MTU) {
1941                if (info->rti_rmx->rmx_mtu != 0) {
1942
1943                        /*
1944                         * MTU was explicitly provided by user.
1945                         * Keep it.
1946                         */
1947                        rt->rt_flags |= RTF_FIXEDMTU;
1948                } else {
1949
1950                        /*
1951                         * User explicitly sets MTU to 0.
1952                         * Assume rollback to default.
1953                         */
1954                        rt->rt_flags &= ~RTF_FIXEDMTU;
1955                }
1956                rt->rt_mtu = info->rti_rmx->rmx_mtu;
1957        }
1958        if (info->rti_mflags & RTV_WEIGHT)
1959                rt->rt_weight = info->rti_rmx->rmx_weight;
1960        /* Kernel -> userland timebase conversion. */
1961        if (info->rti_mflags & RTV_EXPIRE)
1962                rt->rt_expire = info->rti_rmx->rmx_expire ?
1963                    info->rti_rmx->rmx_expire - time_second + time_uptime : 0;
1964}
1965
1966int
1967rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
1968{
1969        /* XXX dst may be overwritten, can we move this to below */
1970        int dlen = SA_SIZE(dst), glen = SA_SIZE(gate);
1971
1972        /*
1973         * Prepare to store the gateway in rt->rt_gateway.
1974         * Both dst and gateway are stored one after the other in the same
1975         * malloc'd chunk. If we have room, we can reuse the old buffer,
1976         * rt_gateway already points to the right place.
1977         * Otherwise, malloc a new block and update the 'dst' address.
1978         */
1979        if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) {
1980                caddr_t new;
1981
1982                R_Malloc(new, caddr_t, dlen + glen);
1983                if (new == NULL)
1984                        return ENOBUFS;
1985                /*
1986                 * XXX note, we copy from *dst and not *rt_key(rt) because
1987                 * rt_setgate() can be called to initialize a newly
1988                 * allocated route entry, in which case rt_key(rt) == NULL
1989                 * (and also rt->rt_gateway == NULL).
1990                 * Free()/free() handle a NULL argument just fine.
1991                 */
1992                bcopy(dst, new, dlen);
1993                R_Free(rt_key(rt));     /* free old block, if any */
1994                rt_key(rt) = (struct sockaddr *)new;
1995                rt->rt_gateway = (struct sockaddr *)(new + dlen);
1996        }
1997
1998        /*
1999         * Copy the new gateway value into the memory chunk.
2000         */
2001        bcopy(gate, rt->rt_gateway, glen);
2002
2003        return (0);
2004}
2005
2006void
2007rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask)
2008{
2009        u_char *cp1 = (u_char *)src;
2010        u_char *cp2 = (u_char *)dst;
2011        u_char *cp3 = (u_char *)netmask;
2012        u_char *cplim = cp2 + *cp3;
2013        u_char *cplim2 = cp2 + *cp1;
2014
2015        *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
2016        cp3 += 2;
2017        if (cplim > cplim2)
2018                cplim = cplim2;
2019        while (cp2 < cplim)
2020                *cp2++ = *cp1++ & *cp3++;
2021        if (cp2 < cplim2)
2022                bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
2023}
2024
2025/*
2026 * Set up a routing table entry, normally
2027 * for an interface.
2028 */
2029#define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */
2030static inline  int
2031rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
2032{
2033        struct sockaddr *dst;
2034        struct sockaddr *netmask;
2035        struct rtentry *rt = NULL;
2036        struct rt_addrinfo info;
2037        int error = 0;
2038        int startfib, endfib;
2039        char tempbuf[_SOCKADDR_TMPSIZE];
2040        int didwork = 0;
2041        int a_failure = 0;
2042        static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
2043        struct rib_head *rnh;
2044
2045        if (flags & RTF_HOST) {
2046                dst = ifa->ifa_dstaddr;
2047                netmask = NULL;
2048        } else {
2049                dst = ifa->ifa_addr;
2050                netmask = ifa->ifa_netmask;
2051        }
2052        if (dst->sa_len == 0)
2053                return(EINVAL);
2054        switch (dst->sa_family) {
2055        case AF_INET6:
2056        case AF_INET:
2057                /* We support multiple FIBs. */
2058                break;
2059        default:
2060                fibnum = RT_DEFAULT_FIB;
2061                break;
2062        }
2063        if (fibnum == RT_ALL_FIBS) {
2064                if (V_rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD)
2065#ifndef __rtems__
2066                        startfib = endfib = ifa->ifa_ifp->if_fib;
2067#else /* __rtems__ */
2068                        startfib = endfib = BSD_DEFAULT_FIB;
2069#endif /* __rtems__ */
2070                else {
2071                        startfib = 0;
2072                        endfib = rt_numfibs - 1;
2073                }
2074        } else {
2075                KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum"));
2076                startfib = fibnum;
2077                endfib = fibnum;
2078        }
2079
2080        /*
2081         * If it's a delete, check that if it exists,
2082         * it's on the correct interface or we might scrub
2083         * a route to another ifa which would
2084         * be confusing at best and possibly worse.
2085         */
2086        if (cmd == RTM_DELETE) {
2087                /*
2088                 * It's a delete, so it should already exist..
2089                 * If it's a net, mask off the host bits
2090                 * (Assuming we have a mask)
2091                 * XXX this is kinda inet specific..
2092                 */
2093                if (netmask != NULL) {
2094                        rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask);
2095                        dst = (struct sockaddr *)tempbuf;
2096                }
2097        }
2098        /*
2099         * Now go through all the requested tables (fibs) and do the
2100         * requested action. Realistically, this will either be fib 0
2101         * for protocols that don't do multiple tables or all the
2102         * tables for those that do.
2103         */
2104        for ( fibnum = startfib; fibnum <= endfib; fibnum++) {
2105                if (cmd == RTM_DELETE) {
2106                        struct radix_node *rn;
2107                        /*
2108                         * Look up an rtentry that is in the routing tree and
2109                         * contains the correct info.
2110                         */
2111                        rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
2112                        if (rnh == NULL)
2113                                /* this table doesn't exist but others might */
2114                                continue;
2115                        RIB_RLOCK(rnh);
2116                        rn = rnh->rnh_lookup(dst, netmask, &rnh->head);
2117#ifdef RADIX_MPATH
2118                        if (rt_mpath_capable(rnh)) {
2119
2120                                if (rn == NULL)
2121                                        error = ESRCH;
2122                                else {
2123                                        rt = RNTORT(rn);
2124                                        /*
2125                                         * for interface route the
2126                                         * rt->rt_gateway is sockaddr_intf
2127                                         * for cloning ARP entries, so
2128                                         * rt_mpath_matchgate must use the
2129                                         * interface address
2130                                         */
2131                                        rt = rt_mpath_matchgate(rt,
2132                                            ifa->ifa_addr);
2133                                        if (rt == NULL)
2134                                                error = ESRCH;
2135                                }
2136                        }
2137#endif
2138                        error = (rn == NULL ||
2139                            (rn->rn_flags & RNF_ROOT) ||
2140                            RNTORT(rn)->rt_ifa != ifa);
2141                        RIB_RUNLOCK(rnh);
2142                        if (error) {
2143                                /* this is only an error if bad on ALL tables */
2144                                continue;
2145                        }
2146                }
2147                /*
2148                 * Do the actual request
2149                 */
2150                bzero((caddr_t)&info, sizeof(info));
2151                info.rti_ifa = ifa;
2152                info.rti_flags = flags |
2153                    (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED;
2154                info.rti_info[RTAX_DST] = dst;
2155                /*
2156                 * doing this for compatibility reasons
2157                 */
2158                if (cmd == RTM_ADD)
2159                        info.rti_info[RTAX_GATEWAY] =
2160                            (struct sockaddr *)&null_sdl;
2161                else
2162                        info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
2163                info.rti_info[RTAX_NETMASK] = netmask;
2164                error = rtrequest1_fib(cmd, &info, &rt, fibnum);
2165
2166                if (error == 0 && rt != NULL) {
2167                        /*
2168                         * notify any listening routing agents of the change
2169                         */
2170                        RT_LOCK(rt);
2171#ifdef RADIX_MPATH
2172                        /*
2173                         * in case address alias finds the first address
2174                         * e.g. ifconfig bge0 192.0.2.246/24
2175                         * e.g. ifconfig bge0 192.0.2.247/24
2176                         * the address set in the route is 192.0.2.246
2177                         * so we need to replace it with 192.0.2.247
2178                         */
2179                        if (memcmp(rt->rt_ifa->ifa_addr,
2180                            ifa->ifa_addr, ifa->ifa_addr->sa_len)) {
2181                                ifa_free(rt->rt_ifa);
2182                                ifa_ref(ifa);
2183                                rt->rt_ifp = ifa->ifa_ifp;
2184                                rt->rt_ifa = ifa;
2185                        }
2186#endif
2187                        /*
2188                         * doing this for compatibility reasons
2189                         */
2190                        if (cmd == RTM_ADD) {
2191                            ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type  =
2192                                rt->rt_ifp->if_type;
2193                            ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
2194                                rt->rt_ifp->if_index;
2195                        }
2196                        RT_ADDREF(rt);
2197                        RT_UNLOCK(rt);
2198                        rt_newaddrmsg_fib(cmd, ifa, error, rt, fibnum);
2199                        RT_LOCK(rt);
2200                        RT_REMREF(rt);
2201                        if (cmd == RTM_DELETE) {
2202                                /*
2203                                 * If we are deleting, and we found an entry,
2204                                 * then it's been removed from the tree..
2205                                 * now throw it away.
2206                                 */
2207                                RTFREE_LOCKED(rt);
2208                        } else {
2209                                if (cmd == RTM_ADD) {
2210                                        /*
2211                                         * We just wanted to add it..
2212                                         * we don't actually need a reference.
2213                                         */
2214                                        RT_REMREF(rt);
2215                                }
2216                                RT_UNLOCK(rt);
2217                        }
2218                        didwork = 1;
2219                }
2220                if (error)
2221                        a_failure = error;
2222        }
2223        if (cmd == RTM_DELETE) {
2224                if (didwork) {
2225                        error = 0;
2226                } else {
2227                        /* we only give an error if it wasn't in any table */
2228                        error = ((flags & RTF_HOST) ?
2229                            EHOSTUNREACH : ENETUNREACH);
2230                }
2231        } else {
2232                if (a_failure) {
2233                        /* return an error if any of them failed */
2234                        error = a_failure;
2235                }
2236        }
2237        return (error);
2238}
2239
2240/*
2241 * Set up a routing table entry, normally
2242 * for an interface.
2243 */
2244int
2245rtinit(struct ifaddr *ifa, int cmd, int flags)
2246{
2247        struct sockaddr *dst;
2248        int fib = RT_DEFAULT_FIB;
2249
2250        if (flags & RTF_HOST) {
2251                dst = ifa->ifa_dstaddr;
2252        } else {
2253                dst = ifa->ifa_addr;
2254        }
2255
2256        switch (dst->sa_family) {
2257        case AF_INET6:
2258        case AF_INET:
2259                /* We do support multiple FIBs. */
2260                fib = RT_ALL_FIBS;
2261                break;
2262        }
2263        return (rtinit1(ifa, cmd, flags, fib));
2264}
2265
2266/*
2267 * Announce interface address arrival/withdraw
2268 * Returns 0 on success.
2269 */
2270int
2271rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
2272{
2273
2274        KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
2275            ("unexpected cmd %d", cmd));
2276       
2277        KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
2278            ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
2279
2280#if defined(INET) || defined(INET6)
2281#ifdef SCTP
2282        /*
2283         * notify the SCTP stack
2284         * this will only get called when an address is added/deleted
2285         * XXX pass the ifaddr struct instead if ifa->ifa_addr...
2286         */
2287        sctp_addr_change(ifa, cmd);
2288#endif /* SCTP */
2289#endif
2290        return (rtsock_addrmsg(cmd, ifa, fibnum));
2291}
2292
2293/*
2294 * Announce route addition/removal.
2295 * Users of this function MUST validate input data BEFORE calling.
2296 * However we have to be able to handle invalid data:
2297 * if some userland app sends us "invalid" route message (invalid mask,
2298 * no dst, wrong address families, etc...) we need to pass it back
2299 * to app (and any other rtsock consumers) with rtm_errno field set to
2300 * non-zero value.
2301 * Returns 0 on success.
2302 */
2303int
2304rt_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt,
2305    int fibnum)
2306{
2307
2308        KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
2309            ("unexpected cmd %d", cmd));
2310       
2311        KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
2312            ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
2313
2314        KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__));
2315
2316        return (rtsock_routemsg(cmd, ifp, error, rt, fibnum));
2317}
2318
2319void
2320rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
2321{
2322
2323        rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS);
2324}
2325
2326/*
2327 * This is called to generate messages from the routing socket
2328 * indicating a network interface has had addresses associated with it.
2329 */
2330void
2331rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt,
2332    int fibnum)
2333{
2334
2335        KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
2336                ("unexpected cmd %u", cmd));
2337        KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
2338            ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
2339
2340        if (cmd == RTM_ADD) {
2341                rt_addrmsg(cmd, ifa, fibnum);
2342                if (rt != NULL)
2343                        rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
2344        } else {
2345                if (rt != NULL)
2346                        rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum);
2347                rt_addrmsg(cmd, ifa, fibnum);
2348        }
2349}
2350
Note: See TracBrowser for help on using the repository browser.