aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/inetdevice.h3
-rw-r--r--net/ipv4/devinet.c133
2 files changed, 101 insertions, 35 deletions
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 1ef174d83e09..40adefdfe5d1 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -3,6 +3,7 @@
3 3
4#ifdef __KERNEL__ 4#ifdef __KERNEL__
5 5
6#include <linux/bitmap.h>
6#include <linux/if.h> 7#include <linux/if.h>
7#include <linux/netdevice.h> 8#include <linux/netdevice.h>
8#include <linux/rcupdate.h> 9#include <linux/rcupdate.h>
@@ -12,6 +13,7 @@ struct ipv4_devconf
12{ 13{
13 void *sysctl; 14 void *sysctl;
14 int data[__NET_IPV4_CONF_MAX - 1]; 15 int data[__NET_IPV4_CONF_MAX - 1];
16 DECLARE_BITMAP(state, __NET_IPV4_CONF_MAX - 1);
15}; 17};
16 18
17extern struct ipv4_devconf ipv4_devconf; 19extern struct ipv4_devconf ipv4_devconf;
@@ -53,6 +55,7 @@ static inline void ipv4_devconf_set(struct in_device *in_dev, int index,
53 int val) 55 int val)
54{ 56{
55 index--; 57 index--;
58 set_bit(index, in_dev->cnf.state);
56 in_dev->cnf.data[index] = val; 59 in_dev->cnf.data[index] = val;
57} 60}
58 61
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 00940660739f..e19734795a7b 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1244,6 +1244,91 @@ errout:
1244 1244
1245#ifdef CONFIG_SYSCTL 1245#ifdef CONFIG_SYSCTL
1246 1246
1247static void devinet_copy_dflt_conf(int i)
1248{
1249 struct net_device *dev;
1250
1251 read_lock(&dev_base_lock);
1252 for_each_netdev(dev) {
1253 struct in_device *in_dev;
1254 rcu_read_lock();
1255 in_dev = __in_dev_get_rcu(dev);
1256 if (in_dev && !test_bit(i, in_dev->cnf.state))
1257 in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
1258 rcu_read_unlock();
1259 }
1260 read_unlock(&dev_base_lock);
1261}
1262
1263static int devinet_conf_proc(ctl_table *ctl, int write,
1264 struct file* filp, void __user *buffer,
1265 size_t *lenp, loff_t *ppos)
1266{
1267 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1268
1269 if (write) {
1270 struct ipv4_devconf *cnf = ctl->extra1;
1271 int i = (int *)ctl->data - cnf->data;
1272
1273 set_bit(i, cnf->state);
1274
1275 if (cnf == &ipv4_devconf_dflt)
1276 devinet_copy_dflt_conf(i);
1277 }
1278
1279 return ret;
1280}
1281
1282static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1283 void __user *oldval, size_t __user *oldlenp,
1284 void __user *newval, size_t newlen)
1285{
1286 struct ipv4_devconf *cnf;
1287 int *valp = table->data;
1288 int new;
1289 int i;
1290
1291 if (!newval || !newlen)
1292 return 0;
1293
1294 if (newlen != sizeof(int))
1295 return -EINVAL;
1296
1297 if (get_user(new, (int __user *)newval))
1298 return -EFAULT;
1299
1300 if (new == *valp)
1301 return 0;
1302
1303 if (oldval && oldlenp) {
1304 size_t len;
1305
1306 if (get_user(len, oldlenp))
1307 return -EFAULT;
1308
1309 if (len) {
1310 if (len > table->maxlen)
1311 len = table->maxlen;
1312 if (copy_to_user(oldval, valp, len))
1313 return -EFAULT;
1314 if (put_user(len, oldlenp))
1315 return -EFAULT;
1316 }
1317 }
1318
1319 *valp = new;
1320
1321 cnf = table->extra1;
1322 i = (int *)table->data - cnf->data;
1323
1324 set_bit(i, cnf->state);
1325
1326 if (cnf == &ipv4_devconf_dflt)
1327 devinet_copy_dflt_conf(i);
1328
1329 return 1;
1330}
1331
1247void inet_forward_change(void) 1332void inet_forward_change(void)
1248{ 1333{
1249 struct net_device *dev; 1334 struct net_device *dev;
@@ -1302,40 +1387,13 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1302 void __user *oldval, size_t __user *oldlenp, 1387 void __user *oldval, size_t __user *oldlenp,
1303 void __user *newval, size_t newlen) 1388 void __user *newval, size_t newlen)
1304{ 1389{
1305 int *valp = table->data; 1390 int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
1306 int new; 1391 newval, newlen);
1307
1308 if (!newval || !newlen)
1309 return 0;
1310
1311 if (newlen != sizeof(int))
1312 return -EINVAL;
1313 1392
1314 if (get_user(new, (int __user *)newval)) 1393 if (ret == 1)
1315 return -EFAULT; 1394 rt_cache_flush(0);
1316
1317 if (new == *valp)
1318 return 0;
1319
1320 if (oldval && oldlenp) {
1321 size_t len;
1322
1323 if (get_user(len, oldlenp))
1324 return -EFAULT;
1325
1326 if (len) {
1327 if (len > table->maxlen)
1328 len = table->maxlen;
1329 if (copy_to_user(oldval, valp, len))
1330 return -EFAULT;
1331 if (put_user(len, oldlenp))
1332 return -EFAULT;
1333 }
1334 }
1335 1395
1336 *valp = new; 1396 return ret;
1337 rt_cache_flush(0);
1338 return 1;
1339} 1397}
1340 1398
1341 1399
@@ -1349,13 +1407,16 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
1349 .mode = mval, \ 1407 .mode = mval, \
1350 .proc_handler = proc, \ 1408 .proc_handler = proc, \
1351 .strategy = sysctl, \ 1409 .strategy = sysctl, \
1410 .extra1 = &ipv4_devconf, \
1352 } 1411 }
1353 1412
1354#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \ 1413#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \
1355 DEVINET_SYSCTL_ENTRY(attr, name, 0644, &proc_dointvec, NULL) 1414 DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \
1415 devinet_conf_sysctl)
1356 1416
1357#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \ 1417#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \
1358 DEVINET_SYSCTL_ENTRY(attr, name, 0444, &proc_dointvec, NULL) 1418 DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \
1419 devinet_conf_sysctl)
1359 1420
1360#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \ 1421#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \
1361 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl) 1422 DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)
@@ -1374,7 +1435,8 @@ static struct devinet_sysctl_table {
1374} devinet_sysctl = { 1435} devinet_sysctl = {
1375 .devinet_vars = { 1436 .devinet_vars = {
1376 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding", 1437 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
1377 devinet_sysctl_forward, NULL), 1438 devinet_sysctl_forward,
1439 devinet_conf_sysctl),
1378 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"), 1440 DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
1379 1441
1380 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"), 1442 DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
@@ -1448,6 +1510,7 @@ static void devinet_sysctl_register(struct in_device *in_dev,
1448 return; 1510 return;
1449 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { 1511 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1450 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; 1512 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
1513 t->devinet_vars[i].extra1 = p;
1451 } 1514 }
1452 1515
1453 if (dev) { 1516 if (dev) {