diff options
author | David S. Miller <davem@davemloft.net> | 2015-03-23 22:12:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-23 22:12:15 -0400 |
commit | ce046c568cbfb4734583131086f88cfe993c01d0 (patch) | |
tree | 8bba1bae6c6c9edf8c630dd317c748a7bfc80c69 /net/ipv6 | |
parent | 7f163d07ecd6fbba2ed3a2fcd0ca830846cc170e (diff) | |
parent | 9f0761c154eaf2bf796f7e0e3431631de8d362ae (diff) |
Merge branch 'ipv6_stable_privacy_address'
Hannes Frederic Sowa says:
====================
ipv6: RFC7217 stable privacy addresses implementation
this is an implementation of basic support for RFC7217 stable privacy
addresses. Please review and consider for net-next.
v2:
* Correct references to RFC 7212 -> RFC 7217 in documentation patch (thanks, Eric!)
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 293 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 2 | ||||
-rw-r--r-- | net/ipv6/sysctl_net_ipv6.c | 16 |
3 files changed, 284 insertions, 27 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 158378e73f0a..d2d238334a11 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/socket.h> | 46 | #include <linux/socket.h> |
47 | #include <linux/sockios.h> | 47 | #include <linux/sockios.h> |
48 | #include <linux/net.h> | 48 | #include <linux/net.h> |
49 | #include <linux/inet.h> | ||
49 | #include <linux/in6.h> | 50 | #include <linux/in6.h> |
50 | #include <linux/netdevice.h> | 51 | #include <linux/netdevice.h> |
51 | #include <linux/if_addr.h> | 52 | #include <linux/if_addr.h> |
@@ -102,6 +103,9 @@ | |||
102 | 103 | ||
103 | #define INFINITY_LIFE_TIME 0xFFFFFFFF | 104 | #define INFINITY_LIFE_TIME 0xFFFFFFFF |
104 | 105 | ||
106 | #define IPV6_MAX_STRLEN \ | ||
107 | sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") | ||
108 | |||
105 | static inline u32 cstamp_delta(unsigned long cstamp) | 109 | static inline u32 cstamp_delta(unsigned long cstamp) |
106 | { | 110 | { |
107 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | 111 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; |
@@ -127,6 +131,9 @@ static void ipv6_regen_rndid(unsigned long data); | |||
127 | 131 | ||
128 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); | 132 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); |
129 | static int ipv6_count_addresses(struct inet6_dev *idev); | 133 | static int ipv6_count_addresses(struct inet6_dev *idev); |
134 | static int ipv6_generate_stable_address(struct in6_addr *addr, | ||
135 | u8 dad_count, | ||
136 | const struct inet6_dev *idev); | ||
130 | 137 | ||
131 | /* | 138 | /* |
132 | * Configured unicast address hash table | 139 | * Configured unicast address hash table |
@@ -202,6 +209,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
202 | .accept_dad = 1, | 209 | .accept_dad = 1, |
203 | .suppress_frag_ndisc = 1, | 210 | .suppress_frag_ndisc = 1, |
204 | .accept_ra_mtu = 1, | 211 | .accept_ra_mtu = 1, |
212 | .stable_secret = { | ||
213 | .initialized = false, | ||
214 | } | ||
205 | }; | 215 | }; |
206 | 216 | ||
207 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 217 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
@@ -240,6 +250,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
240 | .accept_dad = 1, | 250 | .accept_dad = 1, |
241 | .suppress_frag_ndisc = 1, | 251 | .suppress_frag_ndisc = 1, |
242 | .accept_ra_mtu = 1, | 252 | .accept_ra_mtu = 1, |
253 | .stable_secret = { | ||
254 | .initialized = false, | ||
255 | }, | ||
243 | }; | 256 | }; |
244 | 257 | ||
245 | /* Check if a valid qdisc is available */ | 258 | /* Check if a valid qdisc is available */ |
@@ -860,7 +873,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
860 | ifa->peer_addr = *peer_addr; | 873 | ifa->peer_addr = *peer_addr; |
861 | 874 | ||
862 | spin_lock_init(&ifa->lock); | 875 | spin_lock_init(&ifa->lock); |
863 | spin_lock_init(&ifa->state_lock); | ||
864 | INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work); | 876 | INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work); |
865 | INIT_HLIST_NODE(&ifa->addr_lst); | 877 | INIT_HLIST_NODE(&ifa->addr_lst); |
866 | ifa->scope = scope; | 878 | ifa->scope = scope; |
@@ -1003,10 +1015,10 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
1003 | 1015 | ||
1004 | ASSERT_RTNL(); | 1016 | ASSERT_RTNL(); |
1005 | 1017 | ||
1006 | spin_lock_bh(&ifp->state_lock); | 1018 | spin_lock_bh(&ifp->lock); |
1007 | state = ifp->state; | 1019 | state = ifp->state; |
1008 | ifp->state = INET6_IFADDR_STATE_DEAD; | 1020 | ifp->state = INET6_IFADDR_STATE_DEAD; |
1009 | spin_unlock_bh(&ifp->state_lock); | 1021 | spin_unlock_bh(&ifp->lock); |
1010 | 1022 | ||
1011 | if (state == INET6_IFADDR_STATE_DEAD) | 1023 | if (state == INET6_IFADDR_STATE_DEAD) |
1012 | goto out; | 1024 | goto out; |
@@ -1686,19 +1698,21 @@ static int addrconf_dad_end(struct inet6_ifaddr *ifp) | |||
1686 | { | 1698 | { |
1687 | int err = -ENOENT; | 1699 | int err = -ENOENT; |
1688 | 1700 | ||
1689 | spin_lock_bh(&ifp->state_lock); | 1701 | spin_lock_bh(&ifp->lock); |
1690 | if (ifp->state == INET6_IFADDR_STATE_DAD) { | 1702 | if (ifp->state == INET6_IFADDR_STATE_DAD) { |
1691 | ifp->state = INET6_IFADDR_STATE_POSTDAD; | 1703 | ifp->state = INET6_IFADDR_STATE_POSTDAD; |
1692 | err = 0; | 1704 | err = 0; |
1693 | } | 1705 | } |
1694 | spin_unlock_bh(&ifp->state_lock); | 1706 | spin_unlock_bh(&ifp->lock); |
1695 | 1707 | ||
1696 | return err; | 1708 | return err; |
1697 | } | 1709 | } |
1698 | 1710 | ||
1699 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1711 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
1700 | { | 1712 | { |
1713 | struct in6_addr addr; | ||
1701 | struct inet6_dev *idev = ifp->idev; | 1714 | struct inet6_dev *idev = ifp->idev; |
1715 | struct net *net = dev_net(ifp->idev->dev); | ||
1702 | 1716 | ||
1703 | if (addrconf_dad_end(ifp)) { | 1717 | if (addrconf_dad_end(ifp)) { |
1704 | in6_ifa_put(ifp); | 1718 | in6_ifa_put(ifp); |
@@ -1708,9 +1722,57 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1708 | net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", | 1722 | net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", |
1709 | ifp->idev->dev->name, &ifp->addr); | 1723 | ifp->idev->dev->name, &ifp->addr); |
1710 | 1724 | ||
1711 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | 1725 | spin_lock_bh(&ifp->lock); |
1712 | struct in6_addr addr; | 1726 | |
1727 | if (ifp->flags & IFA_F_STABLE_PRIVACY) { | ||
1728 | int scope = ifp->scope; | ||
1729 | u32 flags = ifp->flags; | ||
1730 | struct in6_addr new_addr; | ||
1731 | struct inet6_ifaddr *ifp2; | ||
1732 | u32 valid_lft, preferred_lft; | ||
1733 | int pfxlen = ifp->prefix_len; | ||
1734 | int retries = ifp->stable_privacy_retry + 1; | ||
1735 | |||
1736 | if (retries > net->ipv6.sysctl.idgen_retries) { | ||
1737 | net_info_ratelimited("%s: privacy stable address generation failed because of DAD conflicts!\n", | ||
1738 | ifp->idev->dev->name); | ||
1739 | goto errdad; | ||
1740 | } | ||
1741 | |||
1742 | new_addr = ifp->addr; | ||
1743 | if (ipv6_generate_stable_address(&new_addr, retries, | ||
1744 | idev)) | ||
1745 | goto errdad; | ||
1713 | 1746 | ||
1747 | valid_lft = ifp->valid_lft; | ||
1748 | preferred_lft = ifp->prefered_lft; | ||
1749 | |||
1750 | spin_unlock_bh(&ifp->lock); | ||
1751 | |||
1752 | if (idev->cnf.max_addresses && | ||
1753 | ipv6_count_addresses(idev) >= | ||
1754 | idev->cnf.max_addresses) | ||
1755 | goto lock_errdad; | ||
1756 | |||
1757 | net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", | ||
1758 | ifp->idev->dev->name); | ||
1759 | |||
1760 | ifp2 = ipv6_add_addr(idev, &new_addr, NULL, pfxlen, | ||
1761 | scope, flags, valid_lft, | ||
1762 | preferred_lft); | ||
1763 | if (IS_ERR(ifp2)) | ||
1764 | goto lock_errdad; | ||
1765 | |||
1766 | spin_lock_bh(&ifp2->lock); | ||
1767 | ifp2->stable_privacy_retry = retries; | ||
1768 | ifp2->state = INET6_IFADDR_STATE_PREDAD; | ||
1769 | spin_unlock_bh(&ifp2->lock); | ||
1770 | |||
1771 | addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay); | ||
1772 | in6_ifa_put(ifp2); | ||
1773 | lock_errdad: | ||
1774 | spin_lock_bh(&ifp->lock); | ||
1775 | } else if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | ||
1714 | addr.s6_addr32[0] = htonl(0xfe800000); | 1776 | addr.s6_addr32[0] = htonl(0xfe800000); |
1715 | addr.s6_addr32[1] = 0; | 1777 | addr.s6_addr32[1] = 0; |
1716 | 1778 | ||
@@ -1724,10 +1786,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1724 | } | 1786 | } |
1725 | } | 1787 | } |
1726 | 1788 | ||
1727 | spin_lock_bh(&ifp->state_lock); | 1789 | errdad: |
1728 | /* transition from _POSTDAD to _ERRDAD */ | 1790 | /* transition from _POSTDAD to _ERRDAD */ |
1729 | ifp->state = INET6_IFADDR_STATE_ERRDAD; | 1791 | ifp->state = INET6_IFADDR_STATE_ERRDAD; |
1730 | spin_unlock_bh(&ifp->state_lock); | 1792 | spin_unlock_bh(&ifp->lock); |
1731 | 1793 | ||
1732 | addrconf_mod_dad_work(ifp, 0); | 1794 | addrconf_mod_dad_work(ifp, 0); |
1733 | } | 1795 | } |
@@ -2186,6 +2248,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | |||
2186 | __u32 valid_lft; | 2248 | __u32 valid_lft; |
2187 | __u32 prefered_lft; | 2249 | __u32 prefered_lft; |
2188 | int addr_type; | 2250 | int addr_type; |
2251 | u32 addr_flags = 0; | ||
2189 | struct inet6_dev *in6_dev; | 2252 | struct inet6_dev *in6_dev; |
2190 | struct net *net = dev_net(dev); | 2253 | struct net *net = dev_net(dev); |
2191 | 2254 | ||
@@ -2292,6 +2355,12 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) | |||
2292 | in6_dev->token.s6_addr + 8, 8); | 2355 | in6_dev->token.s6_addr + 8, 8); |
2293 | read_unlock_bh(&in6_dev->lock); | 2356 | read_unlock_bh(&in6_dev->lock); |
2294 | tokenized = true; | 2357 | tokenized = true; |
2358 | } else if (in6_dev->addr_gen_mode == | ||
2359 | IN6_ADDR_GEN_MODE_STABLE_PRIVACY && | ||
2360 | !ipv6_generate_stable_address(&addr, 0, | ||
2361 | in6_dev)) { | ||
2362 | addr_flags |= IFA_F_STABLE_PRIVACY; | ||
2363 | goto ok; | ||
2295 | } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && | 2364 | } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && |
2296 | ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { | 2365 | ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { |
2297 | in6_dev_put(in6_dev); | 2366 | in6_dev_put(in6_dev); |
@@ -2310,7 +2379,6 @@ ok: | |||
2310 | 2379 | ||
2311 | if (ifp == NULL && valid_lft) { | 2380 | if (ifp == NULL && valid_lft) { |
2312 | int max_addresses = in6_dev->cnf.max_addresses; | 2381 | int max_addresses = in6_dev->cnf.max_addresses; |
2313 | u32 addr_flags = 0; | ||
2314 | 2382 | ||
2315 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 2383 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
2316 | if (in6_dev->cnf.optimistic_dad && | 2384 | if (in6_dev->cnf.optimistic_dad && |
@@ -2350,7 +2418,7 @@ ok: | |||
2350 | u32 stored_lft; | 2418 | u32 stored_lft; |
2351 | 2419 | ||
2352 | /* update lifetime (RFC2462 5.5.3 e) */ | 2420 | /* update lifetime (RFC2462 5.5.3 e) */ |
2353 | spin_lock(&ifp->lock); | 2421 | spin_lock_bh(&ifp->lock); |
2354 | now = jiffies; | 2422 | now = jiffies; |
2355 | if (ifp->valid_lft > (now - ifp->tstamp) / HZ) | 2423 | if (ifp->valid_lft > (now - ifp->tstamp) / HZ) |
2356 | stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; | 2424 | stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; |
@@ -2380,12 +2448,12 @@ ok: | |||
2380 | ifp->tstamp = now; | 2448 | ifp->tstamp = now; |
2381 | flags = ifp->flags; | 2449 | flags = ifp->flags; |
2382 | ifp->flags &= ~IFA_F_DEPRECATED; | 2450 | ifp->flags &= ~IFA_F_DEPRECATED; |
2383 | spin_unlock(&ifp->lock); | 2451 | spin_unlock_bh(&ifp->lock); |
2384 | 2452 | ||
2385 | if (!(flags&IFA_F_TENTATIVE)) | 2453 | if (!(flags&IFA_F_TENTATIVE)) |
2386 | ipv6_ifa_notify(0, ifp); | 2454 | ipv6_ifa_notify(0, ifp); |
2387 | } else | 2455 | } else |
2388 | spin_unlock(&ifp->lock); | 2456 | spin_unlock_bh(&ifp->lock); |
2389 | 2457 | ||
2390 | manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, | 2458 | manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, |
2391 | create, now); | 2459 | create, now); |
@@ -2789,10 +2857,11 @@ static void init_loopback(struct net_device *dev) | |||
2789 | } | 2857 | } |
2790 | } | 2858 | } |
2791 | 2859 | ||
2792 | static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) | 2860 | static void addrconf_add_linklocal(struct inet6_dev *idev, |
2861 | const struct in6_addr *addr, u32 flags) | ||
2793 | { | 2862 | { |
2794 | struct inet6_ifaddr *ifp; | 2863 | struct inet6_ifaddr *ifp; |
2795 | u32 addr_flags = IFA_F_PERMANENT; | 2864 | u32 addr_flags = flags | IFA_F_PERMANENT; |
2796 | 2865 | ||
2797 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 2866 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
2798 | if (idev->cnf.optimistic_dad && | 2867 | if (idev->cnf.optimistic_dad && |
@@ -2800,7 +2869,6 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr | |||
2800 | addr_flags |= IFA_F_OPTIMISTIC; | 2869 | addr_flags |= IFA_F_OPTIMISTIC; |
2801 | #endif | 2870 | #endif |
2802 | 2871 | ||
2803 | |||
2804 | ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, | 2872 | ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, |
2805 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | 2873 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); |
2806 | if (!IS_ERR(ifp)) { | 2874 | if (!IS_ERR(ifp)) { |
@@ -2810,18 +2878,103 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr | |||
2810 | } | 2878 | } |
2811 | } | 2879 | } |
2812 | 2880 | ||
2881 | static bool ipv6_reserved_interfaceid(struct in6_addr address) | ||
2882 | { | ||
2883 | if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0) | ||
2884 | return true; | ||
2885 | |||
2886 | if (address.s6_addr32[2] == htonl(0x02005eff) && | ||
2887 | ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000))) | ||
2888 | return true; | ||
2889 | |||
2890 | if (address.s6_addr32[2] == htonl(0xfdffffff) && | ||
2891 | ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80))) | ||
2892 | return true; | ||
2893 | |||
2894 | return false; | ||
2895 | } | ||
2896 | |||
2897 | static int ipv6_generate_stable_address(struct in6_addr *address, | ||
2898 | u8 dad_count, | ||
2899 | const struct inet6_dev *idev) | ||
2900 | { | ||
2901 | static DEFINE_SPINLOCK(lock); | ||
2902 | static __u32 digest[SHA_DIGEST_WORDS]; | ||
2903 | static __u32 workspace[SHA_WORKSPACE_WORDS]; | ||
2904 | |||
2905 | static union { | ||
2906 | char __data[SHA_MESSAGE_BYTES]; | ||
2907 | struct { | ||
2908 | struct in6_addr secret; | ||
2909 | __be64 prefix; | ||
2910 | unsigned char hwaddr[MAX_ADDR_LEN]; | ||
2911 | u8 dad_count; | ||
2912 | } __packed; | ||
2913 | } data; | ||
2914 | |||
2915 | struct in6_addr secret; | ||
2916 | struct in6_addr temp; | ||
2917 | struct net *net = dev_net(idev->dev); | ||
2918 | |||
2919 | BUILD_BUG_ON(sizeof(data.__data) != sizeof(data)); | ||
2920 | |||
2921 | if (idev->cnf.stable_secret.initialized) | ||
2922 | secret = idev->cnf.stable_secret.secret; | ||
2923 | else if (net->ipv6.devconf_dflt->stable_secret.initialized) | ||
2924 | secret = net->ipv6.devconf_dflt->stable_secret.secret; | ||
2925 | else | ||
2926 | return -1; | ||
2927 | |||
2928 | retry: | ||
2929 | spin_lock_bh(&lock); | ||
2930 | |||
2931 | sha_init(digest); | ||
2932 | memset(&data, 0, sizeof(data)); | ||
2933 | memset(workspace, 0, sizeof(workspace)); | ||
2934 | memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len); | ||
2935 | data.prefix = ((__be64)address->s6_addr32[0] << 32) | | ||
2936 | (__be64)address->s6_addr32[1]; | ||
2937 | data.secret = secret; | ||
2938 | data.dad_count = dad_count; | ||
2939 | |||
2940 | sha_transform(digest, data.__data, workspace); | ||
2941 | |||
2942 | temp = *address; | ||
2943 | temp.s6_addr32[2] = digest[0]; | ||
2944 | temp.s6_addr32[3] = digest[1]; | ||
2945 | |||
2946 | spin_unlock_bh(&lock); | ||
2947 | |||
2948 | if (ipv6_reserved_interfaceid(temp)) { | ||
2949 | dad_count++; | ||
2950 | if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries) | ||
2951 | return -1; | ||
2952 | goto retry; | ||
2953 | } | ||
2954 | |||
2955 | *address = temp; | ||
2956 | return 0; | ||
2957 | } | ||
2958 | |||
2813 | static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) | 2959 | static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) |
2814 | { | 2960 | { |
2815 | if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) { | 2961 | struct in6_addr addr; |
2816 | struct in6_addr addr; | ||
2817 | 2962 | ||
2818 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); | 2963 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); |
2964 | |||
2965 | if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) { | ||
2966 | if (!ipv6_generate_stable_address(&addr, 0, idev)) | ||
2967 | addrconf_add_linklocal(idev, &addr, | ||
2968 | IFA_F_STABLE_PRIVACY); | ||
2969 | else if (prefix_route) | ||
2970 | addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); | ||
2971 | } else if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) { | ||
2819 | /* addrconf_add_linklocal also adds a prefix_route and we | 2972 | /* addrconf_add_linklocal also adds a prefix_route and we |
2820 | * only need to care about prefix routes if ipv6_generate_eui64 | 2973 | * only need to care about prefix routes if ipv6_generate_eui64 |
2821 | * couldn't generate one. | 2974 | * couldn't generate one. |
2822 | */ | 2975 | */ |
2823 | if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0) | 2976 | if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0) |
2824 | addrconf_add_linklocal(idev, &addr); | 2977 | addrconf_add_linklocal(idev, &addr, 0); |
2825 | else if (prefix_route) | 2978 | else if (prefix_route) |
2826 | addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); | 2979 | addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); |
2827 | } | 2980 | } |
@@ -3159,10 +3312,10 @@ restart: | |||
3159 | 3312 | ||
3160 | write_unlock_bh(&idev->lock); | 3313 | write_unlock_bh(&idev->lock); |
3161 | 3314 | ||
3162 | spin_lock_bh(&ifa->state_lock); | 3315 | spin_lock_bh(&ifa->lock); |
3163 | state = ifa->state; | 3316 | state = ifa->state; |
3164 | ifa->state = INET6_IFADDR_STATE_DEAD; | 3317 | ifa->state = INET6_IFADDR_STATE_DEAD; |
3165 | spin_unlock_bh(&ifa->state_lock); | 3318 | spin_unlock_bh(&ifa->lock); |
3166 | 3319 | ||
3167 | if (state != INET6_IFADDR_STATE_DEAD) { | 3320 | if (state != INET6_IFADDR_STATE_DEAD) { |
3168 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 3321 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
@@ -3320,12 +3473,12 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) | |||
3320 | { | 3473 | { |
3321 | bool begin_dad = false; | 3474 | bool begin_dad = false; |
3322 | 3475 | ||
3323 | spin_lock_bh(&ifp->state_lock); | 3476 | spin_lock_bh(&ifp->lock); |
3324 | if (ifp->state != INET6_IFADDR_STATE_DEAD) { | 3477 | if (ifp->state != INET6_IFADDR_STATE_DEAD) { |
3325 | ifp->state = INET6_IFADDR_STATE_PREDAD; | 3478 | ifp->state = INET6_IFADDR_STATE_PREDAD; |
3326 | begin_dad = true; | 3479 | begin_dad = true; |
3327 | } | 3480 | } |
3328 | spin_unlock_bh(&ifp->state_lock); | 3481 | spin_unlock_bh(&ifp->lock); |
3329 | 3482 | ||
3330 | if (begin_dad) | 3483 | if (begin_dad) |
3331 | addrconf_mod_dad_work(ifp, 0); | 3484 | addrconf_mod_dad_work(ifp, 0); |
@@ -3347,7 +3500,7 @@ static void addrconf_dad_work(struct work_struct *w) | |||
3347 | 3500 | ||
3348 | rtnl_lock(); | 3501 | rtnl_lock(); |
3349 | 3502 | ||
3350 | spin_lock_bh(&ifp->state_lock); | 3503 | spin_lock_bh(&ifp->lock); |
3351 | if (ifp->state == INET6_IFADDR_STATE_PREDAD) { | 3504 | if (ifp->state == INET6_IFADDR_STATE_PREDAD) { |
3352 | action = DAD_BEGIN; | 3505 | action = DAD_BEGIN; |
3353 | ifp->state = INET6_IFADDR_STATE_DAD; | 3506 | ifp->state = INET6_IFADDR_STATE_DAD; |
@@ -3355,7 +3508,7 @@ static void addrconf_dad_work(struct work_struct *w) | |||
3355 | action = DAD_ABORT; | 3508 | action = DAD_ABORT; |
3356 | ifp->state = INET6_IFADDR_STATE_POSTDAD; | 3509 | ifp->state = INET6_IFADDR_STATE_POSTDAD; |
3357 | } | 3510 | } |
3358 | spin_unlock_bh(&ifp->state_lock); | 3511 | spin_unlock_bh(&ifp->lock); |
3359 | 3512 | ||
3360 | if (action == DAD_BEGIN) { | 3513 | if (action == DAD_BEGIN) { |
3361 | addrconf_dad_begin(ifp); | 3514 | addrconf_dad_begin(ifp); |
@@ -4430,6 +4583,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
4430 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; | 4583 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; |
4431 | array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; | 4584 | array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; |
4432 | array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; | 4585 | array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; |
4586 | /* we omit DEVCONF_STABLE_SECRET for now */ | ||
4433 | } | 4587 | } |
4434 | 4588 | ||
4435 | static inline size_t inet6_ifla6_size(void) | 4589 | static inline size_t inet6_ifla6_size(void) |
@@ -4664,8 +4818,15 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) | |||
4664 | u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); | 4818 | u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); |
4665 | 4819 | ||
4666 | if (mode != IN6_ADDR_GEN_MODE_EUI64 && | 4820 | if (mode != IN6_ADDR_GEN_MODE_EUI64 && |
4667 | mode != IN6_ADDR_GEN_MODE_NONE) | 4821 | mode != IN6_ADDR_GEN_MODE_NONE && |
4822 | mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) | ||
4668 | return -EINVAL; | 4823 | return -EINVAL; |
4824 | |||
4825 | if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY && | ||
4826 | !idev->cnf.stable_secret.initialized && | ||
4827 | !dev_net(dev)->ipv6.devconf_dflt->stable_secret.initialized) | ||
4828 | return -EINVAL; | ||
4829 | |||
4669 | idev->addr_gen_mode = mode; | 4830 | idev->addr_gen_mode = mode; |
4670 | err = 0; | 4831 | err = 0; |
4671 | } | 4832 | } |
@@ -5074,6 +5235,74 @@ int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, | |||
5074 | return ret; | 5235 | return ret; |
5075 | } | 5236 | } |
5076 | 5237 | ||
5238 | static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write, | ||
5239 | void __user *buffer, size_t *lenp, | ||
5240 | loff_t *ppos) | ||
5241 | { | ||
5242 | int err; | ||
5243 | struct in6_addr addr; | ||
5244 | char str[IPV6_MAX_STRLEN]; | ||
5245 | struct ctl_table lctl = *ctl; | ||
5246 | struct net *net = ctl->extra2; | ||
5247 | struct ipv6_stable_secret *secret = ctl->data; | ||
5248 | |||
5249 | if (&net->ipv6.devconf_all->stable_secret == ctl->data) | ||
5250 | return -EIO; | ||
5251 | |||
5252 | lctl.maxlen = IPV6_MAX_STRLEN; | ||
5253 | lctl.data = str; | ||
5254 | |||
5255 | if (!rtnl_trylock()) | ||
5256 | return restart_syscall(); | ||
5257 | |||
5258 | if (!write && !secret->initialized) { | ||
5259 | err = -EIO; | ||
5260 | goto out; | ||
5261 | } | ||
5262 | |||
5263 | if (!write) { | ||
5264 | err = snprintf(str, sizeof(str), "%pI6", | ||
5265 | &secret->secret); | ||
5266 | if (err >= sizeof(str)) { | ||
5267 | err = -EIO; | ||
5268 | goto out; | ||
5269 | } | ||
5270 | } | ||
5271 | |||
5272 | err = proc_dostring(&lctl, write, buffer, lenp, ppos); | ||
5273 | if (err || !write) | ||
5274 | goto out; | ||
5275 | |||
5276 | if (in6_pton(str, -1, addr.in6_u.u6_addr8, -1, NULL) != 1) { | ||
5277 | err = -EIO; | ||
5278 | goto out; | ||
5279 | } | ||
5280 | |||
5281 | secret->initialized = true; | ||
5282 | secret->secret = addr; | ||
5283 | |||
5284 | if (&net->ipv6.devconf_dflt->stable_secret == ctl->data) { | ||
5285 | struct net_device *dev; | ||
5286 | |||
5287 | for_each_netdev(net, dev) { | ||
5288 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
5289 | |||
5290 | if (idev) { | ||
5291 | idev->addr_gen_mode = | ||
5292 | IN6_ADDR_GEN_MODE_STABLE_PRIVACY; | ||
5293 | } | ||
5294 | } | ||
5295 | } else { | ||
5296 | struct inet6_dev *idev = ctl->extra1; | ||
5297 | |||
5298 | idev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; | ||
5299 | } | ||
5300 | |||
5301 | out: | ||
5302 | rtnl_unlock(); | ||
5303 | |||
5304 | return err; | ||
5305 | } | ||
5077 | 5306 | ||
5078 | static struct addrconf_sysctl_table | 5307 | static struct addrconf_sysctl_table |
5079 | { | 5308 | { |
@@ -5347,6 +5576,13 @@ static struct addrconf_sysctl_table | |||
5347 | .proc_handler = proc_dointvec, | 5576 | .proc_handler = proc_dointvec, |
5348 | }, | 5577 | }, |
5349 | { | 5578 | { |
5579 | .procname = "stable_secret", | ||
5580 | .data = &ipv6_devconf.stable_secret, | ||
5581 | .maxlen = IPV6_MAX_STRLEN, | ||
5582 | .mode = 0600, | ||
5583 | .proc_handler = addrconf_sysctl_stable_secret, | ||
5584 | }, | ||
5585 | { | ||
5350 | /* sentinel */ | 5586 | /* sentinel */ |
5351 | } | 5587 | } |
5352 | }, | 5588 | }, |
@@ -5442,6 +5678,9 @@ static int __net_init addrconf_init_net(struct net *net) | |||
5442 | dflt->autoconf = ipv6_defaults.autoconf; | 5678 | dflt->autoconf = ipv6_defaults.autoconf; |
5443 | dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; | 5679 | dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; |
5444 | 5680 | ||
5681 | dflt->stable_secret.initialized = false; | ||
5682 | all->stable_secret.initialized = false; | ||
5683 | |||
5445 | net->ipv6.devconf_all = all; | 5684 | net->ipv6.devconf_all = all; |
5446 | net->ipv6.devconf_dflt = dflt; | 5685 | net->ipv6.devconf_dflt = dflt; |
5447 | 5686 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6bafcc2c79e3..d8dcc526339e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -766,6 +766,8 @@ static int __net_init inet6_net_init(struct net *net) | |||
766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; | 766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; |
767 | net->ipv6.sysctl.flowlabel_consistency = 1; | 767 | net->ipv6.sysctl.flowlabel_consistency = 1; |
768 | net->ipv6.sysctl.auto_flowlabels = 0; | 768 | net->ipv6.sysctl.auto_flowlabels = 0; |
769 | net->ipv6.sysctl.idgen_retries = 3; | ||
770 | net->ipv6.sysctl.idgen_delay = 1 * HZ; | ||
769 | atomic_set(&net->ipv6.fib6_sernum, 1); | 771 | atomic_set(&net->ipv6.fib6_sernum, 1); |
770 | 772 | ||
771 | err = ipv6_init_mibs(net); | 773 | err = ipv6_init_mibs(net); |
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index c5c10fafcfe2..30f5a4ad04eb 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -54,6 +54,20 @@ static struct ctl_table ipv6_table_template[] = { | |||
54 | .mode = 0644, | 54 | .mode = 0644, |
55 | .proc_handler = proc_dointvec | 55 | .proc_handler = proc_dointvec |
56 | }, | 56 | }, |
57 | { | ||
58 | .procname = "idgen_retries", | ||
59 | .data = &init_net.ipv6.sysctl.idgen_retries, | ||
60 | .maxlen = sizeof(int), | ||
61 | .mode = 0644, | ||
62 | .proc_handler = proc_dointvec, | ||
63 | }, | ||
64 | { | ||
65 | .procname = "idgen_delay", | ||
66 | .data = &init_net.ipv6.sysctl.idgen_delay, | ||
67 | .maxlen = sizeof(int), | ||
68 | .mode = 0644, | ||
69 | .proc_handler = proc_dointvec_jiffies, | ||
70 | }, | ||
57 | { } | 71 | { } |
58 | }; | 72 | }; |
59 | 73 | ||
@@ -93,6 +107,8 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) | |||
93 | ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; | 107 | ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; |
94 | ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels; | 108 | ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels; |
95 | ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect; | 109 | ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect; |
110 | ipv6_table[5].data = &net->ipv6.sysctl.idgen_retries; | ||
111 | ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay; | ||
96 | 112 | ||
97 | ipv6_route_table = ipv6_route_sysctl_init(net); | 113 | ipv6_route_table = ipv6_route_sysctl_init(net); |
98 | if (!ipv6_route_table) | 114 | if (!ipv6_route_table) |