1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
--- 16 unchanged lines hidden (view full) ---
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 231852 2012-02-17 02:39:58Z bz $");
34
35#include "opt_inet.h"
36#include "opt_inet6.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
--- 426 unchanged lines hidden (view full) ---
468 ifa_free(ifa);
469}
470
471static void
472defrouter_addreq(struct nd_defrouter *new)
473{
474 struct sockaddr_in6 def, mask, gate;
475 struct rtentry *newrt = NULL;
476 int s;
477 int error;
478
479 bzero(&def, sizeof(def));
480 bzero(&mask, sizeof(mask));
481 bzero(&gate, sizeof(gate));
482
483 def.sin6_len = mask.sin6_len = gate.sin6_len =
484 sizeof(struct sockaddr_in6);
485 def.sin6_family = gate.sin6_family = AF_INET6;
486 gate.sin6_addr = new->rtaddr;
487
488 s = splnet();
489 error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
490 (struct sockaddr *)&gate, (struct sockaddr *)&mask,
491 RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
492 if (newrt) {
493 nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
494 RTFREE(newrt);
495 }
496 if (error == 0)
497 new->installed = 1;
498 splx(s);
499 return;
500}
501
502struct nd_defrouter *
503defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
504{
505 struct nd_defrouter *dr;
506
--- 112 unchanged lines hidden (view full) ---
619 * At this moment, we do not try to install more than one default router,
620 * even when the multipath routing is available, because we're not sure about
621 * the benefits for stub hosts comparing to the risk of making the code
622 * complicated and the possibility of introducing bugs.
623 */
624void
625defrouter_select(void)
626{
627 int s = splnet();
628 struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
629 struct llentry *ln = NULL;
630
631 /*
632 * Let's handle easy case (3) first:
633 * If default router list is empty, there's nothing to be done.
634 */
635 if (TAILQ_EMPTY(&V_nd_defrouter)) {
636 splx(s);
637 return;
638 }
639
640 /*
641 * Search for a (probably) reachable router from the list.
642 * We just pick up the first reachable one (if any), assuming that
643 * the ordering rule of the list described in defrtrlist_update().
644 */
645 TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
646 IF_AFDATA_LOCK(dr->ifp);
--- 47 unchanged lines hidden (view full) ---
694 * Note that the selected router is never NULL here.
695 */
696 if (installed_dr != selected_dr) {
697 if (installed_dr)
698 defrouter_delreq(installed_dr);
699 defrouter_addreq(selected_dr);
700 }
701
702 splx(s);
703 return;
704}
705
706/*
707 * for default router selection
708 * regards router-preference field as a 2-bit signed integer
709 */
710static int
--- 18 unchanged lines hidden (view full) ---
729 }
730 /* NOTREACHED */
731}
732
733static struct nd_defrouter *
734defrtrlist_update(struct nd_defrouter *new)
735{
736 struct nd_defrouter *dr, *n;
737 int s = splnet();
738
739 if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
740 /* entry exists */
741 if (new->rtlifetime == 0) {
742 defrtrlist_del(dr);
743 dr = NULL;
744 } else {
745 int oldpref = rtpref(dr);
746
747 /* override */
748 dr->flags = new->flags; /* xxx flag check */
749 dr->rtlifetime = new->rtlifetime;
750 dr->expire = new->expire;
751
752 /*
753 * If the preference does not change, there's no need
754 * to sort the entries. Also make sure the selected
755 * router is still installed in the kernel.
756 */
757 if (dr->installed && rtpref(new) == oldpref) {
758 splx(s);
759 return (dr);
760 }
761
762 /*
763 * preferred router may be changed, so relocate
764 * this router.
765 * XXX: calling TAILQ_REMOVE directly is a bad manner.
766 * However, since defrtrlist_del() has many side
767 * effects, we intentionally do so here.
768 * defrouter_select() below will handle routing
769 * changes later.
770 */
771 TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
772 n = dr;
773 goto insert;
774 }
775 splx(s);
776 return (dr);
777 }
778
779 /* entry does not exist */
780 if (new->rtlifetime == 0) {
781 splx(s);
782 return (NULL);
783 }
784
785 n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
786 if (n == NULL) {
787 splx(s);
788 return (NULL);
789 }
790 bzero(n, sizeof(*n));
791 *n = *new;
792
793insert:
794 /*
795 * Insert the new router in the Default Router List;
796 * The Default Router List should be in the descending order
797 * of router-preferece. Routers with the same preference are
--- 7 unchanged lines hidden (view full) ---
805 }
806 if (dr)
807 TAILQ_INSERT_BEFORE(dr, n, dr_entry);
808 else
809 TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry);
810
811 defrouter_select();
812
813 splx(s);
814
815 return (n);
816}
817
818static struct nd_pfxrouter *
819pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
820{
821 struct nd_pfxrouter *search;
822
--- 46 unchanged lines hidden (view full) ---
869}
870
871int
872nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
873 struct nd_prefix **newp)
874{
875 struct nd_prefix *new = NULL;
876 int error = 0;
877 int i, s;
878 char ip6buf[INET6_ADDRSTRLEN];
879
880 new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
881 if (new == NULL)
882 return(ENOMEM);
883 bzero(new, sizeof(*new));
884 new->ndpr_ifp = pr->ndpr_ifp;
885 new->ndpr_prefix = pr->ndpr_prefix;
--- 12 unchanged lines hidden (view full) ---
898 /* initialization */
899 LIST_INIT(&new->ndpr_advrtrs);
900 in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
901 /* make prefix in the canonical form */
902 for (i = 0; i < 4; i++)
903 new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
904 new->ndpr_mask.s6_addr32[i];
905
906 s = splnet();
907 /* link ndpr_entry to nd_prefix list */
908 LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry);
909 splx(s);
910
911 /* ND_OPT_PI_FLAG_ONLINK processing */
912 if (new->ndpr_raf_onlink) {
913 int e;
914
915 if ((e = nd6_prefix_onlink(new)) != 0) {
916 nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
917 "the prefix %s/%d on-link on %s (errno=%d)\n",
--- 8 unchanged lines hidden (view full) ---
926
927 return 0;
928}
929
930void
931prelist_remove(struct nd_prefix *pr)
932{
933 struct nd_pfxrouter *pfr, *next;
934 int e, s;
935 char ip6buf[INET6_ADDRSTRLEN];
936
937 /* make sure to invalidate the prefix until it is really freed. */
938 pr->ndpr_vltime = 0;
939 pr->ndpr_pltime = 0;
940
941 /*
942 * Though these flags are now meaningless, we'd rather keep the value
--- 8 unchanged lines hidden (view full) ---
951 ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
952 pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
953 /* what should we do? */
954 }
955
956 if (pr->ndpr_refcnt > 0)
957 return; /* notice here? */
958
959 s = splnet();
960
961 /* unlink ndpr_entry from nd_prefix list */
962 LIST_REMOVE(pr, ndpr_entry);
963
964 /* free list of routers that adversed the prefix */
965 LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) {
966 free(pfr, M_IP6NDP);
967 }
968 splx(s);
969
970 free(pr, M_IP6NDP);
971
972 pfxlist_onlink_check();
973}
974
975/*
976 * dr - may be NULL
977 */
978
979static int
980prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
981 struct mbuf *m, int mcast)
982{
983 struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
984 struct ifaddr *ifa;
985 struct ifnet *ifp = new->ndpr_ifp;
986 struct nd_prefix *pr;
987 int s = splnet();
988 int error = 0;
989 int newprefix = 0;
990 int auth;
991 struct in6_addrlifetime lt6_tmp;
992 char ip6buf[INET6_ADDRSTRLEN];
993
994 auth = 0;
995 if (m) {
--- 308 unchanged lines hidden (view full) ---
1304 pfxlist_onlink_check();
1305 } else {
1306 /* just set an error. do not bark here. */
1307 error = EADDRNOTAVAIL; /* XXX: might be unused. */
1308 }
1309 }
1310
1311 end:
1312 splx(s);
1313 return error;
1314}
1315
1316/*
1317 * A supplement function used in the on-link detection below;
1318 * detect if a given prefix has a (probably) reachable advertising router.
1319 * XXX: lengthy function name...
1320 */
--- 786 unchanged lines hidden (view full) ---
2107 * XXX: this function causes search through all entries of routing table, so
2108 * it shouldn't be called when acting as a router.
2109 */
2110void
2111rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
2112{
2113 struct radix_node_head *rnh;
2114 u_int fibnum;
2115 int s = splnet();
2116
2117 /* We'll care only link-local addresses */
2118 if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
2119 splx(s);
2120 return;
2121 }
2122
2123 /* XXX Do we really need to walk any but the default FIB? */
2124 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
2125 rnh = rt_tables_get_rnh(fibnum, AF_INET6);
2126 if (rnh == NULL)
2127 continue;
2128
2129 RADIX_NODE_HEAD_LOCK(rnh);
2130 rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2131 RADIX_NODE_HEAD_UNLOCK(rnh);
2132 }
2133 splx(s);
2134}
2135
2136static int
2137rt6_deleteroute(struct radix_node *rn, void *arg)
2138{
2139#define SIN6(s) ((struct sockaddr_in6 *)s)
2140 struct rtentry *rt = (struct rtentry *)rn;
2141 struct in6_addr *gate = (struct in6_addr *)arg;
--- 55 unchanged lines hidden ---
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
--- 16 unchanged lines hidden (view full) ---
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 231852 2012-02-17 02:39:58Z bz $");
34
35#include "opt_inet.h"
36#include "opt_inet6.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
--- 426 unchanged lines hidden (view full) ---
468 ifa_free(ifa);
469}
470
471static void
472defrouter_addreq(struct nd_defrouter *new)
473{
474 struct sockaddr_in6 def, mask, gate;
475 struct rtentry *newrt = NULL;
476 int s;
477 int error;
478
479 bzero(&def, sizeof(def));
480 bzero(&mask, sizeof(mask));
481 bzero(&gate, sizeof(gate));
482
483 def.sin6_len = mask.sin6_len = gate.sin6_len =
484 sizeof(struct sockaddr_in6);
485 def.sin6_family = gate.sin6_family = AF_INET6;
486 gate.sin6_addr = new->rtaddr;
487
488 s = splnet();
489 error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
490 (struct sockaddr *)&gate, (struct sockaddr *)&mask,
491 RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
492 if (newrt) {
493 nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
494 RTFREE(newrt);
495 }
496 if (error == 0)
497 new->installed = 1;
498 splx(s);
499 return;
500}
501
502struct nd_defrouter *
503defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
504{
505 struct nd_defrouter *dr;
506
--- 112 unchanged lines hidden (view full) ---
619 * At this moment, we do not try to install more than one default router,
620 * even when the multipath routing is available, because we're not sure about
621 * the benefits for stub hosts comparing to the risk of making the code
622 * complicated and the possibility of introducing bugs.
623 */
624void
625defrouter_select(void)
626{
627 int s = splnet();
628 struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
629 struct llentry *ln = NULL;
630
631 /*
632 * Let's handle easy case (3) first:
633 * If default router list is empty, there's nothing to be done.
634 */
635 if (TAILQ_EMPTY(&V_nd_defrouter)) {
636 splx(s);
637 return;
638 }
639
640 /*
641 * Search for a (probably) reachable router from the list.
642 * We just pick up the first reachable one (if any), assuming that
643 * the ordering rule of the list described in defrtrlist_update().
644 */
645 TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
646 IF_AFDATA_LOCK(dr->ifp);
--- 47 unchanged lines hidden (view full) ---
694 * Note that the selected router is never NULL here.
695 */
696 if (installed_dr != selected_dr) {
697 if (installed_dr)
698 defrouter_delreq(installed_dr);
699 defrouter_addreq(selected_dr);
700 }
701
702 splx(s);
703 return;
704}
705
706/*
707 * for default router selection
708 * regards router-preference field as a 2-bit signed integer
709 */
710static int
--- 18 unchanged lines hidden (view full) ---
729 }
730 /* NOTREACHED */
731}
732
733static struct nd_defrouter *
734defrtrlist_update(struct nd_defrouter *new)
735{
736 struct nd_defrouter *dr, *n;
737 int s = splnet();
738
739 if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
740 /* entry exists */
741 if (new->rtlifetime == 0) {
742 defrtrlist_del(dr);
743 dr = NULL;
744 } else {
745 int oldpref = rtpref(dr);
746
747 /* override */
748 dr->flags = new->flags; /* xxx flag check */
749 dr->rtlifetime = new->rtlifetime;
750 dr->expire = new->expire;
751
752 /*
753 * If the preference does not change, there's no need
754 * to sort the entries. Also make sure the selected
755 * router is still installed in the kernel.
756 */
757 if (dr->installed && rtpref(new) == oldpref) {
758 splx(s);
759 return (dr);
760 }
761
762 /*
763 * preferred router may be changed, so relocate
764 * this router.
765 * XXX: calling TAILQ_REMOVE directly is a bad manner.
766 * However, since defrtrlist_del() has many side
767 * effects, we intentionally do so here.
768 * defrouter_select() below will handle routing
769 * changes later.
770 */
771 TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
772 n = dr;
773 goto insert;
774 }
775 splx(s);
776 return (dr);
777 }
778
779 /* entry does not exist */
780 if (new->rtlifetime == 0) {
781 splx(s);
782 return (NULL);
783 }
784
785 n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
786 if (n == NULL) {
787 splx(s);
788 return (NULL);
789 }
790 bzero(n, sizeof(*n));
791 *n = *new;
792
793insert:
794 /*
795 * Insert the new router in the Default Router List;
796 * The Default Router List should be in the descending order
797 * of router-preferece. Routers with the same preference are
--- 7 unchanged lines hidden (view full) ---
805 }
806 if (dr)
807 TAILQ_INSERT_BEFORE(dr, n, dr_entry);
808 else
809 TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry);
810
811 defrouter_select();
812
813 splx(s);
814
815 return (n);
816}
817
818static struct nd_pfxrouter *
819pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
820{
821 struct nd_pfxrouter *search;
822
--- 46 unchanged lines hidden (view full) ---
869}
870
871int
872nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
873 struct nd_prefix **newp)
874{
875 struct nd_prefix *new = NULL;
876 int error = 0;
877 int i, s;
878 char ip6buf[INET6_ADDRSTRLEN];
879
880 new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
881 if (new == NULL)
882 return(ENOMEM);
883 bzero(new, sizeof(*new));
884 new->ndpr_ifp = pr->ndpr_ifp;
885 new->ndpr_prefix = pr->ndpr_prefix;
--- 12 unchanged lines hidden (view full) ---
898 /* initialization */
899 LIST_INIT(&new->ndpr_advrtrs);
900 in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
901 /* make prefix in the canonical form */
902 for (i = 0; i < 4; i++)
903 new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
904 new->ndpr_mask.s6_addr32[i];
905
906 s = splnet();
907 /* link ndpr_entry to nd_prefix list */
908 LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry);
909 splx(s);
910
911 /* ND_OPT_PI_FLAG_ONLINK processing */
912 if (new->ndpr_raf_onlink) {
913 int e;
914
915 if ((e = nd6_prefix_onlink(new)) != 0) {
916 nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
917 "the prefix %s/%d on-link on %s (errno=%d)\n",
--- 8 unchanged lines hidden (view full) ---
926
927 return 0;
928}
929
930void
931prelist_remove(struct nd_prefix *pr)
932{
933 struct nd_pfxrouter *pfr, *next;
934 int e, s;
935 char ip6buf[INET6_ADDRSTRLEN];
936
937 /* make sure to invalidate the prefix until it is really freed. */
938 pr->ndpr_vltime = 0;
939 pr->ndpr_pltime = 0;
940
941 /*
942 * Though these flags are now meaningless, we'd rather keep the value
--- 8 unchanged lines hidden (view full) ---
951 ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
952 pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
953 /* what should we do? */
954 }
955
956 if (pr->ndpr_refcnt > 0)
957 return; /* notice here? */
958
959 s = splnet();
960
961 /* unlink ndpr_entry from nd_prefix list */
962 LIST_REMOVE(pr, ndpr_entry);
963
964 /* free list of routers that adversed the prefix */
965 LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) {
966 free(pfr, M_IP6NDP);
967 }
968 splx(s);
969
970 free(pr, M_IP6NDP);
971
972 pfxlist_onlink_check();
973}
974
975/*
976 * dr - may be NULL
977 */
978
979static int
980prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
981 struct mbuf *m, int mcast)
982{
983 struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
984 struct ifaddr *ifa;
985 struct ifnet *ifp = new->ndpr_ifp;
986 struct nd_prefix *pr;
987 int s = splnet();
988 int error = 0;
989 int newprefix = 0;
990 int auth;
991 struct in6_addrlifetime lt6_tmp;
992 char ip6buf[INET6_ADDRSTRLEN];
993
994 auth = 0;
995 if (m) {
--- 308 unchanged lines hidden (view full) ---
1304 pfxlist_onlink_check();
1305 } else {
1306 /* just set an error. do not bark here. */
1307 error = EADDRNOTAVAIL; /* XXX: might be unused. */
1308 }
1309 }
1310
1311 end:
1312 splx(s);
1313 return error;
1314}
1315
1316/*
1317 * A supplement function used in the on-link detection below;
1318 * detect if a given prefix has a (probably) reachable advertising router.
1319 * XXX: lengthy function name...
1320 */
--- 786 unchanged lines hidden (view full) ---
2107 * XXX: this function causes search through all entries of routing table, so
2108 * it shouldn't be called when acting as a router.
2109 */
2110void
2111rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
2112{
2113 struct radix_node_head *rnh;
2114 u_int fibnum;
2115 int s = splnet();
2116
2117 /* We'll care only link-local addresses */
2118 if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
2119 splx(s);
2120 return;
2121 }
2122
2123 /* XXX Do we really need to walk any but the default FIB? */
2124 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
2125 rnh = rt_tables_get_rnh(fibnum, AF_INET6);
2126 if (rnh == NULL)
2127 continue;
2128
2129 RADIX_NODE_HEAD_LOCK(rnh);
2130 rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2131 RADIX_NODE_HEAD_UNLOCK(rnh);
2132 }
2133 splx(s);
2134}
2135
2136static int
2137rt6_deleteroute(struct radix_node *rn, void *arg)
2138{
2139#define SIN6(s) ((struct sockaddr_in6 *)s)
2140 struct rtentry *rt = (struct rtentry *)rn;
2141 struct in6_addr *gate = (struct in6_addr *)arg;
--- 55 unchanged lines hidden ---