diff options
Diffstat (limited to 'net/ipv6')
40 files changed, 1291 insertions, 1114 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ab7a9124f985..e6f83b6a2b76 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | config IPV6 | 6 | config IPV6 |
| 7 | tristate "The IPv6 protocol" | 7 | tristate "The IPv6 protocol" |
| 8 | default m | 8 | default m |
| 9 | select CRYPTO if IPV6_PRIVACY | ||
| 10 | select CRYPTO_MD5 if IPV6_PRIVACY | ||
| 11 | ---help--- | 9 | ---help--- |
| 12 | This is complemental support for the IP version 6. | 10 | This is complemental support for the IP version 6. |
| 13 | You will still be able to do traditional IPv4 networking as well. | 11 | You will still be able to do traditional IPv4 networking as well. |
| @@ -22,7 +20,7 @@ config IPV6 | |||
| 22 | module will be called ipv6. | 20 | module will be called ipv6. |
| 23 | 21 | ||
| 24 | config IPV6_PRIVACY | 22 | config IPV6_PRIVACY |
| 25 | bool "IPv6: Privacy Extensions (RFC 3041) support" | 23 | bool "IPv6: Privacy Extensions support" |
| 26 | depends on IPV6 | 24 | depends on IPV6 |
| 27 | ---help--- | 25 | ---help--- |
| 28 | Privacy Extensions for Stateless Address Autoconfiguration in IPv6 | 26 | Privacy Extensions for Stateless Address Autoconfiguration in IPv6 |
| @@ -30,6 +28,9 @@ config IPV6_PRIVACY | |||
| 30 | pseudo-random global-scope unicast address(es) will assigned to | 28 | pseudo-random global-scope unicast address(es) will assigned to |
| 31 | your interface(s). | 29 | your interface(s). |
| 32 | 30 | ||
| 31 | We use our standard pseudo random algorithm to generate randomized | ||
| 32 | interface identifier, instead of one described in RFC 3041. | ||
| 33 | |||
| 33 | By default, kernel do not generate temporary addresses. | 34 | By default, kernel do not generate temporary addresses. |
| 34 | To use temporary addresses, do | 35 | To use temporary addresses, do |
| 35 | 36 | ||
| @@ -37,6 +38,25 @@ config IPV6_PRIVACY | |||
| 37 | 38 | ||
| 38 | See <file:Documentation/networking/ip-sysctl.txt> for details. | 39 | See <file:Documentation/networking/ip-sysctl.txt> for details. |
| 39 | 40 | ||
| 41 | config IPV6_ROUTER_PREF | ||
| 42 | bool "IPv6: Router Preference (RFC 4191) support" | ||
| 43 | depends on IPV6 | ||
| 44 | ---help--- | ||
| 45 | Router Preference is an optional extension to the Router | ||
| 46 | Advertisement message to improve the ability of hosts | ||
| 47 | to pick more appropriate router, especially when the hosts | ||
| 48 | is placed in a multi-homed network. | ||
| 49 | |||
| 50 | If unsure, say N. | ||
| 51 | |||
| 52 | config IPV6_ROUTE_INFO | ||
| 53 | bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)" | ||
| 54 | depends on IPV6_ROUTER_PREF && EXPERIMENTAL | ||
| 55 | ---help--- | ||
| 56 | This is experimental support of Route Information. | ||
| 57 | |||
| 58 | If unsure, say N. | ||
| 59 | |||
| 40 | config INET6_AH | 60 | config INET6_AH |
| 41 | tristate "IPv6: AH transformation" | 61 | tristate "IPv6: AH transformation" |
| 42 | depends on IPV6 | 62 | depends on IPV6 |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 19727d941962..01c62a0d3742 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -78,8 +78,6 @@ | |||
| 78 | 78 | ||
| 79 | #ifdef CONFIG_IPV6_PRIVACY | 79 | #ifdef CONFIG_IPV6_PRIVACY |
| 80 | #include <linux/random.h> | 80 | #include <linux/random.h> |
| 81 | #include <linux/crypto.h> | ||
| 82 | #include <linux/scatterlist.h> | ||
| 83 | #endif | 81 | #endif |
| 84 | 82 | ||
| 85 | #include <asm/uaccess.h> | 83 | #include <asm/uaccess.h> |
| @@ -110,8 +108,6 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad | |||
| 110 | static void ipv6_regen_rndid(unsigned long data); | 108 | static void ipv6_regen_rndid(unsigned long data); |
| 111 | 109 | ||
| 112 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | 110 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; |
| 113 | static struct crypto_tfm *md5_tfm; | ||
| 114 | static DEFINE_SPINLOCK(md5_tfm_lock); | ||
| 115 | #endif | 111 | #endif |
| 116 | 112 | ||
| 117 | static int ipv6_count_addresses(struct inet6_dev *idev); | 113 | static int ipv6_count_addresses(struct inet6_dev *idev); |
| @@ -169,6 +165,15 @@ struct ipv6_devconf ipv6_devconf = { | |||
| 169 | .max_desync_factor = MAX_DESYNC_FACTOR, | 165 | .max_desync_factor = MAX_DESYNC_FACTOR, |
| 170 | #endif | 166 | #endif |
| 171 | .max_addresses = IPV6_MAX_ADDRESSES, | 167 | .max_addresses = IPV6_MAX_ADDRESSES, |
| 168 | .accept_ra_defrtr = 1, | ||
| 169 | .accept_ra_pinfo = 1, | ||
| 170 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 171 | .accept_ra_rtr_pref = 1, | ||
| 172 | .rtr_probe_interval = 60 * HZ, | ||
| 173 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 174 | .accept_ra_rt_info_max_plen = 0, | ||
| 175 | #endif | ||
| 176 | #endif | ||
| 172 | }; | 177 | }; |
| 173 | 178 | ||
| 174 | static struct ipv6_devconf ipv6_devconf_dflt = { | 179 | static struct ipv6_devconf ipv6_devconf_dflt = { |
| @@ -190,6 +195,15 @@ static struct ipv6_devconf ipv6_devconf_dflt = { | |||
| 190 | .max_desync_factor = MAX_DESYNC_FACTOR, | 195 | .max_desync_factor = MAX_DESYNC_FACTOR, |
| 191 | #endif | 196 | #endif |
| 192 | .max_addresses = IPV6_MAX_ADDRESSES, | 197 | .max_addresses = IPV6_MAX_ADDRESSES, |
| 198 | .accept_ra_defrtr = 1, | ||
| 199 | .accept_ra_pinfo = 1, | ||
| 200 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 201 | .accept_ra_rtr_pref = 1, | ||
| 202 | .rtr_probe_interval = 60 * HZ, | ||
| 203 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 204 | .accept_ra_rt_info_max_plen = 0, | ||
| 205 | #endif | ||
| 206 | #endif | ||
| 193 | }; | 207 | }; |
| 194 | 208 | ||
| 195 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
| @@ -327,86 +341,83 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
| 327 | if (dev->mtu < IPV6_MIN_MTU) | 341 | if (dev->mtu < IPV6_MIN_MTU) |
| 328 | return NULL; | 342 | return NULL; |
| 329 | 343 | ||
| 330 | ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL); | 344 | ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); |
| 331 | 345 | ||
| 332 | if (ndev) { | 346 | if (ndev == NULL) |
| 333 | memset(ndev, 0, sizeof(struct inet6_dev)); | 347 | return NULL; |
| 334 | 348 | ||
| 335 | rwlock_init(&ndev->lock); | 349 | rwlock_init(&ndev->lock); |
| 336 | ndev->dev = dev; | 350 | ndev->dev = dev; |
| 337 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); | 351 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); |
| 338 | ndev->cnf.mtu6 = dev->mtu; | 352 | ndev->cnf.mtu6 = dev->mtu; |
| 339 | ndev->cnf.sysctl = NULL; | 353 | ndev->cnf.sysctl = NULL; |
| 340 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); | 354 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); |
| 341 | if (ndev->nd_parms == NULL) { | 355 | if (ndev->nd_parms == NULL) { |
| 342 | kfree(ndev); | 356 | kfree(ndev); |
| 343 | return NULL; | 357 | return NULL; |
| 344 | } | 358 | } |
| 345 | /* We refer to the device */ | 359 | /* We refer to the device */ |
| 346 | dev_hold(dev); | 360 | dev_hold(dev); |
| 347 | |||
| 348 | if (snmp6_alloc_dev(ndev) < 0) { | ||
| 349 | ADBG((KERN_WARNING | ||
| 350 | "%s(): cannot allocate memory for statistics; dev=%s.\n", | ||
| 351 | __FUNCTION__, dev->name)); | ||
| 352 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | ||
| 353 | ndev->dead = 1; | ||
| 354 | in6_dev_finish_destroy(ndev); | ||
| 355 | return NULL; | ||
| 356 | } | ||
| 357 | 361 | ||
| 358 | if (snmp6_register_dev(ndev) < 0) { | 362 | if (snmp6_alloc_dev(ndev) < 0) { |
| 359 | ADBG((KERN_WARNING | 363 | ADBG((KERN_WARNING |
| 360 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", | 364 | "%s(): cannot allocate memory for statistics; dev=%s.\n", |
| 361 | __FUNCTION__, dev->name)); | 365 | __FUNCTION__, dev->name)); |
| 362 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | 366 | neigh_parms_release(&nd_tbl, ndev->nd_parms); |
| 363 | ndev->dead = 1; | 367 | ndev->dead = 1; |
| 364 | in6_dev_finish_destroy(ndev); | 368 | in6_dev_finish_destroy(ndev); |
| 365 | return NULL; | 369 | return NULL; |
| 366 | } | 370 | } |
| 367 | 371 | ||
| 368 | /* One reference from device. We must do this before | 372 | if (snmp6_register_dev(ndev) < 0) { |
| 369 | * we invoke __ipv6_regen_rndid(). | 373 | ADBG((KERN_WARNING |
| 370 | */ | 374 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", |
| 371 | in6_dev_hold(ndev); | 375 | __FUNCTION__, dev->name)); |
| 376 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | ||
| 377 | ndev->dead = 1; | ||
| 378 | in6_dev_finish_destroy(ndev); | ||
| 379 | return NULL; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* One reference from device. We must do this before | ||
| 383 | * we invoke __ipv6_regen_rndid(). | ||
| 384 | */ | ||
| 385 | in6_dev_hold(ndev); | ||
| 372 | 386 | ||
| 373 | #ifdef CONFIG_IPV6_PRIVACY | 387 | #ifdef CONFIG_IPV6_PRIVACY |
| 374 | get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); | 388 | init_timer(&ndev->regen_timer); |
| 375 | get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); | 389 | ndev->regen_timer.function = ipv6_regen_rndid; |
| 376 | init_timer(&ndev->regen_timer); | 390 | ndev->regen_timer.data = (unsigned long) ndev; |
| 377 | ndev->regen_timer.function = ipv6_regen_rndid; | 391 | if ((dev->flags&IFF_LOOPBACK) || |
| 378 | ndev->regen_timer.data = (unsigned long) ndev; | 392 | dev->type == ARPHRD_TUNNEL || |
| 379 | if ((dev->flags&IFF_LOOPBACK) || | 393 | dev->type == ARPHRD_NONE || |
| 380 | dev->type == ARPHRD_TUNNEL || | 394 | dev->type == ARPHRD_SIT) { |
| 381 | dev->type == ARPHRD_NONE || | 395 | printk(KERN_INFO |
| 382 | dev->type == ARPHRD_SIT) { | 396 | "%s: Disabled Privacy Extensions\n", |
| 383 | printk(KERN_INFO | 397 | dev->name); |
| 384 | "%s: Disabled Privacy Extensions\n", | 398 | ndev->cnf.use_tempaddr = -1; |
| 385 | dev->name); | 399 | } else { |
| 386 | ndev->cnf.use_tempaddr = -1; | 400 | in6_dev_hold(ndev); |
| 387 | } else { | 401 | ipv6_regen_rndid((unsigned long) ndev); |
| 388 | in6_dev_hold(ndev); | 402 | } |
| 389 | ipv6_regen_rndid((unsigned long) ndev); | ||
| 390 | } | ||
| 391 | #endif | 403 | #endif |
| 392 | 404 | ||
| 393 | if (netif_carrier_ok(dev)) | 405 | if (netif_carrier_ok(dev)) |
| 394 | ndev->if_flags |= IF_READY; | 406 | ndev->if_flags |= IF_READY; |
| 395 | 407 | ||
| 396 | write_lock_bh(&addrconf_lock); | 408 | write_lock_bh(&addrconf_lock); |
| 397 | dev->ip6_ptr = ndev; | 409 | dev->ip6_ptr = ndev; |
| 398 | write_unlock_bh(&addrconf_lock); | 410 | write_unlock_bh(&addrconf_lock); |
| 399 | 411 | ||
| 400 | ipv6_mc_init_dev(ndev); | 412 | ipv6_mc_init_dev(ndev); |
| 401 | ndev->tstamp = jiffies; | 413 | ndev->tstamp = jiffies; |
| 402 | #ifdef CONFIG_SYSCTL | 414 | #ifdef CONFIG_SYSCTL |
| 403 | neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, | 415 | neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, |
| 404 | NET_IPV6_NEIGH, "ipv6", | 416 | NET_IPV6_NEIGH, "ipv6", |
| 405 | &ndisc_ifinfo_sysctl_change, | 417 | &ndisc_ifinfo_sysctl_change, |
| 406 | NULL); | 418 | NULL); |
| 407 | addrconf_sysctl_register(ndev, &ndev->cnf); | 419 | addrconf_sysctl_register(ndev, &ndev->cnf); |
| 408 | #endif | 420 | #endif |
| 409 | } | ||
| 410 | return ndev; | 421 | return ndev; |
| 411 | } | 422 | } |
| 412 | 423 | ||
| @@ -524,7 +535,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 524 | goto out; | 535 | goto out; |
| 525 | } | 536 | } |
| 526 | 537 | ||
| 527 | ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); | 538 | ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); |
| 528 | 539 | ||
| 529 | if (ifa == NULL) { | 540 | if (ifa == NULL) { |
| 530 | ADBG(("ipv6_add_addr: malloc failed\n")); | 541 | ADBG(("ipv6_add_addr: malloc failed\n")); |
| @@ -538,7 +549,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 538 | goto out; | 549 | goto out; |
| 539 | } | 550 | } |
| 540 | 551 | ||
| 541 | memset(ifa, 0, sizeof(struct inet6_ifaddr)); | ||
| 542 | ipv6_addr_copy(&ifa->addr, addr); | 552 | ipv6_addr_copy(&ifa->addr, addr); |
| 543 | 553 | ||
| 544 | spin_lock_init(&ifa->lock); | 554 | spin_lock_init(&ifa->lock); |
| @@ -1305,52 +1315,67 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp) | |||
| 1305 | __ipv6_dev_ac_dec(ifp->idev, &addr); | 1315 | __ipv6_dev_ac_dec(ifp->idev, &addr); |
| 1306 | } | 1316 | } |
| 1307 | 1317 | ||
| 1318 | static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) | ||
| 1319 | { | ||
| 1320 | if (dev->addr_len != ETH_ALEN) | ||
| 1321 | return -1; | ||
| 1322 | memcpy(eui, dev->dev_addr, 3); | ||
| 1323 | memcpy(eui + 5, dev->dev_addr + 3, 3); | ||
| 1324 | |||
| 1325 | /* | ||
| 1326 | * The zSeries OSA network cards can be shared among various | ||
| 1327 | * OS instances, but the OSA cards have only one MAC address. | ||
| 1328 | * This leads to duplicate address conflicts in conjunction | ||
| 1329 | * with IPv6 if more than one instance uses the same card. | ||
| 1330 | * | ||
| 1331 | * The driver for these cards can deliver a unique 16-bit | ||
| 1332 | * identifier for each instance sharing the same card. It is | ||
| 1333 | * placed instead of 0xFFFE in the interface identifier. The | ||
| 1334 | * "u" bit of the interface identifier is not inverted in this | ||
| 1335 | * case. Hence the resulting interface identifier has local | ||
| 1336 | * scope according to RFC2373. | ||
| 1337 | */ | ||
| 1338 | if (dev->dev_id) { | ||
| 1339 | eui[3] = (dev->dev_id >> 8) & 0xFF; | ||
| 1340 | eui[4] = dev->dev_id & 0xFF; | ||
| 1341 | } else { | ||
| 1342 | eui[3] = 0xFF; | ||
| 1343 | eui[4] = 0xFE; | ||
| 1344 | eui[0] ^= 2; | ||
| 1345 | } | ||
| 1346 | return 0; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) | ||
| 1350 | { | ||
| 1351 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ | ||
| 1352 | if (dev->addr_len != ARCNET_ALEN) | ||
| 1353 | return -1; | ||
| 1354 | memset(eui, 0, 7); | ||
| 1355 | eui[7] = *(u8*)dev->dev_addr; | ||
| 1356 | return 0; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) | ||
| 1360 | { | ||
| 1361 | if (dev->addr_len != INFINIBAND_ALEN) | ||
| 1362 | return -1; | ||
| 1363 | memcpy(eui, dev->dev_addr + 12, 8); | ||
| 1364 | eui[0] |= 2; | ||
| 1365 | return 0; | ||
| 1366 | } | ||
| 1367 | |||
| 1308 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) | 1368 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) |
| 1309 | { | 1369 | { |
| 1310 | switch (dev->type) { | 1370 | switch (dev->type) { |
| 1311 | case ARPHRD_ETHER: | 1371 | case ARPHRD_ETHER: |
| 1312 | case ARPHRD_FDDI: | 1372 | case ARPHRD_FDDI: |
| 1313 | case ARPHRD_IEEE802_TR: | 1373 | case ARPHRD_IEEE802_TR: |
| 1314 | if (dev->addr_len != ETH_ALEN) | 1374 | return addrconf_ifid_eui48(eui, dev); |
| 1315 | return -1; | ||
| 1316 | memcpy(eui, dev->dev_addr, 3); | ||
| 1317 | memcpy(eui + 5, dev->dev_addr + 3, 3); | ||
| 1318 | |||
| 1319 | /* | ||
| 1320 | * The zSeries OSA network cards can be shared among various | ||
| 1321 | * OS instances, but the OSA cards have only one MAC address. | ||
| 1322 | * This leads to duplicate address conflicts in conjunction | ||
| 1323 | * with IPv6 if more than one instance uses the same card. | ||
| 1324 | * | ||
| 1325 | * The driver for these cards can deliver a unique 16-bit | ||
| 1326 | * identifier for each instance sharing the same card. It is | ||
| 1327 | * placed instead of 0xFFFE in the interface identifier. The | ||
| 1328 | * "u" bit of the interface identifier is not inverted in this | ||
| 1329 | * case. Hence the resulting interface identifier has local | ||
| 1330 | * scope according to RFC2373. | ||
| 1331 | */ | ||
| 1332 | if (dev->dev_id) { | ||
| 1333 | eui[3] = (dev->dev_id >> 8) & 0xFF; | ||
| 1334 | eui[4] = dev->dev_id & 0xFF; | ||
| 1335 | } else { | ||
| 1336 | eui[3] = 0xFF; | ||
| 1337 | eui[4] = 0xFE; | ||
| 1338 | eui[0] ^= 2; | ||
| 1339 | } | ||
| 1340 | return 0; | ||
| 1341 | case ARPHRD_ARCNET: | 1375 | case ARPHRD_ARCNET: |
| 1342 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ | 1376 | return addrconf_ifid_arcnet(eui, dev); |
| 1343 | if (dev->addr_len != ARCNET_ALEN) | ||
| 1344 | return -1; | ||
| 1345 | memset(eui, 0, 7); | ||
| 1346 | eui[7] = *(u8*)dev->dev_addr; | ||
| 1347 | return 0; | ||
| 1348 | case ARPHRD_INFINIBAND: | 1377 | case ARPHRD_INFINIBAND: |
| 1349 | if (dev->addr_len != INFINIBAND_ALEN) | 1378 | return addrconf_ifid_infiniband(eui, dev); |
| 1350 | return -1; | ||
| 1351 | memcpy(eui, dev->dev_addr + 12, 8); | ||
| 1352 | eui[0] |= 2; | ||
| 1353 | return 0; | ||
| 1354 | } | 1379 | } |
| 1355 | return -1; | 1380 | return -1; |
| 1356 | } | 1381 | } |
| @@ -1376,34 +1401,9 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
| 1376 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ | 1401 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ |
| 1377 | static int __ipv6_regen_rndid(struct inet6_dev *idev) | 1402 | static int __ipv6_regen_rndid(struct inet6_dev *idev) |
| 1378 | { | 1403 | { |
| 1379 | struct net_device *dev; | ||
| 1380 | struct scatterlist sg[2]; | ||
| 1381 | |||
| 1382 | sg_set_buf(&sg[0], idev->entropy, 8); | ||
| 1383 | sg_set_buf(&sg[1], idev->work_eui64, 8); | ||
| 1384 | |||
| 1385 | dev = idev->dev; | ||
| 1386 | |||
| 1387 | if (ipv6_generate_eui64(idev->work_eui64, dev)) { | ||
| 1388 | printk(KERN_INFO | ||
| 1389 | "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n", | ||
| 1390 | idev); | ||
| 1391 | get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64)); | ||
| 1392 | } | ||
| 1393 | regen: | 1404 | regen: |
| 1394 | spin_lock(&md5_tfm_lock); | 1405 | get_random_bytes(idev->rndid, sizeof(idev->rndid)); |
| 1395 | if (unlikely(md5_tfm == NULL)) { | ||
| 1396 | spin_unlock(&md5_tfm_lock); | ||
| 1397 | return -1; | ||
| 1398 | } | ||
| 1399 | crypto_digest_init(md5_tfm); | ||
| 1400 | crypto_digest_update(md5_tfm, sg, 2); | ||
| 1401 | crypto_digest_final(md5_tfm, idev->work_digest); | ||
| 1402 | spin_unlock(&md5_tfm_lock); | ||
| 1403 | |||
| 1404 | memcpy(idev->rndid, &idev->work_digest[0], 8); | ||
| 1405 | idev->rndid[0] &= ~0x02; | 1406 | idev->rndid[0] &= ~0x02; |
| 1406 | memcpy(idev->entropy, &idev->work_digest[8], 8); | ||
| 1407 | 1407 | ||
| 1408 | /* | 1408 | /* |
| 1409 | * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: | 1409 | * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: |
| @@ -2143,7 +2143,6 @@ static void addrconf_ip6_tnl_config(struct net_device *dev) | |||
| 2143 | return; | 2143 | return; |
| 2144 | } | 2144 | } |
| 2145 | ip6_tnl_add_linklocal(idev); | 2145 | ip6_tnl_add_linklocal(idev); |
| 2146 | addrconf_add_mroute(dev); | ||
| 2147 | } | 2146 | } |
| 2148 | 2147 | ||
| 2149 | static int addrconf_notify(struct notifier_block *this, unsigned long event, | 2148 | static int addrconf_notify(struct notifier_block *this, unsigned long event, |
| @@ -2668,11 +2667,10 @@ static int if6_seq_open(struct inode *inode, struct file *file) | |||
| 2668 | { | 2667 | { |
| 2669 | struct seq_file *seq; | 2668 | struct seq_file *seq; |
| 2670 | int rc = -ENOMEM; | 2669 | int rc = -ENOMEM; |
| 2671 | struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2670 | struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 2672 | 2671 | ||
| 2673 | if (!s) | 2672 | if (!s) |
| 2674 | goto out; | 2673 | goto out; |
| 2675 | memset(s, 0, sizeof(*s)); | ||
| 2676 | 2674 | ||
| 2677 | rc = seq_open(file, &if6_seq_ops); | 2675 | rc = seq_open(file, &if6_seq_ops); |
| 2678 | if (rc) | 2676 | if (rc) |
| @@ -3133,6 +3131,15 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
| 3133 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; | 3131 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; |
| 3134 | #endif | 3132 | #endif |
| 3135 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; | 3133 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; |
| 3134 | array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; | ||
| 3135 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; | ||
| 3136 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 3137 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; | ||
| 3138 | array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; | ||
| 3139 | #ifdef CONFIV_IPV6_ROUTE_INFO | ||
| 3140 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | ||
| 3141 | #endif | ||
| 3142 | #endif | ||
| 3136 | } | 3143 | } |
| 3137 | 3144 | ||
| 3138 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3145 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
| @@ -3586,6 +3593,51 @@ static struct addrconf_sysctl_table | |||
| 3586 | .proc_handler = &proc_dointvec, | 3593 | .proc_handler = &proc_dointvec, |
| 3587 | }, | 3594 | }, |
| 3588 | { | 3595 | { |
| 3596 | .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR, | ||
| 3597 | .procname = "accept_ra_defrtr", | ||
| 3598 | .data = &ipv6_devconf.accept_ra_defrtr, | ||
| 3599 | .maxlen = sizeof(int), | ||
| 3600 | .mode = 0644, | ||
| 3601 | .proc_handler = &proc_dointvec, | ||
| 3602 | }, | ||
| 3603 | { | ||
| 3604 | .ctl_name = NET_IPV6_ACCEPT_RA_PINFO, | ||
| 3605 | .procname = "accept_ra_pinfo", | ||
| 3606 | .data = &ipv6_devconf.accept_ra_pinfo, | ||
| 3607 | .maxlen = sizeof(int), | ||
| 3608 | .mode = 0644, | ||
| 3609 | .proc_handler = &proc_dointvec, | ||
| 3610 | }, | ||
| 3611 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 3612 | { | ||
| 3613 | .ctl_name = NET_IPV6_ACCEPT_RA_RTR_PREF, | ||
| 3614 | .procname = "accept_ra_rtr_pref", | ||
| 3615 | .data = &ipv6_devconf.accept_ra_rtr_pref, | ||
| 3616 | .maxlen = sizeof(int), | ||
| 3617 | .mode = 0644, | ||
| 3618 | .proc_handler = &proc_dointvec, | ||
| 3619 | }, | ||
| 3620 | { | ||
| 3621 | .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL, | ||
| 3622 | .procname = "router_probe_interval", | ||
| 3623 | .data = &ipv6_devconf.rtr_probe_interval, | ||
| 3624 | .maxlen = sizeof(int), | ||
| 3625 | .mode = 0644, | ||
| 3626 | .proc_handler = &proc_dointvec_jiffies, | ||
| 3627 | .strategy = &sysctl_jiffies, | ||
| 3628 | }, | ||
| 3629 | #ifdef CONFIV_IPV6_ROUTE_INFO | ||
| 3630 | { | ||
| 3631 | .ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, | ||
| 3632 | .procname = "accept_ra_rt_info_max_plen", | ||
| 3633 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, | ||
| 3634 | .maxlen = sizeof(int), | ||
| 3635 | .mode = 0644, | ||
| 3636 | .proc_handler = &proc_dointvec, | ||
| 3637 | }, | ||
| 3638 | #endif | ||
| 3639 | #endif | ||
| 3640 | { | ||
| 3589 | .ctl_name = 0, /* sentinel */ | 3641 | .ctl_name = 0, /* sentinel */ |
| 3590 | } | 3642 | } |
| 3591 | }, | 3643 | }, |
| @@ -3760,13 +3812,6 @@ int __init addrconf_init(void) | |||
| 3760 | 3812 | ||
| 3761 | register_netdevice_notifier(&ipv6_dev_notf); | 3813 | register_netdevice_notifier(&ipv6_dev_notf); |
| 3762 | 3814 | ||
| 3763 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 3764 | md5_tfm = crypto_alloc_tfm("md5", 0); | ||
| 3765 | if (unlikely(md5_tfm == NULL)) | ||
| 3766 | printk(KERN_WARNING | ||
| 3767 | "failed to load transform for md5\n"); | ||
| 3768 | #endif | ||
| 3769 | |||
| 3770 | addrconf_verify(0); | 3815 | addrconf_verify(0); |
| 3771 | rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; | 3816 | rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; |
| 3772 | #ifdef CONFIG_SYSCTL | 3817 | #ifdef CONFIG_SYSCTL |
| @@ -3829,11 +3874,6 @@ void __exit addrconf_cleanup(void) | |||
| 3829 | 3874 | ||
| 3830 | rtnl_unlock(); | 3875 | rtnl_unlock(); |
| 3831 | 3876 | ||
| 3832 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 3833 | crypto_free_tfm(md5_tfm); | ||
| 3834 | md5_tfm = NULL; | ||
| 3835 | #endif | ||
| 3836 | |||
| 3837 | #ifdef CONFIG_PROC_FS | 3877 | #ifdef CONFIG_PROC_FS |
| 3838 | proc_net_remove("if_inet6"); | 3878 | proc_net_remove("if_inet6"); |
| 3839 | #endif | 3879 | #endif |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6c9711ac1c03..e19457fe4f6e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -456,45 +456,53 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | const struct proto_ops inet6_stream_ops = { | 458 | const struct proto_ops inet6_stream_ops = { |
| 459 | .family = PF_INET6, | 459 | .family = PF_INET6, |
| 460 | .owner = THIS_MODULE, | 460 | .owner = THIS_MODULE, |
| 461 | .release = inet6_release, | 461 | .release = inet6_release, |
| 462 | .bind = inet6_bind, | 462 | .bind = inet6_bind, |
| 463 | .connect = inet_stream_connect, /* ok */ | 463 | .connect = inet_stream_connect, /* ok */ |
| 464 | .socketpair = sock_no_socketpair, /* a do nothing */ | 464 | .socketpair = sock_no_socketpair, /* a do nothing */ |
| 465 | .accept = inet_accept, /* ok */ | 465 | .accept = inet_accept, /* ok */ |
| 466 | .getname = inet6_getname, | 466 | .getname = inet6_getname, |
| 467 | .poll = tcp_poll, /* ok */ | 467 | .poll = tcp_poll, /* ok */ |
| 468 | .ioctl = inet6_ioctl, /* must change */ | 468 | .ioctl = inet6_ioctl, /* must change */ |
| 469 | .listen = inet_listen, /* ok */ | 469 | .listen = inet_listen, /* ok */ |
| 470 | .shutdown = inet_shutdown, /* ok */ | 470 | .shutdown = inet_shutdown, /* ok */ |
| 471 | .setsockopt = sock_common_setsockopt, /* ok */ | 471 | .setsockopt = sock_common_setsockopt, /* ok */ |
| 472 | .getsockopt = sock_common_getsockopt, /* ok */ | 472 | .getsockopt = sock_common_getsockopt, /* ok */ |
| 473 | .sendmsg = inet_sendmsg, /* ok */ | 473 | .sendmsg = inet_sendmsg, /* ok */ |
| 474 | .recvmsg = sock_common_recvmsg, /* ok */ | 474 | .recvmsg = sock_common_recvmsg, /* ok */ |
| 475 | .mmap = sock_no_mmap, | 475 | .mmap = sock_no_mmap, |
| 476 | .sendpage = tcp_sendpage | 476 | .sendpage = tcp_sendpage, |
| 477 | #ifdef CONFIG_COMPAT | ||
| 478 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
| 479 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
| 480 | #endif | ||
| 477 | }; | 481 | }; |
| 478 | 482 | ||
| 479 | const struct proto_ops inet6_dgram_ops = { | 483 | const struct proto_ops inet6_dgram_ops = { |
| 480 | .family = PF_INET6, | 484 | .family = PF_INET6, |
| 481 | .owner = THIS_MODULE, | 485 | .owner = THIS_MODULE, |
| 482 | .release = inet6_release, | 486 | .release = inet6_release, |
| 483 | .bind = inet6_bind, | 487 | .bind = inet6_bind, |
| 484 | .connect = inet_dgram_connect, /* ok */ | 488 | .connect = inet_dgram_connect, /* ok */ |
| 485 | .socketpair = sock_no_socketpair, /* a do nothing */ | 489 | .socketpair = sock_no_socketpair, /* a do nothing */ |
| 486 | .accept = sock_no_accept, /* a do nothing */ | 490 | .accept = sock_no_accept, /* a do nothing */ |
| 487 | .getname = inet6_getname, | 491 | .getname = inet6_getname, |
| 488 | .poll = udp_poll, /* ok */ | 492 | .poll = udp_poll, /* ok */ |
| 489 | .ioctl = inet6_ioctl, /* must change */ | 493 | .ioctl = inet6_ioctl, /* must change */ |
| 490 | .listen = sock_no_listen, /* ok */ | 494 | .listen = sock_no_listen, /* ok */ |
| 491 | .shutdown = inet_shutdown, /* ok */ | 495 | .shutdown = inet_shutdown, /* ok */ |
| 492 | .setsockopt = sock_common_setsockopt, /* ok */ | 496 | .setsockopt = sock_common_setsockopt, /* ok */ |
| 493 | .getsockopt = sock_common_getsockopt, /* ok */ | 497 | .getsockopt = sock_common_getsockopt, /* ok */ |
| 494 | .sendmsg = inet_sendmsg, /* ok */ | 498 | .sendmsg = inet_sendmsg, /* ok */ |
| 495 | .recvmsg = sock_common_recvmsg, /* ok */ | 499 | .recvmsg = sock_common_recvmsg, /* ok */ |
| 496 | .mmap = sock_no_mmap, | 500 | .mmap = sock_no_mmap, |
| 497 | .sendpage = sock_no_sendpage, | 501 | .sendpage = sock_no_sendpage, |
| 502 | #ifdef CONFIG_COMPAT | ||
| 503 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
| 504 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
| 505 | #endif | ||
| 498 | }; | 506 | }; |
| 499 | 507 | ||
| 500 | static struct net_proto_family inet6_family_ops = { | 508 | static struct net_proto_family inet6_family_ops = { |
| @@ -505,24 +513,28 @@ static struct net_proto_family inet6_family_ops = { | |||
| 505 | 513 | ||
| 506 | /* Same as inet6_dgram_ops, sans udp_poll. */ | 514 | /* Same as inet6_dgram_ops, sans udp_poll. */ |
| 507 | static const struct proto_ops inet6_sockraw_ops = { | 515 | static const struct proto_ops inet6_sockraw_ops = { |
| 508 | .family = PF_INET6, | 516 | .family = PF_INET6, |
| 509 | .owner = THIS_MODULE, | 517 | .owner = THIS_MODULE, |
| 510 | .release = inet6_release, | 518 | .release = inet6_release, |
| 511 | .bind = inet6_bind, | 519 | .bind = inet6_bind, |
| 512 | .connect = inet_dgram_connect, /* ok */ | 520 | .connect = inet_dgram_connect, /* ok */ |
| 513 | .socketpair = sock_no_socketpair, /* a do nothing */ | 521 | .socketpair = sock_no_socketpair, /* a do nothing */ |
| 514 | .accept = sock_no_accept, /* a do nothing */ | 522 | .accept = sock_no_accept, /* a do nothing */ |
| 515 | .getname = inet6_getname, | 523 | .getname = inet6_getname, |
| 516 | .poll = datagram_poll, /* ok */ | 524 | .poll = datagram_poll, /* ok */ |
| 517 | .ioctl = inet6_ioctl, /* must change */ | 525 | .ioctl = inet6_ioctl, /* must change */ |
| 518 | .listen = sock_no_listen, /* ok */ | 526 | .listen = sock_no_listen, /* ok */ |
| 519 | .shutdown = inet_shutdown, /* ok */ | 527 | .shutdown = inet_shutdown, /* ok */ |
| 520 | .setsockopt = sock_common_setsockopt, /* ok */ | 528 | .setsockopt = sock_common_setsockopt, /* ok */ |
| 521 | .getsockopt = sock_common_getsockopt, /* ok */ | 529 | .getsockopt = sock_common_getsockopt, /* ok */ |
| 522 | .sendmsg = inet_sendmsg, /* ok */ | 530 | .sendmsg = inet_sendmsg, /* ok */ |
| 523 | .recvmsg = sock_common_recvmsg, /* ok */ | 531 | .recvmsg = sock_common_recvmsg, /* ok */ |
| 524 | .mmap = sock_no_mmap, | 532 | .mmap = sock_no_mmap, |
| 525 | .sendpage = sock_no_sendpage, | 533 | .sendpage = sock_no_sendpage, |
| 534 | #ifdef CONFIG_COMPAT | ||
| 535 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
| 536 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
| 537 | #endif | ||
| 526 | }; | 538 | }; |
| 527 | 539 | ||
| 528 | static struct inet_protosw rawv6_protosw = { | 540 | static struct inet_protosw rawv6_protosw = { |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 84963749ab77..cf58251df4b3 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
| @@ -213,6 +213,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 213 | ah->reserved = 0; | 213 | ah->reserved = 0; |
| 214 | ah->spi = x->id.spi; | 214 | ah->spi = x->id.spi; |
| 215 | ah->seq_no = htonl(++x->replay.oseq); | 215 | ah->seq_no = htonl(++x->replay.oseq); |
| 216 | xfrm_aevent_doreplay(x); | ||
| 216 | ahp->icv(ahp, skb, ah->auth_data); | 217 | ahp->icv(ahp, skb, ah->auth_data); |
| 217 | 218 | ||
| 218 | err = 0; | 219 | err = 0; |
| @@ -353,12 +354,10 @@ static int ah6_init_state(struct xfrm_state *x) | |||
| 353 | if (x->encap) | 354 | if (x->encap) |
| 354 | goto error; | 355 | goto error; |
| 355 | 356 | ||
| 356 | ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); | 357 | ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); |
| 357 | if (ahp == NULL) | 358 | if (ahp == NULL) |
| 358 | return -ENOMEM; | 359 | return -ENOMEM; |
| 359 | 360 | ||
| 360 | memset(ahp, 0, sizeof(*ahp)); | ||
| 361 | |||
| 362 | ahp->key = x->aalg->alg_key; | 361 | ahp->key = x->aalg->alg_key; |
| 363 | ahp->key_len = (x->aalg->alg_key_len+7)/8; | 362 | ahp->key_len = (x->aalg->alg_key_len+7)/8; |
| 364 | ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); | 363 | ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 840a33d33296..39ec528923f6 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
| @@ -308,7 +308,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
| 308 | * not found: create a new one. | 308 | * not found: create a new one. |
| 309 | */ | 309 | */ |
| 310 | 310 | ||
| 311 | aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); | 311 | aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); |
| 312 | 312 | ||
| 313 | if (aca == NULL) { | 313 | if (aca == NULL) { |
| 314 | err = -ENOMEM; | 314 | err = -ENOMEM; |
| @@ -322,8 +322,6 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
| 322 | goto out; | 322 | goto out; |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | memset(aca, 0, sizeof(struct ifacaddr6)); | ||
| 326 | |||
| 327 | ipv6_addr_copy(&aca->aca_addr, addr); | 325 | ipv6_addr_copy(&aca->aca_addr, addr); |
| 328 | aca->aca_idev = idev; | 326 | aca->aca_idev = idev; |
| 329 | aca->aca_rt = rt; | 327 | aca->aca_rt = rt; |
| @@ -550,7 +548,7 @@ static int ac6_seq_open(struct inode *inode, struct file *file) | |||
| 550 | { | 548 | { |
| 551 | struct seq_file *seq; | 549 | struct seq_file *seq; |
| 552 | int rc = -ENOMEM; | 550 | int rc = -ENOMEM; |
| 553 | struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 551 | struct ac6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 554 | 552 | ||
| 555 | if (!s) | 553 | if (!s) |
| 556 | goto out; | 554 | goto out; |
| @@ -561,7 +559,6 @@ static int ac6_seq_open(struct inode *inode, struct file *file) | |||
| 561 | 559 | ||
| 562 | seq = file->private_data; | 560 | seq = file->private_data; |
| 563 | seq->private = s; | 561 | seq->private = s; |
| 564 | memset(s, 0, sizeof(*s)); | ||
| 565 | out: | 562 | out: |
| 566 | return rc; | 563 | return rc; |
| 567 | out_kfree: | 564 | out_kfree: |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 7b5b94f13902..3dcaac7a0972 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -94,6 +94,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
| 94 | 94 | ||
| 95 | esph->spi = x->id.spi; | 95 | esph->spi = x->id.spi; |
| 96 | esph->seq_no = htonl(++x->replay.oseq); | 96 | esph->seq_no = htonl(++x->replay.oseq); |
| 97 | xfrm_aevent_doreplay(x); | ||
| 97 | 98 | ||
| 98 | if (esp->conf.ivlen) | 99 | if (esp->conf.ivlen) |
| 99 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 100 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); |
| @@ -304,12 +305,10 @@ static int esp6_init_state(struct xfrm_state *x) | |||
| 304 | if (x->encap) | 305 | if (x->encap) |
| 305 | goto error; | 306 | goto error; |
| 306 | 307 | ||
| 307 | esp = kmalloc(sizeof(*esp), GFP_KERNEL); | 308 | esp = kzalloc(sizeof(*esp), GFP_KERNEL); |
| 308 | if (esp == NULL) | 309 | if (esp == NULL) |
| 309 | return -ENOMEM; | 310 | return -ENOMEM; |
| 310 | 311 | ||
| 311 | memset(esp, 0, sizeof(*esp)); | ||
| 312 | |||
| 313 | if (x->aalg) { | 312 | if (x->aalg) { |
| 314 | struct xfrm_algo_desc *aalg_desc; | 313 | struct xfrm_algo_desc *aalg_desc; |
| 315 | 314 | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1bf6d9a769e6..2cb6149349bf 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
| 1105 | if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { | 1105 | if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { |
| 1106 | if (time_after(now, rt->rt6i_expires)) { | 1106 | if (time_after(now, rt->rt6i_expires)) { |
| 1107 | RT6_TRACE("expiring %p\n", rt); | 1107 | RT6_TRACE("expiring %p\n", rt); |
| 1108 | rt6_reset_dflt_pointer(rt); | ||
| 1109 | return -1; | 1108 | return -1; |
| 1110 | } | 1109 | } |
| 1111 | gc_args.more++; | 1110 | gc_args.more++; |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 69cbe8a66d02..f9ca63912fbf 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -287,10 +287,9 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * | |||
| 287 | int err; | 287 | int err; |
| 288 | 288 | ||
| 289 | err = -ENOMEM; | 289 | err = -ENOMEM; |
| 290 | fl = kmalloc(sizeof(*fl), GFP_KERNEL); | 290 | fl = kzalloc(sizeof(*fl), GFP_KERNEL); |
| 291 | if (fl == NULL) | 291 | if (fl == NULL) |
| 292 | goto done; | 292 | goto done; |
| 293 | memset(fl, 0, sizeof(*fl)); | ||
| 294 | 293 | ||
| 295 | olen = optlen - CMSG_ALIGN(sizeof(*freq)); | 294 | olen = optlen - CMSG_ALIGN(sizeof(*freq)); |
| 296 | if (olen > 0) { | 295 | if (olen > 0) { |
| @@ -663,7 +662,7 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file) | |||
| 663 | { | 662 | { |
| 664 | struct seq_file *seq; | 663 | struct seq_file *seq; |
| 665 | int rc = -ENOMEM; | 664 | int rc = -ENOMEM; |
| 666 | struct ip6fl_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 665 | struct ip6fl_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 667 | 666 | ||
| 668 | if (!s) | 667 | if (!s) |
| 669 | goto out; | 668 | goto out; |
| @@ -674,7 +673,6 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file) | |||
| 674 | 673 | ||
| 675 | seq = file->private_data; | 674 | seq = file->private_data; |
| 676 | seq->private = s; | 675 | seq->private = s; |
| 677 | memset(s, 0, sizeof(*s)); | ||
| 678 | out: | 676 | out: |
| 679 | return rc; | 677 | return rc; |
| 680 | out_kfree: | 678 | out_kfree: |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5bf70b1442ea..e46048974f37 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -161,7 +161,7 @@ int ip6_output(struct sk_buff *skb) | |||
| 161 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | 161 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, |
| 162 | struct ipv6_txoptions *opt, int ipfragok) | 162 | struct ipv6_txoptions *opt, int ipfragok) |
| 163 | { | 163 | { |
| 164 | struct ipv6_pinfo *np = sk ? inet6_sk(sk) : NULL; | 164 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 165 | struct in6_addr *first_hop = &fl->fl6_dst; | 165 | struct in6_addr *first_hop = &fl->fl6_dst; |
| 166 | struct dst_entry *dst = skb->dst; | 166 | struct dst_entry *dst = skb->dst; |
| 167 | struct ipv6hdr *hdr; | 167 | struct ipv6hdr *hdr; |
| @@ -733,28 +733,29 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | |||
| 733 | if (*dst) { | 733 | if (*dst) { |
| 734 | struct rt6_info *rt = (struct rt6_info*)*dst; | 734 | struct rt6_info *rt = (struct rt6_info*)*dst; |
| 735 | 735 | ||
| 736 | /* Yes, checking route validity in not connected | 736 | /* Yes, checking route validity in not connected |
| 737 | case is not very simple. Take into account, | 737 | * case is not very simple. Take into account, |
| 738 | that we do not support routing by source, TOS, | 738 | * that we do not support routing by source, TOS, |
| 739 | and MSG_DONTROUTE --ANK (980726) | 739 | * and MSG_DONTROUTE --ANK (980726) |
| 740 | 740 | * | |
| 741 | 1. If route was host route, check that | 741 | * 1. If route was host route, check that |
| 742 | cached destination is current. | 742 | * cached destination is current. |
| 743 | If it is network route, we still may | 743 | * If it is network route, we still may |
| 744 | check its validity using saved pointer | 744 | * check its validity using saved pointer |
| 745 | to the last used address: daddr_cache. | 745 | * to the last used address: daddr_cache. |
| 746 | We do not want to save whole address now, | 746 | * We do not want to save whole address now, |
| 747 | (because main consumer of this service | 747 | * (because main consumer of this service |
| 748 | is tcp, which has not this problem), | 748 | * is tcp, which has not this problem), |
| 749 | so that the last trick works only on connected | 749 | * so that the last trick works only on connected |
| 750 | sockets. | 750 | * sockets. |
| 751 | 2. oif also should be the same. | 751 | * 2. oif also should be the same. |
| 752 | */ | 752 | */ |
| 753 | |||
| 754 | if (((rt->rt6i_dst.plen != 128 || | 753 | if (((rt->rt6i_dst.plen != 128 || |
| 755 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) | 754 | !ipv6_addr_equal(&fl->fl6_dst, |
| 755 | &rt->rt6i_dst.addr)) | ||
| 756 | && (np->daddr_cache == NULL || | 756 | && (np->daddr_cache == NULL || |
| 757 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) | 757 | !ipv6_addr_equal(&fl->fl6_dst, |
| 758 | np->daddr_cache))) | ||
| 758 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { | 759 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { |
| 759 | dst_release(*dst); | 760 | dst_release(*dst); |
| 760 | *dst = NULL; | 761 | *dst = NULL; |
| @@ -889,7 +890,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 889 | np->cork.hop_limit = hlimit; | 890 | np->cork.hop_limit = hlimit; |
| 890 | np->cork.tclass = tclass; | 891 | np->cork.tclass = tclass; |
| 891 | mtu = dst_mtu(rt->u.dst.path); | 892 | mtu = dst_mtu(rt->u.dst.path); |
| 892 | if (np && np->frag_size < mtu) { | 893 | if (np->frag_size < mtu) { |
| 893 | if (np->frag_size) | 894 | if (np->frag_size) |
| 894 | mtu = np->frag_size; | 895 | mtu = np->frag_size; |
| 895 | } | 896 | } |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index d511a884dad0..028b636687ec 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <net/protocol.h> | 50 | #include <net/protocol.h> |
| 51 | #include <linux/ipv6.h> | 51 | #include <linux/ipv6.h> |
| 52 | #include <linux/icmpv6.h> | 52 | #include <linux/icmpv6.h> |
| 53 | #include <linux/mutex.h> | ||
| 53 | 54 | ||
| 54 | struct ipcomp6_tfms { | 55 | struct ipcomp6_tfms { |
| 55 | struct list_head list; | 56 | struct list_head list; |
| @@ -57,7 +58,7 @@ struct ipcomp6_tfms { | |||
| 57 | int users; | 58 | int users; |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| 60 | static DECLARE_MUTEX(ipcomp6_resource_sem); | 61 | static DEFINE_MUTEX(ipcomp6_resource_mutex); |
| 61 | static void **ipcomp6_scratches; | 62 | static void **ipcomp6_scratches; |
| 62 | static int ipcomp6_scratch_users; | 63 | static int ipcomp6_scratch_users; |
| 63 | static LIST_HEAD(ipcomp6_tfms_list); | 64 | static LIST_HEAD(ipcomp6_tfms_list); |
| @@ -286,8 +287,8 @@ static void ipcomp6_free_scratches(void) | |||
| 286 | 287 | ||
| 287 | for_each_cpu(i) { | 288 | for_each_cpu(i) { |
| 288 | void *scratch = *per_cpu_ptr(scratches, i); | 289 | void *scratch = *per_cpu_ptr(scratches, i); |
| 289 | if (scratch) | 290 | |
| 290 | vfree(scratch); | 291 | vfree(scratch); |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 293 | free_percpu(scratches); | 294 | free_percpu(scratches); |
| @@ -405,9 +406,9 @@ static void ipcomp6_destroy(struct xfrm_state *x) | |||
| 405 | if (!ipcd) | 406 | if (!ipcd) |
| 406 | return; | 407 | return; |
| 407 | xfrm_state_delete_tunnel(x); | 408 | xfrm_state_delete_tunnel(x); |
| 408 | down(&ipcomp6_resource_sem); | 409 | mutex_lock(&ipcomp6_resource_mutex); |
| 409 | ipcomp6_free_data(ipcd); | 410 | ipcomp6_free_data(ipcd); |
| 410 | up(&ipcomp6_resource_sem); | 411 | mutex_unlock(&ipcomp6_resource_mutex); |
| 411 | kfree(ipcd); | 412 | kfree(ipcd); |
| 412 | 413 | ||
| 413 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 414 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); |
| @@ -427,23 +428,22 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
| 427 | goto out; | 428 | goto out; |
| 428 | 429 | ||
| 429 | err = -ENOMEM; | 430 | err = -ENOMEM; |
| 430 | ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL); | 431 | ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL); |
| 431 | if (!ipcd) | 432 | if (!ipcd) |
| 432 | goto out; | 433 | goto out; |
| 433 | 434 | ||
| 434 | memset(ipcd, 0, sizeof(*ipcd)); | ||
| 435 | x->props.header_len = 0; | 435 | x->props.header_len = 0; |
| 436 | if (x->props.mode) | 436 | if (x->props.mode) |
| 437 | x->props.header_len += sizeof(struct ipv6hdr); | 437 | x->props.header_len += sizeof(struct ipv6hdr); |
| 438 | 438 | ||
| 439 | down(&ipcomp6_resource_sem); | 439 | mutex_lock(&ipcomp6_resource_mutex); |
| 440 | if (!ipcomp6_alloc_scratches()) | 440 | if (!ipcomp6_alloc_scratches()) |
| 441 | goto error; | 441 | goto error; |
| 442 | 442 | ||
| 443 | ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); | 443 | ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); |
| 444 | if (!ipcd->tfms) | 444 | if (!ipcd->tfms) |
| 445 | goto error; | 445 | goto error; |
| 446 | up(&ipcomp6_resource_sem); | 446 | mutex_unlock(&ipcomp6_resource_mutex); |
| 447 | 447 | ||
| 448 | if (x->props.mode) { | 448 | if (x->props.mode) { |
| 449 | err = ipcomp6_tunnel_attach(x); | 449 | err = ipcomp6_tunnel_attach(x); |
| @@ -459,10 +459,10 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
| 459 | out: | 459 | out: |
| 460 | return err; | 460 | return err; |
| 461 | error_tunnel: | 461 | error_tunnel: |
| 462 | down(&ipcomp6_resource_sem); | 462 | mutex_lock(&ipcomp6_resource_mutex); |
| 463 | error: | 463 | error: |
| 464 | ipcomp6_free_data(ipcd); | 464 | ipcomp6_free_data(ipcd); |
| 465 | up(&ipcomp6_resource_sem); | 465 | mutex_unlock(&ipcomp6_resource_mutex); |
| 466 | kfree(ipcd); | 466 | kfree(ipcd); |
| 467 | 467 | ||
| 468 | goto out; | 468 | goto out; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f7142ba519ab..4c20eeb3d568 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) | |||
| 109 | return 0; | 109 | return 0; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | 112 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
| 113 | char __user *optval, int optlen) | 113 | char __user *optval, int optlen) |
| 114 | { | 114 | { |
| 115 | struct ipv6_pinfo *np = inet6_sk(sk); | 115 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 116 | int val, valbool; | 116 | int val, valbool; |
| 117 | int retv = -ENOPROTOOPT; | 117 | int retv = -ENOPROTOOPT; |
| 118 | 118 | ||
| 119 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
| 120 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
| 121 | |||
| 122 | if(level!=SOL_IPV6) | ||
| 123 | goto out; | ||
| 124 | |||
| 125 | if (optval == NULL) | 119 | if (optval == NULL) |
| 126 | val=0; | 120 | val=0; |
| 127 | else if (get_user(val, (int __user *) optval)) | 121 | else if (get_user(val, (int __user *) optval)) |
| @@ -613,17 +607,9 @@ done: | |||
| 613 | retv = xfrm_user_policy(sk, optname, optval, optlen); | 607 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
| 614 | break; | 608 | break; |
| 615 | 609 | ||
| 616 | #ifdef CONFIG_NETFILTER | ||
| 617 | default: | ||
| 618 | retv = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
| 619 | optlen); | ||
| 620 | break; | ||
| 621 | #endif | ||
| 622 | |||
| 623 | } | 610 | } |
| 624 | release_sock(sk); | 611 | release_sock(sk); |
| 625 | 612 | ||
| 626 | out: | ||
| 627 | return retv; | 613 | return retv; |
| 628 | 614 | ||
| 629 | e_inval: | 615 | e_inval: |
| @@ -631,6 +617,65 @@ e_inval: | |||
| 631 | return -EINVAL; | 617 | return -EINVAL; |
| 632 | } | 618 | } |
| 633 | 619 | ||
| 620 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
| 621 | char __user *optval, int optlen) | ||
| 622 | { | ||
| 623 | int err; | ||
| 624 | |||
| 625 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
| 626 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
| 627 | |||
| 628 | if (level != SOL_IPV6) | ||
| 629 | return -ENOPROTOOPT; | ||
| 630 | |||
| 631 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 632 | #ifdef CONFIG_NETFILTER | ||
| 633 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
| 634 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
| 635 | optname != IPV6_XFRM_POLICY) { | ||
| 636 | lock_sock(sk); | ||
| 637 | err = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
| 638 | optlen); | ||
| 639 | release_sock(sk); | ||
| 640 | } | ||
| 641 | #endif | ||
| 642 | return err; | ||
| 643 | } | ||
| 644 | |||
| 645 | |||
| 646 | #ifdef CONFIG_COMPAT | ||
| 647 | int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
| 648 | char __user *optval, int optlen) | ||
| 649 | { | ||
| 650 | int err; | ||
| 651 | |||
| 652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
| 653 | if (udp_prot.compat_setsockopt != NULL) | ||
| 654 | return udp_prot.compat_setsockopt(sk, level, optname, | ||
| 655 | optval, optlen); | ||
| 656 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
| 657 | } | ||
| 658 | |||
| 659 | if (level != SOL_IPV6) | ||
| 660 | return -ENOPROTOOPT; | ||
| 661 | |||
| 662 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 663 | #ifdef CONFIG_NETFILTER | ||
| 664 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
| 665 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
| 666 | optname != IPV6_XFRM_POLICY) { | ||
| 667 | lock_sock(sk); | ||
| 668 | err = compat_nf_setsockopt(sk, PF_INET6, optname, | ||
| 669 | optval, optlen); | ||
| 670 | release_sock(sk); | ||
| 671 | } | ||
| 672 | #endif | ||
| 673 | return err; | ||
| 674 | } | ||
| 675 | |||
| 676 | EXPORT_SYMBOL(compat_ipv6_setsockopt); | ||
| 677 | #endif | ||
| 678 | |||
| 634 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | 679 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, |
| 635 | char __user *optval, int len) | 680 | char __user *optval, int len) |
| 636 | { | 681 | { |
| @@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | |||
| 642 | return len; | 687 | return len; |
| 643 | } | 688 | } |
| 644 | 689 | ||
| 645 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 690 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
| 646 | char __user *optval, int __user *optlen) | 691 | char __user *optval, int __user *optlen) |
| 647 | { | 692 | { |
| 648 | struct ipv6_pinfo *np = inet6_sk(sk); | 693 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 649 | int len; | 694 | int len; |
| 650 | int val; | 695 | int val; |
| 651 | 696 | ||
| 652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
| 653 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
| 654 | if(level!=SOL_IPV6) | ||
| 655 | return -ENOPROTOOPT; | ||
| 656 | if (get_user(len, optlen)) | 697 | if (get_user(len, optlen)) |
| 657 | return -EFAULT; | 698 | return -EFAULT; |
| 658 | switch (optname) { | 699 | switch (optname) { |
| @@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 842 | break; | 883 | break; |
| 843 | 884 | ||
| 844 | default: | 885 | default: |
| 845 | #ifdef CONFIG_NETFILTER | ||
| 846 | lock_sock(sk); | ||
| 847 | val = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
| 848 | &len); | ||
| 849 | release_sock(sk); | ||
| 850 | if (val >= 0) | ||
| 851 | val = put_user(len, optlen); | ||
| 852 | return val; | ||
| 853 | #else | ||
| 854 | return -EINVAL; | 886 | return -EINVAL; |
| 855 | #endif | ||
| 856 | } | 887 | } |
| 857 | len = min_t(unsigned int, sizeof(int), len); | 888 | len = min_t(unsigned int, sizeof(int), len); |
| 858 | if(put_user(len, optlen)) | 889 | if(put_user(len, optlen)) |
| @@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 862 | return 0; | 893 | return 0; |
| 863 | } | 894 | } |
| 864 | 895 | ||
| 896 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 897 | char __user *optval, int __user *optlen) | ||
| 898 | { | ||
| 899 | int err; | ||
| 900 | |||
| 901 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
| 902 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
| 903 | |||
| 904 | if(level != SOL_IPV6) | ||
| 905 | return -ENOPROTOOPT; | ||
| 906 | |||
| 907 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 908 | #ifdef CONFIG_NETFILTER | ||
| 909 | /* we need to exclude all possible EINVALs except default case */ | ||
| 910 | if (err == -EINVAL && optname != IPV6_ADDRFORM && | ||
| 911 | optname != MCAST_MSFILTER) { | ||
| 912 | int len; | ||
| 913 | |||
| 914 | if (get_user(len, optlen)) | ||
| 915 | return -EFAULT; | ||
| 916 | |||
| 917 | lock_sock(sk); | ||
| 918 | err = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
| 919 | &len); | ||
| 920 | release_sock(sk); | ||
| 921 | if (err >= 0) | ||
| 922 | err = put_user(len, optlen); | ||
| 923 | } | ||
| 924 | #endif | ||
| 925 | return err; | ||
| 926 | } | ||
| 927 | |||
| 928 | #ifdef CONFIG_COMPAT | ||
| 929 | int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 930 | char __user *optval, int __user *optlen) | ||
| 931 | { | ||
| 932 | int err; | ||
| 933 | |||
| 934 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
| 935 | if (udp_prot.compat_getsockopt != NULL) | ||
| 936 | return udp_prot.compat_getsockopt(sk, level, optname, | ||
| 937 | optval, optlen); | ||
| 938 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
| 939 | } | ||
| 940 | |||
| 941 | if (level != SOL_IPV6) | ||
| 942 | return -ENOPROTOOPT; | ||
| 943 | |||
| 944 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 945 | #ifdef CONFIG_NETFILTER | ||
| 946 | /* we need to exclude all possible EINVALs except default case */ | ||
| 947 | if (err == -EINVAL && optname != IPV6_ADDRFORM && | ||
| 948 | optname != MCAST_MSFILTER) { | ||
| 949 | int len; | ||
| 950 | |||
| 951 | if (get_user(len, optlen)) | ||
| 952 | return -EFAULT; | ||
| 953 | |||
| 954 | lock_sock(sk); | ||
| 955 | err = compat_nf_getsockopt(sk, PF_INET6, | ||
| 956 | optname, optval, &len); | ||
| 957 | release_sock(sk); | ||
| 958 | if (err >= 0) | ||
| 959 | err = put_user(len, optlen); | ||
| 960 | } | ||
| 961 | #endif | ||
| 962 | return err; | ||
| 963 | } | ||
| 964 | |||
| 965 | EXPORT_SYMBOL(compat_ipv6_getsockopt); | ||
| 966 | #endif | ||
| 967 | |||
| 865 | void __init ipv6_packet_init(void) | 968 | void __init ipv6_packet_init(void) |
| 866 | { | 969 | { |
| 867 | dev_add_pack(&ipv6_packet_type); | 970 | dev_add_pack(&ipv6_packet_type); |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 807c021d64a2..6e871afbb2c7 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -767,10 +767,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
| 767 | * for deleted items allows change reports to use common code with | 767 | * for deleted items allows change reports to use common code with |
| 768 | * non-deleted or query-response MCA's. | 768 | * non-deleted or query-response MCA's. |
| 769 | */ | 769 | */ |
| 770 | pmc = kmalloc(sizeof(*pmc), GFP_ATOMIC); | 770 | pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC); |
| 771 | if (!pmc) | 771 | if (!pmc) |
| 772 | return; | 772 | return; |
| 773 | memset(pmc, 0, sizeof(*pmc)); | 773 | |
| 774 | spin_lock_bh(&im->mca_lock); | 774 | spin_lock_bh(&im->mca_lock); |
| 775 | spin_lock_init(&pmc->mca_lock); | 775 | spin_lock_init(&pmc->mca_lock); |
| 776 | pmc->idev = im->idev; | 776 | pmc->idev = im->idev; |
| @@ -893,7 +893,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | |||
| 893 | * not found: create a new one. | 893 | * not found: create a new one. |
| 894 | */ | 894 | */ |
| 895 | 895 | ||
| 896 | mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); | 896 | mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); |
| 897 | 897 | ||
| 898 | if (mc == NULL) { | 898 | if (mc == NULL) { |
| 899 | write_unlock_bh(&idev->lock); | 899 | write_unlock_bh(&idev->lock); |
| @@ -901,7 +901,6 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | |||
| 901 | return -ENOMEM; | 901 | return -ENOMEM; |
| 902 | } | 902 | } |
| 903 | 903 | ||
| 904 | memset(mc, 0, sizeof(struct ifmcaddr6)); | ||
| 905 | init_timer(&mc->mca_timer); | 904 | init_timer(&mc->mca_timer); |
| 906 | mc->mca_timer.function = igmp6_timer_handler; | 905 | mc->mca_timer.function = igmp6_timer_handler; |
| 907 | mc->mca_timer.data = (unsigned long) mc; | 906 | mc->mca_timer.data = (unsigned long) mc; |
| @@ -1934,10 +1933,10 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, | |||
| 1934 | psf_prev = psf; | 1933 | psf_prev = psf; |
| 1935 | } | 1934 | } |
| 1936 | if (!psf) { | 1935 | if (!psf) { |
| 1937 | psf = kmalloc(sizeof(*psf), GFP_ATOMIC); | 1936 | psf = kzalloc(sizeof(*psf), GFP_ATOMIC); |
| 1938 | if (!psf) | 1937 | if (!psf) |
| 1939 | return -ENOBUFS; | 1938 | return -ENOBUFS; |
| 1940 | memset(psf, 0, sizeof(*psf)); | 1939 | |
| 1941 | psf->sf_addr = *psfsrc; | 1940 | psf->sf_addr = *psfsrc; |
| 1942 | if (psf_prev) { | 1941 | if (psf_prev) { |
| 1943 | psf_prev->sf_next = psf; | 1942 | psf_prev->sf_next = psf; |
| @@ -2431,7 +2430,7 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | |||
| 2431 | { | 2430 | { |
| 2432 | struct seq_file *seq; | 2431 | struct seq_file *seq; |
| 2433 | int rc = -ENOMEM; | 2432 | int rc = -ENOMEM; |
| 2434 | struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2433 | struct igmp6_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 2435 | 2434 | ||
| 2436 | if (!s) | 2435 | if (!s) |
| 2437 | goto out; | 2436 | goto out; |
| @@ -2442,7 +2441,6 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | |||
| 2442 | 2441 | ||
| 2443 | seq = file->private_data; | 2442 | seq = file->private_data; |
| 2444 | seq->private = s; | 2443 | seq->private = s; |
| 2445 | memset(s, 0, sizeof(*s)); | ||
| 2446 | out: | 2444 | out: |
| 2447 | return rc; | 2445 | return rc; |
| 2448 | out_kfree: | 2446 | out_kfree: |
| @@ -2606,7 +2604,7 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | |||
| 2606 | { | 2604 | { |
| 2607 | struct seq_file *seq; | 2605 | struct seq_file *seq; |
| 2608 | int rc = -ENOMEM; | 2606 | int rc = -ENOMEM; |
| 2609 | struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2607 | struct igmp6_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 2610 | 2608 | ||
| 2611 | if (!s) | 2609 | if (!s) |
| 2612 | goto out; | 2610 | goto out; |
| @@ -2617,7 +2615,6 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | |||
| 2617 | 2615 | ||
| 2618 | seq = file->private_data; | 2616 | seq = file->private_data; |
| 2619 | seq->private = s; | 2617 | seq->private = s; |
| 2620 | memset(s, 0, sizeof(*s)); | ||
| 2621 | out: | 2618 | out: |
| 2622 | return rc; | 2619 | return rc; |
| 2623 | out_kfree: | 2620 | out_kfree: |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index cb8856b1d951..dfa20d3be9b6 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -156,7 +156,11 @@ struct neigh_table nd_tbl = { | |||
| 156 | 156 | ||
| 157 | /* ND options */ | 157 | /* ND options */ |
| 158 | struct ndisc_options { | 158 | struct ndisc_options { |
| 159 | struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX]; | 159 | struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX]; |
| 160 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 161 | struct nd_opt_hdr *nd_opts_ri; | ||
| 162 | struct nd_opt_hdr *nd_opts_ri_end; | ||
| 163 | #endif | ||
| 160 | }; | 164 | }; |
| 161 | 165 | ||
| 162 | #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] | 166 | #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] |
| @@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
| 255 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) | 259 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) |
| 256 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; | 260 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; |
| 257 | break; | 261 | break; |
| 262 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 263 | case ND_OPT_ROUTE_INFO: | ||
| 264 | ndopts->nd_opts_ri_end = nd_opt; | ||
| 265 | if (!ndopts->nd_opts_ri) | ||
| 266 | ndopts->nd_opts_ri = nd_opt; | ||
| 267 | break; | ||
| 268 | #endif | ||
| 258 | default: | 269 | default: |
| 259 | /* | 270 | /* |
| 260 | * Unknown options must be silently ignored, | 271 | * Unknown options must be silently ignored, |
| @@ -1019,10 +1030,11 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1019 | struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; | 1030 | struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; |
| 1020 | struct neighbour *neigh = NULL; | 1031 | struct neighbour *neigh = NULL; |
| 1021 | struct inet6_dev *in6_dev; | 1032 | struct inet6_dev *in6_dev; |
| 1022 | struct rt6_info *rt; | 1033 | struct rt6_info *rt = NULL; |
| 1023 | int lifetime; | 1034 | int lifetime; |
| 1024 | struct ndisc_options ndopts; | 1035 | struct ndisc_options ndopts; |
| 1025 | int optlen; | 1036 | int optlen; |
| 1037 | unsigned int pref = 0; | ||
| 1026 | 1038 | ||
| 1027 | __u8 * opt = (__u8 *)(ra_msg + 1); | 1039 | __u8 * opt = (__u8 *)(ra_msg + 1); |
| 1028 | 1040 | ||
| @@ -1081,8 +1093,19 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1081 | (ra_msg->icmph.icmp6_addrconf_other ? | 1093 | (ra_msg->icmph.icmp6_addrconf_other ? |
| 1082 | IF_RA_OTHERCONF : 0); | 1094 | IF_RA_OTHERCONF : 0); |
| 1083 | 1095 | ||
| 1096 | if (!in6_dev->cnf.accept_ra_defrtr) | ||
| 1097 | goto skip_defrtr; | ||
| 1098 | |||
| 1084 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); | 1099 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
| 1085 | 1100 | ||
| 1101 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 1102 | pref = ra_msg->icmph.icmp6_router_pref; | ||
| 1103 | /* 10b is handled as if it were 00b (medium) */ | ||
| 1104 | if (pref == ICMPV6_ROUTER_PREF_INVALID || | ||
| 1105 | in6_dev->cnf.accept_ra_rtr_pref) | ||
| 1106 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | ||
| 1107 | #endif | ||
| 1108 | |||
| 1086 | rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); | 1109 | rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); |
| 1087 | 1110 | ||
| 1088 | if (rt) | 1111 | if (rt) |
| @@ -1098,7 +1121,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1098 | ND_PRINTK3(KERN_DEBUG | 1121 | ND_PRINTK3(KERN_DEBUG |
| 1099 | "ICMPv6 RA: adding default router.\n"); | 1122 | "ICMPv6 RA: adding default router.\n"); |
| 1100 | 1123 | ||
| 1101 | rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); | 1124 | rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref); |
| 1102 | if (rt == NULL) { | 1125 | if (rt == NULL) { |
| 1103 | ND_PRINTK0(KERN_ERR | 1126 | ND_PRINTK0(KERN_ERR |
| 1104 | "ICMPv6 RA: %s() failed to add default route.\n", | 1127 | "ICMPv6 RA: %s() failed to add default route.\n", |
| @@ -1117,6 +1140,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1117 | return; | 1140 | return; |
| 1118 | } | 1141 | } |
| 1119 | neigh->flags |= NTF_ROUTER; | 1142 | neigh->flags |= NTF_ROUTER; |
| 1143 | } else if (rt) { | ||
| 1144 | rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); | ||
| 1120 | } | 1145 | } |
| 1121 | 1146 | ||
| 1122 | if (rt) | 1147 | if (rt) |
| @@ -1128,6 +1153,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1128 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; | 1153 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; |
| 1129 | } | 1154 | } |
| 1130 | 1155 | ||
| 1156 | skip_defrtr: | ||
| 1157 | |||
| 1131 | /* | 1158 | /* |
| 1132 | * Update Reachable Time and Retrans Timer | 1159 | * Update Reachable Time and Retrans Timer |
| 1133 | */ | 1160 | */ |
| @@ -1186,7 +1213,21 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1186 | NEIGH_UPDATE_F_ISROUTER); | 1213 | NEIGH_UPDATE_F_ISROUTER); |
| 1187 | } | 1214 | } |
| 1188 | 1215 | ||
| 1189 | if (ndopts.nd_opts_pi) { | 1216 | #ifdef CONFIG_IPV6_ROUTE_INFO |
| 1217 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { | ||
| 1218 | struct nd_opt_hdr *p; | ||
| 1219 | for (p = ndopts.nd_opts_ri; | ||
| 1220 | p; | ||
| 1221 | p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { | ||
| 1222 | if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | ||
| 1223 | continue; | ||
| 1224 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, | ||
| 1225 | &skb->nh.ipv6h->saddr); | ||
| 1226 | } | ||
| 1227 | } | ||
| 1228 | #endif | ||
| 1229 | |||
| 1230 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { | ||
| 1190 | struct nd_opt_hdr *p; | 1231 | struct nd_opt_hdr *p; |
| 1191 | for (p = ndopts.nd_opts_pi; | 1232 | for (p = ndopts.nd_opts_pi; |
| 1192 | p; | 1233 | p; |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 2d6f8ecbc27b..98f78759f1ab 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
| @@ -133,16 +133,6 @@ config IP6_NF_MATCH_EUI64 | |||
| 133 | 133 | ||
| 134 | To compile it as a module, choose M here. If unsure, say N. | 134 | To compile it as a module, choose M here. If unsure, say N. |
| 135 | 135 | ||
| 136 | config IP6_NF_MATCH_POLICY | ||
| 137 | tristate "IPsec policy match support" | ||
| 138 | depends on IP6_NF_IPTABLES && XFRM | ||
| 139 | help | ||
| 140 | Policy matching allows you to match packets based on the | ||
| 141 | IPsec policy that was used during decapsulation/will | ||
| 142 | be used during encapsulation. | ||
| 143 | |||
| 144 | To compile it as a module, choose M here. If unsure, say N. | ||
| 145 | |||
| 146 | # The targets | 136 | # The targets |
| 147 | config IP6_NF_FILTER | 137 | config IP6_NF_FILTER |
| 148 | tristate "Packet filtering" | 138 | tristate "Packet filtering" |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index db6073c94163..8436a1a1731f 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
| @@ -9,7 +9,6 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o | |||
| 9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o | 9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
| 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o | 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
| 11 | obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o | 11 | obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o |
| 12 | obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o | ||
| 13 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o | 12 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
| 14 | obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o | 13 | obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o |
| 15 | obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o | 14 | obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index af0635084df8..344eab3b5da8 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
| 36 | #include <linux/sysctl.h> | 36 | #include <linux/sysctl.h> |
| 37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
| 38 | #include <linux/mutex.h> | ||
| 38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
| 39 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
| 40 | #include <net/ip6_route.h> | 41 | #include <net/ip6_route.h> |
| @@ -65,7 +66,7 @@ static unsigned int queue_dropped = 0; | |||
| 65 | static unsigned int queue_user_dropped = 0; | 66 | static unsigned int queue_user_dropped = 0; |
| 66 | static struct sock *ipqnl; | 67 | static struct sock *ipqnl; |
| 67 | static LIST_HEAD(queue_list); | 68 | static LIST_HEAD(queue_list); |
| 68 | static DECLARE_MUTEX(ipqnl_sem); | 69 | static DEFINE_MUTEX(ipqnl_mutex); |
| 69 | 70 | ||
| 70 | static void | 71 | static void |
| 71 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) | 72 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) |
| @@ -537,7 +538,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
| 537 | struct sk_buff *skb; | 538 | struct sk_buff *skb; |
| 538 | unsigned int qlen; | 539 | unsigned int qlen; |
| 539 | 540 | ||
| 540 | down(&ipqnl_sem); | 541 | mutex_lock(&ipqnl_mutex); |
| 541 | 542 | ||
| 542 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { | 543 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { |
| 543 | skb = skb_dequeue(&sk->sk_receive_queue); | 544 | skb = skb_dequeue(&sk->sk_receive_queue); |
| @@ -545,7 +546,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
| 545 | kfree_skb(skb); | 546 | kfree_skb(skb); |
| 546 | } | 547 | } |
| 547 | 548 | ||
| 548 | up(&ipqnl_sem); | 549 | mutex_unlock(&ipqnl_mutex); |
| 549 | } | 550 | } |
| 550 | 551 | ||
| 551 | static int | 552 | static int |
| @@ -704,8 +705,8 @@ cleanup_sysctl: | |||
| 704 | 705 | ||
| 705 | cleanup_ipqnl: | 706 | cleanup_ipqnl: |
| 706 | sock_release(ipqnl->sk_socket); | 707 | sock_release(ipqnl->sk_socket); |
| 707 | down(&ipqnl_sem); | 708 | mutex_lock(&ipqnl_mutex); |
| 708 | up(&ipqnl_sem); | 709 | mutex_unlock(&ipqnl_mutex); |
| 709 | 710 | ||
| 710 | cleanup_netlink_notifier: | 711 | cleanup_netlink_notifier: |
| 711 | netlink_unregister_notifier(&ipq_nl_notifier); | 712 | netlink_unregister_notifier(&ipq_nl_notifier); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74ff56c322f4..db3c9ae98e95 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
| 30 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
| 31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| 32 | #include <asm/semaphore.h> | 32 | #include <linux/mutex.h> |
| 33 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
| 34 | #include <linux/cpumask.h> | 34 | #include <linux/cpumask.h> |
| 35 | 35 | ||
| @@ -94,19 +94,6 @@ do { \ | |||
| 94 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) | 94 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) |
| 95 | #endif | 95 | #endif |
| 96 | 96 | ||
| 97 | int | ||
| 98 | ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask, | ||
| 99 | const struct in6_addr *addr2) | ||
| 100 | { | ||
| 101 | int i; | ||
| 102 | for( i = 0; i < 16; i++){ | ||
| 103 | if((addr1->s6_addr[i] & mask->s6_addr[i]) != | ||
| 104 | (addr2->s6_addr[i] & mask->s6_addr[i])) | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | /* Check for an extension */ | 97 | /* Check for an extension */ |
| 111 | int | 98 | int |
| 112 | ip6t_ext_hdr(u8 nexthdr) | 99 | ip6t_ext_hdr(u8 nexthdr) |
| @@ -135,10 +122,10 @@ ip6_packet_match(const struct sk_buff *skb, | |||
| 135 | 122 | ||
| 136 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) | 123 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) |
| 137 | 124 | ||
| 138 | if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, | 125 | if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, |
| 139 | &ip6info->src), IP6T_INV_SRCIP) | 126 | &ip6info->src), IP6T_INV_SRCIP) |
| 140 | || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, | 127 | || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, |
| 141 | &ip6info->dst), IP6T_INV_DSTIP)) { | 128 | &ip6info->dst), IP6T_INV_DSTIP)) { |
| 142 | dprintf("Source or dest mismatch.\n"); | 129 | dprintf("Source or dest mismatch.\n"); |
| 143 | /* | 130 | /* |
| 144 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, | 131 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, |
| @@ -232,6 +219,7 @@ ip6t_error(struct sk_buff **pskb, | |||
| 232 | const struct net_device *in, | 219 | const struct net_device *in, |
| 233 | const struct net_device *out, | 220 | const struct net_device *out, |
| 234 | unsigned int hooknum, | 221 | unsigned int hooknum, |
| 222 | const struct xt_target *target, | ||
| 235 | const void *targinfo, | 223 | const void *targinfo, |
| 236 | void *userinfo) | 224 | void *userinfo) |
| 237 | { | 225 | { |
| @@ -251,7 +239,7 @@ int do_match(struct ip6t_entry_match *m, | |||
| 251 | int *hotdrop) | 239 | int *hotdrop) |
| 252 | { | 240 | { |
| 253 | /* Stop iteration if it doesn't match */ | 241 | /* Stop iteration if it doesn't match */ |
| 254 | if (!m->u.kernel.match->match(skb, in, out, m->data, | 242 | if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data, |
| 255 | offset, protoff, hotdrop)) | 243 | offset, protoff, hotdrop)) |
| 256 | return 1; | 244 | return 1; |
| 257 | else | 245 | else |
| @@ -373,6 +361,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
| 373 | verdict = t->u.kernel.target->target(pskb, | 361 | verdict = t->u.kernel.target->target(pskb, |
| 374 | in, out, | 362 | in, out, |
| 375 | hook, | 363 | hook, |
| 364 | t->u.kernel.target, | ||
| 376 | t->data, | 365 | t->data, |
| 377 | userdata); | 366 | userdata); |
| 378 | 367 | ||
| @@ -531,7 +520,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | |||
| 531 | return 1; | 520 | return 1; |
| 532 | 521 | ||
| 533 | if (m->u.kernel.match->destroy) | 522 | if (m->u.kernel.match->destroy) |
| 534 | m->u.kernel.match->destroy(m->data, | 523 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, |
| 535 | m->u.match_size - sizeof(*m)); | 524 | m->u.match_size - sizeof(*m)); |
| 536 | module_put(m->u.kernel.match->me); | 525 | module_put(m->u.kernel.match->me); |
| 537 | return 0; | 526 | return 0; |
| @@ -544,21 +533,12 @@ standard_check(const struct ip6t_entry_target *t, | |||
| 544 | struct ip6t_standard_target *targ = (void *)t; | 533 | struct ip6t_standard_target *targ = (void *)t; |
| 545 | 534 | ||
| 546 | /* Check standard info. */ | 535 | /* Check standard info. */ |
| 547 | if (t->u.target_size | ||
| 548 | != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) { | ||
| 549 | duprintf("standard_check: target size %u != %u\n", | ||
| 550 | t->u.target_size, | ||
| 551 | IP6T_ALIGN(sizeof(struct ip6t_standard_target))); | ||
| 552 | return 0; | ||
| 553 | } | ||
| 554 | |||
| 555 | if (targ->verdict >= 0 | 536 | if (targ->verdict >= 0 |
| 556 | && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { | 537 | && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { |
| 557 | duprintf("ip6t_standard_check: bad verdict (%i)\n", | 538 | duprintf("ip6t_standard_check: bad verdict (%i)\n", |
| 558 | targ->verdict); | 539 | targ->verdict); |
| 559 | return 0; | 540 | return 0; |
| 560 | } | 541 | } |
| 561 | |||
| 562 | if (targ->verdict < -NF_MAX_VERDICT - 1) { | 542 | if (targ->verdict < -NF_MAX_VERDICT - 1) { |
| 563 | duprintf("ip6t_standard_check: bad negative verdict (%i)\n", | 543 | duprintf("ip6t_standard_check: bad negative verdict (%i)\n", |
| 564 | targ->verdict); | 544 | targ->verdict); |
| @@ -575,6 +555,7 @@ check_match(struct ip6t_entry_match *m, | |||
| 575 | unsigned int *i) | 555 | unsigned int *i) |
| 576 | { | 556 | { |
| 577 | struct ip6t_match *match; | 557 | struct ip6t_match *match; |
| 558 | int ret; | ||
| 578 | 559 | ||
| 579 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, | 560 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, |
| 580 | m->u.user.revision), | 561 | m->u.user.revision), |
| @@ -585,18 +566,27 @@ check_match(struct ip6t_entry_match *m, | |||
| 585 | } | 566 | } |
| 586 | m->u.kernel.match = match; | 567 | m->u.kernel.match = match; |
| 587 | 568 | ||
| 569 | ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), | ||
| 570 | name, hookmask, ipv6->proto, | ||
| 571 | ipv6->invflags & IP6T_INV_PROTO); | ||
| 572 | if (ret) | ||
| 573 | goto err; | ||
| 574 | |||
| 588 | if (m->u.kernel.match->checkentry | 575 | if (m->u.kernel.match->checkentry |
| 589 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, | 576 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, |
| 590 | m->u.match_size - sizeof(*m), | 577 | m->u.match_size - sizeof(*m), |
| 591 | hookmask)) { | 578 | hookmask)) { |
| 592 | module_put(m->u.kernel.match->me); | ||
| 593 | duprintf("ip_tables: check failed for `%s'.\n", | 579 | duprintf("ip_tables: check failed for `%s'.\n", |
| 594 | m->u.kernel.match->name); | 580 | m->u.kernel.match->name); |
| 595 | return -EINVAL; | 581 | ret = -EINVAL; |
| 582 | goto err; | ||
| 596 | } | 583 | } |
| 597 | 584 | ||
| 598 | (*i)++; | 585 | (*i)++; |
| 599 | return 0; | 586 | return 0; |
| 587 | err: | ||
| 588 | module_put(m->u.kernel.match->me); | ||
| 589 | return ret; | ||
| 600 | } | 590 | } |
| 601 | 591 | ||
| 602 | static struct ip6t_target ip6t_standard_target; | 592 | static struct ip6t_target ip6t_standard_target; |
| @@ -632,26 +622,32 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
| 632 | } | 622 | } |
| 633 | t->u.kernel.target = target; | 623 | t->u.kernel.target = target; |
| 634 | 624 | ||
| 625 | ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), | ||
| 626 | name, e->comefrom, e->ipv6.proto, | ||
| 627 | e->ipv6.invflags & IP6T_INV_PROTO); | ||
| 628 | if (ret) | ||
| 629 | goto err; | ||
| 630 | |||
| 635 | if (t->u.kernel.target == &ip6t_standard_target) { | 631 | if (t->u.kernel.target == &ip6t_standard_target) { |
| 636 | if (!standard_check(t, size)) { | 632 | if (!standard_check(t, size)) { |
| 637 | ret = -EINVAL; | 633 | ret = -EINVAL; |
| 638 | goto cleanup_matches; | 634 | goto cleanup_matches; |
| 639 | } | 635 | } |
| 640 | } else if (t->u.kernel.target->checkentry | 636 | } else if (t->u.kernel.target->checkentry |
| 641 | && !t->u.kernel.target->checkentry(name, e, t->data, | 637 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
| 642 | t->u.target_size | 638 | t->u.target_size |
| 643 | - sizeof(*t), | 639 | - sizeof(*t), |
| 644 | e->comefrom)) { | 640 | e->comefrom)) { |
| 645 | module_put(t->u.kernel.target->me); | ||
| 646 | duprintf("ip_tables: check failed for `%s'.\n", | 641 | duprintf("ip_tables: check failed for `%s'.\n", |
| 647 | t->u.kernel.target->name); | 642 | t->u.kernel.target->name); |
| 648 | ret = -EINVAL; | 643 | ret = -EINVAL; |
| 649 | goto cleanup_matches; | 644 | goto err; |
| 650 | } | 645 | } |
| 651 | 646 | ||
| 652 | (*i)++; | 647 | (*i)++; |
| 653 | return 0; | 648 | return 0; |
| 654 | 649 | err: | |
| 650 | module_put(t->u.kernel.target->me); | ||
| 655 | cleanup_matches: | 651 | cleanup_matches: |
| 656 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 652 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); |
| 657 | return ret; | 653 | return ret; |
| @@ -712,7 +708,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) | |||
| 712 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 708 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); |
| 713 | t = ip6t_get_target(e); | 709 | t = ip6t_get_target(e); |
| 714 | if (t->u.kernel.target->destroy) | 710 | if (t->u.kernel.target->destroy) |
| 715 | t->u.kernel.target->destroy(t->data, | 711 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, |
| 716 | t->u.target_size - sizeof(*t)); | 712 | t->u.target_size - sizeof(*t)); |
| 717 | module_put(t->u.kernel.target->me); | 713 | module_put(t->u.kernel.target->me); |
| 718 | return 0; | 714 | return 0; |
| @@ -1333,6 +1329,7 @@ static int | |||
| 1333 | icmp6_match(const struct sk_buff *skb, | 1329 | icmp6_match(const struct sk_buff *skb, |
| 1334 | const struct net_device *in, | 1330 | const struct net_device *in, |
| 1335 | const struct net_device *out, | 1331 | const struct net_device *out, |
| 1332 | const struct xt_match *match, | ||
| 1336 | const void *matchinfo, | 1333 | const void *matchinfo, |
| 1337 | int offset, | 1334 | int offset, |
| 1338 | unsigned int protoff, | 1335 | unsigned int protoff, |
| @@ -1365,28 +1362,29 @@ icmp6_match(const struct sk_buff *skb, | |||
| 1365 | static int | 1362 | static int |
| 1366 | icmp6_checkentry(const char *tablename, | 1363 | icmp6_checkentry(const char *tablename, |
| 1367 | const void *entry, | 1364 | const void *entry, |
| 1365 | const struct xt_match *match, | ||
| 1368 | void *matchinfo, | 1366 | void *matchinfo, |
| 1369 | unsigned int matchsize, | 1367 | unsigned int matchsize, |
| 1370 | unsigned int hook_mask) | 1368 | unsigned int hook_mask) |
| 1371 | { | 1369 | { |
| 1372 | const struct ip6t_ip6 *ipv6 = entry; | ||
| 1373 | const struct ip6t_icmp *icmpinfo = matchinfo; | 1370 | const struct ip6t_icmp *icmpinfo = matchinfo; |
| 1374 | 1371 | ||
| 1375 | /* Must specify proto == ICMP, and no unknown invflags */ | 1372 | /* Must specify no unknown invflags */ |
| 1376 | return ipv6->proto == IPPROTO_ICMPV6 | 1373 | return !(icmpinfo->invflags & ~IP6T_ICMP_INV); |
| 1377 | && !(ipv6->invflags & IP6T_INV_PROTO) | ||
| 1378 | && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp)) | ||
| 1379 | && !(icmpinfo->invflags & ~IP6T_ICMP_INV); | ||
| 1380 | } | 1374 | } |
| 1381 | 1375 | ||
| 1382 | /* The built-in targets: standard (NULL) and error. */ | 1376 | /* The built-in targets: standard (NULL) and error. */ |
| 1383 | static struct ip6t_target ip6t_standard_target = { | 1377 | static struct ip6t_target ip6t_standard_target = { |
| 1384 | .name = IP6T_STANDARD_TARGET, | 1378 | .name = IP6T_STANDARD_TARGET, |
| 1379 | .targetsize = sizeof(int), | ||
| 1380 | .family = AF_INET6, | ||
| 1385 | }; | 1381 | }; |
| 1386 | 1382 | ||
| 1387 | static struct ip6t_target ip6t_error_target = { | 1383 | static struct ip6t_target ip6t_error_target = { |
| 1388 | .name = IP6T_ERROR_TARGET, | 1384 | .name = IP6T_ERROR_TARGET, |
| 1389 | .target = ip6t_error, | 1385 | .target = ip6t_error, |
| 1386 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, | ||
| 1387 | .family = AF_INET6, | ||
| 1390 | }; | 1388 | }; |
| 1391 | 1389 | ||
| 1392 | static struct nf_sockopt_ops ip6t_sockopts = { | 1390 | static struct nf_sockopt_ops ip6t_sockopts = { |
| @@ -1402,7 +1400,10 @@ static struct nf_sockopt_ops ip6t_sockopts = { | |||
| 1402 | static struct ip6t_match icmp6_matchstruct = { | 1400 | static struct ip6t_match icmp6_matchstruct = { |
| 1403 | .name = "icmp6", | 1401 | .name = "icmp6", |
| 1404 | .match = &icmp6_match, | 1402 | .match = &icmp6_match, |
| 1405 | .checkentry = &icmp6_checkentry, | 1403 | .matchsize = sizeof(struct ip6t_icmp), |
| 1404 | .checkentry = icmp6_checkentry, | ||
| 1405 | .proto = IPPROTO_ICMPV6, | ||
| 1406 | .family = AF_INET6, | ||
| 1406 | }; | 1407 | }; |
| 1407 | 1408 | ||
| 1408 | static int __init init(void) | 1409 | static int __init init(void) |
| @@ -1412,9 +1413,9 @@ static int __init init(void) | |||
| 1412 | xt_proto_init(AF_INET6); | 1413 | xt_proto_init(AF_INET6); |
| 1413 | 1414 | ||
| 1414 | /* Noone else will be downing sem now, so we won't sleep */ | 1415 | /* Noone else will be downing sem now, so we won't sleep */ |
| 1415 | xt_register_target(AF_INET6, &ip6t_standard_target); | 1416 | xt_register_target(&ip6t_standard_target); |
| 1416 | xt_register_target(AF_INET6, &ip6t_error_target); | 1417 | xt_register_target(&ip6t_error_target); |
| 1417 | xt_register_match(AF_INET6, &icmp6_matchstruct); | 1418 | xt_register_match(&icmp6_matchstruct); |
| 1418 | 1419 | ||
| 1419 | /* Register setsockopt */ | 1420 | /* Register setsockopt */ |
| 1420 | ret = nf_register_sockopt(&ip6t_sockopts); | 1421 | ret = nf_register_sockopt(&ip6t_sockopts); |
| @@ -1431,9 +1432,9 @@ static int __init init(void) | |||
| 1431 | static void __exit fini(void) | 1432 | static void __exit fini(void) |
| 1432 | { | 1433 | { |
| 1433 | nf_unregister_sockopt(&ip6t_sockopts); | 1434 | nf_unregister_sockopt(&ip6t_sockopts); |
| 1434 | xt_unregister_match(AF_INET6, &icmp6_matchstruct); | 1435 | xt_unregister_match(&icmp6_matchstruct); |
| 1435 | xt_unregister_target(AF_INET6, &ip6t_error_target); | 1436 | xt_unregister_target(&ip6t_error_target); |
| 1436 | xt_unregister_target(AF_INET6, &ip6t_standard_target); | 1437 | xt_unregister_target(&ip6t_standard_target); |
| 1437 | xt_proto_fini(AF_INET6); | 1438 | xt_proto_fini(AF_INET6); |
| 1438 | } | 1439 | } |
| 1439 | 1440 | ||
| @@ -1515,7 +1516,6 @@ EXPORT_SYMBOL(ip6t_unregister_table); | |||
| 1515 | EXPORT_SYMBOL(ip6t_do_table); | 1516 | EXPORT_SYMBOL(ip6t_do_table); |
| 1516 | EXPORT_SYMBOL(ip6t_ext_hdr); | 1517 | EXPORT_SYMBOL(ip6t_ext_hdr); |
| 1517 | EXPORT_SYMBOL(ipv6_find_hdr); | 1518 | EXPORT_SYMBOL(ipv6_find_hdr); |
| 1518 | EXPORT_SYMBOL(ip6_masked_addrcmp); | ||
| 1519 | 1519 | ||
| 1520 | module_init(init); | 1520 | module_init(init); |
| 1521 | module_exit(fini); | 1521 | module_exit(fini); |
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index 306200c35057..da14c6d86bcc 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c | |||
| @@ -21,6 +21,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
| 21 | const struct net_device *in, | 21 | const struct net_device *in, |
| 22 | const struct net_device *out, | 22 | const struct net_device *out, |
| 23 | unsigned int hooknum, | 23 | unsigned int hooknum, |
| 24 | const struct xt_target *target, | ||
| 24 | const void *targinfo, void *userinfo) | 25 | const void *targinfo, void *userinfo) |
| 25 | { | 26 | { |
| 26 | struct ipv6hdr *ip6h; | 27 | struct ipv6hdr *ip6h; |
| @@ -63,43 +64,31 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
| 63 | 64 | ||
| 64 | static int ip6t_hl_checkentry(const char *tablename, | 65 | static int ip6t_hl_checkentry(const char *tablename, |
| 65 | const void *entry, | 66 | const void *entry, |
| 67 | const struct xt_target *target, | ||
| 66 | void *targinfo, | 68 | void *targinfo, |
| 67 | unsigned int targinfosize, | 69 | unsigned int targinfosize, |
| 68 | unsigned int hook_mask) | 70 | unsigned int hook_mask) |
| 69 | { | 71 | { |
| 70 | struct ip6t_HL_info *info = targinfo; | 72 | struct ip6t_HL_info *info = targinfo; |
| 71 | 73 | ||
| 72 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) { | ||
| 73 | printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n", | ||
| 74 | targinfosize, | ||
| 75 | IP6T_ALIGN(sizeof(struct ip6t_HL_info))); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | if (strcmp(tablename, "mangle")) { | ||
| 80 | printk(KERN_WARNING "ip6t_HL: can only be called from " | ||
| 81 | "\"mangle\" table, not \"%s\"\n", tablename); | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (info->mode > IP6T_HL_MAXMODE) { | 74 | if (info->mode > IP6T_HL_MAXMODE) { |
| 86 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | 75 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", |
| 87 | info->mode); | 76 | info->mode); |
| 88 | return 0; | 77 | return 0; |
| 89 | } | 78 | } |
| 90 | |||
| 91 | if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { | 79 | if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { |
| 92 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | 80 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " |
| 93 | "make sense with value 0\n"); | 81 | "make sense with value 0\n"); |
| 94 | return 0; | 82 | return 0; |
| 95 | } | 83 | } |
| 96 | |||
| 97 | return 1; | 84 | return 1; |
| 98 | } | 85 | } |
| 99 | 86 | ||
| 100 | static struct ip6t_target ip6t_HL = { | 87 | static struct ip6t_target ip6t_HL = { |
| 101 | .name = "HL", | 88 | .name = "HL", |
| 102 | .target = ip6t_hl_target, | 89 | .target = ip6t_hl_target, |
| 90 | .targetsize = sizeof(struct ip6t_HL_info), | ||
| 91 | .table = "mangle", | ||
| 103 | .checkentry = ip6t_hl_checkentry, | 92 | .checkentry = ip6t_hl_checkentry, |
| 104 | .me = THIS_MODULE | 93 | .me = THIS_MODULE |
| 105 | }; | 94 | }; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 6b930efa9fb9..07c6bcbe4c5f 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
| @@ -426,6 +426,7 @@ ip6t_log_target(struct sk_buff **pskb, | |||
| 426 | const struct net_device *in, | 426 | const struct net_device *in, |
| 427 | const struct net_device *out, | 427 | const struct net_device *out, |
| 428 | unsigned int hooknum, | 428 | unsigned int hooknum, |
| 429 | const struct xt_target *target, | ||
| 429 | const void *targinfo, | 430 | const void *targinfo, |
| 430 | void *userinfo) | 431 | void *userinfo) |
| 431 | { | 432 | { |
| @@ -449,35 +450,29 @@ ip6t_log_target(struct sk_buff **pskb, | |||
| 449 | 450 | ||
| 450 | static int ip6t_log_checkentry(const char *tablename, | 451 | static int ip6t_log_checkentry(const char *tablename, |
| 451 | const void *entry, | 452 | const void *entry, |
| 453 | const struct xt_target *target, | ||
| 452 | void *targinfo, | 454 | void *targinfo, |
| 453 | unsigned int targinfosize, | 455 | unsigned int targinfosize, |
| 454 | unsigned int hook_mask) | 456 | unsigned int hook_mask) |
| 455 | { | 457 | { |
| 456 | const struct ip6t_log_info *loginfo = targinfo; | 458 | const struct ip6t_log_info *loginfo = targinfo; |
| 457 | 459 | ||
| 458 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) { | ||
| 459 | DEBUGP("LOG: targinfosize %u != %u\n", | ||
| 460 | targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info))); | ||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | if (loginfo->level >= 8) { | 460 | if (loginfo->level >= 8) { |
| 465 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); | 461 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); |
| 466 | return 0; | 462 | return 0; |
| 467 | } | 463 | } |
| 468 | |||
| 469 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | 464 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { |
| 470 | DEBUGP("LOG: prefix term %i\n", | 465 | DEBUGP("LOG: prefix term %i\n", |
| 471 | loginfo->prefix[sizeof(loginfo->prefix)-1]); | 466 | loginfo->prefix[sizeof(loginfo->prefix)-1]); |
| 472 | return 0; | 467 | return 0; |
| 473 | } | 468 | } |
| 474 | |||
| 475 | return 1; | 469 | return 1; |
| 476 | } | 470 | } |
| 477 | 471 | ||
| 478 | static struct ip6t_target ip6t_log_reg = { | 472 | static struct ip6t_target ip6t_log_reg = { |
| 479 | .name = "LOG", | 473 | .name = "LOG", |
| 480 | .target = ip6t_log_target, | 474 | .target = ip6t_log_target, |
| 475 | .targetsize = sizeof(struct ip6t_log_info), | ||
| 481 | .checkentry = ip6t_log_checkentry, | 476 | .checkentry = ip6t_log_checkentry, |
| 482 | .me = THIS_MODULE, | 477 | .me = THIS_MODULE, |
| 483 | }; | 478 | }; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 0e6d1d4bbd5c..ddfa38575fe2 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
| @@ -179,6 +179,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
| 179 | const struct net_device *in, | 179 | const struct net_device *in, |
| 180 | const struct net_device *out, | 180 | const struct net_device *out, |
| 181 | unsigned int hooknum, | 181 | unsigned int hooknum, |
| 182 | const struct xt_target *target, | ||
| 182 | const void *targinfo, | 183 | const void *targinfo, |
| 183 | void *userinfo) | 184 | void *userinfo) |
| 184 | { | 185 | { |
| @@ -221,6 +222,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
| 221 | 222 | ||
| 222 | static int check(const char *tablename, | 223 | static int check(const char *tablename, |
| 223 | const void *entry, | 224 | const void *entry, |
| 225 | const struct xt_target *target, | ||
| 224 | void *targinfo, | 226 | void *targinfo, |
| 225 | unsigned int targinfosize, | 227 | unsigned int targinfosize, |
| 226 | unsigned int hook_mask) | 228 | unsigned int hook_mask) |
| @@ -228,24 +230,6 @@ static int check(const char *tablename, | |||
| 228 | const struct ip6t_reject_info *rejinfo = targinfo; | 230 | const struct ip6t_reject_info *rejinfo = targinfo; |
| 229 | const struct ip6t_entry *e = entry; | 231 | const struct ip6t_entry *e = entry; |
| 230 | 232 | ||
| 231 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { | ||
| 232 | DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* Only allow these for packet filtering. */ | ||
| 237 | if (strcmp(tablename, "filter") != 0) { | ||
| 238 | DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename); | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN) | ||
| 243 | | (1 << NF_IP6_FORWARD) | ||
| 244 | | (1 << NF_IP6_LOCAL_OUT))) != 0) { | ||
| 245 | DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask); | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { | 233 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { |
| 250 | printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); | 234 | printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); |
| 251 | return 0; | 235 | return 0; |
| @@ -257,13 +241,16 @@ static int check(const char *tablename, | |||
| 257 | return 0; | 241 | return 0; |
| 258 | } | 242 | } |
| 259 | } | 243 | } |
| 260 | |||
| 261 | return 1; | 244 | return 1; |
| 262 | } | 245 | } |
| 263 | 246 | ||
| 264 | static struct ip6t_target ip6t_reject_reg = { | 247 | static struct ip6t_target ip6t_reject_reg = { |
| 265 | .name = "REJECT", | 248 | .name = "REJECT", |
| 266 | .target = reject6_target, | 249 | .target = reject6_target, |
| 250 | .targetsize = sizeof(struct ip6t_reject_info), | ||
| 251 | .table = "filter", | ||
| 252 | .hooks = (1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | | ||
| 253 | (1 << NF_IP6_LOCAL_OUT), | ||
| 267 | .checkentry = check, | 254 | .checkentry = check, |
| 268 | .me = THIS_MODULE | 255 | .me = THIS_MODULE |
| 269 | }; | 256 | }; |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 219a30365dff..178f6fb1e53d 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
| @@ -44,6 +44,7 @@ static int | |||
| 44 | match(const struct sk_buff *skb, | 44 | match(const struct sk_buff *skb, |
| 45 | const struct net_device *in, | 45 | const struct net_device *in, |
| 46 | const struct net_device *out, | 46 | const struct net_device *out, |
| 47 | const struct xt_match *match, | ||
| 47 | const void *matchinfo, | 48 | const void *matchinfo, |
| 48 | int offset, | 49 | int offset, |
| 49 | unsigned int protoff, | 50 | unsigned int protoff, |
| @@ -99,17 +100,13 @@ match(const struct sk_buff *skb, | |||
| 99 | static int | 100 | static int |
| 100 | checkentry(const char *tablename, | 101 | checkentry(const char *tablename, |
| 101 | const void *entry, | 102 | const void *entry, |
| 103 | const struct xt_match *match, | ||
| 102 | void *matchinfo, | 104 | void *matchinfo, |
| 103 | unsigned int matchinfosize, | 105 | unsigned int matchinfosize, |
| 104 | unsigned int hook_mask) | 106 | unsigned int hook_mask) |
| 105 | { | 107 | { |
| 106 | const struct ip6t_ah *ahinfo = matchinfo; | 108 | const struct ip6t_ah *ahinfo = matchinfo; |
| 107 | 109 | ||
| 108 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { | ||
| 109 | DEBUGP("ip6t_ah: matchsize %u != %u\n", | ||
| 110 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { | 110 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
| 114 | DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); | 111 | DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); |
| 115 | return 0; | 112 | return 0; |
| @@ -119,8 +116,9 @@ checkentry(const char *tablename, | |||
| 119 | 116 | ||
| 120 | static struct ip6t_match ah_match = { | 117 | static struct ip6t_match ah_match = { |
| 121 | .name = "ah", | 118 | .name = "ah", |
| 122 | .match = &match, | 119 | .match = match, |
| 123 | .checkentry = &checkentry, | 120 | .matchsize = sizeof(struct ip6t_ah), |
| 121 | .checkentry = checkentry, | ||
| 124 | .me = THIS_MODULE, | 122 | .me = THIS_MODULE, |
| 125 | }; | 123 | }; |
| 126 | 124 | ||
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index b4c153a53500..e97a70226987 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c | |||
| @@ -55,6 +55,7 @@ static int | |||
| 55 | match(const struct sk_buff *skb, | 55 | match(const struct sk_buff *skb, |
| 56 | const struct net_device *in, | 56 | const struct net_device *in, |
| 57 | const struct net_device *out, | 57 | const struct net_device *out, |
| 58 | const struct xt_match *match, | ||
| 58 | const void *matchinfo, | 59 | const void *matchinfo, |
| 59 | int offset, | 60 | int offset, |
| 60 | unsigned int protoff, | 61 | unsigned int protoff, |
| @@ -179,22 +180,17 @@ match(const struct sk_buff *skb, | |||
| 179 | static int | 180 | static int |
| 180 | checkentry(const char *tablename, | 181 | checkentry(const char *tablename, |
| 181 | const void *info, | 182 | const void *info, |
| 183 | const struct xt_match *match, | ||
| 182 | void *matchinfo, | 184 | void *matchinfo, |
| 183 | unsigned int matchinfosize, | 185 | unsigned int matchinfosize, |
| 184 | unsigned int hook_mask) | 186 | unsigned int hook_mask) |
| 185 | { | 187 | { |
| 186 | const struct ip6t_opts *optsinfo = matchinfo; | 188 | const struct ip6t_opts *optsinfo = matchinfo; |
| 187 | 189 | ||
| 188 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { | ||
| 189 | DEBUGP("ip6t_opts: matchsize %u != %u\n", | ||
| 190 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | 190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { |
| 194 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | 191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); |
| 195 | return 0; | 192 | return 0; |
| 196 | } | 193 | } |
| 197 | |||
| 198 | return 1; | 194 | return 1; |
| 199 | } | 195 | } |
| 200 | 196 | ||
| @@ -204,8 +200,9 @@ static struct ip6t_match opts_match = { | |||
| 204 | #else | 200 | #else |
| 205 | .name = "dst", | 201 | .name = "dst", |
| 206 | #endif | 202 | #endif |
| 207 | .match = &match, | 203 | .match = match, |
| 208 | .checkentry = &checkentry, | 204 | .matchsize = sizeof(struct ip6t_opts), |
| 205 | .checkentry = checkentry, | ||
| 209 | .me = THIS_MODULE, | 206 | .me = THIS_MODULE, |
| 210 | }; | 207 | }; |
| 211 | 208 | ||
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index 724285df8711..540b8bfd5055 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c | |||
| @@ -44,6 +44,7 @@ static int | |||
| 44 | match(const struct sk_buff *skb, | 44 | match(const struct sk_buff *skb, |
| 45 | const struct net_device *in, | 45 | const struct net_device *in, |
| 46 | const struct net_device *out, | 46 | const struct net_device *out, |
| 47 | const struct xt_match *match, | ||
| 47 | const void *matchinfo, | 48 | const void *matchinfo, |
| 48 | int offset, | 49 | int offset, |
| 49 | unsigned int protoff, | 50 | unsigned int protoff, |
| @@ -77,17 +78,13 @@ match(const struct sk_buff *skb, | |||
| 77 | static int | 78 | static int |
| 78 | checkentry(const char *tablename, | 79 | checkentry(const char *tablename, |
| 79 | const void *ip, | 80 | const void *ip, |
| 81 | const struct xt_match *match, | ||
| 80 | void *matchinfo, | 82 | void *matchinfo, |
| 81 | unsigned int matchinfosize, | 83 | unsigned int matchinfosize, |
| 82 | unsigned int hook_mask) | 84 | unsigned int hook_mask) |
| 83 | { | 85 | { |
| 84 | const struct ip6t_esp *espinfo = matchinfo; | 86 | const struct ip6t_esp *espinfo = matchinfo; |
| 85 | 87 | ||
| 86 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) { | ||
| 87 | DEBUGP("ip6t_esp: matchsize %u != %u\n", | ||
| 88 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp))); | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { | 88 | if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { |
| 92 | DEBUGP("ip6t_esp: unknown flags %X\n", | 89 | DEBUGP("ip6t_esp: unknown flags %X\n", |
| 93 | espinfo->invflags); | 90 | espinfo->invflags); |
| @@ -98,8 +95,9 @@ checkentry(const char *tablename, | |||
| 98 | 95 | ||
| 99 | static struct ip6t_match esp_match = { | 96 | static struct ip6t_match esp_match = { |
| 100 | .name = "esp", | 97 | .name = "esp", |
| 101 | .match = &match, | 98 | .match = match, |
| 102 | .checkentry = &checkentry, | 99 | .matchsize = sizeof(struct ip6t_esp), |
| 100 | .checkentry = checkentry, | ||
| 103 | .me = THIS_MODULE, | 101 | .me = THIS_MODULE, |
| 104 | }; | 102 | }; |
| 105 | 103 | ||
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 27396ac0b9ed..d4b0bad52830 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c | |||
| @@ -22,6 +22,7 @@ static int | |||
| 22 | match(const struct sk_buff *skb, | 22 | match(const struct sk_buff *skb, |
| 23 | const struct net_device *in, | 23 | const struct net_device *in, |
| 24 | const struct net_device *out, | 24 | const struct net_device *out, |
| 25 | const struct xt_match *match, | ||
| 25 | const void *matchinfo, | 26 | const void *matchinfo, |
| 26 | int offset, | 27 | int offset, |
| 27 | unsigned int protoff, | 28 | unsigned int protoff, |
| @@ -60,30 +61,12 @@ match(const struct sk_buff *skb, | |||
| 60 | return 0; | 61 | return 0; |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | static int | ||
| 64 | ip6t_eui64_checkentry(const char *tablename, | ||
| 65 | const void *ip, | ||
| 66 | void *matchinfo, | ||
| 67 | unsigned int matchsize, | ||
| 68 | unsigned int hook_mask) | ||
| 69 | { | ||
| 70 | if (hook_mask | ||
| 71 | & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | | ||
| 72 | (1 << NF_IP6_FORWARD))) { | ||
| 73 | printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | if (matchsize != IP6T_ALIGN(sizeof(int))) | ||
| 78 | return 0; | ||
| 79 | |||
| 80 | return 1; | ||
| 81 | } | ||
| 82 | |||
| 83 | static struct ip6t_match eui64_match = { | 64 | static struct ip6t_match eui64_match = { |
| 84 | .name = "eui64", | 65 | .name = "eui64", |
| 85 | .match = &match, | 66 | .match = match, |
| 86 | .checkentry = &ip6t_eui64_checkentry, | 67 | .matchsize = sizeof(int), |
| 68 | .hooks = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | | ||
| 69 | (1 << NF_IP6_FORWARD), | ||
| 87 | .me = THIS_MODULE, | 70 | .me = THIS_MODULE, |
| 88 | }; | 71 | }; |
| 89 | 72 | ||
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 4c14125a0e26..4c41e14823d5 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
| @@ -43,6 +43,7 @@ static int | |||
| 43 | match(const struct sk_buff *skb, | 43 | match(const struct sk_buff *skb, |
| 44 | const struct net_device *in, | 44 | const struct net_device *in, |
| 45 | const struct net_device *out, | 45 | const struct net_device *out, |
| 46 | const struct xt_match *match, | ||
| 46 | const void *matchinfo, | 47 | const void *matchinfo, |
| 47 | int offset, | 48 | int offset, |
| 48 | unsigned int protoff, | 49 | unsigned int protoff, |
| @@ -116,29 +117,25 @@ match(const struct sk_buff *skb, | |||
| 116 | static int | 117 | static int |
| 117 | checkentry(const char *tablename, | 118 | checkentry(const char *tablename, |
| 118 | const void *ip, | 119 | const void *ip, |
| 120 | const struct xt_match *match, | ||
| 119 | void *matchinfo, | 121 | void *matchinfo, |
| 120 | unsigned int matchinfosize, | 122 | unsigned int matchinfosize, |
| 121 | unsigned int hook_mask) | 123 | unsigned int hook_mask) |
| 122 | { | 124 | { |
| 123 | const struct ip6t_frag *fraginfo = matchinfo; | 125 | const struct ip6t_frag *fraginfo = matchinfo; |
| 124 | 126 | ||
| 125 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) { | ||
| 126 | DEBUGP("ip6t_frag: matchsize %u != %u\n", | ||
| 127 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag))); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { | 127 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
| 131 | DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); | 128 | DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); |
| 132 | return 0; | 129 | return 0; |
| 133 | } | 130 | } |
| 134 | |||
| 135 | return 1; | 131 | return 1; |
| 136 | } | 132 | } |
| 137 | 133 | ||
| 138 | static struct ip6t_match frag_match = { | 134 | static struct ip6t_match frag_match = { |
| 139 | .name = "frag", | 135 | .name = "frag", |
| 140 | .match = &match, | 136 | .match = match, |
| 141 | .checkentry = &checkentry, | 137 | .matchsize = sizeof(struct ip6t_frag), |
| 138 | .checkentry = checkentry, | ||
| 142 | .me = THIS_MODULE, | 139 | .me = THIS_MODULE, |
| 143 | }; | 140 | }; |
| 144 | 141 | ||
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 37a8474a7e0c..b4a1fdfe6abc 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
| @@ -55,6 +55,7 @@ static int | |||
| 55 | match(const struct sk_buff *skb, | 55 | match(const struct sk_buff *skb, |
| 56 | const struct net_device *in, | 56 | const struct net_device *in, |
| 57 | const struct net_device *out, | 57 | const struct net_device *out, |
| 58 | const struct xt_match *match, | ||
| 58 | const void *matchinfo, | 59 | const void *matchinfo, |
| 59 | int offset, | 60 | int offset, |
| 60 | unsigned int protoff, | 61 | unsigned int protoff, |
| @@ -179,22 +180,17 @@ match(const struct sk_buff *skb, | |||
| 179 | static int | 180 | static int |
| 180 | checkentry(const char *tablename, | 181 | checkentry(const char *tablename, |
| 181 | const void *entry, | 182 | const void *entry, |
| 183 | const struct xt_match *match, | ||
| 182 | void *matchinfo, | 184 | void *matchinfo, |
| 183 | unsigned int matchinfosize, | 185 | unsigned int matchinfosize, |
| 184 | unsigned int hook_mask) | 186 | unsigned int hook_mask) |
| 185 | { | 187 | { |
| 186 | const struct ip6t_opts *optsinfo = matchinfo; | 188 | const struct ip6t_opts *optsinfo = matchinfo; |
| 187 | 189 | ||
| 188 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { | ||
| 189 | DEBUGP("ip6t_opts: matchsize %u != %u\n", | ||
| 190 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | 190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { |
| 194 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | 191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); |
| 195 | return 0; | 192 | return 0; |
| 196 | } | 193 | } |
| 197 | |||
| 198 | return 1; | 194 | return 1; |
| 199 | } | 195 | } |
| 200 | 196 | ||
| @@ -204,8 +200,9 @@ static struct ip6t_match opts_match = { | |||
| 204 | #else | 200 | #else |
| 205 | .name = "dst", | 201 | .name = "dst", |
| 206 | #endif | 202 | #endif |
| 207 | .match = &match, | 203 | .match = match, |
| 208 | .checkentry = &checkentry, | 204 | .matchsize = sizeof(struct ip6t_opts), |
| 205 | .checkentry = checkentry, | ||
| 209 | .me = THIS_MODULE, | 206 | .me = THIS_MODULE, |
| 210 | }; | 207 | }; |
| 211 | 208 | ||
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c index c5d9079f2d9d..374055733b26 100644 --- a/net/ipv6/netfilter/ip6t_hl.c +++ b/net/ipv6/netfilter/ip6t_hl.c | |||
| @@ -18,10 +18,10 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |||
| 18 | MODULE_DESCRIPTION("IP tables Hop Limit matching module"); | 18 | MODULE_DESCRIPTION("IP tables Hop Limit matching module"); |
| 19 | MODULE_LICENSE("GPL"); | 19 | MODULE_LICENSE("GPL"); |
| 20 | 20 | ||
| 21 | static int match(const struct sk_buff *skb, const struct net_device *in, | 21 | static int match(const struct sk_buff *skb, |
| 22 | const struct net_device *out, const void *matchinfo, | 22 | const struct net_device *in, const struct net_device *out, |
| 23 | int offset, unsigned int protoff, | 23 | const struct xt_match *match, const void *matchinfo, |
| 24 | int *hotdrop) | 24 | int offset, unsigned int protoff, int *hotdrop) |
| 25 | { | 25 | { |
| 26 | const struct ip6t_hl_info *info = matchinfo; | 26 | const struct ip6t_hl_info *info = matchinfo; |
| 27 | const struct ipv6hdr *ip6h = skb->nh.ipv6h; | 27 | const struct ipv6hdr *ip6h = skb->nh.ipv6h; |
| @@ -48,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
| 48 | return 0; | 48 | return 0; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | static int checkentry(const char *tablename, const void *entry, | ||
| 52 | void *matchinfo, unsigned int matchsize, | ||
| 53 | unsigned int hook_mask) | ||
| 54 | { | ||
| 55 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info))) | ||
| 56 | return 0; | ||
| 57 | |||
| 58 | return 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | static struct ip6t_match hl_match = { | 51 | static struct ip6t_match hl_match = { |
| 62 | .name = "hl", | 52 | .name = "hl", |
| 63 | .match = &match, | 53 | .match = match, |
| 64 | .checkentry = &checkentry, | 54 | .matchsize = sizeof(struct ip6t_hl_info), |
| 65 | .me = THIS_MODULE, | 55 | .me = THIS_MODULE, |
| 66 | }; | 56 | }; |
| 67 | 57 | ||
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 83ad6b272f7e..9375eeb1369f 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
| @@ -29,6 +29,7 @@ static int | |||
| 29 | ipv6header_match(const struct sk_buff *skb, | 29 | ipv6header_match(const struct sk_buff *skb, |
| 30 | const struct net_device *in, | 30 | const struct net_device *in, |
| 31 | const struct net_device *out, | 31 | const struct net_device *out, |
| 32 | const struct xt_match *match, | ||
| 32 | const void *matchinfo, | 33 | const void *matchinfo, |
| 33 | int offset, | 34 | int offset, |
| 34 | unsigned int protoff, | 35 | unsigned int protoff, |
| @@ -125,17 +126,13 @@ ipv6header_match(const struct sk_buff *skb, | |||
| 125 | static int | 126 | static int |
| 126 | ipv6header_checkentry(const char *tablename, | 127 | ipv6header_checkentry(const char *tablename, |
| 127 | const void *ip, | 128 | const void *ip, |
| 129 | const struct xt_match *match, | ||
| 128 | void *matchinfo, | 130 | void *matchinfo, |
| 129 | unsigned int matchsize, | 131 | unsigned int matchsize, |
| 130 | unsigned int hook_mask) | 132 | unsigned int hook_mask) |
| 131 | { | 133 | { |
| 132 | const struct ip6t_ipv6header_info *info = matchinfo; | 134 | const struct ip6t_ipv6header_info *info = matchinfo; |
| 133 | 135 | ||
| 134 | /* Check for obvious errors */ | ||
| 135 | /* This match is valid in all hooks! */ | ||
| 136 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) | ||
| 137 | return 0; | ||
| 138 | |||
| 139 | /* invflags is 0 or 0xff in hard mode */ | 136 | /* invflags is 0 or 0xff in hard mode */ |
| 140 | if ((!info->modeflag) && info->invflags != 0x00 && | 137 | if ((!info->modeflag) && info->invflags != 0x00 && |
| 141 | info->invflags != 0xFF) | 138 | info->invflags != 0xFF) |
| @@ -147,6 +144,7 @@ ipv6header_checkentry(const char *tablename, | |||
| 147 | static struct ip6t_match ip6t_ipv6header_match = { | 144 | static struct ip6t_match ip6t_ipv6header_match = { |
| 148 | .name = "ipv6header", | 145 | .name = "ipv6header", |
| 149 | .match = &ipv6header_match, | 146 | .match = &ipv6header_match, |
| 147 | .matchsize = sizeof(struct ip6t_ipv6header_info), | ||
| 150 | .checkentry = &ipv6header_checkentry, | 148 | .checkentry = &ipv6header_checkentry, |
| 151 | .destroy = NULL, | 149 | .destroy = NULL, |
| 152 | .me = THIS_MODULE, | 150 | .me = THIS_MODULE, |
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c index 49f7829dfbc2..752b65d21c72 100644 --- a/net/ipv6/netfilter/ip6t_multiport.c +++ b/net/ipv6/netfilter/ip6t_multiport.c | |||
| @@ -51,6 +51,7 @@ static int | |||
| 51 | match(const struct sk_buff *skb, | 51 | match(const struct sk_buff *skb, |
| 52 | const struct net_device *in, | 52 | const struct net_device *in, |
| 53 | const struct net_device *out, | 53 | const struct net_device *out, |
| 54 | const struct xt_match *match, | ||
| 54 | const void *matchinfo, | 55 | const void *matchinfo, |
| 55 | int offset, | 56 | int offset, |
| 56 | unsigned int protoff, | 57 | unsigned int protoff, |
| @@ -85,6 +86,7 @@ match(const struct sk_buff *skb, | |||
| 85 | static int | 86 | static int |
| 86 | checkentry(const char *tablename, | 87 | checkentry(const char *tablename, |
| 87 | const void *info, | 88 | const void *info, |
| 89 | const struct xt_match *match, | ||
| 88 | void *matchinfo, | 90 | void *matchinfo, |
| 89 | unsigned int matchsize, | 91 | unsigned int matchsize, |
| 90 | unsigned int hook_mask) | 92 | unsigned int hook_mask) |
| @@ -92,13 +94,9 @@ checkentry(const char *tablename, | |||
| 92 | const struct ip6t_ip6 *ip = info; | 94 | const struct ip6t_ip6 *ip = info; |
| 93 | const struct ip6t_multiport *multiinfo = matchinfo; | 95 | const struct ip6t_multiport *multiinfo = matchinfo; |
| 94 | 96 | ||
| 95 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport))) | ||
| 96 | return 0; | ||
| 97 | |||
| 98 | /* Must specify proto == TCP/UDP, no unknown flags or bad count */ | 97 | /* Must specify proto == TCP/UDP, no unknown flags or bad count */ |
| 99 | return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) | 98 | return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) |
| 100 | && !(ip->invflags & IP6T_INV_PROTO) | 99 | && !(ip->invflags & IP6T_INV_PROTO) |
| 101 | && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport)) | ||
| 102 | && (multiinfo->flags == IP6T_MULTIPORT_SOURCE | 100 | && (multiinfo->flags == IP6T_MULTIPORT_SOURCE |
| 103 | || multiinfo->flags == IP6T_MULTIPORT_DESTINATION | 101 | || multiinfo->flags == IP6T_MULTIPORT_DESTINATION |
| 104 | || multiinfo->flags == IP6T_MULTIPORT_EITHER) | 102 | || multiinfo->flags == IP6T_MULTIPORT_EITHER) |
| @@ -107,8 +105,9 @@ checkentry(const char *tablename, | |||
| 107 | 105 | ||
| 108 | static struct ip6t_match multiport_match = { | 106 | static struct ip6t_match multiport_match = { |
| 109 | .name = "multiport", | 107 | .name = "multiport", |
| 110 | .match = &match, | 108 | .match = match, |
| 111 | .checkentry = &checkentry, | 109 | .matchsize = sizeof(struct ip6t_multiport), |
| 110 | .checkentry = checkentry, | ||
| 112 | .me = THIS_MODULE, | 111 | .me = THIS_MODULE, |
| 113 | }; | 112 | }; |
| 114 | 113 | ||
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 8c8a4c7ec934..e2cee3bcdef9 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c | |||
| @@ -26,6 +26,7 @@ static int | |||
| 26 | match(const struct sk_buff *skb, | 26 | match(const struct sk_buff *skb, |
| 27 | const struct net_device *in, | 27 | const struct net_device *in, |
| 28 | const struct net_device *out, | 28 | const struct net_device *out, |
| 29 | const struct xt_match *match, | ||
| 29 | const void *matchinfo, | 30 | const void *matchinfo, |
| 30 | int offset, | 31 | int offset, |
| 31 | unsigned int protoff, | 32 | unsigned int protoff, |
| @@ -54,34 +55,27 @@ match(const struct sk_buff *skb, | |||
| 54 | static int | 55 | static int |
| 55 | checkentry(const char *tablename, | 56 | checkentry(const char *tablename, |
| 56 | const void *ip, | 57 | const void *ip, |
| 58 | const struct xt_match *match, | ||
| 57 | void *matchinfo, | 59 | void *matchinfo, |
| 58 | unsigned int matchsize, | 60 | unsigned int matchsize, |
| 59 | unsigned int hook_mask) | 61 | unsigned int hook_mask) |
| 60 | { | 62 | { |
| 61 | const struct ip6t_owner_info *info = matchinfo; | 63 | const struct ip6t_owner_info *info = matchinfo; |
| 62 | 64 | ||
| 63 | if (hook_mask | ||
| 64 | & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) { | ||
| 65 | printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info))) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { | 65 | if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { |
| 73 | printk("ipt_owner: pid and sid matching " | 66 | printk("ipt_owner: pid and sid matching " |
| 74 | "not supported anymore\n"); | 67 | "not supported anymore\n"); |
| 75 | return 0; | 68 | return 0; |
| 76 | } | 69 | } |
| 77 | |||
| 78 | return 1; | 70 | return 1; |
| 79 | } | 71 | } |
| 80 | 72 | ||
| 81 | static struct ip6t_match owner_match = { | 73 | static struct ip6t_match owner_match = { |
| 82 | .name = "owner", | 74 | .name = "owner", |
| 83 | .match = &match, | 75 | .match = match, |
| 84 | .checkentry = &checkentry, | 76 | .matchsize = sizeof(struct ip6t_owner_info), |
| 77 | .hooks = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING), | ||
| 78 | .checkentry = checkentry, | ||
| 85 | .me = THIS_MODULE, | 79 | .me = THIS_MODULE, |
| 86 | }; | 80 | }; |
| 87 | 81 | ||
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c deleted file mode 100644 index 3d39ec924041..000000000000 --- a/net/ipv6/netfilter/ip6t_policy.c +++ /dev/null | |||
| @@ -1,176 +0,0 @@ | |||
| 1 | /* IP tables module for matching IPsec policy | ||
| 2 | * | ||
| 3 | * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/config.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/skbuff.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <net/xfrm.h> | ||
| 16 | |||
| 17 | #include <linux/netfilter_ipv6.h> | ||
| 18 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
| 19 | #include <linux/netfilter_ipv6/ip6t_policy.h> | ||
| 20 | |||
| 21 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
| 22 | MODULE_DESCRIPTION("IPtables IPsec policy matching module"); | ||
| 23 | MODULE_LICENSE("GPL"); | ||
| 24 | |||
| 25 | |||
| 26 | static inline int | ||
| 27 | match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e) | ||
| 28 | { | ||
| 29 | #define MATCH_ADDR(x,y,z) (!e->match.x || \ | ||
| 30 | ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \ | ||
| 31 | ^ e->invert.x)) | ||
| 32 | #define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) | ||
| 33 | |||
| 34 | return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) && | ||
| 35 | MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) && | ||
| 36 | MATCH(proto, x->id.proto) && | ||
| 37 | MATCH(mode, x->props.mode) && | ||
| 38 | MATCH(spi, x->id.spi) && | ||
| 39 | MATCH(reqid, x->props.reqid); | ||
| 40 | } | ||
| 41 | |||
| 42 | static int | ||
| 43 | match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info) | ||
| 44 | { | ||
| 45 | const struct ip6t_policy_elem *e; | ||
| 46 | struct sec_path *sp = skb->sp; | ||
| 47 | int strict = info->flags & IP6T_POLICY_MATCH_STRICT; | ||
| 48 | int i, pos; | ||
| 49 | |||
| 50 | if (sp == NULL) | ||
| 51 | return -1; | ||
| 52 | if (strict && info->len != sp->len) | ||
| 53 | return 0; | ||
| 54 | |||
| 55 | for (i = sp->len - 1; i >= 0; i--) { | ||
| 56 | pos = strict ? i - sp->len + 1 : 0; | ||
| 57 | if (pos >= info->len) | ||
| 58 | return 0; | ||
| 59 | e = &info->pol[pos]; | ||
| 60 | |||
| 61 | if (match_xfrm_state(sp->x[i].xvec, e)) { | ||
| 62 | if (!strict) | ||
| 63 | return 1; | ||
| 64 | } else if (strict) | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | return strict ? 1 : 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int | ||
| 72 | match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info) | ||
| 73 | { | ||
| 74 | const struct ip6t_policy_elem *e; | ||
| 75 | struct dst_entry *dst = skb->dst; | ||
| 76 | int strict = info->flags & IP6T_POLICY_MATCH_STRICT; | ||
| 77 | int i, pos; | ||
| 78 | |||
| 79 | if (dst->xfrm == NULL) | ||
| 80 | return -1; | ||
| 81 | |||
| 82 | for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { | ||
| 83 | pos = strict ? i : 0; | ||
| 84 | if (pos >= info->len) | ||
| 85 | return 0; | ||
| 86 | e = &info->pol[pos]; | ||
| 87 | |||
| 88 | if (match_xfrm_state(dst->xfrm, e)) { | ||
| 89 | if (!strict) | ||
| 90 | return 1; | ||
| 91 | } else if (strict) | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | return strict ? i == info->len : 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int match(const struct sk_buff *skb, | ||
| 99 | const struct net_device *in, | ||
| 100 | const struct net_device *out, | ||
| 101 | const void *matchinfo, | ||
| 102 | int offset, | ||
| 103 | unsigned int protoff, | ||
| 104 | int *hotdrop) | ||
| 105 | { | ||
| 106 | const struct ip6t_policy_info *info = matchinfo; | ||
| 107 | int ret; | ||
| 108 | |||
| 109 | if (info->flags & IP6T_POLICY_MATCH_IN) | ||
| 110 | ret = match_policy_in(skb, info); | ||
| 111 | else | ||
| 112 | ret = match_policy_out(skb, info); | ||
| 113 | |||
| 114 | if (ret < 0) | ||
| 115 | ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0; | ||
| 116 | else if (info->flags & IP6T_POLICY_MATCH_NONE) | ||
| 117 | ret = 0; | ||
| 118 | |||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int checkentry(const char *tablename, const void *ip_void, | ||
| 123 | void *matchinfo, unsigned int matchsize, | ||
| 124 | unsigned int hook_mask) | ||
| 125 | { | ||
| 126 | struct ip6t_policy_info *info = matchinfo; | ||
| 127 | |||
| 128 | if (matchsize != IP6T_ALIGN(sizeof(*info))) { | ||
| 129 | printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n", | ||
| 130 | matchsize, IP6T_ALIGN(sizeof(*info))); | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) { | ||
| 134 | printk(KERN_ERR "ip6t_policy: neither incoming nor " | ||
| 135 | "outgoing policy selected\n"); | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN) | ||
| 139 | && info->flags & IP6T_POLICY_MATCH_OUT) { | ||
| 140 | printk(KERN_ERR "ip6t_policy: output policy not valid in " | ||
| 141 | "PRE_ROUTING and INPUT\n"); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT) | ||
| 145 | && info->flags & IP6T_POLICY_MATCH_IN) { | ||
| 146 | printk(KERN_ERR "ip6t_policy: input policy not valid in " | ||
| 147 | "POST_ROUTING and OUTPUT\n"); | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | if (info->len > IP6T_POLICY_MAX_ELEM) { | ||
| 151 | printk(KERN_ERR "ip6t_policy: too many policy elements\n"); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | return 1; | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct ip6t_match policy_match = { | ||
| 159 | .name = "policy", | ||
| 160 | .match = match, | ||
| 161 | .checkentry = checkentry, | ||
| 162 | .me = THIS_MODULE, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static int __init init(void) | ||
| 166 | { | ||
| 167 | return ip6t_register_match(&policy_match); | ||
| 168 | } | ||
| 169 | |||
| 170 | static void __exit fini(void) | ||
| 171 | { | ||
| 172 | ip6t_unregister_match(&policy_match); | ||
| 173 | } | ||
| 174 | |||
| 175 | module_init(init); | ||
| 176 | module_exit(fini); | ||
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 8f82476dc89e..4c6b55bb225b 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
| @@ -45,6 +45,7 @@ static int | |||
| 45 | match(const struct sk_buff *skb, | 45 | match(const struct sk_buff *skb, |
| 46 | const struct net_device *in, | 46 | const struct net_device *in, |
| 47 | const struct net_device *out, | 47 | const struct net_device *out, |
| 48 | const struct xt_match *match, | ||
| 48 | const void *matchinfo, | 49 | const void *matchinfo, |
| 49 | int offset, | 50 | int offset, |
| 50 | unsigned int protoff, | 51 | unsigned int protoff, |
| @@ -194,17 +195,13 @@ match(const struct sk_buff *skb, | |||
| 194 | static int | 195 | static int |
| 195 | checkentry(const char *tablename, | 196 | checkentry(const char *tablename, |
| 196 | const void *entry, | 197 | const void *entry, |
| 198 | const struct xt_match *match, | ||
| 197 | void *matchinfo, | 199 | void *matchinfo, |
| 198 | unsigned int matchinfosize, | 200 | unsigned int matchinfosize, |
| 199 | unsigned int hook_mask) | 201 | unsigned int hook_mask) |
| 200 | { | 202 | { |
| 201 | const struct ip6t_rt *rtinfo = matchinfo; | 203 | const struct ip6t_rt *rtinfo = matchinfo; |
| 202 | 204 | ||
| 203 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) { | ||
| 204 | DEBUGP("ip6t_rt: matchsize %u != %u\n", | ||
| 205 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt))); | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { | 205 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { |
| 209 | DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); | 206 | DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); |
| 210 | return 0; | 207 | return 0; |
| @@ -222,8 +219,9 @@ checkentry(const char *tablename, | |||
| 222 | 219 | ||
| 223 | static struct ip6t_match rt_match = { | 220 | static struct ip6t_match rt_match = { |
| 224 | .name = "rt", | 221 | .name = "rt", |
| 225 | .match = &match, | 222 | .match = match, |
| 226 | .checkentry = &checkentry, | 223 | .matchsize = sizeof(struct ip6t_rt), |
| 224 | .checkentry = checkentry, | ||
| 227 | .me = THIS_MODULE, | 225 | .me = THIS_MODULE, |
| 228 | }; | 226 | }; |
| 229 | 227 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ac702a29dd16..c16f62934bd9 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
| @@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
| 179 | int (*okfn)(struct sk_buff *)) | 179 | int (*okfn)(struct sk_buff *)) |
| 180 | { | 180 | { |
| 181 | struct nf_conn *ct; | 181 | struct nf_conn *ct; |
| 182 | struct nf_conn_help *help; | ||
| 182 | enum ip_conntrack_info ctinfo; | 183 | enum ip_conntrack_info ctinfo; |
| 184 | unsigned int ret, protoff; | ||
| 185 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
| 186 | - (*pskb)->data; | ||
| 187 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
| 188 | |||
| 183 | 189 | ||
| 184 | /* This is where we call the helper: as the packet goes out. */ | 190 | /* This is where we call the helper: as the packet goes out. */ |
| 185 | ct = nf_ct_get(*pskb, &ctinfo); | 191 | ct = nf_ct_get(*pskb, &ctinfo); |
| 186 | if (ct && ct->helper) { | 192 | if (!ct) |
| 187 | unsigned int ret, protoff; | 193 | goto out; |
| 188 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
| 189 | - (*pskb)->data; | ||
| 190 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
| 191 | |||
| 192 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
| 193 | (*pskb)->len - extoff); | ||
| 194 | if (protoff < 0 || protoff > (*pskb)->len || | ||
| 195 | pnum == NEXTHDR_FRAGMENT) { | ||
| 196 | DEBUGP("proto header not found\n"); | ||
| 197 | return NF_ACCEPT; | ||
| 198 | } | ||
| 199 | 194 | ||
| 200 | ret = ct->helper->help(pskb, protoff, ct, ctinfo); | 195 | help = nfct_help(ct); |
| 201 | if (ret != NF_ACCEPT) | 196 | if (!help || !help->helper) |
| 202 | return ret; | 197 | goto out; |
| 198 | |||
| 199 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
| 200 | (*pskb)->len - extoff); | ||
| 201 | if (protoff < 0 || protoff > (*pskb)->len || | ||
| 202 | pnum == NEXTHDR_FRAGMENT) { | ||
| 203 | DEBUGP("proto header not found\n"); | ||
| 204 | return NF_ACCEPT; | ||
| 203 | } | 205 | } |
| 204 | 206 | ||
| 207 | ret = help->helper->help(pskb, protoff, ct, ctinfo); | ||
| 208 | if (ret != NF_ACCEPT) | ||
| 209 | return ret; | ||
| 210 | out: | ||
| 205 | /* We've seen it coming out the other side: confirm it */ | 211 | /* We've seen it coming out the other side: confirm it */ |
| 206 | |||
| 207 | return nf_conntrack_confirm(pskb); | 212 | return nf_conntrack_confirm(pskb); |
| 208 | } | 213 | } |
| 209 | 214 | ||
| @@ -579,6 +584,7 @@ static int init_or_cleanup(int init) | |||
| 579 | return ret; | 584 | return ret; |
| 580 | } | 585 | } |
| 581 | 586 | ||
| 587 | MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); | ||
| 582 | MODULE_LICENSE("GPL"); | 588 | MODULE_LICENSE("GPL"); |
| 583 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); | 589 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); |
| 584 | 590 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 84ef9a13108d..3e319035f82d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -313,8 +313,8 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, | |||
| 313 | #ifdef CONFIG_SMP | 313 | #ifdef CONFIG_SMP |
| 314 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { | 314 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { |
| 315 | if (fq->id == fq_in->id && | 315 | if (fq->id == fq_in->id && |
| 316 | !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) && | 316 | ipv6_addr_equal(&fq_in->saddr, &fq->saddr) && |
| 317 | !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) { | 317 | ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) { |
| 318 | atomic_inc(&fq->refcnt); | 318 | atomic_inc(&fq->refcnt); |
| 319 | write_unlock(&nf_ct_frag6_lock); | 319 | write_unlock(&nf_ct_frag6_lock); |
| 320 | fq_in->last_in |= COMPLETE; | 320 | fq_in->last_in |= COMPLETE; |
| @@ -376,8 +376,8 @@ fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) | |||
| 376 | read_lock(&nf_ct_frag6_lock); | 376 | read_lock(&nf_ct_frag6_lock); |
| 377 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { | 377 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { |
| 378 | if (fq->id == id && | 378 | if (fq->id == id && |
| 379 | !ipv6_addr_cmp(src, &fq->saddr) && | 379 | ipv6_addr_equal(src, &fq->saddr) && |
| 380 | !ipv6_addr_cmp(dst, &fq->daddr)) { | 380 | ipv6_addr_equal(dst, &fq->daddr)) { |
| 381 | atomic_inc(&fq->refcnt); | 381 | atomic_inc(&fq->refcnt); |
| 382 | read_unlock(&nf_ct_frag6_lock); | 382 | read_unlock(&nf_ct_frag6_lock); |
| 383 | return fq; | 383 | return fq; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ae20a0ec9bd8..fa1ce0ae123e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -859,29 +859,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, | |||
| 859 | } | 859 | } |
| 860 | 860 | ||
| 861 | 861 | ||
| 862 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, | 862 | static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, |
| 863 | char __user *optval, int optlen) | 863 | char __user *optval, int optlen) |
| 864 | { | 864 | { |
| 865 | struct raw6_sock *rp = raw6_sk(sk); | 865 | struct raw6_sock *rp = raw6_sk(sk); |
| 866 | int val; | 866 | int val; |
| 867 | 867 | ||
| 868 | switch(level) { | ||
| 869 | case SOL_RAW: | ||
| 870 | break; | ||
| 871 | |||
| 872 | case SOL_ICMPV6: | ||
| 873 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
| 874 | return -EOPNOTSUPP; | ||
| 875 | return rawv6_seticmpfilter(sk, level, optname, optval, | ||
| 876 | optlen); | ||
| 877 | case SOL_IPV6: | ||
| 878 | if (optname == IPV6_CHECKSUM) | ||
| 879 | break; | ||
| 880 | default: | ||
| 881 | return ipv6_setsockopt(sk, level, optname, optval, | ||
| 882 | optlen); | ||
| 883 | }; | ||
| 884 | |||
| 885 | if (get_user(val, (int __user *)optval)) | 868 | if (get_user(val, (int __user *)optval)) |
| 886 | return -EFAULT; | 869 | return -EFAULT; |
| 887 | 870 | ||
| @@ -906,12 +889,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 906 | } | 889 | } |
| 907 | } | 890 | } |
| 908 | 891 | ||
| 909 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | 892 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, |
| 910 | char __user *optval, int __user *optlen) | 893 | char __user *optval, int optlen) |
| 911 | { | 894 | { |
| 912 | struct raw6_sock *rp = raw6_sk(sk); | ||
| 913 | int val, len; | ||
| 914 | |||
| 915 | switch(level) { | 895 | switch(level) { |
| 916 | case SOL_RAW: | 896 | case SOL_RAW: |
| 917 | break; | 897 | break; |
| @@ -919,15 +899,45 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 919 | case SOL_ICMPV6: | 899 | case SOL_ICMPV6: |
| 920 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 900 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) |
| 921 | return -EOPNOTSUPP; | 901 | return -EOPNOTSUPP; |
| 922 | return rawv6_geticmpfilter(sk, level, optname, optval, | 902 | return rawv6_seticmpfilter(sk, level, optname, optval, |
| 923 | optlen); | 903 | optlen); |
| 924 | case SOL_IPV6: | 904 | case SOL_IPV6: |
| 925 | if (optname == IPV6_CHECKSUM) | 905 | if (optname == IPV6_CHECKSUM) |
| 926 | break; | 906 | break; |
| 927 | default: | 907 | default: |
| 928 | return ipv6_getsockopt(sk, level, optname, optval, | 908 | return ipv6_setsockopt(sk, level, optname, optval, |
| 929 | optlen); | 909 | optlen); |
| 930 | }; | 910 | }; |
| 911 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 912 | } | ||
| 913 | |||
| 914 | #ifdef CONFIG_COMPAT | ||
| 915 | static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, | ||
| 916 | char __user *optval, int optlen) | ||
| 917 | { | ||
| 918 | switch (level) { | ||
| 919 | case SOL_RAW: | ||
| 920 | break; | ||
| 921 | case SOL_ICMPV6: | ||
| 922 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
| 923 | return -EOPNOTSUPP; | ||
| 924 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); | ||
| 925 | case SOL_IPV6: | ||
| 926 | if (optname == IPV6_CHECKSUM) | ||
| 927 | break; | ||
| 928 | default: | ||
| 929 | return compat_ipv6_setsockopt(sk, level, optname, | ||
| 930 | optval, optlen); | ||
| 931 | }; | ||
| 932 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 933 | } | ||
| 934 | #endif | ||
| 935 | |||
| 936 | static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 937 | char __user *optval, int __user *optlen) | ||
| 938 | { | ||
| 939 | struct raw6_sock *rp = raw6_sk(sk); | ||
| 940 | int val, len; | ||
| 931 | 941 | ||
| 932 | if (get_user(len,optlen)) | 942 | if (get_user(len,optlen)) |
| 933 | return -EFAULT; | 943 | return -EFAULT; |
| @@ -953,6 +963,50 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 953 | return 0; | 963 | return 0; |
| 954 | } | 964 | } |
| 955 | 965 | ||
| 966 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 967 | char __user *optval, int __user *optlen) | ||
| 968 | { | ||
| 969 | switch(level) { | ||
| 970 | case SOL_RAW: | ||
| 971 | break; | ||
| 972 | |||
| 973 | case SOL_ICMPV6: | ||
| 974 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
| 975 | return -EOPNOTSUPP; | ||
| 976 | return rawv6_geticmpfilter(sk, level, optname, optval, | ||
| 977 | optlen); | ||
| 978 | case SOL_IPV6: | ||
| 979 | if (optname == IPV6_CHECKSUM) | ||
| 980 | break; | ||
| 981 | default: | ||
| 982 | return ipv6_getsockopt(sk, level, optname, optval, | ||
| 983 | optlen); | ||
| 984 | }; | ||
| 985 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 986 | } | ||
| 987 | |||
| 988 | #ifdef CONFIG_COMPAT | ||
| 989 | static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 990 | char __user *optval, int __user *optlen) | ||
| 991 | { | ||
| 992 | switch (level) { | ||
| 993 | case SOL_RAW: | ||
| 994 | break; | ||
| 995 | case SOL_ICMPV6: | ||
| 996 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
| 997 | return -EOPNOTSUPP; | ||
| 998 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); | ||
| 999 | case SOL_IPV6: | ||
| 1000 | if (optname == IPV6_CHECKSUM) | ||
| 1001 | break; | ||
| 1002 | default: | ||
| 1003 | return compat_ipv6_getsockopt(sk, level, optname, | ||
| 1004 | optval, optlen); | ||
| 1005 | }; | ||
| 1006 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 1007 | } | ||
| 1008 | #endif | ||
| 1009 | |||
| 956 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | 1010 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) |
| 957 | { | 1011 | { |
| 958 | switch(cmd) { | 1012 | switch(cmd) { |
| @@ -998,23 +1052,27 @@ static int rawv6_init_sk(struct sock *sk) | |||
| 998 | } | 1052 | } |
| 999 | 1053 | ||
| 1000 | struct proto rawv6_prot = { | 1054 | struct proto rawv6_prot = { |
| 1001 | .name = "RAWv6", | 1055 | .name = "RAWv6", |
| 1002 | .owner = THIS_MODULE, | 1056 | .owner = THIS_MODULE, |
| 1003 | .close = rawv6_close, | 1057 | .close = rawv6_close, |
| 1004 | .connect = ip6_datagram_connect, | 1058 | .connect = ip6_datagram_connect, |
| 1005 | .disconnect = udp_disconnect, | 1059 | .disconnect = udp_disconnect, |
| 1006 | .ioctl = rawv6_ioctl, | 1060 | .ioctl = rawv6_ioctl, |
| 1007 | .init = rawv6_init_sk, | 1061 | .init = rawv6_init_sk, |
| 1008 | .destroy = inet6_destroy_sock, | 1062 | .destroy = inet6_destroy_sock, |
| 1009 | .setsockopt = rawv6_setsockopt, | 1063 | .setsockopt = rawv6_setsockopt, |
| 1010 | .getsockopt = rawv6_getsockopt, | 1064 | .getsockopt = rawv6_getsockopt, |
| 1011 | .sendmsg = rawv6_sendmsg, | 1065 | .sendmsg = rawv6_sendmsg, |
| 1012 | .recvmsg = rawv6_recvmsg, | 1066 | .recvmsg = rawv6_recvmsg, |
| 1013 | .bind = rawv6_bind, | 1067 | .bind = rawv6_bind, |
| 1014 | .backlog_rcv = rawv6_rcv_skb, | 1068 | .backlog_rcv = rawv6_rcv_skb, |
| 1015 | .hash = raw_v6_hash, | 1069 | .hash = raw_v6_hash, |
| 1016 | .unhash = raw_v6_unhash, | 1070 | .unhash = raw_v6_unhash, |
| 1017 | .obj_size = sizeof(struct raw6_sock), | 1071 | .obj_size = sizeof(struct raw6_sock), |
| 1072 | #ifdef CONFIG_COMPAT | ||
| 1073 | .compat_setsockopt = compat_rawv6_setsockopt, | ||
| 1074 | .compat_getsockopt = compat_rawv6_getsockopt, | ||
| 1075 | #endif | ||
| 1018 | }; | 1076 | }; |
| 1019 | 1077 | ||
| 1020 | #ifdef CONFIG_PROC_FS | 1078 | #ifdef CONFIG_PROC_FS |
| @@ -1140,7 +1198,7 @@ static int raw6_seq_open(struct inode *inode, struct file *file) | |||
| 1140 | { | 1198 | { |
| 1141 | struct seq_file *seq; | 1199 | struct seq_file *seq; |
| 1142 | int rc = -ENOMEM; | 1200 | int rc = -ENOMEM; |
| 1143 | struct raw6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 1201 | struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 1144 | if (!s) | 1202 | if (!s) |
| 1145 | goto out; | 1203 | goto out; |
| 1146 | rc = seq_open(file, &raw6_seq_ops); | 1204 | rc = seq_open(file, &raw6_seq_ops); |
| @@ -1148,7 +1206,6 @@ static int raw6_seq_open(struct inode *inode, struct file *file) | |||
| 1148 | goto out_kfree; | 1206 | goto out_kfree; |
| 1149 | seq = file->private_data; | 1207 | seq = file->private_data; |
| 1150 | seq->private = s; | 1208 | seq->private = s; |
| 1151 | memset(s, 0, sizeof(*s)); | ||
| 1152 | out: | 1209 | out: |
| 1153 | return rc; | 1210 | return rc; |
| 1154 | out_kfree: | 1211 | out_kfree: |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 15e1456b3f18..b67a45fb93e9 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
| @@ -203,7 +203,7 @@ static inline void frag_free_queue(struct frag_queue *fq, int *work) | |||
| 203 | 203 | ||
| 204 | static inline struct frag_queue *frag_alloc_queue(void) | 204 | static inline struct frag_queue *frag_alloc_queue(void) |
| 205 | { | 205 | { |
| 206 | struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC); | 206 | struct frag_queue *fq = kzalloc(sizeof(struct frag_queue), GFP_ATOMIC); |
| 207 | 207 | ||
| 208 | if(!fq) | 208 | if(!fq) |
| 209 | return NULL; | 209 | return NULL; |
| @@ -288,6 +288,7 @@ static void ip6_evictor(void) | |||
| 288 | static void ip6_frag_expire(unsigned long data) | 288 | static void ip6_frag_expire(unsigned long data) |
| 289 | { | 289 | { |
| 290 | struct frag_queue *fq = (struct frag_queue *) data; | 290 | struct frag_queue *fq = (struct frag_queue *) data; |
| 291 | struct net_device *dev; | ||
| 291 | 292 | ||
| 292 | spin_lock(&fq->lock); | 293 | spin_lock(&fq->lock); |
| 293 | 294 | ||
| @@ -299,22 +300,22 @@ static void ip6_frag_expire(unsigned long data) | |||
| 299 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); | 300 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); |
| 300 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 301 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); |
| 301 | 302 | ||
| 302 | /* Send error only if the first segment arrived. */ | 303 | /* Don't send error if the first segment did not arrive. */ |
| 303 | if (fq->last_in&FIRST_IN && fq->fragments) { | 304 | if (!(fq->last_in&FIRST_IN) || !fq->fragments) |
| 304 | struct net_device *dev = dev_get_by_index(fq->iif); | 305 | goto out; |
| 305 | 306 | ||
| 306 | /* | 307 | dev = dev_get_by_index(fq->iif); |
| 307 | But use as source device on which LAST ARRIVED | 308 | if (!dev) |
| 308 | segment was received. And do not use fq->dev | 309 | goto out; |
| 309 | pointer directly, device might already disappeared. | 310 | |
| 310 | */ | 311 | /* |
| 311 | if (dev) { | 312 | But use as source device on which LAST ARRIVED |
| 312 | fq->fragments->dev = dev; | 313 | segment was received. And do not use fq->dev |
| 313 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, | 314 | pointer directly, device might already disappeared. |
| 314 | dev); | 315 | */ |
| 315 | dev_put(dev); | 316 | fq->fragments->dev = dev; |
| 316 | } | 317 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); |
| 317 | } | 318 | dev_put(dev); |
| 318 | out: | 319 | out: |
| 319 | spin_unlock(&fq->lock); | 320 | spin_unlock(&fq->lock); |
| 320 | fq_put(fq, NULL); | 321 | fq_put(fq, NULL); |
| @@ -368,8 +369,6 @@ ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr | |||
| 368 | if ((fq = frag_alloc_queue()) == NULL) | 369 | if ((fq = frag_alloc_queue()) == NULL) |
| 369 | goto oom; | 370 | goto oom; |
| 370 | 371 | ||
| 371 | memset(fq, 0, sizeof(struct frag_queue)); | ||
| 372 | |||
| 373 | fq->id = id; | 372 | fq->id = id; |
| 374 | ipv6_addr_copy(&fq->saddr, src); | 373 | ipv6_addr_copy(&fq->saddr, src); |
| 375 | ipv6_addr_copy(&fq->daddr, dst); | 374 | ipv6_addr_copy(&fq->daddr, dst); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e0d3ad02ffb5..79078747a646 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -72,6 +72,10 @@ | |||
| 72 | #define RT6_TRACE(x...) do { ; } while (0) | 72 | #define RT6_TRACE(x...) do { ; } while (0) |
| 73 | #endif | 73 | #endif |
| 74 | 74 | ||
| 75 | #define CLONE_OFFLINK_ROUTE 0 | ||
| 76 | |||
| 77 | #define RT6_SELECT_F_IFACE 0x1 | ||
| 78 | #define RT6_SELECT_F_REACHABLE 0x2 | ||
| 75 | 79 | ||
| 76 | static int ip6_rt_max_size = 4096; | 80 | static int ip6_rt_max_size = 4096; |
| 77 | static int ip6_rt_gc_min_interval = HZ / 2; | 81 | static int ip6_rt_gc_min_interval = HZ / 2; |
| @@ -94,6 +98,14 @@ static int ip6_pkt_discard_out(struct sk_buff *skb); | |||
| 94 | static void ip6_link_failure(struct sk_buff *skb); | 98 | static void ip6_link_failure(struct sk_buff *skb); |
| 95 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | 99 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); |
| 96 | 100 | ||
| 101 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 102 | static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, | ||
| 103 | struct in6_addr *gwaddr, int ifindex, | ||
| 104 | unsigned pref); | ||
| 105 | static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, | ||
| 106 | struct in6_addr *gwaddr, int ifindex); | ||
| 107 | #endif | ||
| 108 | |||
| 97 | static struct dst_ops ip6_dst_ops = { | 109 | static struct dst_ops ip6_dst_ops = { |
| 98 | .family = AF_INET6, | 110 | .family = AF_INET6, |
| 99 | .protocol = __constant_htons(ETH_P_IPV6), | 111 | .protocol = __constant_htons(ETH_P_IPV6), |
| @@ -214,150 +226,211 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, | |||
| 214 | return rt; | 226 | return rt; |
| 215 | } | 227 | } |
| 216 | 228 | ||
| 229 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
| 230 | static void rt6_probe(struct rt6_info *rt) | ||
| 231 | { | ||
| 232 | struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL; | ||
| 233 | /* | ||
| 234 | * Okay, this does not seem to be appropriate | ||
| 235 | * for now, however, we need to check if it | ||
| 236 | * is really so; aka Router Reachability Probing. | ||
| 237 | * | ||
| 238 | * Router Reachability Probe MUST be rate-limited | ||
| 239 | * to no more than one per minute. | ||
| 240 | */ | ||
| 241 | if (!neigh || (neigh->nud_state & NUD_VALID)) | ||
| 242 | return; | ||
| 243 | read_lock_bh(&neigh->lock); | ||
| 244 | if (!(neigh->nud_state & NUD_VALID) && | ||
| 245 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | ||
| 246 | struct in6_addr mcaddr; | ||
| 247 | struct in6_addr *target; | ||
| 248 | |||
| 249 | neigh->updated = jiffies; | ||
| 250 | read_unlock_bh(&neigh->lock); | ||
| 251 | |||
| 252 | target = (struct in6_addr *)&neigh->primary_key; | ||
| 253 | addrconf_addr_solict_mult(target, &mcaddr); | ||
| 254 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); | ||
| 255 | } else | ||
| 256 | read_unlock_bh(&neigh->lock); | ||
| 257 | } | ||
| 258 | #else | ||
| 259 | static inline void rt6_probe(struct rt6_info *rt) | ||
| 260 | { | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | #endif | ||
| 264 | |||
| 217 | /* | 265 | /* |
| 218 | * pointer to the last default router chosen. BH is disabled locally. | 266 | * Default Router Selection (RFC 2461 6.3.6) |
| 219 | */ | 267 | */ |
| 220 | static struct rt6_info *rt6_dflt_pointer; | 268 | static int inline rt6_check_dev(struct rt6_info *rt, int oif) |
| 221 | static DEFINE_SPINLOCK(rt6_dflt_lock); | 269 | { |
| 270 | struct net_device *dev = rt->rt6i_dev; | ||
| 271 | if (!oif || dev->ifindex == oif) | ||
| 272 | return 2; | ||
| 273 | if ((dev->flags & IFF_LOOPBACK) && | ||
| 274 | rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) | ||
| 275 | return 1; | ||
| 276 | return 0; | ||
| 277 | } | ||
| 222 | 278 | ||
| 223 | void rt6_reset_dflt_pointer(struct rt6_info *rt) | 279 | static int inline rt6_check_neigh(struct rt6_info *rt) |
| 224 | { | 280 | { |
| 225 | spin_lock_bh(&rt6_dflt_lock); | 281 | struct neighbour *neigh = rt->rt6i_nexthop; |
| 226 | if (rt == NULL || rt == rt6_dflt_pointer) { | 282 | int m = 0; |
| 227 | RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer); | 283 | if (neigh) { |
| 228 | rt6_dflt_pointer = NULL; | 284 | read_lock_bh(&neigh->lock); |
| 285 | if (neigh->nud_state & NUD_VALID) | ||
| 286 | m = 1; | ||
| 287 | read_unlock_bh(&neigh->lock); | ||
| 229 | } | 288 | } |
| 230 | spin_unlock_bh(&rt6_dflt_lock); | 289 | return m; |
| 231 | } | 290 | } |
| 232 | 291 | ||
| 233 | /* Default Router Selection (RFC 2461 6.3.6) */ | 292 | static int rt6_score_route(struct rt6_info *rt, int oif, |
| 234 | static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) | 293 | int strict) |
| 235 | { | 294 | { |
| 236 | struct rt6_info *match = NULL; | 295 | int m = rt6_check_dev(rt, oif); |
| 237 | struct rt6_info *sprt; | 296 | if (!m && (strict & RT6_SELECT_F_IFACE)) |
| 238 | int mpri = 0; | 297 | return -1; |
| 239 | 298 | #ifdef CONFIG_IPV6_ROUTER_PREF | |
| 240 | for (sprt = rt; sprt; sprt = sprt->u.next) { | 299 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; |
| 241 | struct neighbour *neigh; | 300 | #endif |
| 242 | int m = 0; | 301 | if (rt6_check_neigh(rt)) |
| 243 | 302 | m |= 16; | |
| 244 | if (!oif || | 303 | else if (strict & RT6_SELECT_F_REACHABLE) |
| 245 | (sprt->rt6i_dev && | 304 | return -1; |
| 246 | sprt->rt6i_dev->ifindex == oif)) | 305 | return m; |
| 247 | m += 8; | 306 | } |
| 248 | 307 | ||
| 249 | if (rt6_check_expired(sprt)) | 308 | static struct rt6_info *rt6_select(struct rt6_info **head, int oif, |
| 250 | continue; | 309 | int strict) |
| 310 | { | ||
| 311 | struct rt6_info *match = NULL, *last = NULL; | ||
| 312 | struct rt6_info *rt, *rt0 = *head; | ||
| 313 | u32 metric; | ||
| 314 | int mpri = -1; | ||
| 251 | 315 | ||
| 252 | if (sprt == rt6_dflt_pointer) | 316 | RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", |
| 253 | m += 4; | 317 | __FUNCTION__, head, head ? *head : NULL, oif); |
| 254 | 318 | ||
| 255 | if ((neigh = sprt->rt6i_nexthop) != NULL) { | 319 | for (rt = rt0, metric = rt0->rt6i_metric; |
| 256 | read_lock_bh(&neigh->lock); | 320 | rt && rt->rt6i_metric == metric; |
| 257 | switch (neigh->nud_state) { | 321 | rt = rt->u.next) { |
| 258 | case NUD_REACHABLE: | 322 | int m; |
| 259 | m += 3; | ||
| 260 | break; | ||
| 261 | 323 | ||
| 262 | case NUD_STALE: | 324 | if (rt6_check_expired(rt)) |
| 263 | case NUD_DELAY: | 325 | continue; |
| 264 | case NUD_PROBE: | ||
| 265 | m += 2; | ||
| 266 | break; | ||
| 267 | 326 | ||
| 268 | case NUD_NOARP: | 327 | last = rt; |
| 269 | case NUD_PERMANENT: | ||
| 270 | m += 1; | ||
| 271 | break; | ||
| 272 | 328 | ||
| 273 | case NUD_INCOMPLETE: | 329 | m = rt6_score_route(rt, oif, strict); |
| 274 | default: | 330 | if (m < 0) |
| 275 | read_unlock_bh(&neigh->lock); | ||
| 276 | continue; | ||
| 277 | } | ||
| 278 | read_unlock_bh(&neigh->lock); | ||
| 279 | } else { | ||
| 280 | continue; | 331 | continue; |
| 281 | } | ||
| 282 | 332 | ||
| 283 | if (m > mpri || m >= 12) { | 333 | if (m > mpri) { |
| 284 | match = sprt; | 334 | rt6_probe(match); |
| 335 | match = rt; | ||
| 285 | mpri = m; | 336 | mpri = m; |
| 286 | if (m >= 12) { | 337 | } else { |
| 287 | /* we choose the last default router if it | 338 | rt6_probe(rt); |
| 288 | * is in (probably) reachable state. | ||
| 289 | * If route changed, we should do pmtu | ||
| 290 | * discovery. --yoshfuji | ||
| 291 | */ | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | } | 339 | } |
| 295 | } | 340 | } |
| 296 | 341 | ||
| 297 | spin_lock(&rt6_dflt_lock); | 342 | if (!match && |
| 298 | if (!match) { | 343 | (strict & RT6_SELECT_F_REACHABLE) && |
| 299 | /* | 344 | last && last != rt0) { |
| 300 | * No default routers are known to be reachable. | 345 | /* no entries matched; do round-robin */ |
| 301 | * SHOULD round robin | 346 | *head = rt0->u.next; |
| 302 | */ | 347 | rt0->u.next = last->u.next; |
| 303 | if (rt6_dflt_pointer) { | 348 | last->u.next = rt0; |
| 304 | for (sprt = rt6_dflt_pointer->u.next; | ||
| 305 | sprt; sprt = sprt->u.next) { | ||
| 306 | if (sprt->u.dst.obsolete <= 0 && | ||
| 307 | sprt->u.dst.error == 0 && | ||
| 308 | !rt6_check_expired(sprt)) { | ||
| 309 | match = sprt; | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | for (sprt = rt; | ||
| 314 | !match && sprt; | ||
| 315 | sprt = sprt->u.next) { | ||
| 316 | if (sprt->u.dst.obsolete <= 0 && | ||
| 317 | sprt->u.dst.error == 0 && | ||
| 318 | !rt6_check_expired(sprt)) { | ||
| 319 | match = sprt; | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | if (sprt == rt6_dflt_pointer) | ||
| 323 | break; | ||
| 324 | } | ||
| 325 | } | ||
| 326 | } | 349 | } |
| 327 | 350 | ||
| 328 | if (match) { | 351 | RT6_TRACE("%s() => %p, score=%d\n", |
| 329 | if (rt6_dflt_pointer != match) | 352 | __FUNCTION__, match, mpri); |
| 330 | RT6_TRACE("changed default router: %p->%p\n", | 353 | |
| 331 | rt6_dflt_pointer, match); | 354 | return (match ? match : &ip6_null_entry); |
| 332 | rt6_dflt_pointer = match; | 355 | } |
| 356 | |||
| 357 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 358 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | ||
| 359 | struct in6_addr *gwaddr) | ||
| 360 | { | ||
| 361 | struct route_info *rinfo = (struct route_info *) opt; | ||
| 362 | struct in6_addr prefix_buf, *prefix; | ||
| 363 | unsigned int pref; | ||
| 364 | u32 lifetime; | ||
| 365 | struct rt6_info *rt; | ||
| 366 | |||
| 367 | if (len < sizeof(struct route_info)) { | ||
| 368 | return -EINVAL; | ||
| 333 | } | 369 | } |
| 334 | spin_unlock(&rt6_dflt_lock); | ||
| 335 | 370 | ||
| 336 | if (!match) { | 371 | /* Sanity check for prefix_len and length */ |
| 337 | /* | 372 | if (rinfo->length > 3) { |
| 338 | * Last Resort: if no default routers found, | 373 | return -EINVAL; |
| 339 | * use addrconf default route. | 374 | } else if (rinfo->prefix_len > 128) { |
| 340 | * We don't record this route. | 375 | return -EINVAL; |
| 341 | */ | 376 | } else if (rinfo->prefix_len > 64) { |
| 342 | for (sprt = ip6_routing_table.leaf; | 377 | if (rinfo->length < 2) { |
| 343 | sprt; sprt = sprt->u.next) { | 378 | return -EINVAL; |
| 344 | if (!rt6_check_expired(sprt) && | ||
| 345 | (sprt->rt6i_flags & RTF_DEFAULT) && | ||
| 346 | (!oif || | ||
| 347 | (sprt->rt6i_dev && | ||
| 348 | sprt->rt6i_dev->ifindex == oif))) { | ||
| 349 | match = sprt; | ||
| 350 | break; | ||
| 351 | } | ||
| 352 | } | 379 | } |
| 353 | if (!match) { | 380 | } else if (rinfo->prefix_len > 0) { |
| 354 | /* no default route. give up. */ | 381 | if (rinfo->length < 1) { |
| 355 | match = &ip6_null_entry; | 382 | return -EINVAL; |
| 356 | } | 383 | } |
| 357 | } | 384 | } |
| 358 | 385 | ||
| 359 | return match; | 386 | pref = rinfo->route_pref; |
| 387 | if (pref == ICMPV6_ROUTER_PREF_INVALID) | ||
| 388 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | ||
| 389 | |||
| 390 | lifetime = htonl(rinfo->lifetime); | ||
| 391 | if (lifetime == 0xffffffff) { | ||
| 392 | /* infinity */ | ||
| 393 | } else if (lifetime > 0x7fffffff/HZ) { | ||
| 394 | /* Avoid arithmetic overflow */ | ||
| 395 | lifetime = 0x7fffffff/HZ - 1; | ||
| 396 | } | ||
| 397 | |||
| 398 | if (rinfo->length == 3) | ||
| 399 | prefix = (struct in6_addr *)rinfo->prefix; | ||
| 400 | else { | ||
| 401 | /* this function is safe */ | ||
| 402 | ipv6_addr_prefix(&prefix_buf, | ||
| 403 | (struct in6_addr *)rinfo->prefix, | ||
| 404 | rinfo->prefix_len); | ||
| 405 | prefix = &prefix_buf; | ||
| 406 | } | ||
| 407 | |||
| 408 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); | ||
| 409 | |||
| 410 | if (rt && !lifetime) { | ||
| 411 | ip6_del_rt(rt, NULL, NULL, NULL); | ||
| 412 | rt = NULL; | ||
| 413 | } | ||
| 414 | |||
| 415 | if (!rt && lifetime) | ||
| 416 | rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex, | ||
| 417 | pref); | ||
| 418 | else if (rt) | ||
| 419 | rt->rt6i_flags = RTF_ROUTEINFO | | ||
| 420 | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); | ||
| 421 | |||
| 422 | if (rt) { | ||
| 423 | if (lifetime == 0xffffffff) { | ||
| 424 | rt->rt6i_flags &= ~RTF_EXPIRES; | ||
| 425 | } else { | ||
| 426 | rt->rt6i_expires = jiffies + HZ * lifetime; | ||
| 427 | rt->rt6i_flags |= RTF_EXPIRES; | ||
| 428 | } | ||
| 429 | dst_release(&rt->u.dst); | ||
| 430 | } | ||
| 431 | return 0; | ||
| 360 | } | 432 | } |
| 433 | #endif | ||
| 361 | 434 | ||
| 362 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | 435 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, |
| 363 | int oif, int strict) | 436 | int oif, int strict) |
| @@ -397,14 +470,9 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
| 397 | return err; | 470 | return err; |
| 398 | } | 471 | } |
| 399 | 472 | ||
| 400 | /* No rt6_lock! If COW failed, the function returns dead route entry | 473 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
| 401 | with dst->error set to errno value. | 474 | struct in6_addr *saddr) |
| 402 | */ | ||
| 403 | |||
| 404 | static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | ||
| 405 | struct in6_addr *saddr, struct netlink_skb_parms *req) | ||
| 406 | { | 475 | { |
| 407 | int err; | ||
| 408 | struct rt6_info *rt; | 476 | struct rt6_info *rt; |
| 409 | 477 | ||
| 410 | /* | 478 | /* |
| @@ -435,25 +503,30 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | |||
| 435 | 503 | ||
| 436 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); | 504 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); |
| 437 | 505 | ||
| 438 | dst_hold(&rt->u.dst); | 506 | } |
| 439 | |||
| 440 | err = ip6_ins_rt(rt, NULL, NULL, req); | ||
| 441 | if (err == 0) | ||
| 442 | return rt; | ||
| 443 | 507 | ||
| 444 | rt->u.dst.error = err; | 508 | return rt; |
| 509 | } | ||
| 445 | 510 | ||
| 446 | return rt; | 511 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) |
| 512 | { | ||
| 513 | struct rt6_info *rt = ip6_rt_copy(ort); | ||
| 514 | if (rt) { | ||
| 515 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | ||
| 516 | rt->rt6i_dst.plen = 128; | ||
| 517 | rt->rt6i_flags |= RTF_CACHE; | ||
| 518 | if (rt->rt6i_flags & RTF_REJECT) | ||
| 519 | rt->u.dst.error = ort->u.dst.error; | ||
| 520 | rt->u.dst.flags |= DST_HOST; | ||
| 521 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); | ||
| 447 | } | 522 | } |
| 448 | dst_hold(&ip6_null_entry.u.dst); | 523 | return rt; |
| 449 | return &ip6_null_entry; | ||
| 450 | } | 524 | } |
| 451 | 525 | ||
| 452 | #define BACKTRACK() \ | 526 | #define BACKTRACK() \ |
| 453 | if (rt == &ip6_null_entry && strict) { \ | 527 | if (rt == &ip6_null_entry) { \ |
| 454 | while ((fn = fn->parent) != NULL) { \ | 528 | while ((fn = fn->parent) != NULL) { \ |
| 455 | if (fn->fn_flags & RTN_ROOT) { \ | 529 | if (fn->fn_flags & RTN_ROOT) { \ |
| 456 | dst_hold(&rt->u.dst); \ | ||
| 457 | goto out; \ | 530 | goto out; \ |
| 458 | } \ | 531 | } \ |
| 459 | if (fn->fn_flags & RTN_RTINFO) \ | 532 | if (fn->fn_flags & RTN_RTINFO) \ |
| @@ -465,115 +538,138 @@ if (rt == &ip6_null_entry && strict) { \ | |||
| 465 | void ip6_route_input(struct sk_buff *skb) | 538 | void ip6_route_input(struct sk_buff *skb) |
| 466 | { | 539 | { |
| 467 | struct fib6_node *fn; | 540 | struct fib6_node *fn; |
| 468 | struct rt6_info *rt; | 541 | struct rt6_info *rt, *nrt; |
| 469 | int strict; | 542 | int strict; |
| 470 | int attempts = 3; | 543 | int attempts = 3; |
| 544 | int err; | ||
| 545 | int reachable = RT6_SELECT_F_REACHABLE; | ||
| 471 | 546 | ||
| 472 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 547 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; |
| 473 | 548 | ||
| 474 | relookup: | 549 | relookup: |
| 475 | read_lock_bh(&rt6_lock); | 550 | read_lock_bh(&rt6_lock); |
| 476 | 551 | ||
| 552 | restart_2: | ||
| 477 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, | 553 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, |
| 478 | &skb->nh.ipv6h->saddr); | 554 | &skb->nh.ipv6h->saddr); |
| 479 | 555 | ||
| 480 | restart: | 556 | restart: |
| 481 | rt = fn->leaf; | 557 | rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable); |
| 482 | |||
| 483 | if ((rt->rt6i_flags & RTF_CACHE)) { | ||
| 484 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); | ||
| 485 | BACKTRACK(); | ||
| 486 | dst_hold(&rt->u.dst); | ||
| 487 | goto out; | ||
| 488 | } | ||
| 489 | |||
| 490 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); | ||
| 491 | BACKTRACK(); | 558 | BACKTRACK(); |
| 559 | if (rt == &ip6_null_entry || | ||
| 560 | rt->rt6i_flags & RTF_CACHE) | ||
| 561 | goto out; | ||
| 492 | 562 | ||
| 493 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 563 | dst_hold(&rt->u.dst); |
| 494 | struct rt6_info *nrt; | 564 | read_unlock_bh(&rt6_lock); |
| 495 | dst_hold(&rt->u.dst); | ||
| 496 | read_unlock_bh(&rt6_lock); | ||
| 497 | 565 | ||
| 498 | nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, | 566 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| 499 | &skb->nh.ipv6h->saddr, | 567 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); |
| 500 | &NETLINK_CB(skb)); | 568 | else { |
| 569 | #if CLONE_OFFLINK_ROUTE | ||
| 570 | nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); | ||
| 571 | #else | ||
| 572 | goto out2; | ||
| 573 | #endif | ||
| 574 | } | ||
| 501 | 575 | ||
| 502 | dst_release(&rt->u.dst); | 576 | dst_release(&rt->u.dst); |
| 503 | rt = nrt; | 577 | rt = nrt ? : &ip6_null_entry; |
| 504 | 578 | ||
| 505 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 579 | dst_hold(&rt->u.dst); |
| 580 | if (nrt) { | ||
| 581 | err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); | ||
| 582 | if (!err) | ||
| 506 | goto out2; | 583 | goto out2; |
| 507 | |||
| 508 | /* Race condition! In the gap, when rt6_lock was | ||
| 509 | released someone could insert this route. Relookup. | ||
| 510 | */ | ||
| 511 | dst_release(&rt->u.dst); | ||
| 512 | goto relookup; | ||
| 513 | } | 584 | } |
| 514 | dst_hold(&rt->u.dst); | 585 | |
| 586 | if (--attempts <= 0) | ||
| 587 | goto out2; | ||
| 588 | |||
| 589 | /* | ||
| 590 | * Race condition! In the gap, when rt6_lock was | ||
| 591 | * released someone could insert this route. Relookup. | ||
| 592 | */ | ||
| 593 | dst_release(&rt->u.dst); | ||
| 594 | goto relookup; | ||
| 515 | 595 | ||
| 516 | out: | 596 | out: |
| 597 | if (reachable) { | ||
| 598 | reachable = 0; | ||
| 599 | goto restart_2; | ||
| 600 | } | ||
| 601 | dst_hold(&rt->u.dst); | ||
| 517 | read_unlock_bh(&rt6_lock); | 602 | read_unlock_bh(&rt6_lock); |
| 518 | out2: | 603 | out2: |
| 519 | rt->u.dst.lastuse = jiffies; | 604 | rt->u.dst.lastuse = jiffies; |
| 520 | rt->u.dst.__use++; | 605 | rt->u.dst.__use++; |
| 521 | skb->dst = (struct dst_entry *) rt; | 606 | skb->dst = (struct dst_entry *) rt; |
| 607 | return; | ||
| 522 | } | 608 | } |
| 523 | 609 | ||
| 524 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 610 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) |
| 525 | { | 611 | { |
| 526 | struct fib6_node *fn; | 612 | struct fib6_node *fn; |
| 527 | struct rt6_info *rt; | 613 | struct rt6_info *rt, *nrt; |
| 528 | int strict; | 614 | int strict; |
| 529 | int attempts = 3; | 615 | int attempts = 3; |
| 616 | int err; | ||
| 617 | int reachable = RT6_SELECT_F_REACHABLE; | ||
| 530 | 618 | ||
| 531 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 619 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; |
| 532 | 620 | ||
| 533 | relookup: | 621 | relookup: |
| 534 | read_lock_bh(&rt6_lock); | 622 | read_lock_bh(&rt6_lock); |
| 535 | 623 | ||
| 624 | restart_2: | ||
| 536 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); | 625 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); |
| 537 | 626 | ||
| 538 | restart: | 627 | restart: |
| 539 | rt = fn->leaf; | 628 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); |
| 540 | 629 | BACKTRACK(); | |
| 541 | if ((rt->rt6i_flags & RTF_CACHE)) { | 630 | if (rt == &ip6_null_entry || |
| 542 | rt = rt6_device_match(rt, fl->oif, strict); | 631 | rt->rt6i_flags & RTF_CACHE) |
| 543 | BACKTRACK(); | ||
| 544 | dst_hold(&rt->u.dst); | ||
| 545 | goto out; | 632 | goto out; |
| 546 | } | ||
| 547 | if (rt->rt6i_flags & RTF_DEFAULT) { | ||
| 548 | if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) | ||
| 549 | rt = rt6_best_dflt(rt, fl->oif); | ||
| 550 | } else { | ||
| 551 | rt = rt6_device_match(rt, fl->oif, strict); | ||
| 552 | BACKTRACK(); | ||
| 553 | } | ||
| 554 | 633 | ||
| 555 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 634 | dst_hold(&rt->u.dst); |
| 556 | struct rt6_info *nrt; | 635 | read_unlock_bh(&rt6_lock); |
| 557 | dst_hold(&rt->u.dst); | ||
| 558 | read_unlock_bh(&rt6_lock); | ||
| 559 | 636 | ||
| 560 | nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); | 637 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| 638 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | ||
| 639 | else { | ||
| 640 | #if CLONE_OFFLINK_ROUTE | ||
| 641 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | ||
| 642 | #else | ||
| 643 | goto out2; | ||
| 644 | #endif | ||
| 645 | } | ||
| 561 | 646 | ||
| 562 | dst_release(&rt->u.dst); | 647 | dst_release(&rt->u.dst); |
| 563 | rt = nrt; | 648 | rt = nrt ? : &ip6_null_entry; |
| 564 | 649 | ||
| 565 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 650 | dst_hold(&rt->u.dst); |
| 651 | if (nrt) { | ||
| 652 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | ||
| 653 | if (!err) | ||
| 566 | goto out2; | 654 | goto out2; |
| 567 | |||
| 568 | /* Race condition! In the gap, when rt6_lock was | ||
| 569 | released someone could insert this route. Relookup. | ||
| 570 | */ | ||
| 571 | dst_release(&rt->u.dst); | ||
| 572 | goto relookup; | ||
| 573 | } | 655 | } |
| 574 | dst_hold(&rt->u.dst); | 656 | |
| 657 | if (--attempts <= 0) | ||
| 658 | goto out2; | ||
| 659 | |||
| 660 | /* | ||
| 661 | * Race condition! In the gap, when rt6_lock was | ||
| 662 | * released someone could insert this route. Relookup. | ||
| 663 | */ | ||
| 664 | dst_release(&rt->u.dst); | ||
| 665 | goto relookup; | ||
| 575 | 666 | ||
| 576 | out: | 667 | out: |
| 668 | if (reachable) { | ||
| 669 | reachable = 0; | ||
| 670 | goto restart_2; | ||
| 671 | } | ||
| 672 | dst_hold(&rt->u.dst); | ||
| 577 | read_unlock_bh(&rt6_lock); | 673 | read_unlock_bh(&rt6_lock); |
| 578 | out2: | 674 | out2: |
| 579 | rt->u.dst.lastuse = jiffies; | 675 | rt->u.dst.lastuse = jiffies; |
| @@ -999,8 +1095,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct | |||
| 999 | 1095 | ||
| 1000 | write_lock_bh(&rt6_lock); | 1096 | write_lock_bh(&rt6_lock); |
| 1001 | 1097 | ||
| 1002 | rt6_reset_dflt_pointer(NULL); | ||
| 1003 | |||
| 1004 | err = fib6_del(rt, nlh, _rtattr, req); | 1098 | err = fib6_del(rt, nlh, _rtattr, req); |
| 1005 | dst_release(&rt->u.dst); | 1099 | dst_release(&rt->u.dst); |
| 1006 | 1100 | ||
| @@ -1050,59 +1144,63 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r | |||
| 1050 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1144 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, |
| 1051 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1145 | struct neighbour *neigh, u8 *lladdr, int on_link) |
| 1052 | { | 1146 | { |
| 1053 | struct rt6_info *rt, *nrt; | 1147 | struct rt6_info *rt, *nrt = NULL; |
| 1054 | 1148 | int strict; | |
| 1055 | /* Locate old route to this destination. */ | 1149 | struct fib6_node *fn; |
| 1056 | rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1); | ||
| 1057 | |||
| 1058 | if (rt == NULL) | ||
| 1059 | return; | ||
| 1060 | |||
| 1061 | if (neigh->dev != rt->rt6i_dev) | ||
| 1062 | goto out; | ||
| 1063 | 1150 | ||
| 1064 | /* | 1151 | /* |
| 1065 | * Current route is on-link; redirect is always invalid. | 1152 | * Get the "current" route for this destination and |
| 1066 | * | 1153 | * check if the redirect has come from approriate router. |
| 1067 | * Seems, previous statement is not true. It could | 1154 | * |
| 1068 | * be node, which looks for us as on-link (f.e. proxy ndisc) | 1155 | * RFC 2461 specifies that redirects should only be |
| 1069 | * But then router serving it might decide, that we should | 1156 | * accepted if they come from the nexthop to the target. |
| 1070 | * know truth 8)8) --ANK (980726). | 1157 | * Due to the way the routes are chosen, this notion |
| 1158 | * is a bit fuzzy and one might need to check all possible | ||
| 1159 | * routes. | ||
| 1071 | */ | 1160 | */ |
| 1072 | if (!(rt->rt6i_flags&RTF_GATEWAY)) | 1161 | strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); |
| 1073 | goto out; | ||
| 1074 | 1162 | ||
| 1075 | /* | 1163 | read_lock_bh(&rt6_lock); |
| 1076 | * RFC 2461 specifies that redirects should only be | 1164 | fn = fib6_lookup(&ip6_routing_table, dest, NULL); |
| 1077 | * accepted if they come from the nexthop to the target. | 1165 | restart: |
| 1078 | * Due to the way default routers are chosen, this notion | 1166 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
| 1079 | * is a bit fuzzy and one might need to check all default | 1167 | /* |
| 1080 | * routers. | 1168 | * Current route is on-link; redirect is always invalid. |
| 1081 | */ | 1169 | * |
| 1082 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) { | 1170 | * Seems, previous statement is not true. It could |
| 1083 | if (rt->rt6i_flags & RTF_DEFAULT) { | 1171 | * be node, which looks for us as on-link (f.e. proxy ndisc) |
| 1084 | struct rt6_info *rt1; | 1172 | * But then router serving it might decide, that we should |
| 1085 | 1173 | * know truth 8)8) --ANK (980726). | |
| 1086 | read_lock(&rt6_lock); | 1174 | */ |
| 1087 | for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { | 1175 | if (rt6_check_expired(rt)) |
| 1088 | if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) { | 1176 | continue; |
| 1089 | dst_hold(&rt1->u.dst); | 1177 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
| 1090 | dst_release(&rt->u.dst); | 1178 | continue; |
| 1091 | read_unlock(&rt6_lock); | 1179 | if (neigh->dev != rt->rt6i_dev) |
| 1092 | rt = rt1; | 1180 | continue; |
| 1093 | goto source_ok; | 1181 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) |
| 1094 | } | 1182 | continue; |
| 1095 | } | 1183 | break; |
| 1096 | read_unlock(&rt6_lock); | 1184 | } |
| 1185 | if (rt) | ||
| 1186 | dst_hold(&rt->u.dst); | ||
| 1187 | else if (strict) { | ||
| 1188 | while ((fn = fn->parent) != NULL) { | ||
| 1189 | if (fn->fn_flags & RTN_ROOT) | ||
| 1190 | break; | ||
| 1191 | if (fn->fn_flags & RTN_RTINFO) | ||
| 1192 | goto restart; | ||
| 1097 | } | 1193 | } |
| 1194 | } | ||
| 1195 | read_unlock_bh(&rt6_lock); | ||
| 1196 | |||
| 1197 | if (!rt) { | ||
| 1098 | if (net_ratelimit()) | 1198 | if (net_ratelimit()) |
| 1099 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1199 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
| 1100 | "for redirect target\n"); | 1200 | "for redirect target\n"); |
| 1101 | goto out; | 1201 | return; |
| 1102 | } | 1202 | } |
| 1103 | 1203 | ||
| 1104 | source_ok: | ||
| 1105 | |||
| 1106 | /* | 1204 | /* |
| 1107 | * We have finally decided to accept it. | 1205 | * We have finally decided to accept it. |
| 1108 | */ | 1206 | */ |
| @@ -1210,38 +1308,27 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1210 | 1. It is connected route. Action: COW | 1308 | 1. It is connected route. Action: COW |
| 1211 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. | 1309 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. |
| 1212 | */ | 1310 | */ |
| 1213 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 1311 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| 1214 | nrt = rt6_cow(rt, daddr, saddr, NULL); | 1312 | nrt = rt6_alloc_cow(rt, daddr, saddr); |
| 1215 | if (!nrt->u.dst.error) { | 1313 | else |
| 1216 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1314 | nrt = rt6_alloc_clone(rt, daddr); |
| 1217 | if (allfrag) | 1315 | |
| 1218 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1316 | if (nrt) { |
| 1219 | /* According to RFC 1981, detecting PMTU increase shouldn't be | ||
| 1220 | happened within 5 mins, the recommended timer is 10 mins. | ||
| 1221 | Here this route expiration time is set to ip6_rt_mtu_expires | ||
| 1222 | which is 10 mins. After 10 mins the decreased pmtu is expired | ||
| 1223 | and detecting PMTU increase will be automatically happened. | ||
| 1224 | */ | ||
| 1225 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
| 1226 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | ||
| 1227 | } | ||
| 1228 | dst_release(&nrt->u.dst); | ||
| 1229 | } else { | ||
| 1230 | nrt = ip6_rt_copy(rt); | ||
| 1231 | if (nrt == NULL) | ||
| 1232 | goto out; | ||
| 1233 | ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr); | ||
| 1234 | nrt->rt6i_dst.plen = 128; | ||
| 1235 | nrt->u.dst.flags |= DST_HOST; | ||
| 1236 | nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop); | ||
| 1237 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
| 1238 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; | ||
| 1239 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1317 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; |
| 1240 | if (allfrag) | 1318 | if (allfrag) |
| 1241 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1319 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
| 1320 | |||
| 1321 | /* According to RFC 1981, detecting PMTU increase shouldn't be | ||
| 1322 | * happened within 5 mins, the recommended timer is 10 mins. | ||
| 1323 | * Here this route expiration time is set to ip6_rt_mtu_expires | ||
| 1324 | * which is 10 mins. After 10 mins the decreased pmtu is expired | ||
| 1325 | * and detecting PMTU increase will be automatically happened. | ||
| 1326 | */ | ||
| 1327 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
| 1328 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | ||
| 1329 | |||
| 1242 | ip6_ins_rt(nrt, NULL, NULL, NULL); | 1330 | ip6_ins_rt(nrt, NULL, NULL, NULL); |
| 1243 | } | 1331 | } |
| 1244 | |||
| 1245 | out: | 1332 | out: |
| 1246 | dst_release(&rt->u.dst); | 1333 | dst_release(&rt->u.dst); |
| 1247 | } | 1334 | } |
| @@ -1280,6 +1367,57 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
| 1280 | return rt; | 1367 | return rt; |
| 1281 | } | 1368 | } |
| 1282 | 1369 | ||
| 1370 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
| 1371 | static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, | ||
| 1372 | struct in6_addr *gwaddr, int ifindex) | ||
| 1373 | { | ||
| 1374 | struct fib6_node *fn; | ||
| 1375 | struct rt6_info *rt = NULL; | ||
| 1376 | |||
| 1377 | write_lock_bh(&rt6_lock); | ||
| 1378 | fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); | ||
| 1379 | if (!fn) | ||
| 1380 | goto out; | ||
| 1381 | |||
| 1382 | for (rt = fn->leaf; rt; rt = rt->u.next) { | ||
| 1383 | if (rt->rt6i_dev->ifindex != ifindex) | ||
| 1384 | continue; | ||
| 1385 | if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) | ||
| 1386 | continue; | ||
| 1387 | if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) | ||
| 1388 | continue; | ||
| 1389 | dst_hold(&rt->u.dst); | ||
| 1390 | break; | ||
| 1391 | } | ||
| 1392 | out: | ||
| 1393 | write_unlock_bh(&rt6_lock); | ||
| 1394 | return rt; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, | ||
| 1398 | struct in6_addr *gwaddr, int ifindex, | ||
| 1399 | unsigned pref) | ||
| 1400 | { | ||
| 1401 | struct in6_rtmsg rtmsg; | ||
| 1402 | |||
| 1403 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
| 1404 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
| 1405 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
| 1406 | rtmsg.rtmsg_dst_len = prefixlen; | ||
| 1407 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
| 1408 | rtmsg.rtmsg_metric = 1024; | ||
| 1409 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
| 1410 | /* We should treat it as a default route if prefix length is 0. */ | ||
| 1411 | if (!prefixlen) | ||
| 1412 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | ||
| 1413 | rtmsg.rtmsg_ifindex = ifindex; | ||
| 1414 | |||
| 1415 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
| 1416 | |||
| 1417 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | ||
| 1418 | } | ||
| 1419 | #endif | ||
| 1420 | |||
| 1283 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1421 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) |
| 1284 | { | 1422 | { |
| 1285 | struct rt6_info *rt; | 1423 | struct rt6_info *rt; |
| @@ -1290,6 +1428,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
| 1290 | write_lock_bh(&rt6_lock); | 1428 | write_lock_bh(&rt6_lock); |
| 1291 | for (rt = fn->leaf; rt; rt=rt->u.next) { | 1429 | for (rt = fn->leaf; rt; rt=rt->u.next) { |
| 1292 | if (dev == rt->rt6i_dev && | 1430 | if (dev == rt->rt6i_dev && |
| 1431 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | ||
| 1293 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1432 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
| 1294 | break; | 1433 | break; |
| 1295 | } | 1434 | } |
| @@ -1300,7 +1439,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
| 1300 | } | 1439 | } |
| 1301 | 1440 | ||
| 1302 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1441 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, |
| 1303 | struct net_device *dev) | 1442 | struct net_device *dev, |
| 1443 | unsigned int pref) | ||
| 1304 | { | 1444 | { |
| 1305 | struct in6_rtmsg rtmsg; | 1445 | struct in6_rtmsg rtmsg; |
| 1306 | 1446 | ||
| @@ -1308,7 +1448,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
| 1308 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1448 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; |
| 1309 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | 1449 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); |
| 1310 | rtmsg.rtmsg_metric = 1024; | 1450 | rtmsg.rtmsg_metric = 1024; |
| 1311 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES; | 1451 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | |
| 1452 | RTF_PREF(pref); | ||
| 1312 | 1453 | ||
| 1313 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1454 | rtmsg.rtmsg_ifindex = dev->ifindex; |
| 1314 | 1455 | ||
| @@ -1326,8 +1467,6 @@ restart: | |||
| 1326 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1467 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
| 1327 | dst_hold(&rt->u.dst); | 1468 | dst_hold(&rt->u.dst); |
| 1328 | 1469 | ||
| 1329 | rt6_reset_dflt_pointer(NULL); | ||
| 1330 | |||
| 1331 | read_unlock_bh(&rt6_lock); | 1470 | read_unlock_bh(&rt6_lock); |
| 1332 | 1471 | ||
| 1333 | ip6_del_rt(rt, NULL, NULL, NULL); | 1472 | ip6_del_rt(rt, NULL, NULL, NULL); |
| @@ -1738,11 +1877,10 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1738 | /* | 1877 | /* |
| 1739 | * 2. allocate and initialize walker. | 1878 | * 2. allocate and initialize walker. |
| 1740 | */ | 1879 | */ |
| 1741 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | 1880 | w = kzalloc(sizeof(*w), GFP_ATOMIC); |
| 1742 | if (w == NULL) | 1881 | if (w == NULL) |
| 1743 | return -ENOMEM; | 1882 | return -ENOMEM; |
| 1744 | RT6_TRACE("dump<%p", w); | 1883 | RT6_TRACE("dump<%p", w); |
| 1745 | memset(w, 0, sizeof(*w)); | ||
| 1746 | w->root = &ip6_routing_table; | 1884 | w->root = &ip6_routing_table; |
| 1747 | w->func = fib6_dump_node; | 1885 | w->func = fib6_dump_node; |
| 1748 | w->args = &arg; | 1886 | w->args = &arg; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ca9cf6853755..301eee726b0f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -987,6 +987,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 987 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 987 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
| 988 | newnp->opt->opt_flen); | 988 | newnp->opt->opt_flen); |
| 989 | 989 | ||
| 990 | tcp_mtup_init(newsk); | ||
| 990 | tcp_sync_mss(newsk, dst_mtu(dst)); | 991 | tcp_sync_mss(newsk, dst_mtu(dst)); |
| 991 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 992 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
| 992 | tcp_initialize_rcv_mss(newsk); | 993 | tcp_initialize_rcv_mss(newsk); |
| @@ -1297,18 +1298,21 @@ static int tcp_v6_remember_stamp(struct sock *sk) | |||
| 1297 | } | 1298 | } |
| 1298 | 1299 | ||
| 1299 | static struct inet_connection_sock_af_ops ipv6_specific = { | 1300 | static struct inet_connection_sock_af_ops ipv6_specific = { |
| 1300 | .queue_xmit = inet6_csk_xmit, | 1301 | .queue_xmit = inet6_csk_xmit, |
| 1301 | .send_check = tcp_v6_send_check, | 1302 | .send_check = tcp_v6_send_check, |
| 1302 | .rebuild_header = inet6_sk_rebuild_header, | 1303 | .rebuild_header = inet6_sk_rebuild_header, |
| 1303 | .conn_request = tcp_v6_conn_request, | 1304 | .conn_request = tcp_v6_conn_request, |
| 1304 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1305 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
| 1305 | .remember_stamp = tcp_v6_remember_stamp, | 1306 | .remember_stamp = tcp_v6_remember_stamp, |
| 1306 | .net_header_len = sizeof(struct ipv6hdr), | 1307 | .net_header_len = sizeof(struct ipv6hdr), |
| 1307 | 1308 | .setsockopt = ipv6_setsockopt, | |
| 1308 | .setsockopt = ipv6_setsockopt, | 1309 | .getsockopt = ipv6_getsockopt, |
| 1309 | .getsockopt = ipv6_getsockopt, | 1310 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
| 1310 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1311 | .sockaddr_len = sizeof(struct sockaddr_in6), |
| 1311 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1312 | #ifdef CONFIG_COMPAT |
| 1313 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
| 1314 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
| 1315 | #endif | ||
| 1312 | }; | 1316 | }; |
| 1313 | 1317 | ||
| 1314 | /* | 1318 | /* |
| @@ -1316,22 +1320,23 @@ static struct inet_connection_sock_af_ops ipv6_specific = { | |||
| 1316 | */ | 1320 | */ |
| 1317 | 1321 | ||
| 1318 | static struct inet_connection_sock_af_ops ipv6_mapped = { | 1322 | static struct inet_connection_sock_af_ops ipv6_mapped = { |
| 1319 | .queue_xmit = ip_queue_xmit, | 1323 | .queue_xmit = ip_queue_xmit, |
| 1320 | .send_check = tcp_v4_send_check, | 1324 | .send_check = tcp_v4_send_check, |
| 1321 | .rebuild_header = inet_sk_rebuild_header, | 1325 | .rebuild_header = inet_sk_rebuild_header, |
| 1322 | .conn_request = tcp_v6_conn_request, | 1326 | .conn_request = tcp_v6_conn_request, |
| 1323 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1327 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
| 1324 | .remember_stamp = tcp_v4_remember_stamp, | 1328 | .remember_stamp = tcp_v4_remember_stamp, |
| 1325 | .net_header_len = sizeof(struct iphdr), | 1329 | .net_header_len = sizeof(struct iphdr), |
| 1326 | 1330 | .setsockopt = ipv6_setsockopt, | |
| 1327 | .setsockopt = ipv6_setsockopt, | 1331 | .getsockopt = ipv6_getsockopt, |
| 1328 | .getsockopt = ipv6_getsockopt, | 1332 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
| 1329 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1333 | .sockaddr_len = sizeof(struct sockaddr_in6), |
| 1330 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1334 | #ifdef CONFIG_COMPAT |
| 1335 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
| 1336 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
| 1337 | #endif | ||
| 1331 | }; | 1338 | }; |
| 1332 | 1339 | ||
| 1333 | |||
| 1334 | |||
| 1335 | /* NOTE: A lot of things set to zero explicitly by call to | 1340 | /* NOTE: A lot of things set to zero explicitly by call to |
| 1336 | * sk_alloc() so need not be done here. | 1341 | * sk_alloc() so need not be done here. |
| 1337 | */ | 1342 | */ |
| @@ -1583,6 +1588,10 @@ struct proto tcpv6_prot = { | |||
| 1583 | .obj_size = sizeof(struct tcp6_sock), | 1588 | .obj_size = sizeof(struct tcp6_sock), |
| 1584 | .twsk_prot = &tcp6_timewait_sock_ops, | 1589 | .twsk_prot = &tcp6_timewait_sock_ops, |
| 1585 | .rsk_prot = &tcp6_request_sock_ops, | 1590 | .rsk_prot = &tcp6_request_sock_ops, |
| 1591 | #ifdef CONFIG_COMPAT | ||
| 1592 | .compat_setsockopt = compat_tcp_setsockopt, | ||
| 1593 | .compat_getsockopt = compat_tcp_getsockopt, | ||
| 1594 | #endif | ||
| 1586 | }; | 1595 | }; |
| 1587 | 1596 | ||
| 1588 | static struct inet6_protocol tcpv6_protocol = { | 1597 | static struct inet6_protocol tcpv6_protocol = { |
| @@ -1604,21 +1613,12 @@ static struct inet_protosw tcpv6_protosw = { | |||
| 1604 | 1613 | ||
| 1605 | void __init tcpv6_init(void) | 1614 | void __init tcpv6_init(void) |
| 1606 | { | 1615 | { |
| 1607 | int err; | ||
| 1608 | |||
| 1609 | /* register inet6 protocol */ | 1616 | /* register inet6 protocol */ |
| 1610 | if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) | 1617 | if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) |
| 1611 | printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); | 1618 | printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); |
| 1612 | inet6_register_protosw(&tcpv6_protosw); | 1619 | inet6_register_protosw(&tcpv6_protosw); |
| 1613 | 1620 | ||
| 1614 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_TCP, &tcp6_socket); | 1621 | if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW, |
| 1615 | if (err < 0) | 1622 | IPPROTO_TCP) < 0) |
| 1616 | panic("Failed to create the TCPv6 control socket.\n"); | 1623 | panic("Failed to create the TCPv6 control socket.\n"); |
| 1617 | tcp6_socket->sk->sk_allocation = GFP_ATOMIC; | ||
| 1618 | |||
| 1619 | /* Unhash it so that IP input processing does not even | ||
| 1620 | * see it, we do not wish this socket to see incoming | ||
| 1621 | * packets. | ||
| 1622 | */ | ||
| 1623 | tcp6_socket->sk->sk_prot->unhash(tcp6_socket->sk); | ||
| 1624 | } | 1624 | } |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c47648892c04..8d3432a70f3a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -880,16 +880,13 @@ static int udpv6_destroy_sock(struct sock *sk) | |||
| 880 | /* | 880 | /* |
| 881 | * Socket option code for UDP | 881 | * Socket option code for UDP |
| 882 | */ | 882 | */ |
| 883 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, | 883 | static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, |
| 884 | char __user *optval, int optlen) | 884 | char __user *optval, int optlen) |
| 885 | { | 885 | { |
| 886 | struct udp_sock *up = udp_sk(sk); | 886 | struct udp_sock *up = udp_sk(sk); |
| 887 | int val; | 887 | int val; |
| 888 | int err = 0; | 888 | int err = 0; |
| 889 | 889 | ||
| 890 | if (level != SOL_UDP) | ||
| 891 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 892 | |||
| 893 | if(optlen<sizeof(int)) | 890 | if(optlen<sizeof(int)) |
| 894 | return -EINVAL; | 891 | return -EINVAL; |
| 895 | 892 | ||
| @@ -927,15 +924,31 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 927 | return err; | 924 | return err; |
| 928 | } | 925 | } |
| 929 | 926 | ||
| 930 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | 927 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, |
| 928 | char __user *optval, int optlen) | ||
| 929 | { | ||
| 930 | if (level != SOL_UDP) | ||
| 931 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 932 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 933 | } | ||
| 934 | |||
| 935 | #ifdef CONFIG_COMPAT | ||
| 936 | static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | ||
| 937 | char __user *optval, int optlen) | ||
| 938 | { | ||
| 939 | if (level != SOL_UDP) | ||
| 940 | return compat_ipv6_setsockopt(sk, level, optname, | ||
| 941 | optval, optlen); | ||
| 942 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
| 943 | } | ||
| 944 | #endif | ||
| 945 | |||
| 946 | static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 931 | char __user *optval, int __user *optlen) | 947 | char __user *optval, int __user *optlen) |
| 932 | { | 948 | { |
| 933 | struct udp_sock *up = udp_sk(sk); | 949 | struct udp_sock *up = udp_sk(sk); |
| 934 | int val, len; | 950 | int val, len; |
| 935 | 951 | ||
| 936 | if (level != SOL_UDP) | ||
| 937 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 938 | |||
| 939 | if(get_user(len,optlen)) | 952 | if(get_user(len,optlen)) |
| 940 | return -EFAULT; | 953 | return -EFAULT; |
| 941 | 954 | ||
| @@ -964,6 +977,25 @@ static int udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 964 | return 0; | 977 | return 0; |
| 965 | } | 978 | } |
| 966 | 979 | ||
| 980 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 981 | char __user *optval, int __user *optlen) | ||
| 982 | { | ||
| 983 | if (level != SOL_UDP) | ||
| 984 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 985 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 986 | } | ||
| 987 | |||
| 988 | #ifdef CONFIG_COMPAT | ||
| 989 | static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
| 990 | char __user *optval, int __user *optlen) | ||
| 991 | { | ||
| 992 | if (level != SOL_UDP) | ||
| 993 | return compat_ipv6_getsockopt(sk, level, optname, | ||
| 994 | optval, optlen); | ||
| 995 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
| 996 | } | ||
| 997 | #endif | ||
| 998 | |||
| 967 | static struct inet6_protocol udpv6_protocol = { | 999 | static struct inet6_protocol udpv6_protocol = { |
| 968 | .handler = udpv6_rcv, | 1000 | .handler = udpv6_rcv, |
| 969 | .err_handler = udpv6_err, | 1001 | .err_handler = udpv6_err, |
| @@ -1037,22 +1069,26 @@ void udp6_proc_exit(void) { | |||
| 1037 | /* ------------------------------------------------------------------------ */ | 1069 | /* ------------------------------------------------------------------------ */ |
| 1038 | 1070 | ||
| 1039 | struct proto udpv6_prot = { | 1071 | struct proto udpv6_prot = { |
| 1040 | .name = "UDPv6", | 1072 | .name = "UDPv6", |
| 1041 | .owner = THIS_MODULE, | 1073 | .owner = THIS_MODULE, |
| 1042 | .close = udpv6_close, | 1074 | .close = udpv6_close, |
| 1043 | .connect = ip6_datagram_connect, | 1075 | .connect = ip6_datagram_connect, |
| 1044 | .disconnect = udp_disconnect, | 1076 | .disconnect = udp_disconnect, |
| 1045 | .ioctl = udp_ioctl, | 1077 | .ioctl = udp_ioctl, |
| 1046 | .destroy = udpv6_destroy_sock, | 1078 | .destroy = udpv6_destroy_sock, |
| 1047 | .setsockopt = udpv6_setsockopt, | 1079 | .setsockopt = udpv6_setsockopt, |
| 1048 | .getsockopt = udpv6_getsockopt, | 1080 | .getsockopt = udpv6_getsockopt, |
| 1049 | .sendmsg = udpv6_sendmsg, | 1081 | .sendmsg = udpv6_sendmsg, |
| 1050 | .recvmsg = udpv6_recvmsg, | 1082 | .recvmsg = udpv6_recvmsg, |
| 1051 | .backlog_rcv = udpv6_queue_rcv_skb, | 1083 | .backlog_rcv = udpv6_queue_rcv_skb, |
| 1052 | .hash = udp_v6_hash, | 1084 | .hash = udp_v6_hash, |
| 1053 | .unhash = udp_v6_unhash, | 1085 | .unhash = udp_v6_unhash, |
| 1054 | .get_port = udp_v6_get_port, | 1086 | .get_port = udp_v6_get_port, |
| 1055 | .obj_size = sizeof(struct udp6_sock), | 1087 | .obj_size = sizeof(struct udp6_sock), |
| 1088 | #ifdef CONFIG_COMPAT | ||
| 1089 | .compat_setsockopt = compat_udpv6_setsockopt, | ||
| 1090 | .compat_getsockopt = compat_udpv6_getsockopt, | ||
| 1091 | #endif | ||
| 1056 | }; | 1092 | }; |
| 1057 | 1093 | ||
| 1058 | static struct inet_protosw udpv6_protosw = { | 1094 | static struct inet_protosw udpv6_protosw = { |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 8cfc58b96fc2..08f9abbdf1d7 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <net/protocol.h> | 31 | #include <net/protocol.h> |
| 32 | #include <linux/ipv6.h> | 32 | #include <linux/ipv6.h> |
| 33 | #include <linux/icmpv6.h> | 33 | #include <linux/icmpv6.h> |
| 34 | #include <linux/mutex.h> | ||
| 34 | 35 | ||
| 35 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG | 36 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG |
| 36 | # define X6TDEBUG 3 | 37 | # define X6TDEBUG 3 |
| @@ -357,19 +358,19 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec | |||
| 357 | } | 358 | } |
| 358 | 359 | ||
| 359 | static struct xfrm6_tunnel *xfrm6_tunnel_handler; | 360 | static struct xfrm6_tunnel *xfrm6_tunnel_handler; |
| 360 | static DECLARE_MUTEX(xfrm6_tunnel_sem); | 361 | static DEFINE_MUTEX(xfrm6_tunnel_mutex); |
| 361 | 362 | ||
| 362 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | 363 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) |
| 363 | { | 364 | { |
| 364 | int ret; | 365 | int ret; |
| 365 | 366 | ||
| 366 | down(&xfrm6_tunnel_sem); | 367 | mutex_lock(&xfrm6_tunnel_mutex); |
| 367 | ret = 0; | 368 | ret = 0; |
| 368 | if (xfrm6_tunnel_handler != NULL) | 369 | if (xfrm6_tunnel_handler != NULL) |
| 369 | ret = -EINVAL; | 370 | ret = -EINVAL; |
| 370 | if (!ret) | 371 | if (!ret) |
| 371 | xfrm6_tunnel_handler = handler; | 372 | xfrm6_tunnel_handler = handler; |
| 372 | up(&xfrm6_tunnel_sem); | 373 | mutex_unlock(&xfrm6_tunnel_mutex); |
| 373 | 374 | ||
| 374 | return ret; | 375 | return ret; |
| 375 | } | 376 | } |
| @@ -380,13 +381,13 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) | |||
| 380 | { | 381 | { |
| 381 | int ret; | 382 | int ret; |
| 382 | 383 | ||
| 383 | down(&xfrm6_tunnel_sem); | 384 | mutex_lock(&xfrm6_tunnel_mutex); |
| 384 | ret = 0; | 385 | ret = 0; |
| 385 | if (xfrm6_tunnel_handler != handler) | 386 | if (xfrm6_tunnel_handler != handler) |
| 386 | ret = -EINVAL; | 387 | ret = -EINVAL; |
| 387 | if (!ret) | 388 | if (!ret) |
| 388 | xfrm6_tunnel_handler = NULL; | 389 | xfrm6_tunnel_handler = NULL; |
| 389 | up(&xfrm6_tunnel_sem); | 390 | mutex_unlock(&xfrm6_tunnel_mutex); |
| 390 | 391 | ||
| 391 | synchronize_net(); | 392 | synchronize_net(); |
| 392 | 393 | ||
