aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2015-03-23 18:36:00 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-23 22:12:08 -0400
commit3d1bec99320d4e96897805440f8cf4f68eff226b (patch)
tree4926f2e4fe0ef525249397d391443e24cbea3fc2 /net/ipv6
parentab2bb3241739870d417979a81843631e5588a2d7 (diff)
ipv6: introduce secret_stable to ipv6_devconf
This patch implements the procfs logic for the stable_address knob: The secret is formatted as an ipv6 address and will be stored per interface and per namespace. We track initialized flag and return EIO errors until the secret is set. We don't inherit the secret to newly created namespaces. Cc: Erik Kline <ek@google.com> Cc: Fernando Gont <fgont@si6networks.com> Cc: Lorenzo Colitti <lorenzo@google.com> Cc: YOSHIFUJI Hideaki/吉藤英明 <hideaki.yoshifuji@miraclelinux.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 158378e73f0a..5b967c8a617a 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
105static inline u32 cstamp_delta(unsigned long cstamp) 109static inline u32 cstamp_delta(unsigned long cstamp)
106{ 110{
107 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; 111 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
@@ -202,6 +206,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
202 .accept_dad = 1, 206 .accept_dad = 1,
203 .suppress_frag_ndisc = 1, 207 .suppress_frag_ndisc = 1,
204 .accept_ra_mtu = 1, 208 .accept_ra_mtu = 1,
209 .stable_secret = {
210 .initialized = false,
211 }
205}; 212};
206 213
207static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 214static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -240,6 +247,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
240 .accept_dad = 1, 247 .accept_dad = 1,
241 .suppress_frag_ndisc = 1, 248 .suppress_frag_ndisc = 1,
242 .accept_ra_mtu = 1, 249 .accept_ra_mtu = 1,
250 .stable_secret = {
251 .initialized = false,
252 },
243}; 253};
244 254
245/* Check if a valid qdisc is available */ 255/* Check if a valid qdisc is available */
@@ -4430,6 +4440,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4430 array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; 4440 array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
4431 array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; 4441 array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
4432 array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; 4442 array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu;
4443 /* we omit DEVCONF_STABLE_SECRET for now */
4433} 4444}
4434 4445
4435static inline size_t inet6_ifla6_size(void) 4446static inline size_t inet6_ifla6_size(void)
@@ -5074,6 +5085,53 @@ int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write,
5074 return ret; 5085 return ret;
5075} 5086}
5076 5087
5088static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
5089 void __user *buffer, size_t *lenp,
5090 loff_t *ppos)
5091{
5092 int err;
5093 struct in6_addr addr;
5094 char str[IPV6_MAX_STRLEN];
5095 struct ctl_table lctl = *ctl;
5096 struct ipv6_stable_secret *secret = ctl->data;
5097
5098 lctl.maxlen = IPV6_MAX_STRLEN;
5099 lctl.data = str;
5100
5101 if (!rtnl_trylock())
5102 return restart_syscall();
5103
5104 if (!write && !secret->initialized) {
5105 err = -EIO;
5106 goto out;
5107 }
5108
5109 if (!write) {
5110 err = snprintf(str, sizeof(str), "%pI6",
5111 &secret->secret);
5112 if (err >= sizeof(str)) {
5113 err = -EIO;
5114 goto out;
5115 }
5116 }
5117
5118 err = proc_dostring(&lctl, write, buffer, lenp, ppos);
5119 if (err || !write)
5120 goto out;
5121
5122 if (in6_pton(str, -1, addr.in6_u.u6_addr8, -1, NULL) != 1) {
5123 err = -EIO;
5124 goto out;
5125 }
5126
5127 secret->initialized = true;
5128 secret->secret = addr;
5129
5130out:
5131 rtnl_unlock();
5132
5133 return err;
5134}
5077 5135
5078static struct addrconf_sysctl_table 5136static struct addrconf_sysctl_table
5079{ 5137{
@@ -5347,6 +5405,13 @@ static struct addrconf_sysctl_table
5347 .proc_handler = proc_dointvec, 5405 .proc_handler = proc_dointvec,
5348 }, 5406 },
5349 { 5407 {
5408 .procname = "stable_secret",
5409 .data = &ipv6_devconf.stable_secret,
5410 .maxlen = IPV6_MAX_STRLEN,
5411 .mode = 0600,
5412 .proc_handler = addrconf_sysctl_stable_secret,
5413 },
5414 {
5350 /* sentinel */ 5415 /* sentinel */
5351 } 5416 }
5352 }, 5417 },
@@ -5442,6 +5507,9 @@ static int __net_init addrconf_init_net(struct net *net)
5442 dflt->autoconf = ipv6_defaults.autoconf; 5507 dflt->autoconf = ipv6_defaults.autoconf;
5443 dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; 5508 dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
5444 5509
5510 dflt->stable_secret.initialized = false;
5511 all->stable_secret.initialized = false;
5512
5445 net->ipv6.devconf_all = all; 5513 net->ipv6.devconf_all = all;
5446 net->ipv6.devconf_dflt = dflt; 5514 net->ipv6.devconf_dflt = dflt;
5447 5515