diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-06-05 02:35:37 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-06-07 16:39:19 -0400 |
commit | 31be308541e990592a2d0a3e77e8e51bd0cea0e0 (patch) | |
tree | 4b37efef3a38439be092ca269e687706be07f8f1 /net/ipv4 | |
parent | 42f811b8bcdf6695bf74de580b1daf53445e8949 (diff) |
[IPV4]: Add default config support after inetdev_init
Previously once inetdev_init has been called on a device any changes
made to ipv4_devconf_dflt would have no effect on that device's
configuration.
This creates a problem since we have moved the point where
inetdev_init is called from when an address is added to where the
device is registered.
This patch is the first half of a set that tries to mimic the old
behaviour while still calling inetdev_init.
It propagates any changes to ipv4_devconf_dflt to those devices that
have not had the corresponding attribute set.
The next patch will forcibly set all values at the point where
inetdev_init was previously called.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/devinet.c | 133 |
1 files changed, 98 insertions, 35 deletions
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) { |