#include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
+#include <linux/inet.h>
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_addr.h>
 
 #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)
 {
        return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
        .accept_dad             = 1,
        .suppress_frag_ndisc    = 1,
        .accept_ra_mtu          = 1,
+       .stable_secret          = {
+               .initialized = false,
+       }
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .accept_dad             = 1,
        .suppress_frag_ndisc    = 1,
        .accept_ra_mtu          = 1,
+       .stable_secret          = {
+               .initialized = false,
+       },
 };
 
 /* Check if a valid qdisc is available */
        array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
        array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
        array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu;
+       /* we omit DEVCONF_STABLE_SECRET for now */
 }
 
 static inline size_t inet6_ifla6_size(void)
        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
 {
                        .mode           = 0644,
                        .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 */
                }
        dflt->autoconf = ipv6_defaults.autoconf;
        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_dflt = dflt;