|
@@ -46,6 +46,7 @@
|
|
#include <linux/socket.h>
|
|
#include <linux/socket.h>
|
|
#include <linux/sockios.h>
|
|
#include <linux/sockios.h>
|
|
#include <linux/net.h>
|
|
#include <linux/net.h>
|
|
|
|
+#include <linux/inet.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/if_addr.h>
|
|
#include <linux/if_addr.h>
|
|
@@ -102,6 +103,9 @@
|
|
|
|
|
|
#define INFINITY_LIFE_TIME 0xFFFFFFFF
|
|
#define INFINITY_LIFE_TIME 0xFFFFFFFF
|
|
|
|
|
|
|
|
+#define IPV6_MAX_STRLEN \
|
|
|
|
+ sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
|
|
|
|
+
|
|
static inline u32 cstamp_delta(unsigned long cstamp)
|
|
static inline u32 cstamp_delta(unsigned long cstamp)
|
|
{
|
|
{
|
|
return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
|
|
return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
|
|
@@ -202,6 +206,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
|
|
.accept_dad = 1,
|
|
.accept_dad = 1,
|
|
.suppress_frag_ndisc = 1,
|
|
.suppress_frag_ndisc = 1,
|
|
.accept_ra_mtu = 1,
|
|
.accept_ra_mtu = 1,
|
|
|
|
+ .stable_secret = {
|
|
|
|
+ .initialized = false,
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
@@ -240,6 +247,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
|
|
.accept_dad = 1,
|
|
.accept_dad = 1,
|
|
.suppress_frag_ndisc = 1,
|
|
.suppress_frag_ndisc = 1,
|
|
.accept_ra_mtu = 1,
|
|
.accept_ra_mtu = 1,
|
|
|
|
+ .stable_secret = {
|
|
|
|
+ .initialized = false,
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
/* Check if a valid qdisc is available */
|
|
/* Check if a valid qdisc is available */
|
|
@@ -4430,6 +4440,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
|
|
array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
|
|
array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
|
|
array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
|
|
array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
|
|
array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu;
|
|
array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu;
|
|
|
|
+ /* we omit DEVCONF_STABLE_SECRET for now */
|
|
}
|
|
}
|
|
|
|
|
|
static inline size_t inet6_ifla6_size(void)
|
|
static inline size_t inet6_ifla6_size(void)
|
|
@@ -5074,6 +5085,53 @@ int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
|
|
|
|
+ void __user *buffer, size_t *lenp,
|
|
|
|
+ loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ int err;
|
|
|
|
+ struct in6_addr addr;
|
|
|
|
+ char str[IPV6_MAX_STRLEN];
|
|
|
|
+ struct ctl_table lctl = *ctl;
|
|
|
|
+ struct ipv6_stable_secret *secret = ctl->data;
|
|
|
|
+
|
|
|
|
+ lctl.maxlen = IPV6_MAX_STRLEN;
|
|
|
|
+ lctl.data = str;
|
|
|
|
+
|
|
|
|
+ if (!rtnl_trylock())
|
|
|
|
+ return restart_syscall();
|
|
|
|
+
|
|
|
|
+ if (!write && !secret->initialized) {
|
|
|
|
+ err = -EIO;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!write) {
|
|
|
|
+ err = snprintf(str, sizeof(str), "%pI6",
|
|
|
|
+ &secret->secret);
|
|
|
|
+ if (err >= sizeof(str)) {
|
|
|
|
+ err = -EIO;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = proc_dostring(&lctl, write, buffer, lenp, ppos);
|
|
|
|
+ if (err || !write)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ if (in6_pton(str, -1, addr.in6_u.u6_addr8, -1, NULL) != 1) {
|
|
|
|
+ err = -EIO;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ secret->initialized = true;
|
|
|
|
+ secret->secret = addr;
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ rtnl_unlock();
|
|
|
|
+
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
|
|
static struct addrconf_sysctl_table
|
|
static struct addrconf_sysctl_table
|
|
{
|
|
{
|
|
@@ -5346,6 +5404,13 @@ static struct addrconf_sysctl_table
|
|
.mode = 0644,
|
|
.mode = 0644,
|
|
.proc_handler = proc_dointvec,
|
|
.proc_handler = proc_dointvec,
|
|
},
|
|
},
|
|
|
|
+ {
|
|
|
|
+ .procname = "stable_secret",
|
|
|
|
+ .data = &ipv6_devconf.stable_secret,
|
|
|
|
+ .maxlen = IPV6_MAX_STRLEN,
|
|
|
|
+ .mode = 0600,
|
|
|
|
+ .proc_handler = addrconf_sysctl_stable_secret,
|
|
|
|
+ },
|
|
{
|
|
{
|
|
/* sentinel */
|
|
/* sentinel */
|
|
}
|
|
}
|
|
@@ -5442,6 +5507,9 @@ static int __net_init addrconf_init_net(struct net *net)
|
|
dflt->autoconf = ipv6_defaults.autoconf;
|
|
dflt->autoconf = ipv6_defaults.autoconf;
|
|
dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
|
|
dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
|
|
|
|
|
|
|
|
+ dflt->stable_secret.initialized = false;
|
|
|
|
+ all->stable_secret.initialized = false;
|
|
|
|
+
|
|
net->ipv6.devconf_all = all;
|
|
net->ipv6.devconf_all = all;
|
|
net->ipv6.devconf_dflt = dflt;
|
|
net->ipv6.devconf_dflt = dflt;
|
|
|
|
|