aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c56
1 files changed, 38 insertions, 18 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 358edd2272ac..4c03c2843094 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2730,9 +2730,25 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
2730 } 2730 }
2731} 2731}
2732 2732
2733static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
2734{
2735 if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) {
2736 struct in6_addr addr;
2737
2738 ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
2739 /* addrconf_add_linklocal also adds a prefix_route and we
2740 * only need to care about prefix routes if ipv6_generate_eui64
2741 * couldn't generate one.
2742 */
2743 if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0)
2744 addrconf_add_linklocal(idev, &addr);
2745 else if (prefix_route)
2746 addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
2747 }
2748}
2749
2733static void addrconf_dev_config(struct net_device *dev) 2750static void addrconf_dev_config(struct net_device *dev)
2734{ 2751{
2735 struct in6_addr addr;
2736 struct inet6_dev *idev; 2752 struct inet6_dev *idev;
2737 2753
2738 ASSERT_RTNL(); 2754 ASSERT_RTNL();
@@ -2753,11 +2769,7 @@ static void addrconf_dev_config(struct net_device *dev)
2753 if (IS_ERR(idev)) 2769 if (IS_ERR(idev))
2754 return; 2770 return;
2755 2771
2756 memset(&addr, 0, sizeof(struct in6_addr)); 2772 addrconf_addr_gen(idev, false);
2757 addr.s6_addr32[0] = htonl(0xFE800000);
2758
2759 if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)
2760 addrconf_add_linklocal(idev, &addr);
2761} 2773}
2762 2774
2763#if IS_ENABLED(CONFIG_IPV6_SIT) 2775#if IS_ENABLED(CONFIG_IPV6_SIT)
@@ -2779,11 +2791,7 @@ static void addrconf_sit_config(struct net_device *dev)
2779 } 2791 }
2780 2792
2781 if (dev->priv_flags & IFF_ISATAP) { 2793 if (dev->priv_flags & IFF_ISATAP) {
2782 struct in6_addr addr; 2794 addrconf_addr_gen(idev, false);
2783
2784 ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
2785 if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
2786 addrconf_add_linklocal(idev, &addr);
2787 return; 2795 return;
2788 } 2796 }
2789 2797
@@ -2798,7 +2806,6 @@ static void addrconf_sit_config(struct net_device *dev)
2798static void addrconf_gre_config(struct net_device *dev) 2806static void addrconf_gre_config(struct net_device *dev)
2799{ 2807{
2800 struct inet6_dev *idev; 2808 struct inet6_dev *idev;
2801 struct in6_addr addr;
2802 2809
2803 ASSERT_RTNL(); 2810 ASSERT_RTNL();
2804 2811
@@ -2807,11 +2814,7 @@ static void addrconf_gre_config(struct net_device *dev)
2807 return; 2814 return;
2808 } 2815 }
2809 2816
2810 ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); 2817 addrconf_addr_gen(idev, true);
2811 if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
2812 addrconf_add_linklocal(idev, &addr);
2813 else
2814 addrconf_prefix_route(&addr, 64, dev, 0, 0);
2815} 2818}
2816#endif 2819#endif
2817 2820
@@ -4423,6 +4426,10 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
4423 nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); 4426 nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr));
4424 if (nla == NULL) 4427 if (nla == NULL)
4425 goto nla_put_failure; 4428 goto nla_put_failure;
4429
4430 if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->addr_gen_mode))
4431 goto nla_put_failure;
4432
4426 read_lock_bh(&idev->lock); 4433 read_lock_bh(&idev->lock);
4427 memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); 4434 memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla));
4428 read_unlock_bh(&idev->lock); 4435 read_unlock_bh(&idev->lock);
@@ -4527,8 +4534,21 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
4527 if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) 4534 if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0)
4528 BUG(); 4535 BUG();
4529 4536
4530 if (tb[IFLA_INET6_TOKEN]) 4537 if (tb[IFLA_INET6_TOKEN]) {
4531 err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); 4538 err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN]));
4539 if (err)
4540 return err;
4541 }
4542
4543 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
4544 u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]);
4545
4546 if (mode != IN6_ADDR_GEN_MODE_EUI64 &&
4547 mode != IN6_ADDR_GEN_MODE_NONE)
4548 return -EINVAL;
4549 idev->addr_gen_mode = mode;
4550 err = 0;
4551 }
4532 4552
4533 return err; 4553 return err;
4534} 4554}