diff mbox series

ipv6: Add IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC mode

Message ID 20200519120748.115833-1-brambonne@google.com
State New
Headers show
Series ipv6: Add IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC mode | expand

Commit Message

=?UTF-8?q?Bram=20Bonn=C3=A9?= May 19, 2020, 12:07 p.m. UTC
IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC behaves like the existing
IN6_ADDR_GEN_MODE_STABLE_PRIVACY mode, but uses the software-defined MAC
address (dev_addr) instead of the permanent, hardware-defined MAC
address (perm_addr) when generating IPv6 link-local addresses.

This mode allows the IPv6 link-local address to change in line with the
MAC address when per-network MAC address randomization is used. In this
case, the MAC address fulfills the role of both the Net_Iface and the
Network_ID parameters in RFC7217.

Signed-off-by: Bram Bonné <brambonne@google.com>
---
 include/uapi/linux/if_link.h |  1 +
 net/ipv6/addrconf.c          | 29 ++++++++++++++++++++++++-----
 2 files changed, 25 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index a009365ad67b..0de71cfdcd84 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -240,6 +240,7 @@  enum in6_addr_gen_mode {
 	IN6_ADDR_GEN_MODE_NONE,
 	IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
 	IN6_ADDR_GEN_MODE_RANDOM,
+	IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC,
 };
 
 /* Bridge section */
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ab7e839753ae..02d999ca332c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -142,6 +142,7 @@  static int ipv6_count_addresses(const struct inet6_dev *idev);
 static int ipv6_generate_stable_address(struct in6_addr *addr,
 					u8 dad_count,
 					const struct inet6_dev *idev);
+static bool ipv6_addr_gen_use_softmac(const struct inet6_dev *idev);
 
 #define IN6_ADDR_HSIZE_SHIFT	8
 #define IN6_ADDR_HSIZE		(1 << IN6_ADDR_HSIZE_SHIFT)
@@ -381,7 +382,8 @@  static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
 	timer_setup(&ndev->rs_timer, addrconf_rs_timer, 0);
 	memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
 
-	if (ndev->cnf.stable_secret.initialized)
+	if (ndev->cnf.stable_secret.initialized &&
+	    !ipv6_addr_gen_use_softmac(ndev))
 		ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 
 	ndev->cnf.mtu6 = dev->mtu;
@@ -2540,6 +2542,8 @@  static void manage_tempaddrs(struct inet6_dev *idev,
 static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
 {
 	return idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
+	       idev->cnf.addr_gen_mode ==
+		       IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC ||
 	       idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
 }
 
@@ -3191,6 +3195,12 @@  static bool ipv6_reserved_interfaceid(struct in6_addr address)
 	return false;
 }
 
+static inline bool ipv6_addr_gen_use_softmac(const struct inet6_dev *idev)
+{
+	return idev->cnf.addr_gen_mode ==
+	    IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC;
+}
+
 static int ipv6_generate_stable_address(struct in6_addr *address,
 					u8 dad_count,
 					const struct inet6_dev *idev)
@@ -3212,6 +3222,7 @@  static int ipv6_generate_stable_address(struct in6_addr *address,
 	struct in6_addr secret;
 	struct in6_addr temp;
 	struct net *net = dev_net(idev->dev);
+	unsigned char *hwaddr;
 
 	BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
 
@@ -3222,13 +3233,16 @@  static int ipv6_generate_stable_address(struct in6_addr *address,
 	else
 		return -1;
 
+	hwaddr = ipv6_addr_gen_use_softmac(idev) ?
+			idev->dev->dev_addr : idev->dev->perm_addr;
+
 retry:
 	spin_lock_bh(&lock);
 
 	sha_init(digest);
 	memset(&data, 0, sizeof(data));
 	memset(workspace, 0, sizeof(workspace));
-	memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+	memcpy(data.hwaddr, hwaddr, idev->dev->addr_len);
 	data.prefix[0] = address->s6_addr32[0];
 	data.prefix[1] = address->s6_addr32[1];
 	data.secret = secret;
@@ -3283,6 +3297,7 @@  static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
 		ipv6_gen_mode_random_init(idev);
 		fallthrough;
 	case IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
+	case IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC:
 		if (!ipv6_generate_stable_address(&addr, 0, idev))
 			addrconf_add_linklocal(idev, &addr,
 					       IFA_F_STABLE_PRIVACY);
@@ -5726,6 +5741,7 @@  static int check_addr_gen_mode(int mode)
 	if (mode != IN6_ADDR_GEN_MODE_EUI64 &&
 	    mode != IN6_ADDR_GEN_MODE_NONE &&
 	    mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+	    mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY_SOFTMAC &&
 	    mode != IN6_ADDR_GEN_MODE_RANDOM)
 		return -EINVAL;
 	return 1;
@@ -5734,7 +5750,8 @@  static int check_addr_gen_mode(int mode)
 static int check_stable_privacy(struct inet6_dev *idev, struct net *net,
 				int mode)
 {
-	if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+	if ((mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
+	     mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) &&
 	    !idev->cnf.stable_secret.initialized &&
 	    !net->ipv6.devconf_dflt->stable_secret.initialized)
 		return -EINVAL;
@@ -6355,7 +6372,7 @@  static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
 		for_each_netdev(net, dev) {
 			struct inet6_dev *idev = __in6_dev_get(dev);
 
-			if (idev) {
+			if (idev && !ipv6_addr_gen_use_softmac(idev)) {
 				idev->cnf.addr_gen_mode =
 					IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 			}
@@ -6363,7 +6380,9 @@  static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
 	} else {
 		struct inet6_dev *idev = ctl->extra1;
 
-		idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+		if (idev && !ipv6_addr_gen_use_softmac(idev))
+			idev->cnf.addr_gen_mode =
+				IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 	}
 
 out: