diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 25 | ||||
-rw-r--r-- | include/linux/ipv6.h | 4 | ||||
-rw-r--r-- | include/net/if_inet6.h | 4 | ||||
-rw-r--r-- | include/net/netns/ipv6.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/if_addr.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/ipv6.h | 1 | ||||
-rw-r--r-- | lib/sha1.c | 1 | ||||
-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 |
11 files changed, 321 insertions, 29 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 6c07c2b36909..071fb18dc57c 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -1220,6 +1220,17 @@ anycast_src_echo_reply - BOOLEAN | |||
1220 | FALSE: disabled | 1220 | FALSE: disabled |
1221 | Default: FALSE | 1221 | Default: FALSE |
1222 | 1222 | ||
1223 | idgen_delay - INTEGER | ||
1224 | Controls the delay in seconds after which time to retry | ||
1225 | privacy stable address generation if a DAD conflict is | ||
1226 | detected. | ||
1227 | Default: 1 (as specified in RFC7217) | ||
1228 | |||
1229 | idgen_retries - INTEGER | ||
1230 | Controls the number of retries to generate a stable privacy | ||
1231 | address if a DAD conflict is detected. | ||
1232 | Default: 3 (as specified in RFC7217) | ||
1233 | |||
1223 | mld_qrv - INTEGER | 1234 | mld_qrv - INTEGER |
1224 | Controls the MLD query robustness variable (see RFC3810 9.1). | 1235 | Controls the MLD query robustness variable (see RFC3810 9.1). |
1225 | Default: 2 (as specified by RFC3810 9.1) | 1236 | Default: 2 (as specified by RFC3810 9.1) |
@@ -1540,6 +1551,20 @@ use_optimistic - BOOLEAN | |||
1540 | 0: disabled (default) | 1551 | 0: disabled (default) |
1541 | 1: enabled | 1552 | 1: enabled |
1542 | 1553 | ||
1554 | stable_secret - IPv6 address | ||
1555 | This IPv6 address will be used as a secret to generate IPv6 | ||
1556 | addresses for link-local addresses and autoconfigured | ||
1557 | ones. All addresses generated after setting this secret will | ||
1558 | be stable privacy ones by default. This can be changed via the | ||
1559 | addrgenmode ip-link. conf/default/stable_secret is used as the | ||
1560 | secret for the namespace, the interface specific ones can | ||
1561 | overwrite that. Writes to conf/all/stable_secret are refused. | ||
1562 | |||
1563 | It is recommended to generate this secret during installation | ||
1564 | of a system and keep it stable after that. | ||
1565 | |||
1566 | By default the stable secret is unset. | ||
1567 | |||
1543 | icmp/*: | 1568 | icmp/*: |
1544 | ratelimit - INTEGER | 1569 | ratelimit - INTEGER |
1545 | Limit the maximal rates for sending ICMPv6 packets. | 1570 | Limit the maximal rates for sending ICMPv6 packets. |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4d5169f5d7d1..82806c60aa42 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -53,6 +53,10 @@ struct ipv6_devconf { | |||
53 | __s32 ndisc_notify; | 53 | __s32 ndisc_notify; |
54 | __s32 suppress_frag_ndisc; | 54 | __s32 suppress_frag_ndisc; |
55 | __s32 accept_ra_mtu; | 55 | __s32 accept_ra_mtu; |
56 | struct ipv6_stable_secret { | ||
57 | bool initialized; | ||
58 | struct in6_addr secret; | ||
59 | } stable_secret; | ||
56 | void *sysctl; | 60 | void *sysctl; |
57 | }; | 61 | }; |
58 | 62 | ||
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 98e5f9578f86..1c8b6820b694 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -41,18 +41,18 @@ enum { | |||
41 | struct inet6_ifaddr { | 41 | struct inet6_ifaddr { |
42 | struct in6_addr addr; | 42 | struct in6_addr addr; |
43 | __u32 prefix_len; | 43 | __u32 prefix_len; |
44 | 44 | ||
45 | /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ | 45 | /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ |
46 | __u32 valid_lft; | 46 | __u32 valid_lft; |
47 | __u32 prefered_lft; | 47 | __u32 prefered_lft; |
48 | atomic_t refcnt; | 48 | atomic_t refcnt; |
49 | spinlock_t lock; | 49 | spinlock_t lock; |
50 | spinlock_t state_lock; | ||
51 | 50 | ||
52 | int state; | 51 | int state; |
53 | 52 | ||
54 | __u32 flags; | 53 | __u32 flags; |
55 | __u8 dad_probes; | 54 | __u8 dad_probes; |
55 | __u8 stable_privacy_retry; | ||
56 | 56 | ||
57 | __u16 scope; | 57 | __u16 scope; |
58 | 58 | ||
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index ca0db12cd089..d2527bf81142 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h | |||
@@ -32,6 +32,8 @@ struct netns_sysctl_ipv6 { | |||
32 | int icmpv6_time; | 32 | int icmpv6_time; |
33 | int anycast_src_echo_reply; | 33 | int anycast_src_echo_reply; |
34 | int fwmark_reflect; | 34 | int fwmark_reflect; |
35 | int idgen_retries; | ||
36 | int idgen_delay; | ||
35 | }; | 37 | }; |
36 | 38 | ||
37 | struct netns_ipv6 { | 39 | struct netns_ipv6 { |
diff --git a/include/uapi/linux/if_addr.h b/include/uapi/linux/if_addr.h index 40fdfea39714..4318ab1635ce 100644 --- a/include/uapi/linux/if_addr.h +++ b/include/uapi/linux/if_addr.h | |||
@@ -51,6 +51,7 @@ enum { | |||
51 | #define IFA_F_MANAGETEMPADDR 0x100 | 51 | #define IFA_F_MANAGETEMPADDR 0x100 |
52 | #define IFA_F_NOPREFIXROUTE 0x200 | 52 | #define IFA_F_NOPREFIXROUTE 0x200 |
53 | #define IFA_F_MCAUTOJOIN 0x400 | 53 | #define IFA_F_MCAUTOJOIN 0x400 |
54 | #define IFA_F_STABLE_PRIVACY 0x800 | ||
54 | 55 | ||
55 | struct ifa_cacheinfo { | 56 | struct ifa_cacheinfo { |
56 | __u32 ifa_prefered; | 57 | __u32 ifa_prefered; |
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index f5f5edd5ae5f..7ffb18df01ca 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -216,6 +216,7 @@ enum { | |||
216 | enum in6_addr_gen_mode { | 216 | enum in6_addr_gen_mode { |
217 | IN6_ADDR_GEN_MODE_EUI64, | 217 | IN6_ADDR_GEN_MODE_EUI64, |
218 | IN6_ADDR_GEN_MODE_NONE, | 218 | IN6_ADDR_GEN_MODE_NONE, |
219 | IN6_ADDR_GEN_MODE_STABLE_PRIVACY, | ||
219 | }; | 220 | }; |
220 | 221 | ||
221 | /* Bridge section */ | 222 | /* Bridge section */ |
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 437a6a4b125a..5efa54ae567c 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h | |||
@@ -170,6 +170,7 @@ enum { | |||
170 | DEVCONF_ACCEPT_RA_FROM_LOCAL, | 170 | DEVCONF_ACCEPT_RA_FROM_LOCAL, |
171 | DEVCONF_USE_OPTIMISTIC, | 171 | DEVCONF_USE_OPTIMISTIC, |
172 | DEVCONF_ACCEPT_RA_MTU, | 172 | DEVCONF_ACCEPT_RA_MTU, |
173 | DEVCONF_STABLE_SECRET, | ||
173 | DEVCONF_MAX | 174 | DEVCONF_MAX |
174 | }; | 175 | }; |
175 | 176 | ||
diff --git a/lib/sha1.c b/lib/sha1.c index 1df191e04a24..5a56dfd7b99d 100644 --- a/lib/sha1.c +++ b/lib/sha1.c | |||
@@ -198,3 +198,4 @@ void sha_init(__u32 *buf) | |||
198 | buf[3] = 0x10325476; | 198 | buf[3] = 0x10325476; |
199 | buf[4] = 0xc3d2e1f0; | 199 | buf[4] = 0xc3d2e1f0; |
200 | } | 200 | } |
201 | EXPORT_SYMBOL(sha_init); | ||
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) |