|
@@ -243,6 +243,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
|
|
|
.seg6_require_hmac = 0,
|
|
|
#endif
|
|
|
.enhanced_dad = 1,
|
|
|
+ .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
|
|
|
};
|
|
|
|
|
|
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
@@ -294,6 +295,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
|
.seg6_require_hmac = 0,
|
|
|
#endif
|
|
|
.enhanced_dad = 1,
|
|
|
+ .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
|
|
|
};
|
|
|
|
|
|
/* Check if a valid qdisc is available */
|
|
@@ -386,9 +388,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
|
|
memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
|
|
|
|
|
|
if (ndev->cnf.stable_secret.initialized)
|
|
|
- ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
+ ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
else
|
|
|
- ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64;
|
|
|
+ ndev->cnf.addr_gen_mode = ipv6_devconf_dflt.addr_gen_mode;
|
|
|
|
|
|
ndev->cnf.mtu6 = dev->mtu;
|
|
|
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
|
|
@@ -2387,8 +2389,8 @@ static void manage_tempaddrs(struct inet6_dev *idev,
|
|
|
|
|
|
static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
|
|
|
{
|
|
|
- return idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
|
|
|
- idev->addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
|
|
|
+ return idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
|
|
|
+ idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
|
|
|
}
|
|
|
|
|
|
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
|
|
@@ -3152,7 +3154,7 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
|
|
|
|
|
|
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
|
|
|
|
|
|
- switch (idev->addr_gen_mode) {
|
|
|
+ switch (idev->cnf.addr_gen_mode) {
|
|
|
case IN6_ADDR_GEN_MODE_RANDOM:
|
|
|
ipv6_gen_mode_random_init(idev);
|
|
|
/* fallthrough */
|
|
@@ -3204,8 +3206,8 @@ static void addrconf_dev_config(struct net_device *dev)
|
|
|
|
|
|
/* this device type has no EUI support */
|
|
|
if (dev->type == ARPHRD_NONE &&
|
|
|
- idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)
|
|
|
- idev->addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM;
|
|
|
+ idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)
|
|
|
+ idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM;
|
|
|
|
|
|
addrconf_addr_gen(idev, false);
|
|
|
}
|
|
@@ -4982,6 +4984,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
|
|
|
array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac;
|
|
|
#endif
|
|
|
array[DEVCONF_ENHANCED_DAD] = cnf->enhanced_dad;
|
|
|
+ array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode;
|
|
|
}
|
|
|
|
|
|
static inline size_t inet6_ifla6_size(void)
|
|
@@ -5093,7 +5096,7 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev,
|
|
|
if (!nla)
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
- if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->addr_gen_mode))
|
|
|
+ if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->cnf.addr_gen_mode))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
read_lock_bh(&idev->lock);
|
|
@@ -5211,6 +5214,26 @@ static int inet6_validate_link_af(const struct net_device *dev,
|
|
|
return nla_parse_nested(tb, IFLA_INET6_MAX, nla, inet6_af_policy);
|
|
|
}
|
|
|
|
|
|
+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_RANDOM)
|
|
|
+ return -EINVAL;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int check_stable_privacy(struct inet6_dev *idev, struct net *net,
|
|
|
+ int mode)
|
|
|
+{
|
|
|
+ if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
|
|
|
+ !idev->cnf.stable_secret.initialized &&
|
|
|
+ !net->ipv6.devconf_dflt->stable_secret.initialized)
|
|
|
+ return -EINVAL;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
|
|
|
{
|
|
|
int err = -EINVAL;
|
|
@@ -5232,18 +5255,11 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
|
|
|
if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
|
|
|
u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_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_RANDOM)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
|
|
|
- !idev->cnf.stable_secret.initialized &&
|
|
|
- !dev_net(dev)->ipv6.devconf_dflt->stable_secret.initialized)
|
|
|
+ if (check_addr_gen_mode(mode) < 0 ||
|
|
|
+ check_stable_privacy(idev, dev_net(dev), mode) < 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- idev->addr_gen_mode = mode;
|
|
|
+ idev->cnf.addr_gen_mode = mode;
|
|
|
err = 0;
|
|
|
}
|
|
|
|
|
@@ -5652,6 +5668,47 @@ int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
|
|
|
+ void __user *buffer, size_t *lenp,
|
|
|
+ loff_t *ppos)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ int new_val;
|
|
|
+ struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1;
|
|
|
+ struct net *net = (struct net *)ctl->extra2;
|
|
|
+
|
|
|
+ ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
|
|
|
+
|
|
|
+ if (write) {
|
|
|
+ new_val = *((int *)ctl->data);
|
|
|
+
|
|
|
+ if (check_addr_gen_mode(new_val) < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* request for default */
|
|
|
+ if (&net->ipv6.devconf_dflt->addr_gen_mode == ctl->data) {
|
|
|
+ ipv6_devconf_dflt.addr_gen_mode = new_val;
|
|
|
+
|
|
|
+ /* request for individual net device */
|
|
|
+ } else {
|
|
|
+ if (!idev)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (check_stable_privacy(idev, net, new_val) < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (idev->cnf.addr_gen_mode != new_val) {
|
|
|
+ idev->cnf.addr_gen_mode = new_val;
|
|
|
+ rtnl_lock();
|
|
|
+ addrconf_dev_config(idev->dev);
|
|
|
+ rtnl_unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
|
|
|
void __user *buffer, size_t *lenp,
|
|
|
loff_t *ppos)
|
|
@@ -5702,14 +5759,14 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
|
|
|
struct inet6_dev *idev = __in6_dev_get(dev);
|
|
|
|
|
|
if (idev) {
|
|
|
- idev->addr_gen_mode =
|
|
|
+ idev->cnf.addr_gen_mode =
|
|
|
IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
struct inet6_dev *idev = ctl->extra1;
|
|
|
|
|
|
- idev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
+ idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -6096,6 +6153,13 @@ static const struct ctl_table addrconf_sysctl[] = {
|
|
|
.mode = 0644,
|
|
|
.proc_handler = proc_dointvec,
|
|
|
},
|
|
|
+ {
|
|
|
+ .procname = "addr_gen_mode",
|
|
|
+ .data = &ipv6_devconf.addr_gen_mode,
|
|
|
+ .maxlen = sizeof(int),
|
|
|
+ .mode = 0644,
|
|
|
+ .proc_handler = addrconf_sysctl_addr_gen_mode,
|
|
|
+ },
|
|
|
{
|
|
|
/* sentinel */
|
|
|
}
|