diff options
-rw-r--r-- | include/linux/inetdevice.h | 3 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 133 |
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 | ||
17 | extern struct ipv4_devconf ipv4_devconf; | 19 | extern 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 | ||
1247 | static 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 | |||
1263 | static 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 | |||
1282 | static 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 | |||
1247 | void inet_forward_change(void) | 1332 | void 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) { |