diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 56 |
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 | ||
2733 | static 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 | |||
2733 | static void addrconf_dev_config(struct net_device *dev) | 2750 | static 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) | |||
2798 | static void addrconf_gre_config(struct net_device *dev) | 2806 | static 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 | } |