diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3c5d6bb3b850..d3f87ceb3408 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1759,6 +1759,10 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg) | |||
1759 | int addr_type; | 1759 | int addr_type; |
1760 | int err = -EINVAL; | 1760 | int err = -EINVAL; |
1761 | 1761 | ||
1762 | /* RTF_PCPU is an internal flag; can not be set by userspace */ | ||
1763 | if (cfg->fc_flags & RTF_PCPU) | ||
1764 | goto out; | ||
1765 | |||
1762 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) | 1766 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
1763 | goto out; | 1767 | goto out; |
1764 | #ifndef CONFIG_IPV6_SUBTREES | 1768 | #ifndef CONFIG_IPV6_SUBTREES |
@@ -2085,6 +2089,8 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
2085 | continue; | 2089 | continue; |
2086 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) | 2090 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
2087 | continue; | 2091 | continue; |
2092 | if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol) | ||
2093 | continue; | ||
2088 | dst_hold(&rt->dst); | 2094 | dst_hold(&rt->dst); |
2089 | read_unlock_bh(&table->tb6_lock); | 2095 | read_unlock_bh(&table->tb6_lock); |
2090 | 2096 | ||
@@ -2819,17 +2825,11 @@ static int ip6_route_info_append(struct list_head *rt6_nh_list, | |||
2819 | struct rt6_info *rt, struct fib6_config *r_cfg) | 2825 | struct rt6_info *rt, struct fib6_config *r_cfg) |
2820 | { | 2826 | { |
2821 | struct rt6_nh *nh; | 2827 | struct rt6_nh *nh; |
2822 | struct rt6_info *rtnh; | ||
2823 | int err = -EEXIST; | 2828 | int err = -EEXIST; |
2824 | 2829 | ||
2825 | list_for_each_entry(nh, rt6_nh_list, next) { | 2830 | list_for_each_entry(nh, rt6_nh_list, next) { |
2826 | /* check if rt6_info already exists */ | 2831 | /* check if rt6_info already exists */ |
2827 | rtnh = nh->rt6_info; | 2832 | if (rt6_duplicate_nexthop(nh->rt6_info, rt)) |
2828 | |||
2829 | if (rtnh->dst.dev == rt->dst.dev && | ||
2830 | rtnh->rt6i_idev == rt->rt6i_idev && | ||
2831 | ipv6_addr_equal(&rtnh->rt6i_gateway, | ||
2832 | &rt->rt6i_gateway)) | ||
2833 | return err; | 2833 | return err; |
2834 | } | 2834 | } |
2835 | 2835 | ||
@@ -3188,7 +3188,8 @@ static int rt6_fill_node(struct net *net, | |||
3188 | if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) | 3188 | if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) |
3189 | goto nla_put_failure; | 3189 | goto nla_put_failure; |
3190 | 3190 | ||
3191 | lwtunnel_fill_encap(skb, rt->dst.lwtstate); | 3191 | if (lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0) |
3192 | goto nla_put_failure; | ||
3192 | 3193 | ||
3193 | nlmsg_end(skb, nlh); | 3194 | nlmsg_end(skb, nlh); |
3194 | return 0; | 3195 | return 0; |
@@ -3354,7 +3355,10 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3354 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 3355 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
3355 | struct net *net = dev_net(dev); | 3356 | struct net *net = dev_net(dev); |
3356 | 3357 | ||
3357 | if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { | 3358 | if (!(dev->flags & IFF_LOOPBACK)) |
3359 | return NOTIFY_OK; | ||
3360 | |||
3361 | if (event == NETDEV_REGISTER) { | ||
3358 | net->ipv6.ip6_null_entry->dst.dev = dev; | 3362 | net->ipv6.ip6_null_entry->dst.dev = dev; |
3359 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); | 3363 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); |
3360 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 3364 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
@@ -3363,6 +3367,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3363 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; | 3367 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; |
3364 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); | 3368 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); |
3365 | #endif | 3369 | #endif |
3370 | } else if (event == NETDEV_UNREGISTER) { | ||
3371 | in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); | ||
3372 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3373 | in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); | ||
3374 | in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); | ||
3375 | #endif | ||
3366 | } | 3376 | } |
3367 | 3377 | ||
3368 | return NOTIFY_OK; | 3378 | return NOTIFY_OK; |
@@ -3669,9 +3679,24 @@ static struct pernet_operations ip6_route_net_late_ops = { | |||
3669 | 3679 | ||
3670 | static struct notifier_block ip6_route_dev_notifier = { | 3680 | static struct notifier_block ip6_route_dev_notifier = { |
3671 | .notifier_call = ip6_route_dev_notify, | 3681 | .notifier_call = ip6_route_dev_notify, |
3672 | .priority = 0, | 3682 | .priority = ADDRCONF_NOTIFY_PRIORITY - 10, |
3673 | }; | 3683 | }; |
3674 | 3684 | ||
3685 | void __init ip6_route_init_special_entries(void) | ||
3686 | { | ||
3687 | /* Registering of the loopback is done before this portion of code, | ||
3688 | * the loopback reference in rt6_info will not be taken, do it | ||
3689 | * manually for init_net */ | ||
3690 | init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; | ||
3691 | init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3692 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3693 | init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; | ||
3694 | init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3695 | init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; | ||
3696 | init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3697 | #endif | ||
3698 | } | ||
3699 | |||
3675 | int __init ip6_route_init(void) | 3700 | int __init ip6_route_init(void) |
3676 | { | 3701 | { |
3677 | int ret; | 3702 | int ret; |
@@ -3698,17 +3723,6 @@ int __init ip6_route_init(void) | |||
3698 | 3723 | ||
3699 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; | 3724 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; |
3700 | 3725 | ||
3701 | /* Registering of the loopback is done before this portion of code, | ||
3702 | * the loopback reference in rt6_info will not be taken, do it | ||
3703 | * manually for init_net */ | ||
3704 | init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; | ||
3705 | init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3706 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3707 | init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; | ||
3708 | init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3709 | init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; | ||
3710 | init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | ||
3711 | #endif | ||
3712 | ret = fib6_init(); | 3726 | ret = fib6_init(); |
3713 | if (ret) | 3727 | if (ret) |
3714 | goto out_register_subsys; | 3728 | goto out_register_subsys; |