diff options
Diffstat (limited to 'net/ipv6')
60 files changed, 3425 insertions, 3008 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index a578096152ab..36d7437ac054 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -229,6 +229,20 @@ config IPV6_MROUTE | |||
| 229 | Experimental support for IPv6 multicast forwarding. | 229 | Experimental support for IPv6 multicast forwarding. |
| 230 | If unsure, say N. | 230 | If unsure, say N. |
| 231 | 231 | ||
| 232 | config IPV6_MROUTE_MULTIPLE_TABLES | ||
| 233 | bool "IPv6: multicast policy routing" | ||
| 234 | depends on IPV6_MROUTE | ||
| 235 | select FIB_RULES | ||
| 236 | help | ||
| 237 | Normally, a multicast router runs a userspace daemon and decides | ||
| 238 | what to do with a multicast packet based on the source and | ||
| 239 | destination addresses. If you say Y here, the multicast router | ||
| 240 | will also be able to take interfaces and packet marks into | ||
| 241 | account and run multiple instances of userspace daemons | ||
| 242 | simultaneously, each one handling a single table. | ||
| 243 | |||
| 244 | If unsure, say N. | ||
| 245 | |||
| 232 | config IPV6_PIMSM_V2 | 246 | config IPV6_PIMSM_V2 |
| 233 | bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" | 247 | bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" |
| 234 | depends on IPV6_MROUTE | 248 | depends on IPV6_MROUTE |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index de7a194a64ab..324fac3b6c16 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <linux/route.h> | 53 | #include <linux/route.h> |
| 54 | #include <linux/inetdevice.h> | 54 | #include <linux/inetdevice.h> |
| 55 | #include <linux/init.h> | 55 | #include <linux/init.h> |
| 56 | #include <linux/slab.h> | ||
| 56 | #ifdef CONFIG_SYSCTL | 57 | #ifdef CONFIG_SYSCTL |
| 57 | #include <linux/sysctl.h> | 58 | #include <linux/sysctl.h> |
| 58 | #endif | 59 | #endif |
| @@ -81,7 +82,7 @@ | |||
| 81 | #include <linux/random.h> | 82 | #include <linux/random.h> |
| 82 | #endif | 83 | #endif |
| 83 | 84 | ||
| 84 | #include <asm/uaccess.h> | 85 | #include <linux/uaccess.h> |
| 85 | #include <asm/unaligned.h> | 86 | #include <asm/unaligned.h> |
| 86 | 87 | ||
| 87 | #include <linux/proc_fs.h> | 88 | #include <linux/proc_fs.h> |
| @@ -97,7 +98,11 @@ | |||
| 97 | #endif | 98 | #endif |
| 98 | 99 | ||
| 99 | #define INFINITY_LIFE_TIME 0xFFFFFFFF | 100 | #define INFINITY_LIFE_TIME 0xFFFFFFFF |
| 100 | #define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b))) | 101 | #define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) |
| 102 | |||
| 103 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | ||
| 104 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | ||
| 105 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | ||
| 101 | 106 | ||
| 102 | #ifdef CONFIG_SYSCTL | 107 | #ifdef CONFIG_SYSCTL |
| 103 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 108 | static void addrconf_sysctl_register(struct inet6_dev *idev); |
| @@ -116,8 +121,6 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
| 116 | static int __ipv6_regen_rndid(struct inet6_dev *idev); | 121 | static int __ipv6_regen_rndid(struct inet6_dev *idev); |
| 117 | static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); | 122 | static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); |
| 118 | static void ipv6_regen_rndid(unsigned long data); | 123 | static void ipv6_regen_rndid(unsigned long data); |
| 119 | |||
| 120 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | ||
| 121 | #endif | 124 | #endif |
| 122 | 125 | ||
| 123 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); | 126 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); |
| @@ -126,8 +129,8 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
| 126 | /* | 129 | /* |
| 127 | * Configured unicast address hash table | 130 | * Configured unicast address hash table |
| 128 | */ | 131 | */ |
| 129 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 132 | static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; |
| 130 | static DEFINE_RWLOCK(addrconf_hash_lock); | 133 | static DEFINE_SPINLOCK(addrconf_hash_lock); |
| 131 | 134 | ||
| 132 | static void addrconf_verify(unsigned long); | 135 | static void addrconf_verify(unsigned long); |
| 133 | 136 | ||
| @@ -137,8 +140,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock); | |||
| 137 | static void addrconf_join_anycast(struct inet6_ifaddr *ifp); | 140 | static void addrconf_join_anycast(struct inet6_ifaddr *ifp); |
| 138 | static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); | 141 | static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); |
| 139 | 142 | ||
| 140 | static void addrconf_bonding_change(struct net_device *dev, | 143 | static void addrconf_type_change(struct net_device *dev, |
| 141 | unsigned long event); | 144 | unsigned long event); |
| 142 | static int addrconf_ifdown(struct net_device *dev, int how); | 145 | static int addrconf_ifdown(struct net_device *dev, int how); |
| 143 | 146 | ||
| 144 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); | 147 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); |
| @@ -151,8 +154,8 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | |||
| 151 | 154 | ||
| 152 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, | 155 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, |
| 153 | struct prefix_info *pinfo); | 156 | struct prefix_info *pinfo); |
| 154 | static int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | 157 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, |
| 155 | struct net_device *dev); | 158 | struct net_device *dev); |
| 156 | 159 | ||
| 157 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); | 160 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
| 158 | 161 | ||
| @@ -249,8 +252,7 @@ static void addrconf_del_timer(struct inet6_ifaddr *ifp) | |||
| 249 | __in6_ifa_put(ifp); | 252 | __in6_ifa_put(ifp); |
| 250 | } | 253 | } |
| 251 | 254 | ||
| 252 | enum addrconf_timer_t | 255 | enum addrconf_timer_t { |
| 253 | { | ||
| 254 | AC_NONE, | 256 | AC_NONE, |
| 255 | AC_DAD, | 257 | AC_DAD, |
| 256 | AC_RS, | 258 | AC_RS, |
| @@ -270,7 +272,8 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
| 270 | case AC_RS: | 272 | case AC_RS: |
| 271 | ifp->timer.function = addrconf_rs_timer; | 273 | ifp->timer.function = addrconf_rs_timer; |
| 272 | break; | 274 | break; |
| 273 | default:; | 275 | default: |
| 276 | break; | ||
| 274 | } | 277 | } |
| 275 | ifp->timer.expires = jiffies + when; | 278 | ifp->timer.expires = jiffies + when; |
| 276 | add_timer(&ifp->timer); | 279 | add_timer(&ifp->timer); |
| @@ -278,31 +281,34 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
| 278 | 281 | ||
| 279 | static int snmp6_alloc_dev(struct inet6_dev *idev) | 282 | static int snmp6_alloc_dev(struct inet6_dev *idev) |
| 280 | { | 283 | { |
| 281 | if (snmp_mib_init((void **)idev->stats.ipv6, | 284 | if (snmp_mib_init((void __percpu **)idev->stats.ipv6, |
| 282 | sizeof(struct ipstats_mib)) < 0) | 285 | sizeof(struct ipstats_mib), |
| 286 | __alignof__(struct ipstats_mib)) < 0) | ||
| 283 | goto err_ip; | 287 | goto err_ip; |
| 284 | if (snmp_mib_init((void **)idev->stats.icmpv6, | 288 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, |
| 285 | sizeof(struct icmpv6_mib)) < 0) | 289 | sizeof(struct icmpv6_mib), |
| 290 | __alignof__(struct icmpv6_mib)) < 0) | ||
| 286 | goto err_icmp; | 291 | goto err_icmp; |
| 287 | if (snmp_mib_init((void **)idev->stats.icmpv6msg, | 292 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, |
| 288 | sizeof(struct icmpv6msg_mib)) < 0) | 293 | sizeof(struct icmpv6msg_mib), |
| 294 | __alignof__(struct icmpv6msg_mib)) < 0) | ||
| 289 | goto err_icmpmsg; | 295 | goto err_icmpmsg; |
| 290 | 296 | ||
| 291 | return 0; | 297 | return 0; |
| 292 | 298 | ||
| 293 | err_icmpmsg: | 299 | err_icmpmsg: |
| 294 | snmp_mib_free((void **)idev->stats.icmpv6); | 300 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
| 295 | err_icmp: | 301 | err_icmp: |
| 296 | snmp_mib_free((void **)idev->stats.ipv6); | 302 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
| 297 | err_ip: | 303 | err_ip: |
| 298 | return -ENOMEM; | 304 | return -ENOMEM; |
| 299 | } | 305 | } |
| 300 | 306 | ||
| 301 | static void snmp6_free_dev(struct inet6_dev *idev) | 307 | static void snmp6_free_dev(struct inet6_dev *idev) |
| 302 | { | 308 | { |
| 303 | snmp_mib_free((void **)idev->stats.icmpv6msg); | 309 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); |
| 304 | snmp_mib_free((void **)idev->stats.icmpv6); | 310 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
| 305 | snmp_mib_free((void **)idev->stats.ipv6); | 311 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
| 306 | } | 312 | } |
| 307 | 313 | ||
| 308 | /* Nobody refers to this device, we may destroy it. */ | 314 | /* Nobody refers to this device, we may destroy it. */ |
| @@ -317,7 +323,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
| 317 | { | 323 | { |
| 318 | struct net_device *dev = idev->dev; | 324 | struct net_device *dev = idev->dev; |
| 319 | 325 | ||
| 320 | WARN_ON(idev->addr_list != NULL); | 326 | WARN_ON(!list_empty(&idev->addr_list)); |
| 321 | WARN_ON(idev->mc_list != NULL); | 327 | WARN_ON(idev->mc_list != NULL); |
| 322 | 328 | ||
| 323 | #ifdef NET_REFCNT_DEBUG | 329 | #ifdef NET_REFCNT_DEBUG |
| @@ -325,7 +331,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
| 325 | #endif | 331 | #endif |
| 326 | dev_put(dev); | 332 | dev_put(dev); |
| 327 | if (!idev->dead) { | 333 | if (!idev->dead) { |
| 328 | printk("Freeing alive inet6 device %p\n", idev); | 334 | pr_warning("Freeing alive inet6 device %p\n", idev); |
| 329 | return; | 335 | return; |
| 330 | } | 336 | } |
| 331 | snmp6_free_dev(idev); | 337 | snmp6_free_dev(idev); |
| @@ -350,6 +356,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
| 350 | 356 | ||
| 351 | rwlock_init(&ndev->lock); | 357 | rwlock_init(&ndev->lock); |
| 352 | ndev->dev = dev; | 358 | ndev->dev = dev; |
| 359 | INIT_LIST_HEAD(&ndev->addr_list); | ||
| 360 | |||
| 353 | memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); | 361 | memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); |
| 354 | ndev->cnf.mtu6 = dev->mtu; | 362 | ndev->cnf.mtu6 = dev->mtu; |
| 355 | ndev->cnf.sysctl = NULL; | 363 | ndev->cnf.sysctl = NULL; |
| @@ -401,6 +409,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
| 401 | #endif | 409 | #endif |
| 402 | 410 | ||
| 403 | #ifdef CONFIG_IPV6_PRIVACY | 411 | #ifdef CONFIG_IPV6_PRIVACY |
| 412 | INIT_LIST_HEAD(&ndev->tempaddr_list); | ||
| 404 | setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); | 413 | setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); |
| 405 | if ((dev->flags&IFF_LOOPBACK) || | 414 | if ((dev->flags&IFF_LOOPBACK) || |
| 406 | dev->type == ARPHRD_TUNNEL || | 415 | dev->type == ARPHRD_TUNNEL || |
| @@ -438,8 +447,10 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev) | |||
| 438 | 447 | ||
| 439 | ASSERT_RTNL(); | 448 | ASSERT_RTNL(); |
| 440 | 449 | ||
| 441 | if ((idev = __in6_dev_get(dev)) == NULL) { | 450 | idev = __in6_dev_get(dev); |
| 442 | if ((idev = ipv6_add_dev(dev)) == NULL) | 451 | if (!idev) { |
| 452 | idev = ipv6_add_dev(dev); | ||
| 453 | if (!idev) | ||
| 443 | return NULL; | 454 | return NULL; |
| 444 | } | 455 | } |
| 445 | 456 | ||
| @@ -465,7 +476,8 @@ static void dev_forward_change(struct inet6_dev *idev) | |||
| 465 | else | 476 | else |
| 466 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); | 477 | ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); |
| 467 | } | 478 | } |
| 468 | for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { | 479 | |
| 480 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
| 469 | if (ifa->flags&IFA_F_TENTATIVE) | 481 | if (ifa->flags&IFA_F_TENTATIVE) |
| 470 | continue; | 482 | continue; |
| 471 | if (idev->cnf.forwarding) | 483 | if (idev->cnf.forwarding) |
| @@ -502,8 +514,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
| 502 | if (p == &net->ipv6.devconf_dflt->forwarding) | 514 | if (p == &net->ipv6.devconf_dflt->forwarding) |
| 503 | return 0; | 515 | return 0; |
| 504 | 516 | ||
| 505 | if (!rtnl_trylock()) | 517 | if (!rtnl_trylock()) { |
| 518 | /* Restore the original values before restarting */ | ||
| 519 | *p = old; | ||
| 506 | return restart_syscall(); | 520 | return restart_syscall(); |
| 521 | } | ||
| 507 | 522 | ||
| 508 | if (p == &net->ipv6.devconf_all->forwarding) { | 523 | if (p == &net->ipv6.devconf_all->forwarding) { |
| 509 | __s32 newf = net->ipv6.devconf_all->forwarding; | 524 | __s32 newf = net->ipv6.devconf_all->forwarding; |
| @@ -519,12 +534,16 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
| 519 | } | 534 | } |
| 520 | #endif | 535 | #endif |
| 521 | 536 | ||
| 522 | /* Nobody refers to this ifaddr, destroy it */ | 537 | static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) |
| 538 | { | ||
| 539 | struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); | ||
| 540 | kfree(ifp); | ||
| 541 | } | ||
| 523 | 542 | ||
| 543 | /* Nobody refers to this ifaddr, destroy it */ | ||
| 524 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | 544 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) |
| 525 | { | 545 | { |
| 526 | WARN_ON(ifp->if_next != NULL); | 546 | WARN_ON(!hlist_unhashed(&ifp->addr_lst)); |
| 527 | WARN_ON(ifp->lst_next != NULL); | ||
| 528 | 547 | ||
| 529 | #ifdef NET_REFCNT_DEBUG | 548 | #ifdef NET_REFCNT_DEBUG |
| 530 | printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); | 549 | printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); |
| @@ -533,54 +552,46 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
| 533 | in6_dev_put(ifp->idev); | 552 | in6_dev_put(ifp->idev); |
| 534 | 553 | ||
| 535 | if (del_timer(&ifp->timer)) | 554 | if (del_timer(&ifp->timer)) |
| 536 | printk("Timer is still running, when freeing ifa=%p\n", ifp); | 555 | pr_notice("Timer is still running, when freeing ifa=%p\n", ifp); |
| 537 | 556 | ||
| 538 | if (!ifp->dead) { | 557 | if (ifp->state != INET6_IFADDR_STATE_DEAD) { |
| 539 | printk("Freeing alive inet6 address %p\n", ifp); | 558 | pr_warning("Freeing alive inet6 address %p\n", ifp); |
| 540 | return; | 559 | return; |
| 541 | } | 560 | } |
| 542 | dst_release(&ifp->rt->u.dst); | 561 | dst_release(&ifp->rt->dst); |
| 543 | 562 | ||
| 544 | kfree(ifp); | 563 | call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu); |
| 545 | } | 564 | } |
| 546 | 565 | ||
| 547 | static void | 566 | static void |
| 548 | ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) | 567 | ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) |
| 549 | { | 568 | { |
| 550 | struct inet6_ifaddr *ifa, **ifap; | 569 | struct list_head *p; |
| 551 | int ifp_scope = ipv6_addr_src_scope(&ifp->addr); | 570 | int ifp_scope = ipv6_addr_src_scope(&ifp->addr); |
| 552 | 571 | ||
| 553 | /* | 572 | /* |
| 554 | * Each device address list is sorted in order of scope - | 573 | * Each device address list is sorted in order of scope - |
| 555 | * global before linklocal. | 574 | * global before linklocal. |
| 556 | */ | 575 | */ |
| 557 | for (ifap = &idev->addr_list; (ifa = *ifap) != NULL; | 576 | list_for_each(p, &idev->addr_list) { |
| 558 | ifap = &ifa->if_next) { | 577 | struct inet6_ifaddr *ifa |
| 578 | = list_entry(p, struct inet6_ifaddr, if_list); | ||
| 559 | if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) | 579 | if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) |
| 560 | break; | 580 | break; |
| 561 | } | 581 | } |
| 562 | 582 | ||
| 563 | ifp->if_next = *ifap; | 583 | list_add_tail(&ifp->if_list, p); |
| 564 | *ifap = ifp; | ||
| 565 | } | 584 | } |
| 566 | 585 | ||
| 567 | /* | 586 | static u32 ipv6_addr_hash(const struct in6_addr *addr) |
| 568 | * Hash function taken from net_alias.c | ||
| 569 | */ | ||
| 570 | static u8 ipv6_addr_hash(const struct in6_addr *addr) | ||
| 571 | { | 587 | { |
| 572 | __u32 word; | ||
| 573 | |||
| 574 | /* | 588 | /* |
| 575 | * We perform the hash function over the last 64 bits of the address | 589 | * We perform the hash function over the last 64 bits of the address |
| 576 | * This will include the IEEE address token on links that support it. | 590 | * This will include the IEEE address token on links that support it. |
| 577 | */ | 591 | */ |
| 578 | 592 | return jhash_2words((__force u32)addr->s6_addr32[2], | |
| 579 | word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]); | 593 | (__force u32)addr->s6_addr32[3], 0) |
| 580 | word ^= (word >> 16); | 594 | & (IN6_ADDR_HSIZE - 1); |
| 581 | word ^= (word >> 8); | ||
| 582 | |||
| 583 | return ((word ^ (word >> 4)) & 0x0f); | ||
| 584 | } | 595 | } |
| 585 | 596 | ||
| 586 | /* On success it returns ifp with increased reference count */ | 597 | /* On success it returns ifp with increased reference count */ |
| @@ -591,7 +602,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 591 | { | 602 | { |
| 592 | struct inet6_ifaddr *ifa = NULL; | 603 | struct inet6_ifaddr *ifa = NULL; |
| 593 | struct rt6_info *rt; | 604 | struct rt6_info *rt; |
| 594 | int hash; | 605 | unsigned int hash; |
| 595 | int err = 0; | 606 | int err = 0; |
| 596 | int addr_type = ipv6_addr_type(addr); | 607 | int addr_type = ipv6_addr_type(addr); |
| 597 | 608 | ||
| @@ -612,7 +623,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 612 | goto out2; | 623 | goto out2; |
| 613 | } | 624 | } |
| 614 | 625 | ||
| 615 | write_lock(&addrconf_hash_lock); | 626 | spin_lock(&addrconf_hash_lock); |
| 616 | 627 | ||
| 617 | /* Ignore adding duplicate addresses on an interface */ | 628 | /* Ignore adding duplicate addresses on an interface */ |
| 618 | if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { | 629 | if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { |
| @@ -638,7 +649,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 638 | ipv6_addr_copy(&ifa->addr, addr); | 649 | ipv6_addr_copy(&ifa->addr, addr); |
| 639 | 650 | ||
| 640 | spin_lock_init(&ifa->lock); | 651 | spin_lock_init(&ifa->lock); |
| 652 | spin_lock_init(&ifa->state_lock); | ||
| 641 | init_timer(&ifa->timer); | 653 | init_timer(&ifa->timer); |
| 654 | INIT_HLIST_NODE(&ifa->addr_lst); | ||
| 642 | ifa->timer.data = (unsigned long) ifa; | 655 | ifa->timer.data = (unsigned long) ifa; |
| 643 | ifa->scope = scope; | 656 | ifa->scope = scope; |
| 644 | ifa->prefix_len = pfxlen; | 657 | ifa->prefix_len = pfxlen; |
| @@ -665,10 +678,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 665 | /* Add to big hash table */ | 678 | /* Add to big hash table */ |
| 666 | hash = ipv6_addr_hash(addr); | 679 | hash = ipv6_addr_hash(addr); |
| 667 | 680 | ||
| 668 | ifa->lst_next = inet6_addr_lst[hash]; | 681 | hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]); |
| 669 | inet6_addr_lst[hash] = ifa; | 682 | spin_unlock(&addrconf_hash_lock); |
| 670 | in6_ifa_hold(ifa); | ||
| 671 | write_unlock(&addrconf_hash_lock); | ||
| 672 | 683 | ||
| 673 | write_lock(&idev->lock); | 684 | write_lock(&idev->lock); |
| 674 | /* Add to inet6_dev unicast addr list. */ | 685 | /* Add to inet6_dev unicast addr list. */ |
| @@ -676,8 +687,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 676 | 687 | ||
| 677 | #ifdef CONFIG_IPV6_PRIVACY | 688 | #ifdef CONFIG_IPV6_PRIVACY |
| 678 | if (ifa->flags&IFA_F_TEMPORARY) { | 689 | if (ifa->flags&IFA_F_TEMPORARY) { |
| 679 | ifa->tmp_next = idev->tempaddr_list; | 690 | list_add(&ifa->tmp_list, &idev->tempaddr_list); |
| 680 | idev->tempaddr_list = ifa; | ||
| 681 | in6_ifa_hold(ifa); | 691 | in6_ifa_hold(ifa); |
| 682 | } | 692 | } |
| 683 | #endif | 693 | #endif |
| @@ -696,7 +706,7 @@ out2: | |||
| 696 | 706 | ||
| 697 | return ifa; | 707 | return ifa; |
| 698 | out: | 708 | out: |
| 699 | write_unlock(&addrconf_hash_lock); | 709 | spin_unlock(&addrconf_hash_lock); |
| 700 | goto out2; | 710 | goto out2; |
| 701 | } | 711 | } |
| 702 | 712 | ||
| @@ -704,52 +714,44 @@ out: | |||
| 704 | 714 | ||
| 705 | static void ipv6_del_addr(struct inet6_ifaddr *ifp) | 715 | static void ipv6_del_addr(struct inet6_ifaddr *ifp) |
| 706 | { | 716 | { |
| 707 | struct inet6_ifaddr *ifa, **ifap; | 717 | struct inet6_ifaddr *ifa, *ifn; |
| 708 | struct inet6_dev *idev = ifp->idev; | 718 | struct inet6_dev *idev = ifp->idev; |
| 719 | int state; | ||
| 709 | int hash; | 720 | int hash; |
| 710 | int deleted = 0, onlink = 0; | 721 | int deleted = 0, onlink = 0; |
| 711 | unsigned long expires = jiffies; | 722 | unsigned long expires = jiffies; |
| 712 | 723 | ||
| 713 | hash = ipv6_addr_hash(&ifp->addr); | 724 | hash = ipv6_addr_hash(&ifp->addr); |
| 714 | 725 | ||
| 715 | ifp->dead = 1; | 726 | spin_lock_bh(&ifp->state_lock); |
| 727 | state = ifp->state; | ||
| 728 | ifp->state = INET6_IFADDR_STATE_DEAD; | ||
| 729 | spin_unlock_bh(&ifp->state_lock); | ||
| 716 | 730 | ||
| 717 | write_lock_bh(&addrconf_hash_lock); | 731 | if (state == INET6_IFADDR_STATE_DEAD) |
| 718 | for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; | 732 | goto out; |
| 719 | ifap = &ifa->lst_next) { | 733 | |
| 720 | if (ifa == ifp) { | 734 | spin_lock_bh(&addrconf_hash_lock); |
| 721 | *ifap = ifa->lst_next; | 735 | hlist_del_init_rcu(&ifp->addr_lst); |
| 722 | __in6_ifa_put(ifp); | 736 | spin_unlock_bh(&addrconf_hash_lock); |
| 723 | ifa->lst_next = NULL; | ||
| 724 | break; | ||
| 725 | } | ||
| 726 | } | ||
| 727 | write_unlock_bh(&addrconf_hash_lock); | ||
| 728 | 737 | ||
| 729 | write_lock_bh(&idev->lock); | 738 | write_lock_bh(&idev->lock); |
| 730 | #ifdef CONFIG_IPV6_PRIVACY | 739 | #ifdef CONFIG_IPV6_PRIVACY |
| 731 | if (ifp->flags&IFA_F_TEMPORARY) { | 740 | if (ifp->flags&IFA_F_TEMPORARY) { |
| 732 | for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL; | 741 | list_del(&ifp->tmp_list); |
| 733 | ifap = &ifa->tmp_next) { | 742 | if (ifp->ifpub) { |
| 734 | if (ifa == ifp) { | 743 | in6_ifa_put(ifp->ifpub); |
| 735 | *ifap = ifa->tmp_next; | 744 | ifp->ifpub = NULL; |
| 736 | if (ifp->ifpub) { | ||
| 737 | in6_ifa_put(ifp->ifpub); | ||
| 738 | ifp->ifpub = NULL; | ||
| 739 | } | ||
| 740 | __in6_ifa_put(ifp); | ||
| 741 | ifa->tmp_next = NULL; | ||
| 742 | break; | ||
| 743 | } | ||
| 744 | } | 745 | } |
| 746 | __in6_ifa_put(ifp); | ||
| 745 | } | 747 | } |
| 746 | #endif | 748 | #endif |
| 747 | 749 | ||
| 748 | for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) { | 750 | list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) { |
| 749 | if (ifa == ifp) { | 751 | if (ifa == ifp) { |
| 750 | *ifap = ifa->if_next; | 752 | list_del_init(&ifp->if_list); |
| 751 | __in6_ifa_put(ifp); | 753 | __in6_ifa_put(ifp); |
| 752 | ifa->if_next = NULL; | 754 | |
| 753 | if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) | 755 | if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) |
| 754 | break; | 756 | break; |
| 755 | deleted = 1; | 757 | deleted = 1; |
| @@ -782,7 +784,6 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 782 | } | 784 | } |
| 783 | } | 785 | } |
| 784 | } | 786 | } |
| 785 | ifap = &ifa->if_next; | ||
| 786 | } | 787 | } |
| 787 | write_unlock_bh(&idev->lock); | 788 | write_unlock_bh(&idev->lock); |
| 788 | 789 | ||
| @@ -823,9 +824,10 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 823 | rt->rt6i_flags |= RTF_EXPIRES; | 824 | rt->rt6i_flags |= RTF_EXPIRES; |
| 824 | } | 825 | } |
| 825 | } | 826 | } |
| 826 | dst_release(&rt->u.dst); | 827 | dst_release(&rt->dst); |
| 827 | } | 828 | } |
| 828 | 829 | ||
| 830 | out: | ||
| 829 | in6_ifa_put(ifp); | 831 | in6_ifa_put(ifp); |
| 830 | } | 832 | } |
| 831 | 833 | ||
| @@ -889,7 +891,8 @@ retry: | |||
| 889 | idev->cnf.temp_valid_lft); | 891 | idev->cnf.temp_valid_lft); |
| 890 | tmp_prefered_lft = min_t(__u32, | 892 | tmp_prefered_lft = min_t(__u32, |
| 891 | ifp->prefered_lft, | 893 | ifp->prefered_lft, |
| 892 | idev->cnf.temp_prefered_lft - desync_factor / HZ); | 894 | idev->cnf.temp_prefered_lft - |
| 895 | idev->cnf.max_desync_factor); | ||
| 893 | tmp_plen = ifp->prefix_len; | 896 | tmp_plen = ifp->prefix_len; |
| 894 | max_addresses = idev->cnf.max_addresses; | 897 | max_addresses = idev->cnf.max_addresses; |
| 895 | tmp_cstamp = ifp->cstamp; | 898 | tmp_cstamp = ifp->cstamp; |
| @@ -989,8 +992,7 @@ struct ipv6_saddr_dst { | |||
| 989 | 992 | ||
| 990 | static inline int ipv6_saddr_preferred(int type) | 993 | static inline int ipv6_saddr_preferred(int type) |
| 991 | { | 994 | { |
| 992 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| | 995 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) |
| 993 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) | ||
| 994 | return 1; | 996 | return 1; |
| 995 | return 0; | 997 | return 0; |
| 996 | } | 998 | } |
| @@ -1162,7 +1164,7 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, | |||
| 1162 | continue; | 1164 | continue; |
| 1163 | 1165 | ||
| 1164 | read_lock_bh(&idev->lock); | 1166 | read_lock_bh(&idev->lock); |
| 1165 | for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) { | 1167 | list_for_each_entry(score->ifa, &idev->addr_list, if_list) { |
| 1166 | int i; | 1168 | int i; |
| 1167 | 1169 | ||
| 1168 | /* | 1170 | /* |
| @@ -1240,7 +1242,6 @@ try_nextdev: | |||
| 1240 | in6_ifa_put(hiscore->ifa); | 1242 | in6_ifa_put(hiscore->ifa); |
| 1241 | return 0; | 1243 | return 0; |
| 1242 | } | 1244 | } |
| 1243 | |||
| 1244 | EXPORT_SYMBOL(ipv6_dev_get_saddr); | 1245 | EXPORT_SYMBOL(ipv6_dev_get_saddr); |
| 1245 | 1246 | ||
| 1246 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, | 1247 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, |
| @@ -1250,12 +1251,14 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, | |||
| 1250 | int err = -EADDRNOTAVAIL; | 1251 | int err = -EADDRNOTAVAIL; |
| 1251 | 1252 | ||
| 1252 | rcu_read_lock(); | 1253 | rcu_read_lock(); |
| 1253 | if ((idev = __in6_dev_get(dev)) != NULL) { | 1254 | idev = __in6_dev_get(dev); |
| 1255 | if (idev) { | ||
| 1254 | struct inet6_ifaddr *ifp; | 1256 | struct inet6_ifaddr *ifp; |
| 1255 | 1257 | ||
| 1256 | read_lock_bh(&idev->lock); | 1258 | read_lock_bh(&idev->lock); |
| 1257 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | 1259 | list_for_each_entry(ifp, &idev->addr_list, if_list) { |
| 1258 | if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { | 1260 | if (ifp->scope == IFA_LINK && |
| 1261 | !(ifp->flags & banned_flags)) { | ||
| 1259 | ipv6_addr_copy(addr, &ifp->addr); | 1262 | ipv6_addr_copy(addr, &ifp->addr); |
| 1260 | err = 0; | 1263 | err = 0; |
| 1261 | break; | 1264 | break; |
| @@ -1273,7 +1276,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
| 1273 | struct inet6_ifaddr *ifp; | 1276 | struct inet6_ifaddr *ifp; |
| 1274 | 1277 | ||
| 1275 | read_lock_bh(&idev->lock); | 1278 | read_lock_bh(&idev->lock); |
| 1276 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) | 1279 | list_for_each_entry(ifp, &idev->addr_list, if_list) |
| 1277 | cnt++; | 1280 | cnt++; |
| 1278 | read_unlock_bh(&idev->lock); | 1281 | read_unlock_bh(&idev->lock); |
| 1279 | return cnt; | 1282 | return cnt; |
| @@ -1282,41 +1285,44 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
| 1282 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, | 1285 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, |
| 1283 | struct net_device *dev, int strict) | 1286 | struct net_device *dev, int strict) |
| 1284 | { | 1287 | { |
| 1285 | struct inet6_ifaddr * ifp; | 1288 | struct inet6_ifaddr *ifp; |
| 1286 | u8 hash = ipv6_addr_hash(addr); | 1289 | struct hlist_node *node; |
| 1290 | unsigned int hash = ipv6_addr_hash(addr); | ||
| 1287 | 1291 | ||
| 1288 | read_lock_bh(&addrconf_hash_lock); | 1292 | rcu_read_lock_bh(); |
| 1289 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1293 | hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1290 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1294 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1291 | continue; | 1295 | continue; |
| 1292 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1296 | if (ipv6_addr_equal(&ifp->addr, addr) && |
| 1293 | !(ifp->flags&IFA_F_TENTATIVE)) { | 1297 | !(ifp->flags&IFA_F_TENTATIVE) && |
| 1294 | if (dev == NULL || ifp->idev->dev == dev || | 1298 | (dev == NULL || ifp->idev->dev == dev || |
| 1295 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) | 1299 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { |
| 1296 | break; | 1300 | rcu_read_unlock_bh(); |
| 1301 | return 1; | ||
| 1297 | } | 1302 | } |
| 1298 | } | 1303 | } |
| 1299 | read_unlock_bh(&addrconf_hash_lock); | 1304 | |
| 1300 | return ifp != NULL; | 1305 | rcu_read_unlock_bh(); |
| 1306 | return 0; | ||
| 1301 | } | 1307 | } |
| 1302 | EXPORT_SYMBOL(ipv6_chk_addr); | 1308 | EXPORT_SYMBOL(ipv6_chk_addr); |
| 1303 | 1309 | ||
| 1304 | static | 1310 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, |
| 1305 | int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | 1311 | struct net_device *dev) |
| 1306 | struct net_device *dev) | ||
| 1307 | { | 1312 | { |
| 1308 | struct inet6_ifaddr * ifp; | 1313 | unsigned int hash = ipv6_addr_hash(addr); |
| 1309 | u8 hash = ipv6_addr_hash(addr); | 1314 | struct inet6_ifaddr *ifp; |
| 1315 | struct hlist_node *node; | ||
| 1310 | 1316 | ||
| 1311 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1317 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1312 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1318 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1313 | continue; | 1319 | continue; |
| 1314 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1320 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
| 1315 | if (dev == NULL || ifp->idev->dev == dev) | 1321 | if (dev == NULL || ifp->idev->dev == dev) |
| 1316 | break; | 1322 | return true; |
| 1317 | } | 1323 | } |
| 1318 | } | 1324 | } |
| 1319 | return ifp != NULL; | 1325 | return false; |
| 1320 | } | 1326 | } |
| 1321 | 1327 | ||
| 1322 | int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) | 1328 | int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) |
| @@ -1330,7 +1336,7 @@ int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) | |||
| 1330 | idev = __in6_dev_get(dev); | 1336 | idev = __in6_dev_get(dev); |
| 1331 | if (idev) { | 1337 | if (idev) { |
| 1332 | read_lock_bh(&idev->lock); | 1338 | read_lock_bh(&idev->lock); |
| 1333 | for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { | 1339 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
| 1334 | onlink = ipv6_prefix_equal(addr, &ifa->addr, | 1340 | onlink = ipv6_prefix_equal(addr, &ifa->addr, |
| 1335 | ifa->prefix_len); | 1341 | ifa->prefix_len); |
| 1336 | if (onlink) | 1342 | if (onlink) |
| @@ -1347,24 +1353,26 @@ EXPORT_SYMBOL(ipv6_chk_prefix); | |||
| 1347 | struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, | 1353 | struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, |
| 1348 | struct net_device *dev, int strict) | 1354 | struct net_device *dev, int strict) |
| 1349 | { | 1355 | { |
| 1350 | struct inet6_ifaddr * ifp; | 1356 | struct inet6_ifaddr *ifp, *result = NULL; |
| 1351 | u8 hash = ipv6_addr_hash(addr); | 1357 | unsigned int hash = ipv6_addr_hash(addr); |
| 1358 | struct hlist_node *node; | ||
| 1352 | 1359 | ||
| 1353 | read_lock_bh(&addrconf_hash_lock); | 1360 | rcu_read_lock_bh(); |
| 1354 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1361 | hlist_for_each_entry_rcu_bh(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1355 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1362 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1356 | continue; | 1363 | continue; |
| 1357 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1364 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
| 1358 | if (dev == NULL || ifp->idev->dev == dev || | 1365 | if (dev == NULL || ifp->idev->dev == dev || |
| 1359 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { | 1366 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { |
| 1367 | result = ifp; | ||
| 1360 | in6_ifa_hold(ifp); | 1368 | in6_ifa_hold(ifp); |
| 1361 | break; | 1369 | break; |
| 1362 | } | 1370 | } |
| 1363 | } | 1371 | } |
| 1364 | } | 1372 | } |
| 1365 | read_unlock_bh(&addrconf_hash_lock); | 1373 | rcu_read_unlock_bh(); |
| 1366 | 1374 | ||
| 1367 | return ifp; | 1375 | return result; |
| 1368 | } | 1376 | } |
| 1369 | 1377 | ||
| 1370 | /* Gets referenced address, destroys ifaddr */ | 1378 | /* Gets referenced address, destroys ifaddr */ |
| @@ -1378,6 +1386,8 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) | |||
| 1378 | if (dad_failed) | 1386 | if (dad_failed) |
| 1379 | ifp->flags |= IFA_F_DADFAILED; | 1387 | ifp->flags |= IFA_F_DADFAILED; |
| 1380 | spin_unlock_bh(&ifp->lock); | 1388 | spin_unlock_bh(&ifp->lock); |
| 1389 | if (dad_failed) | ||
| 1390 | ipv6_ifa_notify(0, ifp); | ||
| 1381 | in6_ifa_put(ifp); | 1391 | in6_ifa_put(ifp); |
| 1382 | #ifdef CONFIG_IPV6_PRIVACY | 1392 | #ifdef CONFIG_IPV6_PRIVACY |
| 1383 | } else if (ifp->flags&IFA_F_TEMPORARY) { | 1393 | } else if (ifp->flags&IFA_F_TEMPORARY) { |
| @@ -1398,10 +1408,27 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) | |||
| 1398 | ipv6_del_addr(ifp); | 1408 | ipv6_del_addr(ifp); |
| 1399 | } | 1409 | } |
| 1400 | 1410 | ||
| 1411 | static int addrconf_dad_end(struct inet6_ifaddr *ifp) | ||
| 1412 | { | ||
| 1413 | int err = -ENOENT; | ||
| 1414 | |||
| 1415 | spin_lock(&ifp->state_lock); | ||
| 1416 | if (ifp->state == INET6_IFADDR_STATE_DAD) { | ||
| 1417 | ifp->state = INET6_IFADDR_STATE_POSTDAD; | ||
| 1418 | err = 0; | ||
| 1419 | } | ||
| 1420 | spin_unlock(&ifp->state_lock); | ||
| 1421 | |||
| 1422 | return err; | ||
| 1423 | } | ||
| 1424 | |||
| 1401 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1425 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
| 1402 | { | 1426 | { |
| 1403 | struct inet6_dev *idev = ifp->idev; | 1427 | struct inet6_dev *idev = ifp->idev; |
| 1404 | 1428 | ||
| 1429 | if (addrconf_dad_end(ifp)) | ||
| 1430 | return; | ||
| 1431 | |||
| 1405 | if (net_ratelimit()) | 1432 | if (net_ratelimit()) |
| 1406 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", | 1433 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", |
| 1407 | ifp->idev->dev->name, &ifp->addr); | 1434 | ifp->idev->dev->name, &ifp->addr); |
| @@ -1565,7 +1592,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
| 1565 | struct inet6_ifaddr *ifp; | 1592 | struct inet6_ifaddr *ifp; |
| 1566 | 1593 | ||
| 1567 | read_lock_bh(&idev->lock); | 1594 | read_lock_bh(&idev->lock); |
| 1568 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | 1595 | list_for_each_entry(ifp, &idev->addr_list, if_list) { |
| 1569 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { | 1596 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { |
| 1570 | memcpy(eui, ifp->addr.s6_addr+8, 8); | 1597 | memcpy(eui, ifp->addr.s6_addr+8, 8); |
| 1571 | err = 0; | 1598 | err = 0; |
| @@ -1625,7 +1652,8 @@ static void ipv6_regen_rndid(unsigned long data) | |||
| 1625 | 1652 | ||
| 1626 | expires = jiffies + | 1653 | expires = jiffies + |
| 1627 | idev->cnf.temp_prefered_lft * HZ - | 1654 | idev->cnf.temp_prefered_lft * HZ - |
| 1628 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor; | 1655 | idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - |
| 1656 | idev->cnf.max_desync_factor * HZ; | ||
| 1629 | if (time_before(expires, jiffies)) { | 1657 | if (time_before(expires, jiffies)) { |
| 1630 | printk(KERN_WARNING | 1658 | printk(KERN_WARNING |
| 1631 | "ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n", | 1659 | "ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n", |
| @@ -1733,8 +1761,12 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) | |||
| 1733 | 1761 | ||
| 1734 | ASSERT_RTNL(); | 1762 | ASSERT_RTNL(); |
| 1735 | 1763 | ||
| 1736 | if ((idev = ipv6_find_idev(dev)) == NULL) | 1764 | idev = ipv6_find_idev(dev); |
| 1737 | return NULL; | 1765 | if (!idev) |
| 1766 | return ERR_PTR(-ENOBUFS); | ||
| 1767 | |||
| 1768 | if (idev->cnf.disable_ipv6) | ||
| 1769 | return ERR_PTR(-EACCES); | ||
| 1738 | 1770 | ||
| 1739 | /* Add default multicast route */ | 1771 | /* Add default multicast route */ |
| 1740 | addrconf_add_mroute(dev); | 1772 | addrconf_add_mroute(dev); |
| @@ -1837,7 +1869,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
| 1837 | dev, expires, flags); | 1869 | dev, expires, flags); |
| 1838 | } | 1870 | } |
| 1839 | if (rt) | 1871 | if (rt) |
| 1840 | dst_release(&rt->u.dst); | 1872 | dst_release(&rt->dst); |
| 1841 | } | 1873 | } |
| 1842 | 1874 | ||
| 1843 | /* Try to figure out our local address for this prefix */ | 1875 | /* Try to figure out our local address for this prefix */ |
| @@ -1966,7 +1998,7 @@ ok: | |||
| 1966 | #ifdef CONFIG_IPV6_PRIVACY | 1998 | #ifdef CONFIG_IPV6_PRIVACY |
| 1967 | read_lock_bh(&in6_dev->lock); | 1999 | read_lock_bh(&in6_dev->lock); |
| 1968 | /* update all temporary addresses in the list */ | 2000 | /* update all temporary addresses in the list */ |
| 1969 | for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) { | 2001 | list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) { |
| 1970 | /* | 2002 | /* |
| 1971 | * When adjusting the lifetimes of an existing | 2003 | * When adjusting the lifetimes of an existing |
| 1972 | * temporary address, only lower the lifetimes. | 2004 | * temporary address, only lower the lifetimes. |
| @@ -2103,8 +2135,9 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
| 2103 | if (!dev) | 2135 | if (!dev) |
| 2104 | return -ENODEV; | 2136 | return -ENODEV; |
| 2105 | 2137 | ||
| 2106 | if ((idev = addrconf_add_dev(dev)) == NULL) | 2138 | idev = addrconf_add_dev(dev); |
| 2107 | return -ENOBUFS; | 2139 | if (IS_ERR(idev)) |
| 2140 | return PTR_ERR(idev); | ||
| 2108 | 2141 | ||
| 2109 | scope = ipv6_addr_scope(pfx); | 2142 | scope = ipv6_addr_scope(pfx); |
| 2110 | 2143 | ||
| @@ -2169,7 +2202,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, | |||
| 2169 | return -ENXIO; | 2202 | return -ENXIO; |
| 2170 | 2203 | ||
| 2171 | read_lock_bh(&idev->lock); | 2204 | read_lock_bh(&idev->lock); |
| 2172 | for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { | 2205 | list_for_each_entry(ifp, &idev->addr_list, if_list) { |
| 2173 | if (ifp->prefix_len == plen && | 2206 | if (ifp->prefix_len == plen && |
| 2174 | ipv6_addr_equal(pfx, &ifp->addr)) { | 2207 | ipv6_addr_equal(pfx, &ifp->addr)) { |
| 2175 | in6_ifa_hold(ifp); | 2208 | in6_ifa_hold(ifp); |
| @@ -2180,7 +2213,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, | |||
| 2180 | /* If the last address is deleted administratively, | 2213 | /* If the last address is deleted administratively, |
| 2181 | disable IPv6 on this interface. | 2214 | disable IPv6 on this interface. |
| 2182 | */ | 2215 | */ |
| 2183 | if (idev->addr_list == NULL) | 2216 | if (list_empty(&idev->addr_list)) |
| 2184 | addrconf_ifdown(idev->dev, 1); | 2217 | addrconf_ifdown(idev->dev, 1); |
| 2185 | return 0; | 2218 | return 0; |
| 2186 | } | 2219 | } |
| @@ -2351,7 +2384,7 @@ static void addrconf_dev_config(struct net_device *dev) | |||
| 2351 | } | 2384 | } |
| 2352 | 2385 | ||
| 2353 | idev = addrconf_add_dev(dev); | 2386 | idev = addrconf_add_dev(dev); |
| 2354 | if (idev == NULL) | 2387 | if (IS_ERR(idev)) |
| 2355 | return; | 2388 | return; |
| 2356 | 2389 | ||
| 2357 | memset(&addr, 0, sizeof(struct in6_addr)); | 2390 | memset(&addr, 0, sizeof(struct in6_addr)); |
| @@ -2441,7 +2474,8 @@ static void addrconf_ip6_tnl_config(struct net_device *dev) | |||
| 2441 | 2474 | ||
| 2442 | ASSERT_RTNL(); | 2475 | ASSERT_RTNL(); |
| 2443 | 2476 | ||
| 2444 | if ((idev = addrconf_add_dev(dev)) == NULL) { | 2477 | idev = addrconf_add_dev(dev); |
| 2478 | if (IS_ERR(idev)) { | ||
| 2445 | printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n"); | 2479 | printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n"); |
| 2446 | return; | 2480 | return; |
| 2447 | } | 2481 | } |
| @@ -2456,7 +2490,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2456 | int run_pending = 0; | 2490 | int run_pending = 0; |
| 2457 | int err; | 2491 | int err; |
| 2458 | 2492 | ||
| 2459 | switch(event) { | 2493 | switch (event) { |
| 2460 | case NETDEV_REGISTER: | 2494 | case NETDEV_REGISTER: |
| 2461 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { | 2495 | if (!idev && dev->mtu >= IPV6_MIN_MTU) { |
| 2462 | idev = ipv6_add_dev(dev); | 2496 | idev = ipv6_add_dev(dev); |
| @@ -2464,6 +2498,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2464 | return notifier_from_errno(-ENOMEM); | 2498 | return notifier_from_errno(-ENOMEM); |
| 2465 | } | 2499 | } |
| 2466 | break; | 2500 | break; |
| 2501 | |||
| 2467 | case NETDEV_UP: | 2502 | case NETDEV_UP: |
| 2468 | case NETDEV_CHANGE: | 2503 | case NETDEV_CHANGE: |
| 2469 | if (dev->flags & IFF_SLAVE) | 2504 | if (dev->flags & IFF_SLAVE) |
| @@ -2493,10 +2528,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2493 | } | 2528 | } |
| 2494 | 2529 | ||
| 2495 | if (idev) { | 2530 | if (idev) { |
| 2496 | if (idev->if_flags & IF_READY) { | 2531 | if (idev->if_flags & IF_READY) |
| 2497 | /* device is already configured. */ | 2532 | /* device is already configured. */ |
| 2498 | break; | 2533 | break; |
| 2499 | } | ||
| 2500 | idev->if_flags |= IF_READY; | 2534 | idev->if_flags |= IF_READY; |
| 2501 | } | 2535 | } |
| 2502 | 2536 | ||
| @@ -2508,7 +2542,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2508 | run_pending = 1; | 2542 | run_pending = 1; |
| 2509 | } | 2543 | } |
| 2510 | 2544 | ||
| 2511 | switch(dev->type) { | 2545 | switch (dev->type) { |
| 2512 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) | 2546 | #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) |
| 2513 | case ARPHRD_SIT: | 2547 | case ARPHRD_SIT: |
| 2514 | addrconf_sit_config(dev); | 2548 | addrconf_sit_config(dev); |
| @@ -2525,25 +2559,30 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2525 | addrconf_dev_config(dev); | 2559 | addrconf_dev_config(dev); |
| 2526 | break; | 2560 | break; |
| 2527 | } | 2561 | } |
| 2562 | |||
| 2528 | if (idev) { | 2563 | if (idev) { |
| 2529 | if (run_pending) | 2564 | if (run_pending) |
| 2530 | addrconf_dad_run(idev); | 2565 | addrconf_dad_run(idev); |
| 2531 | 2566 | ||
| 2532 | /* If the MTU changed during the interface down, when the | 2567 | /* |
| 2533 | interface up, the changed MTU must be reflected in the | 2568 | * If the MTU changed during the interface down, |
| 2534 | idev as well as routers. | 2569 | * when the interface up, the changed MTU must be |
| 2570 | * reflected in the idev as well as routers. | ||
| 2535 | */ | 2571 | */ |
| 2536 | if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) { | 2572 | if (idev->cnf.mtu6 != dev->mtu && |
| 2573 | dev->mtu >= IPV6_MIN_MTU) { | ||
| 2537 | rt6_mtu_change(dev, dev->mtu); | 2574 | rt6_mtu_change(dev, dev->mtu); |
| 2538 | idev->cnf.mtu6 = dev->mtu; | 2575 | idev->cnf.mtu6 = dev->mtu; |
| 2539 | } | 2576 | } |
| 2540 | idev->tstamp = jiffies; | 2577 | idev->tstamp = jiffies; |
| 2541 | inet6_ifinfo_notify(RTM_NEWLINK, idev); | 2578 | inet6_ifinfo_notify(RTM_NEWLINK, idev); |
| 2542 | /* If the changed mtu during down is lower than IPV6_MIN_MTU | 2579 | |
| 2543 | stop IPv6 on this interface. | 2580 | /* |
| 2581 | * If the changed mtu during down is lower than | ||
| 2582 | * IPV6_MIN_MTU stop IPv6 on this interface. | ||
| 2544 | */ | 2583 | */ |
| 2545 | if (dev->mtu < IPV6_MIN_MTU) | 2584 | if (dev->mtu < IPV6_MIN_MTU) |
| 2546 | addrconf_ifdown(dev, event != NETDEV_DOWN); | 2585 | addrconf_ifdown(dev, 1); |
| 2547 | } | 2586 | } |
| 2548 | break; | 2587 | break; |
| 2549 | 2588 | ||
| @@ -2560,7 +2599,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2560 | break; | 2599 | break; |
| 2561 | } | 2600 | } |
| 2562 | 2601 | ||
| 2563 | /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */ | 2602 | /* |
| 2603 | * MTU falled under IPV6_MIN_MTU. | ||
| 2604 | * Stop IPv6 on this interface. | ||
| 2605 | */ | ||
| 2564 | 2606 | ||
| 2565 | case NETDEV_DOWN: | 2607 | case NETDEV_DOWN: |
| 2566 | case NETDEV_UNREGISTER: | 2608 | case NETDEV_UNREGISTER: |
| @@ -2580,9 +2622,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2580 | return notifier_from_errno(err); | 2622 | return notifier_from_errno(err); |
| 2581 | } | 2623 | } |
| 2582 | break; | 2624 | break; |
| 2583 | case NETDEV_BONDING_OLDTYPE: | 2625 | |
| 2584 | case NETDEV_BONDING_NEWTYPE: | 2626 | case NETDEV_PRE_TYPE_CHANGE: |
| 2585 | addrconf_bonding_change(dev, event); | 2627 | case NETDEV_POST_TYPE_CHANGE: |
| 2628 | addrconf_type_change(dev, event); | ||
| 2586 | break; | 2629 | break; |
| 2587 | } | 2630 | } |
| 2588 | 2631 | ||
| @@ -2594,28 +2637,28 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
| 2594 | */ | 2637 | */ |
| 2595 | static struct notifier_block ipv6_dev_notf = { | 2638 | static struct notifier_block ipv6_dev_notf = { |
| 2596 | .notifier_call = addrconf_notify, | 2639 | .notifier_call = addrconf_notify, |
| 2597 | .priority = 0 | ||
| 2598 | }; | 2640 | }; |
| 2599 | 2641 | ||
| 2600 | static void addrconf_bonding_change(struct net_device *dev, unsigned long event) | 2642 | static void addrconf_type_change(struct net_device *dev, unsigned long event) |
| 2601 | { | 2643 | { |
| 2602 | struct inet6_dev *idev; | 2644 | struct inet6_dev *idev; |
| 2603 | ASSERT_RTNL(); | 2645 | ASSERT_RTNL(); |
| 2604 | 2646 | ||
| 2605 | idev = __in6_dev_get(dev); | 2647 | idev = __in6_dev_get(dev); |
| 2606 | 2648 | ||
| 2607 | if (event == NETDEV_BONDING_NEWTYPE) | 2649 | if (event == NETDEV_POST_TYPE_CHANGE) |
| 2608 | ipv6_mc_remap(idev); | 2650 | ipv6_mc_remap(idev); |
| 2609 | else if (event == NETDEV_BONDING_OLDTYPE) | 2651 | else if (event == NETDEV_PRE_TYPE_CHANGE) |
| 2610 | ipv6_mc_unmap(idev); | 2652 | ipv6_mc_unmap(idev); |
| 2611 | } | 2653 | } |
| 2612 | 2654 | ||
| 2613 | static int addrconf_ifdown(struct net_device *dev, int how) | 2655 | static int addrconf_ifdown(struct net_device *dev, int how) |
| 2614 | { | 2656 | { |
| 2615 | struct inet6_dev *idev; | ||
| 2616 | struct inet6_ifaddr *ifa, **bifa; | ||
| 2617 | struct net *net = dev_net(dev); | 2657 | struct net *net = dev_net(dev); |
| 2618 | int i; | 2658 | struct inet6_dev *idev; |
| 2659 | struct inet6_ifaddr *ifa; | ||
| 2660 | LIST_HEAD(keep_list); | ||
| 2661 | int state; | ||
| 2619 | 2662 | ||
| 2620 | ASSERT_RTNL(); | 2663 | ASSERT_RTNL(); |
| 2621 | 2664 | ||
| @@ -2626,8 +2669,9 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2626 | if (idev == NULL) | 2669 | if (idev == NULL) |
| 2627 | return -ENODEV; | 2670 | return -ENODEV; |
| 2628 | 2671 | ||
| 2629 | /* Step 1: remove reference to ipv6 device from parent device. | 2672 | /* |
| 2630 | Do not dev_put! | 2673 | * Step 1: remove reference to ipv6 device from parent device. |
| 2674 | * Do not dev_put! | ||
| 2631 | */ | 2675 | */ |
| 2632 | if (how) { | 2676 | if (how) { |
| 2633 | idev->dead = 1; | 2677 | idev->dead = 1; |
| @@ -2640,40 +2684,21 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2640 | 2684 | ||
| 2641 | } | 2685 | } |
| 2642 | 2686 | ||
| 2643 | /* Step 2: clear hash table */ | ||
| 2644 | for (i=0; i<IN6_ADDR_HSIZE; i++) { | ||
| 2645 | bifa = &inet6_addr_lst[i]; | ||
| 2646 | |||
| 2647 | write_lock_bh(&addrconf_hash_lock); | ||
| 2648 | while ((ifa = *bifa) != NULL) { | ||
| 2649 | if (ifa->idev == idev) { | ||
| 2650 | *bifa = ifa->lst_next; | ||
| 2651 | ifa->lst_next = NULL; | ||
| 2652 | addrconf_del_timer(ifa); | ||
| 2653 | in6_ifa_put(ifa); | ||
| 2654 | continue; | ||
| 2655 | } | ||
| 2656 | bifa = &ifa->lst_next; | ||
| 2657 | } | ||
| 2658 | write_unlock_bh(&addrconf_hash_lock); | ||
| 2659 | } | ||
| 2660 | |||
| 2661 | write_lock_bh(&idev->lock); | 2687 | write_lock_bh(&idev->lock); |
| 2662 | 2688 | ||
| 2663 | /* Step 3: clear flags for stateless addrconf */ | 2689 | /* Step 2: clear flags for stateless addrconf */ |
| 2664 | if (!how) | 2690 | if (!how) |
| 2665 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); | 2691 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); |
| 2666 | 2692 | ||
| 2667 | /* Step 4: clear address list */ | ||
| 2668 | #ifdef CONFIG_IPV6_PRIVACY | 2693 | #ifdef CONFIG_IPV6_PRIVACY |
| 2669 | if (how && del_timer(&idev->regen_timer)) | 2694 | if (how && del_timer(&idev->regen_timer)) |
| 2670 | in6_dev_put(idev); | 2695 | in6_dev_put(idev); |
| 2671 | 2696 | ||
| 2672 | /* clear tempaddr list */ | 2697 | /* Step 3: clear tempaddr list */ |
| 2673 | while ((ifa = idev->tempaddr_list) != NULL) { | 2698 | while (!list_empty(&idev->tempaddr_list)) { |
| 2674 | idev->tempaddr_list = ifa->tmp_next; | 2699 | ifa = list_first_entry(&idev->tempaddr_list, |
| 2675 | ifa->tmp_next = NULL; | 2700 | struct inet6_ifaddr, tmp_list); |
| 2676 | ifa->dead = 1; | 2701 | list_del(&ifa->tmp_list); |
| 2677 | write_unlock_bh(&idev->lock); | 2702 | write_unlock_bh(&idev->lock); |
| 2678 | spin_lock_bh(&ifa->lock); | 2703 | spin_lock_bh(&ifa->lock); |
| 2679 | 2704 | ||
| @@ -2686,23 +2711,70 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2686 | write_lock_bh(&idev->lock); | 2711 | write_lock_bh(&idev->lock); |
| 2687 | } | 2712 | } |
| 2688 | #endif | 2713 | #endif |
| 2689 | while ((ifa = idev->addr_list) != NULL) { | 2714 | |
| 2690 | idev->addr_list = ifa->if_next; | 2715 | while (!list_empty(&idev->addr_list)) { |
| 2691 | ifa->if_next = NULL; | 2716 | ifa = list_first_entry(&idev->addr_list, |
| 2692 | ifa->dead = 1; | 2717 | struct inet6_ifaddr, if_list); |
| 2693 | addrconf_del_timer(ifa); | 2718 | addrconf_del_timer(ifa); |
| 2694 | write_unlock_bh(&idev->lock); | 2719 | |
| 2720 | /* If just doing link down, and address is permanent | ||
| 2721 | and not link-local, then retain it. */ | ||
| 2722 | if (!how && | ||
| 2723 | (ifa->flags&IFA_F_PERMANENT) && | ||
| 2724 | !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
| 2725 | list_move_tail(&ifa->if_list, &keep_list); | ||
| 2726 | |||
| 2727 | /* If not doing DAD on this address, just keep it. */ | ||
| 2728 | if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
| 2729 | idev->cnf.accept_dad <= 0 || | ||
| 2730 | (ifa->flags & IFA_F_NODAD)) | ||
| 2731 | continue; | ||
| 2732 | |||
| 2733 | /* If it was tentative already, no need to notify */ | ||
| 2734 | if (ifa->flags & IFA_F_TENTATIVE) | ||
| 2735 | continue; | ||
| 2736 | |||
| 2737 | /* Flag it for later restoration when link comes up */ | ||
| 2738 | ifa->flags |= IFA_F_TENTATIVE; | ||
| 2739 | ifa->state = INET6_IFADDR_STATE_DAD; | ||
| 2740 | |||
| 2741 | write_unlock_bh(&idev->lock); | ||
| 2742 | |||
| 2743 | in6_ifa_hold(ifa); | ||
| 2744 | } else { | ||
| 2745 | list_del(&ifa->if_list); | ||
| 2746 | |||
| 2747 | /* clear hash table */ | ||
| 2748 | spin_lock_bh(&addrconf_hash_lock); | ||
| 2749 | hlist_del_init_rcu(&ifa->addr_lst); | ||
| 2750 | spin_unlock_bh(&addrconf_hash_lock); | ||
| 2751 | |||
| 2752 | write_unlock_bh(&idev->lock); | ||
| 2753 | spin_lock_bh(&ifa->state_lock); | ||
| 2754 | state = ifa->state; | ||
| 2755 | ifa->state = INET6_IFADDR_STATE_DEAD; | ||
| 2756 | spin_unlock_bh(&ifa->state_lock); | ||
| 2757 | |||
| 2758 | if (state == INET6_IFADDR_STATE_DEAD) | ||
| 2759 | goto put_ifa; | ||
| 2760 | } | ||
| 2695 | 2761 | ||
| 2696 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2762 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
| 2697 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | 2763 | if (ifa->state == INET6_IFADDR_STATE_DEAD) |
| 2764 | atomic_notifier_call_chain(&inet6addr_chain, | ||
| 2765 | NETDEV_DOWN, ifa); | ||
| 2766 | |||
| 2767 | put_ifa: | ||
| 2698 | in6_ifa_put(ifa); | 2768 | in6_ifa_put(ifa); |
| 2699 | 2769 | ||
| 2700 | write_lock_bh(&idev->lock); | 2770 | write_lock_bh(&idev->lock); |
| 2701 | } | 2771 | } |
| 2772 | |||
| 2773 | list_splice(&keep_list, &idev->addr_list); | ||
| 2774 | |||
| 2702 | write_unlock_bh(&idev->lock); | 2775 | write_unlock_bh(&idev->lock); |
| 2703 | 2776 | ||
| 2704 | /* Step 5: Discard multicast list */ | 2777 | /* Step 5: Discard multicast list */ |
| 2705 | |||
| 2706 | if (how) | 2778 | if (how) |
| 2707 | ipv6_mc_destroy_dev(idev); | 2779 | ipv6_mc_destroy_dev(idev); |
| 2708 | else | 2780 | else |
| @@ -2710,8 +2782,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2710 | 2782 | ||
| 2711 | idev->tstamp = jiffies; | 2783 | idev->tstamp = jiffies; |
| 2712 | 2784 | ||
| 2713 | /* Shot the device (if unregistered) */ | 2785 | /* Last: Shot the device (if unregistered) */ |
| 2714 | |||
| 2715 | if (how) { | 2786 | if (how) { |
| 2716 | addrconf_sysctl_unregister(idev); | 2787 | addrconf_sysctl_unregister(idev); |
| 2717 | neigh_parms_release(&nd_tbl, idev->nd_parms); | 2788 | neigh_parms_release(&nd_tbl, idev->nd_parms); |
| @@ -2724,28 +2795,29 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2724 | static void addrconf_rs_timer(unsigned long data) | 2795 | static void addrconf_rs_timer(unsigned long data) |
| 2725 | { | 2796 | { |
| 2726 | struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; | 2797 | struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; |
| 2798 | struct inet6_dev *idev = ifp->idev; | ||
| 2727 | 2799 | ||
| 2728 | if (ifp->idev->cnf.forwarding) | 2800 | read_lock(&idev->lock); |
| 2801 | if (idev->dead || !(idev->if_flags & IF_READY)) | ||
| 2729 | goto out; | 2802 | goto out; |
| 2730 | 2803 | ||
| 2731 | if (ifp->idev->if_flags & IF_RA_RCVD) { | 2804 | if (idev->cnf.forwarding) |
| 2732 | /* | 2805 | goto out; |
| 2733 | * Announcement received after solicitation | 2806 | |
| 2734 | * was sent | 2807 | /* Announcement received after solicitation was sent */ |
| 2735 | */ | 2808 | if (idev->if_flags & IF_RA_RCVD) |
| 2736 | goto out; | 2809 | goto out; |
| 2737 | } | ||
| 2738 | 2810 | ||
| 2739 | spin_lock(&ifp->lock); | 2811 | spin_lock(&ifp->lock); |
| 2740 | if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { | 2812 | if (ifp->probes++ < idev->cnf.rtr_solicits) { |
| 2741 | /* The wait after the last probe can be shorter */ | 2813 | /* The wait after the last probe can be shorter */ |
| 2742 | addrconf_mod_timer(ifp, AC_RS, | 2814 | addrconf_mod_timer(ifp, AC_RS, |
| 2743 | (ifp->probes == ifp->idev->cnf.rtr_solicits) ? | 2815 | (ifp->probes == idev->cnf.rtr_solicits) ? |
| 2744 | ifp->idev->cnf.rtr_solicit_delay : | 2816 | idev->cnf.rtr_solicit_delay : |
| 2745 | ifp->idev->cnf.rtr_solicit_interval); | 2817 | idev->cnf.rtr_solicit_interval); |
| 2746 | spin_unlock(&ifp->lock); | 2818 | spin_unlock(&ifp->lock); |
| 2747 | 2819 | ||
| 2748 | ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); | 2820 | ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); |
| 2749 | } else { | 2821 | } else { |
| 2750 | spin_unlock(&ifp->lock); | 2822 | spin_unlock(&ifp->lock); |
| 2751 | /* | 2823 | /* |
| @@ -2753,10 +2825,11 @@ static void addrconf_rs_timer(unsigned long data) | |||
| 2753 | * assumption any longer. | 2825 | * assumption any longer. |
| 2754 | */ | 2826 | */ |
| 2755 | printk(KERN_DEBUG "%s: no IPv6 routers present\n", | 2827 | printk(KERN_DEBUG "%s: no IPv6 routers present\n", |
| 2756 | ifp->idev->dev->name); | 2828 | idev->dev->name); |
| 2757 | } | 2829 | } |
| 2758 | 2830 | ||
| 2759 | out: | 2831 | out: |
| 2832 | read_unlock(&idev->lock); | ||
| 2760 | in6_ifa_put(ifp); | 2833 | in6_ifa_put(ifp); |
| 2761 | } | 2834 | } |
| 2762 | 2835 | ||
| @@ -2787,16 +2860,16 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
| 2787 | net_srandom(ifp->addr.s6_addr32[3]); | 2860 | net_srandom(ifp->addr.s6_addr32[3]); |
| 2788 | 2861 | ||
| 2789 | read_lock_bh(&idev->lock); | 2862 | read_lock_bh(&idev->lock); |
| 2790 | if (ifp->dead) | 2863 | spin_lock(&ifp->lock); |
| 2864 | if (ifp->state == INET6_IFADDR_STATE_DEAD) | ||
| 2791 | goto out; | 2865 | goto out; |
| 2792 | spin_lock_bh(&ifp->lock); | ||
| 2793 | 2866 | ||
| 2794 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2867 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
| 2795 | idev->cnf.accept_dad < 1 || | 2868 | idev->cnf.accept_dad < 1 || |
| 2796 | !(ifp->flags&IFA_F_TENTATIVE) || | 2869 | !(ifp->flags&IFA_F_TENTATIVE) || |
| 2797 | ifp->flags & IFA_F_NODAD) { | 2870 | ifp->flags & IFA_F_NODAD) { |
| 2798 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2871 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
| 2799 | spin_unlock_bh(&ifp->lock); | 2872 | spin_unlock(&ifp->lock); |
| 2800 | read_unlock_bh(&idev->lock); | 2873 | read_unlock_bh(&idev->lock); |
| 2801 | 2874 | ||
| 2802 | addrconf_dad_completed(ifp); | 2875 | addrconf_dad_completed(ifp); |
| @@ -2804,7 +2877,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
| 2804 | } | 2877 | } |
| 2805 | 2878 | ||
| 2806 | if (!(idev->if_flags & IF_READY)) { | 2879 | if (!(idev->if_flags & IF_READY)) { |
| 2807 | spin_unlock_bh(&ifp->lock); | 2880 | spin_unlock(&ifp->lock); |
| 2808 | read_unlock_bh(&idev->lock); | 2881 | read_unlock_bh(&idev->lock); |
| 2809 | /* | 2882 | /* |
| 2810 | * If the device is not ready: | 2883 | * If the device is not ready: |
| @@ -2820,12 +2893,12 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
| 2820 | * Optimistic nodes can start receiving | 2893 | * Optimistic nodes can start receiving |
| 2821 | * Frames right away | 2894 | * Frames right away |
| 2822 | */ | 2895 | */ |
| 2823 | if(ifp->flags & IFA_F_OPTIMISTIC) | 2896 | if (ifp->flags & IFA_F_OPTIMISTIC) |
| 2824 | ip6_ins_rt(ifp->rt); | 2897 | ip6_ins_rt(ifp->rt); |
| 2825 | 2898 | ||
| 2826 | addrconf_dad_kick(ifp); | 2899 | addrconf_dad_kick(ifp); |
| 2827 | spin_unlock_bh(&ifp->lock); | ||
| 2828 | out: | 2900 | out: |
| 2901 | spin_unlock(&ifp->lock); | ||
| 2829 | read_unlock_bh(&idev->lock); | 2902 | read_unlock_bh(&idev->lock); |
| 2830 | } | 2903 | } |
| 2831 | 2904 | ||
| @@ -2835,20 +2908,30 @@ static void addrconf_dad_timer(unsigned long data) | |||
| 2835 | struct inet6_dev *idev = ifp->idev; | 2908 | struct inet6_dev *idev = ifp->idev; |
| 2836 | struct in6_addr mcaddr; | 2909 | struct in6_addr mcaddr; |
| 2837 | 2910 | ||
| 2838 | read_lock_bh(&idev->lock); | 2911 | if (!ifp->probes && addrconf_dad_end(ifp)) |
| 2839 | if (idev->dead) { | 2912 | goto out; |
| 2840 | read_unlock_bh(&idev->lock); | 2913 | |
| 2914 | read_lock(&idev->lock); | ||
| 2915 | if (idev->dead || !(idev->if_flags & IF_READY)) { | ||
| 2916 | read_unlock(&idev->lock); | ||
| 2841 | goto out; | 2917 | goto out; |
| 2842 | } | 2918 | } |
| 2843 | spin_lock_bh(&ifp->lock); | 2919 | |
| 2920 | spin_lock(&ifp->lock); | ||
| 2921 | if (ifp->state == INET6_IFADDR_STATE_DEAD) { | ||
| 2922 | spin_unlock(&ifp->lock); | ||
| 2923 | read_unlock(&idev->lock); | ||
| 2924 | goto out; | ||
| 2925 | } | ||
| 2926 | |||
| 2844 | if (ifp->probes == 0) { | 2927 | if (ifp->probes == 0) { |
| 2845 | /* | 2928 | /* |
| 2846 | * DAD was successful | 2929 | * DAD was successful |
| 2847 | */ | 2930 | */ |
| 2848 | 2931 | ||
| 2849 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2932 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
| 2850 | spin_unlock_bh(&ifp->lock); | 2933 | spin_unlock(&ifp->lock); |
| 2851 | read_unlock_bh(&idev->lock); | 2934 | read_unlock(&idev->lock); |
| 2852 | 2935 | ||
| 2853 | addrconf_dad_completed(ifp); | 2936 | addrconf_dad_completed(ifp); |
| 2854 | 2937 | ||
| @@ -2857,8 +2940,8 @@ static void addrconf_dad_timer(unsigned long data) | |||
| 2857 | 2940 | ||
| 2858 | ifp->probes--; | 2941 | ifp->probes--; |
| 2859 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); | 2942 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); |
| 2860 | spin_unlock_bh(&ifp->lock); | 2943 | spin_unlock(&ifp->lock); |
| 2861 | read_unlock_bh(&idev->lock); | 2944 | read_unlock(&idev->lock); |
| 2862 | 2945 | ||
| 2863 | /* send a neighbour solicitation for our addr */ | 2946 | /* send a neighbour solicitation for our addr */ |
| 2864 | addrconf_addr_solict_mult(&ifp->addr, &mcaddr); | 2947 | addrconf_addr_solict_mult(&ifp->addr, &mcaddr); |
| @@ -2869,7 +2952,7 @@ out: | |||
| 2869 | 2952 | ||
| 2870 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | 2953 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp) |
| 2871 | { | 2954 | { |
| 2872 | struct net_device * dev = ifp->idev->dev; | 2955 | struct net_device *dev = ifp->idev->dev; |
| 2873 | 2956 | ||
| 2874 | /* | 2957 | /* |
| 2875 | * Configure the address for reception. Now it is valid. | 2958 | * Configure the address for reception. Now it is valid. |
| @@ -2900,18 +2983,17 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
| 2900 | } | 2983 | } |
| 2901 | } | 2984 | } |
| 2902 | 2985 | ||
| 2903 | static void addrconf_dad_run(struct inet6_dev *idev) { | 2986 | static void addrconf_dad_run(struct inet6_dev *idev) |
| 2987 | { | ||
| 2904 | struct inet6_ifaddr *ifp; | 2988 | struct inet6_ifaddr *ifp; |
| 2905 | 2989 | ||
| 2906 | read_lock_bh(&idev->lock); | 2990 | read_lock_bh(&idev->lock); |
| 2907 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | 2991 | list_for_each_entry(ifp, &idev->addr_list, if_list) { |
| 2908 | spin_lock_bh(&ifp->lock); | 2992 | spin_lock(&ifp->lock); |
| 2909 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | 2993 | if (ifp->flags & IFA_F_TENTATIVE && |
| 2910 | spin_unlock_bh(&ifp->lock); | 2994 | ifp->state == INET6_IFADDR_STATE_DAD) |
| 2911 | continue; | 2995 | addrconf_dad_kick(ifp); |
| 2912 | } | 2996 | spin_unlock(&ifp->lock); |
| 2913 | spin_unlock_bh(&ifp->lock); | ||
| 2914 | addrconf_dad_kick(ifp); | ||
| 2915 | } | 2997 | } |
| 2916 | read_unlock_bh(&idev->lock); | 2998 | read_unlock_bh(&idev->lock); |
| 2917 | } | 2999 | } |
| @@ -2929,36 +3011,35 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) | |||
| 2929 | struct net *net = seq_file_net(seq); | 3011 | struct net *net = seq_file_net(seq); |
| 2930 | 3012 | ||
| 2931 | for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { | 3013 | for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { |
| 2932 | ifa = inet6_addr_lst[state->bucket]; | 3014 | struct hlist_node *n; |
| 2933 | 3015 | hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], | |
| 2934 | while (ifa && !net_eq(dev_net(ifa->idev->dev), net)) | 3016 | addr_lst) |
| 2935 | ifa = ifa->lst_next; | 3017 | if (net_eq(dev_net(ifa->idev->dev), net)) |
| 2936 | if (ifa) | 3018 | return ifa; |
| 2937 | break; | ||
| 2938 | } | 3019 | } |
| 2939 | return ifa; | 3020 | return NULL; |
| 2940 | } | 3021 | } |
| 2941 | 3022 | ||
| 2942 | static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa) | 3023 | static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, |
| 3024 | struct inet6_ifaddr *ifa) | ||
| 2943 | { | 3025 | { |
| 2944 | struct if6_iter_state *state = seq->private; | 3026 | struct if6_iter_state *state = seq->private; |
| 2945 | struct net *net = seq_file_net(seq); | 3027 | struct net *net = seq_file_net(seq); |
| 3028 | struct hlist_node *n = &ifa->addr_lst; | ||
| 2946 | 3029 | ||
| 2947 | ifa = ifa->lst_next; | 3030 | hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) |
| 2948 | try_again: | 3031 | if (net_eq(dev_net(ifa->idev->dev), net)) |
| 2949 | if (ifa) { | 3032 | return ifa; |
| 2950 | if (!net_eq(dev_net(ifa->idev->dev), net)) { | ||
| 2951 | ifa = ifa->lst_next; | ||
| 2952 | goto try_again; | ||
| 2953 | } | ||
| 2954 | } | ||
| 2955 | 3033 | ||
| 2956 | if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { | 3034 | while (++state->bucket < IN6_ADDR_HSIZE) { |
| 2957 | ifa = inet6_addr_lst[state->bucket]; | 3035 | hlist_for_each_entry_rcu_bh(ifa, n, |
| 2958 | goto try_again; | 3036 | &inet6_addr_lst[state->bucket], addr_lst) { |
| 3037 | if (net_eq(dev_net(ifa->idev->dev), net)) | ||
| 3038 | return ifa; | ||
| 3039 | } | ||
| 2959 | } | 3040 | } |
| 2960 | 3041 | ||
| 2961 | return ifa; | 3042 | return NULL; |
| 2962 | } | 3043 | } |
| 2963 | 3044 | ||
| 2964 | static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) | 3045 | static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) |
| @@ -2966,15 +3047,15 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) | |||
| 2966 | struct inet6_ifaddr *ifa = if6_get_first(seq); | 3047 | struct inet6_ifaddr *ifa = if6_get_first(seq); |
| 2967 | 3048 | ||
| 2968 | if (ifa) | 3049 | if (ifa) |
| 2969 | while(pos && (ifa = if6_get_next(seq, ifa)) != NULL) | 3050 | while (pos && (ifa = if6_get_next(seq, ifa)) != NULL) |
| 2970 | --pos; | 3051 | --pos; |
| 2971 | return pos ? NULL : ifa; | 3052 | return pos ? NULL : ifa; |
| 2972 | } | 3053 | } |
| 2973 | 3054 | ||
| 2974 | static void *if6_seq_start(struct seq_file *seq, loff_t *pos) | 3055 | static void *if6_seq_start(struct seq_file *seq, loff_t *pos) |
| 2975 | __acquires(addrconf_hash_lock) | 3056 | __acquires(rcu_bh) |
| 2976 | { | 3057 | { |
| 2977 | read_lock_bh(&addrconf_hash_lock); | 3058 | rcu_read_lock_bh(); |
| 2978 | return if6_get_idx(seq, *pos); | 3059 | return if6_get_idx(seq, *pos); |
| 2979 | } | 3060 | } |
| 2980 | 3061 | ||
| @@ -2988,9 +3069,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 2988 | } | 3069 | } |
| 2989 | 3070 | ||
| 2990 | static void if6_seq_stop(struct seq_file *seq, void *v) | 3071 | static void if6_seq_stop(struct seq_file *seq, void *v) |
| 2991 | __releases(addrconf_hash_lock) | 3072 | __releases(rcu_bh) |
| 2992 | { | 3073 | { |
| 2993 | read_unlock_bh(&addrconf_hash_lock); | 3074 | rcu_read_unlock_bh(); |
| 2994 | } | 3075 | } |
| 2995 | 3076 | ||
| 2996 | static int if6_seq_show(struct seq_file *seq, void *v) | 3077 | static int if6_seq_show(struct seq_file *seq, void *v) |
| @@ -3027,14 +3108,14 @@ static const struct file_operations if6_fops = { | |||
| 3027 | .release = seq_release_net, | 3108 | .release = seq_release_net, |
| 3028 | }; | 3109 | }; |
| 3029 | 3110 | ||
| 3030 | static int if6_proc_net_init(struct net *net) | 3111 | static int __net_init if6_proc_net_init(struct net *net) |
| 3031 | { | 3112 | { |
| 3032 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3113 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) |
| 3033 | return -ENOMEM; | 3114 | return -ENOMEM; |
| 3034 | return 0; | 3115 | return 0; |
| 3035 | } | 3116 | } |
| 3036 | 3117 | ||
| 3037 | static void if6_proc_net_exit(struct net *net) | 3118 | static void __net_exit if6_proc_net_exit(struct net *net) |
| 3038 | { | 3119 | { |
| 3039 | proc_net_remove(net, "if_inet6"); | 3120 | proc_net_remove(net, "if_inet6"); |
| 3040 | } | 3121 | } |
| @@ -3060,10 +3141,12 @@ void if6_proc_exit(void) | |||
| 3060 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | 3141 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) |
| 3061 | { | 3142 | { |
| 3062 | int ret = 0; | 3143 | int ret = 0; |
| 3063 | struct inet6_ifaddr * ifp; | 3144 | struct inet6_ifaddr *ifp = NULL; |
| 3064 | u8 hash = ipv6_addr_hash(addr); | 3145 | struct hlist_node *n; |
| 3065 | read_lock_bh(&addrconf_hash_lock); | 3146 | unsigned int hash = ipv6_addr_hash(addr); |
| 3066 | for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { | 3147 | |
| 3148 | rcu_read_lock_bh(); | ||
| 3149 | hlist_for_each_entry_rcu_bh(ifp, n, &inet6_addr_lst[hash], addr_lst) { | ||
| 3067 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 3150 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 3068 | continue; | 3151 | continue; |
| 3069 | if (ipv6_addr_equal(&ifp->addr, addr) && | 3152 | if (ipv6_addr_equal(&ifp->addr, addr) && |
| @@ -3072,7 +3155,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | |||
| 3072 | break; | 3155 | break; |
| 3073 | } | 3156 | } |
| 3074 | } | 3157 | } |
| 3075 | read_unlock_bh(&addrconf_hash_lock); | 3158 | rcu_read_unlock_bh(); |
| 3076 | return ret; | 3159 | return ret; |
| 3077 | } | 3160 | } |
| 3078 | #endif | 3161 | #endif |
| @@ -3083,43 +3166,35 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | |||
| 3083 | 3166 | ||
| 3084 | static void addrconf_verify(unsigned long foo) | 3167 | static void addrconf_verify(unsigned long foo) |
| 3085 | { | 3168 | { |
| 3169 | unsigned long now, next, next_sec, next_sched; | ||
| 3086 | struct inet6_ifaddr *ifp; | 3170 | struct inet6_ifaddr *ifp; |
| 3087 | unsigned long now, next; | 3171 | struct hlist_node *node; |
| 3088 | int i; | 3172 | int i; |
| 3089 | 3173 | ||
| 3090 | spin_lock_bh(&addrconf_verify_lock); | 3174 | rcu_read_lock_bh(); |
| 3175 | spin_lock(&addrconf_verify_lock); | ||
| 3091 | now = jiffies; | 3176 | now = jiffies; |
| 3092 | next = now + ADDR_CHECK_FREQUENCY; | 3177 | next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); |
| 3093 | 3178 | ||
| 3094 | del_timer(&addr_chk_timer); | 3179 | del_timer(&addr_chk_timer); |
| 3095 | 3180 | ||
| 3096 | for (i=0; i < IN6_ADDR_HSIZE; i++) { | 3181 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
| 3097 | |||
| 3098 | restart: | 3182 | restart: |
| 3099 | read_lock(&addrconf_hash_lock); | 3183 | hlist_for_each_entry_rcu_bh(ifp, node, |
| 3100 | for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { | 3184 | &inet6_addr_lst[i], addr_lst) { |
| 3101 | unsigned long age; | 3185 | unsigned long age; |
| 3102 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 3103 | unsigned long regen_advance; | ||
| 3104 | #endif | ||
| 3105 | 3186 | ||
| 3106 | if (ifp->flags & IFA_F_PERMANENT) | 3187 | if (ifp->flags & IFA_F_PERMANENT) |
| 3107 | continue; | 3188 | continue; |
| 3108 | 3189 | ||
| 3109 | spin_lock(&ifp->lock); | 3190 | spin_lock(&ifp->lock); |
| 3110 | age = (now - ifp->tstamp) / HZ; | 3191 | /* We try to batch several events at once. */ |
| 3111 | 3192 | age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; | |
| 3112 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 3113 | regen_advance = ifp->idev->cnf.regen_max_retry * | ||
| 3114 | ifp->idev->cnf.dad_transmits * | ||
| 3115 | ifp->idev->nd_parms->retrans_time / HZ; | ||
| 3116 | #endif | ||
| 3117 | 3193 | ||
| 3118 | if (ifp->valid_lft != INFINITY_LIFE_TIME && | 3194 | if (ifp->valid_lft != INFINITY_LIFE_TIME && |
| 3119 | age >= ifp->valid_lft) { | 3195 | age >= ifp->valid_lft) { |
| 3120 | spin_unlock(&ifp->lock); | 3196 | spin_unlock(&ifp->lock); |
| 3121 | in6_ifa_hold(ifp); | 3197 | in6_ifa_hold(ifp); |
| 3122 | read_unlock(&addrconf_hash_lock); | ||
| 3123 | ipv6_del_addr(ifp); | 3198 | ipv6_del_addr(ifp); |
| 3124 | goto restart; | 3199 | goto restart; |
| 3125 | } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { | 3200 | } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { |
| @@ -3141,7 +3216,6 @@ restart: | |||
| 3141 | 3216 | ||
| 3142 | if (deprecate) { | 3217 | if (deprecate) { |
| 3143 | in6_ifa_hold(ifp); | 3218 | in6_ifa_hold(ifp); |
| 3144 | read_unlock(&addrconf_hash_lock); | ||
| 3145 | 3219 | ||
| 3146 | ipv6_ifa_notify(0, ifp); | 3220 | ipv6_ifa_notify(0, ifp); |
| 3147 | in6_ifa_put(ifp); | 3221 | in6_ifa_put(ifp); |
| @@ -3150,6 +3224,10 @@ restart: | |||
| 3150 | #ifdef CONFIG_IPV6_PRIVACY | 3224 | #ifdef CONFIG_IPV6_PRIVACY |
| 3151 | } else if ((ifp->flags&IFA_F_TEMPORARY) && | 3225 | } else if ((ifp->flags&IFA_F_TEMPORARY) && |
| 3152 | !(ifp->flags&IFA_F_TENTATIVE)) { | 3226 | !(ifp->flags&IFA_F_TENTATIVE)) { |
| 3227 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * | ||
| 3228 | ifp->idev->cnf.dad_transmits * | ||
| 3229 | ifp->idev->nd_parms->retrans_time / HZ; | ||
| 3230 | |||
| 3153 | if (age >= ifp->prefered_lft - regen_advance) { | 3231 | if (age >= ifp->prefered_lft - regen_advance) { |
| 3154 | struct inet6_ifaddr *ifpub = ifp->ifpub; | 3232 | struct inet6_ifaddr *ifpub = ifp->ifpub; |
| 3155 | if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) | 3233 | if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) |
| @@ -3159,7 +3237,7 @@ restart: | |||
| 3159 | in6_ifa_hold(ifp); | 3237 | in6_ifa_hold(ifp); |
| 3160 | in6_ifa_hold(ifpub); | 3238 | in6_ifa_hold(ifpub); |
| 3161 | spin_unlock(&ifp->lock); | 3239 | spin_unlock(&ifp->lock); |
| 3162 | read_unlock(&addrconf_hash_lock); | 3240 | |
| 3163 | spin_lock(&ifpub->lock); | 3241 | spin_lock(&ifpub->lock); |
| 3164 | ifpub->regen_count = 0; | 3242 | ifpub->regen_count = 0; |
| 3165 | spin_unlock(&ifpub->lock); | 3243 | spin_unlock(&ifpub->lock); |
| @@ -3179,12 +3257,26 @@ restart: | |||
| 3179 | spin_unlock(&ifp->lock); | 3257 | spin_unlock(&ifp->lock); |
| 3180 | } | 3258 | } |
| 3181 | } | 3259 | } |
| 3182 | read_unlock(&addrconf_hash_lock); | ||
| 3183 | } | 3260 | } |
| 3184 | 3261 | ||
| 3185 | addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next; | 3262 | next_sec = round_jiffies_up(next); |
| 3263 | next_sched = next; | ||
| 3264 | |||
| 3265 | /* If rounded timeout is accurate enough, accept it. */ | ||
| 3266 | if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ)) | ||
| 3267 | next_sched = next_sec; | ||
| 3268 | |||
| 3269 | /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */ | ||
| 3270 | if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX)) | ||
| 3271 | next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX; | ||
| 3272 | |||
| 3273 | ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n", | ||
| 3274 | now, next, next_sec, next_sched)); | ||
| 3275 | |||
| 3276 | addr_chk_timer.expires = next_sched; | ||
| 3186 | add_timer(&addr_chk_timer); | 3277 | add_timer(&addr_chk_timer); |
| 3187 | spin_unlock_bh(&addrconf_verify_lock); | 3278 | spin_unlock(&addrconf_verify_lock); |
| 3279 | rcu_read_unlock_bh(); | ||
| 3188 | } | 3280 | } |
| 3189 | 3281 | ||
| 3190 | static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) | 3282 | static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) |
| @@ -3407,8 +3499,12 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | |||
| 3407 | preferred -= tval; | 3499 | preferred -= tval; |
| 3408 | else | 3500 | else |
| 3409 | preferred = 0; | 3501 | preferred = 0; |
| 3410 | if (valid != INFINITY_LIFE_TIME) | 3502 | if (valid != INFINITY_LIFE_TIME) { |
| 3411 | valid -= tval; | 3503 | if (valid > tval) |
| 3504 | valid -= tval; | ||
| 3505 | else | ||
| 3506 | valid = 0; | ||
| 3507 | } | ||
| 3412 | } | 3508 | } |
| 3413 | } else { | 3509 | } else { |
| 3414 | preferred = INFINITY_LIFE_TIME; | 3510 | preferred = INFINITY_LIFE_TIME; |
| @@ -3474,8 +3570,7 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | |||
| 3474 | return nlmsg_end(skb, nlh); | 3570 | return nlmsg_end(skb, nlh); |
| 3475 | } | 3571 | } |
| 3476 | 3572 | ||
| 3477 | enum addr_type_t | 3573 | enum addr_type_t { |
| 3478 | { | ||
| 3479 | UNICAST_ADDR, | 3574 | UNICAST_ADDR, |
| 3480 | MULTICAST_ADDR, | 3575 | MULTICAST_ADDR, |
| 3481 | ANYCAST_ADDR, | 3576 | ANYCAST_ADDR, |
| @@ -3486,7 +3581,6 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
| 3486 | struct netlink_callback *cb, enum addr_type_t type, | 3581 | struct netlink_callback *cb, enum addr_type_t type, |
| 3487 | int s_ip_idx, int *p_ip_idx) | 3582 | int s_ip_idx, int *p_ip_idx) |
| 3488 | { | 3583 | { |
| 3489 | struct inet6_ifaddr *ifa; | ||
| 3490 | struct ifmcaddr6 *ifmca; | 3584 | struct ifmcaddr6 *ifmca; |
| 3491 | struct ifacaddr6 *ifaca; | 3585 | struct ifacaddr6 *ifaca; |
| 3492 | int err = 1; | 3586 | int err = 1; |
| @@ -3494,11 +3588,12 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
| 3494 | 3588 | ||
| 3495 | read_lock_bh(&idev->lock); | 3589 | read_lock_bh(&idev->lock); |
| 3496 | switch (type) { | 3590 | switch (type) { |
| 3497 | case UNICAST_ADDR: | 3591 | case UNICAST_ADDR: { |
| 3592 | struct inet6_ifaddr *ifa; | ||
| 3593 | |||
| 3498 | /* unicast address incl. temp addr */ | 3594 | /* unicast address incl. temp addr */ |
| 3499 | for (ifa = idev->addr_list; ifa; | 3595 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
| 3500 | ifa = ifa->if_next, ip_idx++) { | 3596 | if (++ip_idx < s_ip_idx) |
| 3501 | if (ip_idx < s_ip_idx) | ||
| 3502 | continue; | 3597 | continue; |
| 3503 | err = inet6_fill_ifaddr(skb, ifa, | 3598 | err = inet6_fill_ifaddr(skb, ifa, |
| 3504 | NETLINK_CB(cb->skb).pid, | 3599 | NETLINK_CB(cb->skb).pid, |
| @@ -3509,6 +3604,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
| 3509 | break; | 3604 | break; |
| 3510 | } | 3605 | } |
| 3511 | break; | 3606 | break; |
| 3607 | } | ||
| 3512 | case MULTICAST_ADDR: | 3608 | case MULTICAST_ADDR: |
| 3513 | /* multicast address */ | 3609 | /* multicast address */ |
| 3514 | for (ifmca = idev->mc_list; ifmca; | 3610 | for (ifmca = idev->mc_list; ifmca; |
| @@ -3570,10 +3666,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 3570 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { | 3666 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { |
| 3571 | if (idx < s_idx) | 3667 | if (idx < s_idx) |
| 3572 | goto cont; | 3668 | goto cont; |
| 3573 | if (idx > s_idx) | 3669 | if (h > s_h || idx > s_idx) |
| 3574 | s_ip_idx = 0; | 3670 | s_ip_idx = 0; |
| 3575 | ip_idx = 0; | 3671 | ip_idx = 0; |
| 3576 | if ((idev = __in6_dev_get(dev)) == NULL) | 3672 | idev = __in6_dev_get(dev); |
| 3673 | if (!idev) | ||
| 3577 | goto cont; | 3674 | goto cont; |
| 3578 | 3675 | ||
| 3579 | if (in6_dump_addrs(idev, skb, cb, type, | 3676 | if (in6_dump_addrs(idev, skb, cb, type, |
| @@ -3640,12 +3737,14 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, | |||
| 3640 | if (ifm->ifa_index) | 3737 | if (ifm->ifa_index) |
| 3641 | dev = __dev_get_by_index(net, ifm->ifa_index); | 3738 | dev = __dev_get_by_index(net, ifm->ifa_index); |
| 3642 | 3739 | ||
| 3643 | if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) { | 3740 | ifa = ipv6_get_ifaddr(net, addr, dev, 1); |
| 3741 | if (!ifa) { | ||
| 3644 | err = -EADDRNOTAVAIL; | 3742 | err = -EADDRNOTAVAIL; |
| 3645 | goto errout; | 3743 | goto errout; |
| 3646 | } | 3744 | } |
| 3647 | 3745 | ||
| 3648 | if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) { | 3746 | skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL); |
| 3747 | if (!skb) { | ||
| 3649 | err = -ENOBUFS; | 3748 | err = -ENOBUFS; |
| 3650 | goto errout_ifa; | 3749 | goto errout_ifa; |
| 3651 | } | 3750 | } |
| @@ -3752,8 +3851,8 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
| 3752 | ); | 3851 | ); |
| 3753 | } | 3852 | } |
| 3754 | 3853 | ||
| 3755 | static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | 3854 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, |
| 3756 | int bytes) | 3855 | int items, int bytes) |
| 3757 | { | 3856 | { |
| 3758 | int i; | 3857 | int i; |
| 3759 | int pad = bytes - sizeof(u64) * items; | 3858 | int pad = bytes - sizeof(u64) * items; |
| @@ -3767,15 +3866,31 @@ static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | |||
| 3767 | memset(&stats[items], 0, pad); | 3866 | memset(&stats[items], 0, pad); |
| 3768 | } | 3867 | } |
| 3769 | 3868 | ||
| 3869 | static inline void __snmp6_fill_stats64(u64 *stats, void __percpu **mib, | ||
| 3870 | int items, int bytes, size_t syncpoff) | ||
| 3871 | { | ||
| 3872 | int i; | ||
| 3873 | int pad = bytes - sizeof(u64) * items; | ||
| 3874 | BUG_ON(pad < 0); | ||
| 3875 | |||
| 3876 | /* Use put_unaligned() because stats may not be aligned for u64. */ | ||
| 3877 | put_unaligned(items, &stats[0]); | ||
| 3878 | for (i = 1; i < items; i++) | ||
| 3879 | put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]); | ||
| 3880 | |||
| 3881 | memset(&stats[items], 0, pad); | ||
| 3882 | } | ||
| 3883 | |||
| 3770 | static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | 3884 | static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, |
| 3771 | int bytes) | 3885 | int bytes) |
| 3772 | { | 3886 | { |
| 3773 | switch(attrtype) { | 3887 | switch (attrtype) { |
| 3774 | case IFLA_INET6_STATS: | 3888 | case IFLA_INET6_STATS: |
| 3775 | __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | 3889 | __snmp6_fill_stats64(stats, (void __percpu **)idev->stats.ipv6, |
| 3890 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); | ||
| 3776 | break; | 3891 | break; |
| 3777 | case IFLA_INET6_ICMP6STATS: | 3892 | case IFLA_INET6_ICMP6STATS: |
| 3778 | __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3893 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); |
| 3779 | break; | 3894 | break; |
| 3780 | } | 3895 | } |
| 3781 | } | 3896 | } |
| @@ -4005,9 +4120,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
| 4005 | if (ifp->idev->cnf.forwarding) | 4120 | if (ifp->idev->cnf.forwarding) |
| 4006 | addrconf_leave_anycast(ifp); | 4121 | addrconf_leave_anycast(ifp); |
| 4007 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 4122 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
| 4008 | dst_hold(&ifp->rt->u.dst); | 4123 | dst_hold(&ifp->rt->dst); |
| 4009 | if (ip6_del_rt(ifp->rt)) | 4124 | |
| 4010 | dst_free(&ifp->rt->u.dst); | 4125 | if (ifp->state == INET6_IFADDR_STATE_DEAD && |
| 4126 | ip6_del_rt(ifp->rt)) | ||
| 4127 | dst_free(&ifp->rt->dst); | ||
| 4011 | break; | 4128 | break; |
| 4012 | } | 4129 | } |
| 4013 | } | 4130 | } |
| @@ -4028,12 +4145,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, | |||
| 4028 | { | 4145 | { |
| 4029 | int *valp = ctl->data; | 4146 | int *valp = ctl->data; |
| 4030 | int val = *valp; | 4147 | int val = *valp; |
| 4148 | loff_t pos = *ppos; | ||
| 4031 | int ret; | 4149 | int ret; |
| 4032 | 4150 | ||
| 4033 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4151 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
| 4034 | 4152 | ||
| 4035 | if (write) | 4153 | if (write) |
| 4036 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 4154 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
| 4155 | if (ret) | ||
| 4156 | *ppos = pos; | ||
| 4037 | return ret; | 4157 | return ret; |
| 4038 | } | 4158 | } |
| 4039 | 4159 | ||
| @@ -4075,8 +4195,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | |||
| 4075 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) | 4195 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) |
| 4076 | return 0; | 4196 | return 0; |
| 4077 | 4197 | ||
| 4078 | if (!rtnl_trylock()) | 4198 | if (!rtnl_trylock()) { |
| 4199 | /* Restore the original values before restarting */ | ||
| 4200 | *p = old; | ||
| 4079 | return restart_syscall(); | 4201 | return restart_syscall(); |
| 4202 | } | ||
| 4080 | 4203 | ||
| 4081 | if (p == &net->ipv6.devconf_all->disable_ipv6) { | 4204 | if (p == &net->ipv6.devconf_all->disable_ipv6) { |
| 4082 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; | 4205 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; |
| @@ -4095,12 +4218,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, | |||
| 4095 | { | 4218 | { |
| 4096 | int *valp = ctl->data; | 4219 | int *valp = ctl->data; |
| 4097 | int val = *valp; | 4220 | int val = *valp; |
| 4221 | loff_t pos = *ppos; | ||
| 4098 | int ret; | 4222 | int ret; |
| 4099 | 4223 | ||
| 4100 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4224 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
| 4101 | 4225 | ||
| 4102 | if (write) | 4226 | if (write) |
| 4103 | ret = addrconf_disable_ipv6(ctl, valp, val); | 4227 | ret = addrconf_disable_ipv6(ctl, valp, val); |
| 4228 | if (ret) | ||
| 4229 | *ppos = pos; | ||
| 4104 | return ret; | 4230 | return ret; |
| 4105 | } | 4231 | } |
| 4106 | 4232 | ||
| @@ -4113,211 +4239,211 @@ static struct addrconf_sysctl_table | |||
| 4113 | .sysctl_header = NULL, | 4239 | .sysctl_header = NULL, |
| 4114 | .addrconf_vars = { | 4240 | .addrconf_vars = { |
| 4115 | { | 4241 | { |
| 4116 | .procname = "forwarding", | 4242 | .procname = "forwarding", |
| 4117 | .data = &ipv6_devconf.forwarding, | 4243 | .data = &ipv6_devconf.forwarding, |
| 4118 | .maxlen = sizeof(int), | 4244 | .maxlen = sizeof(int), |
| 4119 | .mode = 0644, | 4245 | .mode = 0644, |
| 4120 | .proc_handler = addrconf_sysctl_forward, | 4246 | .proc_handler = addrconf_sysctl_forward, |
| 4121 | }, | 4247 | }, |
| 4122 | { | 4248 | { |
| 4123 | .procname = "hop_limit", | 4249 | .procname = "hop_limit", |
| 4124 | .data = &ipv6_devconf.hop_limit, | 4250 | .data = &ipv6_devconf.hop_limit, |
| 4125 | .maxlen = sizeof(int), | 4251 | .maxlen = sizeof(int), |
| 4126 | .mode = 0644, | 4252 | .mode = 0644, |
| 4127 | .proc_handler = proc_dointvec, | 4253 | .proc_handler = proc_dointvec, |
| 4128 | }, | 4254 | }, |
| 4129 | { | 4255 | { |
| 4130 | .procname = "mtu", | 4256 | .procname = "mtu", |
| 4131 | .data = &ipv6_devconf.mtu6, | 4257 | .data = &ipv6_devconf.mtu6, |
| 4132 | .maxlen = sizeof(int), | 4258 | .maxlen = sizeof(int), |
| 4133 | .mode = 0644, | 4259 | .mode = 0644, |
| 4134 | .proc_handler = proc_dointvec, | 4260 | .proc_handler = proc_dointvec, |
| 4135 | }, | 4261 | }, |
| 4136 | { | 4262 | { |
| 4137 | .procname = "accept_ra", | 4263 | .procname = "accept_ra", |
| 4138 | .data = &ipv6_devconf.accept_ra, | 4264 | .data = &ipv6_devconf.accept_ra, |
| 4139 | .maxlen = sizeof(int), | 4265 | .maxlen = sizeof(int), |
| 4140 | .mode = 0644, | 4266 | .mode = 0644, |
| 4141 | .proc_handler = proc_dointvec, | 4267 | .proc_handler = proc_dointvec, |
| 4142 | }, | 4268 | }, |
| 4143 | { | 4269 | { |
| 4144 | .procname = "accept_redirects", | 4270 | .procname = "accept_redirects", |
| 4145 | .data = &ipv6_devconf.accept_redirects, | 4271 | .data = &ipv6_devconf.accept_redirects, |
| 4146 | .maxlen = sizeof(int), | 4272 | .maxlen = sizeof(int), |
| 4147 | .mode = 0644, | 4273 | .mode = 0644, |
| 4148 | .proc_handler = proc_dointvec, | 4274 | .proc_handler = proc_dointvec, |
| 4149 | }, | 4275 | }, |
| 4150 | { | 4276 | { |
| 4151 | .procname = "autoconf", | 4277 | .procname = "autoconf", |
| 4152 | .data = &ipv6_devconf.autoconf, | 4278 | .data = &ipv6_devconf.autoconf, |
| 4153 | .maxlen = sizeof(int), | 4279 | .maxlen = sizeof(int), |
| 4154 | .mode = 0644, | 4280 | .mode = 0644, |
| 4155 | .proc_handler = proc_dointvec, | 4281 | .proc_handler = proc_dointvec, |
| 4156 | }, | 4282 | }, |
| 4157 | { | 4283 | { |
| 4158 | .procname = "dad_transmits", | 4284 | .procname = "dad_transmits", |
| 4159 | .data = &ipv6_devconf.dad_transmits, | 4285 | .data = &ipv6_devconf.dad_transmits, |
| 4160 | .maxlen = sizeof(int), | 4286 | .maxlen = sizeof(int), |
| 4161 | .mode = 0644, | 4287 | .mode = 0644, |
| 4162 | .proc_handler = proc_dointvec, | 4288 | .proc_handler = proc_dointvec, |
| 4163 | }, | 4289 | }, |
| 4164 | { | 4290 | { |
| 4165 | .procname = "router_solicitations", | 4291 | .procname = "router_solicitations", |
| 4166 | .data = &ipv6_devconf.rtr_solicits, | 4292 | .data = &ipv6_devconf.rtr_solicits, |
| 4167 | .maxlen = sizeof(int), | 4293 | .maxlen = sizeof(int), |
| 4168 | .mode = 0644, | 4294 | .mode = 0644, |
| 4169 | .proc_handler = proc_dointvec, | 4295 | .proc_handler = proc_dointvec, |
| 4170 | }, | 4296 | }, |
| 4171 | { | 4297 | { |
| 4172 | .procname = "router_solicitation_interval", | 4298 | .procname = "router_solicitation_interval", |
| 4173 | .data = &ipv6_devconf.rtr_solicit_interval, | 4299 | .data = &ipv6_devconf.rtr_solicit_interval, |
| 4174 | .maxlen = sizeof(int), | 4300 | .maxlen = sizeof(int), |
| 4175 | .mode = 0644, | 4301 | .mode = 0644, |
| 4176 | .proc_handler = proc_dointvec_jiffies, | 4302 | .proc_handler = proc_dointvec_jiffies, |
| 4177 | }, | 4303 | }, |
| 4178 | { | 4304 | { |
| 4179 | .procname = "router_solicitation_delay", | 4305 | .procname = "router_solicitation_delay", |
| 4180 | .data = &ipv6_devconf.rtr_solicit_delay, | 4306 | .data = &ipv6_devconf.rtr_solicit_delay, |
| 4181 | .maxlen = sizeof(int), | 4307 | .maxlen = sizeof(int), |
| 4182 | .mode = 0644, | 4308 | .mode = 0644, |
| 4183 | .proc_handler = proc_dointvec_jiffies, | 4309 | .proc_handler = proc_dointvec_jiffies, |
| 4184 | }, | 4310 | }, |
| 4185 | { | 4311 | { |
| 4186 | .procname = "force_mld_version", | 4312 | .procname = "force_mld_version", |
| 4187 | .data = &ipv6_devconf.force_mld_version, | 4313 | .data = &ipv6_devconf.force_mld_version, |
| 4188 | .maxlen = sizeof(int), | 4314 | .maxlen = sizeof(int), |
| 4189 | .mode = 0644, | 4315 | .mode = 0644, |
| 4190 | .proc_handler = proc_dointvec, | 4316 | .proc_handler = proc_dointvec, |
| 4191 | }, | 4317 | }, |
| 4192 | #ifdef CONFIG_IPV6_PRIVACY | 4318 | #ifdef CONFIG_IPV6_PRIVACY |
| 4193 | { | 4319 | { |
| 4194 | .procname = "use_tempaddr", | 4320 | .procname = "use_tempaddr", |
| 4195 | .data = &ipv6_devconf.use_tempaddr, | 4321 | .data = &ipv6_devconf.use_tempaddr, |
| 4196 | .maxlen = sizeof(int), | 4322 | .maxlen = sizeof(int), |
| 4197 | .mode = 0644, | 4323 | .mode = 0644, |
| 4198 | .proc_handler = proc_dointvec, | 4324 | .proc_handler = proc_dointvec, |
| 4199 | }, | 4325 | }, |
| 4200 | { | 4326 | { |
| 4201 | .procname = "temp_valid_lft", | 4327 | .procname = "temp_valid_lft", |
| 4202 | .data = &ipv6_devconf.temp_valid_lft, | 4328 | .data = &ipv6_devconf.temp_valid_lft, |
| 4203 | .maxlen = sizeof(int), | 4329 | .maxlen = sizeof(int), |
| 4204 | .mode = 0644, | 4330 | .mode = 0644, |
| 4205 | .proc_handler = proc_dointvec, | 4331 | .proc_handler = proc_dointvec, |
| 4206 | }, | 4332 | }, |
| 4207 | { | 4333 | { |
| 4208 | .procname = "temp_prefered_lft", | 4334 | .procname = "temp_prefered_lft", |
| 4209 | .data = &ipv6_devconf.temp_prefered_lft, | 4335 | .data = &ipv6_devconf.temp_prefered_lft, |
| 4210 | .maxlen = sizeof(int), | 4336 | .maxlen = sizeof(int), |
| 4211 | .mode = 0644, | 4337 | .mode = 0644, |
| 4212 | .proc_handler = proc_dointvec, | 4338 | .proc_handler = proc_dointvec, |
| 4213 | }, | 4339 | }, |
| 4214 | { | 4340 | { |
| 4215 | .procname = "regen_max_retry", | 4341 | .procname = "regen_max_retry", |
| 4216 | .data = &ipv6_devconf.regen_max_retry, | 4342 | .data = &ipv6_devconf.regen_max_retry, |
| 4217 | .maxlen = sizeof(int), | 4343 | .maxlen = sizeof(int), |
| 4218 | .mode = 0644, | 4344 | .mode = 0644, |
| 4219 | .proc_handler = proc_dointvec, | 4345 | .proc_handler = proc_dointvec, |
| 4220 | }, | 4346 | }, |
| 4221 | { | 4347 | { |
| 4222 | .procname = "max_desync_factor", | 4348 | .procname = "max_desync_factor", |
| 4223 | .data = &ipv6_devconf.max_desync_factor, | 4349 | .data = &ipv6_devconf.max_desync_factor, |
| 4224 | .maxlen = sizeof(int), | 4350 | .maxlen = sizeof(int), |
| 4225 | .mode = 0644, | 4351 | .mode = 0644, |
| 4226 | .proc_handler = proc_dointvec, | 4352 | .proc_handler = proc_dointvec, |
| 4227 | }, | 4353 | }, |
| 4228 | #endif | 4354 | #endif |
| 4229 | { | 4355 | { |
| 4230 | .procname = "max_addresses", | 4356 | .procname = "max_addresses", |
| 4231 | .data = &ipv6_devconf.max_addresses, | 4357 | .data = &ipv6_devconf.max_addresses, |
| 4232 | .maxlen = sizeof(int), | 4358 | .maxlen = sizeof(int), |
| 4233 | .mode = 0644, | 4359 | .mode = 0644, |
| 4234 | .proc_handler = proc_dointvec, | 4360 | .proc_handler = proc_dointvec, |
| 4235 | }, | 4361 | }, |
| 4236 | { | 4362 | { |
| 4237 | .procname = "accept_ra_defrtr", | 4363 | .procname = "accept_ra_defrtr", |
| 4238 | .data = &ipv6_devconf.accept_ra_defrtr, | 4364 | .data = &ipv6_devconf.accept_ra_defrtr, |
| 4239 | .maxlen = sizeof(int), | 4365 | .maxlen = sizeof(int), |
| 4240 | .mode = 0644, | 4366 | .mode = 0644, |
| 4241 | .proc_handler = proc_dointvec, | 4367 | .proc_handler = proc_dointvec, |
| 4242 | }, | 4368 | }, |
| 4243 | { | 4369 | { |
| 4244 | .procname = "accept_ra_pinfo", | 4370 | .procname = "accept_ra_pinfo", |
| 4245 | .data = &ipv6_devconf.accept_ra_pinfo, | 4371 | .data = &ipv6_devconf.accept_ra_pinfo, |
| 4246 | .maxlen = sizeof(int), | 4372 | .maxlen = sizeof(int), |
| 4247 | .mode = 0644, | 4373 | .mode = 0644, |
| 4248 | .proc_handler = proc_dointvec, | 4374 | .proc_handler = proc_dointvec, |
| 4249 | }, | 4375 | }, |
| 4250 | #ifdef CONFIG_IPV6_ROUTER_PREF | 4376 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 4251 | { | 4377 | { |
| 4252 | .procname = "accept_ra_rtr_pref", | 4378 | .procname = "accept_ra_rtr_pref", |
| 4253 | .data = &ipv6_devconf.accept_ra_rtr_pref, | 4379 | .data = &ipv6_devconf.accept_ra_rtr_pref, |
| 4254 | .maxlen = sizeof(int), | 4380 | .maxlen = sizeof(int), |
| 4255 | .mode = 0644, | 4381 | .mode = 0644, |
| 4256 | .proc_handler = proc_dointvec, | 4382 | .proc_handler = proc_dointvec, |
| 4257 | }, | 4383 | }, |
| 4258 | { | 4384 | { |
| 4259 | .procname = "router_probe_interval", | 4385 | .procname = "router_probe_interval", |
| 4260 | .data = &ipv6_devconf.rtr_probe_interval, | 4386 | .data = &ipv6_devconf.rtr_probe_interval, |
| 4261 | .maxlen = sizeof(int), | 4387 | .maxlen = sizeof(int), |
| 4262 | .mode = 0644, | 4388 | .mode = 0644, |
| 4263 | .proc_handler = proc_dointvec_jiffies, | 4389 | .proc_handler = proc_dointvec_jiffies, |
| 4264 | }, | 4390 | }, |
| 4265 | #ifdef CONFIG_IPV6_ROUTE_INFO | 4391 | #ifdef CONFIG_IPV6_ROUTE_INFO |
| 4266 | { | 4392 | { |
| 4267 | .procname = "accept_ra_rt_info_max_plen", | 4393 | .procname = "accept_ra_rt_info_max_plen", |
| 4268 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, | 4394 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, |
| 4269 | .maxlen = sizeof(int), | 4395 | .maxlen = sizeof(int), |
| 4270 | .mode = 0644, | 4396 | .mode = 0644, |
| 4271 | .proc_handler = proc_dointvec, | 4397 | .proc_handler = proc_dointvec, |
| 4272 | }, | 4398 | }, |
| 4273 | #endif | 4399 | #endif |
| 4274 | #endif | 4400 | #endif |
| 4275 | { | 4401 | { |
| 4276 | .procname = "proxy_ndp", | 4402 | .procname = "proxy_ndp", |
| 4277 | .data = &ipv6_devconf.proxy_ndp, | 4403 | .data = &ipv6_devconf.proxy_ndp, |
| 4278 | .maxlen = sizeof(int), | 4404 | .maxlen = sizeof(int), |
| 4279 | .mode = 0644, | 4405 | .mode = 0644, |
| 4280 | .proc_handler = proc_dointvec, | 4406 | .proc_handler = proc_dointvec, |
| 4281 | }, | 4407 | }, |
| 4282 | { | 4408 | { |
| 4283 | .procname = "accept_source_route", | 4409 | .procname = "accept_source_route", |
| 4284 | .data = &ipv6_devconf.accept_source_route, | 4410 | .data = &ipv6_devconf.accept_source_route, |
| 4285 | .maxlen = sizeof(int), | 4411 | .maxlen = sizeof(int), |
| 4286 | .mode = 0644, | 4412 | .mode = 0644, |
| 4287 | .proc_handler = proc_dointvec, | 4413 | .proc_handler = proc_dointvec, |
| 4288 | }, | 4414 | }, |
| 4289 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 4415 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
| 4290 | { | 4416 | { |
| 4291 | .procname = "optimistic_dad", | 4417 | .procname = "optimistic_dad", |
| 4292 | .data = &ipv6_devconf.optimistic_dad, | 4418 | .data = &ipv6_devconf.optimistic_dad, |
| 4293 | .maxlen = sizeof(int), | 4419 | .maxlen = sizeof(int), |
| 4294 | .mode = 0644, | 4420 | .mode = 0644, |
| 4295 | .proc_handler = proc_dointvec, | 4421 | .proc_handler = proc_dointvec, |
| 4296 | 4422 | ||
| 4297 | }, | 4423 | }, |
| 4298 | #endif | 4424 | #endif |
| 4299 | #ifdef CONFIG_IPV6_MROUTE | 4425 | #ifdef CONFIG_IPV6_MROUTE |
| 4300 | { | 4426 | { |
| 4301 | .procname = "mc_forwarding", | 4427 | .procname = "mc_forwarding", |
| 4302 | .data = &ipv6_devconf.mc_forwarding, | 4428 | .data = &ipv6_devconf.mc_forwarding, |
| 4303 | .maxlen = sizeof(int), | 4429 | .maxlen = sizeof(int), |
| 4304 | .mode = 0444, | 4430 | .mode = 0444, |
| 4305 | .proc_handler = proc_dointvec, | 4431 | .proc_handler = proc_dointvec, |
| 4306 | }, | 4432 | }, |
| 4307 | #endif | 4433 | #endif |
| 4308 | { | 4434 | { |
| 4309 | .procname = "disable_ipv6", | 4435 | .procname = "disable_ipv6", |
| 4310 | .data = &ipv6_devconf.disable_ipv6, | 4436 | .data = &ipv6_devconf.disable_ipv6, |
| 4311 | .maxlen = sizeof(int), | 4437 | .maxlen = sizeof(int), |
| 4312 | .mode = 0644, | 4438 | .mode = 0644, |
| 4313 | .proc_handler = addrconf_sysctl_disable, | 4439 | .proc_handler = addrconf_sysctl_disable, |
| 4314 | }, | 4440 | }, |
| 4315 | { | 4441 | { |
| 4316 | .procname = "accept_dad", | 4442 | .procname = "accept_dad", |
| 4317 | .data = &ipv6_devconf.accept_dad, | 4443 | .data = &ipv6_devconf.accept_dad, |
| 4318 | .maxlen = sizeof(int), | 4444 | .maxlen = sizeof(int), |
| 4319 | .mode = 0644, | 4445 | .mode = 0644, |
| 4320 | .proc_handler = proc_dointvec, | 4446 | .proc_handler = proc_dointvec, |
| 4321 | }, | 4447 | }, |
| 4322 | { | 4448 | { |
| 4323 | .procname = "force_tllao", | 4449 | .procname = "force_tllao", |
| @@ -4353,8 +4479,8 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name, | |||
| 4353 | if (t == NULL) | 4479 | if (t == NULL) |
| 4354 | goto out; | 4480 | goto out; |
| 4355 | 4481 | ||
| 4356 | for (i=0; t->addrconf_vars[i].data; i++) { | 4482 | for (i = 0; t->addrconf_vars[i].data; i++) { |
| 4357 | t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; | 4483 | t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf; |
| 4358 | t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */ | 4484 | t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */ |
| 4359 | t->addrconf_vars[i].extra2 = net; | 4485 | t->addrconf_vars[i].extra2 = net; |
| 4360 | } | 4486 | } |
| @@ -4402,8 +4528,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
| 4402 | 4528 | ||
| 4403 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 4529 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
| 4404 | { | 4530 | { |
| 4405 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, | 4531 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", |
| 4406 | NET_IPV6_NEIGH, "ipv6", | ||
| 4407 | &ndisc_ifinfo_sysctl_change); | 4532 | &ndisc_ifinfo_sysctl_change); |
| 4408 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 4533 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
| 4409 | idev, &idev->cnf); | 4534 | idev, &idev->cnf); |
| @@ -4418,7 +4543,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
| 4418 | 4543 | ||
| 4419 | #endif | 4544 | #endif |
| 4420 | 4545 | ||
| 4421 | static int addrconf_init_net(struct net *net) | 4546 | static int __net_init addrconf_init_net(struct net *net) |
| 4422 | { | 4547 | { |
| 4423 | int err; | 4548 | int err; |
| 4424 | struct ipv6_devconf *all, *dflt; | 4549 | struct ipv6_devconf *all, *dflt; |
| @@ -4467,7 +4592,7 @@ err_alloc_all: | |||
| 4467 | return err; | 4592 | return err; |
| 4468 | } | 4593 | } |
| 4469 | 4594 | ||
| 4470 | static void addrconf_exit_net(struct net *net) | 4595 | static void __net_exit addrconf_exit_net(struct net *net) |
| 4471 | { | 4596 | { |
| 4472 | #ifdef CONFIG_SYSCTL | 4597 | #ifdef CONFIG_SYSCTL |
| 4473 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); | 4598 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); |
| @@ -4492,14 +4617,12 @@ int register_inet6addr_notifier(struct notifier_block *nb) | |||
| 4492 | { | 4617 | { |
| 4493 | return atomic_notifier_chain_register(&inet6addr_chain, nb); | 4618 | return atomic_notifier_chain_register(&inet6addr_chain, nb); |
| 4494 | } | 4619 | } |
| 4495 | |||
| 4496 | EXPORT_SYMBOL(register_inet6addr_notifier); | 4620 | EXPORT_SYMBOL(register_inet6addr_notifier); |
| 4497 | 4621 | ||
| 4498 | int unregister_inet6addr_notifier(struct notifier_block *nb) | 4622 | int unregister_inet6addr_notifier(struct notifier_block *nb) |
| 4499 | { | 4623 | { |
| 4500 | return atomic_notifier_chain_unregister(&inet6addr_chain,nb); | 4624 | return atomic_notifier_chain_unregister(&inet6addr_chain, nb); |
| 4501 | } | 4625 | } |
| 4502 | |||
| 4503 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4626 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
| 4504 | 4627 | ||
| 4505 | /* | 4628 | /* |
| @@ -4508,15 +4631,18 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier); | |||
| 4508 | 4631 | ||
| 4509 | int __init addrconf_init(void) | 4632 | int __init addrconf_init(void) |
| 4510 | { | 4633 | { |
| 4511 | int err; | 4634 | int i, err; |
| 4512 | 4635 | ||
| 4513 | if ((err = ipv6_addr_label_init()) < 0) { | 4636 | err = ipv6_addr_label_init(); |
| 4514 | printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n", | 4637 | if (err < 0) { |
| 4515 | err); | 4638 | printk(KERN_CRIT "IPv6 Addrconf:" |
| 4516 | return err; | 4639 | " cannot initialize default policy table: %d.\n", err); |
| 4640 | goto out; | ||
| 4517 | } | 4641 | } |
| 4518 | 4642 | ||
| 4519 | register_pernet_subsys(&addrconf_ops); | 4643 | err = register_pernet_subsys(&addrconf_ops); |
| 4644 | if (err < 0) | ||
| 4645 | goto out_addrlabel; | ||
| 4520 | 4646 | ||
| 4521 | /* The addrconf netdev notifier requires that loopback_dev | 4647 | /* The addrconf netdev notifier requires that loopback_dev |
| 4522 | * has it's ipv6 private information allocated and setup | 4648 | * has it's ipv6 private information allocated and setup |
| @@ -4543,6 +4669,9 @@ int __init addrconf_init(void) | |||
| 4543 | if (err) | 4669 | if (err) |
| 4544 | goto errlo; | 4670 | goto errlo; |
| 4545 | 4671 | ||
| 4672 | for (i = 0; i < IN6_ADDR_HSIZE; i++) | ||
| 4673 | INIT_HLIST_HEAD(&inet6_addr_lst[i]); | ||
| 4674 | |||
| 4546 | register_netdevice_notifier(&ipv6_dev_notf); | 4675 | register_netdevice_notifier(&ipv6_dev_notf); |
| 4547 | 4676 | ||
| 4548 | addrconf_verify(0); | 4677 | addrconf_verify(0); |
| @@ -4565,18 +4694,20 @@ errout: | |||
| 4565 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4694 | unregister_netdevice_notifier(&ipv6_dev_notf); |
| 4566 | errlo: | 4695 | errlo: |
| 4567 | unregister_pernet_subsys(&addrconf_ops); | 4696 | unregister_pernet_subsys(&addrconf_ops); |
| 4568 | 4697 | out_addrlabel: | |
| 4698 | ipv6_addr_label_cleanup(); | ||
| 4699 | out: | ||
| 4569 | return err; | 4700 | return err; |
| 4570 | } | 4701 | } |
| 4571 | 4702 | ||
| 4572 | void addrconf_cleanup(void) | 4703 | void addrconf_cleanup(void) |
| 4573 | { | 4704 | { |
| 4574 | struct inet6_ifaddr *ifa; | ||
| 4575 | struct net_device *dev; | 4705 | struct net_device *dev; |
| 4576 | int i; | 4706 | int i; |
| 4577 | 4707 | ||
| 4578 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4708 | unregister_netdevice_notifier(&ipv6_dev_notf); |
| 4579 | unregister_pernet_subsys(&addrconf_ops); | 4709 | unregister_pernet_subsys(&addrconf_ops); |
| 4710 | ipv6_addr_label_cleanup(); | ||
| 4580 | 4711 | ||
| 4581 | rtnl_lock(); | 4712 | rtnl_lock(); |
| 4582 | 4713 | ||
| @@ -4591,20 +4722,10 @@ void addrconf_cleanup(void) | |||
| 4591 | /* | 4722 | /* |
| 4592 | * Check hash table. | 4723 | * Check hash table. |
| 4593 | */ | 4724 | */ |
| 4594 | write_lock_bh(&addrconf_hash_lock); | 4725 | spin_lock_bh(&addrconf_hash_lock); |
| 4595 | for (i=0; i < IN6_ADDR_HSIZE; i++) { | 4726 | for (i = 0; i < IN6_ADDR_HSIZE; i++) |
| 4596 | for (ifa=inet6_addr_lst[i]; ifa; ) { | 4727 | WARN_ON(!hlist_empty(&inet6_addr_lst[i])); |
| 4597 | struct inet6_ifaddr *bifa; | 4728 | spin_unlock_bh(&addrconf_hash_lock); |
| 4598 | |||
| 4599 | bifa = ifa; | ||
| 4600 | ifa = ifa->lst_next; | ||
| 4601 | printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa); | ||
| 4602 | /* Do not free it; something is wrong. | ||
| 4603 | Now we can investigate it with debugger. | ||
| 4604 | */ | ||
| 4605 | } | ||
| 4606 | } | ||
| 4607 | write_unlock_bh(&addrconf_hash_lock); | ||
| 4608 | 4729 | ||
| 4609 | del_timer(&addr_chk_timer); | 4730 | del_timer(&addr_chk_timer); |
| 4610 | rtnl_unlock(); | 4731 | rtnl_unlock(); |
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 3f82e9542eda..6b03826552e1 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c | |||
| @@ -72,7 +72,7 @@ int __ipv6_addr_type(const struct in6_addr *addr) | |||
| 72 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ | 72 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | return (IPV6_ADDR_RESERVED | | 75 | return (IPV6_ADDR_UNICAST | |
| 76 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ | 76 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ |
| 77 | } | 77 | } |
| 78 | EXPORT_SYMBOL(__ipv6_addr_type); | 78 | EXPORT_SYMBOL(__ipv6_addr_type); |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 6ff73c4c126a..8175f802651b 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
| 14 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
| 15 | #include <linux/in6.h> | 15 | #include <linux/in6.h> |
| 16 | #include <linux/slab.h> | ||
| 16 | #include <net/addrconf.h> | 17 | #include <net/addrconf.h> |
| 17 | #include <linux/if_addrlabel.h> | 18 | #include <linux/if_addrlabel.h> |
| 18 | #include <linux/netlink.h> | 19 | #include <linux/netlink.h> |
| @@ -52,11 +53,7 @@ static struct ip6addrlbl_table | |||
| 52 | static inline | 53 | static inline |
| 53 | struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) | 54 | struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) |
| 54 | { | 55 | { |
| 55 | #ifdef CONFIG_NET_NS | 56 | return read_pnet(&lbl->lbl_net); |
| 56 | return lbl->lbl_net; | ||
| 57 | #else | ||
| 58 | return &init_net; | ||
| 59 | #endif | ||
| 60 | } | 57 | } |
| 61 | 58 | ||
| 62 | /* | 59 | /* |
| @@ -396,6 +393,11 @@ int __init ipv6_addr_label_init(void) | |||
| 396 | return register_pernet_subsys(&ipv6_addr_label_ops); | 393 | return register_pernet_subsys(&ipv6_addr_label_ops); |
| 397 | } | 394 | } |
| 398 | 395 | ||
| 396 | void ipv6_addr_label_cleanup(void) | ||
| 397 | { | ||
| 398 | unregister_pernet_subsys(&ipv6_addr_label_ops); | ||
| 399 | } | ||
| 400 | |||
| 399 | static const struct nla_policy ifal_policy[IFAL_MAX+1] = { | 401 | static const struct nla_policy ifal_policy[IFAL_MAX+1] = { |
| 400 | [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, | 402 | [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, |
| 401 | [IFAL_LABEL] = { .len = sizeof(u32), }, | 403 | [IFAL_LABEL] = { .len = sizeof(u32), }, |
| @@ -421,10 +423,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 421 | ifal->ifal_prefixlen > 128) | 423 | ifal->ifal_prefixlen > 128) |
| 422 | return -EINVAL; | 424 | return -EINVAL; |
| 423 | 425 | ||
| 424 | if (ifal->ifal_index && | ||
| 425 | !__dev_get_by_index(net, ifal->ifal_index)) | ||
| 426 | return -EINVAL; | ||
| 427 | |||
| 428 | if (!tb[IFAL_ADDRESS]) | 426 | if (!tb[IFAL_ADDRESS]) |
| 429 | return -EINVAL; | 427 | return -EINVAL; |
| 430 | 428 | ||
| @@ -440,6 +438,10 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 440 | 438 | ||
| 441 | switch(nlh->nlmsg_type) { | 439 | switch(nlh->nlmsg_type) { |
| 442 | case RTM_NEWADDRLABEL: | 440 | case RTM_NEWADDRLABEL: |
| 441 | if (ifal->ifal_index && | ||
| 442 | !__dev_get_by_index(net, ifal->ifal_index)) | ||
| 443 | return -EINVAL; | ||
| 444 | |||
| 443 | err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen, | 445 | err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen, |
| 444 | ifal->ifal_index, label, | 446 | ifal->ifal_index, label, |
| 445 | nlh->nlmsg_flags & NLM_F_REPLACE); | 447 | nlh->nlmsg_flags & NLM_F_REPLACE); |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 12e69d364dd5..56b9bf2516f4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/proc_fs.h> | 36 | #include <linux/proc_fs.h> |
| 37 | #include <linux/stat.h> | 37 | #include <linux/stat.h> |
| 38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
| 39 | #include <linux/slab.h> | ||
| 39 | 40 | ||
| 40 | #include <linux/inet.h> | 41 | #include <linux/inet.h> |
| 41 | #include <linux/netdevice.h> | 42 | #include <linux/netdevice.h> |
| @@ -199,7 +200,7 @@ lookup_protocol: | |||
| 199 | 200 | ||
| 200 | inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); | 201 | inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); |
| 201 | np->hop_limit = -1; | 202 | np->hop_limit = -1; |
| 202 | np->mcast_hops = -1; | 203 | np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; |
| 203 | np->mc_loop = 1; | 204 | np->mc_loop = 1; |
| 204 | np->pmtudisc = IPV6_PMTUDISC_WANT; | 205 | np->pmtudisc = IPV6_PMTUDISC_WANT; |
| 205 | np->ipv6only = net->ipv6.sysctl.bindv6only; | 206 | np->ipv6only = net->ipv6.sysctl.bindv6only; |
| @@ -416,6 +417,9 @@ void inet6_destroy_sock(struct sock *sk) | |||
| 416 | if ((skb = xchg(&np->pktoptions, NULL)) != NULL) | 417 | if ((skb = xchg(&np->pktoptions, NULL)) != NULL) |
| 417 | kfree_skb(skb); | 418 | kfree_skb(skb); |
| 418 | 419 | ||
| 420 | if ((skb = xchg(&np->rxpmtu, NULL)) != NULL) | ||
| 421 | kfree_skb(skb); | ||
| 422 | |||
| 419 | /* Free flowlabels */ | 423 | /* Free flowlabels */ |
| 420 | fl6_free_socklist(sk); | 424 | fl6_free_socklist(sk); |
| 421 | 425 | ||
| @@ -518,10 +522,10 @@ const struct proto_ops inet6_stream_ops = { | |||
| 518 | .shutdown = inet_shutdown, /* ok */ | 522 | .shutdown = inet_shutdown, /* ok */ |
| 519 | .setsockopt = sock_common_setsockopt, /* ok */ | 523 | .setsockopt = sock_common_setsockopt, /* ok */ |
| 520 | .getsockopt = sock_common_getsockopt, /* ok */ | 524 | .getsockopt = sock_common_getsockopt, /* ok */ |
| 521 | .sendmsg = tcp_sendmsg, /* ok */ | 525 | .sendmsg = inet_sendmsg, /* ok */ |
| 522 | .recvmsg = sock_common_recvmsg, /* ok */ | 526 | .recvmsg = inet_recvmsg, /* ok */ |
| 523 | .mmap = sock_no_mmap, | 527 | .mmap = sock_no_mmap, |
| 524 | .sendpage = tcp_sendpage, | 528 | .sendpage = inet_sendpage, |
| 525 | .splice_read = tcp_splice_read, | 529 | .splice_read = tcp_splice_read, |
| 526 | #ifdef CONFIG_COMPAT | 530 | #ifdef CONFIG_COMPAT |
| 527 | .compat_setsockopt = compat_sock_common_setsockopt, | 531 | .compat_setsockopt = compat_sock_common_setsockopt, |
| @@ -545,7 +549,7 @@ const struct proto_ops inet6_dgram_ops = { | |||
| 545 | .setsockopt = sock_common_setsockopt, /* ok */ | 549 | .setsockopt = sock_common_setsockopt, /* ok */ |
| 546 | .getsockopt = sock_common_getsockopt, /* ok */ | 550 | .getsockopt = sock_common_getsockopt, /* ok */ |
| 547 | .sendmsg = inet_sendmsg, /* ok */ | 551 | .sendmsg = inet_sendmsg, /* ok */ |
| 548 | .recvmsg = sock_common_recvmsg, /* ok */ | 552 | .recvmsg = inet_recvmsg, /* ok */ |
| 549 | .mmap = sock_no_mmap, | 553 | .mmap = sock_no_mmap, |
| 550 | .sendpage = sock_no_sendpage, | 554 | .sendpage = sock_no_sendpage, |
| 551 | #ifdef CONFIG_COMPAT | 555 | #ifdef CONFIG_COMPAT |
| @@ -647,7 +651,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 647 | 651 | ||
| 648 | if (dst == NULL) { | 652 | if (dst == NULL) { |
| 649 | struct inet_sock *inet = inet_sk(sk); | 653 | struct inet_sock *inet = inet_sk(sk); |
| 650 | struct in6_addr *final_p = NULL, final; | 654 | struct in6_addr *final_p, final; |
| 651 | struct flowi fl; | 655 | struct flowi fl; |
| 652 | 656 | ||
| 653 | memset(&fl, 0, sizeof(fl)); | 657 | memset(&fl, 0, sizeof(fl)); |
| @@ -661,12 +665,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 661 | fl.fl_ip_sport = inet->inet_sport; | 665 | fl.fl_ip_sport = inet->inet_sport; |
| 662 | security_sk_classify_flow(sk, &fl); | 666 | security_sk_classify_flow(sk, &fl); |
| 663 | 667 | ||
| 664 | if (np->opt && np->opt->srcrt) { | 668 | final_p = fl6_update_dst(&fl, np->opt, &final); |
| 665 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | ||
| 666 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 667 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 668 | final_p = &final; | ||
| 669 | } | ||
| 670 | 669 | ||
| 671 | err = ip6_dst_lookup(sk, &dst, &fl); | 670 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 672 | if (err) { | 671 | if (err) { |
| @@ -971,41 +970,46 @@ static void ipv6_packet_cleanup(void) | |||
| 971 | 970 | ||
| 972 | static int __net_init ipv6_init_mibs(struct net *net) | 971 | static int __net_init ipv6_init_mibs(struct net *net) |
| 973 | { | 972 | { |
| 974 | if (snmp_mib_init((void **)net->mib.udp_stats_in6, | 973 | if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6, |
| 975 | sizeof (struct udp_mib)) < 0) | 974 | sizeof(struct udp_mib), |
| 975 | __alignof__(struct udp_mib)) < 0) | ||
| 976 | return -ENOMEM; | 976 | return -ENOMEM; |
| 977 | if (snmp_mib_init((void **)net->mib.udplite_stats_in6, | 977 | if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6, |
| 978 | sizeof (struct udp_mib)) < 0) | 978 | sizeof(struct udp_mib), |
| 979 | __alignof__(struct udp_mib)) < 0) | ||
| 979 | goto err_udplite_mib; | 980 | goto err_udplite_mib; |
| 980 | if (snmp_mib_init((void **)net->mib.ipv6_statistics, | 981 | if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics, |
| 981 | sizeof(struct ipstats_mib)) < 0) | 982 | sizeof(struct ipstats_mib), |
| 983 | __alignof__(struct ipstats_mib)) < 0) | ||
| 982 | goto err_ip_mib; | 984 | goto err_ip_mib; |
| 983 | if (snmp_mib_init((void **)net->mib.icmpv6_statistics, | 985 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics, |
| 984 | sizeof(struct icmpv6_mib)) < 0) | 986 | sizeof(struct icmpv6_mib), |
| 987 | __alignof__(struct icmpv6_mib)) < 0) | ||
| 985 | goto err_icmp_mib; | 988 | goto err_icmp_mib; |
| 986 | if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics, | 989 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics, |
| 987 | sizeof(struct icmpv6msg_mib)) < 0) | 990 | sizeof(struct icmpv6msg_mib), |
| 991 | __alignof__(struct icmpv6msg_mib)) < 0) | ||
| 988 | goto err_icmpmsg_mib; | 992 | goto err_icmpmsg_mib; |
| 989 | return 0; | 993 | return 0; |
| 990 | 994 | ||
| 991 | err_icmpmsg_mib: | 995 | err_icmpmsg_mib: |
| 992 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 996 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
| 993 | err_icmp_mib: | 997 | err_icmp_mib: |
| 994 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 998 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
| 995 | err_ip_mib: | 999 | err_ip_mib: |
| 996 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 1000 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
| 997 | err_udplite_mib: | 1001 | err_udplite_mib: |
| 998 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 1002 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
| 999 | return -ENOMEM; | 1003 | return -ENOMEM; |
| 1000 | } | 1004 | } |
| 1001 | 1005 | ||
| 1002 | static void __net_exit ipv6_cleanup_mibs(struct net *net) | 1006 | static void ipv6_cleanup_mibs(struct net *net) |
| 1003 | { | 1007 | { |
| 1004 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 1008 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
| 1005 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 1009 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
| 1006 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 1010 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
| 1007 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 1011 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
| 1008 | snmp_mib_free((void **)net->mib.icmpv6msg_statistics); | 1012 | snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics); |
| 1009 | } | 1013 | } |
| 1010 | 1014 | ||
| 1011 | static int __net_init inet6_net_init(struct net *net) | 1015 | static int __net_init inet6_net_init(struct net *net) |
| @@ -1042,7 +1046,7 @@ out: | |||
| 1042 | #endif | 1046 | #endif |
| 1043 | } | 1047 | } |
| 1044 | 1048 | ||
| 1045 | static void inet6_net_exit(struct net *net) | 1049 | static void __net_exit inet6_net_exit(struct net *net) |
| 1046 | { | 1050 | { |
| 1047 | #ifdef CONFIG_PROC_FS | 1051 | #ifdef CONFIG_PROC_FS |
| 1048 | udp6_proc_exit(net); | 1052 | udp6_proc_exit(net); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c2f300c314be..ee82d4ef26ce 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include <crypto/hash.h> | 27 | #include <crypto/hash.h> |
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/slab.h> | ||
| 29 | #include <net/ip.h> | 30 | #include <net/ip.h> |
| 30 | #include <net/ah.h> | 31 | #include <net/ah.h> |
| 31 | #include <linux/crypto.h> | 32 | #include <linux/crypto.h> |
| @@ -614,7 +615,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 614 | type != ICMPV6_PKT_TOOBIG) | 615 | type != ICMPV6_PKT_TOOBIG) |
| 615 | return; | 616 | return; |
| 616 | 617 | ||
| 617 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); | 618 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); |
| 618 | if (!x) | 619 | if (!x) |
| 619 | return; | 620 | return; |
| 620 | 621 | ||
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f1c74c8ef9de..0e5e943446f0 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
| 30 | #include <linux/proc_fs.h> | 30 | #include <linux/proc_fs.h> |
| 31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
| 32 | #include <linux/slab.h> | ||
| 32 | 33 | ||
| 33 | #include <net/net_namespace.h> | 34 | #include <net/net_namespace.h> |
| 34 | #include <net/sock.h> | 35 | #include <net/sock.h> |
| @@ -76,41 +77,40 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
| 76 | pac->acl_next = NULL; | 77 | pac->acl_next = NULL; |
| 77 | ipv6_addr_copy(&pac->acl_addr, addr); | 78 | ipv6_addr_copy(&pac->acl_addr, addr); |
| 78 | 79 | ||
| 80 | rcu_read_lock(); | ||
| 79 | if (ifindex == 0) { | 81 | if (ifindex == 0) { |
| 80 | struct rt6_info *rt; | 82 | struct rt6_info *rt; |
| 81 | 83 | ||
| 82 | rt = rt6_lookup(net, addr, NULL, 0, 0); | 84 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
| 83 | if (rt) { | 85 | if (rt) { |
| 84 | dev = rt->rt6i_dev; | 86 | dev = rt->rt6i_dev; |
| 85 | dev_hold(dev); | 87 | dst_release(&rt->dst); |
| 86 | dst_release(&rt->u.dst); | ||
| 87 | } else if (ishost) { | 88 | } else if (ishost) { |
| 88 | err = -EADDRNOTAVAIL; | 89 | err = -EADDRNOTAVAIL; |
| 89 | goto out_free_pac; | 90 | goto error; |
| 90 | } else { | 91 | } else { |
| 91 | /* router, no matching interface: just pick one */ | 92 | /* router, no matching interface: just pick one */ |
| 92 | 93 | dev = dev_get_by_flags_rcu(net, IFF_UP, | |
| 93 | dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK); | 94 | IFF_UP | IFF_LOOPBACK); |
| 94 | } | 95 | } |
| 95 | } else | 96 | } else |
| 96 | dev = dev_get_by_index(net, ifindex); | 97 | dev = dev_get_by_index_rcu(net, ifindex); |
| 97 | 98 | ||
| 98 | if (dev == NULL) { | 99 | if (dev == NULL) { |
| 99 | err = -ENODEV; | 100 | err = -ENODEV; |
| 100 | goto out_free_pac; | 101 | goto error; |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | idev = in6_dev_get(dev); | 104 | idev = __in6_dev_get(dev); |
| 104 | if (!idev) { | 105 | if (!idev) { |
| 105 | if (ifindex) | 106 | if (ifindex) |
| 106 | err = -ENODEV; | 107 | err = -ENODEV; |
| 107 | else | 108 | else |
| 108 | err = -EADDRNOTAVAIL; | 109 | err = -EADDRNOTAVAIL; |
| 109 | goto out_dev_put; | 110 | goto error; |
| 110 | } | 111 | } |
| 111 | /* reset ishost, now that we have a specific device */ | 112 | /* reset ishost, now that we have a specific device */ |
| 112 | ishost = !idev->cnf.forwarding; | 113 | ishost = !idev->cnf.forwarding; |
| 113 | in6_dev_put(idev); | ||
| 114 | 114 | ||
| 115 | pac->acl_ifindex = dev->ifindex; | 115 | pac->acl_ifindex = dev->ifindex; |
| 116 | 116 | ||
| @@ -123,26 +123,22 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
| 123 | if (ishost) | 123 | if (ishost) |
| 124 | err = -EADDRNOTAVAIL; | 124 | err = -EADDRNOTAVAIL; |
| 125 | if (err) | 125 | if (err) |
| 126 | goto out_dev_put; | 126 | goto error; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | err = ipv6_dev_ac_inc(dev, addr); | 129 | err = ipv6_dev_ac_inc(dev, addr); |
| 130 | if (err) | 130 | if (!err) { |
| 131 | goto out_dev_put; | 131 | write_lock_bh(&ipv6_sk_ac_lock); |
| 132 | 132 | pac->acl_next = np->ipv6_ac_list; | |
| 133 | write_lock_bh(&ipv6_sk_ac_lock); | 133 | np->ipv6_ac_list = pac; |
| 134 | pac->acl_next = np->ipv6_ac_list; | 134 | write_unlock_bh(&ipv6_sk_ac_lock); |
| 135 | np->ipv6_ac_list = pac; | 135 | pac = NULL; |
| 136 | write_unlock_bh(&ipv6_sk_ac_lock); | 136 | } |
| 137 | |||
| 138 | dev_put(dev); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | 137 | ||
| 142 | out_dev_put: | 138 | error: |
| 143 | dev_put(dev); | 139 | rcu_read_unlock(); |
| 144 | out_free_pac: | 140 | if (pac) |
| 145 | sock_kfree_s(sk, pac, sizeof(*pac)); | 141 | sock_kfree_s(sk, pac, sizeof(*pac)); |
| 146 | return err; | 142 | return err; |
| 147 | } | 143 | } |
| 148 | 144 | ||
| @@ -175,11 +171,12 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
| 175 | 171 | ||
| 176 | write_unlock_bh(&ipv6_sk_ac_lock); | 172 | write_unlock_bh(&ipv6_sk_ac_lock); |
| 177 | 173 | ||
| 178 | dev = dev_get_by_index(net, pac->acl_ifindex); | 174 | rcu_read_lock(); |
| 179 | if (dev) { | 175 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); |
| 176 | if (dev) | ||
| 180 | ipv6_dev_ac_dec(dev, &pac->acl_addr); | 177 | ipv6_dev_ac_dec(dev, &pac->acl_addr); |
| 181 | dev_put(dev); | 178 | rcu_read_unlock(); |
| 182 | } | 179 | |
| 183 | sock_kfree_s(sk, pac, sizeof(*pac)); | 180 | sock_kfree_s(sk, pac, sizeof(*pac)); |
| 184 | return 0; | 181 | return 0; |
| 185 | } | 182 | } |
| @@ -198,13 +195,12 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
| 198 | write_unlock_bh(&ipv6_sk_ac_lock); | 195 | write_unlock_bh(&ipv6_sk_ac_lock); |
| 199 | 196 | ||
| 200 | prev_index = 0; | 197 | prev_index = 0; |
| 198 | rcu_read_lock(); | ||
| 201 | while (pac) { | 199 | while (pac) { |
| 202 | struct ipv6_ac_socklist *next = pac->acl_next; | 200 | struct ipv6_ac_socklist *next = pac->acl_next; |
| 203 | 201 | ||
| 204 | if (pac->acl_ifindex != prev_index) { | 202 | if (pac->acl_ifindex != prev_index) { |
| 205 | if (dev) | 203 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); |
| 206 | dev_put(dev); | ||
| 207 | dev = dev_get_by_index(net, pac->acl_ifindex); | ||
| 208 | prev_index = pac->acl_ifindex; | 204 | prev_index = pac->acl_ifindex; |
| 209 | } | 205 | } |
| 210 | if (dev) | 206 | if (dev) |
| @@ -212,8 +208,7 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
| 212 | sock_kfree_s(sk, pac, sizeof(*pac)); | 208 | sock_kfree_s(sk, pac, sizeof(*pac)); |
| 213 | pac = next; | 209 | pac = next; |
| 214 | } | 210 | } |
| 215 | if (dev) | 211 | rcu_read_unlock(); |
| 216 | dev_put(dev); | ||
| 217 | } | 212 | } |
| 218 | 213 | ||
| 219 | #if 0 | 214 | #if 0 |
| @@ -249,7 +244,7 @@ static void aca_put(struct ifacaddr6 *ac) | |||
| 249 | { | 244 | { |
| 250 | if (atomic_dec_and_test(&ac->aca_refcnt)) { | 245 | if (atomic_dec_and_test(&ac->aca_refcnt)) { |
| 251 | in6_dev_put(ac->aca_idev); | 246 | in6_dev_put(ac->aca_idev); |
| 252 | dst_release(&ac->aca_rt->u.dst); | 247 | dst_release(&ac->aca_rt->dst); |
| 253 | kfree(ac); | 248 | kfree(ac); |
| 254 | } | 249 | } |
| 255 | } | 250 | } |
| @@ -355,40 +350,39 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
| 355 | write_unlock_bh(&idev->lock); | 350 | write_unlock_bh(&idev->lock); |
| 356 | addrconf_leave_solict(idev, &aca->aca_addr); | 351 | addrconf_leave_solict(idev, &aca->aca_addr); |
| 357 | 352 | ||
| 358 | dst_hold(&aca->aca_rt->u.dst); | 353 | dst_hold(&aca->aca_rt->dst); |
| 359 | ip6_del_rt(aca->aca_rt); | 354 | ip6_del_rt(aca->aca_rt); |
| 360 | 355 | ||
| 361 | aca_put(aca); | 356 | aca_put(aca); |
| 362 | return 0; | 357 | return 0; |
| 363 | } | 358 | } |
| 364 | 359 | ||
| 360 | /* called with rcu_read_lock() */ | ||
| 365 | static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) | 361 | static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) |
| 366 | { | 362 | { |
| 367 | int ret; | 363 | struct inet6_dev *idev = __in6_dev_get(dev); |
| 368 | struct inet6_dev *idev = in6_dev_get(dev); | 364 | |
| 369 | if (idev == NULL) | 365 | if (idev == NULL) |
| 370 | return -ENODEV; | 366 | return -ENODEV; |
| 371 | ret = __ipv6_dev_ac_dec(idev, addr); | 367 | return __ipv6_dev_ac_dec(idev, addr); |
| 372 | in6_dev_put(idev); | ||
| 373 | return ret; | ||
| 374 | } | 368 | } |
| 375 | 369 | ||
| 376 | /* | 370 | /* |
| 377 | * check if the interface has this anycast address | 371 | * check if the interface has this anycast address |
| 372 | * called with rcu_read_lock() | ||
| 378 | */ | 373 | */ |
| 379 | static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) | 374 | static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) |
| 380 | { | 375 | { |
| 381 | struct inet6_dev *idev; | 376 | struct inet6_dev *idev; |
| 382 | struct ifacaddr6 *aca; | 377 | struct ifacaddr6 *aca; |
| 383 | 378 | ||
| 384 | idev = in6_dev_get(dev); | 379 | idev = __in6_dev_get(dev); |
| 385 | if (idev) { | 380 | if (idev) { |
| 386 | read_lock_bh(&idev->lock); | 381 | read_lock_bh(&idev->lock); |
| 387 | for (aca = idev->ac_list; aca; aca = aca->aca_next) | 382 | for (aca = idev->ac_list; aca; aca = aca->aca_next) |
| 388 | if (ipv6_addr_equal(&aca->aca_addr, addr)) | 383 | if (ipv6_addr_equal(&aca->aca_addr, addr)) |
| 389 | break; | 384 | break; |
| 390 | read_unlock_bh(&idev->lock); | 385 | read_unlock_bh(&idev->lock); |
| 391 | in6_dev_put(idev); | ||
| 392 | return aca != NULL; | 386 | return aca != NULL; |
| 393 | } | 387 | } |
| 394 | return 0; | 388 | return 0; |
| @@ -402,14 +396,15 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, | |||
| 402 | { | 396 | { |
| 403 | int found = 0; | 397 | int found = 0; |
| 404 | 398 | ||
| 405 | if (dev) | ||
| 406 | return ipv6_chk_acast_dev(dev, addr); | ||
| 407 | rcu_read_lock(); | 399 | rcu_read_lock(); |
| 408 | for_each_netdev_rcu(net, dev) | 400 | if (dev) |
| 409 | if (ipv6_chk_acast_dev(dev, addr)) { | 401 | found = ipv6_chk_acast_dev(dev, addr); |
| 410 | found = 1; | 402 | else |
| 411 | break; | 403 | for_each_netdev_rcu(net, dev) |
| 412 | } | 404 | if (ipv6_chk_acast_dev(dev, addr)) { |
| 405 | found = 1; | ||
| 406 | break; | ||
| 407 | } | ||
| 413 | rcu_read_unlock(); | 408 | rcu_read_unlock(); |
| 414 | return found; | 409 | return found; |
| 415 | } | 410 | } |
| @@ -538,7 +533,7 @@ static const struct file_operations ac6_seq_fops = { | |||
| 538 | .release = seq_release_net, | 533 | .release = seq_release_net, |
| 539 | }; | 534 | }; |
| 540 | 535 | ||
| 541 | int ac6_proc_init(struct net *net) | 536 | int __net_init ac6_proc_init(struct net *net) |
| 542 | { | 537 | { |
| 543 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) | 538 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) |
| 544 | return -ENOMEM; | 539 | return -ENOMEM; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index e6f9cdf780fe..ef371aa01ac5 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/in6.h> | 21 | #include <linux/in6.h> |
| 22 | #include <linux/ipv6.h> | 22 | #include <linux/ipv6.h> |
| 23 | #include <linux/route.h> | 23 | #include <linux/route.h> |
| 24 | #include <linux/slab.h> | ||
| 24 | 25 | ||
| 25 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
| 26 | #include <net/ndisc.h> | 27 | #include <net/ndisc.h> |
| @@ -37,10 +38,11 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 37 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 38 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; |
| 38 | struct inet_sock *inet = inet_sk(sk); | 39 | struct inet_sock *inet = inet_sk(sk); |
| 39 | struct ipv6_pinfo *np = inet6_sk(sk); | 40 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 40 | struct in6_addr *daddr, *final_p = NULL, final; | 41 | struct in6_addr *daddr, *final_p, final; |
| 41 | struct dst_entry *dst; | 42 | struct dst_entry *dst; |
| 42 | struct flowi fl; | 43 | struct flowi fl; |
| 43 | struct ip6_flowlabel *flowlabel = NULL; | 44 | struct ip6_flowlabel *flowlabel = NULL; |
| 45 | struct ipv6_txoptions *opt; | ||
| 44 | int addr_type; | 46 | int addr_type; |
| 45 | int err; | 47 | int err; |
| 46 | 48 | ||
| @@ -103,9 +105,12 @@ ipv4_connected: | |||
| 103 | if (ipv6_addr_any(&np->saddr)) | 105 | if (ipv6_addr_any(&np->saddr)) |
| 104 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); | 106 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); |
| 105 | 107 | ||
| 106 | if (ipv6_addr_any(&np->rcv_saddr)) | 108 | if (ipv6_addr_any(&np->rcv_saddr)) { |
| 107 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, | 109 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, |
| 108 | &np->rcv_saddr); | 110 | &np->rcv_saddr); |
| 111 | if (sk->sk_prot->rehash) | ||
| 112 | sk->sk_prot->rehash(sk); | ||
| 113 | } | ||
| 109 | 114 | ||
| 110 | goto out; | 115 | goto out; |
| 111 | } | 116 | } |
| @@ -154,19 +159,8 @@ ipv4_connected: | |||
| 154 | 159 | ||
| 155 | security_sk_classify_flow(sk, &fl); | 160 | security_sk_classify_flow(sk, &fl); |
| 156 | 161 | ||
| 157 | if (flowlabel) { | 162 | opt = flowlabel ? flowlabel->opt : np->opt; |
| 158 | if (flowlabel->opt && flowlabel->opt->srcrt) { | 163 | final_p = fl6_update_dst(&fl, opt, &final); |
| 159 | struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; | ||
| 160 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 161 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 162 | final_p = &final; | ||
| 163 | } | ||
| 164 | } else if (np->opt && np->opt->srcrt) { | ||
| 165 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
| 166 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 167 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 168 | final_p = &final; | ||
| 169 | } | ||
| 170 | 164 | ||
| 171 | err = ip6_dst_lookup(sk, &dst, &fl); | 165 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 172 | if (err) | 166 | if (err) |
| @@ -190,6 +184,8 @@ ipv4_connected: | |||
| 190 | if (ipv6_addr_any(&np->rcv_saddr)) { | 184 | if (ipv6_addr_any(&np->rcv_saddr)) { |
| 191 | ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); | 185 | ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); |
| 192 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; | 186 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; |
| 187 | if (sk->sk_prot->rehash) | ||
| 188 | sk->sk_prot->rehash(sk); | ||
| 193 | } | 189 | } |
| 194 | 190 | ||
| 195 | ip6_dst_store(sk, dst, | 191 | ip6_dst_store(sk, dst, |
| @@ -221,6 +217,8 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, | |||
| 221 | if (!skb) | 217 | if (!skb) |
| 222 | return; | 218 | return; |
| 223 | 219 | ||
| 220 | skb->protocol = htons(ETH_P_IPV6); | ||
| 221 | |||
| 224 | serr = SKB_EXT_ERR(skb); | 222 | serr = SKB_EXT_ERR(skb); |
| 225 | serr->ee.ee_errno = err; | 223 | serr->ee.ee_errno = err; |
| 226 | serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6; | 224 | serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6; |
| @@ -254,6 +252,8 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
| 254 | if (!skb) | 252 | if (!skb) |
| 255 | return; | 253 | return; |
| 256 | 254 | ||
| 255 | skb->protocol = htons(ETH_P_IPV6); | ||
| 256 | |||
| 257 | skb_put(skb, sizeof(struct ipv6hdr)); | 257 | skb_put(skb, sizeof(struct ipv6hdr)); |
| 258 | skb_reset_network_header(skb); | 258 | skb_reset_network_header(skb); |
| 259 | iph = ipv6_hdr(skb); | 259 | iph = ipv6_hdr(skb); |
| @@ -277,6 +277,45 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
| 277 | kfree_skb(skb); | 277 | kfree_skb(skb); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu) | ||
| 281 | { | ||
| 282 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 283 | struct ipv6hdr *iph; | ||
| 284 | struct sk_buff *skb; | ||
| 285 | struct ip6_mtuinfo *mtu_info; | ||
| 286 | |||
| 287 | if (!np->rxopt.bits.rxpmtu) | ||
| 288 | return; | ||
| 289 | |||
| 290 | skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); | ||
| 291 | if (!skb) | ||
| 292 | return; | ||
| 293 | |||
| 294 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
| 295 | skb_reset_network_header(skb); | ||
| 296 | iph = ipv6_hdr(skb); | ||
| 297 | ipv6_addr_copy(&iph->daddr, &fl->fl6_dst); | ||
| 298 | |||
| 299 | mtu_info = IP6CBMTU(skb); | ||
| 300 | if (!mtu_info) { | ||
| 301 | kfree_skb(skb); | ||
| 302 | return; | ||
| 303 | } | ||
| 304 | |||
| 305 | mtu_info->ip6m_mtu = mtu; | ||
| 306 | mtu_info->ip6m_addr.sin6_family = AF_INET6; | ||
| 307 | mtu_info->ip6m_addr.sin6_port = 0; | ||
| 308 | mtu_info->ip6m_addr.sin6_flowinfo = 0; | ||
| 309 | mtu_info->ip6m_addr.sin6_scope_id = fl->oif; | ||
| 310 | ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr); | ||
| 311 | |||
| 312 | __skb_pull(skb, skb_tail_pointer(skb) - skb->data); | ||
| 313 | skb_reset_transport_header(skb); | ||
| 314 | |||
| 315 | skb = xchg(&np->rxpmtu, skb); | ||
| 316 | kfree_skb(skb); | ||
| 317 | } | ||
| 318 | |||
| 280 | /* | 319 | /* |
| 281 | * Handle MSG_ERRQUEUE | 320 | * Handle MSG_ERRQUEUE |
| 282 | */ | 321 | */ |
| @@ -318,7 +357,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
| 318 | sin->sin6_flowinfo = 0; | 357 | sin->sin6_flowinfo = 0; |
| 319 | sin->sin6_port = serr->port; | 358 | sin->sin6_port = serr->port; |
| 320 | sin->sin6_scope_id = 0; | 359 | sin->sin6_scope_id = 0; |
| 321 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) { | 360 | if (skb->protocol == htons(ETH_P_IPV6)) { |
| 322 | ipv6_addr_copy(&sin->sin6_addr, | 361 | ipv6_addr_copy(&sin->sin6_addr, |
| 323 | (struct in6_addr *)(nh + serr->addr_offset)); | 362 | (struct in6_addr *)(nh + serr->addr_offset)); |
| 324 | if (np->sndflow) | 363 | if (np->sndflow) |
| @@ -340,7 +379,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
| 340 | sin->sin6_family = AF_INET6; | 379 | sin->sin6_family = AF_INET6; |
| 341 | sin->sin6_flowinfo = 0; | 380 | sin->sin6_flowinfo = 0; |
| 342 | sin->sin6_scope_id = 0; | 381 | sin->sin6_scope_id = 0; |
| 343 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) { | 382 | if (skb->protocol == htons(ETH_P_IPV6)) { |
| 344 | ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr); | 383 | ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr); |
| 345 | if (np->rxopt.all) | 384 | if (np->rxopt.all) |
| 346 | datagram_recv_ctl(sk, msg, skb); | 385 | datagram_recv_ctl(sk, msg, skb); |
| @@ -380,6 +419,54 @@ out: | |||
| 380 | return err; | 419 | return err; |
| 381 | } | 420 | } |
| 382 | 421 | ||
| 422 | /* | ||
| 423 | * Handle IPV6_RECVPATHMTU | ||
| 424 | */ | ||
| 425 | int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len) | ||
| 426 | { | ||
| 427 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 428 | struct sk_buff *skb; | ||
| 429 | struct sockaddr_in6 *sin; | ||
| 430 | struct ip6_mtuinfo mtu_info; | ||
| 431 | int err; | ||
| 432 | int copied; | ||
| 433 | |||
| 434 | err = -EAGAIN; | ||
| 435 | skb = xchg(&np->rxpmtu, NULL); | ||
| 436 | if (skb == NULL) | ||
| 437 | goto out; | ||
| 438 | |||
| 439 | copied = skb->len; | ||
| 440 | if (copied > len) { | ||
| 441 | msg->msg_flags |= MSG_TRUNC; | ||
| 442 | copied = len; | ||
| 443 | } | ||
| 444 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
| 445 | if (err) | ||
| 446 | goto out_free_skb; | ||
| 447 | |||
| 448 | sock_recv_timestamp(msg, sk, skb); | ||
| 449 | |||
| 450 | memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info)); | ||
| 451 | |||
| 452 | sin = (struct sockaddr_in6 *)msg->msg_name; | ||
| 453 | if (sin) { | ||
| 454 | sin->sin6_family = AF_INET6; | ||
| 455 | sin->sin6_flowinfo = 0; | ||
| 456 | sin->sin6_port = 0; | ||
| 457 | sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; | ||
| 458 | ipv6_addr_copy(&sin->sin6_addr, &mtu_info.ip6m_addr.sin6_addr); | ||
| 459 | } | ||
| 460 | |||
| 461 | put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); | ||
| 462 | |||
| 463 | err = copied; | ||
| 464 | |||
| 465 | out_free_skb: | ||
| 466 | kfree_skb(skb); | ||
| 467 | out: | ||
| 468 | return err; | ||
| 469 | } | ||
| 383 | 470 | ||
| 384 | 471 | ||
| 385 | int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | 472 | int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) |
| @@ -496,7 +583,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
| 496 | int datagram_send_ctl(struct net *net, | 583 | int datagram_send_ctl(struct net *net, |
| 497 | struct msghdr *msg, struct flowi *fl, | 584 | struct msghdr *msg, struct flowi *fl, |
| 498 | struct ipv6_txoptions *opt, | 585 | struct ipv6_txoptions *opt, |
| 499 | int *hlimit, int *tclass) | 586 | int *hlimit, int *tclass, int *dontfrag) |
| 500 | { | 587 | { |
| 501 | struct in6_pktinfo *src_info; | 588 | struct in6_pktinfo *src_info; |
| 502 | struct cmsghdr *cmsg; | 589 | struct cmsghdr *cmsg; |
| @@ -736,6 +823,25 @@ int datagram_send_ctl(struct net *net, | |||
| 736 | 823 | ||
| 737 | break; | 824 | break; |
| 738 | } | 825 | } |
| 826 | |||
| 827 | case IPV6_DONTFRAG: | ||
| 828 | { | ||
| 829 | int df; | ||
| 830 | |||
| 831 | err = -EINVAL; | ||
| 832 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { | ||
| 833 | goto exit_f; | ||
| 834 | } | ||
| 835 | |||
| 836 | df = *(int *)CMSG_DATA(cmsg); | ||
| 837 | if (df < 0 || df > 1) | ||
| 838 | goto exit_f; | ||
| 839 | |||
| 840 | err = 0; | ||
| 841 | *dontfrag = df; | ||
| 842 | |||
| 843 | break; | ||
| 844 | } | ||
| 739 | default: | 845 | default: |
| 740 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", | 846 | LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n", |
| 741 | cmsg->cmsg_type); | 847 | cmsg->cmsg_type); |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 668a46b655e6..ee9b93bdd6a2 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
| @@ -365,7 +365,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 365 | type != ICMPV6_PKT_TOOBIG) | 365 | type != ICMPV6_PKT_TOOBIG) |
| 366 | return; | 366 | return; |
| 367 | 367 | ||
| 368 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); | 368 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); |
| 369 | if (!x) | 369 | if (!x) |
| 370 | return; | 370 | return; |
| 371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", | 371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 4bac362b1335..262f105d23b9 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
| 30 | #include <linux/in6.h> | 30 | #include <linux/in6.h> |
| 31 | #include <linux/icmpv6.h> | 31 | #include <linux/icmpv6.h> |
| 32 | #include <linux/slab.h> | ||
| 32 | 33 | ||
| 33 | #include <net/dst.h> | 34 | #include <net/dst.h> |
| 34 | #include <net/sock.h> | 35 | #include <net/sock.h> |
| @@ -311,6 +312,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb) | |||
| 311 | Routing header. | 312 | Routing header. |
| 312 | ********************************/ | 313 | ********************************/ |
| 313 | 314 | ||
| 315 | /* called with rcu_read_lock() */ | ||
| 314 | static int ipv6_rthdr_rcv(struct sk_buff *skb) | 316 | static int ipv6_rthdr_rcv(struct sk_buff *skb) |
| 315 | { | 317 | { |
| 316 | struct inet6_skb_parm *opt = IP6CB(skb); | 318 | struct inet6_skb_parm *opt = IP6CB(skb); |
| @@ -323,12 +325,9 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb) | |||
| 323 | struct net *net = dev_net(skb->dev); | 325 | struct net *net = dev_net(skb->dev); |
| 324 | int accept_source_route = net->ipv6.devconf_all->accept_source_route; | 326 | int accept_source_route = net->ipv6.devconf_all->accept_source_route; |
| 325 | 327 | ||
| 326 | idev = in6_dev_get(skb->dev); | 328 | idev = __in6_dev_get(skb->dev); |
| 327 | if (idev) { | 329 | if (idev && accept_source_route > idev->cnf.accept_source_route) |
| 328 | if (accept_source_route > idev->cnf.accept_source_route) | 330 | accept_source_route = idev->cnf.accept_source_route; |
| 329 | accept_source_route = idev->cnf.accept_source_route; | ||
| 330 | in6_dev_put(idev); | ||
| 331 | } | ||
| 332 | 331 | ||
| 333 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || | 332 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || |
| 334 | !pskb_may_pull(skb, (skb_transport_offset(skb) + | 333 | !pskb_may_pull(skb, (skb_transport_offset(skb) + |
| @@ -481,7 +480,7 @@ looped_back: | |||
| 481 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | 480 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
| 482 | IPSTATS_MIB_INHDRERRORS); | 481 | IPSTATS_MIB_INHDRERRORS); |
| 483 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 482 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
| 484 | 0, skb->dev); | 483 | 0); |
| 485 | kfree_skb(skb); | 484 | kfree_skb(skb); |
| 486 | return -1; | 485 | return -1; |
| 487 | } | 486 | } |
| @@ -873,3 +872,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, | |||
| 873 | return opt; | 872 | return opt; |
| 874 | } | 873 | } |
| 875 | 874 | ||
| 875 | /** | ||
| 876 | * fl6_update_dst - update flowi destination address with info given | ||
| 877 | * by srcrt option, if any. | ||
| 878 | * | ||
| 879 | * @fl: flowi for which fl6_dst is to be updated | ||
| 880 | * @opt: struct ipv6_txoptions in which to look for srcrt opt | ||
| 881 | * @orig: copy of original fl6_dst address if modified | ||
| 882 | * | ||
| 883 | * Returns NULL if no txoptions or no srcrt, otherwise returns orig | ||
| 884 | * and initial value of fl->fl6_dst set in orig | ||
| 885 | */ | ||
| 886 | struct in6_addr *fl6_update_dst(struct flowi *fl, | ||
| 887 | const struct ipv6_txoptions *opt, | ||
| 888 | struct in6_addr *orig) | ||
| 889 | { | ||
| 890 | if (!opt || !opt->srcrt) | ||
| 891 | return NULL; | ||
| 892 | |||
| 893 | ipv6_addr_copy(orig, &fl->fl6_dst); | ||
| 894 | ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr); | ||
| 895 | return orig; | ||
| 896 | } | ||
| 897 | |||
| 898 | EXPORT_SYMBOL_GPL(fl6_update_dst); | ||
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b7aa7c64cc4a..b1108ede18e1 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
| @@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
| 43 | if (arg.result) | 43 | if (arg.result) |
| 44 | return arg.result; | 44 | return arg.result; |
| 45 | 45 | ||
| 46 | dst_hold(&net->ipv6.ip6_null_entry->u.dst); | 46 | dst_hold(&net->ipv6.ip6_null_entry->dst); |
| 47 | return &net->ipv6.ip6_null_entry->u.dst; | 47 | return &net->ipv6.ip6_null_entry->dst; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | 50 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, |
| @@ -84,18 +84,11 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
| 84 | if ((rule->flags & FIB_RULE_FIND_SADDR) && | 84 | if ((rule->flags & FIB_RULE_FIND_SADDR) && |
| 85 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { | 85 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { |
| 86 | struct in6_addr saddr; | 86 | struct in6_addr saddr; |
| 87 | unsigned int srcprefs = 0; | ||
| 88 | |||
| 89 | if (flags & RT6_LOOKUP_F_SRCPREF_TMP) | ||
| 90 | srcprefs |= IPV6_PREFER_SRC_TMP; | ||
| 91 | if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC) | ||
| 92 | srcprefs |= IPV6_PREFER_SRC_PUBLIC; | ||
| 93 | if (flags & RT6_LOOKUP_F_SRCPREF_COA) | ||
| 94 | srcprefs |= IPV6_PREFER_SRC_COA; | ||
| 95 | 87 | ||
| 96 | if (ipv6_dev_get_saddr(net, | 88 | if (ipv6_dev_get_saddr(net, |
| 97 | ip6_dst_idev(&rt->u.dst)->dev, | 89 | ip6_dst_idev(&rt->dst)->dev, |
| 98 | &flp->fl6_dst, srcprefs, | 90 | &flp->fl6_dst, |
| 91 | rt6_flags2srcprefs(flags), | ||
| 99 | &saddr)) | 92 | &saddr)) |
| 100 | goto again; | 93 | goto again; |
| 101 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, | 94 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, |
| @@ -106,12 +99,12 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
| 106 | goto out; | 99 | goto out; |
| 107 | } | 100 | } |
| 108 | again: | 101 | again: |
| 109 | dst_release(&rt->u.dst); | 102 | dst_release(&rt->dst); |
| 110 | rt = NULL; | 103 | rt = NULL; |
| 111 | goto out; | 104 | goto out; |
| 112 | 105 | ||
| 113 | discard_pkt: | 106 | discard_pkt: |
| 114 | dst_hold(&rt->u.dst); | 107 | dst_hold(&rt->dst); |
| 115 | out: | 108 | out: |
| 116 | arg->result = rt; | 109 | arg->result = rt; |
| 117 | return rt == NULL ? -EAGAIN : 0; | 110 | return rt == NULL ? -EAGAIN : 0; |
| @@ -215,7 +208,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | |||
| 215 | { | 208 | { |
| 216 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | 209 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; |
| 217 | 210 | ||
| 218 | frh->family = AF_INET6; | ||
| 219 | frh->dst_len = rule6->dst.plen; | 211 | frh->dst_len = rule6->dst.plen; |
| 220 | frh->src_len = rule6->src.plen; | 212 | frh->src_len = rule6->src.plen; |
| 221 | frh->tos = rule6->tclass; | 213 | frh->tos = rule6->tclass; |
| @@ -245,7 +237,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) | |||
| 245 | + nla_total_size(16); /* src */ | 237 | + nla_total_size(16); /* src */ |
| 246 | } | 238 | } |
| 247 | 239 | ||
| 248 | static struct fib_rules_ops fib6_rules_ops_template = { | 240 | static const struct fib_rules_ops __net_initdata fib6_rules_ops_template = { |
| 249 | .family = AF_INET6, | 241 | .family = AF_INET6, |
| 250 | .rule_size = sizeof(struct fib6_rule), | 242 | .rule_size = sizeof(struct fib6_rule), |
| 251 | .addr_size = sizeof(struct in6_addr), | 243 | .addr_size = sizeof(struct in6_addr), |
| @@ -262,7 +254,7 @@ static struct fib_rules_ops fib6_rules_ops_template = { | |||
| 262 | .fro_net = &init_net, | 254 | .fro_net = &init_net, |
| 263 | }; | 255 | }; |
| 264 | 256 | ||
| 265 | static int fib6_rules_net_init(struct net *net) | 257 | static int __net_init fib6_rules_net_init(struct net *net) |
| 266 | { | 258 | { |
| 267 | struct fib_rules_ops *ops; | 259 | struct fib_rules_ops *ops; |
| 268 | int err = -ENOMEM; | 260 | int err = -ENOMEM; |
| @@ -291,7 +283,7 @@ out_fib6_rules_ops: | |||
| 291 | goto out; | 283 | goto out; |
| 292 | } | 284 | } |
| 293 | 285 | ||
| 294 | static void fib6_rules_net_exit(struct net *net) | 286 | static void __net_exit fib6_rules_net_exit(struct net *net) |
| 295 | { | 287 | { |
| 296 | fib_rules_unregister(net->ipv6.fib6_rules_ops); | 288 | fib_rules_unregister(net->ipv6.fib6_rules_ops); |
| 297 | } | 289 | } |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 4ae661bc3677..03e62f94ff8e 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
| 41 | #include <linux/init.h> | 41 | #include <linux/init.h> |
| 42 | #include <linux/netfilter.h> | 42 | #include <linux/netfilter.h> |
| 43 | #include <linux/slab.h> | ||
| 43 | 44 | ||
| 44 | #ifdef CONFIG_SYSCTL | 45 | #ifdef CONFIG_SYSCTL |
| 45 | #include <linux/sysctl.h> | 46 | #include <linux/sysctl.h> |
| @@ -67,11 +68,6 @@ | |||
| 67 | #include <asm/uaccess.h> | 68 | #include <asm/uaccess.h> |
| 68 | #include <asm/system.h> | 69 | #include <asm/system.h> |
| 69 | 70 | ||
| 70 | DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly; | ||
| 71 | EXPORT_SYMBOL(icmpv6_statistics); | ||
| 72 | DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics) __read_mostly; | ||
| 73 | EXPORT_SYMBOL(icmpv6msg_statistics); | ||
| 74 | |||
| 75 | /* | 71 | /* |
| 76 | * The ICMP socket(s). This is the most convenient way to flow control | 72 | * The ICMP socket(s). This is the most convenient way to flow control |
| 77 | * our ICMP output as well as maintain a clean interface throughout | 73 | * our ICMP output as well as maintain a clean interface throughout |
| @@ -119,7 +115,7 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk) | |||
| 119 | */ | 115 | */ |
| 120 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) | 116 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) |
| 121 | { | 117 | { |
| 122 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | 118 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); |
| 123 | kfree_skb(skb); | 119 | kfree_skb(skb); |
| 124 | } | 120 | } |
| 125 | 121 | ||
| @@ -305,8 +301,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} | |||
| 305 | /* | 301 | /* |
| 306 | * Send an ICMP message in response to a packet in error | 302 | * Send an ICMP message in response to a packet in error |
| 307 | */ | 303 | */ |
| 308 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | 304 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) |
| 309 | struct net_device *dev) | ||
| 310 | { | 305 | { |
| 311 | struct net *net = dev_net(skb->dev); | 306 | struct net *net = dev_net(skb->dev); |
| 312 | struct inet6_dev *idev = NULL; | 307 | struct inet6_dev *idev = NULL; |
| @@ -486,8 +481,9 @@ route_done: | |||
| 486 | len + sizeof(struct icmp6hdr), | 481 | len + sizeof(struct icmp6hdr), |
| 487 | sizeof(struct icmp6hdr), hlimit, | 482 | sizeof(struct icmp6hdr), hlimit, |
| 488 | np->tclass, NULL, &fl, (struct rt6_info*)dst, | 483 | np->tclass, NULL, &fl, (struct rt6_info*)dst, |
| 489 | MSG_DONTWAIT); | 484 | MSG_DONTWAIT, np->dontfrag); |
| 490 | if (err) { | 485 | if (err) { |
| 486 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); | ||
| 491 | ip6_flush_pending_frames(sk); | 487 | ip6_flush_pending_frames(sk); |
| 492 | goto out_put; | 488 | goto out_put; |
| 493 | } | 489 | } |
| @@ -565,9 +561,11 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 565 | 561 | ||
| 566 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), | 562 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), |
| 567 | sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl, | 563 | sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl, |
| 568 | (struct rt6_info*)dst, MSG_DONTWAIT); | 564 | (struct rt6_info*)dst, MSG_DONTWAIT, |
| 565 | np->dontfrag); | ||
| 569 | 566 | ||
| 570 | if (err) { | 567 | if (err) { |
| 568 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); | ||
| 571 | ip6_flush_pending_frames(sk); | 569 | ip6_flush_pending_frames(sk); |
| 572 | goto out_put; | 570 | goto out_put; |
| 573 | } | 571 | } |
| @@ -951,7 +949,7 @@ ctl_table ipv6_icmp_table_template[] = { | |||
| 951 | { }, | 949 | { }, |
| 952 | }; | 950 | }; |
| 953 | 951 | ||
| 954 | struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) | 952 | struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) |
| 955 | { | 953 | { |
| 956 | struct ctl_table *table; | 954 | struct ctl_table *table; |
| 957 | 955 | ||
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 3516e6fe2e56..8a1628023bd1 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/in6.h> | 17 | #include <linux/in6.h> |
| 18 | #include <linux/ipv6.h> | 18 | #include <linux/ipv6.h> |
| 19 | #include <linux/jhash.h> | 19 | #include <linux/jhash.h> |
| 20 | #include <linux/slab.h> | ||
| 20 | 21 | ||
| 21 | #include <net/addrconf.h> | 22 | #include <net/addrconf.h> |
| 22 | #include <net/inet_connection_sock.h> | 23 | #include <net/inet_connection_sock.h> |
| @@ -177,14 +178,14 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) | |||
| 177 | return dst; | 178 | return dst; |
| 178 | } | 179 | } |
| 179 | 180 | ||
| 180 | int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | 181 | int inet6_csk_xmit(struct sk_buff *skb) |
| 181 | { | 182 | { |
| 182 | struct sock *sk = skb->sk; | 183 | struct sock *sk = skb->sk; |
| 183 | struct inet_sock *inet = inet_sk(sk); | 184 | struct inet_sock *inet = inet_sk(sk); |
| 184 | struct ipv6_pinfo *np = inet6_sk(sk); | 185 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 185 | struct flowi fl; | 186 | struct flowi fl; |
| 186 | struct dst_entry *dst; | 187 | struct dst_entry *dst; |
| 187 | struct in6_addr *final_p = NULL, final; | 188 | struct in6_addr *final_p, final; |
| 188 | 189 | ||
| 189 | memset(&fl, 0, sizeof(fl)); | 190 | memset(&fl, 0, sizeof(fl)); |
| 190 | fl.proto = sk->sk_protocol; | 191 | fl.proto = sk->sk_protocol; |
| @@ -198,12 +199,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
| 198 | fl.fl_ip_dport = inet->inet_dport; | 199 | fl.fl_ip_dport = inet->inet_dport; |
| 199 | security_sk_classify_flow(sk, &fl); | 200 | security_sk_classify_flow(sk, &fl); |
| 200 | 201 | ||
| 201 | if (np->opt && np->opt->srcrt) { | 202 | final_p = fl6_update_dst(&fl, np->opt, &final); |
| 202 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
| 203 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 204 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 205 | final_p = &final; | ||
| 206 | } | ||
| 207 | 203 | ||
| 208 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); | 204 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); |
| 209 | 205 | ||
| @@ -233,7 +229,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
| 233 | /* Restore final destination back after routing done */ | 229 | /* Restore final destination back after routing done */ |
| 234 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 230 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); |
| 235 | 231 | ||
| 236 | return ip6_xmit(sk, skb, &fl, np->opt, 0); | 232 | return ip6_xmit(sk, skb, &fl, np->opt); |
| 237 | } | 233 | } |
| 238 | 234 | ||
| 239 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); | 235 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0e93ca56eb69..b6a585909d35 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/in6.h> | 26 | #include <linux/in6.h> |
| 27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
| 28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
| 29 | #include <linux/slab.h> | ||
| 29 | 30 | ||
| 30 | #ifdef CONFIG_PROC_FS | 31 | #ifdef CONFIG_PROC_FS |
| 31 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
| @@ -93,29 +94,20 @@ static __u32 rt_sernum; | |||
| 93 | 94 | ||
| 94 | static void fib6_gc_timer_cb(unsigned long arg); | 95 | static void fib6_gc_timer_cb(unsigned long arg); |
| 95 | 96 | ||
| 96 | static struct fib6_walker_t fib6_walker_list = { | 97 | static LIST_HEAD(fib6_walkers); |
| 97 | .prev = &fib6_walker_list, | 98 | #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) |
| 98 | .next = &fib6_walker_list, | ||
| 99 | }; | ||
| 100 | |||
| 101 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) | ||
| 102 | 99 | ||
| 103 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 100 | static inline void fib6_walker_link(struct fib6_walker_t *w) |
| 104 | { | 101 | { |
| 105 | write_lock_bh(&fib6_walker_lock); | 102 | write_lock_bh(&fib6_walker_lock); |
| 106 | w->next = fib6_walker_list.next; | 103 | list_add(&w->lh, &fib6_walkers); |
| 107 | w->prev = &fib6_walker_list; | ||
| 108 | w->next->prev = w; | ||
| 109 | w->prev->next = w; | ||
| 110 | write_unlock_bh(&fib6_walker_lock); | 104 | write_unlock_bh(&fib6_walker_lock); |
| 111 | } | 105 | } |
| 112 | 106 | ||
| 113 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 107 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) |
| 114 | { | 108 | { |
| 115 | write_lock_bh(&fib6_walker_lock); | 109 | write_lock_bh(&fib6_walker_lock); |
| 116 | w->next->prev = w->prev; | 110 | list_del(&w->lh); |
| 117 | w->prev->next = w->next; | ||
| 118 | w->prev = w->next = w; | ||
| 119 | write_unlock_bh(&fib6_walker_lock); | 111 | write_unlock_bh(&fib6_walker_lock); |
| 120 | } | 112 | } |
| 121 | static __inline__ u32 fib6_new_sernum(void) | 113 | static __inline__ u32 fib6_new_sernum(void) |
| @@ -136,12 +128,24 @@ static __inline__ u32 fib6_new_sernum(void) | |||
| 136 | /* | 128 | /* |
| 137 | * test bit | 129 | * test bit |
| 138 | */ | 130 | */ |
| 131 | #if defined(__LITTLE_ENDIAN) | ||
| 132 | # define BITOP_BE32_SWIZZLE (0x1F & ~7) | ||
| 133 | #else | ||
| 134 | # define BITOP_BE32_SWIZZLE 0 | ||
| 135 | #endif | ||
| 139 | 136 | ||
| 140 | static __inline__ __be32 addr_bit_set(void *token, int fn_bit) | 137 | static __inline__ __be32 addr_bit_set(void *token, int fn_bit) |
| 141 | { | 138 | { |
| 142 | __be32 *addr = token; | 139 | __be32 *addr = token; |
| 143 | 140 | /* | |
| 144 | return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5]; | 141 | * Here, |
| 142 | * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) | ||
| 143 | * is optimized version of | ||
| 144 | * htonl(1 << ((~fn_bit)&0x1F)) | ||
| 145 | * See include/asm-generic/bitops/le.h. | ||
| 146 | */ | ||
| 147 | return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) & | ||
| 148 | addr[fn_bit >> 5]; | ||
| 145 | } | 149 | } |
| 146 | 150 | ||
| 147 | static __inline__ struct fib6_node * node_alloc(void) | 151 | static __inline__ struct fib6_node * node_alloc(void) |
| @@ -161,7 +165,7 @@ static __inline__ void node_free(struct fib6_node * fn) | |||
| 161 | static __inline__ void rt6_release(struct rt6_info *rt) | 165 | static __inline__ void rt6_release(struct rt6_info *rt) |
| 162 | { | 166 | { |
| 163 | if (atomic_dec_and_test(&rt->rt6i_ref)) | 167 | if (atomic_dec_and_test(&rt->rt6i_ref)) |
| 164 | dst_free(&rt->u.dst); | 168 | dst_free(&rt->dst); |
| 165 | } | 169 | } |
| 166 | 170 | ||
| 167 | static void fib6_link_table(struct net *net, struct fib6_table *tb) | 171 | static void fib6_link_table(struct net *net, struct fib6_table *tb) |
| @@ -239,7 +243,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
| 239 | return NULL; | 243 | return NULL; |
| 240 | } | 244 | } |
| 241 | 245 | ||
| 242 | static void fib6_tables_init(struct net *net) | 246 | static void __net_init fib6_tables_init(struct net *net) |
| 243 | { | 247 | { |
| 244 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 248 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
| 245 | fib6_link_table(net, net->ipv6.fib6_local_tbl); | 249 | fib6_link_table(net, net->ipv6.fib6_local_tbl); |
| @@ -262,7 +266,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
| 262 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); | 266 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); |
| 263 | } | 267 | } |
| 264 | 268 | ||
| 265 | static void fib6_tables_init(struct net *net) | 269 | static void __net_init fib6_tables_init(struct net *net) |
| 266 | { | 270 | { |
| 267 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 271 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
| 268 | } | 272 | } |
| @@ -274,7 +278,7 @@ static int fib6_dump_node(struct fib6_walker_t *w) | |||
| 274 | int res; | 278 | int res; |
| 275 | struct rt6_info *rt; | 279 | struct rt6_info *rt; |
| 276 | 280 | ||
| 277 | for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { | 281 | for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { |
| 278 | res = rt6_dump_route(rt, w->args); | 282 | res = rt6_dump_route(rt, w->args); |
| 279 | if (res < 0) { | 283 | if (res < 0) { |
| 280 | /* Frame is full, suspend walking */ | 284 | /* Frame is full, suspend walking */ |
| @@ -319,12 +323,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | |||
| 319 | w->root = &table->tb6_root; | 323 | w->root = &table->tb6_root; |
| 320 | 324 | ||
| 321 | if (cb->args[4] == 0) { | 325 | if (cb->args[4] == 0) { |
| 326 | w->count = 0; | ||
| 327 | w->skip = 0; | ||
| 328 | |||
| 322 | read_lock_bh(&table->tb6_lock); | 329 | read_lock_bh(&table->tb6_lock); |
| 323 | res = fib6_walk(w); | 330 | res = fib6_walk(w); |
| 324 | read_unlock_bh(&table->tb6_lock); | 331 | read_unlock_bh(&table->tb6_lock); |
| 325 | if (res > 0) | 332 | if (res > 0) { |
| 326 | cb->args[4] = 1; | 333 | cb->args[4] = 1; |
| 334 | cb->args[5] = w->root->fn_sernum; | ||
| 335 | } | ||
| 327 | } else { | 336 | } else { |
| 337 | if (cb->args[5] != w->root->fn_sernum) { | ||
| 338 | /* Begin at the root if the tree changed */ | ||
| 339 | cb->args[5] = w->root->fn_sernum; | ||
| 340 | w->state = FWS_INIT; | ||
| 341 | w->node = w->root; | ||
| 342 | w->skip = w->count; | ||
| 343 | } else | ||
| 344 | w->skip = 0; | ||
| 345 | |||
| 328 | read_lock_bh(&table->tb6_lock); | 346 | read_lock_bh(&table->tb6_lock); |
| 329 | res = fib6_walk_continue(w); | 347 | res = fib6_walk_continue(w); |
| 330 | read_unlock_bh(&table->tb6_lock); | 348 | read_unlock_bh(&table->tb6_lock); |
| @@ -601,7 +619,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 601 | 619 | ||
| 602 | ins = &fn->leaf; | 620 | ins = &fn->leaf; |
| 603 | 621 | ||
| 604 | for (iter = fn->leaf; iter; iter=iter->u.dst.rt6_next) { | 622 | for (iter = fn->leaf; iter; iter=iter->dst.rt6_next) { |
| 605 | /* | 623 | /* |
| 606 | * Search for duplicates | 624 | * Search for duplicates |
| 607 | */ | 625 | */ |
| @@ -629,7 +647,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 629 | if (iter->rt6i_metric > rt->rt6i_metric) | 647 | if (iter->rt6i_metric > rt->rt6i_metric) |
| 630 | break; | 648 | break; |
| 631 | 649 | ||
| 632 | ins = &iter->u.dst.rt6_next; | 650 | ins = &iter->dst.rt6_next; |
| 633 | } | 651 | } |
| 634 | 652 | ||
| 635 | /* Reset round-robin state, if necessary */ | 653 | /* Reset round-robin state, if necessary */ |
| @@ -640,7 +658,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 640 | * insert node | 658 | * insert node |
| 641 | */ | 659 | */ |
| 642 | 660 | ||
| 643 | rt->u.dst.rt6_next = iter; | 661 | rt->dst.rt6_next = iter; |
| 644 | *ins = rt; | 662 | *ins = rt; |
| 645 | rt->rt6i_node = fn; | 663 | rt->rt6i_node = fn; |
| 646 | atomic_inc(&rt->rt6i_ref); | 664 | atomic_inc(&rt->rt6i_ref); |
| @@ -781,7 +799,7 @@ out: | |||
| 781 | atomic_inc(&pn->leaf->rt6i_ref); | 799 | atomic_inc(&pn->leaf->rt6i_ref); |
| 782 | } | 800 | } |
| 783 | #endif | 801 | #endif |
| 784 | dst_free(&rt->u.dst); | 802 | dst_free(&rt->dst); |
| 785 | } | 803 | } |
| 786 | return err; | 804 | return err; |
| 787 | 805 | ||
| @@ -792,7 +810,7 @@ out: | |||
| 792 | st_failure: | 810 | st_failure: |
| 793 | if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) | 811 | if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) |
| 794 | fib6_repair_tree(info->nl_net, fn); | 812 | fib6_repair_tree(info->nl_net, fn); |
| 795 | dst_free(&rt->u.dst); | 813 | dst_free(&rt->dst); |
| 796 | return err; | 814 | return err; |
| 797 | #endif | 815 | #endif |
| 798 | } | 816 | } |
| @@ -1090,7 +1108,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 1090 | RT6_TRACE("fib6_del_route\n"); | 1108 | RT6_TRACE("fib6_del_route\n"); |
| 1091 | 1109 | ||
| 1092 | /* Unlink it */ | 1110 | /* Unlink it */ |
| 1093 | *rtp = rt->u.dst.rt6_next; | 1111 | *rtp = rt->dst.rt6_next; |
| 1094 | rt->rt6i_node = NULL; | 1112 | rt->rt6i_node = NULL; |
| 1095 | net->ipv6.rt6_stats->fib_rt_entries--; | 1113 | net->ipv6.rt6_stats->fib_rt_entries--; |
| 1096 | net->ipv6.rt6_stats->fib_discarded_routes++; | 1114 | net->ipv6.rt6_stats->fib_discarded_routes++; |
| @@ -1104,14 +1122,14 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 1104 | FOR_WALKERS(w) { | 1122 | FOR_WALKERS(w) { |
| 1105 | if (w->state == FWS_C && w->leaf == rt) { | 1123 | if (w->state == FWS_C && w->leaf == rt) { |
| 1106 | RT6_TRACE("walker %p adjusted by delroute\n", w); | 1124 | RT6_TRACE("walker %p adjusted by delroute\n", w); |
| 1107 | w->leaf = rt->u.dst.rt6_next; | 1125 | w->leaf = rt->dst.rt6_next; |
| 1108 | if (w->leaf == NULL) | 1126 | if (w->leaf == NULL) |
| 1109 | w->state = FWS_U; | 1127 | w->state = FWS_U; |
| 1110 | } | 1128 | } |
| 1111 | } | 1129 | } |
| 1112 | read_unlock(&fib6_walker_lock); | 1130 | read_unlock(&fib6_walker_lock); |
| 1113 | 1131 | ||
| 1114 | rt->u.dst.rt6_next = NULL; | 1132 | rt->dst.rt6_next = NULL; |
| 1115 | 1133 | ||
| 1116 | /* If it was last route, expunge its radix tree node */ | 1134 | /* If it was last route, expunge its radix tree node */ |
| 1117 | if (fn->leaf == NULL) { | 1135 | if (fn->leaf == NULL) { |
| @@ -1150,7 +1168,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) | |||
| 1150 | struct rt6_info **rtp; | 1168 | struct rt6_info **rtp; |
| 1151 | 1169 | ||
| 1152 | #if RT6_DEBUG >= 2 | 1170 | #if RT6_DEBUG >= 2 |
| 1153 | if (rt->u.dst.obsolete>0) { | 1171 | if (rt->dst.obsolete>0) { |
| 1154 | WARN_ON(fn != NULL); | 1172 | WARN_ON(fn != NULL); |
| 1155 | return -ENOENT; | 1173 | return -ENOENT; |
| 1156 | } | 1174 | } |
| @@ -1177,7 +1195,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) | |||
| 1177 | * Walk the leaf entries looking for ourself | 1195 | * Walk the leaf entries looking for ourself |
| 1178 | */ | 1196 | */ |
| 1179 | 1197 | ||
| 1180 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.dst.rt6_next) { | 1198 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->dst.rt6_next) { |
| 1181 | if (*rtp == rt) { | 1199 | if (*rtp == rt) { |
| 1182 | fib6_del_route(fn, rtp, info); | 1200 | fib6_del_route(fn, rtp, info); |
| 1183 | return 0; | 1201 | return 0; |
| @@ -1250,9 +1268,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
| 1250 | w->leaf = fn->leaf; | 1268 | w->leaf = fn->leaf; |
| 1251 | case FWS_C: | 1269 | case FWS_C: |
| 1252 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { | 1270 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { |
| 1253 | int err = w->func(w); | 1271 | int err; |
| 1272 | |||
| 1273 | if (w->count < w->skip) { | ||
| 1274 | w->count++; | ||
| 1275 | continue; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | err = w->func(w); | ||
| 1254 | if (err) | 1279 | if (err) |
| 1255 | return err; | 1280 | return err; |
| 1281 | |||
| 1282 | w->count++; | ||
| 1256 | continue; | 1283 | continue; |
| 1257 | } | 1284 | } |
| 1258 | w->state = FWS_U; | 1285 | w->state = FWS_U; |
| @@ -1307,7 +1334,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
| 1307 | .nl_net = c->net, | 1334 | .nl_net = c->net, |
| 1308 | }; | 1335 | }; |
| 1309 | 1336 | ||
| 1310 | for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { | 1337 | for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { |
| 1311 | res = c->func(rt, c->arg); | 1338 | res = c->func(rt, c->arg); |
| 1312 | if (res < 0) { | 1339 | if (res < 0) { |
| 1313 | w->leaf = rt; | 1340 | w->leaf = rt; |
| @@ -1346,6 +1373,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
| 1346 | c.w.root = root; | 1373 | c.w.root = root; |
| 1347 | c.w.func = fib6_clean_node; | 1374 | c.w.func = fib6_clean_node; |
| 1348 | c.w.prune = prune; | 1375 | c.w.prune = prune; |
| 1376 | c.w.count = 0; | ||
| 1377 | c.w.skip = 0; | ||
| 1349 | c.func = func; | 1378 | c.func = func; |
| 1350 | c.arg = arg; | 1379 | c.arg = arg; |
| 1351 | c.net = net; | 1380 | c.net = net; |
| @@ -1419,8 +1448,8 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
| 1419 | } | 1448 | } |
| 1420 | gc_args.more++; | 1449 | gc_args.more++; |
| 1421 | } else if (rt->rt6i_flags & RTF_CACHE) { | 1450 | } else if (rt->rt6i_flags & RTF_CACHE) { |
| 1422 | if (atomic_read(&rt->u.dst.__refcnt) == 0 && | 1451 | if (atomic_read(&rt->dst.__refcnt) == 0 && |
| 1423 | time_after_eq(now, rt->u.dst.lastuse + gc_args.timeout)) { | 1452 | time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) { |
| 1424 | RT6_TRACE("aging clone %p\n", rt); | 1453 | RT6_TRACE("aging clone %p\n", rt); |
| 1425 | return -1; | 1454 | return -1; |
| 1426 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && | 1455 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && |
| @@ -1469,7 +1498,7 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
| 1469 | fib6_run_gc(0, (struct net *)arg); | 1498 | fib6_run_gc(0, (struct net *)arg); |
| 1470 | } | 1499 | } |
| 1471 | 1500 | ||
| 1472 | static int fib6_net_init(struct net *net) | 1501 | static int __net_init fib6_net_init(struct net *net) |
| 1473 | { | 1502 | { |
| 1474 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1503 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
| 1475 | 1504 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 6e7bffa2205e..13654686aeab 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/route.h> | 20 | #include <linux/route.h> |
| 21 | #include <linux/proc_fs.h> | 21 | #include <linux/proc_fs.h> |
| 22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
| 23 | #include <linux/slab.h> | ||
| 23 | 24 | ||
| 24 | #include <net/net_namespace.h> | 25 | #include <net/net_namespace.h> |
| 25 | #include <net/sock.h> | 26 | #include <net/sock.h> |
| @@ -154,7 +155,7 @@ static void ip6_fl_gc(unsigned long dummy) | |||
| 154 | write_unlock(&ip6_fl_lock); | 155 | write_unlock(&ip6_fl_lock); |
| 155 | } | 156 | } |
| 156 | 157 | ||
| 157 | static void ip6_fl_purge(struct net *net) | 158 | static void __net_exit ip6_fl_purge(struct net *net) |
| 158 | { | 159 | { |
| 159 | int i; | 160 | int i; |
| 160 | 161 | ||
| @@ -359,7 +360,8 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, | |||
| 359 | msg.msg_control = (void*)(fl->opt+1); | 360 | msg.msg_control = (void*)(fl->opt+1); |
| 360 | flowi.oif = 0; | 361 | flowi.oif = 0; |
| 361 | 362 | ||
| 362 | err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, &junk); | 363 | err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, |
| 364 | &junk, &junk); | ||
| 363 | if (err) | 365 | if (err) |
| 364 | goto done; | 366 | goto done; |
| 365 | err = -EINVAL; | 367 | err = -EINVAL; |
| @@ -735,7 +737,7 @@ static const struct file_operations ip6fl_seq_fops = { | |||
| 735 | .release = seq_release_net, | 737 | .release = seq_release_net, |
| 736 | }; | 738 | }; |
| 737 | 739 | ||
| 738 | static int ip6_flowlabel_proc_init(struct net *net) | 740 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |
| 739 | { | 741 | { |
| 740 | if (!proc_net_fops_create(net, "ip6_flowlabel", | 742 | if (!proc_net_fops_create(net, "ip6_flowlabel", |
| 741 | S_IRUGO, &ip6fl_seq_fops)) | 743 | S_IRUGO, &ip6fl_seq_fops)) |
| @@ -743,7 +745,7 @@ static int ip6_flowlabel_proc_init(struct net *net) | |||
| 743 | return 0; | 745 | return 0; |
| 744 | } | 746 | } |
| 745 | 747 | ||
| 746 | static void ip6_flowlabel_proc_fini(struct net *net) | 748 | static void __net_exit ip6_flowlabel_proc_fini(struct net *net) |
| 747 | { | 749 | { |
| 748 | proc_net_remove(net, "ip6_flowlabel"); | 750 | proc_net_remove(net, "ip6_flowlabel"); |
| 749 | } | 751 | } |
| @@ -754,11 +756,10 @@ static inline int ip6_flowlabel_proc_init(struct net *net) | |||
| 754 | } | 756 | } |
| 755 | static inline void ip6_flowlabel_proc_fini(struct net *net) | 757 | static inline void ip6_flowlabel_proc_fini(struct net *net) |
| 756 | { | 758 | { |
| 757 | return ; | ||
| 758 | } | 759 | } |
| 759 | #endif | 760 | #endif |
| 760 | 761 | ||
| 761 | static inline void ip6_flowlabel_net_exit(struct net *net) | 762 | static void __net_exit ip6_flowlabel_net_exit(struct net *net) |
| 762 | { | 763 | { |
| 763 | ip6_fl_purge(net); | 764 | ip6_fl_purge(net); |
| 764 | ip6_flowlabel_proc_fini(net); | 765 | ip6_flowlabel_proc_fini(net); |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 237e2dba6e94..a83e9209cecc 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
| 29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
| 30 | #include <linux/mroute6.h> | 30 | #include <linux/mroute6.h> |
| 31 | #include <linux/slab.h> | ||
| 31 | 32 | ||
| 32 | #include <linux/netfilter.h> | 33 | #include <linux/netfilter.h> |
| 33 | #include <linux/netfilter_ipv6.h> | 34 | #include <linux/netfilter_ipv6.h> |
| @@ -142,7 +143,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 142 | /* Must drop socket now because of tproxy. */ | 143 | /* Must drop socket now because of tproxy. */ |
| 143 | skb_orphan(skb); | 144 | skb_orphan(skb); |
| 144 | 145 | ||
| 145 | return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL, | 146 | return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL, |
| 146 | ip6_rcv_finish); | 147 | ip6_rcv_finish); |
| 147 | err: | 148 | err: |
| 148 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); | 149 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); |
| @@ -216,8 +217,7 @@ resubmit: | |||
| 216 | IP6_INC_STATS_BH(net, idev, | 217 | IP6_INC_STATS_BH(net, idev, |
| 217 | IPSTATS_MIB_INUNKNOWNPROTOS); | 218 | IPSTATS_MIB_INUNKNOWNPROTOS); |
| 218 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 219 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
| 219 | ICMPV6_UNK_NEXTHDR, nhoff, | 220 | ICMPV6_UNK_NEXTHDR, nhoff); |
| 220 | skb->dev); | ||
| 221 | } | 221 | } |
| 222 | } else | 222 | } else |
| 223 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); | 223 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
| @@ -236,7 +236,7 @@ discard: | |||
| 236 | 236 | ||
| 237 | int ip6_input(struct sk_buff *skb) | 237 | int ip6_input(struct sk_buff *skb) |
| 238 | { | 238 | { |
| 239 | return NF_HOOK(PF_INET6, NF_INET_LOCAL_IN, skb, skb->dev, NULL, | 239 | return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL, |
| 240 | ip6_input_finish); | 240 | ip6_input_finish); |
| 241 | } | 241 | } |
| 242 | 242 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index eb6d09728633..980912ed7a38 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/tcp.h> | 37 | #include <linux/tcp.h> |
| 38 | #include <linux/route.h> | 38 | #include <linux/route.h> |
| 39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
| 40 | #include <linux/slab.h> | ||
| 40 | 41 | ||
| 41 | #include <linux/netfilter.h> | 42 | #include <linux/netfilter.h> |
| 42 | #include <linux/netfilter_ipv6.h> | 43 | #include <linux/netfilter_ipv6.h> |
| @@ -66,8 +67,8 @@ int __ip6_local_out(struct sk_buff *skb) | |||
| 66 | len = 0; | 67 | len = 0; |
| 67 | ipv6_hdr(skb)->payload_len = htons(len); | 68 | ipv6_hdr(skb)->payload_len = htons(len); |
| 68 | 69 | ||
| 69 | return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, | 70 | return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, |
| 70 | dst_output); | 71 | skb_dst(skb)->dev, dst_output); |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | int ip6_local_out(struct sk_buff *skb) | 74 | int ip6_local_out(struct sk_buff *skb) |
| @@ -82,22 +83,6 @@ int ip6_local_out(struct sk_buff *skb) | |||
| 82 | } | 83 | } |
| 83 | EXPORT_SYMBOL_GPL(ip6_local_out); | 84 | EXPORT_SYMBOL_GPL(ip6_local_out); |
| 84 | 85 | ||
| 85 | static int ip6_output_finish(struct sk_buff *skb) | ||
| 86 | { | ||
| 87 | struct dst_entry *dst = skb_dst(skb); | ||
| 88 | |||
| 89 | if (dst->hh) | ||
| 90 | return neigh_hh_output(dst->hh, skb); | ||
| 91 | else if (dst->neighbour) | ||
| 92 | return dst->neighbour->output(skb); | ||
| 93 | |||
| 94 | IP6_INC_STATS_BH(dev_net(dst->dev), | ||
| 95 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | ||
| 96 | kfree_skb(skb); | ||
| 97 | return -EINVAL; | ||
| 98 | |||
| 99 | } | ||
| 100 | |||
| 101 | /* dev_loopback_xmit for use with netfilter. */ | 86 | /* dev_loopback_xmit for use with netfilter. */ |
| 102 | static int ip6_dev_loopback_xmit(struct sk_buff *newskb) | 87 | static int ip6_dev_loopback_xmit(struct sk_buff *newskb) |
| 103 | { | 88 | { |
| @@ -107,12 +92,11 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) | |||
| 107 | newskb->ip_summed = CHECKSUM_UNNECESSARY; | 92 | newskb->ip_summed = CHECKSUM_UNNECESSARY; |
| 108 | WARN_ON(!skb_dst(newskb)); | 93 | WARN_ON(!skb_dst(newskb)); |
| 109 | 94 | ||
| 110 | netif_rx(newskb); | 95 | netif_rx_ni(newskb); |
| 111 | return 0; | 96 | return 0; |
| 112 | } | 97 | } |
| 113 | 98 | ||
| 114 | 99 | static int ip6_finish_output2(struct sk_buff *skb) | |
| 115 | static int ip6_output2(struct sk_buff *skb) | ||
| 116 | { | 100 | { |
| 117 | struct dst_entry *dst = skb_dst(skb); | 101 | struct dst_entry *dst = skb_dst(skb); |
| 118 | struct net_device *dev = dst->dev; | 102 | struct net_device *dev = dst->dev; |
| @@ -124,7 +108,7 @@ static int ip6_output2(struct sk_buff *skb) | |||
| 124 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); | 108 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
| 125 | 109 | ||
| 126 | if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && | 110 | if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && |
| 127 | ((mroute6_socket(dev_net(dev)) && | 111 | ((mroute6_socket(dev_net(dev), skb) && |
| 128 | !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || | 112 | !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || |
| 129 | ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, | 113 | ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, |
| 130 | &ipv6_hdr(skb)->saddr))) { | 114 | &ipv6_hdr(skb)->saddr))) { |
| @@ -134,8 +118,8 @@ static int ip6_output2(struct sk_buff *skb) | |||
| 134 | is not supported in any case. | 118 | is not supported in any case. |
| 135 | */ | 119 | */ |
| 136 | if (newskb) | 120 | if (newskb) |
| 137 | NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, newskb, | 121 | NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, |
| 138 | NULL, newskb->dev, | 122 | newskb, NULL, newskb->dev, |
| 139 | ip6_dev_loopback_xmit); | 123 | ip6_dev_loopback_xmit); |
| 140 | 124 | ||
| 141 | if (ipv6_hdr(skb)->hop_limit == 0) { | 125 | if (ipv6_hdr(skb)->hop_limit == 0) { |
| @@ -150,8 +134,15 @@ static int ip6_output2(struct sk_buff *skb) | |||
| 150 | skb->len); | 134 | skb->len); |
| 151 | } | 135 | } |
| 152 | 136 | ||
| 153 | return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, | 137 | if (dst->hh) |
| 154 | ip6_output_finish); | 138 | return neigh_hh_output(dst->hh, skb); |
| 139 | else if (dst->neighbour) | ||
| 140 | return dst->neighbour->output(skb); | ||
| 141 | |||
| 142 | IP6_INC_STATS_BH(dev_net(dst->dev), | ||
| 143 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | ||
| 144 | kfree_skb(skb); | ||
| 145 | return -EINVAL; | ||
| 155 | } | 146 | } |
| 156 | 147 | ||
| 157 | static inline int ip6_skb_dst_mtu(struct sk_buff *skb) | 148 | static inline int ip6_skb_dst_mtu(struct sk_buff *skb) |
| @@ -162,29 +153,37 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) | |||
| 162 | skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); | 153 | skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); |
| 163 | } | 154 | } |
| 164 | 155 | ||
| 156 | static int ip6_finish_output(struct sk_buff *skb) | ||
| 157 | { | ||
| 158 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | ||
| 159 | dst_allfrag(skb_dst(skb))) | ||
| 160 | return ip6_fragment(skb, ip6_finish_output2); | ||
| 161 | else | ||
| 162 | return ip6_finish_output2(skb); | ||
| 163 | } | ||
| 164 | |||
| 165 | int ip6_output(struct sk_buff *skb) | 165 | int ip6_output(struct sk_buff *skb) |
| 166 | { | 166 | { |
| 167 | struct net_device *dev = skb_dst(skb)->dev; | ||
| 167 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); | 168 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
| 168 | if (unlikely(idev->cnf.disable_ipv6)) { | 169 | if (unlikely(idev->cnf.disable_ipv6)) { |
| 169 | IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev, | 170 | IP6_INC_STATS(dev_net(dev), idev, |
| 170 | IPSTATS_MIB_OUTDISCARDS); | 171 | IPSTATS_MIB_OUTDISCARDS); |
| 171 | kfree_skb(skb); | 172 | kfree_skb(skb); |
| 172 | return 0; | 173 | return 0; |
| 173 | } | 174 | } |
| 174 | 175 | ||
| 175 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | 176 | return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev, |
| 176 | dst_allfrag(skb_dst(skb))) | 177 | ip6_finish_output, |
| 177 | return ip6_fragment(skb, ip6_output2); | 178 | !(IP6CB(skb)->flags & IP6SKB_REROUTED)); |
| 178 | else | ||
| 179 | return ip6_output2(skb); | ||
| 180 | } | 179 | } |
| 181 | 180 | ||
| 182 | /* | 181 | /* |
| 183 | * xmit an sk_buff (used by TCP) | 182 | * xmit an sk_buff (used by TCP, SCTP and DCCP) |
| 184 | */ | 183 | */ |
| 185 | 184 | ||
| 186 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | 185 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, |
| 187 | struct ipv6_txoptions *opt, int ipfragok) | 186 | struct ipv6_txoptions *opt) |
| 188 | { | 187 | { |
| 189 | struct net *net = sock_net(sk); | 188 | struct net *net = sock_net(sk); |
| 190 | struct ipv6_pinfo *np = inet6_sk(sk); | 189 | struct ipv6_pinfo *np = inet6_sk(sk); |
| @@ -217,8 +216,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
| 217 | } | 216 | } |
| 218 | kfree_skb(skb); | 217 | kfree_skb(skb); |
| 219 | skb = skb2; | 218 | skb = skb2; |
| 220 | if (sk) | 219 | skb_set_owner_w(skb, sk); |
| 221 | skb_set_owner_w(skb, sk); | ||
| 222 | } | 220 | } |
| 223 | if (opt->opt_flen) | 221 | if (opt->opt_flen) |
| 224 | ipv6_push_frag_opts(skb, opt, &proto); | 222 | ipv6_push_frag_opts(skb, opt, &proto); |
| @@ -230,10 +228,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
| 230 | skb_reset_network_header(skb); | 228 | skb_reset_network_header(skb); |
| 231 | hdr = ipv6_hdr(skb); | 229 | hdr = ipv6_hdr(skb); |
| 232 | 230 | ||
| 233 | /* Allow local fragmentation. */ | ||
| 234 | if (ipfragok) | ||
| 235 | skb->local_df = 1; | ||
| 236 | |||
| 237 | /* | 231 | /* |
| 238 | * Fill in the IPv6 header | 232 | * Fill in the IPv6 header |
| 239 | */ | 233 | */ |
| @@ -260,14 +254,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
| 260 | if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { | 254 | if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) { |
| 261 | IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), | 255 | IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), |
| 262 | IPSTATS_MIB_OUT, skb->len); | 256 | IPSTATS_MIB_OUT, skb->len); |
| 263 | return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, | 257 | return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, |
| 264 | dst_output); | 258 | dst->dev, dst_output); |
| 265 | } | 259 | } |
| 266 | 260 | ||
| 267 | if (net_ratelimit()) | 261 | if (net_ratelimit()) |
| 268 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); | 262 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); |
| 269 | skb->dev = dst->dev; | 263 | skb->dev = dst->dev; |
| 270 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 264 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 271 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); | 265 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
| 272 | kfree_skb(skb); | 266 | kfree_skb(skb); |
| 273 | return -EMSGSIZE; | 267 | return -EMSGSIZE; |
| @@ -402,6 +396,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 402 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 396 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
| 403 | struct inet6_skb_parm *opt = IP6CB(skb); | 397 | struct inet6_skb_parm *opt = IP6CB(skb); |
| 404 | struct net *net = dev_net(dst->dev); | 398 | struct net *net = dev_net(dst->dev); |
| 399 | u32 mtu; | ||
| 405 | 400 | ||
| 406 | if (net->ipv6.devconf_all->forwarding == 0) | 401 | if (net->ipv6.devconf_all->forwarding == 0) |
| 407 | goto error; | 402 | goto error; |
| @@ -441,8 +436,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 441 | if (hdr->hop_limit <= 1) { | 436 | if (hdr->hop_limit <= 1) { |
| 442 | /* Force OUTPUT device used as source address */ | 437 | /* Force OUTPUT device used as source address */ |
| 443 | skb->dev = dst->dev; | 438 | skb->dev = dst->dev; |
| 444 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 439 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
| 445 | 0, skb->dev); | ||
| 446 | IP6_INC_STATS_BH(net, | 440 | IP6_INC_STATS_BH(net, |
| 447 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); | 441 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
| 448 | 442 | ||
| @@ -504,15 +498,19 @@ int ip6_forward(struct sk_buff *skb) | |||
| 504 | goto error; | 498 | goto error; |
| 505 | if (addrtype & IPV6_ADDR_LINKLOCAL) { | 499 | if (addrtype & IPV6_ADDR_LINKLOCAL) { |
| 506 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, | 500 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, |
| 507 | ICMPV6_NOT_NEIGHBOUR, 0, skb->dev); | 501 | ICMPV6_NOT_NEIGHBOUR, 0); |
| 508 | goto error; | 502 | goto error; |
| 509 | } | 503 | } |
| 510 | } | 504 | } |
| 511 | 505 | ||
| 512 | if (skb->len > dst_mtu(dst)) { | 506 | mtu = dst_mtu(dst); |
| 507 | if (mtu < IPV6_MIN_MTU) | ||
| 508 | mtu = IPV6_MIN_MTU; | ||
| 509 | |||
| 510 | if (skb->len > mtu && !skb_is_gso(skb)) { | ||
| 513 | /* Again, force OUTPUT device used as source address */ | 511 | /* Again, force OUTPUT device used as source address */ |
| 514 | skb->dev = dst->dev; | 512 | skb->dev = dst->dev; |
| 515 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); | 513 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 516 | IP6_INC_STATS_BH(net, | 514 | IP6_INC_STATS_BH(net, |
| 517 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); | 515 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); |
| 518 | IP6_INC_STATS_BH(net, | 516 | IP6_INC_STATS_BH(net, |
| @@ -533,7 +531,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 533 | hdr->hop_limit--; | 531 | hdr->hop_limit--; |
| 534 | 532 | ||
| 535 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); | 533 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); |
| 536 | return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dst->dev, | 534 | return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev, |
| 537 | ip6_forward_finish); | 535 | ip6_forward_finish); |
| 538 | 536 | ||
| 539 | error: | 537 | error: |
| @@ -622,12 +620,11 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 622 | mtu = ip6_skb_dst_mtu(skb); | 620 | mtu = ip6_skb_dst_mtu(skb); |
| 623 | 621 | ||
| 624 | /* We must not fragment if the socket is set to force MTU discovery | 622 | /* We must not fragment if the socket is set to force MTU discovery |
| 625 | * or if the skb it not generated by a local socket. (This last | 623 | * or if the skb it not generated by a local socket. |
| 626 | * check should be redundant, but it's free.) | ||
| 627 | */ | 624 | */ |
| 628 | if (!skb->local_df) { | 625 | if (!skb->local_df && skb->len > mtu) { |
| 629 | skb->dev = skb_dst(skb)->dev; | 626 | skb->dev = skb_dst(skb)->dev; |
| 630 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 627 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 631 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 628 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
| 632 | IPSTATS_MIB_FRAGFAILS); | 629 | IPSTATS_MIB_FRAGFAILS); |
| 633 | kfree_skb(skb); | 630 | kfree_skb(skb); |
| @@ -642,7 +639,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 642 | 639 | ||
| 643 | if (skb_has_frags(skb)) { | 640 | if (skb_has_frags(skb)) { |
| 644 | int first_len = skb_pagelen(skb); | 641 | int first_len = skb_pagelen(skb); |
| 645 | int truesizes = 0; | 642 | struct sk_buff *frag2; |
| 646 | 643 | ||
| 647 | if (first_len - hlen > mtu || | 644 | if (first_len - hlen > mtu || |
| 648 | ((first_len - hlen) & 7) || | 645 | ((first_len - hlen) & 7) || |
| @@ -654,18 +651,18 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 654 | if (frag->len > mtu || | 651 | if (frag->len > mtu || |
| 655 | ((frag->len & 7) && frag->next) || | 652 | ((frag->len & 7) && frag->next) || |
| 656 | skb_headroom(frag) < hlen) | 653 | skb_headroom(frag) < hlen) |
| 657 | goto slow_path; | 654 | goto slow_path_clean; |
| 658 | 655 | ||
| 659 | /* Partially cloned skb? */ | 656 | /* Partially cloned skb? */ |
| 660 | if (skb_shared(frag)) | 657 | if (skb_shared(frag)) |
| 661 | goto slow_path; | 658 | goto slow_path_clean; |
| 662 | 659 | ||
| 663 | BUG_ON(frag->sk); | 660 | BUG_ON(frag->sk); |
| 664 | if (skb->sk) { | 661 | if (skb->sk) { |
| 665 | frag->sk = skb->sk; | 662 | frag->sk = skb->sk; |
| 666 | frag->destructor = sock_wfree; | 663 | frag->destructor = sock_wfree; |
| 667 | truesizes += frag->truesize; | ||
| 668 | } | 664 | } |
| 665 | skb->truesize -= frag->truesize; | ||
| 669 | } | 666 | } |
| 670 | 667 | ||
| 671 | err = 0; | 668 | err = 0; |
| @@ -696,12 +693,11 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 696 | 693 | ||
| 697 | first_len = skb_pagelen(skb); | 694 | first_len = skb_pagelen(skb); |
| 698 | skb->data_len = first_len - skb_headlen(skb); | 695 | skb->data_len = first_len - skb_headlen(skb); |
| 699 | skb->truesize -= truesizes; | ||
| 700 | skb->len = first_len; | 696 | skb->len = first_len; |
| 701 | ipv6_hdr(skb)->payload_len = htons(first_len - | 697 | ipv6_hdr(skb)->payload_len = htons(first_len - |
| 702 | sizeof(struct ipv6hdr)); | 698 | sizeof(struct ipv6hdr)); |
| 703 | 699 | ||
| 704 | dst_hold(&rt->u.dst); | 700 | dst_hold(&rt->dst); |
| 705 | 701 | ||
| 706 | for (;;) { | 702 | for (;;) { |
| 707 | /* Prepare header of the next frame, | 703 | /* Prepare header of the next frame, |
| @@ -729,7 +725,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 729 | 725 | ||
| 730 | err = output(skb); | 726 | err = output(skb); |
| 731 | if(!err) | 727 | if(!err) |
| 732 | IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst), | 728 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
| 733 | IPSTATS_MIB_FRAGCREATES); | 729 | IPSTATS_MIB_FRAGCREATES); |
| 734 | 730 | ||
| 735 | if (err || !frag) | 731 | if (err || !frag) |
| @@ -743,9 +739,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 743 | kfree(tmp_hdr); | 739 | kfree(tmp_hdr); |
| 744 | 740 | ||
| 745 | if (err == 0) { | 741 | if (err == 0) { |
| 746 | IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst), | 742 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
| 747 | IPSTATS_MIB_FRAGOKS); | 743 | IPSTATS_MIB_FRAGOKS); |
| 748 | dst_release(&rt->u.dst); | 744 | dst_release(&rt->dst); |
| 749 | return 0; | 745 | return 0; |
| 750 | } | 746 | } |
| 751 | 747 | ||
| @@ -755,10 +751,19 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 755 | frag = skb; | 751 | frag = skb; |
| 756 | } | 752 | } |
| 757 | 753 | ||
| 758 | IP6_INC_STATS(net, ip6_dst_idev(&rt->u.dst), | 754 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
| 759 | IPSTATS_MIB_FRAGFAILS); | 755 | IPSTATS_MIB_FRAGFAILS); |
| 760 | dst_release(&rt->u.dst); | 756 | dst_release(&rt->dst); |
| 761 | return err; | 757 | return err; |
| 758 | |||
| 759 | slow_path_clean: | ||
| 760 | skb_walk_frags(skb, frag2) { | ||
| 761 | if (frag2 == frag) | ||
| 762 | break; | ||
| 763 | frag2->sk = NULL; | ||
| 764 | frag2->destructor = NULL; | ||
| 765 | skb->truesize += frag2->truesize; | ||
| 766 | } | ||
| 762 | } | 767 | } |
| 763 | 768 | ||
| 764 | slow_path: | 769 | slow_path: |
| @@ -788,7 +793,7 @@ slow_path: | |||
| 788 | * Allocate buffer. | 793 | * Allocate buffer. |
| 789 | */ | 794 | */ |
| 790 | 795 | ||
| 791 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { | 796 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) { |
| 792 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); | 797 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); |
| 793 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 798 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
| 794 | IPSTATS_MIB_FRAGFAILS); | 799 | IPSTATS_MIB_FRAGFAILS); |
| @@ -801,7 +806,7 @@ slow_path: | |||
| 801 | */ | 806 | */ |
| 802 | 807 | ||
| 803 | ip6_copy_metadata(frag, skb); | 808 | ip6_copy_metadata(frag, skb); |
| 804 | skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev)); | 809 | skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev)); |
| 805 | skb_put(frag, len + hlen + sizeof(struct frag_hdr)); | 810 | skb_put(frag, len + hlen + sizeof(struct frag_hdr)); |
| 806 | skb_reset_network_header(frag); | 811 | skb_reset_network_header(frag); |
| 807 | fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); | 812 | fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); |
| @@ -1105,7 +1110,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1105 | int offset, int len, int odd, struct sk_buff *skb), | 1110 | int offset, int len, int odd, struct sk_buff *skb), |
| 1106 | void *from, int length, int transhdrlen, | 1111 | void *from, int length, int transhdrlen, |
| 1107 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, | 1112 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, |
| 1108 | struct rt6_info *rt, unsigned int flags) | 1113 | struct rt6_info *rt, unsigned int flags, int dontfrag) |
| 1109 | { | 1114 | { |
| 1110 | struct inet_sock *inet = inet_sk(sk); | 1115 | struct inet_sock *inet = inet_sk(sk); |
| 1111 | struct ipv6_pinfo *np = inet6_sk(sk); | 1116 | struct ipv6_pinfo *np = inet6_sk(sk); |
| @@ -1159,24 +1164,24 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1159 | 1164 | ||
| 1160 | /* need source address above miyazawa*/ | 1165 | /* need source address above miyazawa*/ |
| 1161 | } | 1166 | } |
| 1162 | dst_hold(&rt->u.dst); | 1167 | dst_hold(&rt->dst); |
| 1163 | inet->cork.dst = &rt->u.dst; | 1168 | inet->cork.dst = &rt->dst; |
| 1164 | inet->cork.fl = *fl; | 1169 | inet->cork.fl = *fl; |
| 1165 | np->cork.hop_limit = hlimit; | 1170 | np->cork.hop_limit = hlimit; |
| 1166 | np->cork.tclass = tclass; | 1171 | np->cork.tclass = tclass; |
| 1167 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1172 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? |
| 1168 | rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path); | 1173 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); |
| 1169 | if (np->frag_size < mtu) { | 1174 | if (np->frag_size < mtu) { |
| 1170 | if (np->frag_size) | 1175 | if (np->frag_size) |
| 1171 | mtu = np->frag_size; | 1176 | mtu = np->frag_size; |
| 1172 | } | 1177 | } |
| 1173 | inet->cork.fragsize = mtu; | 1178 | inet->cork.fragsize = mtu; |
| 1174 | if (dst_allfrag(rt->u.dst.path)) | 1179 | if (dst_allfrag(rt->dst.path)) |
| 1175 | inet->cork.flags |= IPCORK_ALLFRAG; | 1180 | inet->cork.flags |= IPCORK_ALLFRAG; |
| 1176 | inet->cork.length = 0; | 1181 | inet->cork.length = 0; |
| 1177 | sk->sk_sndmsg_page = NULL; | 1182 | sk->sk_sndmsg_page = NULL; |
| 1178 | sk->sk_sndmsg_off = 0; | 1183 | sk->sk_sndmsg_off = 0; |
| 1179 | exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) - | 1184 | exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - |
| 1180 | rt->rt6i_nfheader_len; | 1185 | rt->rt6i_nfheader_len; |
| 1181 | length += exthdrlen; | 1186 | length += exthdrlen; |
| 1182 | transhdrlen += exthdrlen; | 1187 | transhdrlen += exthdrlen; |
| @@ -1189,7 +1194,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1189 | mtu = inet->cork.fragsize; | 1194 | mtu = inet->cork.fragsize; |
| 1190 | } | 1195 | } |
| 1191 | 1196 | ||
| 1192 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | 1197 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
| 1193 | 1198 | ||
| 1194 | fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + | 1199 | fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + |
| 1195 | (opt ? opt->opt_nflen : 0); | 1200 | (opt ? opt->opt_nflen : 0); |
| @@ -1219,15 +1224,23 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
| 1219 | */ | 1224 | */ |
| 1220 | 1225 | ||
| 1221 | inet->cork.length += length; | 1226 | inet->cork.length += length; |
| 1222 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && | 1227 | if (length > mtu) { |
| 1223 | (rt->u.dst.dev->features & NETIF_F_UFO)) { | 1228 | int proto = sk->sk_protocol; |
| 1229 | if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ | ||
| 1230 | ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen); | ||
| 1231 | return -EMSGSIZE; | ||
| 1232 | } | ||
| 1224 | 1233 | ||
| 1225 | err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len, | 1234 | if (proto == IPPROTO_UDP && |
| 1226 | fragheaderlen, transhdrlen, mtu, | 1235 | (rt->dst.dev->features & NETIF_F_UFO)) { |
| 1227 | flags); | 1236 | |
| 1228 | if (err) | 1237 | err = ip6_ufo_append_data(sk, getfrag, from, length, |
| 1229 | goto error; | 1238 | hh_len, fragheaderlen, |
| 1230 | return 0; | 1239 | transhdrlen, mtu, flags); |
| 1240 | if (err) | ||
| 1241 | goto error; | ||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1231 | } | 1244 | } |
| 1232 | 1245 | ||
| 1233 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) | 1246 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) |
| @@ -1265,7 +1278,7 @@ alloc_new_skb: | |||
| 1265 | 1278 | ||
| 1266 | fraglen = datalen + fragheaderlen; | 1279 | fraglen = datalen + fragheaderlen; |
| 1267 | if ((flags & MSG_MORE) && | 1280 | if ((flags & MSG_MORE) && |
| 1268 | !(rt->u.dst.dev->features&NETIF_F_SG)) | 1281 | !(rt->dst.dev->features&NETIF_F_SG)) |
| 1269 | alloclen = mtu; | 1282 | alloclen = mtu; |
| 1270 | else | 1283 | else |
| 1271 | alloclen = datalen + fragheaderlen; | 1284 | alloclen = datalen + fragheaderlen; |
| @@ -1276,7 +1289,7 @@ alloc_new_skb: | |||
| 1276 | * because we have no idea if we're the last one. | 1289 | * because we have no idea if we're the last one. |
| 1277 | */ | 1290 | */ |
| 1278 | if (datalen == length + fraggap) | 1291 | if (datalen == length + fraggap) |
| 1279 | alloclen += rt->u.dst.trailer_len; | 1292 | alloclen += rt->dst.trailer_len; |
| 1280 | 1293 | ||
| 1281 | /* | 1294 | /* |
| 1282 | * We just reserve space for fragment header. | 1295 | * We just reserve space for fragment header. |
| @@ -1353,7 +1366,7 @@ alloc_new_skb: | |||
| 1353 | if (copy > length) | 1366 | if (copy > length) |
| 1354 | copy = length; | 1367 | copy = length; |
| 1355 | 1368 | ||
| 1356 | if (!(rt->u.dst.dev->features&NETIF_F_SG)) { | 1369 | if (!(rt->dst.dev->features&NETIF_F_SG)) { |
| 1357 | unsigned int off; | 1370 | unsigned int off; |
| 1358 | 1371 | ||
| 1359 | off = skb->len; | 1372 | off = skb->len; |
| @@ -1498,7 +1511,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
| 1498 | skb->priority = sk->sk_priority; | 1511 | skb->priority = sk->sk_priority; |
| 1499 | skb->mark = sk->sk_mark; | 1512 | skb->mark = sk->sk_mark; |
| 1500 | 1513 | ||
| 1501 | skb_dst_set(skb, dst_clone(&rt->u.dst)); | 1514 | skb_dst_set(skb, dst_clone(&rt->dst)); |
| 1502 | IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); | 1515 | IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); |
| 1503 | if (proto == IPPROTO_ICMPV6) { | 1516 | if (proto == IPPROTO_ICMPV6) { |
| 1504 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); | 1517 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d453d07b0dfe..0fd027f3f47e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/route.h> | 37 | #include <linux/route.h> |
| 38 | #include <linux/rtnetlink.h> | 38 | #include <linux/rtnetlink.h> |
| 39 | #include <linux/netfilter_ipv6.h> | 39 | #include <linux/netfilter_ipv6.h> |
| 40 | #include <linux/slab.h> | ||
| 40 | 41 | ||
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| 42 | #include <asm/atomic.h> | 43 | #include <asm/atomic.h> |
| @@ -74,7 +75,6 @@ MODULE_LICENSE("GPL"); | |||
| 74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
| 75 | (HASH_SIZE - 1)) | 76 | (HASH_SIZE - 1)) |
| 76 | 77 | ||
| 77 | static void ip6_fb_tnl_dev_init(struct net_device *dev); | ||
| 78 | static void ip6_tnl_dev_init(struct net_device *dev); | 78 | static void ip6_tnl_dev_init(struct net_device *dev); |
| 79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 79 | static void ip6_tnl_dev_setup(struct net_device *dev); |
| 80 | 80 | ||
| @@ -552,7 +552,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 552 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) | 552 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) |
| 553 | goto out; | 553 | goto out; |
| 554 | 554 | ||
| 555 | skb2->dev = rt->u.dst.dev; | 555 | skb2->dev = rt->dst.dev; |
| 556 | 556 | ||
| 557 | /* route "incoming" packet */ | 557 | /* route "incoming" packet */ |
| 558 | if (rt->rt_flags & RTCF_LOCAL) { | 558 | if (rt->rt_flags & RTCF_LOCAL) { |
| @@ -562,7 +562,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 562 | fl.fl4_src = eiph->saddr; | 562 | fl.fl4_src = eiph->saddr; |
| 563 | fl.fl4_tos = eiph->tos; | 563 | fl.fl4_tos = eiph->tos; |
| 564 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || | 564 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || |
| 565 | rt->u.dst.dev->type != ARPHRD_TUNNEL) { | 565 | rt->dst.dev->type != ARPHRD_TUNNEL) { |
| 566 | ip_rt_put(rt); | 566 | ip_rt_put(rt); |
| 567 | goto out; | 567 | goto out; |
| 568 | } | 568 | } |
| @@ -623,10 +623,10 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 623 | if (rt && rt->rt6i_dev) | 623 | if (rt && rt->rt6i_dev) |
| 624 | skb2->dev = rt->rt6i_dev; | 624 | skb2->dev = rt->rt6i_dev; |
| 625 | 625 | ||
| 626 | icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); | 626 | icmpv6_send(skb2, rel_type, rel_code, rel_info); |
| 627 | 627 | ||
| 628 | if (rt) | 628 | if (rt) |
| 629 | dst_release(&rt->u.dst); | 629 | dst_release(&rt->dst); |
| 630 | 630 | ||
| 631 | kfree_skb(skb2); | 631 | kfree_skb(skb2); |
| 632 | } | 632 | } |
| @@ -723,14 +723,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
| 723 | skb->protocol = htons(protocol); | 723 | skb->protocol = htons(protocol); |
| 724 | skb->pkt_type = PACKET_HOST; | 724 | skb->pkt_type = PACKET_HOST; |
| 725 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); | 725 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
| 726 | skb->dev = t->dev; | ||
| 727 | skb_dst_drop(skb); | ||
| 728 | nf_reset(skb); | ||
| 729 | 726 | ||
| 730 | dscp_ecn_decapsulate(t, ipv6h, skb); | 727 | skb_tunnel_rx(skb, t->dev); |
| 731 | 728 | ||
| 732 | t->dev->stats.rx_packets++; | 729 | dscp_ecn_decapsulate(t, ipv6h, skb); |
| 733 | t->dev->stats.rx_bytes += skb->len; | ||
| 734 | netif_rx(skb); | 730 | netif_rx(skb); |
| 735 | rcu_read_unlock(); | 731 | rcu_read_unlock(); |
| 736 | return 0; | 732 | return 0; |
| @@ -1015,7 +1011,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1015 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 1011 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
| 1016 | if (tel->encap_limit == 0) { | 1012 | if (tel->encap_limit == 0) { |
| 1017 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 1013 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
| 1018 | ICMPV6_HDR_FIELD, offset + 2, skb->dev); | 1014 | ICMPV6_HDR_FIELD, offset + 2); |
| 1019 | return -1; | 1015 | return -1; |
| 1020 | } | 1016 | } |
| 1021 | encap_limit = tel->encap_limit - 1; | 1017 | encap_limit = tel->encap_limit - 1; |
| @@ -1034,7 +1030,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 1034 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1030 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); |
| 1035 | if (err != 0) { | 1031 | if (err != 0) { |
| 1036 | if (err == -EMSGSIZE) | 1032 | if (err == -EMSGSIZE) |
| 1037 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 1033 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 1038 | return -1; | 1034 | return -1; |
| 1039 | } | 1035 | } |
| 1040 | 1036 | ||
| @@ -1139,7 +1135,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
| 1139 | if (dev->mtu < IPV6_MIN_MTU) | 1135 | if (dev->mtu < IPV6_MIN_MTU) |
| 1140 | dev->mtu = IPV6_MIN_MTU; | 1136 | dev->mtu = IPV6_MIN_MTU; |
| 1141 | } | 1137 | } |
| 1142 | dst_release(&rt->u.dst); | 1138 | dst_release(&rt->dst); |
| 1143 | } | 1139 | } |
| 1144 | } | 1140 | } |
| 1145 | 1141 | ||
| @@ -1364,7 +1360,7 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
| 1364 | * Return: 0 | 1360 | * Return: 0 |
| 1365 | **/ | 1361 | **/ |
| 1366 | 1362 | ||
| 1367 | static void ip6_fb_tnl_dev_init(struct net_device *dev) | 1363 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
| 1368 | { | 1364 | { |
| 1369 | struct ip6_tnl *t = netdev_priv(dev); | 1365 | struct ip6_tnl *t = netdev_priv(dev); |
| 1370 | struct net *net = dev_net(dev); | 1366 | struct net *net = dev_net(dev); |
| @@ -1388,7 +1384,7 @@ static struct xfrm6_tunnel ip6ip6_handler = { | |||
| 1388 | .priority = 1, | 1384 | .priority = 1, |
| 1389 | }; | 1385 | }; |
| 1390 | 1386 | ||
| 1391 | static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | 1387 | static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) |
| 1392 | { | 1388 | { |
| 1393 | int h; | 1389 | int h; |
| 1394 | struct ip6_tnl *t; | 1390 | struct ip6_tnl *t; |
| @@ -1407,7 +1403,7 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | |||
| 1407 | unregister_netdevice_many(&list); | 1403 | unregister_netdevice_many(&list); |
| 1408 | } | 1404 | } |
| 1409 | 1405 | ||
| 1410 | static int ip6_tnl_init_net(struct net *net) | 1406 | static int __net_init ip6_tnl_init_net(struct net *net) |
| 1411 | { | 1407 | { |
| 1412 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1408 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
| 1413 | int err; | 1409 | int err; |
| @@ -1436,7 +1432,7 @@ err_alloc_dev: | |||
| 1436 | return err; | 1432 | return err; |
| 1437 | } | 1433 | } |
| 1438 | 1434 | ||
| 1439 | static void ip6_tnl_exit_net(struct net *net) | 1435 | static void __net_exit ip6_tnl_exit_net(struct net *net) |
| 1440 | { | 1436 | { |
| 1441 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1437 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
| 1442 | 1438 | ||
| @@ -1462,27 +1458,29 @@ static int __init ip6_tunnel_init(void) | |||
| 1462 | { | 1458 | { |
| 1463 | int err; | 1459 | int err; |
| 1464 | 1460 | ||
| 1465 | if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) { | 1461 | err = register_pernet_device(&ip6_tnl_net_ops); |
| 1462 | if (err < 0) | ||
| 1463 | goto out_pernet; | ||
| 1464 | |||
| 1465 | err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET); | ||
| 1466 | if (err < 0) { | ||
| 1466 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); | 1467 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); |
| 1467 | err = -EAGAIN; | 1468 | goto out_ip4ip6; |
| 1468 | goto out; | ||
| 1469 | } | 1469 | } |
| 1470 | 1470 | ||
| 1471 | if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { | 1471 | err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6); |
| 1472 | if (err < 0) { | ||
| 1472 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); | 1473 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); |
| 1473 | err = -EAGAIN; | 1474 | goto out_ip6ip6; |
| 1474 | goto unreg_ip4ip6; | ||
| 1475 | } | 1475 | } |
| 1476 | 1476 | ||
| 1477 | err = register_pernet_device(&ip6_tnl_net_ops); | ||
| 1478 | if (err < 0) | ||
| 1479 | goto err_pernet; | ||
| 1480 | return 0; | 1477 | return 0; |
| 1481 | err_pernet: | 1478 | |
| 1482 | xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); | 1479 | out_ip6ip6: |
| 1483 | unreg_ip4ip6: | ||
| 1484 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); | 1480 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); |
| 1485 | out: | 1481 | out_ip4ip6: |
| 1482 | unregister_pernet_device(&ip6_tnl_net_ops); | ||
| 1483 | out_pernet: | ||
| 1486 | return err; | 1484 | return err; |
| 1487 | } | 1485 | } |
| 1488 | 1486 | ||
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 52e0f74fdfe0..66078dad7fe8 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
| 34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/slab.h> | ||
| 36 | #include <net/protocol.h> | 37 | #include <net/protocol.h> |
| 37 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
| 38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
| @@ -41,6 +42,7 @@ | |||
| 41 | #include <linux/if_arp.h> | 42 | #include <linux/if_arp.h> |
| 42 | #include <net/checksum.h> | 43 | #include <net/checksum.h> |
| 43 | #include <net/netlink.h> | 44 | #include <net/netlink.h> |
| 45 | #include <net/fib_rules.h> | ||
| 44 | 46 | ||
| 45 | #include <net/ipv6.h> | 47 | #include <net/ipv6.h> |
| 46 | #include <net/ip6_route.h> | 48 | #include <net/ip6_route.h> |
| @@ -50,6 +52,34 @@ | |||
| 50 | #include <linux/netfilter_ipv6.h> | 52 | #include <linux/netfilter_ipv6.h> |
| 51 | #include <net/ip6_checksum.h> | 53 | #include <net/ip6_checksum.h> |
| 52 | 54 | ||
| 55 | struct mr6_table { | ||
| 56 | struct list_head list; | ||
| 57 | #ifdef CONFIG_NET_NS | ||
| 58 | struct net *net; | ||
| 59 | #endif | ||
| 60 | u32 id; | ||
| 61 | struct sock *mroute6_sk; | ||
| 62 | struct timer_list ipmr_expire_timer; | ||
| 63 | struct list_head mfc6_unres_queue; | ||
| 64 | struct list_head mfc6_cache_array[MFC6_LINES]; | ||
| 65 | struct mif_device vif6_table[MAXMIFS]; | ||
| 66 | int maxvif; | ||
| 67 | atomic_t cache_resolve_queue_len; | ||
| 68 | int mroute_do_assert; | ||
| 69 | int mroute_do_pim; | ||
| 70 | #ifdef CONFIG_IPV6_PIMSM_V2 | ||
| 71 | int mroute_reg_vif_num; | ||
| 72 | #endif | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct ip6mr_rule { | ||
| 76 | struct fib_rule common; | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct ip6mr_result { | ||
| 80 | struct mr6_table *mrt; | ||
| 81 | }; | ||
| 82 | |||
| 53 | /* Big lock, protecting vif table, mrt cache and mroute socket state. | 83 | /* Big lock, protecting vif table, mrt cache and mroute socket state. |
| 54 | Note that the changes are semaphored via rtnl_lock. | 84 | Note that the changes are semaphored via rtnl_lock. |
| 55 | */ | 85 | */ |
| @@ -60,9 +90,7 @@ static DEFINE_RWLOCK(mrt_lock); | |||
| 60 | * Multicast router control variables | 90 | * Multicast router control variables |
| 61 | */ | 91 | */ |
| 62 | 92 | ||
| 63 | #define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL) | 93 | #define MIF_EXISTS(_mrt, _idx) ((_mrt)->vif6_table[_idx].dev != NULL) |
| 64 | |||
| 65 | static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ | ||
| 66 | 94 | ||
| 67 | /* Special spinlock for queue of unresolved entries */ | 95 | /* Special spinlock for queue of unresolved entries */ |
| 68 | static DEFINE_SPINLOCK(mfc_unres_lock); | 96 | static DEFINE_SPINLOCK(mfc_unres_lock); |
| @@ -77,20 +105,235 @@ static DEFINE_SPINLOCK(mfc_unres_lock); | |||
| 77 | 105 | ||
| 78 | static struct kmem_cache *mrt_cachep __read_mostly; | 106 | static struct kmem_cache *mrt_cachep __read_mostly; |
| 79 | 107 | ||
| 80 | static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); | 108 | static struct mr6_table *ip6mr_new_table(struct net *net, u32 id); |
| 81 | static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, | 109 | static void ip6mr_free_table(struct mr6_table *mrt); |
| 110 | |||
| 111 | static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | ||
| 112 | struct sk_buff *skb, struct mfc6_cache *cache); | ||
| 113 | static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, | ||
| 82 | mifi_t mifi, int assert); | 114 | mifi_t mifi, int assert); |
| 83 | static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); | 115 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
| 84 | static void mroute_clean_tables(struct net *net); | 116 | struct mfc6_cache *c, struct rtmsg *rtm); |
| 117 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, | ||
| 118 | struct netlink_callback *cb); | ||
| 119 | static void mroute_clean_tables(struct mr6_table *mrt); | ||
| 120 | static void ipmr_expire_process(unsigned long arg); | ||
| 121 | |||
| 122 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES | ||
| 123 | #define ip6mr_for_each_table(mrt, net) \ | ||
| 124 | list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list) | ||
| 125 | |||
| 126 | static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | ||
| 127 | { | ||
| 128 | struct mr6_table *mrt; | ||
| 129 | |||
| 130 | ip6mr_for_each_table(mrt, net) { | ||
| 131 | if (mrt->id == id) | ||
| 132 | return mrt; | ||
| 133 | } | ||
| 134 | return NULL; | ||
| 135 | } | ||
| 136 | |||
| 137 | static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, | ||
| 138 | struct mr6_table **mrt) | ||
| 139 | { | ||
| 140 | struct ip6mr_result res; | ||
| 141 | struct fib_lookup_arg arg = { .result = &res, }; | ||
| 142 | int err; | ||
| 143 | |||
| 144 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg); | ||
| 145 | if (err < 0) | ||
| 146 | return err; | ||
| 147 | *mrt = res.mrt; | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, | ||
| 152 | int flags, struct fib_lookup_arg *arg) | ||
| 153 | { | ||
| 154 | struct ip6mr_result *res = arg->result; | ||
| 155 | struct mr6_table *mrt; | ||
| 156 | |||
| 157 | switch (rule->action) { | ||
| 158 | case FR_ACT_TO_TBL: | ||
| 159 | break; | ||
| 160 | case FR_ACT_UNREACHABLE: | ||
| 161 | return -ENETUNREACH; | ||
| 162 | case FR_ACT_PROHIBIT: | ||
| 163 | return -EACCES; | ||
| 164 | case FR_ACT_BLACKHOLE: | ||
| 165 | default: | ||
| 166 | return -EINVAL; | ||
| 167 | } | ||
| 168 | |||
| 169 | mrt = ip6mr_get_table(rule->fr_net, rule->table); | ||
| 170 | if (mrt == NULL) | ||
| 171 | return -EAGAIN; | ||
| 172 | res->mrt = mrt; | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags) | ||
| 177 | { | ||
| 178 | return 1; | ||
| 179 | } | ||
| 85 | 180 | ||
| 86 | static struct timer_list ipmr_expire_timer; | 181 | static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = { |
| 182 | FRA_GENERIC_POLICY, | ||
| 183 | }; | ||
| 87 | 184 | ||
| 185 | static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | ||
| 186 | struct fib_rule_hdr *frh, struct nlattr **tb) | ||
| 187 | { | ||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | ||
| 192 | struct nlattr **tb) | ||
| 193 | { | ||
| 194 | return 1; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | ||
| 198 | struct fib_rule_hdr *frh) | ||
| 199 | { | ||
| 200 | frh->dst_len = 0; | ||
| 201 | frh->src_len = 0; | ||
| 202 | frh->tos = 0; | ||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = { | ||
| 207 | .family = RTNL_FAMILY_IP6MR, | ||
| 208 | .rule_size = sizeof(struct ip6mr_rule), | ||
| 209 | .addr_size = sizeof(struct in6_addr), | ||
| 210 | .action = ip6mr_rule_action, | ||
| 211 | .match = ip6mr_rule_match, | ||
| 212 | .configure = ip6mr_rule_configure, | ||
| 213 | .compare = ip6mr_rule_compare, | ||
| 214 | .default_pref = fib_default_rule_pref, | ||
| 215 | .fill = ip6mr_rule_fill, | ||
| 216 | .nlgroup = RTNLGRP_IPV6_RULE, | ||
| 217 | .policy = ip6mr_rule_policy, | ||
| 218 | .owner = THIS_MODULE, | ||
| 219 | }; | ||
| 220 | |||
| 221 | static int __net_init ip6mr_rules_init(struct net *net) | ||
| 222 | { | ||
| 223 | struct fib_rules_ops *ops; | ||
| 224 | struct mr6_table *mrt; | ||
| 225 | int err; | ||
| 226 | |||
| 227 | ops = fib_rules_register(&ip6mr_rules_ops_template, net); | ||
| 228 | if (IS_ERR(ops)) | ||
| 229 | return PTR_ERR(ops); | ||
| 230 | |||
| 231 | INIT_LIST_HEAD(&net->ipv6.mr6_tables); | ||
| 232 | |||
| 233 | mrt = ip6mr_new_table(net, RT6_TABLE_DFLT); | ||
| 234 | if (mrt == NULL) { | ||
| 235 | err = -ENOMEM; | ||
| 236 | goto err1; | ||
| 237 | } | ||
| 238 | |||
| 239 | err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0); | ||
| 240 | if (err < 0) | ||
| 241 | goto err2; | ||
| 242 | |||
| 243 | net->ipv6.mr6_rules_ops = ops; | ||
| 244 | return 0; | ||
| 245 | |||
| 246 | err2: | ||
| 247 | kfree(mrt); | ||
| 248 | err1: | ||
| 249 | fib_rules_unregister(ops); | ||
| 250 | return err; | ||
| 251 | } | ||
| 252 | |||
| 253 | static void __net_exit ip6mr_rules_exit(struct net *net) | ||
| 254 | { | ||
| 255 | struct mr6_table *mrt, *next; | ||
| 256 | |||
| 257 | list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { | ||
| 258 | list_del(&mrt->list); | ||
| 259 | ip6mr_free_table(mrt); | ||
| 260 | } | ||
| 261 | fib_rules_unregister(net->ipv6.mr6_rules_ops); | ||
| 262 | } | ||
| 263 | #else | ||
| 264 | #define ip6mr_for_each_table(mrt, net) \ | ||
| 265 | for (mrt = net->ipv6.mrt6; mrt; mrt = NULL) | ||
| 266 | |||
| 267 | static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | ||
| 268 | { | ||
| 269 | return net->ipv6.mrt6; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, | ||
| 273 | struct mr6_table **mrt) | ||
| 274 | { | ||
| 275 | *mrt = net->ipv6.mrt6; | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static int __net_init ip6mr_rules_init(struct net *net) | ||
| 280 | { | ||
| 281 | net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT); | ||
| 282 | return net->ipv6.mrt6 ? 0 : -ENOMEM; | ||
| 283 | } | ||
| 284 | |||
| 285 | static void __net_exit ip6mr_rules_exit(struct net *net) | ||
| 286 | { | ||
| 287 | ip6mr_free_table(net->ipv6.mrt6); | ||
| 288 | } | ||
| 289 | #endif | ||
| 290 | |||
| 291 | static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) | ||
| 292 | { | ||
| 293 | struct mr6_table *mrt; | ||
| 294 | unsigned int i; | ||
| 295 | |||
| 296 | mrt = ip6mr_get_table(net, id); | ||
| 297 | if (mrt != NULL) | ||
| 298 | return mrt; | ||
| 299 | |||
| 300 | mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); | ||
| 301 | if (mrt == NULL) | ||
| 302 | return NULL; | ||
| 303 | mrt->id = id; | ||
| 304 | write_pnet(&mrt->net, net); | ||
| 305 | |||
| 306 | /* Forwarding cache */ | ||
| 307 | for (i = 0; i < MFC6_LINES; i++) | ||
| 308 | INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]); | ||
| 309 | |||
| 310 | INIT_LIST_HEAD(&mrt->mfc6_unres_queue); | ||
| 311 | |||
| 312 | setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process, | ||
| 313 | (unsigned long)mrt); | ||
| 314 | |||
| 315 | #ifdef CONFIG_IPV6_PIMSM_V2 | ||
| 316 | mrt->mroute_reg_vif_num = -1; | ||
| 317 | #endif | ||
| 318 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES | ||
| 319 | list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables); | ||
| 320 | #endif | ||
| 321 | return mrt; | ||
| 322 | } | ||
| 323 | |||
| 324 | static void ip6mr_free_table(struct mr6_table *mrt) | ||
| 325 | { | ||
| 326 | del_timer(&mrt->ipmr_expire_timer); | ||
| 327 | mroute_clean_tables(mrt); | ||
| 328 | kfree(mrt); | ||
| 329 | } | ||
| 88 | 330 | ||
| 89 | #ifdef CONFIG_PROC_FS | 331 | #ifdef CONFIG_PROC_FS |
| 90 | 332 | ||
| 91 | struct ipmr_mfc_iter { | 333 | struct ipmr_mfc_iter { |
| 92 | struct seq_net_private p; | 334 | struct seq_net_private p; |
| 93 | struct mfc6_cache **cache; | 335 | struct mr6_table *mrt; |
| 336 | struct list_head *cache; | ||
| 94 | int ct; | 337 | int ct; |
| 95 | }; | 338 | }; |
| 96 | 339 | ||
| @@ -98,22 +341,22 @@ struct ipmr_mfc_iter { | |||
| 98 | static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, | 341 | static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, |
| 99 | struct ipmr_mfc_iter *it, loff_t pos) | 342 | struct ipmr_mfc_iter *it, loff_t pos) |
| 100 | { | 343 | { |
| 344 | struct mr6_table *mrt = it->mrt; | ||
| 101 | struct mfc6_cache *mfc; | 345 | struct mfc6_cache *mfc; |
| 102 | 346 | ||
| 103 | it->cache = net->ipv6.mfc6_cache_array; | ||
| 104 | read_lock(&mrt_lock); | 347 | read_lock(&mrt_lock); |
| 105 | for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) | 348 | for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) { |
| 106 | for (mfc = net->ipv6.mfc6_cache_array[it->ct]; | 349 | it->cache = &mrt->mfc6_cache_array[it->ct]; |
| 107 | mfc; mfc = mfc->next) | 350 | list_for_each_entry(mfc, it->cache, list) |
| 108 | if (pos-- == 0) | 351 | if (pos-- == 0) |
| 109 | return mfc; | 352 | return mfc; |
| 353 | } | ||
| 110 | read_unlock(&mrt_lock); | 354 | read_unlock(&mrt_lock); |
| 111 | 355 | ||
| 112 | it->cache = &mfc_unres_queue; | ||
| 113 | spin_lock_bh(&mfc_unres_lock); | 356 | spin_lock_bh(&mfc_unres_lock); |
| 114 | for (mfc = mfc_unres_queue; mfc; mfc = mfc->next) | 357 | it->cache = &mrt->mfc6_unres_queue; |
| 115 | if (net_eq(mfc6_net(mfc), net) && | 358 | list_for_each_entry(mfc, it->cache, list) |
| 116 | pos-- == 0) | 359 | if (pos-- == 0) |
| 117 | return mfc; | 360 | return mfc; |
| 118 | spin_unlock_bh(&mfc_unres_lock); | 361 | spin_unlock_bh(&mfc_unres_lock); |
| 119 | 362 | ||
| @@ -121,15 +364,13 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, | |||
| 121 | return NULL; | 364 | return NULL; |
| 122 | } | 365 | } |
| 123 | 366 | ||
| 124 | |||
| 125 | |||
| 126 | |||
| 127 | /* | 367 | /* |
| 128 | * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif | 368 | * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif |
| 129 | */ | 369 | */ |
| 130 | 370 | ||
| 131 | struct ipmr_vif_iter { | 371 | struct ipmr_vif_iter { |
| 132 | struct seq_net_private p; | 372 | struct seq_net_private p; |
| 373 | struct mr6_table *mrt; | ||
| 133 | int ct; | 374 | int ct; |
| 134 | }; | 375 | }; |
| 135 | 376 | ||
| @@ -137,11 +378,13 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net, | |||
| 137 | struct ipmr_vif_iter *iter, | 378 | struct ipmr_vif_iter *iter, |
| 138 | loff_t pos) | 379 | loff_t pos) |
| 139 | { | 380 | { |
| 140 | for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) { | 381 | struct mr6_table *mrt = iter->mrt; |
| 141 | if (!MIF_EXISTS(net, iter->ct)) | 382 | |
| 383 | for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) { | ||
| 384 | if (!MIF_EXISTS(mrt, iter->ct)) | ||
| 142 | continue; | 385 | continue; |
| 143 | if (pos-- == 0) | 386 | if (pos-- == 0) |
| 144 | return &net->ipv6.vif6_table[iter->ct]; | 387 | return &mrt->vif6_table[iter->ct]; |
| 145 | } | 388 | } |
| 146 | return NULL; | 389 | return NULL; |
| 147 | } | 390 | } |
| @@ -149,7 +392,15 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net, | |||
| 149 | static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) | 392 | static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) |
| 150 | __acquires(mrt_lock) | 393 | __acquires(mrt_lock) |
| 151 | { | 394 | { |
| 395 | struct ipmr_vif_iter *iter = seq->private; | ||
| 152 | struct net *net = seq_file_net(seq); | 396 | struct net *net = seq_file_net(seq); |
| 397 | struct mr6_table *mrt; | ||
| 398 | |||
| 399 | mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); | ||
| 400 | if (mrt == NULL) | ||
| 401 | return ERR_PTR(-ENOENT); | ||
| 402 | |||
| 403 | iter->mrt = mrt; | ||
| 153 | 404 | ||
| 154 | read_lock(&mrt_lock); | 405 | read_lock(&mrt_lock); |
| 155 | return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1) | 406 | return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1) |
| @@ -160,15 +411,16 @@ static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 160 | { | 411 | { |
| 161 | struct ipmr_vif_iter *iter = seq->private; | 412 | struct ipmr_vif_iter *iter = seq->private; |
| 162 | struct net *net = seq_file_net(seq); | 413 | struct net *net = seq_file_net(seq); |
| 414 | struct mr6_table *mrt = iter->mrt; | ||
| 163 | 415 | ||
| 164 | ++*pos; | 416 | ++*pos; |
| 165 | if (v == SEQ_START_TOKEN) | 417 | if (v == SEQ_START_TOKEN) |
| 166 | return ip6mr_vif_seq_idx(net, iter, 0); | 418 | return ip6mr_vif_seq_idx(net, iter, 0); |
| 167 | 419 | ||
| 168 | while (++iter->ct < net->ipv6.maxvif) { | 420 | while (++iter->ct < mrt->maxvif) { |
| 169 | if (!MIF_EXISTS(net, iter->ct)) | 421 | if (!MIF_EXISTS(mrt, iter->ct)) |
| 170 | continue; | 422 | continue; |
| 171 | return &net->ipv6.vif6_table[iter->ct]; | 423 | return &mrt->vif6_table[iter->ct]; |
| 172 | } | 424 | } |
| 173 | return NULL; | 425 | return NULL; |
| 174 | } | 426 | } |
| @@ -181,7 +433,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v) | |||
| 181 | 433 | ||
| 182 | static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) | 434 | static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) |
| 183 | { | 435 | { |
| 184 | struct net *net = seq_file_net(seq); | 436 | struct ipmr_vif_iter *iter = seq->private; |
| 437 | struct mr6_table *mrt = iter->mrt; | ||
| 185 | 438 | ||
| 186 | if (v == SEQ_START_TOKEN) { | 439 | if (v == SEQ_START_TOKEN) { |
| 187 | seq_puts(seq, | 440 | seq_puts(seq, |
| @@ -192,7 +445,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) | |||
| 192 | 445 | ||
| 193 | seq_printf(seq, | 446 | seq_printf(seq, |
| 194 | "%2td %-10s %8ld %7ld %8ld %7ld %05X\n", | 447 | "%2td %-10s %8ld %7ld %8ld %7ld %05X\n", |
| 195 | vif - net->ipv6.vif6_table, | 448 | vif - mrt->vif6_table, |
| 196 | name, vif->bytes_in, vif->pkt_in, | 449 | name, vif->bytes_in, vif->pkt_in, |
| 197 | vif->bytes_out, vif->pkt_out, | 450 | vif->bytes_out, vif->pkt_out, |
| 198 | vif->flags); | 451 | vif->flags); |
| @@ -223,8 +476,15 @@ static const struct file_operations ip6mr_vif_fops = { | |||
| 223 | 476 | ||
| 224 | static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) | 477 | static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) |
| 225 | { | 478 | { |
| 479 | struct ipmr_mfc_iter *it = seq->private; | ||
| 226 | struct net *net = seq_file_net(seq); | 480 | struct net *net = seq_file_net(seq); |
| 481 | struct mr6_table *mrt; | ||
| 482 | |||
| 483 | mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); | ||
| 484 | if (mrt == NULL) | ||
| 485 | return ERR_PTR(-ENOENT); | ||
| 227 | 486 | ||
| 487 | it->mrt = mrt; | ||
| 228 | return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) | 488 | return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) |
| 229 | : SEQ_START_TOKEN; | 489 | : SEQ_START_TOKEN; |
| 230 | } | 490 | } |
| @@ -234,35 +494,36 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 234 | struct mfc6_cache *mfc = v; | 494 | struct mfc6_cache *mfc = v; |
| 235 | struct ipmr_mfc_iter *it = seq->private; | 495 | struct ipmr_mfc_iter *it = seq->private; |
| 236 | struct net *net = seq_file_net(seq); | 496 | struct net *net = seq_file_net(seq); |
| 497 | struct mr6_table *mrt = it->mrt; | ||
| 237 | 498 | ||
| 238 | ++*pos; | 499 | ++*pos; |
| 239 | 500 | ||
| 240 | if (v == SEQ_START_TOKEN) | 501 | if (v == SEQ_START_TOKEN) |
| 241 | return ipmr_mfc_seq_idx(net, seq->private, 0); | 502 | return ipmr_mfc_seq_idx(net, seq->private, 0); |
| 242 | 503 | ||
| 243 | if (mfc->next) | 504 | if (mfc->list.next != it->cache) |
| 244 | return mfc->next; | 505 | return list_entry(mfc->list.next, struct mfc6_cache, list); |
| 245 | 506 | ||
| 246 | if (it->cache == &mfc_unres_queue) | 507 | if (it->cache == &mrt->mfc6_unres_queue) |
| 247 | goto end_of_list; | 508 | goto end_of_list; |
| 248 | 509 | ||
| 249 | BUG_ON(it->cache != net->ipv6.mfc6_cache_array); | 510 | BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]); |
| 250 | 511 | ||
| 251 | while (++it->ct < MFC6_LINES) { | 512 | while (++it->ct < MFC6_LINES) { |
| 252 | mfc = net->ipv6.mfc6_cache_array[it->ct]; | 513 | it->cache = &mrt->mfc6_cache_array[it->ct]; |
| 253 | if (mfc) | 514 | if (list_empty(it->cache)) |
| 254 | return mfc; | 515 | continue; |
| 516 | return list_first_entry(it->cache, struct mfc6_cache, list); | ||
| 255 | } | 517 | } |
| 256 | 518 | ||
| 257 | /* exhausted cache_array, show unresolved */ | 519 | /* exhausted cache_array, show unresolved */ |
| 258 | read_unlock(&mrt_lock); | 520 | read_unlock(&mrt_lock); |
| 259 | it->cache = &mfc_unres_queue; | 521 | it->cache = &mrt->mfc6_unres_queue; |
| 260 | it->ct = 0; | 522 | it->ct = 0; |
| 261 | 523 | ||
| 262 | spin_lock_bh(&mfc_unres_lock); | 524 | spin_lock_bh(&mfc_unres_lock); |
| 263 | mfc = mfc_unres_queue; | 525 | if (!list_empty(it->cache)) |
| 264 | if (mfc) | 526 | return list_first_entry(it->cache, struct mfc6_cache, list); |
| 265 | return mfc; | ||
| 266 | 527 | ||
| 267 | end_of_list: | 528 | end_of_list: |
| 268 | spin_unlock_bh(&mfc_unres_lock); | 529 | spin_unlock_bh(&mfc_unres_lock); |
| @@ -274,18 +535,17 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 274 | static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) | 535 | static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) |
| 275 | { | 536 | { |
| 276 | struct ipmr_mfc_iter *it = seq->private; | 537 | struct ipmr_mfc_iter *it = seq->private; |
| 277 | struct net *net = seq_file_net(seq); | 538 | struct mr6_table *mrt = it->mrt; |
| 278 | 539 | ||
| 279 | if (it->cache == &mfc_unres_queue) | 540 | if (it->cache == &mrt->mfc6_unres_queue) |
| 280 | spin_unlock_bh(&mfc_unres_lock); | 541 | spin_unlock_bh(&mfc_unres_lock); |
| 281 | else if (it->cache == net->ipv6.mfc6_cache_array) | 542 | else if (it->cache == mrt->mfc6_cache_array) |
| 282 | read_unlock(&mrt_lock); | 543 | read_unlock(&mrt_lock); |
| 283 | } | 544 | } |
| 284 | 545 | ||
| 285 | static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | 546 | static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) |
| 286 | { | 547 | { |
| 287 | int n; | 548 | int n; |
| 288 | struct net *net = seq_file_net(seq); | ||
| 289 | 549 | ||
| 290 | if (v == SEQ_START_TOKEN) { | 550 | if (v == SEQ_START_TOKEN) { |
| 291 | seq_puts(seq, | 551 | seq_puts(seq, |
| @@ -295,19 +555,20 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) | |||
| 295 | } else { | 555 | } else { |
| 296 | const struct mfc6_cache *mfc = v; | 556 | const struct mfc6_cache *mfc = v; |
| 297 | const struct ipmr_mfc_iter *it = seq->private; | 557 | const struct ipmr_mfc_iter *it = seq->private; |
| 558 | struct mr6_table *mrt = it->mrt; | ||
| 298 | 559 | ||
| 299 | seq_printf(seq, "%pI6 %pI6 %-3hd", | 560 | seq_printf(seq, "%pI6 %pI6 %-3hd", |
| 300 | &mfc->mf6c_mcastgrp, &mfc->mf6c_origin, | 561 | &mfc->mf6c_mcastgrp, &mfc->mf6c_origin, |
| 301 | mfc->mf6c_parent); | 562 | mfc->mf6c_parent); |
| 302 | 563 | ||
| 303 | if (it->cache != &mfc_unres_queue) { | 564 | if (it->cache != &mrt->mfc6_unres_queue) { |
| 304 | seq_printf(seq, " %8lu %8lu %8lu", | 565 | seq_printf(seq, " %8lu %8lu %8lu", |
| 305 | mfc->mfc_un.res.pkt, | 566 | mfc->mfc_un.res.pkt, |
| 306 | mfc->mfc_un.res.bytes, | 567 | mfc->mfc_un.res.bytes, |
| 307 | mfc->mfc_un.res.wrong_if); | 568 | mfc->mfc_un.res.wrong_if); |
| 308 | for (n = mfc->mfc_un.res.minvif; | 569 | for (n = mfc->mfc_un.res.minvif; |
| 309 | n < mfc->mfc_un.res.maxvif; n++) { | 570 | n < mfc->mfc_un.res.maxvif; n++) { |
| 310 | if (MIF_EXISTS(net, n) && | 571 | if (MIF_EXISTS(mrt, n) && |
| 311 | mfc->mfc_un.res.ttls[n] < 255) | 572 | mfc->mfc_un.res.ttls[n] < 255) |
| 312 | seq_printf(seq, | 573 | seq_printf(seq, |
| 313 | " %2d:%-3d", | 574 | " %2d:%-3d", |
| @@ -354,7 +615,12 @@ static int pim6_rcv(struct sk_buff *skb) | |||
| 354 | struct ipv6hdr *encap; | 615 | struct ipv6hdr *encap; |
| 355 | struct net_device *reg_dev = NULL; | 616 | struct net_device *reg_dev = NULL; |
| 356 | struct net *net = dev_net(skb->dev); | 617 | struct net *net = dev_net(skb->dev); |
| 357 | int reg_vif_num = net->ipv6.mroute_reg_vif_num; | 618 | struct mr6_table *mrt; |
| 619 | struct flowi fl = { | ||
| 620 | .iif = skb->dev->ifindex, | ||
| 621 | .mark = skb->mark, | ||
| 622 | }; | ||
| 623 | int reg_vif_num; | ||
| 358 | 624 | ||
| 359 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) | 625 | if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) |
| 360 | goto drop; | 626 | goto drop; |
| @@ -377,9 +643,13 @@ static int pim6_rcv(struct sk_buff *skb) | |||
| 377 | ntohs(encap->payload_len) + sizeof(*pim) > skb->len) | 643 | ntohs(encap->payload_len) + sizeof(*pim) > skb->len) |
| 378 | goto drop; | 644 | goto drop; |
| 379 | 645 | ||
| 646 | if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) | ||
| 647 | goto drop; | ||
| 648 | reg_vif_num = mrt->mroute_reg_vif_num; | ||
| 649 | |||
| 380 | read_lock(&mrt_lock); | 650 | read_lock(&mrt_lock); |
| 381 | if (reg_vif_num >= 0) | 651 | if (reg_vif_num >= 0) |
| 382 | reg_dev = net->ipv6.vif6_table[reg_vif_num].dev; | 652 | reg_dev = mrt->vif6_table[reg_vif_num].dev; |
| 383 | if (reg_dev) | 653 | if (reg_dev) |
| 384 | dev_hold(reg_dev); | 654 | dev_hold(reg_dev); |
| 385 | read_unlock(&mrt_lock); | 655 | read_unlock(&mrt_lock); |
| @@ -390,14 +660,12 @@ static int pim6_rcv(struct sk_buff *skb) | |||
| 390 | skb->mac_header = skb->network_header; | 660 | skb->mac_header = skb->network_header; |
| 391 | skb_pull(skb, (u8 *)encap - skb->data); | 661 | skb_pull(skb, (u8 *)encap - skb->data); |
| 392 | skb_reset_network_header(skb); | 662 | skb_reset_network_header(skb); |
| 393 | skb->dev = reg_dev; | ||
| 394 | skb->protocol = htons(ETH_P_IPV6); | 663 | skb->protocol = htons(ETH_P_IPV6); |
| 395 | skb->ip_summed = 0; | 664 | skb->ip_summed = 0; |
| 396 | skb->pkt_type = PACKET_HOST; | 665 | skb->pkt_type = PACKET_HOST; |
| 397 | skb_dst_drop(skb); | 666 | |
| 398 | reg_dev->stats.rx_bytes += skb->len; | 667 | skb_tunnel_rx(skb, reg_dev); |
| 399 | reg_dev->stats.rx_packets++; | 668 | |
| 400 | nf_reset(skb); | ||
| 401 | netif_rx(skb); | 669 | netif_rx(skb); |
| 402 | dev_put(reg_dev); | 670 | dev_put(reg_dev); |
| 403 | return 0; | 671 | return 0; |
| @@ -416,12 +684,22 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, | |||
| 416 | struct net_device *dev) | 684 | struct net_device *dev) |
| 417 | { | 685 | { |
| 418 | struct net *net = dev_net(dev); | 686 | struct net *net = dev_net(dev); |
| 687 | struct mr6_table *mrt; | ||
| 688 | struct flowi fl = { | ||
| 689 | .oif = dev->ifindex, | ||
| 690 | .iif = skb->skb_iif, | ||
| 691 | .mark = skb->mark, | ||
| 692 | }; | ||
| 693 | int err; | ||
| 694 | |||
| 695 | err = ip6mr_fib_lookup(net, &fl, &mrt); | ||
| 696 | if (err < 0) | ||
| 697 | return err; | ||
| 419 | 698 | ||
| 420 | read_lock(&mrt_lock); | 699 | read_lock(&mrt_lock); |
| 421 | dev->stats.tx_bytes += skb->len; | 700 | dev->stats.tx_bytes += skb->len; |
| 422 | dev->stats.tx_packets++; | 701 | dev->stats.tx_packets++; |
| 423 | ip6mr_cache_report(net, skb, net->ipv6.mroute_reg_vif_num, | 702 | ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT); |
| 424 | MRT6MSG_WHOLEPKT); | ||
| 425 | read_unlock(&mrt_lock); | 703 | read_unlock(&mrt_lock); |
| 426 | kfree_skb(skb); | 704 | kfree_skb(skb); |
| 427 | return NETDEV_TX_OK; | 705 | return NETDEV_TX_OK; |
| @@ -441,11 +719,17 @@ static void reg_vif_setup(struct net_device *dev) | |||
| 441 | dev->features |= NETIF_F_NETNS_LOCAL; | 719 | dev->features |= NETIF_F_NETNS_LOCAL; |
| 442 | } | 720 | } |
| 443 | 721 | ||
| 444 | static struct net_device *ip6mr_reg_vif(struct net *net) | 722 | static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt) |
| 445 | { | 723 | { |
| 446 | struct net_device *dev; | 724 | struct net_device *dev; |
| 725 | char name[IFNAMSIZ]; | ||
| 447 | 726 | ||
| 448 | dev = alloc_netdev(0, "pim6reg", reg_vif_setup); | 727 | if (mrt->id == RT6_TABLE_DFLT) |
| 728 | sprintf(name, "pim6reg"); | ||
| 729 | else | ||
| 730 | sprintf(name, "pim6reg%u", mrt->id); | ||
| 731 | |||
| 732 | dev = alloc_netdev(0, name, reg_vif_setup); | ||
| 449 | if (dev == NULL) | 733 | if (dev == NULL) |
| 450 | return NULL; | 734 | return NULL; |
| 451 | 735 | ||
| @@ -477,15 +761,16 @@ failure: | |||
| 477 | * Delete a VIF entry | 761 | * Delete a VIF entry |
| 478 | */ | 762 | */ |
| 479 | 763 | ||
| 480 | static int mif6_delete(struct net *net, int vifi, struct list_head *head) | 764 | static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head) |
| 481 | { | 765 | { |
| 482 | struct mif_device *v; | 766 | struct mif_device *v; |
| 483 | struct net_device *dev; | 767 | struct net_device *dev; |
| 484 | struct inet6_dev *in6_dev; | 768 | struct inet6_dev *in6_dev; |
| 485 | if (vifi < 0 || vifi >= net->ipv6.maxvif) | 769 | |
| 770 | if (vifi < 0 || vifi >= mrt->maxvif) | ||
| 486 | return -EADDRNOTAVAIL; | 771 | return -EADDRNOTAVAIL; |
| 487 | 772 | ||
| 488 | v = &net->ipv6.vif6_table[vifi]; | 773 | v = &mrt->vif6_table[vifi]; |
| 489 | 774 | ||
| 490 | write_lock_bh(&mrt_lock); | 775 | write_lock_bh(&mrt_lock); |
| 491 | dev = v->dev; | 776 | dev = v->dev; |
| @@ -497,17 +782,17 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head) | |||
| 497 | } | 782 | } |
| 498 | 783 | ||
| 499 | #ifdef CONFIG_IPV6_PIMSM_V2 | 784 | #ifdef CONFIG_IPV6_PIMSM_V2 |
| 500 | if (vifi == net->ipv6.mroute_reg_vif_num) | 785 | if (vifi == mrt->mroute_reg_vif_num) |
| 501 | net->ipv6.mroute_reg_vif_num = -1; | 786 | mrt->mroute_reg_vif_num = -1; |
| 502 | #endif | 787 | #endif |
| 503 | 788 | ||
| 504 | if (vifi + 1 == net->ipv6.maxvif) { | 789 | if (vifi + 1 == mrt->maxvif) { |
| 505 | int tmp; | 790 | int tmp; |
| 506 | for (tmp = vifi - 1; tmp >= 0; tmp--) { | 791 | for (tmp = vifi - 1; tmp >= 0; tmp--) { |
| 507 | if (MIF_EXISTS(net, tmp)) | 792 | if (MIF_EXISTS(mrt, tmp)) |
| 508 | break; | 793 | break; |
| 509 | } | 794 | } |
| 510 | net->ipv6.maxvif = tmp + 1; | 795 | mrt->maxvif = tmp + 1; |
| 511 | } | 796 | } |
| 512 | 797 | ||
| 513 | write_unlock_bh(&mrt_lock); | 798 | write_unlock_bh(&mrt_lock); |
| @@ -527,7 +812,6 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head) | |||
| 527 | 812 | ||
| 528 | static inline void ip6mr_cache_free(struct mfc6_cache *c) | 813 | static inline void ip6mr_cache_free(struct mfc6_cache *c) |
| 529 | { | 814 | { |
| 530 | release_net(mfc6_net(c)); | ||
| 531 | kmem_cache_free(mrt_cachep, c); | 815 | kmem_cache_free(mrt_cachep, c); |
| 532 | } | 816 | } |
| 533 | 817 | ||
| @@ -535,12 +819,12 @@ static inline void ip6mr_cache_free(struct mfc6_cache *c) | |||
| 535 | and reporting error to netlink readers. | 819 | and reporting error to netlink readers. |
| 536 | */ | 820 | */ |
| 537 | 821 | ||
| 538 | static void ip6mr_destroy_unres(struct mfc6_cache *c) | 822 | static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c) |
| 539 | { | 823 | { |
| 824 | struct net *net = read_pnet(&mrt->net); | ||
| 540 | struct sk_buff *skb; | 825 | struct sk_buff *skb; |
| 541 | struct net *net = mfc6_net(c); | ||
| 542 | 826 | ||
| 543 | atomic_dec(&net->ipv6.cache_resolve_queue_len); | 827 | atomic_dec(&mrt->cache_resolve_queue_len); |
| 544 | 828 | ||
| 545 | while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { | 829 | while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { |
| 546 | if (ipv6_hdr(skb)->version == 0) { | 830 | if (ipv6_hdr(skb)->version == 0) { |
| @@ -558,60 +842,59 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c) | |||
| 558 | } | 842 | } |
| 559 | 843 | ||
| 560 | 844 | ||
| 561 | /* Single timer process for all the unresolved queue. */ | 845 | /* Timer process for all the unresolved queue. */ |
| 562 | 846 | ||
| 563 | static void ipmr_do_expire_process(unsigned long dummy) | 847 | static void ipmr_do_expire_process(struct mr6_table *mrt) |
| 564 | { | 848 | { |
| 565 | unsigned long now = jiffies; | 849 | unsigned long now = jiffies; |
| 566 | unsigned long expires = 10 * HZ; | 850 | unsigned long expires = 10 * HZ; |
| 567 | struct mfc6_cache *c, **cp; | 851 | struct mfc6_cache *c, *next; |
| 568 | 852 | ||
| 569 | cp = &mfc_unres_queue; | 853 | list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) { |
| 570 | |||
| 571 | while ((c = *cp) != NULL) { | ||
| 572 | if (time_after(c->mfc_un.unres.expires, now)) { | 854 | if (time_after(c->mfc_un.unres.expires, now)) { |
| 573 | /* not yet... */ | 855 | /* not yet... */ |
| 574 | unsigned long interval = c->mfc_un.unres.expires - now; | 856 | unsigned long interval = c->mfc_un.unres.expires - now; |
| 575 | if (interval < expires) | 857 | if (interval < expires) |
| 576 | expires = interval; | 858 | expires = interval; |
| 577 | cp = &c->next; | ||
| 578 | continue; | 859 | continue; |
| 579 | } | 860 | } |
| 580 | 861 | ||
| 581 | *cp = c->next; | 862 | list_del(&c->list); |
| 582 | ip6mr_destroy_unres(c); | 863 | ip6mr_destroy_unres(mrt, c); |
| 583 | } | 864 | } |
| 584 | 865 | ||
| 585 | if (mfc_unres_queue != NULL) | 866 | if (!list_empty(&mrt->mfc6_unres_queue)) |
| 586 | mod_timer(&ipmr_expire_timer, jiffies + expires); | 867 | mod_timer(&mrt->ipmr_expire_timer, jiffies + expires); |
| 587 | } | 868 | } |
| 588 | 869 | ||
| 589 | static void ipmr_expire_process(unsigned long dummy) | 870 | static void ipmr_expire_process(unsigned long arg) |
| 590 | { | 871 | { |
| 872 | struct mr6_table *mrt = (struct mr6_table *)arg; | ||
| 873 | |||
| 591 | if (!spin_trylock(&mfc_unres_lock)) { | 874 | if (!spin_trylock(&mfc_unres_lock)) { |
| 592 | mod_timer(&ipmr_expire_timer, jiffies + 1); | 875 | mod_timer(&mrt->ipmr_expire_timer, jiffies + 1); |
| 593 | return; | 876 | return; |
| 594 | } | 877 | } |
| 595 | 878 | ||
| 596 | if (mfc_unres_queue != NULL) | 879 | if (!list_empty(&mrt->mfc6_unres_queue)) |
| 597 | ipmr_do_expire_process(dummy); | 880 | ipmr_do_expire_process(mrt); |
| 598 | 881 | ||
| 599 | spin_unlock(&mfc_unres_lock); | 882 | spin_unlock(&mfc_unres_lock); |
| 600 | } | 883 | } |
| 601 | 884 | ||
| 602 | /* Fill oifs list. It is called under write locked mrt_lock. */ | 885 | /* Fill oifs list. It is called under write locked mrt_lock. */ |
| 603 | 886 | ||
| 604 | static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls) | 887 | static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache, |
| 888 | unsigned char *ttls) | ||
| 605 | { | 889 | { |
| 606 | int vifi; | 890 | int vifi; |
| 607 | struct net *net = mfc6_net(cache); | ||
| 608 | 891 | ||
| 609 | cache->mfc_un.res.minvif = MAXMIFS; | 892 | cache->mfc_un.res.minvif = MAXMIFS; |
| 610 | cache->mfc_un.res.maxvif = 0; | 893 | cache->mfc_un.res.maxvif = 0; |
| 611 | memset(cache->mfc_un.res.ttls, 255, MAXMIFS); | 894 | memset(cache->mfc_un.res.ttls, 255, MAXMIFS); |
| 612 | 895 | ||
| 613 | for (vifi = 0; vifi < net->ipv6.maxvif; vifi++) { | 896 | for (vifi = 0; vifi < mrt->maxvif; vifi++) { |
| 614 | if (MIF_EXISTS(net, vifi) && | 897 | if (MIF_EXISTS(mrt, vifi) && |
| 615 | ttls[vifi] && ttls[vifi] < 255) { | 898 | ttls[vifi] && ttls[vifi] < 255) { |
| 616 | cache->mfc_un.res.ttls[vifi] = ttls[vifi]; | 899 | cache->mfc_un.res.ttls[vifi] = ttls[vifi]; |
| 617 | if (cache->mfc_un.res.minvif > vifi) | 900 | if (cache->mfc_un.res.minvif > vifi) |
| @@ -622,16 +905,17 @@ static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttl | |||
| 622 | } | 905 | } |
| 623 | } | 906 | } |
| 624 | 907 | ||
| 625 | static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock) | 908 | static int mif6_add(struct net *net, struct mr6_table *mrt, |
| 909 | struct mif6ctl *vifc, int mrtsock) | ||
| 626 | { | 910 | { |
| 627 | int vifi = vifc->mif6c_mifi; | 911 | int vifi = vifc->mif6c_mifi; |
| 628 | struct mif_device *v = &net->ipv6.vif6_table[vifi]; | 912 | struct mif_device *v = &mrt->vif6_table[vifi]; |
| 629 | struct net_device *dev; | 913 | struct net_device *dev; |
| 630 | struct inet6_dev *in6_dev; | 914 | struct inet6_dev *in6_dev; |
| 631 | int err; | 915 | int err; |
| 632 | 916 | ||
| 633 | /* Is vif busy ? */ | 917 | /* Is vif busy ? */ |
| 634 | if (MIF_EXISTS(net, vifi)) | 918 | if (MIF_EXISTS(mrt, vifi)) |
| 635 | return -EADDRINUSE; | 919 | return -EADDRINUSE; |
| 636 | 920 | ||
| 637 | switch (vifc->mif6c_flags) { | 921 | switch (vifc->mif6c_flags) { |
| @@ -641,9 +925,9 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock) | |||
| 641 | * Special Purpose VIF in PIM | 925 | * Special Purpose VIF in PIM |
| 642 | * All the packets will be sent to the daemon | 926 | * All the packets will be sent to the daemon |
| 643 | */ | 927 | */ |
| 644 | if (net->ipv6.mroute_reg_vif_num >= 0) | 928 | if (mrt->mroute_reg_vif_num >= 0) |
| 645 | return -EADDRINUSE; | 929 | return -EADDRINUSE; |
| 646 | dev = ip6mr_reg_vif(net); | 930 | dev = ip6mr_reg_vif(net, mrt); |
| 647 | if (!dev) | 931 | if (!dev) |
| 648 | return -ENOBUFS; | 932 | return -ENOBUFS; |
| 649 | err = dev_set_allmulti(dev, 1); | 933 | err = dev_set_allmulti(dev, 1); |
| @@ -693,50 +977,48 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock) | |||
| 693 | v->dev = dev; | 977 | v->dev = dev; |
| 694 | #ifdef CONFIG_IPV6_PIMSM_V2 | 978 | #ifdef CONFIG_IPV6_PIMSM_V2 |
| 695 | if (v->flags & MIFF_REGISTER) | 979 | if (v->flags & MIFF_REGISTER) |
| 696 | net->ipv6.mroute_reg_vif_num = vifi; | 980 | mrt->mroute_reg_vif_num = vifi; |
| 697 | #endif | 981 | #endif |
| 698 | if (vifi + 1 > net->ipv6.maxvif) | 982 | if (vifi + 1 > mrt->maxvif) |
| 699 | net->ipv6.maxvif = vifi + 1; | 983 | mrt->maxvif = vifi + 1; |
| 700 | write_unlock_bh(&mrt_lock); | 984 | write_unlock_bh(&mrt_lock); |
| 701 | return 0; | 985 | return 0; |
| 702 | } | 986 | } |
| 703 | 987 | ||
| 704 | static struct mfc6_cache *ip6mr_cache_find(struct net *net, | 988 | static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, |
| 705 | struct in6_addr *origin, | 989 | struct in6_addr *origin, |
| 706 | struct in6_addr *mcastgrp) | 990 | struct in6_addr *mcastgrp) |
| 707 | { | 991 | { |
| 708 | int line = MFC6_HASH(mcastgrp, origin); | 992 | int line = MFC6_HASH(mcastgrp, origin); |
| 709 | struct mfc6_cache *c; | 993 | struct mfc6_cache *c; |
| 710 | 994 | ||
| 711 | for (c = net->ipv6.mfc6_cache_array[line]; c; c = c->next) { | 995 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { |
| 712 | if (ipv6_addr_equal(&c->mf6c_origin, origin) && | 996 | if (ipv6_addr_equal(&c->mf6c_origin, origin) && |
| 713 | ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) | 997 | ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) |
| 714 | break; | 998 | return c; |
| 715 | } | 999 | } |
| 716 | return c; | 1000 | return NULL; |
| 717 | } | 1001 | } |
| 718 | 1002 | ||
| 719 | /* | 1003 | /* |
| 720 | * Allocate a multicast cache entry | 1004 | * Allocate a multicast cache entry |
| 721 | */ | 1005 | */ |
| 722 | static struct mfc6_cache *ip6mr_cache_alloc(struct net *net) | 1006 | static struct mfc6_cache *ip6mr_cache_alloc(void) |
| 723 | { | 1007 | { |
| 724 | struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); | 1008 | struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); |
| 725 | if (c == NULL) | 1009 | if (c == NULL) |
| 726 | return NULL; | 1010 | return NULL; |
| 727 | c->mfc_un.res.minvif = MAXMIFS; | 1011 | c->mfc_un.res.minvif = MAXMIFS; |
| 728 | mfc6_net_set(c, net); | ||
| 729 | return c; | 1012 | return c; |
| 730 | } | 1013 | } |
| 731 | 1014 | ||
| 732 | static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net) | 1015 | static struct mfc6_cache *ip6mr_cache_alloc_unres(void) |
| 733 | { | 1016 | { |
| 734 | struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); | 1017 | struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); |
| 735 | if (c == NULL) | 1018 | if (c == NULL) |
| 736 | return NULL; | 1019 | return NULL; |
| 737 | skb_queue_head_init(&c->mfc_un.unres.unresolved); | 1020 | skb_queue_head_init(&c->mfc_un.unres.unresolved); |
| 738 | c->mfc_un.unres.expires = jiffies + 10 * HZ; | 1021 | c->mfc_un.unres.expires = jiffies + 10 * HZ; |
| 739 | mfc6_net_set(c, net); | ||
| 740 | return c; | 1022 | return c; |
| 741 | } | 1023 | } |
| 742 | 1024 | ||
| @@ -744,7 +1026,8 @@ static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net) | |||
| 744 | * A cache entry has gone into a resolved state from queued | 1026 | * A cache entry has gone into a resolved state from queued |
| 745 | */ | 1027 | */ |
| 746 | 1028 | ||
| 747 | static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) | 1029 | static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, |
| 1030 | struct mfc6_cache *uc, struct mfc6_cache *c) | ||
| 748 | { | 1031 | { |
| 749 | struct sk_buff *skb; | 1032 | struct sk_buff *skb; |
| 750 | 1033 | ||
| @@ -757,7 +1040,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) | |||
| 757 | int err; | 1040 | int err; |
| 758 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); | 1041 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); |
| 759 | 1042 | ||
| 760 | if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { | 1043 | if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { |
| 761 | nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; | 1044 | nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; |
| 762 | } else { | 1045 | } else { |
| 763 | nlh->nlmsg_type = NLMSG_ERROR; | 1046 | nlh->nlmsg_type = NLMSG_ERROR; |
| @@ -765,9 +1048,9 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) | |||
| 765 | skb_trim(skb, nlh->nlmsg_len); | 1048 | skb_trim(skb, nlh->nlmsg_len); |
| 766 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; | 1049 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; |
| 767 | } | 1050 | } |
| 768 | err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid); | 1051 | err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid); |
| 769 | } else | 1052 | } else |
| 770 | ip6_mr_forward(skb, c); | 1053 | ip6_mr_forward(net, mrt, skb, c); |
| 771 | } | 1054 | } |
| 772 | } | 1055 | } |
| 773 | 1056 | ||
| @@ -778,8 +1061,8 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) | |||
| 778 | * Called under mrt_lock. | 1061 | * Called under mrt_lock. |
| 779 | */ | 1062 | */ |
| 780 | 1063 | ||
| 781 | static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, | 1064 | static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, |
| 782 | int assert) | 1065 | mifi_t mifi, int assert) |
| 783 | { | 1066 | { |
| 784 | struct sk_buff *skb; | 1067 | struct sk_buff *skb; |
| 785 | struct mrt6msg *msg; | 1068 | struct mrt6msg *msg; |
| @@ -815,7 +1098,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, | |||
| 815 | msg = (struct mrt6msg *)skb_transport_header(skb); | 1098 | msg = (struct mrt6msg *)skb_transport_header(skb); |
| 816 | msg->im6_mbz = 0; | 1099 | msg->im6_mbz = 0; |
| 817 | msg->im6_msgtype = MRT6MSG_WHOLEPKT; | 1100 | msg->im6_msgtype = MRT6MSG_WHOLEPKT; |
| 818 | msg->im6_mif = net->ipv6.mroute_reg_vif_num; | 1101 | msg->im6_mif = mrt->mroute_reg_vif_num; |
| 819 | msg->im6_pad = 0; | 1102 | msg->im6_pad = 0; |
| 820 | ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); | 1103 | ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); |
| 821 | ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); | 1104 | ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); |
| @@ -850,7 +1133,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, | |||
| 850 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1133 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 851 | } | 1134 | } |
| 852 | 1135 | ||
| 853 | if (net->ipv6.mroute6_sk == NULL) { | 1136 | if (mrt->mroute6_sk == NULL) { |
| 854 | kfree_skb(skb); | 1137 | kfree_skb(skb); |
| 855 | return -EINVAL; | 1138 | return -EINVAL; |
| 856 | } | 1139 | } |
| @@ -858,7 +1141,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, | |||
| 858 | /* | 1141 | /* |
| 859 | * Deliver to user space multicast routing algorithms | 1142 | * Deliver to user space multicast routing algorithms |
| 860 | */ | 1143 | */ |
| 861 | ret = sock_queue_rcv_skb(net->ipv6.mroute6_sk, skb); | 1144 | ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb); |
| 862 | if (ret < 0) { | 1145 | if (ret < 0) { |
| 863 | if (net_ratelimit()) | 1146 | if (net_ratelimit()) |
| 864 | printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n"); | 1147 | printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n"); |
| @@ -873,26 +1156,28 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, | |||
| 873 | */ | 1156 | */ |
| 874 | 1157 | ||
| 875 | static int | 1158 | static int |
| 876 | ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb) | 1159 | ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb) |
| 877 | { | 1160 | { |
| 1161 | bool found = false; | ||
| 878 | int err; | 1162 | int err; |
| 879 | struct mfc6_cache *c; | 1163 | struct mfc6_cache *c; |
| 880 | 1164 | ||
| 881 | spin_lock_bh(&mfc_unres_lock); | 1165 | spin_lock_bh(&mfc_unres_lock); |
| 882 | for (c = mfc_unres_queue; c; c = c->next) { | 1166 | list_for_each_entry(c, &mrt->mfc6_unres_queue, list) { |
| 883 | if (net_eq(mfc6_net(c), net) && | 1167 | if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && |
| 884 | ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && | 1168 | ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) { |
| 885 | ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) | 1169 | found = true; |
| 886 | break; | 1170 | break; |
| 1171 | } | ||
| 887 | } | 1172 | } |
| 888 | 1173 | ||
| 889 | if (c == NULL) { | 1174 | if (!found) { |
| 890 | /* | 1175 | /* |
| 891 | * Create a new entry if allowable | 1176 | * Create a new entry if allowable |
| 892 | */ | 1177 | */ |
| 893 | 1178 | ||
| 894 | if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 || | 1179 | if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 || |
| 895 | (c = ip6mr_cache_alloc_unres(net)) == NULL) { | 1180 | (c = ip6mr_cache_alloc_unres()) == NULL) { |
| 896 | spin_unlock_bh(&mfc_unres_lock); | 1181 | spin_unlock_bh(&mfc_unres_lock); |
| 897 | 1182 | ||
| 898 | kfree_skb(skb); | 1183 | kfree_skb(skb); |
| @@ -909,7 +1194,7 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb) | |||
| 909 | /* | 1194 | /* |
| 910 | * Reflect first query at pim6sd | 1195 | * Reflect first query at pim6sd |
| 911 | */ | 1196 | */ |
| 912 | err = ip6mr_cache_report(net, skb, mifi, MRT6MSG_NOCACHE); | 1197 | err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE); |
| 913 | if (err < 0) { | 1198 | if (err < 0) { |
| 914 | /* If the report failed throw the cache entry | 1199 | /* If the report failed throw the cache entry |
| 915 | out - Brad Parker | 1200 | out - Brad Parker |
| @@ -921,11 +1206,10 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb) | |||
| 921 | return err; | 1206 | return err; |
| 922 | } | 1207 | } |
| 923 | 1208 | ||
| 924 | atomic_inc(&net->ipv6.cache_resolve_queue_len); | 1209 | atomic_inc(&mrt->cache_resolve_queue_len); |
| 925 | c->next = mfc_unres_queue; | 1210 | list_add(&c->list, &mrt->mfc6_unres_queue); |
| 926 | mfc_unres_queue = c; | ||
| 927 | 1211 | ||
| 928 | ipmr_do_expire_process(1); | 1212 | ipmr_do_expire_process(mrt); |
| 929 | } | 1213 | } |
| 930 | 1214 | ||
| 931 | /* | 1215 | /* |
| @@ -947,19 +1231,18 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb) | |||
| 947 | * MFC6 cache manipulation by user space | 1231 | * MFC6 cache manipulation by user space |
| 948 | */ | 1232 | */ |
| 949 | 1233 | ||
| 950 | static int ip6mr_mfc_delete(struct net *net, struct mf6cctl *mfc) | 1234 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) |
| 951 | { | 1235 | { |
| 952 | int line; | 1236 | int line; |
| 953 | struct mfc6_cache *c, **cp; | 1237 | struct mfc6_cache *c, *next; |
| 954 | 1238 | ||
| 955 | line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); | 1239 | line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); |
| 956 | 1240 | ||
| 957 | for (cp = &net->ipv6.mfc6_cache_array[line]; | 1241 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { |
| 958 | (c = *cp) != NULL; cp = &c->next) { | ||
| 959 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1242 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
| 960 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { | 1243 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { |
| 961 | write_lock_bh(&mrt_lock); | 1244 | write_lock_bh(&mrt_lock); |
| 962 | *cp = c->next; | 1245 | list_del(&c->list); |
| 963 | write_unlock_bh(&mrt_lock); | 1246 | write_unlock_bh(&mrt_lock); |
| 964 | 1247 | ||
| 965 | ip6mr_cache_free(c); | 1248 | ip6mr_cache_free(c); |
| @@ -974,6 +1257,7 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
| 974 | { | 1257 | { |
| 975 | struct net_device *dev = ptr; | 1258 | struct net_device *dev = ptr; |
| 976 | struct net *net = dev_net(dev); | 1259 | struct net *net = dev_net(dev); |
| 1260 | struct mr6_table *mrt; | ||
| 977 | struct mif_device *v; | 1261 | struct mif_device *v; |
| 978 | int ct; | 1262 | int ct; |
| 979 | LIST_HEAD(list); | 1263 | LIST_HEAD(list); |
| @@ -981,10 +1265,12 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
| 981 | if (event != NETDEV_UNREGISTER) | 1265 | if (event != NETDEV_UNREGISTER) |
| 982 | return NOTIFY_DONE; | 1266 | return NOTIFY_DONE; |
| 983 | 1267 | ||
| 984 | v = &net->ipv6.vif6_table[0]; | 1268 | ip6mr_for_each_table(mrt, net) { |
| 985 | for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { | 1269 | v = &mrt->vif6_table[0]; |
| 986 | if (v->dev == dev) | 1270 | for (ct = 0; ct < mrt->maxvif; ct++, v++) { |
| 987 | mif6_delete(net, ct, &list); | 1271 | if (v->dev == dev) |
| 1272 | mif6_delete(mrt, ct, &list); | ||
| 1273 | } | ||
| 988 | } | 1274 | } |
| 989 | unregister_netdevice_many(&list); | 1275 | unregister_netdevice_many(&list); |
| 990 | 1276 | ||
| @@ -1001,26 +1287,11 @@ static struct notifier_block ip6_mr_notifier = { | |||
| 1001 | 1287 | ||
| 1002 | static int __net_init ip6mr_net_init(struct net *net) | 1288 | static int __net_init ip6mr_net_init(struct net *net) |
| 1003 | { | 1289 | { |
| 1004 | int err = 0; | 1290 | int err; |
| 1005 | net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device), | ||
| 1006 | GFP_KERNEL); | ||
| 1007 | if (!net->ipv6.vif6_table) { | ||
| 1008 | err = -ENOMEM; | ||
| 1009 | goto fail; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | /* Forwarding cache */ | ||
| 1013 | net->ipv6.mfc6_cache_array = kcalloc(MFC6_LINES, | ||
| 1014 | sizeof(struct mfc6_cache *), | ||
| 1015 | GFP_KERNEL); | ||
| 1016 | if (!net->ipv6.mfc6_cache_array) { | ||
| 1017 | err = -ENOMEM; | ||
| 1018 | goto fail_mfc6_cache; | ||
| 1019 | } | ||
| 1020 | 1291 | ||
| 1021 | #ifdef CONFIG_IPV6_PIMSM_V2 | 1292 | err = ip6mr_rules_init(net); |
| 1022 | net->ipv6.mroute_reg_vif_num = -1; | 1293 | if (err < 0) |
| 1023 | #endif | 1294 | goto fail; |
| 1024 | 1295 | ||
| 1025 | #ifdef CONFIG_PROC_FS | 1296 | #ifdef CONFIG_PROC_FS |
| 1026 | err = -ENOMEM; | 1297 | err = -ENOMEM; |
| @@ -1029,16 +1300,15 @@ static int __net_init ip6mr_net_init(struct net *net) | |||
| 1029 | if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops)) | 1300 | if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops)) |
| 1030 | goto proc_cache_fail; | 1301 | goto proc_cache_fail; |
| 1031 | #endif | 1302 | #endif |
| 1303 | |||
| 1032 | return 0; | 1304 | return 0; |
| 1033 | 1305 | ||
| 1034 | #ifdef CONFIG_PROC_FS | 1306 | #ifdef CONFIG_PROC_FS |
| 1035 | proc_cache_fail: | 1307 | proc_cache_fail: |
| 1036 | proc_net_remove(net, "ip6_mr_vif"); | 1308 | proc_net_remove(net, "ip6_mr_vif"); |
| 1037 | proc_vif_fail: | 1309 | proc_vif_fail: |
| 1038 | kfree(net->ipv6.mfc6_cache_array); | 1310 | ip6mr_rules_exit(net); |
| 1039 | #endif | 1311 | #endif |
| 1040 | fail_mfc6_cache: | ||
| 1041 | kfree(net->ipv6.vif6_table); | ||
| 1042 | fail: | 1312 | fail: |
| 1043 | return err; | 1313 | return err; |
| 1044 | } | 1314 | } |
| @@ -1049,9 +1319,7 @@ static void __net_exit ip6mr_net_exit(struct net *net) | |||
| 1049 | proc_net_remove(net, "ip6_mr_cache"); | 1319 | proc_net_remove(net, "ip6_mr_cache"); |
| 1050 | proc_net_remove(net, "ip6_mr_vif"); | 1320 | proc_net_remove(net, "ip6_mr_vif"); |
| 1051 | #endif | 1321 | #endif |
| 1052 | mroute_clean_tables(net); | 1322 | ip6mr_rules_exit(net); |
| 1053 | kfree(net->ipv6.mfc6_cache_array); | ||
| 1054 | kfree(net->ipv6.vif6_table); | ||
| 1055 | } | 1323 | } |
| 1056 | 1324 | ||
| 1057 | static struct pernet_operations ip6mr_net_ops = { | 1325 | static struct pernet_operations ip6mr_net_ops = { |
| @@ -1074,7 +1342,6 @@ int __init ip6_mr_init(void) | |||
| 1074 | if (err) | 1342 | if (err) |
| 1075 | goto reg_pernet_fail; | 1343 | goto reg_pernet_fail; |
| 1076 | 1344 | ||
| 1077 | setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); | ||
| 1078 | err = register_netdevice_notifier(&ip6_mr_notifier); | 1345 | err = register_netdevice_notifier(&ip6_mr_notifier); |
| 1079 | if (err) | 1346 | if (err) |
| 1080 | goto reg_notif_fail; | 1347 | goto reg_notif_fail; |
| @@ -1085,13 +1352,13 @@ int __init ip6_mr_init(void) | |||
| 1085 | goto add_proto_fail; | 1352 | goto add_proto_fail; |
| 1086 | } | 1353 | } |
| 1087 | #endif | 1354 | #endif |
| 1355 | rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute); | ||
| 1088 | return 0; | 1356 | return 0; |
| 1089 | #ifdef CONFIG_IPV6_PIMSM_V2 | 1357 | #ifdef CONFIG_IPV6_PIMSM_V2 |
| 1090 | add_proto_fail: | 1358 | add_proto_fail: |
| 1091 | unregister_netdevice_notifier(&ip6_mr_notifier); | 1359 | unregister_netdevice_notifier(&ip6_mr_notifier); |
| 1092 | #endif | 1360 | #endif |
| 1093 | reg_notif_fail: | 1361 | reg_notif_fail: |
| 1094 | del_timer(&ipmr_expire_timer); | ||
| 1095 | unregister_pernet_subsys(&ip6mr_net_ops); | 1362 | unregister_pernet_subsys(&ip6mr_net_ops); |
| 1096 | reg_pernet_fail: | 1363 | reg_pernet_fail: |
| 1097 | kmem_cache_destroy(mrt_cachep); | 1364 | kmem_cache_destroy(mrt_cachep); |
| @@ -1101,18 +1368,22 @@ reg_pernet_fail: | |||
| 1101 | void ip6_mr_cleanup(void) | 1368 | void ip6_mr_cleanup(void) |
| 1102 | { | 1369 | { |
| 1103 | unregister_netdevice_notifier(&ip6_mr_notifier); | 1370 | unregister_netdevice_notifier(&ip6_mr_notifier); |
| 1104 | del_timer(&ipmr_expire_timer); | ||
| 1105 | unregister_pernet_subsys(&ip6mr_net_ops); | 1371 | unregister_pernet_subsys(&ip6mr_net_ops); |
| 1106 | kmem_cache_destroy(mrt_cachep); | 1372 | kmem_cache_destroy(mrt_cachep); |
| 1107 | } | 1373 | } |
| 1108 | 1374 | ||
| 1109 | static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | 1375 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, |
| 1376 | struct mf6cctl *mfc, int mrtsock) | ||
| 1110 | { | 1377 | { |
| 1378 | bool found = false; | ||
| 1111 | int line; | 1379 | int line; |
| 1112 | struct mfc6_cache *uc, *c, **cp; | 1380 | struct mfc6_cache *uc, *c; |
| 1113 | unsigned char ttls[MAXMIFS]; | 1381 | unsigned char ttls[MAXMIFS]; |
| 1114 | int i; | 1382 | int i; |
| 1115 | 1383 | ||
| 1384 | if (mfc->mf6cc_parent >= MAXMIFS) | ||
| 1385 | return -ENFILE; | ||
| 1386 | |||
| 1116 | memset(ttls, 255, MAXMIFS); | 1387 | memset(ttls, 255, MAXMIFS); |
| 1117 | for (i = 0; i < MAXMIFS; i++) { | 1388 | for (i = 0; i < MAXMIFS; i++) { |
| 1118 | if (IF_ISSET(i, &mfc->mf6cc_ifset)) | 1389 | if (IF_ISSET(i, &mfc->mf6cc_ifset)) |
| @@ -1122,17 +1393,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
| 1122 | 1393 | ||
| 1123 | line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); | 1394 | line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); |
| 1124 | 1395 | ||
| 1125 | for (cp = &net->ipv6.mfc6_cache_array[line]; | 1396 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { |
| 1126 | (c = *cp) != NULL; cp = &c->next) { | ||
| 1127 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1397 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
| 1128 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) | 1398 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { |
| 1399 | found = true; | ||
| 1129 | break; | 1400 | break; |
| 1401 | } | ||
| 1130 | } | 1402 | } |
| 1131 | 1403 | ||
| 1132 | if (c != NULL) { | 1404 | if (found) { |
| 1133 | write_lock_bh(&mrt_lock); | 1405 | write_lock_bh(&mrt_lock); |
| 1134 | c->mf6c_parent = mfc->mf6cc_parent; | 1406 | c->mf6c_parent = mfc->mf6cc_parent; |
| 1135 | ip6mr_update_thresholds(c, ttls); | 1407 | ip6mr_update_thresholds(mrt, c, ttls); |
| 1136 | if (!mrtsock) | 1408 | if (!mrtsock) |
| 1137 | c->mfc_flags |= MFC_STATIC; | 1409 | c->mfc_flags |= MFC_STATIC; |
| 1138 | write_unlock_bh(&mrt_lock); | 1410 | write_unlock_bh(&mrt_lock); |
| @@ -1142,43 +1414,42 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
| 1142 | if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) | 1414 | if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) |
| 1143 | return -EINVAL; | 1415 | return -EINVAL; |
| 1144 | 1416 | ||
| 1145 | c = ip6mr_cache_alloc(net); | 1417 | c = ip6mr_cache_alloc(); |
| 1146 | if (c == NULL) | 1418 | if (c == NULL) |
| 1147 | return -ENOMEM; | 1419 | return -ENOMEM; |
| 1148 | 1420 | ||
| 1149 | c->mf6c_origin = mfc->mf6cc_origin.sin6_addr; | 1421 | c->mf6c_origin = mfc->mf6cc_origin.sin6_addr; |
| 1150 | c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr; | 1422 | c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr; |
| 1151 | c->mf6c_parent = mfc->mf6cc_parent; | 1423 | c->mf6c_parent = mfc->mf6cc_parent; |
| 1152 | ip6mr_update_thresholds(c, ttls); | 1424 | ip6mr_update_thresholds(mrt, c, ttls); |
| 1153 | if (!mrtsock) | 1425 | if (!mrtsock) |
| 1154 | c->mfc_flags |= MFC_STATIC; | 1426 | c->mfc_flags |= MFC_STATIC; |
| 1155 | 1427 | ||
| 1156 | write_lock_bh(&mrt_lock); | 1428 | write_lock_bh(&mrt_lock); |
| 1157 | c->next = net->ipv6.mfc6_cache_array[line]; | 1429 | list_add(&c->list, &mrt->mfc6_cache_array[line]); |
| 1158 | net->ipv6.mfc6_cache_array[line] = c; | ||
| 1159 | write_unlock_bh(&mrt_lock); | 1430 | write_unlock_bh(&mrt_lock); |
| 1160 | 1431 | ||
| 1161 | /* | 1432 | /* |
| 1162 | * Check to see if we resolved a queued list. If so we | 1433 | * Check to see if we resolved a queued list. If so we |
| 1163 | * need to send on the frames and tidy up. | 1434 | * need to send on the frames and tidy up. |
| 1164 | */ | 1435 | */ |
| 1436 | found = false; | ||
| 1165 | spin_lock_bh(&mfc_unres_lock); | 1437 | spin_lock_bh(&mfc_unres_lock); |
| 1166 | for (cp = &mfc_unres_queue; (uc = *cp) != NULL; | 1438 | list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) { |
| 1167 | cp = &uc->next) { | 1439 | if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && |
| 1168 | if (net_eq(mfc6_net(uc), net) && | ||
| 1169 | ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && | ||
| 1170 | ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { | 1440 | ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { |
| 1171 | *cp = uc->next; | 1441 | list_del(&uc->list); |
| 1172 | atomic_dec(&net->ipv6.cache_resolve_queue_len); | 1442 | atomic_dec(&mrt->cache_resolve_queue_len); |
| 1443 | found = true; | ||
| 1173 | break; | 1444 | break; |
| 1174 | } | 1445 | } |
| 1175 | } | 1446 | } |
| 1176 | if (mfc_unres_queue == NULL) | 1447 | if (list_empty(&mrt->mfc6_unres_queue)) |
| 1177 | del_timer(&ipmr_expire_timer); | 1448 | del_timer(&mrt->ipmr_expire_timer); |
| 1178 | spin_unlock_bh(&mfc_unres_lock); | 1449 | spin_unlock_bh(&mfc_unres_lock); |
| 1179 | 1450 | ||
| 1180 | if (uc) { | 1451 | if (found) { |
| 1181 | ip6mr_cache_resolve(uc, c); | 1452 | ip6mr_cache_resolve(net, mrt, uc, c); |
| 1182 | ip6mr_cache_free(uc); | 1453 | ip6mr_cache_free(uc); |
| 1183 | } | 1454 | } |
| 1184 | return 0; | 1455 | return 0; |
| @@ -1188,17 +1459,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
| 1188 | * Close the multicast socket, and clear the vif tables etc | 1459 | * Close the multicast socket, and clear the vif tables etc |
| 1189 | */ | 1460 | */ |
| 1190 | 1461 | ||
| 1191 | static void mroute_clean_tables(struct net *net) | 1462 | static void mroute_clean_tables(struct mr6_table *mrt) |
| 1192 | { | 1463 | { |
| 1193 | int i; | 1464 | int i; |
| 1194 | LIST_HEAD(list); | 1465 | LIST_HEAD(list); |
| 1466 | struct mfc6_cache *c, *next; | ||
| 1195 | 1467 | ||
| 1196 | /* | 1468 | /* |
| 1197 | * Shut down all active vif entries | 1469 | * Shut down all active vif entries |
| 1198 | */ | 1470 | */ |
| 1199 | for (i = 0; i < net->ipv6.maxvif; i++) { | 1471 | for (i = 0; i < mrt->maxvif; i++) { |
| 1200 | if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) | 1472 | if (!(mrt->vif6_table[i].flags & VIFF_STATIC)) |
| 1201 | mif6_delete(net, i, &list); | 1473 | mif6_delete(mrt, i, &list); |
| 1202 | } | 1474 | } |
| 1203 | unregister_netdevice_many(&list); | 1475 | unregister_netdevice_many(&list); |
| 1204 | 1476 | ||
| @@ -1206,48 +1478,36 @@ static void mroute_clean_tables(struct net *net) | |||
| 1206 | * Wipe the cache | 1478 | * Wipe the cache |
| 1207 | */ | 1479 | */ |
| 1208 | for (i = 0; i < MFC6_LINES; i++) { | 1480 | for (i = 0; i < MFC6_LINES; i++) { |
| 1209 | struct mfc6_cache *c, **cp; | 1481 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) { |
| 1210 | 1482 | if (c->mfc_flags & MFC_STATIC) | |
| 1211 | cp = &net->ipv6.mfc6_cache_array[i]; | ||
| 1212 | while ((c = *cp) != NULL) { | ||
| 1213 | if (c->mfc_flags & MFC_STATIC) { | ||
| 1214 | cp = &c->next; | ||
| 1215 | continue; | 1483 | continue; |
| 1216 | } | ||
| 1217 | write_lock_bh(&mrt_lock); | 1484 | write_lock_bh(&mrt_lock); |
| 1218 | *cp = c->next; | 1485 | list_del(&c->list); |
| 1219 | write_unlock_bh(&mrt_lock); | 1486 | write_unlock_bh(&mrt_lock); |
| 1220 | 1487 | ||
| 1221 | ip6mr_cache_free(c); | 1488 | ip6mr_cache_free(c); |
| 1222 | } | 1489 | } |
| 1223 | } | 1490 | } |
| 1224 | 1491 | ||
| 1225 | if (atomic_read(&net->ipv6.cache_resolve_queue_len) != 0) { | 1492 | if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { |
| 1226 | struct mfc6_cache *c, **cp; | ||
| 1227 | |||
| 1228 | spin_lock_bh(&mfc_unres_lock); | 1493 | spin_lock_bh(&mfc_unres_lock); |
| 1229 | cp = &mfc_unres_queue; | 1494 | list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) { |
| 1230 | while ((c = *cp) != NULL) { | 1495 | list_del(&c->list); |
| 1231 | if (!net_eq(mfc6_net(c), net)) { | 1496 | ip6mr_destroy_unres(mrt, c); |
| 1232 | cp = &c->next; | ||
| 1233 | continue; | ||
| 1234 | } | ||
| 1235 | *cp = c->next; | ||
| 1236 | ip6mr_destroy_unres(c); | ||
| 1237 | } | 1497 | } |
| 1238 | spin_unlock_bh(&mfc_unres_lock); | 1498 | spin_unlock_bh(&mfc_unres_lock); |
| 1239 | } | 1499 | } |
| 1240 | } | 1500 | } |
| 1241 | 1501 | ||
| 1242 | static int ip6mr_sk_init(struct sock *sk) | 1502 | static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk) |
| 1243 | { | 1503 | { |
| 1244 | int err = 0; | 1504 | int err = 0; |
| 1245 | struct net *net = sock_net(sk); | 1505 | struct net *net = sock_net(sk); |
| 1246 | 1506 | ||
| 1247 | rtnl_lock(); | 1507 | rtnl_lock(); |
| 1248 | write_lock_bh(&mrt_lock); | 1508 | write_lock_bh(&mrt_lock); |
| 1249 | if (likely(net->ipv6.mroute6_sk == NULL)) { | 1509 | if (likely(mrt->mroute6_sk == NULL)) { |
| 1250 | net->ipv6.mroute6_sk = sk; | 1510 | mrt->mroute6_sk = sk; |
| 1251 | net->ipv6.devconf_all->mc_forwarding++; | 1511 | net->ipv6.devconf_all->mc_forwarding++; |
| 1252 | } | 1512 | } |
| 1253 | else | 1513 | else |
| @@ -1261,24 +1521,43 @@ static int ip6mr_sk_init(struct sock *sk) | |||
| 1261 | 1521 | ||
| 1262 | int ip6mr_sk_done(struct sock *sk) | 1522 | int ip6mr_sk_done(struct sock *sk) |
| 1263 | { | 1523 | { |
| 1264 | int err = 0; | 1524 | int err = -EACCES; |
| 1265 | struct net *net = sock_net(sk); | 1525 | struct net *net = sock_net(sk); |
| 1526 | struct mr6_table *mrt; | ||
| 1266 | 1527 | ||
| 1267 | rtnl_lock(); | 1528 | rtnl_lock(); |
| 1268 | if (sk == net->ipv6.mroute6_sk) { | 1529 | ip6mr_for_each_table(mrt, net) { |
| 1269 | write_lock_bh(&mrt_lock); | 1530 | if (sk == mrt->mroute6_sk) { |
| 1270 | net->ipv6.mroute6_sk = NULL; | 1531 | write_lock_bh(&mrt_lock); |
| 1271 | net->ipv6.devconf_all->mc_forwarding--; | 1532 | mrt->mroute6_sk = NULL; |
| 1272 | write_unlock_bh(&mrt_lock); | 1533 | net->ipv6.devconf_all->mc_forwarding--; |
| 1534 | write_unlock_bh(&mrt_lock); | ||
| 1273 | 1535 | ||
| 1274 | mroute_clean_tables(net); | 1536 | mroute_clean_tables(mrt); |
| 1275 | } else | 1537 | err = 0; |
| 1276 | err = -EACCES; | 1538 | break; |
| 1539 | } | ||
| 1540 | } | ||
| 1277 | rtnl_unlock(); | 1541 | rtnl_unlock(); |
| 1278 | 1542 | ||
| 1279 | return err; | 1543 | return err; |
| 1280 | } | 1544 | } |
| 1281 | 1545 | ||
| 1546 | struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) | ||
| 1547 | { | ||
| 1548 | struct mr6_table *mrt; | ||
| 1549 | struct flowi fl = { | ||
| 1550 | .iif = skb->skb_iif, | ||
| 1551 | .oif = skb->dev->ifindex, | ||
| 1552 | .mark = skb->mark, | ||
| 1553 | }; | ||
| 1554 | |||
| 1555 | if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) | ||
| 1556 | return NULL; | ||
| 1557 | |||
| 1558 | return mrt->mroute6_sk; | ||
| 1559 | } | ||
| 1560 | |||
| 1282 | /* | 1561 | /* |
| 1283 | * Socket options and virtual interface manipulation. The whole | 1562 | * Socket options and virtual interface manipulation. The whole |
| 1284 | * virtual interface system is a complete heap, but unfortunately | 1563 | * virtual interface system is a complete heap, but unfortunately |
| @@ -1293,9 +1572,14 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1293 | struct mf6cctl mfc; | 1572 | struct mf6cctl mfc; |
| 1294 | mifi_t mifi; | 1573 | mifi_t mifi; |
| 1295 | struct net *net = sock_net(sk); | 1574 | struct net *net = sock_net(sk); |
| 1575 | struct mr6_table *mrt; | ||
| 1576 | |||
| 1577 | mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); | ||
| 1578 | if (mrt == NULL) | ||
| 1579 | return -ENOENT; | ||
| 1296 | 1580 | ||
| 1297 | if (optname != MRT6_INIT) { | 1581 | if (optname != MRT6_INIT) { |
| 1298 | if (sk != net->ipv6.mroute6_sk && !capable(CAP_NET_ADMIN)) | 1582 | if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN)) |
| 1299 | return -EACCES; | 1583 | return -EACCES; |
| 1300 | } | 1584 | } |
| 1301 | 1585 | ||
| @@ -1307,7 +1591,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1307 | if (optlen < sizeof(int)) | 1591 | if (optlen < sizeof(int)) |
| 1308 | return -EINVAL; | 1592 | return -EINVAL; |
| 1309 | 1593 | ||
| 1310 | return ip6mr_sk_init(sk); | 1594 | return ip6mr_sk_init(mrt, sk); |
| 1311 | 1595 | ||
| 1312 | case MRT6_DONE: | 1596 | case MRT6_DONE: |
| 1313 | return ip6mr_sk_done(sk); | 1597 | return ip6mr_sk_done(sk); |
| @@ -1320,7 +1604,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1320 | if (vif.mif6c_mifi >= MAXMIFS) | 1604 | if (vif.mif6c_mifi >= MAXMIFS) |
| 1321 | return -ENFILE; | 1605 | return -ENFILE; |
| 1322 | rtnl_lock(); | 1606 | rtnl_lock(); |
| 1323 | ret = mif6_add(net, &vif, sk == net->ipv6.mroute6_sk); | 1607 | ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk); |
| 1324 | rtnl_unlock(); | 1608 | rtnl_unlock(); |
| 1325 | return ret; | 1609 | return ret; |
| 1326 | 1610 | ||
| @@ -1330,7 +1614,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1330 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) | 1614 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) |
| 1331 | return -EFAULT; | 1615 | return -EFAULT; |
| 1332 | rtnl_lock(); | 1616 | rtnl_lock(); |
| 1333 | ret = mif6_delete(net, mifi, NULL); | 1617 | ret = mif6_delete(mrt, mifi, NULL); |
| 1334 | rtnl_unlock(); | 1618 | rtnl_unlock(); |
| 1335 | return ret; | 1619 | return ret; |
| 1336 | 1620 | ||
| @@ -1346,10 +1630,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1346 | return -EFAULT; | 1630 | return -EFAULT; |
| 1347 | rtnl_lock(); | 1631 | rtnl_lock(); |
| 1348 | if (optname == MRT6_DEL_MFC) | 1632 | if (optname == MRT6_DEL_MFC) |
| 1349 | ret = ip6mr_mfc_delete(net, &mfc); | 1633 | ret = ip6mr_mfc_delete(mrt, &mfc); |
| 1350 | else | 1634 | else |
| 1351 | ret = ip6mr_mfc_add(net, &mfc, | 1635 | ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk); |
| 1352 | sk == net->ipv6.mroute6_sk); | ||
| 1353 | rtnl_unlock(); | 1636 | rtnl_unlock(); |
| 1354 | return ret; | 1637 | return ret; |
| 1355 | 1638 | ||
| @@ -1361,7 +1644,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1361 | int v; | 1644 | int v; |
| 1362 | if (get_user(v, (int __user *)optval)) | 1645 | if (get_user(v, (int __user *)optval)) |
| 1363 | return -EFAULT; | 1646 | return -EFAULT; |
| 1364 | net->ipv6.mroute_do_assert = !!v; | 1647 | mrt->mroute_do_assert = !!v; |
| 1365 | return 0; | 1648 | return 0; |
| 1366 | } | 1649 | } |
| 1367 | 1650 | ||
| @@ -1374,15 +1657,36 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
| 1374 | v = !!v; | 1657 | v = !!v; |
| 1375 | rtnl_lock(); | 1658 | rtnl_lock(); |
| 1376 | ret = 0; | 1659 | ret = 0; |
| 1377 | if (v != net->ipv6.mroute_do_pim) { | 1660 | if (v != mrt->mroute_do_pim) { |
| 1378 | net->ipv6.mroute_do_pim = v; | 1661 | mrt->mroute_do_pim = v; |
| 1379 | net->ipv6.mroute_do_assert = v; | 1662 | mrt->mroute_do_assert = v; |
| 1380 | } | 1663 | } |
| 1381 | rtnl_unlock(); | 1664 | rtnl_unlock(); |
| 1382 | return ret; | 1665 | return ret; |
| 1383 | } | 1666 | } |
| 1384 | 1667 | ||
| 1385 | #endif | 1668 | #endif |
| 1669 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES | ||
| 1670 | case MRT6_TABLE: | ||
| 1671 | { | ||
| 1672 | u32 v; | ||
| 1673 | |||
| 1674 | if (optlen != sizeof(u32)) | ||
| 1675 | return -EINVAL; | ||
| 1676 | if (get_user(v, (u32 __user *)optval)) | ||
| 1677 | return -EFAULT; | ||
| 1678 | if (sk == mrt->mroute6_sk) | ||
| 1679 | return -EBUSY; | ||
| 1680 | |||
| 1681 | rtnl_lock(); | ||
| 1682 | ret = 0; | ||
| 1683 | if (!ip6mr_new_table(net, v)) | ||
| 1684 | ret = -ENOMEM; | ||
| 1685 | raw6_sk(sk)->ip6mr_table = v; | ||
| 1686 | rtnl_unlock(); | ||
| 1687 | return ret; | ||
| 1688 | } | ||
| 1689 | #endif | ||
| 1386 | /* | 1690 | /* |
| 1387 | * Spurious command, or MRT6_VERSION which you cannot | 1691 | * Spurious command, or MRT6_VERSION which you cannot |
| 1388 | * set. | 1692 | * set. |
| @@ -1402,6 +1706,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, | |||
| 1402 | int olr; | 1706 | int olr; |
| 1403 | int val; | 1707 | int val; |
| 1404 | struct net *net = sock_net(sk); | 1708 | struct net *net = sock_net(sk); |
| 1709 | struct mr6_table *mrt; | ||
| 1710 | |||
| 1711 | mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); | ||
| 1712 | if (mrt == NULL) | ||
| 1713 | return -ENOENT; | ||
| 1405 | 1714 | ||
| 1406 | switch (optname) { | 1715 | switch (optname) { |
| 1407 | case MRT6_VERSION: | 1716 | case MRT6_VERSION: |
| @@ -1409,11 +1718,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, | |||
| 1409 | break; | 1718 | break; |
| 1410 | #ifdef CONFIG_IPV6_PIMSM_V2 | 1719 | #ifdef CONFIG_IPV6_PIMSM_V2 |
| 1411 | case MRT6_PIM: | 1720 | case MRT6_PIM: |
| 1412 | val = net->ipv6.mroute_do_pim; | 1721 | val = mrt->mroute_do_pim; |
| 1413 | break; | 1722 | break; |
| 1414 | #endif | 1723 | #endif |
| 1415 | case MRT6_ASSERT: | 1724 | case MRT6_ASSERT: |
| 1416 | val = net->ipv6.mroute_do_assert; | 1725 | val = mrt->mroute_do_assert; |
| 1417 | break; | 1726 | break; |
| 1418 | default: | 1727 | default: |
| 1419 | return -ENOPROTOOPT; | 1728 | return -ENOPROTOOPT; |
| @@ -1444,16 +1753,21 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
| 1444 | struct mif_device *vif; | 1753 | struct mif_device *vif; |
| 1445 | struct mfc6_cache *c; | 1754 | struct mfc6_cache *c; |
| 1446 | struct net *net = sock_net(sk); | 1755 | struct net *net = sock_net(sk); |
| 1756 | struct mr6_table *mrt; | ||
| 1757 | |||
| 1758 | mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); | ||
| 1759 | if (mrt == NULL) | ||
| 1760 | return -ENOENT; | ||
| 1447 | 1761 | ||
| 1448 | switch (cmd) { | 1762 | switch (cmd) { |
| 1449 | case SIOCGETMIFCNT_IN6: | 1763 | case SIOCGETMIFCNT_IN6: |
| 1450 | if (copy_from_user(&vr, arg, sizeof(vr))) | 1764 | if (copy_from_user(&vr, arg, sizeof(vr))) |
| 1451 | return -EFAULT; | 1765 | return -EFAULT; |
| 1452 | if (vr.mifi >= net->ipv6.maxvif) | 1766 | if (vr.mifi >= mrt->maxvif) |
| 1453 | return -EINVAL; | 1767 | return -EINVAL; |
| 1454 | read_lock(&mrt_lock); | 1768 | read_lock(&mrt_lock); |
| 1455 | vif = &net->ipv6.vif6_table[vr.mifi]; | 1769 | vif = &mrt->vif6_table[vr.mifi]; |
| 1456 | if (MIF_EXISTS(net, vr.mifi)) { | 1770 | if (MIF_EXISTS(mrt, vr.mifi)) { |
| 1457 | vr.icount = vif->pkt_in; | 1771 | vr.icount = vif->pkt_in; |
| 1458 | vr.ocount = vif->pkt_out; | 1772 | vr.ocount = vif->pkt_out; |
| 1459 | vr.ibytes = vif->bytes_in; | 1773 | vr.ibytes = vif->bytes_in; |
| @@ -1471,7 +1785,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
| 1471 | return -EFAULT; | 1785 | return -EFAULT; |
| 1472 | 1786 | ||
| 1473 | read_lock(&mrt_lock); | 1787 | read_lock(&mrt_lock); |
| 1474 | c = ip6mr_cache_find(net, &sr.src.sin6_addr, &sr.grp.sin6_addr); | 1788 | c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); |
| 1475 | if (c) { | 1789 | if (c) { |
| 1476 | sr.pktcnt = c->mfc_un.res.pkt; | 1790 | sr.pktcnt = c->mfc_un.res.pkt; |
| 1477 | sr.bytecnt = c->mfc_un.res.bytes; | 1791 | sr.bytecnt = c->mfc_un.res.bytes; |
| @@ -1501,11 +1815,11 @@ static inline int ip6mr_forward2_finish(struct sk_buff *skb) | |||
| 1501 | * Processing handlers for ip6mr_forward | 1815 | * Processing handlers for ip6mr_forward |
| 1502 | */ | 1816 | */ |
| 1503 | 1817 | ||
| 1504 | static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) | 1818 | static int ip6mr_forward2(struct net *net, struct mr6_table *mrt, |
| 1819 | struct sk_buff *skb, struct mfc6_cache *c, int vifi) | ||
| 1505 | { | 1820 | { |
| 1506 | struct ipv6hdr *ipv6h; | 1821 | struct ipv6hdr *ipv6h; |
| 1507 | struct net *net = mfc6_net(c); | 1822 | struct mif_device *vif = &mrt->vif6_table[vifi]; |
| 1508 | struct mif_device *vif = &net->ipv6.vif6_table[vifi]; | ||
| 1509 | struct net_device *dev; | 1823 | struct net_device *dev; |
| 1510 | struct dst_entry *dst; | 1824 | struct dst_entry *dst; |
| 1511 | struct flowi fl; | 1825 | struct flowi fl; |
| @@ -1519,7 +1833,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) | |||
| 1519 | vif->bytes_out += skb->len; | 1833 | vif->bytes_out += skb->len; |
| 1520 | vif->dev->stats.tx_bytes += skb->len; | 1834 | vif->dev->stats.tx_bytes += skb->len; |
| 1521 | vif->dev->stats.tx_packets++; | 1835 | vif->dev->stats.tx_packets++; |
| 1522 | ip6mr_cache_report(net, skb, vifi, MRT6MSG_WHOLEPKT); | 1836 | ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT); |
| 1523 | goto out_free; | 1837 | goto out_free; |
| 1524 | } | 1838 | } |
| 1525 | #endif | 1839 | #endif |
| @@ -1566,7 +1880,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) | |||
| 1566 | 1880 | ||
| 1567 | IP6CB(skb)->flags |= IP6SKB_FORWARDED; | 1881 | IP6CB(skb)->flags |= IP6SKB_FORWARDED; |
| 1568 | 1882 | ||
| 1569 | return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev, | 1883 | return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev, |
| 1570 | ip6mr_forward2_finish); | 1884 | ip6mr_forward2_finish); |
| 1571 | 1885 | ||
| 1572 | out_free: | 1886 | out_free: |
| @@ -1574,22 +1888,22 @@ out_free: | |||
| 1574 | return 0; | 1888 | return 0; |
| 1575 | } | 1889 | } |
| 1576 | 1890 | ||
| 1577 | static int ip6mr_find_vif(struct net_device *dev) | 1891 | static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev) |
| 1578 | { | 1892 | { |
| 1579 | struct net *net = dev_net(dev); | ||
| 1580 | int ct; | 1893 | int ct; |
| 1581 | for (ct = net->ipv6.maxvif - 1; ct >= 0; ct--) { | 1894 | |
| 1582 | if (net->ipv6.vif6_table[ct].dev == dev) | 1895 | for (ct = mrt->maxvif - 1; ct >= 0; ct--) { |
| 1896 | if (mrt->vif6_table[ct].dev == dev) | ||
| 1583 | break; | 1897 | break; |
| 1584 | } | 1898 | } |
| 1585 | return ct; | 1899 | return ct; |
| 1586 | } | 1900 | } |
| 1587 | 1901 | ||
| 1588 | static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) | 1902 | static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, |
| 1903 | struct sk_buff *skb, struct mfc6_cache *cache) | ||
| 1589 | { | 1904 | { |
| 1590 | int psend = -1; | 1905 | int psend = -1; |
| 1591 | int vif, ct; | 1906 | int vif, ct; |
| 1592 | struct net *net = mfc6_net(cache); | ||
| 1593 | 1907 | ||
| 1594 | vif = cache->mf6c_parent; | 1908 | vif = cache->mf6c_parent; |
| 1595 | cache->mfc_un.res.pkt++; | 1909 | cache->mfc_un.res.pkt++; |
| @@ -1598,30 +1912,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) | |||
| 1598 | /* | 1912 | /* |
| 1599 | * Wrong interface: drop packet and (maybe) send PIM assert. | 1913 | * Wrong interface: drop packet and (maybe) send PIM assert. |
| 1600 | */ | 1914 | */ |
| 1601 | if (net->ipv6.vif6_table[vif].dev != skb->dev) { | 1915 | if (mrt->vif6_table[vif].dev != skb->dev) { |
| 1602 | int true_vifi; | 1916 | int true_vifi; |
| 1603 | 1917 | ||
| 1604 | cache->mfc_un.res.wrong_if++; | 1918 | cache->mfc_un.res.wrong_if++; |
| 1605 | true_vifi = ip6mr_find_vif(skb->dev); | 1919 | true_vifi = ip6mr_find_vif(mrt, skb->dev); |
| 1606 | 1920 | ||
| 1607 | if (true_vifi >= 0 && net->ipv6.mroute_do_assert && | 1921 | if (true_vifi >= 0 && mrt->mroute_do_assert && |
| 1608 | /* pimsm uses asserts, when switching from RPT to SPT, | 1922 | /* pimsm uses asserts, when switching from RPT to SPT, |
| 1609 | so that we cannot check that packet arrived on an oif. | 1923 | so that we cannot check that packet arrived on an oif. |
| 1610 | It is bad, but otherwise we would need to move pretty | 1924 | It is bad, but otherwise we would need to move pretty |
| 1611 | large chunk of pimd to kernel. Ough... --ANK | 1925 | large chunk of pimd to kernel. Ough... --ANK |
| 1612 | */ | 1926 | */ |
| 1613 | (net->ipv6.mroute_do_pim || | 1927 | (mrt->mroute_do_pim || |
| 1614 | cache->mfc_un.res.ttls[true_vifi] < 255) && | 1928 | cache->mfc_un.res.ttls[true_vifi] < 255) && |
| 1615 | time_after(jiffies, | 1929 | time_after(jiffies, |
| 1616 | cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { | 1930 | cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { |
| 1617 | cache->mfc_un.res.last_assert = jiffies; | 1931 | cache->mfc_un.res.last_assert = jiffies; |
| 1618 | ip6mr_cache_report(net, skb, true_vifi, MRT6MSG_WRONGMIF); | 1932 | ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF); |
| 1619 | } | 1933 | } |
| 1620 | goto dont_forward; | 1934 | goto dont_forward; |
| 1621 | } | 1935 | } |
| 1622 | 1936 | ||
| 1623 | net->ipv6.vif6_table[vif].pkt_in++; | 1937 | mrt->vif6_table[vif].pkt_in++; |
| 1624 | net->ipv6.vif6_table[vif].bytes_in += skb->len; | 1938 | mrt->vif6_table[vif].bytes_in += skb->len; |
| 1625 | 1939 | ||
| 1626 | /* | 1940 | /* |
| 1627 | * Forward the frame | 1941 | * Forward the frame |
| @@ -1631,13 +1945,13 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) | |||
| 1631 | if (psend != -1) { | 1945 | if (psend != -1) { |
| 1632 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | 1946 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); |
| 1633 | if (skb2) | 1947 | if (skb2) |
| 1634 | ip6mr_forward2(skb2, cache, psend); | 1948 | ip6mr_forward2(net, mrt, skb2, cache, psend); |
| 1635 | } | 1949 | } |
| 1636 | psend = ct; | 1950 | psend = ct; |
| 1637 | } | 1951 | } |
| 1638 | } | 1952 | } |
| 1639 | if (psend != -1) { | 1953 | if (psend != -1) { |
| 1640 | ip6mr_forward2(skb, cache, psend); | 1954 | ip6mr_forward2(net, mrt, skb, cache, psend); |
| 1641 | return 0; | 1955 | return 0; |
| 1642 | } | 1956 | } |
| 1643 | 1957 | ||
| @@ -1655,9 +1969,19 @@ int ip6_mr_input(struct sk_buff *skb) | |||
| 1655 | { | 1969 | { |
| 1656 | struct mfc6_cache *cache; | 1970 | struct mfc6_cache *cache; |
| 1657 | struct net *net = dev_net(skb->dev); | 1971 | struct net *net = dev_net(skb->dev); |
| 1972 | struct mr6_table *mrt; | ||
| 1973 | struct flowi fl = { | ||
| 1974 | .iif = skb->dev->ifindex, | ||
| 1975 | .mark = skb->mark, | ||
| 1976 | }; | ||
| 1977 | int err; | ||
| 1978 | |||
| 1979 | err = ip6mr_fib_lookup(net, &fl, &mrt); | ||
| 1980 | if (err < 0) | ||
| 1981 | return err; | ||
| 1658 | 1982 | ||
| 1659 | read_lock(&mrt_lock); | 1983 | read_lock(&mrt_lock); |
| 1660 | cache = ip6mr_cache_find(net, | 1984 | cache = ip6mr_cache_find(mrt, |
| 1661 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); | 1985 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); |
| 1662 | 1986 | ||
| 1663 | /* | 1987 | /* |
| @@ -1666,9 +1990,9 @@ int ip6_mr_input(struct sk_buff *skb) | |||
| 1666 | if (cache == NULL) { | 1990 | if (cache == NULL) { |
| 1667 | int vif; | 1991 | int vif; |
| 1668 | 1992 | ||
| 1669 | vif = ip6mr_find_vif(skb->dev); | 1993 | vif = ip6mr_find_vif(mrt, skb->dev); |
| 1670 | if (vif >= 0) { | 1994 | if (vif >= 0) { |
| 1671 | int err = ip6mr_cache_unresolved(net, vif, skb); | 1995 | int err = ip6mr_cache_unresolved(mrt, vif, skb); |
| 1672 | read_unlock(&mrt_lock); | 1996 | read_unlock(&mrt_lock); |
| 1673 | 1997 | ||
| 1674 | return err; | 1998 | return err; |
| @@ -1678,7 +2002,7 @@ int ip6_mr_input(struct sk_buff *skb) | |||
| 1678 | return -ENODEV; | 2002 | return -ENODEV; |
| 1679 | } | 2003 | } |
| 1680 | 2004 | ||
| 1681 | ip6_mr_forward(skb, cache); | 2005 | ip6_mr_forward(net, mrt, skb, cache); |
| 1682 | 2006 | ||
| 1683 | read_unlock(&mrt_lock); | 2007 | read_unlock(&mrt_lock); |
| 1684 | 2008 | ||
| @@ -1686,29 +2010,31 @@ int ip6_mr_input(struct sk_buff *skb) | |||
| 1686 | } | 2010 | } |
| 1687 | 2011 | ||
| 1688 | 2012 | ||
| 1689 | static int | 2013 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
| 1690 | ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) | 2014 | struct mfc6_cache *c, struct rtmsg *rtm) |
| 1691 | { | 2015 | { |
| 1692 | int ct; | 2016 | int ct; |
| 1693 | struct rtnexthop *nhp; | 2017 | struct rtnexthop *nhp; |
| 1694 | struct net *net = mfc6_net(c); | ||
| 1695 | struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev; | ||
| 1696 | u8 *b = skb_tail_pointer(skb); | 2018 | u8 *b = skb_tail_pointer(skb); |
| 1697 | struct rtattr *mp_head; | 2019 | struct rtattr *mp_head; |
| 1698 | 2020 | ||
| 1699 | if (dev) | 2021 | /* If cache is unresolved, don't try to parse IIF and OIF */ |
| 1700 | RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); | 2022 | if (c->mf6c_parent >= MAXMIFS) |
| 2023 | return -ENOENT; | ||
| 2024 | |||
| 2025 | if (MIF_EXISTS(mrt, c->mf6c_parent)) | ||
| 2026 | RTA_PUT(skb, RTA_IIF, 4, &mrt->vif6_table[c->mf6c_parent].dev->ifindex); | ||
| 1701 | 2027 | ||
| 1702 | mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); | 2028 | mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); |
| 1703 | 2029 | ||
| 1704 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { | 2030 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { |
| 1705 | if (c->mfc_un.res.ttls[ct] < 255) { | 2031 | if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) { |
| 1706 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) | 2032 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) |
| 1707 | goto rtattr_failure; | 2033 | goto rtattr_failure; |
| 1708 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); | 2034 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); |
| 1709 | nhp->rtnh_flags = 0; | 2035 | nhp->rtnh_flags = 0; |
| 1710 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; | 2036 | nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; |
| 1711 | nhp->rtnh_ifindex = net->ipv6.vif6_table[ct].dev->ifindex; | 2037 | nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex; |
| 1712 | nhp->rtnh_len = sizeof(*nhp); | 2038 | nhp->rtnh_len = sizeof(*nhp); |
| 1713 | } | 2039 | } |
| 1714 | } | 2040 | } |
| @@ -1726,11 +2052,16 @@ int ip6mr_get_route(struct net *net, | |||
| 1726 | struct sk_buff *skb, struct rtmsg *rtm, int nowait) | 2052 | struct sk_buff *skb, struct rtmsg *rtm, int nowait) |
| 1727 | { | 2053 | { |
| 1728 | int err; | 2054 | int err; |
| 2055 | struct mr6_table *mrt; | ||
| 1729 | struct mfc6_cache *cache; | 2056 | struct mfc6_cache *cache; |
| 1730 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | 2057 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
| 1731 | 2058 | ||
| 2059 | mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); | ||
| 2060 | if (mrt == NULL) | ||
| 2061 | return -ENOENT; | ||
| 2062 | |||
| 1732 | read_lock(&mrt_lock); | 2063 | read_lock(&mrt_lock); |
| 1733 | cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); | 2064 | cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); |
| 1734 | 2065 | ||
| 1735 | if (!cache) { | 2066 | if (!cache) { |
| 1736 | struct sk_buff *skb2; | 2067 | struct sk_buff *skb2; |
| @@ -1744,7 +2075,7 @@ int ip6mr_get_route(struct net *net, | |||
| 1744 | } | 2075 | } |
| 1745 | 2076 | ||
| 1746 | dev = skb->dev; | 2077 | dev = skb->dev; |
| 1747 | if (dev == NULL || (vif = ip6mr_find_vif(dev)) < 0) { | 2078 | if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) { |
| 1748 | read_unlock(&mrt_lock); | 2079 | read_unlock(&mrt_lock); |
| 1749 | return -ENODEV; | 2080 | return -ENODEV; |
| 1750 | } | 2081 | } |
| @@ -1773,7 +2104,7 @@ int ip6mr_get_route(struct net *net, | |||
| 1773 | ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); | 2104 | ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); |
| 1774 | ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); | 2105 | ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); |
| 1775 | 2106 | ||
| 1776 | err = ip6mr_cache_unresolved(net, vif, skb2); | 2107 | err = ip6mr_cache_unresolved(mrt, vif, skb2); |
| 1777 | read_unlock(&mrt_lock); | 2108 | read_unlock(&mrt_lock); |
| 1778 | 2109 | ||
| 1779 | return err; | 2110 | return err; |
| @@ -1782,8 +2113,88 @@ int ip6mr_get_route(struct net *net, | |||
| 1782 | if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) | 2113 | if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) |
| 1783 | cache->mfc_flags |= MFC_NOTIFY; | 2114 | cache->mfc_flags |= MFC_NOTIFY; |
| 1784 | 2115 | ||
| 1785 | err = ip6mr_fill_mroute(skb, cache, rtm); | 2116 | err = __ip6mr_fill_mroute(mrt, skb, cache, rtm); |
| 1786 | read_unlock(&mrt_lock); | 2117 | read_unlock(&mrt_lock); |
| 1787 | return err; | 2118 | return err; |
| 1788 | } | 2119 | } |
| 1789 | 2120 | ||
| 2121 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | ||
| 2122 | u32 pid, u32 seq, struct mfc6_cache *c) | ||
| 2123 | { | ||
| 2124 | struct nlmsghdr *nlh; | ||
| 2125 | struct rtmsg *rtm; | ||
| 2126 | |||
| 2127 | nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI); | ||
| 2128 | if (nlh == NULL) | ||
| 2129 | return -EMSGSIZE; | ||
| 2130 | |||
| 2131 | rtm = nlmsg_data(nlh); | ||
| 2132 | rtm->rtm_family = RTNL_FAMILY_IPMR; | ||
| 2133 | rtm->rtm_dst_len = 128; | ||
| 2134 | rtm->rtm_src_len = 128; | ||
| 2135 | rtm->rtm_tos = 0; | ||
| 2136 | rtm->rtm_table = mrt->id; | ||
| 2137 | NLA_PUT_U32(skb, RTA_TABLE, mrt->id); | ||
| 2138 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; | ||
| 2139 | rtm->rtm_protocol = RTPROT_UNSPEC; | ||
| 2140 | rtm->rtm_flags = 0; | ||
| 2141 | |||
| 2142 | NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin); | ||
| 2143 | NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp); | ||
| 2144 | |||
| 2145 | if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0) | ||
| 2146 | goto nla_put_failure; | ||
| 2147 | |||
| 2148 | return nlmsg_end(skb, nlh); | ||
| 2149 | |||
| 2150 | nla_put_failure: | ||
| 2151 | nlmsg_cancel(skb, nlh); | ||
| 2152 | return -EMSGSIZE; | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 2156 | { | ||
| 2157 | struct net *net = sock_net(skb->sk); | ||
| 2158 | struct mr6_table *mrt; | ||
| 2159 | struct mfc6_cache *mfc; | ||
| 2160 | unsigned int t = 0, s_t; | ||
| 2161 | unsigned int h = 0, s_h; | ||
| 2162 | unsigned int e = 0, s_e; | ||
| 2163 | |||
| 2164 | s_t = cb->args[0]; | ||
| 2165 | s_h = cb->args[1]; | ||
| 2166 | s_e = cb->args[2]; | ||
| 2167 | |||
| 2168 | read_lock(&mrt_lock); | ||
| 2169 | ip6mr_for_each_table(mrt, net) { | ||
| 2170 | if (t < s_t) | ||
| 2171 | goto next_table; | ||
| 2172 | if (t > s_t) | ||
| 2173 | s_h = 0; | ||
| 2174 | for (h = s_h; h < MFC6_LINES; h++) { | ||
| 2175 | list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) { | ||
| 2176 | if (e < s_e) | ||
| 2177 | goto next_entry; | ||
| 2178 | if (ip6mr_fill_mroute(mrt, skb, | ||
| 2179 | NETLINK_CB(cb->skb).pid, | ||
| 2180 | cb->nlh->nlmsg_seq, | ||
| 2181 | mfc) < 0) | ||
| 2182 | goto done; | ||
| 2183 | next_entry: | ||
| 2184 | e++; | ||
| 2185 | } | ||
| 2186 | e = s_e = 0; | ||
| 2187 | } | ||
| 2188 | s_h = 0; | ||
| 2189 | next_table: | ||
| 2190 | t++; | ||
| 2191 | } | ||
| 2192 | done: | ||
| 2193 | read_unlock(&mrt_lock); | ||
| 2194 | |||
| 2195 | cb->args[2] = e; | ||
| 2196 | cb->args[1] = h; | ||
| 2197 | cb->args[0] = t; | ||
| 2198 | |||
| 2199 | return skb->len; | ||
| 2200 | } | ||
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 2f2a5ca2c878..85cccd6ed0b7 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 53 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 54 | u8 type, u8 code, int offset, __be32 info) | 54 | u8 type, u8 code, int offset, __be32 info) |
| 55 | { | 55 | { |
| 56 | struct net *net = dev_net(skb->dev); | ||
| 56 | __be32 spi; | 57 | __be32 spi; |
| 57 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 58 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; |
| 58 | struct ip_comp_hdr *ipcomph = | 59 | struct ip_comp_hdr *ipcomph = |
| @@ -63,7 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 63 | return; | 64 | return; |
| 64 | 65 | ||
| 65 | spi = htonl(ntohs(ipcomph->cpi)); | 66 | spi = htonl(ntohs(ipcomph->cpi)); |
| 66 | x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); | 67 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); |
| 67 | if (!x) | 68 | if (!x) |
| 68 | return; | 69 | return; |
| 69 | 70 | ||
| @@ -74,14 +75,15 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 74 | 75 | ||
| 75 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | 76 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) |
| 76 | { | 77 | { |
| 78 | struct net *net = xs_net(x); | ||
| 77 | struct xfrm_state *t = NULL; | 79 | struct xfrm_state *t = NULL; |
| 78 | 80 | ||
| 79 | t = xfrm_state_alloc(&init_net); | 81 | t = xfrm_state_alloc(net); |
| 80 | if (!t) | 82 | if (!t) |
| 81 | goto out; | 83 | goto out; |
| 82 | 84 | ||
| 83 | t->id.proto = IPPROTO_IPV6; | 85 | t->id.proto = IPPROTO_IPV6; |
| 84 | t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr); | 86 | t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr); |
| 85 | if (!t->id.spi) | 87 | if (!t->id.spi) |
| 86 | goto error; | 88 | goto error; |
| 87 | 89 | ||
| @@ -90,6 +92,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | |||
| 90 | t->props.family = AF_INET6; | 92 | t->props.family = AF_INET6; |
| 91 | t->props.mode = x->props.mode; | 93 | t->props.mode = x->props.mode; |
| 92 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); | 94 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
| 95 | memcpy(&t->mark, &x->mark, sizeof(t->mark)); | ||
| 93 | 96 | ||
| 94 | if (xfrm_init_state(t)) | 97 | if (xfrm_init_state(t)) |
| 95 | goto error; | 98 | goto error; |
| @@ -108,13 +111,15 @@ error: | |||
| 108 | 111 | ||
| 109 | static int ipcomp6_tunnel_attach(struct xfrm_state *x) | 112 | static int ipcomp6_tunnel_attach(struct xfrm_state *x) |
| 110 | { | 113 | { |
| 114 | struct net *net = xs_net(x); | ||
| 111 | int err = 0; | 115 | int err = 0; |
| 112 | struct xfrm_state *t = NULL; | 116 | struct xfrm_state *t = NULL; |
| 113 | __be32 spi; | 117 | __be32 spi; |
| 118 | u32 mark = x->mark.m & x->mark.v; | ||
| 114 | 119 | ||
| 115 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); | 120 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&x->props.saddr); |
| 116 | if (spi) | 121 | if (spi) |
| 117 | t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr, | 122 | t = xfrm_state_lookup(net, mark, (xfrm_address_t *)&x->id.daddr, |
| 118 | spi, IPPROTO_IPV6, AF_INET6); | 123 | spi, IPPROTO_IPV6, AF_INET6); |
| 119 | if (!t) { | 124 | if (!t) { |
| 120 | t = ipcomp6_tunnel_create(x); | 125 | t = ipcomp6_tunnel_create(x); |
| @@ -154,16 +159,12 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
| 154 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 159 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
| 155 | err = ipcomp6_tunnel_attach(x); | 160 | err = ipcomp6_tunnel_attach(x); |
| 156 | if (err) | 161 | if (err) |
| 157 | goto error_tunnel; | 162 | goto out; |
| 158 | } | 163 | } |
| 159 | 164 | ||
| 160 | err = 0; | 165 | err = 0; |
| 161 | out: | 166 | out: |
| 162 | return err; | 167 | return err; |
| 163 | error_tunnel: | ||
| 164 | ipcomp_destroy(x); | ||
| 165 | |||
| 166 | goto out; | ||
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | static const struct xfrm_type ipcomp6_type = | 170 | static const struct xfrm_type ipcomp6_type = |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 430454ee5ead..a7f66bc8f0b0 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
| 37 | #include <linux/sysctl.h> | 37 | #include <linux/sysctl.h> |
| 38 | #include <linux/netfilter.h> | 38 | #include <linux/netfilter.h> |
| 39 | #include <linux/slab.h> | ||
| 39 | 40 | ||
| 40 | #include <net/sock.h> | 41 | #include <net/sock.h> |
| 41 | #include <net/snmp.h> | 42 | #include <net/snmp.h> |
| @@ -54,8 +55,6 @@ | |||
| 54 | 55 | ||
| 55 | #include <asm/uaccess.h> | 56 | #include <asm/uaccess.h> |
| 56 | 57 | ||
| 57 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | ||
| 58 | |||
| 59 | struct ip6_ra_chain *ip6_ra_chain; | 58 | struct ip6_ra_chain *ip6_ra_chain; |
| 60 | DEFINE_RWLOCK(ip6_ra_lock); | 59 | DEFINE_RWLOCK(ip6_ra_lock); |
| 61 | 60 | ||
| @@ -113,9 +112,9 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, | |||
| 113 | } | 112 | } |
| 114 | opt = xchg(&inet6_sk(sk)->opt, opt); | 113 | opt = xchg(&inet6_sk(sk)->opt, opt); |
| 115 | } else { | 114 | } else { |
| 116 | write_lock(&sk->sk_dst_lock); | 115 | spin_lock(&sk->sk_dst_lock); |
| 117 | opt = xchg(&inet6_sk(sk)->opt, opt); | 116 | opt = xchg(&inet6_sk(sk)->opt, opt); |
| 118 | write_unlock(&sk->sk_dst_lock); | 117 | spin_unlock(&sk->sk_dst_lock); |
| 119 | } | 118 | } |
| 120 | sk_dst_reset(sk); | 119 | sk_dst_reset(sk); |
| 121 | 120 | ||
| @@ -336,6 +335,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 336 | retv = 0; | 335 | retv = 0; |
| 337 | break; | 336 | break; |
| 338 | 337 | ||
| 338 | case IPV6_RECVPATHMTU: | ||
| 339 | if (optlen < sizeof(int)) | ||
| 340 | goto e_inval; | ||
| 341 | np->rxopt.bits.rxpmtu = valbool; | ||
| 342 | retv = 0; | ||
| 343 | break; | ||
| 344 | |||
| 339 | case IPV6_HOPOPTS: | 345 | case IPV6_HOPOPTS: |
| 340 | case IPV6_RTHDRDSTOPTS: | 346 | case IPV6_RTHDRDSTOPTS: |
| 341 | case IPV6_RTHDR: | 347 | case IPV6_RTHDR: |
| @@ -450,7 +456,8 @@ sticky_done: | |||
| 450 | msg.msg_controllen = optlen; | 456 | msg.msg_controllen = optlen; |
| 451 | msg.msg_control = (void*)(opt+1); | 457 | msg.msg_control = (void*)(opt+1); |
| 452 | 458 | ||
| 453 | retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk); | 459 | retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk, |
| 460 | &junk); | ||
| 454 | if (retv) | 461 | if (retv) |
| 455 | goto done; | 462 | goto done; |
| 456 | update: | 463 | update: |
| @@ -766,6 +773,17 @@ pref_skip_coa: | |||
| 766 | 773 | ||
| 767 | break; | 774 | break; |
| 768 | } | 775 | } |
| 776 | case IPV6_MINHOPCOUNT: | ||
| 777 | if (optlen < sizeof(int)) | ||
| 778 | goto e_inval; | ||
| 779 | if (val < 0 || val > 255) | ||
| 780 | goto e_inval; | ||
| 781 | np->min_hopcount = val; | ||
| 782 | break; | ||
| 783 | case IPV6_DONTFRAG: | ||
| 784 | np->dontfrag = valbool; | ||
| 785 | retv = 0; | ||
| 786 | break; | ||
| 769 | } | 787 | } |
| 770 | 788 | ||
| 771 | release_sock(sk); | 789 | release_sock(sk); |
| @@ -970,14 +988,13 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 970 | case IPV6_MTU: | 988 | case IPV6_MTU: |
| 971 | { | 989 | { |
| 972 | struct dst_entry *dst; | 990 | struct dst_entry *dst; |
| 991 | |||
| 973 | val = 0; | 992 | val = 0; |
| 974 | lock_sock(sk); | 993 | rcu_read_lock(); |
| 975 | dst = sk_dst_get(sk); | 994 | dst = __sk_dst_get(sk); |
| 976 | if (dst) { | 995 | if (dst) |
| 977 | val = dst_mtu(dst); | 996 | val = dst_mtu(dst); |
| 978 | dst_release(dst); | 997 | rcu_read_unlock(); |
| 979 | } | ||
| 980 | release_sock(sk); | ||
| 981 | if (!val) | 998 | if (!val) |
| 982 | return -ENOTCONN; | 999 | return -ENOTCONN; |
| 983 | break; | 1000 | break; |
| @@ -1055,6 +1072,38 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1055 | val = np->rxopt.bits.rxflow; | 1072 | val = np->rxopt.bits.rxflow; |
| 1056 | break; | 1073 | break; |
| 1057 | 1074 | ||
| 1075 | case IPV6_RECVPATHMTU: | ||
| 1076 | val = np->rxopt.bits.rxpmtu; | ||
| 1077 | break; | ||
| 1078 | |||
| 1079 | case IPV6_PATHMTU: | ||
| 1080 | { | ||
| 1081 | struct dst_entry *dst; | ||
| 1082 | struct ip6_mtuinfo mtuinfo; | ||
| 1083 | |||
| 1084 | if (len < sizeof(mtuinfo)) | ||
| 1085 | return -EINVAL; | ||
| 1086 | |||
| 1087 | len = sizeof(mtuinfo); | ||
| 1088 | memset(&mtuinfo, 0, sizeof(mtuinfo)); | ||
| 1089 | |||
| 1090 | rcu_read_lock(); | ||
| 1091 | dst = __sk_dst_get(sk); | ||
| 1092 | if (dst) | ||
| 1093 | mtuinfo.ip6m_mtu = dst_mtu(dst); | ||
| 1094 | rcu_read_unlock(); | ||
| 1095 | if (!mtuinfo.ip6m_mtu) | ||
| 1096 | return -ENOTCONN; | ||
| 1097 | |||
| 1098 | if (put_user(len, optlen)) | ||
| 1099 | return -EFAULT; | ||
| 1100 | if (copy_to_user(optval, &mtuinfo, len)) | ||
| 1101 | return -EFAULT; | ||
| 1102 | |||
| 1103 | return 0; | ||
| 1104 | break; | ||
| 1105 | } | ||
| 1106 | |||
| 1058 | case IPV6_UNICAST_HOPS: | 1107 | case IPV6_UNICAST_HOPS: |
| 1059 | case IPV6_MULTICAST_HOPS: | 1108 | case IPV6_MULTICAST_HOPS: |
| 1060 | { | 1109 | { |
| @@ -1065,12 +1114,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1065 | else | 1114 | else |
| 1066 | val = np->mcast_hops; | 1115 | val = np->mcast_hops; |
| 1067 | 1116 | ||
| 1068 | dst = sk_dst_get(sk); | 1117 | if (val < 0) { |
| 1069 | if (dst) { | 1118 | rcu_read_lock(); |
| 1070 | if (val < 0) | 1119 | dst = __sk_dst_get(sk); |
| 1120 | if (dst) | ||
| 1071 | val = ip6_dst_hoplimit(dst); | 1121 | val = ip6_dst_hoplimit(dst); |
| 1072 | dst_release(dst); | 1122 | rcu_read_unlock(); |
| 1073 | } | 1123 | } |
| 1124 | |||
| 1074 | if (val < 0) | 1125 | if (val < 0) |
| 1075 | val = sock_net(sk)->ipv6.devconf_all->hop_limit; | 1126 | val = sock_net(sk)->ipv6.devconf_all->hop_limit; |
| 1076 | break; | 1127 | break; |
| @@ -1114,6 +1165,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 1114 | val |= IPV6_PREFER_SRC_HOME; | 1165 | val |= IPV6_PREFER_SRC_HOME; |
| 1115 | break; | 1166 | break; |
| 1116 | 1167 | ||
| 1168 | case IPV6_MINHOPCOUNT: | ||
| 1169 | val = np->min_hopcount; | ||
| 1170 | break; | ||
| 1171 | |||
| 1172 | case IPV6_DONTFRAG: | ||
| 1173 | val = np->dontfrag; | ||
| 1174 | break; | ||
| 1175 | |||
| 1117 | default: | 1176 | default: |
| 1118 | return -ENOPROTOOPT; | 1177 | return -ENOPROTOOPT; |
| 1119 | } | 1178 | } |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 1f9c44442e65..d1444b95ad7e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -43,6 +43,8 @@ | |||
| 43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
| 44 | #include <linux/proc_fs.h> | 44 | #include <linux/proc_fs.h> |
| 45 | #include <linux/seq_file.h> | 45 | #include <linux/seq_file.h> |
| 46 | #include <linux/slab.h> | ||
| 47 | #include <net/mld.h> | ||
| 46 | 48 | ||
| 47 | #include <linux/netfilter.h> | 49 | #include <linux/netfilter.h> |
| 48 | #include <linux/netfilter_ipv6.h> | 50 | #include <linux/netfilter_ipv6.h> |
| @@ -70,54 +72,11 @@ | |||
| 70 | #define MDBG(x) | 72 | #define MDBG(x) |
| 71 | #endif | 73 | #endif |
| 72 | 74 | ||
| 73 | /* | 75 | /* Ensure that we have struct in6_addr aligned on 32bit word. */ |
| 74 | * These header formats should be in a separate include file, but icmpv6.h | 76 | static void *__mld2_query_bugs[] __attribute__((__unused__)) = { |
| 75 | * doesn't have in6_addr defined in all cases, there is no __u128, and no | 77 | BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4), |
| 76 | * other files reference these. | 78 | BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4), |
| 77 | * | 79 | BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4) |
| 78 | * +-DLS 4/14/03 | ||
| 79 | */ | ||
| 80 | |||
| 81 | /* Multicast Listener Discovery version 2 headers */ | ||
| 82 | |||
| 83 | struct mld2_grec { | ||
| 84 | __u8 grec_type; | ||
| 85 | __u8 grec_auxwords; | ||
| 86 | __be16 grec_nsrcs; | ||
| 87 | struct in6_addr grec_mca; | ||
| 88 | struct in6_addr grec_src[0]; | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct mld2_report { | ||
| 92 | __u8 type; | ||
| 93 | __u8 resv1; | ||
| 94 | __sum16 csum; | ||
| 95 | __be16 resv2; | ||
| 96 | __be16 ngrec; | ||
| 97 | struct mld2_grec grec[0]; | ||
| 98 | }; | ||
| 99 | |||
| 100 | struct mld2_query { | ||
| 101 | __u8 type; | ||
| 102 | __u8 code; | ||
| 103 | __sum16 csum; | ||
| 104 | __be16 mrc; | ||
| 105 | __be16 resv1; | ||
| 106 | struct in6_addr mca; | ||
| 107 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
| 108 | __u8 qrv:3, | ||
| 109 | suppress:1, | ||
| 110 | resv2:4; | ||
| 111 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
| 112 | __u8 resv2:4, | ||
| 113 | suppress:1, | ||
| 114 | qrv:3; | ||
| 115 | #else | ||
| 116 | #error "Please fix <asm/byteorder.h>" | ||
| 117 | #endif | ||
| 118 | __u8 qqic; | ||
| 119 | __be16 nsrcs; | ||
| 120 | struct in6_addr srcs[0]; | ||
| 121 | }; | 80 | }; |
| 122 | 81 | ||
| 123 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | 82 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; |
| @@ -156,14 +115,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
| 156 | ((idev)->mc_v1_seen && \ | 115 | ((idev)->mc_v1_seen && \ |
| 157 | time_before(jiffies, (idev)->mc_v1_seen))) | 116 | time_before(jiffies, (idev)->mc_v1_seen))) |
| 158 | 117 | ||
| 159 | #define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) | ||
| 160 | #define MLDV2_EXP(thresh, nbmant, nbexp, value) \ | ||
| 161 | ((value) < (thresh) ? (value) : \ | ||
| 162 | ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ | ||
| 163 | (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) | ||
| 164 | |||
| 165 | #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) | ||
| 166 | |||
| 167 | #define IPV6_MLD_MAX_MSF 64 | 118 | #define IPV6_MLD_MAX_MSF 64 |
| 168 | 119 | ||
| 169 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | 120 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; |
| @@ -201,18 +152,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 201 | mc_lst->next = NULL; | 152 | mc_lst->next = NULL; |
| 202 | ipv6_addr_copy(&mc_lst->addr, addr); | 153 | ipv6_addr_copy(&mc_lst->addr, addr); |
| 203 | 154 | ||
| 155 | rcu_read_lock(); | ||
| 204 | if (ifindex == 0) { | 156 | if (ifindex == 0) { |
| 205 | struct rt6_info *rt; | 157 | struct rt6_info *rt; |
| 206 | rt = rt6_lookup(net, addr, NULL, 0, 0); | 158 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
| 207 | if (rt) { | 159 | if (rt) { |
| 208 | dev = rt->rt6i_dev; | 160 | dev = rt->rt6i_dev; |
| 209 | dev_hold(dev); | 161 | dst_release(&rt->dst); |
| 210 | dst_release(&rt->u.dst); | ||
| 211 | } | 162 | } |
| 212 | } else | 163 | } else |
| 213 | dev = dev_get_by_index(net, ifindex); | 164 | dev = dev_get_by_index_rcu(net, ifindex); |
| 214 | 165 | ||
| 215 | if (dev == NULL) { | 166 | if (dev == NULL) { |
| 167 | rcu_read_unlock(); | ||
| 216 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 168 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 217 | return -ENODEV; | 169 | return -ENODEV; |
| 218 | } | 170 | } |
| @@ -229,8 +181,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 229 | err = ipv6_dev_mc_inc(dev, addr); | 181 | err = ipv6_dev_mc_inc(dev, addr); |
| 230 | 182 | ||
| 231 | if (err) { | 183 | if (err) { |
| 184 | rcu_read_unlock(); | ||
| 232 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 185 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 233 | dev_put(dev); | ||
| 234 | return err; | 186 | return err; |
| 235 | } | 187 | } |
| 236 | 188 | ||
| @@ -239,7 +191,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 239 | np->ipv6_mc_list = mc_lst; | 191 | np->ipv6_mc_list = mc_lst; |
| 240 | write_unlock_bh(&ipv6_sk_mc_lock); | 192 | write_unlock_bh(&ipv6_sk_mc_lock); |
| 241 | 193 | ||
| 242 | dev_put(dev); | 194 | rcu_read_unlock(); |
| 243 | 195 | ||
| 244 | return 0; | 196 | return 0; |
| 245 | } | 197 | } |
| @@ -262,18 +214,17 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 262 | *lnk = mc_lst->next; | 214 | *lnk = mc_lst->next; |
| 263 | write_unlock_bh(&ipv6_sk_mc_lock); | 215 | write_unlock_bh(&ipv6_sk_mc_lock); |
| 264 | 216 | ||
| 265 | dev = dev_get_by_index(net, mc_lst->ifindex); | 217 | rcu_read_lock(); |
| 218 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | ||
| 266 | if (dev != NULL) { | 219 | if (dev != NULL) { |
| 267 | struct inet6_dev *idev = in6_dev_get(dev); | 220 | struct inet6_dev *idev = __in6_dev_get(dev); |
| 268 | 221 | ||
| 269 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | 222 | (void) ip6_mc_leave_src(sk, mc_lst, idev); |
| 270 | if (idev) { | 223 | if (idev) |
| 271 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 224 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
| 272 | in6_dev_put(idev); | ||
| 273 | } | ||
| 274 | dev_put(dev); | ||
| 275 | } else | 225 | } else |
| 276 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 226 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
| 227 | rcu_read_unlock(); | ||
| 277 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 228 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 278 | return 0; | 229 | return 0; |
| 279 | } | 230 | } |
| @@ -283,43 +234,36 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
| 283 | return -EADDRNOTAVAIL; | 234 | return -EADDRNOTAVAIL; |
| 284 | } | 235 | } |
| 285 | 236 | ||
| 286 | static struct inet6_dev *ip6_mc_find_dev(struct net *net, | 237 | /* called with rcu_read_lock() */ |
| 287 | struct in6_addr *group, | 238 | static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, |
| 288 | int ifindex) | 239 | struct in6_addr *group, |
| 240 | int ifindex) | ||
| 289 | { | 241 | { |
| 290 | struct net_device *dev = NULL; | 242 | struct net_device *dev = NULL; |
| 291 | struct inet6_dev *idev = NULL; | 243 | struct inet6_dev *idev = NULL; |
| 292 | 244 | ||
| 293 | if (ifindex == 0) { | 245 | if (ifindex == 0) { |
| 294 | struct rt6_info *rt; | 246 | struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0); |
| 295 | 247 | ||
| 296 | rt = rt6_lookup(net, group, NULL, 0, 0); | ||
| 297 | if (rt) { | 248 | if (rt) { |
| 298 | dev = rt->rt6i_dev; | 249 | dev = rt->rt6i_dev; |
| 299 | dev_hold(dev); | 250 | dev_hold(dev); |
| 300 | dst_release(&rt->u.dst); | 251 | dst_release(&rt->dst); |
| 301 | } | 252 | } |
| 302 | } else | 253 | } else |
| 303 | dev = dev_get_by_index(net, ifindex); | 254 | dev = dev_get_by_index_rcu(net, ifindex); |
| 304 | 255 | ||
| 305 | if (!dev) | 256 | if (!dev) |
| 306 | goto nodev; | 257 | return NULL; |
| 307 | idev = in6_dev_get(dev); | 258 | idev = __in6_dev_get(dev); |
| 308 | if (!idev) | 259 | if (!idev) |
| 309 | goto release; | 260 | return NULL;; |
| 310 | read_lock_bh(&idev->lock); | 261 | read_lock_bh(&idev->lock); |
| 311 | if (idev->dead) | 262 | if (idev->dead) { |
| 312 | goto unlock_release; | 263 | read_unlock_bh(&idev->lock); |
| 313 | 264 | return NULL; | |
| 265 | } | ||
| 314 | return idev; | 266 | return idev; |
| 315 | |||
| 316 | unlock_release: | ||
| 317 | read_unlock_bh(&idev->lock); | ||
| 318 | in6_dev_put(idev); | ||
| 319 | release: | ||
| 320 | dev_put(dev); | ||
| 321 | nodev: | ||
| 322 | return NULL; | ||
| 323 | } | 267 | } |
| 324 | 268 | ||
| 325 | void ipv6_sock_mc_close(struct sock *sk) | 269 | void ipv6_sock_mc_close(struct sock *sk) |
| @@ -335,19 +279,17 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
| 335 | np->ipv6_mc_list = mc_lst->next; | 279 | np->ipv6_mc_list = mc_lst->next; |
| 336 | write_unlock_bh(&ipv6_sk_mc_lock); | 280 | write_unlock_bh(&ipv6_sk_mc_lock); |
| 337 | 281 | ||
| 338 | dev = dev_get_by_index(net, mc_lst->ifindex); | 282 | rcu_read_lock(); |
| 283 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | ||
| 339 | if (dev) { | 284 | if (dev) { |
| 340 | struct inet6_dev *idev = in6_dev_get(dev); | 285 | struct inet6_dev *idev = __in6_dev_get(dev); |
| 341 | 286 | ||
| 342 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | 287 | (void) ip6_mc_leave_src(sk, mc_lst, idev); |
| 343 | if (idev) { | 288 | if (idev) |
| 344 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 289 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
| 345 | in6_dev_put(idev); | ||
| 346 | } | ||
| 347 | dev_put(dev); | ||
| 348 | } else | 290 | } else |
| 349 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 291 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
| 350 | 292 | rcu_read_unlock(); | |
| 351 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 293 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
| 352 | 294 | ||
| 353 | write_lock_bh(&ipv6_sk_mc_lock); | 295 | write_lock_bh(&ipv6_sk_mc_lock); |
| @@ -376,14 +318,17 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
| 376 | if (!ipv6_addr_is_multicast(group)) | 318 | if (!ipv6_addr_is_multicast(group)) |
| 377 | return -EINVAL; | 319 | return -EINVAL; |
| 378 | 320 | ||
| 379 | idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface); | 321 | rcu_read_lock(); |
| 380 | if (!idev) | 322 | idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface); |
| 323 | if (!idev) { | ||
| 324 | rcu_read_unlock(); | ||
| 381 | return -ENODEV; | 325 | return -ENODEV; |
| 326 | } | ||
| 382 | dev = idev->dev; | 327 | dev = idev->dev; |
| 383 | 328 | ||
| 384 | err = -EADDRNOTAVAIL; | 329 | err = -EADDRNOTAVAIL; |
| 385 | 330 | ||
| 386 | read_lock_bh(&ipv6_sk_mc_lock); | 331 | read_lock(&ipv6_sk_mc_lock); |
| 387 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | 332 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { |
| 388 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) | 333 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) |
| 389 | continue; | 334 | continue; |
| @@ -407,7 +352,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
| 407 | pmc->sfmode = omode; | 352 | pmc->sfmode = omode; |
| 408 | } | 353 | } |
| 409 | 354 | ||
| 410 | write_lock_bh(&pmc->sflock); | 355 | write_lock(&pmc->sflock); |
| 411 | pmclocked = 1; | 356 | pmclocked = 1; |
| 412 | 357 | ||
| 413 | psl = pmc->sflist; | 358 | psl = pmc->sflist; |
| @@ -482,11 +427,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
| 482 | ip6_mc_add_src(idev, group, omode, 1, source, 1); | 427 | ip6_mc_add_src(idev, group, omode, 1, source, 1); |
| 483 | done: | 428 | done: |
| 484 | if (pmclocked) | 429 | if (pmclocked) |
| 485 | write_unlock_bh(&pmc->sflock); | 430 | write_unlock(&pmc->sflock); |
| 486 | read_unlock_bh(&ipv6_sk_mc_lock); | 431 | read_unlock(&ipv6_sk_mc_lock); |
| 487 | read_unlock_bh(&idev->lock); | 432 | read_unlock_bh(&idev->lock); |
| 488 | in6_dev_put(idev); | 433 | rcu_read_unlock(); |
| 489 | dev_put(dev); | ||
| 490 | if (leavegroup) | 434 | if (leavegroup) |
| 491 | return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); | 435 | return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); |
| 492 | return err; | 436 | return err; |
| @@ -512,14 +456,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
| 512 | gsf->gf_fmode != MCAST_EXCLUDE) | 456 | gsf->gf_fmode != MCAST_EXCLUDE) |
| 513 | return -EINVAL; | 457 | return -EINVAL; |
| 514 | 458 | ||
| 515 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); | 459 | rcu_read_lock(); |
| 460 | idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface); | ||
| 516 | 461 | ||
| 517 | if (!idev) | 462 | if (!idev) { |
| 463 | rcu_read_unlock(); | ||
| 518 | return -ENODEV; | 464 | return -ENODEV; |
| 465 | } | ||
| 519 | dev = idev->dev; | 466 | dev = idev->dev; |
| 520 | 467 | ||
| 521 | err = 0; | 468 | err = 0; |
| 522 | read_lock_bh(&ipv6_sk_mc_lock); | 469 | read_lock(&ipv6_sk_mc_lock); |
| 523 | 470 | ||
| 524 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { | 471 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { |
| 525 | leavegroup = 1; | 472 | leavegroup = 1; |
| @@ -561,7 +508,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
| 561 | (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); | 508 | (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); |
| 562 | } | 509 | } |
| 563 | 510 | ||
| 564 | write_lock_bh(&pmc->sflock); | 511 | write_lock(&pmc->sflock); |
| 565 | psl = pmc->sflist; | 512 | psl = pmc->sflist; |
| 566 | if (psl) { | 513 | if (psl) { |
| 567 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, | 514 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, |
| @@ -571,13 +518,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
| 571 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); | 518 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); |
| 572 | pmc->sflist = newpsl; | 519 | pmc->sflist = newpsl; |
| 573 | pmc->sfmode = gsf->gf_fmode; | 520 | pmc->sfmode = gsf->gf_fmode; |
| 574 | write_unlock_bh(&pmc->sflock); | 521 | write_unlock(&pmc->sflock); |
| 575 | err = 0; | 522 | err = 0; |
| 576 | done: | 523 | done: |
| 577 | read_unlock_bh(&ipv6_sk_mc_lock); | 524 | read_unlock(&ipv6_sk_mc_lock); |
| 578 | read_unlock_bh(&idev->lock); | 525 | read_unlock_bh(&idev->lock); |
| 579 | in6_dev_put(idev); | 526 | rcu_read_unlock(); |
| 580 | dev_put(dev); | ||
| 581 | if (leavegroup) | 527 | if (leavegroup) |
| 582 | err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group); | 528 | err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group); |
| 583 | return err; | 529 | return err; |
| @@ -600,11 +546,13 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
| 600 | if (!ipv6_addr_is_multicast(group)) | 546 | if (!ipv6_addr_is_multicast(group)) |
| 601 | return -EINVAL; | 547 | return -EINVAL; |
| 602 | 548 | ||
| 603 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); | 549 | rcu_read_lock(); |
| 550 | idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface); | ||
| 604 | 551 | ||
| 605 | if (!idev) | 552 | if (!idev) { |
| 553 | rcu_read_unlock(); | ||
| 606 | return -ENODEV; | 554 | return -ENODEV; |
| 607 | 555 | } | |
| 608 | dev = idev->dev; | 556 | dev = idev->dev; |
| 609 | 557 | ||
| 610 | err = -EADDRNOTAVAIL; | 558 | err = -EADDRNOTAVAIL; |
| @@ -626,8 +574,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
| 626 | psl = pmc->sflist; | 574 | psl = pmc->sflist; |
| 627 | count = psl ? psl->sl_count : 0; | 575 | count = psl ? psl->sl_count : 0; |
| 628 | read_unlock_bh(&idev->lock); | 576 | read_unlock_bh(&idev->lock); |
| 629 | in6_dev_put(idev); | 577 | rcu_read_unlock(); |
| 630 | dev_put(dev); | ||
| 631 | 578 | ||
| 632 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; | 579 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; |
| 633 | gsf->gf_numsrc = count; | 580 | gsf->gf_numsrc = count; |
| @@ -653,8 +600,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
| 653 | return 0; | 600 | return 0; |
| 654 | done: | 601 | done: |
| 655 | read_unlock_bh(&idev->lock); | 602 | read_unlock_bh(&idev->lock); |
| 656 | in6_dev_put(idev); | 603 | rcu_read_unlock(); |
| 657 | dev_put(dev); | ||
| 658 | return err; | 604 | return err; |
| 659 | } | 605 | } |
| 660 | 606 | ||
| @@ -714,7 +660,7 @@ static void igmp6_group_added(struct ifmcaddr6 *mc) | |||
| 714 | if (!(mc->mca_flags&MAF_LOADED)) { | 660 | if (!(mc->mca_flags&MAF_LOADED)) { |
| 715 | mc->mca_flags |= MAF_LOADED; | 661 | mc->mca_flags |= MAF_LOADED; |
| 716 | if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) | 662 | if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) |
| 717 | dev_mc_add(dev, buf, dev->addr_len, 0); | 663 | dev_mc_add(dev, buf); |
| 718 | } | 664 | } |
| 719 | spin_unlock_bh(&mc->mca_lock); | 665 | spin_unlock_bh(&mc->mca_lock); |
| 720 | 666 | ||
| @@ -740,7 +686,7 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc) | |||
| 740 | if (mc->mca_flags&MAF_LOADED) { | 686 | if (mc->mca_flags&MAF_LOADED) { |
| 741 | mc->mca_flags &= ~MAF_LOADED; | 687 | mc->mca_flags &= ~MAF_LOADED; |
| 742 | if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) | 688 | if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) |
| 743 | dev_mc_delete(dev, buf, dev->addr_len, 0); | 689 | dev_mc_del(dev, buf); |
| 744 | } | 690 | } |
| 745 | 691 | ||
| 746 | if (mc->mca_flags & MAF_NOREPORT) | 692 | if (mc->mca_flags & MAF_NOREPORT) |
| @@ -793,10 +739,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
| 793 | } | 739 | } |
| 794 | spin_unlock_bh(&im->mca_lock); | 740 | spin_unlock_bh(&im->mca_lock); |
| 795 | 741 | ||
| 796 | write_lock_bh(&idev->mc_lock); | 742 | spin_lock_bh(&idev->mc_lock); |
| 797 | pmc->next = idev->mc_tomb; | 743 | pmc->next = idev->mc_tomb; |
| 798 | idev->mc_tomb = pmc; | 744 | idev->mc_tomb = pmc; |
| 799 | write_unlock_bh(&idev->mc_lock); | 745 | spin_unlock_bh(&idev->mc_lock); |
| 800 | } | 746 | } |
| 801 | 747 | ||
| 802 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | 748 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) |
| @@ -804,7 +750,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
| 804 | struct ifmcaddr6 *pmc, *pmc_prev; | 750 | struct ifmcaddr6 *pmc, *pmc_prev; |
| 805 | struct ip6_sf_list *psf, *psf_next; | 751 | struct ip6_sf_list *psf, *psf_next; |
| 806 | 752 | ||
| 807 | write_lock_bh(&idev->mc_lock); | 753 | spin_lock_bh(&idev->mc_lock); |
| 808 | pmc_prev = NULL; | 754 | pmc_prev = NULL; |
| 809 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { | 755 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { |
| 810 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) | 756 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) |
| @@ -817,7 +763,8 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
| 817 | else | 763 | else |
| 818 | idev->mc_tomb = pmc->next; | 764 | idev->mc_tomb = pmc->next; |
| 819 | } | 765 | } |
| 820 | write_unlock_bh(&idev->mc_lock); | 766 | spin_unlock_bh(&idev->mc_lock); |
| 767 | |||
| 821 | if (pmc) { | 768 | if (pmc) { |
| 822 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { | 769 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { |
| 823 | psf_next = psf->sf_next; | 770 | psf_next = psf->sf_next; |
| @@ -832,10 +779,10 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
| 832 | { | 779 | { |
| 833 | struct ifmcaddr6 *pmc, *nextpmc; | 780 | struct ifmcaddr6 *pmc, *nextpmc; |
| 834 | 781 | ||
| 835 | write_lock_bh(&idev->mc_lock); | 782 | spin_lock_bh(&idev->mc_lock); |
| 836 | pmc = idev->mc_tomb; | 783 | pmc = idev->mc_tomb; |
| 837 | idev->mc_tomb = NULL; | 784 | idev->mc_tomb = NULL; |
| 838 | write_unlock_bh(&idev->mc_lock); | 785 | spin_unlock_bh(&idev->mc_lock); |
| 839 | 786 | ||
| 840 | for (; pmc; pmc = nextpmc) { | 787 | for (; pmc; pmc = nextpmc) { |
| 841 | nextpmc = pmc->next; | 788 | nextpmc = pmc->next; |
| @@ -870,6 +817,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) | |||
| 870 | struct ifmcaddr6 *mc; | 817 | struct ifmcaddr6 *mc; |
| 871 | struct inet6_dev *idev; | 818 | struct inet6_dev *idev; |
| 872 | 819 | ||
| 820 | /* we need to take a reference on idev */ | ||
| 873 | idev = in6_dev_get(dev); | 821 | idev = in6_dev_get(dev); |
| 874 | 822 | ||
| 875 | if (idev == NULL) | 823 | if (idev == NULL) |
| @@ -908,7 +856,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) | |||
| 908 | setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); | 856 | setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); |
| 909 | 857 | ||
| 910 | ipv6_addr_copy(&mc->mca_addr, addr); | 858 | ipv6_addr_copy(&mc->mca_addr, addr); |
| 911 | mc->idev = idev; | 859 | mc->idev = idev; /* (reference taken) */ |
| 912 | mc->mca_users = 1; | 860 | mc->mca_users = 1; |
| 913 | /* mca_stamp should be updated upon changes */ | 861 | /* mca_stamp should be updated upon changes */ |
| 914 | mc->mca_cstamp = mc->mca_tstamp = jiffies; | 862 | mc->mca_cstamp = mc->mca_tstamp = jiffies; |
| @@ -963,16 +911,18 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) | |||
| 963 | 911 | ||
| 964 | int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) | 912 | int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) |
| 965 | { | 913 | { |
| 966 | struct inet6_dev *idev = in6_dev_get(dev); | 914 | struct inet6_dev *idev; |
| 967 | int err; | 915 | int err; |
| 968 | 916 | ||
| 969 | if (!idev) | 917 | rcu_read_lock(); |
| 970 | return -ENODEV; | ||
| 971 | |||
| 972 | err = __ipv6_dev_mc_dec(idev, addr); | ||
| 973 | 918 | ||
| 974 | in6_dev_put(idev); | 919 | idev = __in6_dev_get(dev); |
| 920 | if (!idev) | ||
| 921 | err = -ENODEV; | ||
| 922 | else | ||
| 923 | err = __ipv6_dev_mc_dec(idev, addr); | ||
| 975 | 924 | ||
| 925 | rcu_read_unlock(); | ||
| 976 | return err; | 926 | return err; |
| 977 | } | 927 | } |
| 978 | 928 | ||
| @@ -1013,7 +963,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
| 1013 | struct ifmcaddr6 *mc; | 963 | struct ifmcaddr6 *mc; |
| 1014 | int rv = 0; | 964 | int rv = 0; |
| 1015 | 965 | ||
| 1016 | idev = in6_dev_get(dev); | 966 | rcu_read_lock(); |
| 967 | idev = __in6_dev_get(dev); | ||
| 1017 | if (idev) { | 968 | if (idev) { |
| 1018 | read_lock_bh(&idev->lock); | 969 | read_lock_bh(&idev->lock); |
| 1019 | for (mc = idev->mc_list; mc; mc=mc->next) { | 970 | for (mc = idev->mc_list; mc; mc=mc->next) { |
| @@ -1040,8 +991,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
| 1040 | rv = 1; /* don't filter unspecified source */ | 991 | rv = 1; /* don't filter unspecified source */ |
| 1041 | } | 992 | } |
| 1042 | read_unlock_bh(&idev->lock); | 993 | read_unlock_bh(&idev->lock); |
| 1043 | in6_dev_put(idev); | ||
| 1044 | } | 994 | } |
| 995 | rcu_read_unlock(); | ||
| 1045 | return rv; | 996 | return rv; |
| 1046 | } | 997 | } |
| 1047 | 998 | ||
| @@ -1152,6 +1103,7 @@ static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
| 1152 | return 1; | 1103 | return 1; |
| 1153 | } | 1104 | } |
| 1154 | 1105 | ||
| 1106 | /* called with rcu_read_lock() */ | ||
| 1155 | int igmp6_event_query(struct sk_buff *skb) | 1107 | int igmp6_event_query(struct sk_buff *skb) |
| 1156 | { | 1108 | { |
| 1157 | struct mld2_query *mlh2 = NULL; | 1109 | struct mld2_query *mlh2 = NULL; |
| @@ -1159,7 +1111,7 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1159 | struct in6_addr *group; | 1111 | struct in6_addr *group; |
| 1160 | unsigned long max_delay; | 1112 | unsigned long max_delay; |
| 1161 | struct inet6_dev *idev; | 1113 | struct inet6_dev *idev; |
| 1162 | struct icmp6hdr *hdr; | 1114 | struct mld_msg *mld; |
| 1163 | int group_type; | 1115 | int group_type; |
| 1164 | int mark = 0; | 1116 | int mark = 0; |
| 1165 | int len; | 1117 | int len; |
| @@ -1175,27 +1127,25 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1175 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) | 1127 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) |
| 1176 | return -EINVAL; | 1128 | return -EINVAL; |
| 1177 | 1129 | ||
| 1178 | idev = in6_dev_get(skb->dev); | 1130 | idev = __in6_dev_get(skb->dev); |
| 1179 | 1131 | ||
| 1180 | if (idev == NULL) | 1132 | if (idev == NULL) |
| 1181 | return 0; | 1133 | return 0; |
| 1182 | 1134 | ||
| 1183 | hdr = icmp6_hdr(skb); | 1135 | mld = (struct mld_msg *)icmp6_hdr(skb); |
| 1184 | group = (struct in6_addr *) (hdr + 1); | 1136 | group = &mld->mld_mca; |
| 1185 | group_type = ipv6_addr_type(group); | 1137 | group_type = ipv6_addr_type(group); |
| 1186 | 1138 | ||
| 1187 | if (group_type != IPV6_ADDR_ANY && | 1139 | if (group_type != IPV6_ADDR_ANY && |
| 1188 | !(group_type&IPV6_ADDR_MULTICAST)) { | 1140 | !(group_type&IPV6_ADDR_MULTICAST)) |
| 1189 | in6_dev_put(idev); | ||
| 1190 | return -EINVAL; | 1141 | return -EINVAL; |
| 1191 | } | ||
| 1192 | 1142 | ||
| 1193 | if (len == 24) { | 1143 | if (len == 24) { |
| 1194 | int switchback; | 1144 | int switchback; |
| 1195 | /* MLDv1 router present */ | 1145 | /* MLDv1 router present */ |
| 1196 | 1146 | ||
| 1197 | /* Translate milliseconds to jiffies */ | 1147 | /* Translate milliseconds to jiffies */ |
| 1198 | max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000; | 1148 | max_delay = (ntohs(mld->mld_maxdelay)*HZ)/1000; |
| 1199 | 1149 | ||
| 1200 | switchback = (idev->mc_qrv + 1) * max_delay; | 1150 | switchback = (idev->mc_qrv + 1) * max_delay; |
| 1201 | idev->mc_v1_seen = jiffies + switchback; | 1151 | idev->mc_v1_seen = jiffies + switchback; |
| @@ -1209,40 +1159,34 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1209 | } else if (len >= 28) { | 1159 | } else if (len >= 28) { |
| 1210 | int srcs_offset = sizeof(struct mld2_query) - | 1160 | int srcs_offset = sizeof(struct mld2_query) - |
| 1211 | sizeof(struct icmp6hdr); | 1161 | sizeof(struct icmp6hdr); |
| 1212 | if (!pskb_may_pull(skb, srcs_offset)) { | 1162 | if (!pskb_may_pull(skb, srcs_offset)) |
| 1213 | in6_dev_put(idev); | ||
| 1214 | return -EINVAL; | 1163 | return -EINVAL; |
| 1215 | } | 1164 | |
| 1216 | mlh2 = (struct mld2_query *)skb_transport_header(skb); | 1165 | mlh2 = (struct mld2_query *)skb_transport_header(skb); |
| 1217 | max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; | 1166 | max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000; |
| 1218 | if (!max_delay) | 1167 | if (!max_delay) |
| 1219 | max_delay = 1; | 1168 | max_delay = 1; |
| 1220 | idev->mc_maxdelay = max_delay; | 1169 | idev->mc_maxdelay = max_delay; |
| 1221 | if (mlh2->qrv) | 1170 | if (mlh2->mld2q_qrv) |
| 1222 | idev->mc_qrv = mlh2->qrv; | 1171 | idev->mc_qrv = mlh2->mld2q_qrv; |
| 1223 | if (group_type == IPV6_ADDR_ANY) { /* general query */ | 1172 | if (group_type == IPV6_ADDR_ANY) { /* general query */ |
| 1224 | if (mlh2->nsrcs) { | 1173 | if (mlh2->mld2q_nsrcs) |
| 1225 | in6_dev_put(idev); | ||
| 1226 | return -EINVAL; /* no sources allowed */ | 1174 | return -EINVAL; /* no sources allowed */ |
| 1227 | } | 1175 | |
| 1228 | mld_gq_start_timer(idev); | 1176 | mld_gq_start_timer(idev); |
| 1229 | in6_dev_put(idev); | ||
| 1230 | return 0; | 1177 | return 0; |
| 1231 | } | 1178 | } |
| 1232 | /* mark sources to include, if group & source-specific */ | 1179 | /* mark sources to include, if group & source-specific */ |
| 1233 | if (mlh2->nsrcs != 0) { | 1180 | if (mlh2->mld2q_nsrcs != 0) { |
| 1234 | if (!pskb_may_pull(skb, srcs_offset + | 1181 | if (!pskb_may_pull(skb, srcs_offset + |
| 1235 | ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) { | 1182 | ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) |
| 1236 | in6_dev_put(idev); | ||
| 1237 | return -EINVAL; | 1183 | return -EINVAL; |
| 1238 | } | 1184 | |
| 1239 | mlh2 = (struct mld2_query *)skb_transport_header(skb); | 1185 | mlh2 = (struct mld2_query *)skb_transport_header(skb); |
| 1240 | mark = 1; | 1186 | mark = 1; |
| 1241 | } | 1187 | } |
| 1242 | } else { | 1188 | } else |
| 1243 | in6_dev_put(idev); | ||
| 1244 | return -EINVAL; | 1189 | return -EINVAL; |
| 1245 | } | ||
| 1246 | 1190 | ||
| 1247 | read_lock_bh(&idev->lock); | 1191 | read_lock_bh(&idev->lock); |
| 1248 | if (group_type == IPV6_ADDR_ANY) { | 1192 | if (group_type == IPV6_ADDR_ANY) { |
| @@ -1268,25 +1212,23 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1268 | ma->mca_flags &= ~MAF_GSQUERY; | 1212 | ma->mca_flags &= ~MAF_GSQUERY; |
| 1269 | } | 1213 | } |
| 1270 | if (!(ma->mca_flags & MAF_GSQUERY) || | 1214 | if (!(ma->mca_flags & MAF_GSQUERY) || |
| 1271 | mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) | 1215 | mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs)) |
| 1272 | igmp6_group_queried(ma, max_delay); | 1216 | igmp6_group_queried(ma, max_delay); |
| 1273 | spin_unlock_bh(&ma->mca_lock); | 1217 | spin_unlock_bh(&ma->mca_lock); |
| 1274 | break; | 1218 | break; |
| 1275 | } | 1219 | } |
| 1276 | } | 1220 | } |
| 1277 | read_unlock_bh(&idev->lock); | 1221 | read_unlock_bh(&idev->lock); |
| 1278 | in6_dev_put(idev); | ||
| 1279 | 1222 | ||
| 1280 | return 0; | 1223 | return 0; |
| 1281 | } | 1224 | } |
| 1282 | 1225 | ||
| 1283 | 1226 | /* called with rcu_read_lock() */ | |
| 1284 | int igmp6_event_report(struct sk_buff *skb) | 1227 | int igmp6_event_report(struct sk_buff *skb) |
| 1285 | { | 1228 | { |
| 1286 | struct ifmcaddr6 *ma; | 1229 | struct ifmcaddr6 *ma; |
| 1287 | struct in6_addr *addrp; | ||
| 1288 | struct inet6_dev *idev; | 1230 | struct inet6_dev *idev; |
| 1289 | struct icmp6hdr *hdr; | 1231 | struct mld_msg *mld; |
| 1290 | int addr_type; | 1232 | int addr_type; |
| 1291 | 1233 | ||
| 1292 | /* Our own report looped back. Ignore it. */ | 1234 | /* Our own report looped back. Ignore it. */ |
| @@ -1298,10 +1240,10 @@ int igmp6_event_report(struct sk_buff *skb) | |||
| 1298 | skb->pkt_type != PACKET_BROADCAST) | 1240 | skb->pkt_type != PACKET_BROADCAST) |
| 1299 | return 0; | 1241 | return 0; |
| 1300 | 1242 | ||
| 1301 | if (!pskb_may_pull(skb, sizeof(struct in6_addr))) | 1243 | if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr))) |
| 1302 | return -EINVAL; | 1244 | return -EINVAL; |
| 1303 | 1245 | ||
| 1304 | hdr = icmp6_hdr(skb); | 1246 | mld = (struct mld_msg *)icmp6_hdr(skb); |
| 1305 | 1247 | ||
| 1306 | /* Drop reports with not link local source */ | 1248 | /* Drop reports with not link local source */ |
| 1307 | addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr); | 1249 | addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr); |
| @@ -1309,9 +1251,7 @@ int igmp6_event_report(struct sk_buff *skb) | |||
| 1309 | !(addr_type&IPV6_ADDR_LINKLOCAL)) | 1251 | !(addr_type&IPV6_ADDR_LINKLOCAL)) |
| 1310 | return -EINVAL; | 1252 | return -EINVAL; |
| 1311 | 1253 | ||
| 1312 | addrp = (struct in6_addr *) (hdr + 1); | 1254 | idev = __in6_dev_get(skb->dev); |
| 1313 | |||
| 1314 | idev = in6_dev_get(skb->dev); | ||
| 1315 | if (idev == NULL) | 1255 | if (idev == NULL) |
| 1316 | return -ENODEV; | 1256 | return -ENODEV; |
| 1317 | 1257 | ||
| @@ -1321,7 +1261,7 @@ int igmp6_event_report(struct sk_buff *skb) | |||
| 1321 | 1261 | ||
| 1322 | read_lock_bh(&idev->lock); | 1262 | read_lock_bh(&idev->lock); |
| 1323 | for (ma = idev->mc_list; ma; ma=ma->next) { | 1263 | for (ma = idev->mc_list; ma; ma=ma->next) { |
| 1324 | if (ipv6_addr_equal(&ma->mca_addr, addrp)) { | 1264 | if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) { |
| 1325 | spin_lock(&ma->mca_lock); | 1265 | spin_lock(&ma->mca_lock); |
| 1326 | if (del_timer(&ma->mca_timer)) | 1266 | if (del_timer(&ma->mca_timer)) |
| 1327 | atomic_dec(&ma->mca_refcnt); | 1267 | atomic_dec(&ma->mca_refcnt); |
| @@ -1331,7 +1271,6 @@ int igmp6_event_report(struct sk_buff *skb) | |||
| 1331 | } | 1271 | } |
| 1332 | } | 1272 | } |
| 1333 | read_unlock_bh(&idev->lock); | 1273 | read_unlock_bh(&idev->lock); |
| 1334 | in6_dev_put(idev); | ||
| 1335 | return 0; | 1274 | return 0; |
| 1336 | } | 1275 | } |
| 1337 | 1276 | ||
| @@ -1407,7 +1346,10 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
| 1407 | IPV6_TLV_PADN, 0 }; | 1346 | IPV6_TLV_PADN, 0 }; |
| 1408 | 1347 | ||
| 1409 | /* we assume size > sizeof(ra) here */ | 1348 | /* we assume size > sizeof(ra) here */ |
| 1410 | skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err); | 1349 | size += LL_ALLOCATED_SPACE(dev); |
| 1350 | /* limit our allocations to order-0 page */ | ||
| 1351 | size = min_t(int, size, SKB_MAX_ORDER(0, 0)); | ||
| 1352 | skb = sock_alloc_send_skb(sk, size, 1, &err); | ||
| 1411 | 1353 | ||
| 1412 | if (!skb) | 1354 | if (!skb) |
| 1413 | return NULL; | 1355 | return NULL; |
| @@ -1430,11 +1372,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
| 1430 | skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data); | 1372 | skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data); |
| 1431 | skb_put(skb, sizeof(*pmr)); | 1373 | skb_put(skb, sizeof(*pmr)); |
| 1432 | pmr = (struct mld2_report *)skb_transport_header(skb); | 1374 | pmr = (struct mld2_report *)skb_transport_header(skb); |
| 1433 | pmr->type = ICMPV6_MLD2_REPORT; | 1375 | pmr->mld2r_type = ICMPV6_MLD2_REPORT; |
| 1434 | pmr->resv1 = 0; | 1376 | pmr->mld2r_resv1 = 0; |
| 1435 | pmr->csum = 0; | 1377 | pmr->mld2r_cksum = 0; |
| 1436 | pmr->resv2 = 0; | 1378 | pmr->mld2r_resv2 = 0; |
| 1437 | pmr->ngrec = 0; | 1379 | pmr->mld2r_ngrec = 0; |
| 1438 | return skb; | 1380 | return skb; |
| 1439 | } | 1381 | } |
| 1440 | 1382 | ||
| @@ -1444,21 +1386,24 @@ static void mld_sendpack(struct sk_buff *skb) | |||
| 1444 | struct mld2_report *pmr = | 1386 | struct mld2_report *pmr = |
| 1445 | (struct mld2_report *)skb_transport_header(skb); | 1387 | (struct mld2_report *)skb_transport_header(skb); |
| 1446 | int payload_len, mldlen; | 1388 | int payload_len, mldlen; |
| 1447 | struct inet6_dev *idev = in6_dev_get(skb->dev); | 1389 | struct inet6_dev *idev; |
| 1448 | struct net *net = dev_net(skb->dev); | 1390 | struct net *net = dev_net(skb->dev); |
| 1449 | int err; | 1391 | int err; |
| 1450 | struct flowi fl; | 1392 | struct flowi fl; |
| 1451 | struct dst_entry *dst; | 1393 | struct dst_entry *dst; |
| 1452 | 1394 | ||
| 1395 | rcu_read_lock(); | ||
| 1396 | idev = __in6_dev_get(skb->dev); | ||
| 1453 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | 1397 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
| 1454 | 1398 | ||
| 1455 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); | 1399 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); |
| 1456 | mldlen = skb->tail - skb->transport_header; | 1400 | mldlen = skb->tail - skb->transport_header; |
| 1457 | pip6->payload_len = htons(payload_len); | 1401 | pip6->payload_len = htons(payload_len); |
| 1458 | 1402 | ||
| 1459 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, | 1403 | pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, |
| 1460 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), | 1404 | IPPROTO_ICMPV6, |
| 1461 | mldlen, 0)); | 1405 | csum_partial(skb_transport_header(skb), |
| 1406 | mldlen, 0)); | ||
| 1462 | 1407 | ||
| 1463 | dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | 1408 | dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); |
| 1464 | 1409 | ||
| @@ -1478,7 +1423,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
| 1478 | 1423 | ||
| 1479 | payload_len = skb->len; | 1424 | payload_len = skb->len; |
| 1480 | 1425 | ||
| 1481 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1426 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
| 1482 | dst_output); | 1427 | dst_output); |
| 1483 | out: | 1428 | out: |
| 1484 | if (!err) { | 1429 | if (!err) { |
| @@ -1488,8 +1433,7 @@ out: | |||
| 1488 | } else | 1433 | } else |
| 1489 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS); | 1434 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS); |
| 1490 | 1435 | ||
| 1491 | if (likely(idev != NULL)) | 1436 | rcu_read_unlock(); |
| 1492 | in6_dev_put(idev); | ||
| 1493 | return; | 1437 | return; |
| 1494 | 1438 | ||
| 1495 | err_out: | 1439 | err_out: |
| @@ -1519,7 +1463,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, | |||
| 1519 | pgr->grec_nsrcs = 0; | 1463 | pgr->grec_nsrcs = 0; |
| 1520 | pgr->grec_mca = pmc->mca_addr; /* structure copy */ | 1464 | pgr->grec_mca = pmc->mca_addr; /* structure copy */ |
| 1521 | pmr = (struct mld2_report *)skb_transport_header(skb); | 1465 | pmr = (struct mld2_report *)skb_transport_header(skb); |
| 1522 | pmr->ngrec = htons(ntohs(pmr->ngrec)+1); | 1466 | pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1); |
| 1523 | *ppgr = pgr; | 1467 | *ppgr = pgr; |
| 1524 | return skb; | 1468 | return skb; |
| 1525 | } | 1469 | } |
| @@ -1555,7 +1499,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, | |||
| 1555 | 1499 | ||
| 1556 | /* EX and TO_EX get a fresh packet, if needed */ | 1500 | /* EX and TO_EX get a fresh packet, if needed */ |
| 1557 | if (truncate) { | 1501 | if (truncate) { |
| 1558 | if (pmr && pmr->ngrec && | 1502 | if (pmr && pmr->mld2r_ngrec && |
| 1559 | AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { | 1503 | AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { |
| 1560 | if (skb) | 1504 | if (skb) |
| 1561 | mld_sendpack(skb); | 1505 | mld_sendpack(skb); |
| @@ -1696,7 +1640,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
| 1696 | int type, dtype; | 1640 | int type, dtype; |
| 1697 | 1641 | ||
| 1698 | read_lock_bh(&idev->lock); | 1642 | read_lock_bh(&idev->lock); |
| 1699 | write_lock_bh(&idev->mc_lock); | 1643 | spin_lock(&idev->mc_lock); |
| 1700 | 1644 | ||
| 1701 | /* deleted MCA's */ | 1645 | /* deleted MCA's */ |
| 1702 | pmc_prev = NULL; | 1646 | pmc_prev = NULL; |
| @@ -1730,7 +1674,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
| 1730 | } else | 1674 | } else |
| 1731 | pmc_prev = pmc; | 1675 | pmc_prev = pmc; |
| 1732 | } | 1676 | } |
| 1733 | write_unlock_bh(&idev->mc_lock); | 1677 | spin_unlock(&idev->mc_lock); |
| 1734 | 1678 | ||
| 1735 | /* change recs */ | 1679 | /* change recs */ |
| 1736 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1680 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
| @@ -1768,9 +1712,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
| 1768 | struct sock *sk = net->ipv6.igmp_sk; | 1712 | struct sock *sk = net->ipv6.igmp_sk; |
| 1769 | struct inet6_dev *idev; | 1713 | struct inet6_dev *idev; |
| 1770 | struct sk_buff *skb; | 1714 | struct sk_buff *skb; |
| 1771 | struct icmp6hdr *hdr; | 1715 | struct mld_msg *hdr; |
| 1772 | const struct in6_addr *snd_addr, *saddr; | 1716 | const struct in6_addr *snd_addr, *saddr; |
| 1773 | struct in6_addr *addrp; | ||
| 1774 | struct in6_addr addr_buf; | 1717 | struct in6_addr addr_buf; |
| 1775 | int err, len, payload_len, full_len; | 1718 | int err, len, payload_len, full_len; |
| 1776 | u8 ra[8] = { IPPROTO_ICMPV6, 0, | 1719 | u8 ra[8] = { IPPROTO_ICMPV6, 0, |
| @@ -1818,18 +1761,17 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
| 1818 | 1761 | ||
| 1819 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1762 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
| 1820 | 1763 | ||
| 1821 | hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr)); | 1764 | hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg)); |
| 1822 | memset(hdr, 0, sizeof(struct icmp6hdr)); | 1765 | memset(hdr, 0, sizeof(struct mld_msg)); |
| 1823 | hdr->icmp6_type = type; | 1766 | hdr->mld_type = type; |
| 1824 | 1767 | ipv6_addr_copy(&hdr->mld_mca, addr); | |
| 1825 | addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); | ||
| 1826 | ipv6_addr_copy(addrp, addr); | ||
| 1827 | 1768 | ||
| 1828 | hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len, | 1769 | hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len, |
| 1829 | IPPROTO_ICMPV6, | 1770 | IPPROTO_ICMPV6, |
| 1830 | csum_partial(hdr, len, 0)); | 1771 | csum_partial(hdr, len, 0)); |
| 1831 | 1772 | ||
| 1832 | idev = in6_dev_get(skb->dev); | 1773 | rcu_read_lock(); |
| 1774 | idev = __in6_dev_get(skb->dev); | ||
| 1833 | 1775 | ||
| 1834 | dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | 1776 | dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); |
| 1835 | if (!dst) { | 1777 | if (!dst) { |
| @@ -1846,7 +1788,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
| 1846 | goto err_out; | 1788 | goto err_out; |
| 1847 | 1789 | ||
| 1848 | skb_dst_set(skb, dst); | 1790 | skb_dst_set(skb, dst); |
| 1849 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1791 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
| 1850 | dst_output); | 1792 | dst_output); |
| 1851 | out: | 1793 | out: |
| 1852 | if (!err) { | 1794 | if (!err) { |
| @@ -1856,8 +1798,7 @@ out: | |||
| 1856 | } else | 1798 | } else |
| 1857 | IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); | 1799 | IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); |
| 1858 | 1800 | ||
| 1859 | if (likely(idev != NULL)) | 1801 | rcu_read_unlock(); |
| 1860 | in6_dev_put(idev); | ||
| 1861 | return; | 1802 | return; |
| 1862 | 1803 | ||
| 1863 | err_out: | 1804 | err_out: |
| @@ -2048,8 +1989,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc) | |||
| 2048 | &psf->sf_addr)) | 1989 | &psf->sf_addr)) |
| 2049 | break; | 1990 | break; |
| 2050 | if (!dpsf) { | 1991 | if (!dpsf) { |
| 2051 | dpsf = (struct ip6_sf_list *) | 1992 | dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC); |
| 2052 | kmalloc(sizeof(*dpsf), GFP_ATOMIC); | ||
| 2053 | if (!dpsf) | 1993 | if (!dpsf) |
| 2054 | continue; | 1994 | continue; |
| 2055 | *dpsf = *psf; | 1995 | *dpsf = *psf; |
| @@ -2311,7 +2251,7 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
| 2311 | void ipv6_mc_init_dev(struct inet6_dev *idev) | 2251 | void ipv6_mc_init_dev(struct inet6_dev *idev) |
| 2312 | { | 2252 | { |
| 2313 | write_lock_bh(&idev->lock); | 2253 | write_lock_bh(&idev->lock); |
| 2314 | rwlock_init(&idev->mc_lock); | 2254 | spin_lock_init(&idev->mc_lock); |
| 2315 | idev->mc_gq_running = 0; | 2255 | idev->mc_gq_running = 0; |
| 2316 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, | 2256 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, |
| 2317 | (unsigned long)idev); | 2257 | (unsigned long)idev); |
| @@ -2646,7 +2586,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
| 2646 | .release = seq_release_net, | 2586 | .release = seq_release_net, |
| 2647 | }; | 2587 | }; |
| 2648 | 2588 | ||
| 2649 | static int igmp6_proc_init(struct net *net) | 2589 | static int __net_init igmp6_proc_init(struct net *net) |
| 2650 | { | 2590 | { |
| 2651 | int err; | 2591 | int err; |
| 2652 | 2592 | ||
| @@ -2666,23 +2606,22 @@ out_proc_net_igmp6: | |||
| 2666 | goto out; | 2606 | goto out; |
| 2667 | } | 2607 | } |
| 2668 | 2608 | ||
| 2669 | static void igmp6_proc_exit(struct net *net) | 2609 | static void __net_exit igmp6_proc_exit(struct net *net) |
| 2670 | { | 2610 | { |
| 2671 | proc_net_remove(net, "mcfilter6"); | 2611 | proc_net_remove(net, "mcfilter6"); |
| 2672 | proc_net_remove(net, "igmp6"); | 2612 | proc_net_remove(net, "igmp6"); |
| 2673 | } | 2613 | } |
| 2674 | #else | 2614 | #else |
| 2675 | static int igmp6_proc_init(struct net *net) | 2615 | static inline int igmp6_proc_init(struct net *net) |
| 2676 | { | 2616 | { |
| 2677 | return 0; | 2617 | return 0; |
| 2678 | } | 2618 | } |
| 2679 | static void igmp6_proc_exit(struct net *net) | 2619 | static inline void igmp6_proc_exit(struct net *net) |
| 2680 | { | 2620 | { |
| 2681 | ; | ||
| 2682 | } | 2621 | } |
| 2683 | #endif | 2622 | #endif |
| 2684 | 2623 | ||
| 2685 | static int igmp6_net_init(struct net *net) | 2624 | static int __net_init igmp6_net_init(struct net *net) |
| 2686 | { | 2625 | { |
| 2687 | int err; | 2626 | int err; |
| 2688 | 2627 | ||
| @@ -2708,7 +2647,7 @@ out_sock_create: | |||
| 2708 | goto out; | 2647 | goto out; |
| 2709 | } | 2648 | } |
| 2710 | 2649 | ||
| 2711 | static void igmp6_net_exit(struct net *net) | 2650 | static void __net_exit igmp6_net_exit(struct net *net) |
| 2712 | { | 2651 | { |
| 2713 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2652 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
| 2714 | igmp6_proc_exit(net); | 2653 | igmp6_proc_exit(net); |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index f797e8c6f3b3..d6e9599d0705 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
| @@ -56,7 +56,7 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen) | |||
| 56 | 56 | ||
| 57 | static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) | 57 | static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) |
| 58 | { | 58 | { |
| 59 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | 59 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static int mip6_mh_len(int type) | 62 | static int mip6_mh_len(int type) |
| @@ -347,11 +347,12 @@ static const struct xfrm_type mip6_destopt_type = | |||
| 347 | 347 | ||
| 348 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) | 348 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) |
| 349 | { | 349 | { |
| 350 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 350 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; | 351 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; |
| 351 | int err = rt2->rt_hdr.nexthdr; | 352 | int err = rt2->rt_hdr.nexthdr; |
| 352 | 353 | ||
| 353 | spin_lock(&x->lock); | 354 | spin_lock(&x->lock); |
| 354 | if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) && | 355 | if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) && |
| 355 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) | 356 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) |
| 356 | err = -ENOENT; | 357 | err = -ENOENT; |
| 357 | spin_unlock(&x->lock); | 358 | spin_unlock(&x->lock); |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c45852798092..58841c4ae947 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | #include <linux/route.h> | 59 | #include <linux/route.h> |
| 60 | #include <linux/init.h> | 60 | #include <linux/init.h> |
| 61 | #include <linux/rcupdate.h> | 61 | #include <linux/rcupdate.h> |
| 62 | #include <linux/slab.h> | ||
| 62 | #ifdef CONFIG_SYSCTL | 63 | #ifdef CONFIG_SYSCTL |
| 63 | #include <linux/sysctl.h> | 64 | #include <linux/sysctl.h> |
| 64 | #endif | 65 | #endif |
| @@ -535,7 +536,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
| 535 | idev = in6_dev_get(dst->dev); | 536 | idev = in6_dev_get(dst->dev); |
| 536 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | 537 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
| 537 | 538 | ||
| 538 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, | 539 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, |
| 539 | dst_output); | 540 | dst_output); |
| 540 | if (!err) { | 541 | if (!err) { |
| 541 | ICMP6MSGOUT_INC_STATS(net, idev, type); | 542 | ICMP6MSGOUT_INC_STATS(net, idev, type); |
| @@ -585,6 +586,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 585 | src_addr = solicited_addr; | 586 | src_addr = solicited_addr; |
| 586 | if (ifp->flags & IFA_F_OPTIMISTIC) | 587 | if (ifp->flags & IFA_F_OPTIMISTIC) |
| 587 | override = 0; | 588 | override = 0; |
| 589 | inc_opt |= ifp->idev->cnf.force_tllao; | ||
| 588 | in6_ifa_put(ifp); | 590 | in6_ifa_put(ifp); |
| 589 | } else { | 591 | } else { |
| 590 | if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, | 592 | if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, |
| @@ -598,7 +600,6 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
| 598 | icmp6h.icmp6_solicited = solicited; | 600 | icmp6h.icmp6_solicited = solicited; |
| 599 | icmp6h.icmp6_override = override; | 601 | icmp6h.icmp6_override = override; |
| 600 | 602 | ||
| 601 | inc_opt |= ifp->idev->cnf.force_tllao; | ||
| 602 | __ndisc_send(dev, neigh, daddr, src_addr, | 603 | __ndisc_send(dev, neigh, daddr, src_addr, |
| 603 | &icmp6h, solicited_addr, | 604 | &icmp6h, solicited_addr, |
| 604 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 605 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
| @@ -889,8 +890,6 @@ out: | |||
| 889 | in6_ifa_put(ifp); | 890 | in6_ifa_put(ifp); |
| 890 | else | 891 | else |
| 891 | in6_dev_put(idev); | 892 | in6_dev_put(idev); |
| 892 | |||
| 893 | return; | ||
| 894 | } | 893 | } |
| 895 | 894 | ||
| 896 | static void ndisc_recv_na(struct sk_buff *skb) | 895 | static void ndisc_recv_na(struct sk_buff *skb) |
| @@ -1230,7 +1229,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1230 | ND_PRINTK0(KERN_ERR | 1229 | ND_PRINTK0(KERN_ERR |
| 1231 | "ICMPv6 RA: %s() got default router without neighbour.\n", | 1230 | "ICMPv6 RA: %s() got default router without neighbour.\n", |
| 1232 | __func__); | 1231 | __func__); |
| 1233 | dst_release(&rt->u.dst); | 1232 | dst_release(&rt->dst); |
| 1234 | in6_dev_put(in6_dev); | 1233 | in6_dev_put(in6_dev); |
| 1235 | return; | 1234 | return; |
| 1236 | } | 1235 | } |
| @@ -1245,7 +1244,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
| 1245 | if (ra_msg->icmph.icmp6_hop_limit) { | 1244 | if (ra_msg->icmph.icmp6_hop_limit) { |
| 1246 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; | 1245 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; |
| 1247 | if (rt) | 1246 | if (rt) |
| 1248 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; | 1247 | rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; |
| 1249 | } | 1248 | } |
| 1250 | 1249 | ||
| 1251 | skip_defrtr: | 1250 | skip_defrtr: |
| @@ -1364,7 +1363,7 @@ skip_linkparms: | |||
| 1364 | in6_dev->cnf.mtu6 = mtu; | 1363 | in6_dev->cnf.mtu6 = mtu; |
| 1365 | 1364 | ||
| 1366 | if (rt) | 1365 | if (rt) |
| 1367 | rt->u.dst.metrics[RTAX_MTU-1] = mtu; | 1366 | rt->dst.metrics[RTAX_MTU-1] = mtu; |
| 1368 | 1367 | ||
| 1369 | rt6_mtu_change(skb->dev, mtu); | 1368 | rt6_mtu_change(skb->dev, mtu); |
| 1370 | } | 1369 | } |
| @@ -1385,7 +1384,7 @@ skip_linkparms: | |||
| 1385 | } | 1384 | } |
| 1386 | out: | 1385 | out: |
| 1387 | if (rt) | 1386 | if (rt) |
| 1388 | dst_release(&rt->u.dst); | 1387 | dst_release(&rt->dst); |
| 1389 | else if (neigh) | 1388 | else if (neigh) |
| 1390 | neigh_release(neigh); | 1389 | neigh_release(neigh); |
| 1391 | in6_dev_put(in6_dev); | 1390 | in6_dev_put(in6_dev); |
| @@ -1617,7 +1616,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
| 1617 | skb_dst_set(buff, dst); | 1616 | skb_dst_set(buff, dst); |
| 1618 | idev = in6_dev_get(dst->dev); | 1617 | idev = in6_dev_get(dst->dev); |
| 1619 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | 1618 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
| 1620 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, | 1619 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, |
| 1621 | dst_output); | 1620 | dst_output); |
| 1622 | if (!err) { | 1621 | if (!err) { |
| 1623 | ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); | 1622 | ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); |
| @@ -1772,7 +1771,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu | |||
| 1772 | 1771 | ||
| 1773 | #endif | 1772 | #endif |
| 1774 | 1773 | ||
| 1775 | static int ndisc_net_init(struct net *net) | 1774 | static int __net_init ndisc_net_init(struct net *net) |
| 1776 | { | 1775 | { |
| 1777 | struct ipv6_pinfo *np; | 1776 | struct ipv6_pinfo *np; |
| 1778 | struct sock *sk; | 1777 | struct sock *sk; |
| @@ -1797,7 +1796,7 @@ static int ndisc_net_init(struct net *net) | |||
| 1797 | return 0; | 1796 | return 0; |
| 1798 | } | 1797 | } |
| 1799 | 1798 | ||
| 1800 | static void ndisc_net_exit(struct net *net) | 1799 | static void __net_exit ndisc_net_exit(struct net *net) |
| 1801 | { | 1800 | { |
| 1802 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); | 1801 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); |
| 1803 | } | 1802 | } |
| @@ -1820,8 +1819,7 @@ int __init ndisc_init(void) | |||
| 1820 | neigh_table_init(&nd_tbl); | 1819 | neigh_table_init(&nd_tbl); |
| 1821 | 1820 | ||
| 1822 | #ifdef CONFIG_SYSCTL | 1821 | #ifdef CONFIG_SYSCTL |
| 1823 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, | 1822 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", |
| 1824 | NET_IPV6_NEIGH, "ipv6", | ||
| 1825 | &ndisc_ifinfo_sysctl_change); | 1823 | &ndisc_ifinfo_sysctl_change); |
| 1826 | if (err) | 1824 | if (err) |
| 1827 | goto out_unregister_pernet; | 1825 | goto out_unregister_pernet; |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d5ed92b14346..7155b2451d7c 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
| @@ -25,20 +25,6 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | dst = ip6_route_output(net, skb->sk, &fl); | 27 | dst = ip6_route_output(net, skb->sk, &fl); |
| 28 | |||
| 29 | #ifdef CONFIG_XFRM | ||
| 30 | if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
| 31 | xfrm_decode_session(skb, &fl, AF_INET6) == 0) { | ||
| 32 | struct dst_entry *dst2 = skb_dst(skb); | ||
| 33 | |||
| 34 | if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) { | ||
| 35 | skb_dst_set(skb, NULL); | ||
| 36 | return -1; | ||
| 37 | } | ||
| 38 | skb_dst_set(skb, dst2); | ||
| 39 | } | ||
| 40 | #endif | ||
| 41 | |||
| 42 | if (dst->error) { | 28 | if (dst->error) { |
| 43 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 29 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
| 44 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); | 30 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); |
| @@ -50,6 +36,17 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
| 50 | skb_dst_drop(skb); | 36 | skb_dst_drop(skb); |
| 51 | 37 | ||
| 52 | skb_dst_set(skb, dst); | 38 | skb_dst_set(skb, dst); |
| 39 | |||
| 40 | #ifdef CONFIG_XFRM | ||
| 41 | if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
| 42 | xfrm_decode_session(skb, &fl, AF_INET6) == 0) { | ||
| 43 | skb_dst_set(skb, NULL); | ||
| 44 | if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) | ||
| 45 | return -1; | ||
| 46 | skb_dst_set(skb, dst); | ||
| 47 | } | ||
| 48 | #endif | ||
| 49 | |||
| 53 | return 0; | 50 | return 0; |
| 54 | } | 51 | } |
| 55 | EXPORT_SYMBOL(ip6_route_me_harder); | 52 | EXPORT_SYMBOL(ip6_route_me_harder); |
| @@ -154,9 +151,7 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, | |||
| 154 | protocol, | 151 | protocol, |
| 155 | csum_sub(0, hsum))); | 152 | csum_sub(0, hsum))); |
| 156 | skb->ip_summed = CHECKSUM_NONE; | 153 | skb->ip_summed = CHECKSUM_NONE; |
| 157 | csum = __skb_checksum_complete_head(skb, dataoff + len); | 154 | return __skb_checksum_complete_head(skb, dataoff + len); |
| 158 | if (!csum) | ||
| 159 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 160 | } | 155 | } |
| 161 | return csum; | 156 | return csum; |
| 162 | }; | 157 | }; |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 7854052be60b..413ab0754e1f 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/proc_fs.h> | 25 | #include <linux/proc_fs.h> |
| 26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
| 27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
| 28 | #include <linux/slab.h> | ||
| 28 | #include <net/net_namespace.h> | 29 | #include <net/net_namespace.h> |
| 29 | #include <net/sock.h> | 30 | #include <net/sock.h> |
| 30 | #include <net/ipv6.h> | 31 | #include <net/ipv6.h> |
| @@ -42,7 +43,7 @@ typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); | |||
| 42 | 43 | ||
| 43 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; | 44 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; |
| 44 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; | 45 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; |
| 45 | static DEFINE_RWLOCK(queue_lock); | 46 | static DEFINE_SPINLOCK(queue_lock); |
| 46 | static int peer_pid __read_mostly; | 47 | static int peer_pid __read_mostly; |
| 47 | static unsigned int copy_range __read_mostly; | 48 | static unsigned int copy_range __read_mostly; |
| 48 | static unsigned int queue_total; | 49 | static unsigned int queue_total; |
| @@ -72,10 +73,10 @@ __ipq_set_mode(unsigned char mode, unsigned int range) | |||
| 72 | break; | 73 | break; |
| 73 | 74 | ||
| 74 | case IPQ_COPY_PACKET: | 75 | case IPQ_COPY_PACKET: |
| 75 | copy_mode = mode; | 76 | if (range > 0xFFFF) |
| 77 | range = 0xFFFF; | ||
| 76 | copy_range = range; | 78 | copy_range = range; |
| 77 | if (copy_range > 0xFFFF) | 79 | copy_mode = mode; |
| 78 | copy_range = 0xFFFF; | ||
| 79 | break; | 80 | break; |
| 80 | 81 | ||
| 81 | default: | 82 | default: |
| @@ -101,7 +102,7 @@ ipq_find_dequeue_entry(unsigned long id) | |||
| 101 | { | 102 | { |
| 102 | struct nf_queue_entry *entry = NULL, *i; | 103 | struct nf_queue_entry *entry = NULL, *i; |
| 103 | 104 | ||
| 104 | write_lock_bh(&queue_lock); | 105 | spin_lock_bh(&queue_lock); |
| 105 | 106 | ||
| 106 | list_for_each_entry(i, &queue_list, list) { | 107 | list_for_each_entry(i, &queue_list, list) { |
| 107 | if ((unsigned long)i == id) { | 108 | if ((unsigned long)i == id) { |
| @@ -115,7 +116,7 @@ ipq_find_dequeue_entry(unsigned long id) | |||
| 115 | queue_total--; | 116 | queue_total--; |
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | write_unlock_bh(&queue_lock); | 119 | spin_unlock_bh(&queue_lock); |
| 119 | return entry; | 120 | return entry; |
| 120 | } | 121 | } |
| 121 | 122 | ||
| @@ -136,9 +137,9 @@ __ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | |||
| 136 | static void | 137 | static void |
| 137 | ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | 138 | ipq_flush(ipq_cmpfn cmpfn, unsigned long data) |
| 138 | { | 139 | { |
| 139 | write_lock_bh(&queue_lock); | 140 | spin_lock_bh(&queue_lock); |
| 140 | __ipq_flush(cmpfn, data); | 141 | __ipq_flush(cmpfn, data); |
| 141 | write_unlock_bh(&queue_lock); | 142 | spin_unlock_bh(&queue_lock); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | static struct sk_buff * | 145 | static struct sk_buff * |
| @@ -152,37 +153,29 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) | |||
| 152 | struct nlmsghdr *nlh; | 153 | struct nlmsghdr *nlh; |
| 153 | struct timeval tv; | 154 | struct timeval tv; |
| 154 | 155 | ||
| 155 | read_lock_bh(&queue_lock); | 156 | switch (ACCESS_ONCE(copy_mode)) { |
| 156 | |||
| 157 | switch (copy_mode) { | ||
| 158 | case IPQ_COPY_META: | 157 | case IPQ_COPY_META: |
| 159 | case IPQ_COPY_NONE: | 158 | case IPQ_COPY_NONE: |
| 160 | size = NLMSG_SPACE(sizeof(*pmsg)); | 159 | size = NLMSG_SPACE(sizeof(*pmsg)); |
| 161 | break; | 160 | break; |
| 162 | 161 | ||
| 163 | case IPQ_COPY_PACKET: | 162 | case IPQ_COPY_PACKET: |
| 164 | if ((entry->skb->ip_summed == CHECKSUM_PARTIAL || | 163 | if (entry->skb->ip_summed == CHECKSUM_PARTIAL && |
| 165 | entry->skb->ip_summed == CHECKSUM_COMPLETE) && | 164 | (*errp = skb_checksum_help(entry->skb))) |
| 166 | (*errp = skb_checksum_help(entry->skb))) { | ||
| 167 | read_unlock_bh(&queue_lock); | ||
| 168 | return NULL; | 165 | return NULL; |
| 169 | } | 166 | |
| 170 | if (copy_range == 0 || copy_range > entry->skb->len) | 167 | data_len = ACCESS_ONCE(copy_range); |
| 168 | if (data_len == 0 || data_len > entry->skb->len) | ||
| 171 | data_len = entry->skb->len; | 169 | data_len = entry->skb->len; |
| 172 | else | ||
| 173 | data_len = copy_range; | ||
| 174 | 170 | ||
| 175 | size = NLMSG_SPACE(sizeof(*pmsg) + data_len); | 171 | size = NLMSG_SPACE(sizeof(*pmsg) + data_len); |
| 176 | break; | 172 | break; |
| 177 | 173 | ||
| 178 | default: | 174 | default: |
| 179 | *errp = -EINVAL; | 175 | *errp = -EINVAL; |
| 180 | read_unlock_bh(&queue_lock); | ||
| 181 | return NULL; | 176 | return NULL; |
| 182 | } | 177 | } |
| 183 | 178 | ||
| 184 | read_unlock_bh(&queue_lock); | ||
| 185 | |||
| 186 | skb = alloc_skb(size, GFP_ATOMIC); | 179 | skb = alloc_skb(size, GFP_ATOMIC); |
| 187 | if (!skb) | 180 | if (!skb) |
| 188 | goto nlmsg_failure; | 181 | goto nlmsg_failure; |
| @@ -242,7 +235,7 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
| 242 | if (nskb == NULL) | 235 | if (nskb == NULL) |
| 243 | return status; | 236 | return status; |
| 244 | 237 | ||
| 245 | write_lock_bh(&queue_lock); | 238 | spin_lock_bh(&queue_lock); |
| 246 | 239 | ||
| 247 | if (!peer_pid) | 240 | if (!peer_pid) |
| 248 | goto err_out_free_nskb; | 241 | goto err_out_free_nskb; |
| @@ -266,14 +259,14 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | |||
| 266 | 259 | ||
| 267 | __ipq_enqueue_entry(entry); | 260 | __ipq_enqueue_entry(entry); |
| 268 | 261 | ||
| 269 | write_unlock_bh(&queue_lock); | 262 | spin_unlock_bh(&queue_lock); |
| 270 | return status; | 263 | return status; |
| 271 | 264 | ||
| 272 | err_out_free_nskb: | 265 | err_out_free_nskb: |
| 273 | kfree_skb(nskb); | 266 | kfree_skb(nskb); |
| 274 | 267 | ||
| 275 | err_out_unlock: | 268 | err_out_unlock: |
| 276 | write_unlock_bh(&queue_lock); | 269 | spin_unlock_bh(&queue_lock); |
| 277 | return status; | 270 | return status; |
| 278 | } | 271 | } |
| 279 | 272 | ||
| @@ -342,9 +335,9 @@ ipq_set_mode(unsigned char mode, unsigned int range) | |||
| 342 | { | 335 | { |
| 343 | int status; | 336 | int status; |
| 344 | 337 | ||
| 345 | write_lock_bh(&queue_lock); | 338 | spin_lock_bh(&queue_lock); |
| 346 | status = __ipq_set_mode(mode, range); | 339 | status = __ipq_set_mode(mode, range); |
| 347 | write_unlock_bh(&queue_lock); | 340 | spin_unlock_bh(&queue_lock); |
| 348 | return status; | 341 | return status; |
| 349 | } | 342 | } |
| 350 | 343 | ||
| @@ -441,11 +434,11 @@ __ipq_rcv_skb(struct sk_buff *skb) | |||
| 441 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) | 434 | if (security_netlink_recv(skb, CAP_NET_ADMIN)) |
| 442 | RCV_SKB_FAIL(-EPERM); | 435 | RCV_SKB_FAIL(-EPERM); |
| 443 | 436 | ||
| 444 | write_lock_bh(&queue_lock); | 437 | spin_lock_bh(&queue_lock); |
| 445 | 438 | ||
| 446 | if (peer_pid) { | 439 | if (peer_pid) { |
| 447 | if (peer_pid != pid) { | 440 | if (peer_pid != pid) { |
| 448 | write_unlock_bh(&queue_lock); | 441 | spin_unlock_bh(&queue_lock); |
| 449 | RCV_SKB_FAIL(-EBUSY); | 442 | RCV_SKB_FAIL(-EBUSY); |
| 450 | } | 443 | } |
| 451 | } else { | 444 | } else { |
| @@ -453,7 +446,7 @@ __ipq_rcv_skb(struct sk_buff *skb) | |||
| 453 | peer_pid = pid; | 446 | peer_pid = pid; |
| 454 | } | 447 | } |
| 455 | 448 | ||
| 456 | write_unlock_bh(&queue_lock); | 449 | spin_unlock_bh(&queue_lock); |
| 457 | 450 | ||
| 458 | status = ipq_receive_peer(NLMSG_DATA(nlh), type, | 451 | status = ipq_receive_peer(NLMSG_DATA(nlh), type, |
| 459 | nlmsglen - NLMSG_LENGTH(0)); | 452 | nlmsglen - NLMSG_LENGTH(0)); |
| @@ -462,7 +455,6 @@ __ipq_rcv_skb(struct sk_buff *skb) | |||
| 462 | 455 | ||
| 463 | if (flags & NLM_F_ACK) | 456 | if (flags & NLM_F_ACK) |
| 464 | netlink_ack(skb, nlh, 0); | 457 | netlink_ack(skb, nlh, 0); |
| 465 | return; | ||
| 466 | } | 458 | } |
| 467 | 459 | ||
| 468 | static void | 460 | static void |
| @@ -499,10 +491,10 @@ ipq_rcv_nl_event(struct notifier_block *this, | |||
| 499 | struct netlink_notify *n = ptr; | 491 | struct netlink_notify *n = ptr; |
| 500 | 492 | ||
| 501 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { | 493 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { |
| 502 | write_lock_bh(&queue_lock); | 494 | spin_lock_bh(&queue_lock); |
| 503 | if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) | 495 | if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) |
| 504 | __ipq_reset(); | 496 | __ipq_reset(); |
| 505 | write_unlock_bh(&queue_lock); | 497 | spin_unlock_bh(&queue_lock); |
| 506 | } | 498 | } |
| 507 | return NOTIFY_DONE; | 499 | return NOTIFY_DONE; |
| 508 | } | 500 | } |
| @@ -529,7 +521,7 @@ static ctl_table ipq_table[] = { | |||
| 529 | #ifdef CONFIG_PROC_FS | 521 | #ifdef CONFIG_PROC_FS |
| 530 | static int ip6_queue_show(struct seq_file *m, void *v) | 522 | static int ip6_queue_show(struct seq_file *m, void *v) |
| 531 | { | 523 | { |
| 532 | read_lock_bh(&queue_lock); | 524 | spin_lock_bh(&queue_lock); |
| 533 | 525 | ||
| 534 | seq_printf(m, | 526 | seq_printf(m, |
| 535 | "Peer PID : %d\n" | 527 | "Peer PID : %d\n" |
| @@ -547,7 +539,7 @@ static int ip6_queue_show(struct seq_file *m, void *v) | |||
| 547 | queue_dropped, | 539 | queue_dropped, |
| 548 | queue_user_dropped); | 540 | queue_user_dropped); |
| 549 | 541 | ||
| 550 | read_unlock_bh(&queue_lock); | 542 | spin_unlock_bh(&queue_lock); |
| 551 | return 0; | 543 | return 0; |
| 552 | } | 544 | } |
| 553 | 545 | ||
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 480d7f8c9802..8e754be92c24 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/netfilter_ipv6/ip6_tables.h> | 29 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 30 | #include <linux/netfilter/x_tables.h> | 30 | #include <linux/netfilter/x_tables.h> |
| 31 | #include <net/netfilter/nf_log.h> | 31 | #include <net/netfilter/nf_log.h> |
| 32 | #include "../../netfilter/xt_repldata.h" | ||
| 32 | 33 | ||
| 33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
| 34 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 35 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
| @@ -39,24 +40,19 @@ MODULE_DESCRIPTION("IPv6 packet filter"); | |||
| 39 | /*#define DEBUG_IP_FIREWALL_USER*/ | 40 | /*#define DEBUG_IP_FIREWALL_USER*/ |
| 40 | 41 | ||
| 41 | #ifdef DEBUG_IP_FIREWALL | 42 | #ifdef DEBUG_IP_FIREWALL |
| 42 | #define dprintf(format, args...) printk(format , ## args) | 43 | #define dprintf(format, args...) pr_info(format , ## args) |
| 43 | #else | 44 | #else |
| 44 | #define dprintf(format, args...) | 45 | #define dprintf(format, args...) |
| 45 | #endif | 46 | #endif |
| 46 | 47 | ||
| 47 | #ifdef DEBUG_IP_FIREWALL_USER | 48 | #ifdef DEBUG_IP_FIREWALL_USER |
| 48 | #define duprintf(format, args...) printk(format , ## args) | 49 | #define duprintf(format, args...) pr_info(format , ## args) |
| 49 | #else | 50 | #else |
| 50 | #define duprintf(format, args...) | 51 | #define duprintf(format, args...) |
| 51 | #endif | 52 | #endif |
| 52 | 53 | ||
| 53 | #ifdef CONFIG_NETFILTER_DEBUG | 54 | #ifdef CONFIG_NETFILTER_DEBUG |
| 54 | #define IP_NF_ASSERT(x) \ | 55 | #define IP_NF_ASSERT(x) WARN_ON(!(x)) |
| 55 | do { \ | ||
| 56 | if (!(x)) \ | ||
| 57 | printk("IP_NF_ASSERT: %s:%s:%u\n", \ | ||
| 58 | __func__, __FILE__, __LINE__); \ | ||
| 59 | } while(0) | ||
| 60 | #else | 56 | #else |
| 61 | #define IP_NF_ASSERT(x) | 57 | #define IP_NF_ASSERT(x) |
| 62 | #endif | 58 | #endif |
| @@ -67,6 +63,12 @@ do { \ | |||
| 67 | #define inline | 63 | #define inline |
| 68 | #endif | 64 | #endif |
| 69 | 65 | ||
| 66 | void *ip6t_alloc_initial_table(const struct xt_table *info) | ||
| 67 | { | ||
| 68 | return xt_alloc_initial_table(ip6t, IP6T); | ||
| 69 | } | ||
| 70 | EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); | ||
| 71 | |||
| 70 | /* | 72 | /* |
| 71 | We keep a set of rules for each CPU, so we can avoid write-locking | 73 | We keep a set of rules for each CPU, so we can avoid write-locking |
| 72 | them in the softirq when updating the counters and therefore | 74 | them in the softirq when updating the counters and therefore |
| @@ -190,32 +192,16 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6) | |||
| 190 | } | 192 | } |
| 191 | 193 | ||
| 192 | static unsigned int | 194 | static unsigned int |
| 193 | ip6t_error(struct sk_buff *skb, const struct xt_target_param *par) | 195 | ip6t_error(struct sk_buff *skb, const struct xt_action_param *par) |
| 194 | { | 196 | { |
| 195 | if (net_ratelimit()) | 197 | if (net_ratelimit()) |
| 196 | printk("ip6_tables: error: `%s'\n", | 198 | pr_info("error: `%s'\n", (const char *)par->targinfo); |
| 197 | (const char *)par->targinfo); | ||
| 198 | 199 | ||
| 199 | return NF_DROP; | 200 | return NF_DROP; |
| 200 | } | 201 | } |
| 201 | 202 | ||
| 202 | /* Performance critical - called for every packet */ | ||
| 203 | static inline bool | ||
| 204 | do_match(struct ip6t_entry_match *m, const struct sk_buff *skb, | ||
| 205 | struct xt_match_param *par) | ||
| 206 | { | ||
| 207 | par->match = m->u.kernel.match; | ||
| 208 | par->matchinfo = m->data; | ||
| 209 | |||
| 210 | /* Stop iteration if it doesn't match */ | ||
| 211 | if (!m->u.kernel.match->match(skb, par)) | ||
| 212 | return true; | ||
| 213 | else | ||
| 214 | return false; | ||
| 215 | } | ||
| 216 | |||
| 217 | static inline struct ip6t_entry * | 203 | static inline struct ip6t_entry * |
| 218 | get_entry(void *base, unsigned int offset) | 204 | get_entry(const void *base, unsigned int offset) |
| 219 | { | 205 | { |
| 220 | return (struct ip6t_entry *)(base + offset); | 206 | return (struct ip6t_entry *)(base + offset); |
| 221 | } | 207 | } |
| @@ -229,6 +215,12 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6) | |||
| 229 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; | 215 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; |
| 230 | } | 216 | } |
| 231 | 217 | ||
| 218 | static inline const struct ip6t_entry_target * | ||
| 219 | ip6t_get_target_c(const struct ip6t_entry *e) | ||
| 220 | { | ||
| 221 | return ip6t_get_target((struct ip6t_entry *)e); | ||
| 222 | } | ||
| 223 | |||
| 232 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 224 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ |
| 233 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | 225 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) |
| 234 | /* This cries for unification! */ | 226 | /* This cries for unification! */ |
| @@ -264,11 +256,11 @@ static struct nf_loginfo trace_loginfo = { | |||
| 264 | 256 | ||
| 265 | /* Mildly perf critical (only if packet tracing is on) */ | 257 | /* Mildly perf critical (only if packet tracing is on) */ |
| 266 | static inline int | 258 | static inline int |
| 267 | get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | 259 | get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, |
| 268 | const char *hookname, const char **chainname, | 260 | const char *hookname, const char **chainname, |
| 269 | const char **comment, unsigned int *rulenum) | 261 | const char **comment, unsigned int *rulenum) |
| 270 | { | 262 | { |
| 271 | struct ip6t_standard_target *t = (void *)ip6t_get_target(s); | 263 | const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s); |
| 272 | 264 | ||
| 273 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { | 265 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { |
| 274 | /* Head of user chain: ERROR target with chainname */ | 266 | /* Head of user chain: ERROR target with chainname */ |
| @@ -294,17 +286,18 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | |||
| 294 | return 0; | 286 | return 0; |
| 295 | } | 287 | } |
| 296 | 288 | ||
| 297 | static void trace_packet(struct sk_buff *skb, | 289 | static void trace_packet(const struct sk_buff *skb, |
| 298 | unsigned int hook, | 290 | unsigned int hook, |
| 299 | const struct net_device *in, | 291 | const struct net_device *in, |
| 300 | const struct net_device *out, | 292 | const struct net_device *out, |
| 301 | const char *tablename, | 293 | const char *tablename, |
| 302 | struct xt_table_info *private, | 294 | const struct xt_table_info *private, |
| 303 | struct ip6t_entry *e) | 295 | const struct ip6t_entry *e) |
| 304 | { | 296 | { |
| 305 | void *table_base; | 297 | const void *table_base; |
| 306 | const struct ip6t_entry *root; | 298 | const struct ip6t_entry *root; |
| 307 | const char *hookname, *chainname, *comment; | 299 | const char *hookname, *chainname, *comment; |
| 300 | const struct ip6t_entry *iter; | ||
| 308 | unsigned int rulenum = 0; | 301 | unsigned int rulenum = 0; |
| 309 | 302 | ||
| 310 | table_base = private->entries[smp_processor_id()]; | 303 | table_base = private->entries[smp_processor_id()]; |
| @@ -313,10 +306,10 @@ static void trace_packet(struct sk_buff *skb, | |||
| 313 | hookname = chainname = hooknames[hook]; | 306 | hookname = chainname = hooknames[hook]; |
| 314 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; | 307 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; |
| 315 | 308 | ||
| 316 | IP6T_ENTRY_ITERATE(root, | 309 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
| 317 | private->size - private->hook_entry[hook], | 310 | if (get_chainname_rulenum(iter, e, hookname, |
| 318 | get_chainname_rulenum, | 311 | &chainname, &comment, &rulenum) != 0) |
| 319 | e, hookname, &chainname, &comment, &rulenum); | 312 | break; |
| 320 | 313 | ||
| 321 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | 314 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, |
| 322 | "TRACE: %s:%s:%s:%u ", | 315 | "TRACE: %s:%s:%s:%u ", |
| @@ -338,18 +331,15 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 338 | const struct net_device *out, | 331 | const struct net_device *out, |
| 339 | struct xt_table *table) | 332 | struct xt_table *table) |
| 340 | { | 333 | { |
| 341 | #define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom | ||
| 342 | |||
| 343 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | 334 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
| 344 | bool hotdrop = false; | ||
| 345 | /* Initializing verdict to NF_DROP keeps gcc happy. */ | 335 | /* Initializing verdict to NF_DROP keeps gcc happy. */ |
| 346 | unsigned int verdict = NF_DROP; | 336 | unsigned int verdict = NF_DROP; |
| 347 | const char *indev, *outdev; | 337 | const char *indev, *outdev; |
| 348 | void *table_base; | 338 | const void *table_base; |
| 349 | struct ip6t_entry *e, *back; | 339 | struct ip6t_entry *e, **jumpstack; |
| 350 | struct xt_table_info *private; | 340 | unsigned int *stackptr, origptr, cpu; |
| 351 | struct xt_match_param mtpar; | 341 | const struct xt_table_info *private; |
| 352 | struct xt_target_param tgpar; | 342 | struct xt_action_param acpar; |
| 353 | 343 | ||
| 354 | /* Initialization */ | 344 | /* Initialization */ |
| 355 | indev = in ? in->name : nulldevname; | 345 | indev = in ? in->name : nulldevname; |
| @@ -360,40 +350,46 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 360 | * things we don't know, ie. tcp syn flag or ports). If the | 350 | * things we don't know, ie. tcp syn flag or ports). If the |
| 361 | * rule is also a fragment-specific rule, non-fragments won't | 351 | * rule is also a fragment-specific rule, non-fragments won't |
| 362 | * match it. */ | 352 | * match it. */ |
| 363 | mtpar.hotdrop = &hotdrop; | 353 | acpar.hotdrop = false; |
| 364 | mtpar.in = tgpar.in = in; | 354 | acpar.in = in; |
| 365 | mtpar.out = tgpar.out = out; | 355 | acpar.out = out; |
| 366 | mtpar.family = tgpar.family = NFPROTO_IPV6; | 356 | acpar.family = NFPROTO_IPV6; |
| 367 | mtpar.hooknum = tgpar.hooknum = hook; | 357 | acpar.hooknum = hook; |
| 368 | 358 | ||
| 369 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 359 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
| 370 | 360 | ||
| 371 | xt_info_rdlock_bh(); | 361 | xt_info_rdlock_bh(); |
| 372 | private = table->private; | 362 | private = table->private; |
| 373 | table_base = private->entries[smp_processor_id()]; | 363 | cpu = smp_processor_id(); |
| 364 | table_base = private->entries[cpu]; | ||
| 365 | jumpstack = (struct ip6t_entry **)private->jumpstack[cpu]; | ||
| 366 | stackptr = per_cpu_ptr(private->stackptr, cpu); | ||
| 367 | origptr = *stackptr; | ||
| 374 | 368 | ||
| 375 | e = get_entry(table_base, private->hook_entry[hook]); | 369 | e = get_entry(table_base, private->hook_entry[hook]); |
| 376 | 370 | ||
| 377 | /* For return from builtin chain */ | ||
| 378 | back = get_entry(table_base, private->underflow[hook]); | ||
| 379 | |||
| 380 | do { | 371 | do { |
| 381 | struct ip6t_entry_target *t; | 372 | const struct ip6t_entry_target *t; |
| 373 | const struct xt_entry_match *ematch; | ||
| 382 | 374 | ||
| 383 | IP_NF_ASSERT(e); | 375 | IP_NF_ASSERT(e); |
| 384 | IP_NF_ASSERT(back); | ||
| 385 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, | 376 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, |
| 386 | &mtpar.thoff, &mtpar.fragoff, &hotdrop) || | 377 | &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) { |
| 387 | IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 378 | no_match: |
| 388 | e = ip6t_next_entry(e); | 379 | e = ip6t_next_entry(e); |
| 389 | continue; | 380 | continue; |
| 390 | } | 381 | } |
| 391 | 382 | ||
| 392 | ADD_COUNTER(e->counters, | 383 | xt_ematch_foreach(ematch, e) { |
| 393 | ntohs(ipv6_hdr(skb)->payload_len) + | 384 | acpar.match = ematch->u.kernel.match; |
| 394 | sizeof(struct ipv6hdr), 1); | 385 | acpar.matchinfo = ematch->data; |
| 386 | if (!acpar.match->match(skb, &acpar)) | ||
| 387 | goto no_match; | ||
| 388 | } | ||
| 389 | |||
| 390 | ADD_COUNTER(e->counters, skb->len, 1); | ||
| 395 | 391 | ||
| 396 | t = ip6t_get_target(e); | 392 | t = ip6t_get_target_c(e); |
| 397 | IP_NF_ASSERT(t->u.kernel.target); | 393 | IP_NF_ASSERT(t->u.kernel.target); |
| 398 | 394 | ||
| 399 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 395 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ |
| @@ -414,68 +410,53 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 414 | verdict = (unsigned)(-v) - 1; | 410 | verdict = (unsigned)(-v) - 1; |
| 415 | break; | 411 | break; |
| 416 | } | 412 | } |
| 417 | e = back; | 413 | if (*stackptr == 0) |
| 418 | back = get_entry(table_base, back->comefrom); | 414 | e = get_entry(table_base, |
| 415 | private->underflow[hook]); | ||
| 416 | else | ||
| 417 | e = ip6t_next_entry(jumpstack[--*stackptr]); | ||
| 419 | continue; | 418 | continue; |
| 420 | } | 419 | } |
| 421 | if (table_base + v != ip6t_next_entry(e) && | 420 | if (table_base + v != ip6t_next_entry(e) && |
| 422 | !(e->ipv6.flags & IP6T_F_GOTO)) { | 421 | !(e->ipv6.flags & IP6T_F_GOTO)) { |
| 423 | /* Save old back ptr in next entry */ | 422 | if (*stackptr >= private->stacksize) { |
| 424 | struct ip6t_entry *next = ip6t_next_entry(e); | 423 | verdict = NF_DROP; |
| 425 | next->comefrom = (void *)back - table_base; | 424 | break; |
| 426 | /* set back pointer to next entry */ | 425 | } |
| 427 | back = next; | 426 | jumpstack[(*stackptr)++] = e; |
| 428 | } | 427 | } |
| 429 | 428 | ||
| 430 | e = get_entry(table_base, v); | 429 | e = get_entry(table_base, v); |
| 431 | continue; | 430 | continue; |
| 432 | } | 431 | } |
| 433 | 432 | ||
| 434 | /* Targets which reenter must return | 433 | acpar.target = t->u.kernel.target; |
| 435 | abs. verdicts */ | 434 | acpar.targinfo = t->data; |
| 436 | tgpar.target = t->u.kernel.target; | ||
| 437 | tgpar.targinfo = t->data; | ||
| 438 | |||
| 439 | #ifdef CONFIG_NETFILTER_DEBUG | ||
| 440 | tb_comefrom = 0xeeeeeeec; | ||
| 441 | #endif | ||
| 442 | verdict = t->u.kernel.target->target(skb, &tgpar); | ||
| 443 | 435 | ||
| 444 | #ifdef CONFIG_NETFILTER_DEBUG | 436 | verdict = t->u.kernel.target->target(skb, &acpar); |
| 445 | if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) { | ||
| 446 | printk("Target %s reentered!\n", | ||
| 447 | t->u.kernel.target->name); | ||
| 448 | verdict = NF_DROP; | ||
| 449 | } | ||
| 450 | tb_comefrom = 0x57acc001; | ||
| 451 | #endif | ||
| 452 | if (verdict == IP6T_CONTINUE) | 437 | if (verdict == IP6T_CONTINUE) |
| 453 | e = ip6t_next_entry(e); | 438 | e = ip6t_next_entry(e); |
| 454 | else | 439 | else |
| 455 | /* Verdict */ | 440 | /* Verdict */ |
| 456 | break; | 441 | break; |
| 457 | } while (!hotdrop); | 442 | } while (!acpar.hotdrop); |
| 458 | 443 | ||
| 459 | #ifdef CONFIG_NETFILTER_DEBUG | ||
| 460 | tb_comefrom = NETFILTER_LINK_POISON; | ||
| 461 | #endif | ||
| 462 | xt_info_rdunlock_bh(); | 444 | xt_info_rdunlock_bh(); |
| 445 | *stackptr = origptr; | ||
| 463 | 446 | ||
| 464 | #ifdef DEBUG_ALLOW_ALL | 447 | #ifdef DEBUG_ALLOW_ALL |
| 465 | return NF_ACCEPT; | 448 | return NF_ACCEPT; |
| 466 | #else | 449 | #else |
| 467 | if (hotdrop) | 450 | if (acpar.hotdrop) |
| 468 | return NF_DROP; | 451 | return NF_DROP; |
| 469 | else return verdict; | 452 | else return verdict; |
| 470 | #endif | 453 | #endif |
| 471 | |||
| 472 | #undef tb_comefrom | ||
| 473 | } | 454 | } |
| 474 | 455 | ||
| 475 | /* Figures out from what hook each rule can be called: returns 0 if | 456 | /* Figures out from what hook each rule can be called: returns 0 if |
| 476 | there are loops. Puts hook bitmask in comefrom. */ | 457 | there are loops. Puts hook bitmask in comefrom. */ |
| 477 | static int | 458 | static int |
| 478 | mark_source_chains(struct xt_table_info *newinfo, | 459 | mark_source_chains(const struct xt_table_info *newinfo, |
| 479 | unsigned int valid_hooks, void *entry0) | 460 | unsigned int valid_hooks, void *entry0) |
| 480 | { | 461 | { |
| 481 | unsigned int hook; | 462 | unsigned int hook; |
| @@ -493,12 +474,12 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
| 493 | e->counters.pcnt = pos; | 474 | e->counters.pcnt = pos; |
| 494 | 475 | ||
| 495 | for (;;) { | 476 | for (;;) { |
| 496 | struct ip6t_standard_target *t | 477 | const struct ip6t_standard_target *t |
| 497 | = (void *)ip6t_get_target(e); | 478 | = (void *)ip6t_get_target_c(e); |
| 498 | int visited = e->comefrom & (1 << hook); | 479 | int visited = e->comefrom & (1 << hook); |
| 499 | 480 | ||
| 500 | if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { | 481 | if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { |
| 501 | printk("iptables: loop hook %u pos %u %08X.\n", | 482 | pr_err("iptables: loop hook %u pos %u %08X.\n", |
| 502 | hook, pos, e->comefrom); | 483 | hook, pos, e->comefrom); |
| 503 | return 0; | 484 | return 0; |
| 504 | } | 485 | } |
| @@ -584,27 +565,23 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
| 584 | return 1; | 565 | return 1; |
| 585 | } | 566 | } |
| 586 | 567 | ||
| 587 | static int | 568 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) |
| 588 | cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | ||
| 589 | { | 569 | { |
| 590 | struct xt_mtdtor_param par; | 570 | struct xt_mtdtor_param par; |
| 591 | 571 | ||
| 592 | if (i && (*i)-- == 0) | 572 | par.net = net; |
| 593 | return 1; | ||
| 594 | |||
| 595 | par.match = m->u.kernel.match; | 573 | par.match = m->u.kernel.match; |
| 596 | par.matchinfo = m->data; | 574 | par.matchinfo = m->data; |
| 597 | par.family = NFPROTO_IPV6; | 575 | par.family = NFPROTO_IPV6; |
| 598 | if (par.match->destroy != NULL) | 576 | if (par.match->destroy != NULL) |
| 599 | par.match->destroy(&par); | 577 | par.match->destroy(&par); |
| 600 | module_put(par.match->me); | 578 | module_put(par.match->me); |
| 601 | return 0; | ||
| 602 | } | 579 | } |
| 603 | 580 | ||
| 604 | static int | 581 | static int |
| 605 | check_entry(struct ip6t_entry *e, const char *name) | 582 | check_entry(const struct ip6t_entry *e, const char *name) |
| 606 | { | 583 | { |
| 607 | struct ip6t_entry_target *t; | 584 | const struct ip6t_entry_target *t; |
| 608 | 585 | ||
| 609 | if (!ip6_checkentry(&e->ipv6)) { | 586 | if (!ip6_checkentry(&e->ipv6)) { |
| 610 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | 587 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); |
| @@ -615,15 +592,14 @@ check_entry(struct ip6t_entry *e, const char *name) | |||
| 615 | e->next_offset) | 592 | e->next_offset) |
| 616 | return -EINVAL; | 593 | return -EINVAL; |
| 617 | 594 | ||
| 618 | t = ip6t_get_target(e); | 595 | t = ip6t_get_target_c(e); |
| 619 | if (e->target_offset + t->u.target_size > e->next_offset) | 596 | if (e->target_offset + t->u.target_size > e->next_offset) |
| 620 | return -EINVAL; | 597 | return -EINVAL; |
| 621 | 598 | ||
| 622 | return 0; | 599 | return 0; |
| 623 | } | 600 | } |
| 624 | 601 | ||
| 625 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 602 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
| 626 | unsigned int *i) | ||
| 627 | { | 603 | { |
| 628 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 604 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
| 629 | int ret; | 605 | int ret; |
| @@ -638,27 +614,24 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
| 638 | par.match->name); | 614 | par.match->name); |
| 639 | return ret; | 615 | return ret; |
| 640 | } | 616 | } |
| 641 | ++*i; | ||
| 642 | return 0; | 617 | return 0; |
| 643 | } | 618 | } |
| 644 | 619 | ||
| 645 | static int | 620 | static int |
| 646 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 621 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
| 647 | unsigned int *i) | ||
| 648 | { | 622 | { |
| 649 | struct xt_match *match; | 623 | struct xt_match *match; |
| 650 | int ret; | 624 | int ret; |
| 651 | 625 | ||
| 652 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, | 626 | match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name, |
| 653 | m->u.user.revision), | 627 | m->u.user.revision); |
| 654 | "ip6t_%s", m->u.user.name); | 628 | if (IS_ERR(match)) { |
| 655 | if (IS_ERR(match) || !match) { | ||
| 656 | duprintf("find_check_match: `%s' not found\n", m->u.user.name); | 629 | duprintf("find_check_match: `%s' not found\n", m->u.user.name); |
| 657 | return match ? PTR_ERR(match) : -ENOENT; | 630 | return PTR_ERR(match); |
| 658 | } | 631 | } |
| 659 | m->u.kernel.match = match; | 632 | m->u.kernel.match = match; |
| 660 | 633 | ||
| 661 | ret = check_match(m, par, i); | 634 | ret = check_match(m, par); |
| 662 | if (ret) | 635 | if (ret) |
| 663 | goto err; | 636 | goto err; |
| 664 | 637 | ||
| @@ -668,10 +641,11 @@ err: | |||
| 668 | return ret; | 641 | return ret; |
| 669 | } | 642 | } |
| 670 | 643 | ||
| 671 | static int check_target(struct ip6t_entry *e, const char *name) | 644 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) |
| 672 | { | 645 | { |
| 673 | struct ip6t_entry_target *t = ip6t_get_target(e); | 646 | struct ip6t_entry_target *t = ip6t_get_target(e); |
| 674 | struct xt_tgchk_param par = { | 647 | struct xt_tgchk_param par = { |
| 648 | .net = net, | ||
| 675 | .table = name, | 649 | .table = name, |
| 676 | .entryinfo = e, | 650 | .entryinfo = e, |
| 677 | .target = t->u.kernel.target, | 651 | .target = t->u.kernel.target, |
| @@ -693,61 +667,66 @@ static int check_target(struct ip6t_entry *e, const char *name) | |||
| 693 | } | 667 | } |
| 694 | 668 | ||
| 695 | static int | 669 | static int |
| 696 | find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | 670 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
| 697 | unsigned int *i) | 671 | unsigned int size) |
| 698 | { | 672 | { |
| 699 | struct ip6t_entry_target *t; | 673 | struct ip6t_entry_target *t; |
| 700 | struct xt_target *target; | 674 | struct xt_target *target; |
| 701 | int ret; | 675 | int ret; |
| 702 | unsigned int j; | 676 | unsigned int j; |
| 703 | struct xt_mtchk_param mtpar; | 677 | struct xt_mtchk_param mtpar; |
| 678 | struct xt_entry_match *ematch; | ||
| 704 | 679 | ||
| 705 | ret = check_entry(e, name); | 680 | ret = check_entry(e, name); |
| 706 | if (ret) | 681 | if (ret) |
| 707 | return ret; | 682 | return ret; |
| 708 | 683 | ||
| 709 | j = 0; | 684 | j = 0; |
| 685 | mtpar.net = net; | ||
| 710 | mtpar.table = name; | 686 | mtpar.table = name; |
| 711 | mtpar.entryinfo = &e->ipv6; | 687 | mtpar.entryinfo = &e->ipv6; |
| 712 | mtpar.hook_mask = e->comefrom; | 688 | mtpar.hook_mask = e->comefrom; |
| 713 | mtpar.family = NFPROTO_IPV6; | 689 | mtpar.family = NFPROTO_IPV6; |
| 714 | ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 690 | xt_ematch_foreach(ematch, e) { |
| 715 | if (ret != 0) | 691 | ret = find_check_match(ematch, &mtpar); |
| 716 | goto cleanup_matches; | 692 | if (ret != 0) |
| 693 | goto cleanup_matches; | ||
| 694 | ++j; | ||
| 695 | } | ||
| 717 | 696 | ||
| 718 | t = ip6t_get_target(e); | 697 | t = ip6t_get_target(e); |
| 719 | target = try_then_request_module(xt_find_target(AF_INET6, | 698 | target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name, |
| 720 | t->u.user.name, | 699 | t->u.user.revision); |
| 721 | t->u.user.revision), | 700 | if (IS_ERR(target)) { |
| 722 | "ip6t_%s", t->u.user.name); | ||
| 723 | if (IS_ERR(target) || !target) { | ||
| 724 | duprintf("find_check_entry: `%s' not found\n", t->u.user.name); | 701 | duprintf("find_check_entry: `%s' not found\n", t->u.user.name); |
| 725 | ret = target ? PTR_ERR(target) : -ENOENT; | 702 | ret = PTR_ERR(target); |
| 726 | goto cleanup_matches; | 703 | goto cleanup_matches; |
| 727 | } | 704 | } |
| 728 | t->u.kernel.target = target; | 705 | t->u.kernel.target = target; |
| 729 | 706 | ||
| 730 | ret = check_target(e, name); | 707 | ret = check_target(e, net, name); |
| 731 | if (ret) | 708 | if (ret) |
| 732 | goto err; | 709 | goto err; |
| 733 | |||
| 734 | (*i)++; | ||
| 735 | return 0; | 710 | return 0; |
| 736 | err: | 711 | err: |
| 737 | module_put(t->u.kernel.target->me); | 712 | module_put(t->u.kernel.target->me); |
| 738 | cleanup_matches: | 713 | cleanup_matches: |
| 739 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 714 | xt_ematch_foreach(ematch, e) { |
| 715 | if (j-- == 0) | ||
| 716 | break; | ||
| 717 | cleanup_match(ematch, net); | ||
| 718 | } | ||
| 740 | return ret; | 719 | return ret; |
| 741 | } | 720 | } |
| 742 | 721 | ||
| 743 | static bool check_underflow(struct ip6t_entry *e) | 722 | static bool check_underflow(const struct ip6t_entry *e) |
| 744 | { | 723 | { |
| 745 | const struct ip6t_entry_target *t; | 724 | const struct ip6t_entry_target *t; |
| 746 | unsigned int verdict; | 725 | unsigned int verdict; |
| 747 | 726 | ||
| 748 | if (!unconditional(&e->ipv6)) | 727 | if (!unconditional(&e->ipv6)) |
| 749 | return false; | 728 | return false; |
| 750 | t = ip6t_get_target(e); | 729 | t = ip6t_get_target_c(e); |
| 751 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | 730 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) |
| 752 | return false; | 731 | return false; |
| 753 | verdict = ((struct ip6t_standard_target *)t)->verdict; | 732 | verdict = ((struct ip6t_standard_target *)t)->verdict; |
| @@ -758,12 +737,11 @@ static bool check_underflow(struct ip6t_entry *e) | |||
| 758 | static int | 737 | static int |
| 759 | check_entry_size_and_hooks(struct ip6t_entry *e, | 738 | check_entry_size_and_hooks(struct ip6t_entry *e, |
| 760 | struct xt_table_info *newinfo, | 739 | struct xt_table_info *newinfo, |
| 761 | unsigned char *base, | 740 | const unsigned char *base, |
| 762 | unsigned char *limit, | 741 | const unsigned char *limit, |
| 763 | const unsigned int *hook_entries, | 742 | const unsigned int *hook_entries, |
| 764 | const unsigned int *underflows, | 743 | const unsigned int *underflows, |
| 765 | unsigned int valid_hooks, | 744 | unsigned int valid_hooks) |
| 766 | unsigned int *i) | ||
| 767 | { | 745 | { |
| 768 | unsigned int h; | 746 | unsigned int h; |
| 769 | 747 | ||
| @@ -800,50 +778,41 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
| 800 | /* Clear counters and comefrom */ | 778 | /* Clear counters and comefrom */ |
| 801 | e->counters = ((struct xt_counters) { 0, 0 }); | 779 | e->counters = ((struct xt_counters) { 0, 0 }); |
| 802 | e->comefrom = 0; | 780 | e->comefrom = 0; |
| 803 | |||
| 804 | (*i)++; | ||
| 805 | return 0; | 781 | return 0; |
| 806 | } | 782 | } |
| 807 | 783 | ||
| 808 | static int | 784 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
| 809 | cleanup_entry(struct ip6t_entry *e, unsigned int *i) | ||
| 810 | { | 785 | { |
| 811 | struct xt_tgdtor_param par; | 786 | struct xt_tgdtor_param par; |
| 812 | struct ip6t_entry_target *t; | 787 | struct ip6t_entry_target *t; |
| 813 | 788 | struct xt_entry_match *ematch; | |
| 814 | if (i && (*i)-- == 0) | ||
| 815 | return 1; | ||
| 816 | 789 | ||
| 817 | /* Cleanup all matches */ | 790 | /* Cleanup all matches */ |
| 818 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 791 | xt_ematch_foreach(ematch, e) |
| 792 | cleanup_match(ematch, net); | ||
| 819 | t = ip6t_get_target(e); | 793 | t = ip6t_get_target(e); |
| 820 | 794 | ||
| 795 | par.net = net; | ||
| 821 | par.target = t->u.kernel.target; | 796 | par.target = t->u.kernel.target; |
| 822 | par.targinfo = t->data; | 797 | par.targinfo = t->data; |
| 823 | par.family = NFPROTO_IPV6; | 798 | par.family = NFPROTO_IPV6; |
| 824 | if (par.target->destroy != NULL) | 799 | if (par.target->destroy != NULL) |
| 825 | par.target->destroy(&par); | 800 | par.target->destroy(&par); |
| 826 | module_put(par.target->me); | 801 | module_put(par.target->me); |
| 827 | return 0; | ||
| 828 | } | 802 | } |
| 829 | 803 | ||
| 830 | /* Checks and translates the user-supplied table segment (held in | 804 | /* Checks and translates the user-supplied table segment (held in |
| 831 | newinfo) */ | 805 | newinfo) */ |
| 832 | static int | 806 | static int |
| 833 | translate_table(const char *name, | 807 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
| 834 | unsigned int valid_hooks, | 808 | const struct ip6t_replace *repl) |
| 835 | struct xt_table_info *newinfo, | ||
| 836 | void *entry0, | ||
| 837 | unsigned int size, | ||
| 838 | unsigned int number, | ||
| 839 | const unsigned int *hook_entries, | ||
| 840 | const unsigned int *underflows) | ||
| 841 | { | 809 | { |
| 810 | struct ip6t_entry *iter; | ||
| 842 | unsigned int i; | 811 | unsigned int i; |
| 843 | int ret; | 812 | int ret = 0; |
| 844 | 813 | ||
| 845 | newinfo->size = size; | 814 | newinfo->size = repl->size; |
| 846 | newinfo->number = number; | 815 | newinfo->number = repl->num_entries; |
| 847 | 816 | ||
| 848 | /* Init all hooks to impossible value. */ | 817 | /* Init all hooks to impossible value. */ |
| 849 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 818 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| @@ -854,49 +823,61 @@ translate_table(const char *name, | |||
| 854 | duprintf("translate_table: size %u\n", newinfo->size); | 823 | duprintf("translate_table: size %u\n", newinfo->size); |
| 855 | i = 0; | 824 | i = 0; |
| 856 | /* Walk through entries, checking offsets. */ | 825 | /* Walk through entries, checking offsets. */ |
| 857 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 826 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 858 | check_entry_size_and_hooks, | 827 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
| 859 | newinfo, | 828 | entry0 + repl->size, |
| 860 | entry0, | 829 | repl->hook_entry, |
| 861 | entry0 + size, | 830 | repl->underflow, |
| 862 | hook_entries, underflows, valid_hooks, &i); | 831 | repl->valid_hooks); |
| 863 | if (ret != 0) | 832 | if (ret != 0) |
| 864 | return ret; | 833 | return ret; |
| 834 | ++i; | ||
| 835 | if (strcmp(ip6t_get_target(iter)->u.user.name, | ||
| 836 | XT_ERROR_TARGET) == 0) | ||
| 837 | ++newinfo->stacksize; | ||
| 838 | } | ||
| 865 | 839 | ||
| 866 | if (i != number) { | 840 | if (i != repl->num_entries) { |
| 867 | duprintf("translate_table: %u not %u entries\n", | 841 | duprintf("translate_table: %u not %u entries\n", |
| 868 | i, number); | 842 | i, repl->num_entries); |
| 869 | return -EINVAL; | 843 | return -EINVAL; |
| 870 | } | 844 | } |
| 871 | 845 | ||
| 872 | /* Check hooks all assigned */ | 846 | /* Check hooks all assigned */ |
| 873 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 847 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| 874 | /* Only hooks which are valid */ | 848 | /* Only hooks which are valid */ |
| 875 | if (!(valid_hooks & (1 << i))) | 849 | if (!(repl->valid_hooks & (1 << i))) |
| 876 | continue; | 850 | continue; |
| 877 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 851 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
| 878 | duprintf("Invalid hook entry %u %u\n", | 852 | duprintf("Invalid hook entry %u %u\n", |
| 879 | i, hook_entries[i]); | 853 | i, repl->hook_entry[i]); |
| 880 | return -EINVAL; | 854 | return -EINVAL; |
| 881 | } | 855 | } |
| 882 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 856 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
| 883 | duprintf("Invalid underflow %u %u\n", | 857 | duprintf("Invalid underflow %u %u\n", |
| 884 | i, underflows[i]); | 858 | i, repl->underflow[i]); |
| 885 | return -EINVAL; | 859 | return -EINVAL; |
| 886 | } | 860 | } |
| 887 | } | 861 | } |
| 888 | 862 | ||
| 889 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 863 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
| 890 | return -ELOOP; | 864 | return -ELOOP; |
| 891 | 865 | ||
| 892 | /* Finally, each sanity check must pass */ | 866 | /* Finally, each sanity check must pass */ |
| 893 | i = 0; | 867 | i = 0; |
| 894 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 868 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 895 | find_check_entry, name, size, &i); | 869 | ret = find_check_entry(iter, net, repl->name, repl->size); |
| 870 | if (ret != 0) | ||
| 871 | break; | ||
| 872 | ++i; | ||
| 873 | } | ||
| 896 | 874 | ||
| 897 | if (ret != 0) { | 875 | if (ret != 0) { |
| 898 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 876 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 899 | cleanup_entry, &i); | 877 | if (i-- == 0) |
| 878 | break; | ||
| 879 | cleanup_entry(iter, net); | ||
| 880 | } | ||
| 900 | return ret; | 881 | return ret; |
| 901 | } | 882 | } |
| 902 | 883 | ||
| @@ -909,36 +890,14 @@ translate_table(const char *name, | |||
| 909 | return ret; | 890 | return ret; |
| 910 | } | 891 | } |
| 911 | 892 | ||
| 912 | /* Gets counters. */ | ||
| 913 | static inline int | ||
| 914 | add_entry_to_counter(const struct ip6t_entry *e, | ||
| 915 | struct xt_counters total[], | ||
| 916 | unsigned int *i) | ||
| 917 | { | ||
| 918 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 919 | |||
| 920 | (*i)++; | ||
| 921 | return 0; | ||
| 922 | } | ||
| 923 | |||
| 924 | static inline int | ||
| 925 | set_entry_to_counter(const struct ip6t_entry *e, | ||
| 926 | struct ip6t_counters total[], | ||
| 927 | unsigned int *i) | ||
| 928 | { | ||
| 929 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 930 | |||
| 931 | (*i)++; | ||
| 932 | return 0; | ||
| 933 | } | ||
| 934 | |||
| 935 | static void | 893 | static void |
| 936 | get_counters(const struct xt_table_info *t, | 894 | get_counters(const struct xt_table_info *t, |
| 937 | struct xt_counters counters[]) | 895 | struct xt_counters counters[]) |
| 938 | { | 896 | { |
| 897 | struct ip6t_entry *iter; | ||
| 939 | unsigned int cpu; | 898 | unsigned int cpu; |
| 940 | unsigned int i; | 899 | unsigned int i; |
| 941 | unsigned int curcpu; | 900 | unsigned int curcpu = get_cpu(); |
| 942 | 901 | ||
| 943 | /* Instead of clearing (by a previous call to memset()) | 902 | /* Instead of clearing (by a previous call to memset()) |
| 944 | * the counters and using adds, we set the counters | 903 | * the counters and using adds, we set the counters |
| @@ -948,41 +907,45 @@ get_counters(const struct xt_table_info *t, | |||
| 948 | * if new softirq were to run and call ipt_do_table | 907 | * if new softirq were to run and call ipt_do_table |
| 949 | */ | 908 | */ |
| 950 | local_bh_disable(); | 909 | local_bh_disable(); |
| 951 | curcpu = smp_processor_id(); | ||
| 952 | |||
| 953 | i = 0; | 910 | i = 0; |
| 954 | IP6T_ENTRY_ITERATE(t->entries[curcpu], | 911 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
| 955 | t->size, | 912 | SET_COUNTER(counters[i], iter->counters.bcnt, |
| 956 | set_entry_to_counter, | 913 | iter->counters.pcnt); |
| 957 | counters, | 914 | ++i; |
| 958 | &i); | 915 | } |
| 916 | local_bh_enable(); | ||
| 917 | /* Processing counters from other cpus, we can let bottom half enabled, | ||
| 918 | * (preemption is disabled) | ||
| 919 | */ | ||
| 959 | 920 | ||
| 960 | for_each_possible_cpu(cpu) { | 921 | for_each_possible_cpu(cpu) { |
| 961 | if (cpu == curcpu) | 922 | if (cpu == curcpu) |
| 962 | continue; | 923 | continue; |
| 963 | i = 0; | 924 | i = 0; |
| 925 | local_bh_disable(); | ||
| 964 | xt_info_wrlock(cpu); | 926 | xt_info_wrlock(cpu); |
| 965 | IP6T_ENTRY_ITERATE(t->entries[cpu], | 927 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
| 966 | t->size, | 928 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
| 967 | add_entry_to_counter, | 929 | iter->counters.pcnt); |
| 968 | counters, | 930 | ++i; |
| 969 | &i); | 931 | } |
| 970 | xt_info_wrunlock(cpu); | 932 | xt_info_wrunlock(cpu); |
| 933 | local_bh_enable(); | ||
| 971 | } | 934 | } |
| 972 | local_bh_enable(); | 935 | put_cpu(); |
| 973 | } | 936 | } |
| 974 | 937 | ||
| 975 | static struct xt_counters *alloc_counters(struct xt_table *table) | 938 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
| 976 | { | 939 | { |
| 977 | unsigned int countersize; | 940 | unsigned int countersize; |
| 978 | struct xt_counters *counters; | 941 | struct xt_counters *counters; |
| 979 | struct xt_table_info *private = table->private; | 942 | const struct xt_table_info *private = table->private; |
| 980 | 943 | ||
| 981 | /* We need atomic snapshot of counters: rest doesn't change | 944 | /* We need atomic snapshot of counters: rest doesn't change |
| 982 | (other than comefrom, which userspace doesn't care | 945 | (other than comefrom, which userspace doesn't care |
| 983 | about). */ | 946 | about). */ |
| 984 | countersize = sizeof(struct xt_counters) * private->number; | 947 | countersize = sizeof(struct xt_counters) * private->number; |
| 985 | counters = vmalloc_node(countersize, numa_node_id()); | 948 | counters = vmalloc(countersize); |
| 986 | 949 | ||
| 987 | if (counters == NULL) | 950 | if (counters == NULL) |
| 988 | return ERR_PTR(-ENOMEM); | 951 | return ERR_PTR(-ENOMEM); |
| @@ -994,11 +957,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) | |||
| 994 | 957 | ||
| 995 | static int | 958 | static int |
| 996 | copy_entries_to_user(unsigned int total_size, | 959 | copy_entries_to_user(unsigned int total_size, |
| 997 | struct xt_table *table, | 960 | const struct xt_table *table, |
| 998 | void __user *userptr) | 961 | void __user *userptr) |
| 999 | { | 962 | { |
| 1000 | unsigned int off, num; | 963 | unsigned int off, num; |
| 1001 | struct ip6t_entry *e; | 964 | const struct ip6t_entry *e; |
| 1002 | struct xt_counters *counters; | 965 | struct xt_counters *counters; |
| 1003 | const struct xt_table_info *private = table->private; | 966 | const struct xt_table_info *private = table->private; |
| 1004 | int ret = 0; | 967 | int ret = 0; |
| @@ -1050,7 +1013,7 @@ copy_entries_to_user(unsigned int total_size, | |||
| 1050 | } | 1013 | } |
| 1051 | } | 1014 | } |
| 1052 | 1015 | ||
| 1053 | t = ip6t_get_target(e); | 1016 | t = ip6t_get_target_c(e); |
| 1054 | if (copy_to_user(userptr + off + e->target_offset | 1017 | if (copy_to_user(userptr + off + e->target_offset |
| 1055 | + offsetof(struct ip6t_entry_target, | 1018 | + offsetof(struct ip6t_entry_target, |
| 1056 | u.user.name), | 1019 | u.user.name), |
| @@ -1067,7 +1030,7 @@ copy_entries_to_user(unsigned int total_size, | |||
| 1067 | } | 1030 | } |
| 1068 | 1031 | ||
| 1069 | #ifdef CONFIG_COMPAT | 1032 | #ifdef CONFIG_COMPAT |
| 1070 | static void compat_standard_from_user(void *dst, void *src) | 1033 | static void compat_standard_from_user(void *dst, const void *src) |
| 1071 | { | 1034 | { |
| 1072 | int v = *(compat_int_t *)src; | 1035 | int v = *(compat_int_t *)src; |
| 1073 | 1036 | ||
| @@ -1076,7 +1039,7 @@ static void compat_standard_from_user(void *dst, void *src) | |||
| 1076 | memcpy(dst, &v, sizeof(v)); | 1039 | memcpy(dst, &v, sizeof(v)); |
| 1077 | } | 1040 | } |
| 1078 | 1041 | ||
| 1079 | static int compat_standard_to_user(void __user *dst, void *src) | 1042 | static int compat_standard_to_user(void __user *dst, const void *src) |
| 1080 | { | 1043 | { |
| 1081 | compat_int_t cv = *(int *)src; | 1044 | compat_int_t cv = *(int *)src; |
| 1082 | 1045 | ||
| @@ -1085,25 +1048,20 @@ static int compat_standard_to_user(void __user *dst, void *src) | |||
| 1085 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1048 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
| 1086 | } | 1049 | } |
| 1087 | 1050 | ||
| 1088 | static inline int | 1051 | static int compat_calc_entry(const struct ip6t_entry *e, |
| 1089 | compat_calc_match(struct ip6t_entry_match *m, int *size) | ||
| 1090 | { | ||
| 1091 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
| 1092 | return 0; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | static int compat_calc_entry(struct ip6t_entry *e, | ||
| 1096 | const struct xt_table_info *info, | 1052 | const struct xt_table_info *info, |
| 1097 | void *base, struct xt_table_info *newinfo) | 1053 | const void *base, struct xt_table_info *newinfo) |
| 1098 | { | 1054 | { |
| 1099 | struct ip6t_entry_target *t; | 1055 | const struct xt_entry_match *ematch; |
| 1056 | const struct ip6t_entry_target *t; | ||
| 1100 | unsigned int entry_offset; | 1057 | unsigned int entry_offset; |
| 1101 | int off, i, ret; | 1058 | int off, i, ret; |
| 1102 | 1059 | ||
| 1103 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1060 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1104 | entry_offset = (void *)e - base; | 1061 | entry_offset = (void *)e - base; |
| 1105 | IP6T_MATCH_ITERATE(e, compat_calc_match, &off); | 1062 | xt_ematch_foreach(ematch, e) |
| 1106 | t = ip6t_get_target(e); | 1063 | off += xt_compat_match_offset(ematch->u.kernel.match); |
| 1064 | t = ip6t_get_target_c(e); | ||
| 1107 | off += xt_compat_target_offset(t->u.kernel.target); | 1065 | off += xt_compat_target_offset(t->u.kernel.target); |
| 1108 | newinfo->size -= off; | 1066 | newinfo->size -= off; |
| 1109 | ret = xt_compat_add_offset(AF_INET6, entry_offset, off); | 1067 | ret = xt_compat_add_offset(AF_INET6, entry_offset, off); |
| @@ -1124,7 +1082,9 @@ static int compat_calc_entry(struct ip6t_entry *e, | |||
| 1124 | static int compat_table_info(const struct xt_table_info *info, | 1082 | static int compat_table_info(const struct xt_table_info *info, |
| 1125 | struct xt_table_info *newinfo) | 1083 | struct xt_table_info *newinfo) |
| 1126 | { | 1084 | { |
| 1085 | struct ip6t_entry *iter; | ||
| 1127 | void *loc_cpu_entry; | 1086 | void *loc_cpu_entry; |
| 1087 | int ret; | ||
| 1128 | 1088 | ||
| 1129 | if (!newinfo || !info) | 1089 | if (!newinfo || !info) |
| 1130 | return -EINVAL; | 1090 | return -EINVAL; |
| @@ -1133,13 +1093,17 @@ static int compat_table_info(const struct xt_table_info *info, | |||
| 1133 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1093 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
| 1134 | newinfo->initial_entries = 0; | 1094 | newinfo->initial_entries = 0; |
| 1135 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1095 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
| 1136 | return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1096 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
| 1137 | compat_calc_entry, info, loc_cpu_entry, | 1097 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
| 1138 | newinfo); | 1098 | if (ret != 0) |
| 1099 | return ret; | ||
| 1100 | } | ||
| 1101 | return 0; | ||
| 1139 | } | 1102 | } |
| 1140 | #endif | 1103 | #endif |
| 1141 | 1104 | ||
| 1142 | static int get_info(struct net *net, void __user *user, int *len, int compat) | 1105 | static int get_info(struct net *net, void __user *user, |
| 1106 | const int *len, int compat) | ||
| 1143 | { | 1107 | { |
| 1144 | char name[IP6T_TABLE_MAXNAMELEN]; | 1108 | char name[IP6T_TABLE_MAXNAMELEN]; |
| 1145 | struct xt_table *t; | 1109 | struct xt_table *t; |
| @@ -1164,10 +1128,10 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) | |||
| 1164 | if (t && !IS_ERR(t)) { | 1128 | if (t && !IS_ERR(t)) { |
| 1165 | struct ip6t_getinfo info; | 1129 | struct ip6t_getinfo info; |
| 1166 | const struct xt_table_info *private = t->private; | 1130 | const struct xt_table_info *private = t->private; |
| 1167 | |||
| 1168 | #ifdef CONFIG_COMPAT | 1131 | #ifdef CONFIG_COMPAT |
| 1132 | struct xt_table_info tmp; | ||
| 1133 | |||
| 1169 | if (compat) { | 1134 | if (compat) { |
| 1170 | struct xt_table_info tmp; | ||
| 1171 | ret = compat_table_info(private, &tmp); | 1135 | ret = compat_table_info(private, &tmp); |
| 1172 | xt_compat_flush_offsets(AF_INET6); | 1136 | xt_compat_flush_offsets(AF_INET6); |
| 1173 | private = &tmp; | 1137 | private = &tmp; |
| @@ -1199,7 +1163,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) | |||
| 1199 | } | 1163 | } |
| 1200 | 1164 | ||
| 1201 | static int | 1165 | static int |
| 1202 | get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len) | 1166 | get_entries(struct net *net, struct ip6t_get_entries __user *uptr, |
| 1167 | const int *len) | ||
| 1203 | { | 1168 | { |
| 1204 | int ret; | 1169 | int ret; |
| 1205 | struct ip6t_get_entries get; | 1170 | struct ip6t_get_entries get; |
| @@ -1247,10 +1212,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1247 | struct xt_table_info *oldinfo; | 1212 | struct xt_table_info *oldinfo; |
| 1248 | struct xt_counters *counters; | 1213 | struct xt_counters *counters; |
| 1249 | const void *loc_cpu_old_entry; | 1214 | const void *loc_cpu_old_entry; |
| 1215 | struct ip6t_entry *iter; | ||
| 1250 | 1216 | ||
| 1251 | ret = 0; | 1217 | ret = 0; |
| 1252 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1218 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); |
| 1253 | numa_node_id()); | ||
| 1254 | if (!counters) { | 1219 | if (!counters) { |
| 1255 | ret = -ENOMEM; | 1220 | ret = -ENOMEM; |
| 1256 | goto out; | 1221 | goto out; |
| @@ -1290,8 +1255,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1290 | 1255 | ||
| 1291 | /* Decrease module usage counts and free resource */ | 1256 | /* Decrease module usage counts and free resource */ |
| 1292 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1257 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1293 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1258 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
| 1294 | NULL); | 1259 | cleanup_entry(iter, net); |
| 1260 | |||
| 1295 | xt_free_table_info(oldinfo); | 1261 | xt_free_table_info(oldinfo); |
| 1296 | if (copy_to_user(counters_ptr, counters, | 1262 | if (copy_to_user(counters_ptr, counters, |
| 1297 | sizeof(struct xt_counters) * num_counters) != 0) | 1263 | sizeof(struct xt_counters) * num_counters) != 0) |
| @@ -1310,12 +1276,13 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1310 | } | 1276 | } |
| 1311 | 1277 | ||
| 1312 | static int | 1278 | static int |
| 1313 | do_replace(struct net *net, void __user *user, unsigned int len) | 1279 | do_replace(struct net *net, const void __user *user, unsigned int len) |
| 1314 | { | 1280 | { |
| 1315 | int ret; | 1281 | int ret; |
| 1316 | struct ip6t_replace tmp; | 1282 | struct ip6t_replace tmp; |
| 1317 | struct xt_table_info *newinfo; | 1283 | struct xt_table_info *newinfo; |
| 1318 | void *loc_cpu_entry; | 1284 | void *loc_cpu_entry; |
| 1285 | struct ip6t_entry *iter; | ||
| 1319 | 1286 | ||
| 1320 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1287 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1321 | return -EFAULT; | 1288 | return -EFAULT; |
| @@ -1336,9 +1303,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1336 | goto free_newinfo; | 1303 | goto free_newinfo; |
| 1337 | } | 1304 | } |
| 1338 | 1305 | ||
| 1339 | ret = translate_table(tmp.name, tmp.valid_hooks, | 1306 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
| 1340 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
| 1341 | tmp.hook_entry, tmp.underflow); | ||
| 1342 | if (ret != 0) | 1307 | if (ret != 0) |
| 1343 | goto free_newinfo; | 1308 | goto free_newinfo; |
| 1344 | 1309 | ||
| @@ -1351,27 +1316,15 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1351 | return 0; | 1316 | return 0; |
| 1352 | 1317 | ||
| 1353 | free_newinfo_untrans: | 1318 | free_newinfo_untrans: |
| 1354 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1319 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1320 | cleanup_entry(iter, net); | ||
| 1355 | free_newinfo: | 1321 | free_newinfo: |
| 1356 | xt_free_table_info(newinfo); | 1322 | xt_free_table_info(newinfo); |
| 1357 | return ret; | 1323 | return ret; |
| 1358 | } | 1324 | } |
| 1359 | 1325 | ||
| 1360 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1361 | * and everything is OK. */ | ||
| 1362 | static int | ||
| 1363 | add_counter_to_entry(struct ip6t_entry *e, | ||
| 1364 | const struct xt_counters addme[], | ||
| 1365 | unsigned int *i) | ||
| 1366 | { | ||
| 1367 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1368 | |||
| 1369 | (*i)++; | ||
| 1370 | return 0; | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | static int | 1326 | static int |
| 1374 | do_add_counters(struct net *net, void __user *user, unsigned int len, | 1327 | do_add_counters(struct net *net, const void __user *user, unsigned int len, |
| 1375 | int compat) | 1328 | int compat) |
| 1376 | { | 1329 | { |
| 1377 | unsigned int i, curcpu; | 1330 | unsigned int i, curcpu; |
| @@ -1385,6 +1338,7 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
| 1385 | const struct xt_table_info *private; | 1338 | const struct xt_table_info *private; |
| 1386 | int ret = 0; | 1339 | int ret = 0; |
| 1387 | const void *loc_cpu_entry; | 1340 | const void *loc_cpu_entry; |
| 1341 | struct ip6t_entry *iter; | ||
| 1388 | #ifdef CONFIG_COMPAT | 1342 | #ifdef CONFIG_COMPAT |
| 1389 | struct compat_xt_counters_info compat_tmp; | 1343 | struct compat_xt_counters_info compat_tmp; |
| 1390 | 1344 | ||
| @@ -1415,7 +1369,7 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
| 1415 | if (len != size + num_counters * sizeof(struct xt_counters)) | 1369 | if (len != size + num_counters * sizeof(struct xt_counters)) |
| 1416 | return -EINVAL; | 1370 | return -EINVAL; |
| 1417 | 1371 | ||
| 1418 | paddc = vmalloc_node(len - size, numa_node_id()); | 1372 | paddc = vmalloc(len - size); |
| 1419 | if (!paddc) | 1373 | if (!paddc) |
| 1420 | return -ENOMEM; | 1374 | return -ENOMEM; |
| 1421 | 1375 | ||
| @@ -1443,11 +1397,10 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
| 1443 | curcpu = smp_processor_id(); | 1397 | curcpu = smp_processor_id(); |
| 1444 | xt_info_wrlock(curcpu); | 1398 | xt_info_wrlock(curcpu); |
| 1445 | loc_cpu_entry = private->entries[curcpu]; | 1399 | loc_cpu_entry = private->entries[curcpu]; |
| 1446 | IP6T_ENTRY_ITERATE(loc_cpu_entry, | 1400 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
| 1447 | private->size, | 1401 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
| 1448 | add_counter_to_entry, | 1402 | ++i; |
| 1449 | paddc, | 1403 | } |
| 1450 | &i); | ||
| 1451 | xt_info_wrunlock(curcpu); | 1404 | xt_info_wrunlock(curcpu); |
| 1452 | 1405 | ||
| 1453 | unlock_up_free: | 1406 | unlock_up_free: |
| @@ -1476,45 +1429,40 @@ struct compat_ip6t_replace { | |||
| 1476 | static int | 1429 | static int |
| 1477 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | 1430 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, |
| 1478 | unsigned int *size, struct xt_counters *counters, | 1431 | unsigned int *size, struct xt_counters *counters, |
| 1479 | unsigned int *i) | 1432 | unsigned int i) |
| 1480 | { | 1433 | { |
| 1481 | struct ip6t_entry_target *t; | 1434 | struct ip6t_entry_target *t; |
| 1482 | struct compat_ip6t_entry __user *ce; | 1435 | struct compat_ip6t_entry __user *ce; |
| 1483 | u_int16_t target_offset, next_offset; | 1436 | u_int16_t target_offset, next_offset; |
| 1484 | compat_uint_t origsize; | 1437 | compat_uint_t origsize; |
| 1485 | int ret; | 1438 | const struct xt_entry_match *ematch; |
| 1439 | int ret = 0; | ||
| 1486 | 1440 | ||
| 1487 | ret = -EFAULT; | ||
| 1488 | origsize = *size; | 1441 | origsize = *size; |
| 1489 | ce = (struct compat_ip6t_entry __user *)*dstptr; | 1442 | ce = (struct compat_ip6t_entry __user *)*dstptr; |
| 1490 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry))) | 1443 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || |
| 1491 | goto out; | 1444 | copy_to_user(&ce->counters, &counters[i], |
| 1492 | 1445 | sizeof(counters[i])) != 0) | |
| 1493 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1446 | return -EFAULT; |
| 1494 | goto out; | ||
| 1495 | 1447 | ||
| 1496 | *dstptr += sizeof(struct compat_ip6t_entry); | 1448 | *dstptr += sizeof(struct compat_ip6t_entry); |
| 1497 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1449 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1498 | 1450 | ||
| 1499 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1451 | xt_ematch_foreach(ematch, e) { |
| 1452 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
| 1453 | if (ret != 0) | ||
| 1454 | return ret; | ||
| 1455 | } | ||
| 1500 | target_offset = e->target_offset - (origsize - *size); | 1456 | target_offset = e->target_offset - (origsize - *size); |
| 1501 | if (ret) | ||
| 1502 | goto out; | ||
| 1503 | t = ip6t_get_target(e); | 1457 | t = ip6t_get_target(e); |
| 1504 | ret = xt_compat_target_to_user(t, dstptr, size); | 1458 | ret = xt_compat_target_to_user(t, dstptr, size); |
| 1505 | if (ret) | 1459 | if (ret) |
| 1506 | goto out; | 1460 | return ret; |
| 1507 | ret = -EFAULT; | ||
| 1508 | next_offset = e->next_offset - (origsize - *size); | 1461 | next_offset = e->next_offset - (origsize - *size); |
| 1509 | if (put_user(target_offset, &ce->target_offset)) | 1462 | if (put_user(target_offset, &ce->target_offset) != 0 || |
| 1510 | goto out; | 1463 | put_user(next_offset, &ce->next_offset) != 0) |
| 1511 | if (put_user(next_offset, &ce->next_offset)) | 1464 | return -EFAULT; |
| 1512 | goto out; | ||
| 1513 | |||
| 1514 | (*i)++; | ||
| 1515 | return 0; | 1465 | return 0; |
| 1516 | out: | ||
| 1517 | return ret; | ||
| 1518 | } | 1466 | } |
| 1519 | 1467 | ||
| 1520 | static int | 1468 | static int |
| @@ -1522,61 +1470,45 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
| 1522 | const char *name, | 1470 | const char *name, |
| 1523 | const struct ip6t_ip6 *ipv6, | 1471 | const struct ip6t_ip6 *ipv6, |
| 1524 | unsigned int hookmask, | 1472 | unsigned int hookmask, |
| 1525 | int *size, unsigned int *i) | 1473 | int *size) |
| 1526 | { | 1474 | { |
| 1527 | struct xt_match *match; | 1475 | struct xt_match *match; |
| 1528 | 1476 | ||
| 1529 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, | 1477 | match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name, |
| 1530 | m->u.user.revision), | 1478 | m->u.user.revision); |
| 1531 | "ip6t_%s", m->u.user.name); | 1479 | if (IS_ERR(match)) { |
| 1532 | if (IS_ERR(match) || !match) { | ||
| 1533 | duprintf("compat_check_calc_match: `%s' not found\n", | 1480 | duprintf("compat_check_calc_match: `%s' not found\n", |
| 1534 | m->u.user.name); | 1481 | m->u.user.name); |
| 1535 | return match ? PTR_ERR(match) : -ENOENT; | 1482 | return PTR_ERR(match); |
| 1536 | } | 1483 | } |
| 1537 | m->u.kernel.match = match; | 1484 | m->u.kernel.match = match; |
| 1538 | *size += xt_compat_match_offset(match); | 1485 | *size += xt_compat_match_offset(match); |
| 1539 | |||
| 1540 | (*i)++; | ||
| 1541 | return 0; | 1486 | return 0; |
| 1542 | } | 1487 | } |
| 1543 | 1488 | ||
| 1544 | static int | 1489 | static void compat_release_entry(struct compat_ip6t_entry *e) |
| 1545 | compat_release_match(struct ip6t_entry_match *m, unsigned int *i) | ||
| 1546 | { | ||
| 1547 | if (i && (*i)-- == 0) | ||
| 1548 | return 1; | ||
| 1549 | |||
| 1550 | module_put(m->u.kernel.match->me); | ||
| 1551 | return 0; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | static int | ||
| 1555 | compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i) | ||
| 1556 | { | 1490 | { |
| 1557 | struct ip6t_entry_target *t; | 1491 | struct ip6t_entry_target *t; |
| 1558 | 1492 | struct xt_entry_match *ematch; | |
| 1559 | if (i && (*i)-- == 0) | ||
| 1560 | return 1; | ||
| 1561 | 1493 | ||
| 1562 | /* Cleanup all matches */ | 1494 | /* Cleanup all matches */ |
| 1563 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); | 1495 | xt_ematch_foreach(ematch, e) |
| 1496 | module_put(ematch->u.kernel.match->me); | ||
| 1564 | t = compat_ip6t_get_target(e); | 1497 | t = compat_ip6t_get_target(e); |
| 1565 | module_put(t->u.kernel.target->me); | 1498 | module_put(t->u.kernel.target->me); |
| 1566 | return 0; | ||
| 1567 | } | 1499 | } |
| 1568 | 1500 | ||
| 1569 | static int | 1501 | static int |
| 1570 | check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | 1502 | check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, |
| 1571 | struct xt_table_info *newinfo, | 1503 | struct xt_table_info *newinfo, |
| 1572 | unsigned int *size, | 1504 | unsigned int *size, |
| 1573 | unsigned char *base, | 1505 | const unsigned char *base, |
| 1574 | unsigned char *limit, | 1506 | const unsigned char *limit, |
| 1575 | unsigned int *hook_entries, | 1507 | const unsigned int *hook_entries, |
| 1576 | unsigned int *underflows, | 1508 | const unsigned int *underflows, |
| 1577 | unsigned int *i, | ||
| 1578 | const char *name) | 1509 | const char *name) |
| 1579 | { | 1510 | { |
| 1511 | struct xt_entry_match *ematch; | ||
| 1580 | struct ip6t_entry_target *t; | 1512 | struct ip6t_entry_target *t; |
| 1581 | struct xt_target *target; | 1513 | struct xt_target *target; |
| 1582 | unsigned int entry_offset; | 1514 | unsigned int entry_offset; |
| @@ -1605,20 +1537,21 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
| 1605 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1537 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1606 | entry_offset = (void *)e - (void *)base; | 1538 | entry_offset = (void *)e - (void *)base; |
| 1607 | j = 0; | 1539 | j = 0; |
| 1608 | ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name, | 1540 | xt_ematch_foreach(ematch, e) { |
| 1609 | &e->ipv6, e->comefrom, &off, &j); | 1541 | ret = compat_find_calc_match(ematch, name, |
| 1610 | if (ret != 0) | 1542 | &e->ipv6, e->comefrom, &off); |
| 1611 | goto release_matches; | 1543 | if (ret != 0) |
| 1544 | goto release_matches; | ||
| 1545 | ++j; | ||
| 1546 | } | ||
| 1612 | 1547 | ||
| 1613 | t = compat_ip6t_get_target(e); | 1548 | t = compat_ip6t_get_target(e); |
| 1614 | target = try_then_request_module(xt_find_target(AF_INET6, | 1549 | target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name, |
| 1615 | t->u.user.name, | 1550 | t->u.user.revision); |
| 1616 | t->u.user.revision), | 1551 | if (IS_ERR(target)) { |
| 1617 | "ip6t_%s", t->u.user.name); | ||
| 1618 | if (IS_ERR(target) || !target) { | ||
| 1619 | duprintf("check_compat_entry_size_and_hooks: `%s' not found\n", | 1552 | duprintf("check_compat_entry_size_and_hooks: `%s' not found\n", |
| 1620 | t->u.user.name); | 1553 | t->u.user.name); |
| 1621 | ret = target ? PTR_ERR(target) : -ENOENT; | 1554 | ret = PTR_ERR(target); |
| 1622 | goto release_matches; | 1555 | goto release_matches; |
| 1623 | } | 1556 | } |
| 1624 | t->u.kernel.target = target; | 1557 | t->u.kernel.target = target; |
| @@ -1640,14 +1573,16 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
| 1640 | /* Clear counters and comefrom */ | 1573 | /* Clear counters and comefrom */ |
| 1641 | memset(&e->counters, 0, sizeof(e->counters)); | 1574 | memset(&e->counters, 0, sizeof(e->counters)); |
| 1642 | e->comefrom = 0; | 1575 | e->comefrom = 0; |
| 1643 | |||
| 1644 | (*i)++; | ||
| 1645 | return 0; | 1576 | return 0; |
| 1646 | 1577 | ||
| 1647 | out: | 1578 | out: |
| 1648 | module_put(t->u.kernel.target->me); | 1579 | module_put(t->u.kernel.target->me); |
| 1649 | release_matches: | 1580 | release_matches: |
| 1650 | IP6T_MATCH_ITERATE(e, compat_release_match, &j); | 1581 | xt_ematch_foreach(ematch, e) { |
| 1582 | if (j-- == 0) | ||
| 1583 | break; | ||
| 1584 | module_put(ematch->u.kernel.match->me); | ||
| 1585 | } | ||
| 1651 | return ret; | 1586 | return ret; |
| 1652 | } | 1587 | } |
| 1653 | 1588 | ||
| @@ -1661,6 +1596,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1661 | struct ip6t_entry *de; | 1596 | struct ip6t_entry *de; |
| 1662 | unsigned int origsize; | 1597 | unsigned int origsize; |
| 1663 | int ret, h; | 1598 | int ret, h; |
| 1599 | struct xt_entry_match *ematch; | ||
| 1664 | 1600 | ||
| 1665 | ret = 0; | 1601 | ret = 0; |
| 1666 | origsize = *size; | 1602 | origsize = *size; |
| @@ -1671,10 +1607,11 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1671 | *dstptr += sizeof(struct ip6t_entry); | 1607 | *dstptr += sizeof(struct ip6t_entry); |
| 1672 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1608 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1673 | 1609 | ||
| 1674 | ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user, | 1610 | xt_ematch_foreach(ematch, e) { |
| 1675 | dstptr, size); | 1611 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
| 1676 | if (ret) | 1612 | if (ret != 0) |
| 1677 | return ret; | 1613 | return ret; |
| 1614 | } | ||
| 1678 | de->target_offset = e->target_offset - (origsize - *size); | 1615 | de->target_offset = e->target_offset - (origsize - *size); |
| 1679 | t = compat_ip6t_get_target(e); | 1616 | t = compat_ip6t_get_target(e); |
| 1680 | target = t->u.kernel.target; | 1617 | target = t->u.kernel.target; |
| @@ -1690,36 +1627,44 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1690 | return ret; | 1627 | return ret; |
| 1691 | } | 1628 | } |
| 1692 | 1629 | ||
| 1693 | static int compat_check_entry(struct ip6t_entry *e, const char *name, | 1630 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, |
| 1694 | unsigned int *i) | 1631 | const char *name) |
| 1695 | { | 1632 | { |
| 1696 | unsigned int j; | 1633 | unsigned int j; |
| 1697 | int ret; | 1634 | int ret = 0; |
| 1698 | struct xt_mtchk_param mtpar; | 1635 | struct xt_mtchk_param mtpar; |
| 1636 | struct xt_entry_match *ematch; | ||
| 1699 | 1637 | ||
| 1700 | j = 0; | 1638 | j = 0; |
| 1639 | mtpar.net = net; | ||
| 1701 | mtpar.table = name; | 1640 | mtpar.table = name; |
| 1702 | mtpar.entryinfo = &e->ipv6; | 1641 | mtpar.entryinfo = &e->ipv6; |
| 1703 | mtpar.hook_mask = e->comefrom; | 1642 | mtpar.hook_mask = e->comefrom; |
| 1704 | mtpar.family = NFPROTO_IPV6; | 1643 | mtpar.family = NFPROTO_IPV6; |
| 1705 | ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1644 | xt_ematch_foreach(ematch, e) { |
| 1706 | if (ret) | 1645 | ret = check_match(ematch, &mtpar); |
| 1707 | goto cleanup_matches; | 1646 | if (ret != 0) |
| 1647 | goto cleanup_matches; | ||
| 1648 | ++j; | ||
| 1649 | } | ||
| 1708 | 1650 | ||
| 1709 | ret = check_target(e, name); | 1651 | ret = check_target(e, net, name); |
| 1710 | if (ret) | 1652 | if (ret) |
| 1711 | goto cleanup_matches; | 1653 | goto cleanup_matches; |
| 1712 | |||
| 1713 | (*i)++; | ||
| 1714 | return 0; | 1654 | return 0; |
| 1715 | 1655 | ||
| 1716 | cleanup_matches: | 1656 | cleanup_matches: |
| 1717 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 1657 | xt_ematch_foreach(ematch, e) { |
| 1658 | if (j-- == 0) | ||
| 1659 | break; | ||
| 1660 | cleanup_match(ematch, net); | ||
| 1661 | } | ||
| 1718 | return ret; | 1662 | return ret; |
| 1719 | } | 1663 | } |
| 1720 | 1664 | ||
| 1721 | static int | 1665 | static int |
| 1722 | translate_compat_table(const char *name, | 1666 | translate_compat_table(struct net *net, |
| 1667 | const char *name, | ||
| 1723 | unsigned int valid_hooks, | 1668 | unsigned int valid_hooks, |
| 1724 | struct xt_table_info **pinfo, | 1669 | struct xt_table_info **pinfo, |
| 1725 | void **pentry0, | 1670 | void **pentry0, |
| @@ -1731,8 +1676,10 @@ translate_compat_table(const char *name, | |||
| 1731 | unsigned int i, j; | 1676 | unsigned int i, j; |
| 1732 | struct xt_table_info *newinfo, *info; | 1677 | struct xt_table_info *newinfo, *info; |
| 1733 | void *pos, *entry0, *entry1; | 1678 | void *pos, *entry0, *entry1; |
| 1679 | struct compat_ip6t_entry *iter0; | ||
| 1680 | struct ip6t_entry *iter1; | ||
| 1734 | unsigned int size; | 1681 | unsigned int size; |
| 1735 | int ret; | 1682 | int ret = 0; |
| 1736 | 1683 | ||
| 1737 | info = *pinfo; | 1684 | info = *pinfo; |
| 1738 | entry0 = *pentry0; | 1685 | entry0 = *pentry0; |
| @@ -1749,13 +1696,17 @@ translate_compat_table(const char *name, | |||
| 1749 | j = 0; | 1696 | j = 0; |
| 1750 | xt_compat_lock(AF_INET6); | 1697 | xt_compat_lock(AF_INET6); |
| 1751 | /* Walk through entries, checking offsets. */ | 1698 | /* Walk through entries, checking offsets. */ |
| 1752 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1699 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1753 | check_compat_entry_size_and_hooks, | 1700 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
| 1754 | info, &size, entry0, | 1701 | entry0, |
| 1755 | entry0 + total_size, | 1702 | entry0 + total_size, |
| 1756 | hook_entries, underflows, &j, name); | 1703 | hook_entries, |
| 1757 | if (ret != 0) | 1704 | underflows, |
| 1758 | goto out_unlock; | 1705 | name); |
| 1706 | if (ret != 0) | ||
| 1707 | goto out_unlock; | ||
| 1708 | ++j; | ||
| 1709 | } | ||
| 1759 | 1710 | ||
| 1760 | ret = -EINVAL; | 1711 | ret = -EINVAL; |
| 1761 | if (j != number) { | 1712 | if (j != number) { |
| @@ -1794,9 +1745,12 @@ translate_compat_table(const char *name, | |||
| 1794 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1745 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
| 1795 | pos = entry1; | 1746 | pos = entry1; |
| 1796 | size = total_size; | 1747 | size = total_size; |
| 1797 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1748 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1798 | compat_copy_entry_from_user, | 1749 | ret = compat_copy_entry_from_user(iter0, &pos, &size, |
| 1799 | &pos, &size, name, newinfo, entry1); | 1750 | name, newinfo, entry1); |
| 1751 | if (ret != 0) | ||
| 1752 | break; | ||
| 1753 | } | ||
| 1800 | xt_compat_flush_offsets(AF_INET6); | 1754 | xt_compat_flush_offsets(AF_INET6); |
| 1801 | xt_compat_unlock(AF_INET6); | 1755 | xt_compat_unlock(AF_INET6); |
| 1802 | if (ret) | 1756 | if (ret) |
| @@ -1807,13 +1761,35 @@ translate_compat_table(const char *name, | |||
| 1807 | goto free_newinfo; | 1761 | goto free_newinfo; |
| 1808 | 1762 | ||
| 1809 | i = 0; | 1763 | i = 0; |
| 1810 | ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1764 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
| 1811 | name, &i); | 1765 | ret = compat_check_entry(iter1, net, name); |
| 1766 | if (ret != 0) | ||
| 1767 | break; | ||
| 1768 | ++i; | ||
| 1769 | if (strcmp(ip6t_get_target(iter1)->u.user.name, | ||
| 1770 | XT_ERROR_TARGET) == 0) | ||
| 1771 | ++newinfo->stacksize; | ||
| 1772 | } | ||
| 1812 | if (ret) { | 1773 | if (ret) { |
| 1774 | /* | ||
| 1775 | * The first i matches need cleanup_entry (calls ->destroy) | ||
| 1776 | * because they had called ->check already. The other j-i | ||
| 1777 | * entries need only release. | ||
| 1778 | */ | ||
| 1779 | int skip = i; | ||
| 1813 | j -= i; | 1780 | j -= i; |
| 1814 | COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1781 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
| 1815 | compat_release_entry, &j); | 1782 | if (skip-- > 0) |
| 1816 | IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); | 1783 | continue; |
| 1784 | if (j-- == 0) | ||
| 1785 | break; | ||
| 1786 | compat_release_entry(iter0); | ||
| 1787 | } | ||
| 1788 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
| 1789 | if (i-- == 0) | ||
| 1790 | break; | ||
| 1791 | cleanup_entry(iter1, net); | ||
| 1792 | } | ||
| 1817 | xt_free_table_info(newinfo); | 1793 | xt_free_table_info(newinfo); |
| 1818 | return ret; | 1794 | return ret; |
| 1819 | } | 1795 | } |
| @@ -1831,7 +1807,11 @@ translate_compat_table(const char *name, | |||
| 1831 | free_newinfo: | 1807 | free_newinfo: |
| 1832 | xt_free_table_info(newinfo); | 1808 | xt_free_table_info(newinfo); |
| 1833 | out: | 1809 | out: |
| 1834 | COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1810 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1811 | if (j-- == 0) | ||
| 1812 | break; | ||
| 1813 | compat_release_entry(iter0); | ||
| 1814 | } | ||
| 1835 | return ret; | 1815 | return ret; |
| 1836 | out_unlock: | 1816 | out_unlock: |
| 1837 | xt_compat_flush_offsets(AF_INET6); | 1817 | xt_compat_flush_offsets(AF_INET6); |
| @@ -1846,6 +1826,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1846 | struct compat_ip6t_replace tmp; | 1826 | struct compat_ip6t_replace tmp; |
| 1847 | struct xt_table_info *newinfo; | 1827 | struct xt_table_info *newinfo; |
| 1848 | void *loc_cpu_entry; | 1828 | void *loc_cpu_entry; |
| 1829 | struct ip6t_entry *iter; | ||
| 1849 | 1830 | ||
| 1850 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1831 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1851 | return -EFAULT; | 1832 | return -EFAULT; |
| @@ -1868,7 +1849,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1868 | goto free_newinfo; | 1849 | goto free_newinfo; |
| 1869 | } | 1850 | } |
| 1870 | 1851 | ||
| 1871 | ret = translate_compat_table(tmp.name, tmp.valid_hooks, | 1852 | ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, |
| 1872 | &newinfo, &loc_cpu_entry, tmp.size, | 1853 | &newinfo, &loc_cpu_entry, tmp.size, |
| 1873 | tmp.num_entries, tmp.hook_entry, | 1854 | tmp.num_entries, tmp.hook_entry, |
| 1874 | tmp.underflow); | 1855 | tmp.underflow); |
| @@ -1884,7 +1865,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1884 | return 0; | 1865 | return 0; |
| 1885 | 1866 | ||
| 1886 | free_newinfo_untrans: | 1867 | free_newinfo_untrans: |
| 1887 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1868 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1869 | cleanup_entry(iter, net); | ||
| 1888 | free_newinfo: | 1870 | free_newinfo: |
| 1889 | xt_free_table_info(newinfo); | 1871 | xt_free_table_info(newinfo); |
| 1890 | return ret; | 1872 | return ret; |
| @@ -1933,6 +1915,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1933 | int ret = 0; | 1915 | int ret = 0; |
| 1934 | const void *loc_cpu_entry; | 1916 | const void *loc_cpu_entry; |
| 1935 | unsigned int i = 0; | 1917 | unsigned int i = 0; |
| 1918 | struct ip6t_entry *iter; | ||
| 1936 | 1919 | ||
| 1937 | counters = alloc_counters(table); | 1920 | counters = alloc_counters(table); |
| 1938 | if (IS_ERR(counters)) | 1921 | if (IS_ERR(counters)) |
| @@ -1945,9 +1928,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1945 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1928 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 1946 | pos = userptr; | 1929 | pos = userptr; |
| 1947 | size = total_size; | 1930 | size = total_size; |
| 1948 | ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1931 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
| 1949 | compat_copy_entry_to_user, | 1932 | ret = compat_copy_entry_to_user(iter, &pos, |
| 1950 | &pos, &size, counters, &i); | 1933 | &size, counters, i++); |
| 1934 | if (ret != 0) | ||
| 1935 | break; | ||
| 1936 | } | ||
| 1951 | 1937 | ||
| 1952 | vfree(counters); | 1938 | vfree(counters); |
| 1953 | return ret; | 1939 | return ret; |
| @@ -2106,8 +2092,7 @@ struct xt_table *ip6t_register_table(struct net *net, | |||
| 2106 | { | 2092 | { |
| 2107 | int ret; | 2093 | int ret; |
| 2108 | struct xt_table_info *newinfo; | 2094 | struct xt_table_info *newinfo; |
| 2109 | struct xt_table_info bootstrap | 2095 | struct xt_table_info bootstrap = {0}; |
| 2110 | = { 0, 0, 0, { 0 }, { 0 }, { } }; | ||
| 2111 | void *loc_cpu_entry; | 2096 | void *loc_cpu_entry; |
| 2112 | struct xt_table *new_table; | 2097 | struct xt_table *new_table; |
| 2113 | 2098 | ||
| @@ -2121,11 +2106,7 @@ struct xt_table *ip6t_register_table(struct net *net, | |||
| 2121 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2106 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
| 2122 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2107 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
| 2123 | 2108 | ||
| 2124 | ret = translate_table(table->name, table->valid_hooks, | 2109 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
| 2125 | newinfo, loc_cpu_entry, repl->size, | ||
| 2126 | repl->num_entries, | ||
| 2127 | repl->hook_entry, | ||
| 2128 | repl->underflow); | ||
| 2129 | if (ret != 0) | 2110 | if (ret != 0) |
| 2130 | goto out_free; | 2111 | goto out_free; |
| 2131 | 2112 | ||
| @@ -2142,17 +2123,19 @@ out: | |||
| 2142 | return ERR_PTR(ret); | 2123 | return ERR_PTR(ret); |
| 2143 | } | 2124 | } |
| 2144 | 2125 | ||
| 2145 | void ip6t_unregister_table(struct xt_table *table) | 2126 | void ip6t_unregister_table(struct net *net, struct xt_table *table) |
| 2146 | { | 2127 | { |
| 2147 | struct xt_table_info *private; | 2128 | struct xt_table_info *private; |
| 2148 | void *loc_cpu_entry; | 2129 | void *loc_cpu_entry; |
| 2149 | struct module *table_owner = table->me; | 2130 | struct module *table_owner = table->me; |
| 2131 | struct ip6t_entry *iter; | ||
| 2150 | 2132 | ||
| 2151 | private = xt_unregister_table(table); | 2133 | private = xt_unregister_table(table); |
| 2152 | 2134 | ||
| 2153 | /* Decrease module usage counts and free resources */ | 2135 | /* Decrease module usage counts and free resources */ |
| 2154 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2136 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 2155 | IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); | 2137 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
| 2138 | cleanup_entry(iter, net); | ||
| 2156 | if (private->number > private->initial_entries) | 2139 | if (private->number > private->initial_entries) |
| 2157 | module_put(table_owner); | 2140 | module_put(table_owner); |
| 2158 | xt_free_table_info(private); | 2141 | xt_free_table_info(private); |
| @@ -2169,7 +2152,7 @@ icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code, | |||
| 2169 | } | 2152 | } |
| 2170 | 2153 | ||
| 2171 | static bool | 2154 | static bool |
| 2172 | icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par) | 2155 | icmp6_match(const struct sk_buff *skb, struct xt_action_param *par) |
| 2173 | { | 2156 | { |
| 2174 | const struct icmp6hdr *ic; | 2157 | const struct icmp6hdr *ic; |
| 2175 | struct icmp6hdr _icmph; | 2158 | struct icmp6hdr _icmph; |
| @@ -2185,7 +2168,7 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 2185 | * can't. Hence, no choice but to drop. | 2168 | * can't. Hence, no choice but to drop. |
| 2186 | */ | 2169 | */ |
| 2187 | duprintf("Dropping evil ICMP tinygram.\n"); | 2170 | duprintf("Dropping evil ICMP tinygram.\n"); |
| 2188 | *par->hotdrop = true; | 2171 | par->hotdrop = true; |
| 2189 | return false; | 2172 | return false; |
| 2190 | } | 2173 | } |
| 2191 | 2174 | ||
| @@ -2197,31 +2180,32 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 2197 | } | 2180 | } |
| 2198 | 2181 | ||
| 2199 | /* Called when user tries to insert an entry of this type. */ | 2182 | /* Called when user tries to insert an entry of this type. */ |
| 2200 | static bool icmp6_checkentry(const struct xt_mtchk_param *par) | 2183 | static int icmp6_checkentry(const struct xt_mtchk_param *par) |
| 2201 | { | 2184 | { |
| 2202 | const struct ip6t_icmp *icmpinfo = par->matchinfo; | 2185 | const struct ip6t_icmp *icmpinfo = par->matchinfo; |
| 2203 | 2186 | ||
| 2204 | /* Must specify no unknown invflags */ | 2187 | /* Must specify no unknown invflags */ |
| 2205 | return !(icmpinfo->invflags & ~IP6T_ICMP_INV); | 2188 | return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0; |
| 2206 | } | 2189 | } |
| 2207 | 2190 | ||
| 2208 | /* The built-in targets: standard (NULL) and error. */ | 2191 | /* The built-in targets: standard (NULL) and error. */ |
| 2209 | static struct xt_target ip6t_standard_target __read_mostly = { | 2192 | static struct xt_target ip6t_builtin_tg[] __read_mostly = { |
| 2210 | .name = IP6T_STANDARD_TARGET, | 2193 | { |
| 2211 | .targetsize = sizeof(int), | 2194 | .name = IP6T_STANDARD_TARGET, |
| 2212 | .family = NFPROTO_IPV6, | 2195 | .targetsize = sizeof(int), |
| 2196 | .family = NFPROTO_IPV6, | ||
| 2213 | #ifdef CONFIG_COMPAT | 2197 | #ifdef CONFIG_COMPAT |
| 2214 | .compatsize = sizeof(compat_int_t), | 2198 | .compatsize = sizeof(compat_int_t), |
| 2215 | .compat_from_user = compat_standard_from_user, | 2199 | .compat_from_user = compat_standard_from_user, |
| 2216 | .compat_to_user = compat_standard_to_user, | 2200 | .compat_to_user = compat_standard_to_user, |
| 2217 | #endif | 2201 | #endif |
| 2218 | }; | 2202 | }, |
| 2219 | 2203 | { | |
| 2220 | static struct xt_target ip6t_error_target __read_mostly = { | 2204 | .name = IP6T_ERROR_TARGET, |
| 2221 | .name = IP6T_ERROR_TARGET, | 2205 | .target = ip6t_error, |
| 2222 | .target = ip6t_error, | 2206 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, |
| 2223 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, | 2207 | .family = NFPROTO_IPV6, |
| 2224 | .family = NFPROTO_IPV6, | 2208 | }, |
| 2225 | }; | 2209 | }; |
| 2226 | 2210 | ||
| 2227 | static struct nf_sockopt_ops ip6t_sockopts = { | 2211 | static struct nf_sockopt_ops ip6t_sockopts = { |
| @@ -2241,13 +2225,15 @@ static struct nf_sockopt_ops ip6t_sockopts = { | |||
| 2241 | .owner = THIS_MODULE, | 2225 | .owner = THIS_MODULE, |
| 2242 | }; | 2226 | }; |
| 2243 | 2227 | ||
| 2244 | static struct xt_match icmp6_matchstruct __read_mostly = { | 2228 | static struct xt_match ip6t_builtin_mt[] __read_mostly = { |
| 2245 | .name = "icmp6", | 2229 | { |
| 2246 | .match = icmp6_match, | 2230 | .name = "icmp6", |
| 2247 | .matchsize = sizeof(struct ip6t_icmp), | 2231 | .match = icmp6_match, |
| 2248 | .checkentry = icmp6_checkentry, | 2232 | .matchsize = sizeof(struct ip6t_icmp), |
| 2249 | .proto = IPPROTO_ICMPV6, | 2233 | .checkentry = icmp6_checkentry, |
| 2250 | .family = NFPROTO_IPV6, | 2234 | .proto = IPPROTO_ICMPV6, |
| 2235 | .family = NFPROTO_IPV6, | ||
| 2236 | }, | ||
| 2251 | }; | 2237 | }; |
| 2252 | 2238 | ||
| 2253 | static int __net_init ip6_tables_net_init(struct net *net) | 2239 | static int __net_init ip6_tables_net_init(struct net *net) |
| @@ -2274,13 +2260,10 @@ static int __init ip6_tables_init(void) | |||
| 2274 | goto err1; | 2260 | goto err1; |
| 2275 | 2261 | ||
| 2276 | /* Noone else will be downing sem now, so we won't sleep */ | 2262 | /* Noone else will be downing sem now, so we won't sleep */ |
| 2277 | ret = xt_register_target(&ip6t_standard_target); | 2263 | ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); |
| 2278 | if (ret < 0) | 2264 | if (ret < 0) |
| 2279 | goto err2; | 2265 | goto err2; |
| 2280 | ret = xt_register_target(&ip6t_error_target); | 2266 | ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); |
| 2281 | if (ret < 0) | ||
| 2282 | goto err3; | ||
| 2283 | ret = xt_register_match(&icmp6_matchstruct); | ||
| 2284 | if (ret < 0) | 2267 | if (ret < 0) |
| 2285 | goto err4; | 2268 | goto err4; |
| 2286 | 2269 | ||
| @@ -2289,15 +2272,13 @@ static int __init ip6_tables_init(void) | |||
| 2289 | if (ret < 0) | 2272 | if (ret < 0) |
| 2290 | goto err5; | 2273 | goto err5; |
| 2291 | 2274 | ||
| 2292 | printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n"); | 2275 | pr_info("(C) 2000-2006 Netfilter Core Team\n"); |
| 2293 | return 0; | 2276 | return 0; |
| 2294 | 2277 | ||
| 2295 | err5: | 2278 | err5: |
| 2296 | xt_unregister_match(&icmp6_matchstruct); | 2279 | xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); |
| 2297 | err4: | 2280 | err4: |
| 2298 | xt_unregister_target(&ip6t_error_target); | 2281 | xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); |
| 2299 | err3: | ||
| 2300 | xt_unregister_target(&ip6t_standard_target); | ||
| 2301 | err2: | 2282 | err2: |
| 2302 | unregister_pernet_subsys(&ip6_tables_net_ops); | 2283 | unregister_pernet_subsys(&ip6_tables_net_ops); |
| 2303 | err1: | 2284 | err1: |
| @@ -2308,10 +2289,8 @@ static void __exit ip6_tables_fini(void) | |||
| 2308 | { | 2289 | { |
| 2309 | nf_unregister_sockopt(&ip6t_sockopts); | 2290 | nf_unregister_sockopt(&ip6t_sockopts); |
| 2310 | 2291 | ||
| 2311 | xt_unregister_match(&icmp6_matchstruct); | 2292 | xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); |
| 2312 | xt_unregister_target(&ip6t_error_target); | 2293 | xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); |
| 2313 | xt_unregister_target(&ip6t_standard_target); | ||
| 2314 | |||
| 2315 | unregister_pernet_subsys(&ip6_tables_net_ops); | 2294 | unregister_pernet_subsys(&ip6_tables_net_ops); |
| 2316 | } | 2295 | } |
| 2317 | 2296 | ||
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index b285fdf19050..0a07ae7b933f 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
| @@ -9,9 +9,8 @@ | |||
| 9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | */ | 11 | */ |
| 12 | 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/moduleparam.h> | ||
| 15 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
| 16 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
| 17 | #include <linux/ip.h> | 16 | #include <linux/ip.h> |
| @@ -374,11 +373,61 @@ static void dump_packet(const struct nf_loginfo *info, | |||
| 374 | printk("MARK=0x%x ", skb->mark); | 373 | printk("MARK=0x%x ", skb->mark); |
| 375 | } | 374 | } |
| 376 | 375 | ||
| 376 | static void dump_mac_header(const struct nf_loginfo *info, | ||
| 377 | const struct sk_buff *skb) | ||
| 378 | { | ||
| 379 | struct net_device *dev = skb->dev; | ||
| 380 | unsigned int logflags = 0; | ||
| 381 | |||
| 382 | if (info->type == NF_LOG_TYPE_LOG) | ||
| 383 | logflags = info->u.log.logflags; | ||
| 384 | |||
| 385 | if (!(logflags & IP6T_LOG_MACDECODE)) | ||
| 386 | goto fallback; | ||
| 387 | |||
| 388 | switch (dev->type) { | ||
| 389 | case ARPHRD_ETHER: | ||
| 390 | printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
| 391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
| 392 | ntohs(eth_hdr(skb)->h_proto)); | ||
| 393 | return; | ||
| 394 | default: | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | |||
| 398 | fallback: | ||
| 399 | printk("MAC="); | ||
| 400 | if (dev->hard_header_len && | ||
| 401 | skb->mac_header != skb->network_header) { | ||
| 402 | const unsigned char *p = skb_mac_header(skb); | ||
| 403 | unsigned int len = dev->hard_header_len; | ||
| 404 | unsigned int i; | ||
| 405 | |||
| 406 | if (dev->type == ARPHRD_SIT && | ||
| 407 | (p -= ETH_HLEN) < skb->head) | ||
| 408 | p = NULL; | ||
| 409 | |||
| 410 | if (p != NULL) { | ||
| 411 | printk("%02x", *p++); | ||
| 412 | for (i = 1; i < len; i++) | ||
| 413 | printk(":%02x", p[i]); | ||
| 414 | } | ||
| 415 | printk(" "); | ||
| 416 | |||
| 417 | if (dev->type == ARPHRD_SIT) { | ||
| 418 | const struct iphdr *iph = | ||
| 419 | (struct iphdr *)skb_mac_header(skb); | ||
| 420 | printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); | ||
| 421 | } | ||
| 422 | } else | ||
| 423 | printk(" "); | ||
| 424 | } | ||
| 425 | |||
| 377 | static struct nf_loginfo default_loginfo = { | 426 | static struct nf_loginfo default_loginfo = { |
| 378 | .type = NF_LOG_TYPE_LOG, | 427 | .type = NF_LOG_TYPE_LOG, |
| 379 | .u = { | 428 | .u = { |
| 380 | .log = { | 429 | .log = { |
| 381 | .level = 0, | 430 | .level = 5, |
| 382 | .logflags = NF_LOG_MASK, | 431 | .logflags = NF_LOG_MASK, |
| 383 | }, | 432 | }, |
| 384 | }, | 433 | }, |
| @@ -401,35 +450,10 @@ ip6t_log_packet(u_int8_t pf, | |||
| 401 | prefix, | 450 | prefix, |
| 402 | in ? in->name : "", | 451 | in ? in->name : "", |
| 403 | out ? out->name : ""); | 452 | out ? out->name : ""); |
| 404 | if (in && !out) { | ||
| 405 | unsigned int len; | ||
| 406 | /* MAC logging for input chain only. */ | ||
| 407 | printk("MAC="); | ||
| 408 | if (skb->dev && (len = skb->dev->hard_header_len) && | ||
| 409 | skb->mac_header != skb->network_header) { | ||
| 410 | const unsigned char *p = skb_mac_header(skb); | ||
| 411 | int i; | ||
| 412 | |||
| 413 | if (skb->dev->type == ARPHRD_SIT && | ||
| 414 | (p -= ETH_HLEN) < skb->head) | ||
| 415 | p = NULL; | ||
| 416 | |||
| 417 | if (p != NULL) { | ||
| 418 | for (i = 0; i < len; i++) | ||
| 419 | printk("%02x%s", p[i], | ||
| 420 | i == len - 1 ? "" : ":"); | ||
| 421 | } | ||
| 422 | printk(" "); | ||
| 423 | 453 | ||
| 424 | if (skb->dev->type == ARPHRD_SIT) { | 454 | /* MAC logging for input path only. */ |
| 425 | const struct iphdr *iph = | 455 | if (in && !out) |
| 426 | (struct iphdr *)skb_mac_header(skb); | 456 | dump_mac_header(loginfo, skb); |
| 427 | printk("TUNNEL=%pI4->%pI4 ", | ||
| 428 | &iph->saddr, &iph->daddr); | ||
| 429 | } | ||
| 430 | } else | ||
| 431 | printk(" "); | ||
| 432 | } | ||
| 433 | 457 | ||
| 434 | dump_packet(loginfo, skb, skb_network_offset(skb), 1); | 458 | dump_packet(loginfo, skb, skb_network_offset(skb), 1); |
| 435 | printk("\n"); | 459 | printk("\n"); |
| @@ -437,7 +461,7 @@ ip6t_log_packet(u_int8_t pf, | |||
| 437 | } | 461 | } |
| 438 | 462 | ||
| 439 | static unsigned int | 463 | static unsigned int |
| 440 | log_tg6(struct sk_buff *skb, const struct xt_target_param *par) | 464 | log_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
| 441 | { | 465 | { |
| 442 | const struct ip6t_log_info *loginfo = par->targinfo; | 466 | const struct ip6t_log_info *loginfo = par->targinfo; |
| 443 | struct nf_loginfo li; | 467 | struct nf_loginfo li; |
| @@ -452,20 +476,19 @@ log_tg6(struct sk_buff *skb, const struct xt_target_param *par) | |||
| 452 | } | 476 | } |
| 453 | 477 | ||
| 454 | 478 | ||
| 455 | static bool log_tg6_check(const struct xt_tgchk_param *par) | 479 | static int log_tg6_check(const struct xt_tgchk_param *par) |
| 456 | { | 480 | { |
| 457 | const struct ip6t_log_info *loginfo = par->targinfo; | 481 | const struct ip6t_log_info *loginfo = par->targinfo; |
| 458 | 482 | ||
| 459 | if (loginfo->level >= 8) { | 483 | if (loginfo->level >= 8) { |
| 460 | pr_debug("LOG: level %u >= 8\n", loginfo->level); | 484 | pr_debug("level %u >= 8\n", loginfo->level); |
| 461 | return false; | 485 | return -EINVAL; |
| 462 | } | 486 | } |
| 463 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | 487 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { |
| 464 | pr_debug("LOG: prefix term %i\n", | 488 | pr_debug("prefix not null-terminated\n"); |
| 465 | loginfo->prefix[sizeof(loginfo->prefix)-1]); | 489 | return -EINVAL; |
| 466 | return false; | ||
| 467 | } | 490 | } |
| 468 | return true; | 491 | return 0; |
| 469 | } | 492 | } |
| 470 | 493 | ||
| 471 | static struct xt_target log_tg6_reg __read_mostly = { | 494 | static struct xt_target log_tg6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 8311ca31816a..2933396e0281 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
| @@ -14,7 +14,9 @@ | |||
| 14 | * as published by the Free Software Foundation; either version | 14 | * as published by the Free Software Foundation; either version |
| 15 | * 2 of the License, or (at your option) any later version. | 15 | * 2 of the License, or (at your option) any later version. |
| 16 | */ | 16 | */ |
| 17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 17 | 18 | ||
| 19 | #include <linux/gfp.h> | ||
| 18 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 19 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
| 20 | #include <linux/icmpv6.h> | 22 | #include <linux/icmpv6.h> |
| @@ -49,7 +51,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 49 | 51 | ||
| 50 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || | 52 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || |
| 51 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { | 53 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { |
| 52 | pr_debug("ip6t_REJECT: addr is not unicast.\n"); | 54 | pr_debug("addr is not unicast.\n"); |
| 53 | return; | 55 | return; |
| 54 | } | 56 | } |
| 55 | 57 | ||
| @@ -57,7 +59,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 57 | tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto); | 59 | tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto); |
| 58 | 60 | ||
| 59 | if ((tcphoff < 0) || (tcphoff > oldskb->len)) { | 61 | if ((tcphoff < 0) || (tcphoff > oldskb->len)) { |
| 60 | pr_debug("ip6t_REJECT: Can't get TCP header.\n"); | 62 | pr_debug("Cannot get TCP header.\n"); |
| 61 | return; | 63 | return; |
| 62 | } | 64 | } |
| 63 | 65 | ||
| @@ -65,7 +67,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 65 | 67 | ||
| 66 | /* IP header checks: fragment, too short. */ | 68 | /* IP header checks: fragment, too short. */ |
| 67 | if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { | 69 | if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { |
| 68 | pr_debug("ip6t_REJECT: proto(%d) != IPPROTO_TCP, " | 70 | pr_debug("proto(%d) != IPPROTO_TCP, " |
| 69 | "or too short. otcplen = %d\n", | 71 | "or too short. otcplen = %d\n", |
| 70 | proto, otcplen); | 72 | proto, otcplen); |
| 71 | return; | 73 | return; |
| @@ -76,14 +78,14 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 76 | 78 | ||
| 77 | /* No RST for RST. */ | 79 | /* No RST for RST. */ |
| 78 | if (otcph.rst) { | 80 | if (otcph.rst) { |
| 79 | pr_debug("ip6t_REJECT: RST is set\n"); | 81 | pr_debug("RST is set\n"); |
| 80 | return; | 82 | return; |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | /* Check checksum. */ | 85 | /* Check checksum. */ |
| 84 | if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP, | 86 | if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP, |
| 85 | skb_checksum(oldskb, tcphoff, otcplen, 0))) { | 87 | skb_checksum(oldskb, tcphoff, otcplen, 0))) { |
| 86 | pr_debug("ip6t_REJECT: TCP checksum is invalid\n"); | 88 | pr_debug("TCP checksum is invalid\n"); |
| 87 | return; | 89 | return; |
| 88 | } | 90 | } |
| 89 | 91 | ||
| @@ -95,9 +97,11 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 95 | fl.fl_ip_dport = otcph.source; | 97 | fl.fl_ip_dport = otcph.source; |
| 96 | security_skb_classify_flow(oldskb, &fl); | 98 | security_skb_classify_flow(oldskb, &fl); |
| 97 | dst = ip6_route_output(net, NULL, &fl); | 99 | dst = ip6_route_output(net, NULL, &fl); |
| 98 | if (dst == NULL) | 100 | if (dst == NULL || dst->error) { |
| 101 | dst_release(dst); | ||
| 99 | return; | 102 | return; |
| 100 | if (dst->error || xfrm_lookup(net, &dst, &fl, NULL, 0)) | 103 | } |
| 104 | if (xfrm_lookup(net, &dst, &fl, NULL, 0)) | ||
| 101 | return; | 105 | return; |
| 102 | 106 | ||
| 103 | hh_len = (dst->dev->hard_header_len + 15)&~15; | 107 | hh_len = (dst->dev->hard_header_len + 15)&~15; |
| @@ -107,7 +111,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
| 107 | 111 | ||
| 108 | if (!nskb) { | 112 | if (!nskb) { |
| 109 | if (net_ratelimit()) | 113 | if (net_ratelimit()) |
| 110 | printk("ip6t_REJECT: Can't alloc skb\n"); | 114 | pr_debug("cannot alloc skb\n"); |
| 111 | dst_release(dst); | 115 | dst_release(dst); |
| 112 | return; | 116 | return; |
| 113 | } | 117 | } |
| @@ -169,19 +173,16 @@ send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code, | |||
| 169 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | 173 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) |
| 170 | skb_in->dev = net->loopback_dev; | 174 | skb_in->dev = net->loopback_dev; |
| 171 | 175 | ||
| 172 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); | 176 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); |
| 173 | } | 177 | } |
| 174 | 178 | ||
| 175 | static unsigned int | 179 | static unsigned int |
| 176 | reject_tg6(struct sk_buff *skb, const struct xt_target_param *par) | 180 | reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
| 177 | { | 181 | { |
| 178 | const struct ip6t_reject_info *reject = par->targinfo; | 182 | const struct ip6t_reject_info *reject = par->targinfo; |
| 179 | struct net *net = dev_net((par->in != NULL) ? par->in : par->out); | 183 | struct net *net = dev_net((par->in != NULL) ? par->in : par->out); |
| 180 | 184 | ||
| 181 | pr_debug("%s: medium point\n", __func__); | 185 | pr_debug("%s: medium point\n", __func__); |
| 182 | /* WARNING: This code causes reentry within ip6tables. | ||
| 183 | This means that the ip6tables jump stack is now crap. We | ||
| 184 | must return an absolute verdict. --RR */ | ||
| 185 | switch (reject->with) { | 186 | switch (reject->with) { |
| 186 | case IP6T_ICMP6_NO_ROUTE: | 187 | case IP6T_ICMP6_NO_ROUTE: |
| 187 | send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum); | 188 | send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum); |
| @@ -206,30 +207,30 @@ reject_tg6(struct sk_buff *skb, const struct xt_target_param *par) | |||
| 206 | break; | 207 | break; |
| 207 | default: | 208 | default: |
| 208 | if (net_ratelimit()) | 209 | if (net_ratelimit()) |
| 209 | printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with); | 210 | pr_info("case %u not handled yet\n", reject->with); |
| 210 | break; | 211 | break; |
| 211 | } | 212 | } |
| 212 | 213 | ||
| 213 | return NF_DROP; | 214 | return NF_DROP; |
| 214 | } | 215 | } |
| 215 | 216 | ||
| 216 | static bool reject_tg6_check(const struct xt_tgchk_param *par) | 217 | static int reject_tg6_check(const struct xt_tgchk_param *par) |
| 217 | { | 218 | { |
| 218 | const struct ip6t_reject_info *rejinfo = par->targinfo; | 219 | const struct ip6t_reject_info *rejinfo = par->targinfo; |
| 219 | const struct ip6t_entry *e = par->entryinfo; | 220 | const struct ip6t_entry *e = par->entryinfo; |
| 220 | 221 | ||
| 221 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { | 222 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { |
| 222 | printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); | 223 | pr_info("ECHOREPLY is not supported.\n"); |
| 223 | return false; | 224 | return -EINVAL; |
| 224 | } else if (rejinfo->with == IP6T_TCP_RESET) { | 225 | } else if (rejinfo->with == IP6T_TCP_RESET) { |
| 225 | /* Must specify that it's a TCP packet */ | 226 | /* Must specify that it's a TCP packet */ |
| 226 | if (e->ipv6.proto != IPPROTO_TCP || | 227 | if (e->ipv6.proto != IPPROTO_TCP || |
| 227 | (e->ipv6.invflags & XT_INV_PROTO)) { | 228 | (e->ipv6.invflags & XT_INV_PROTO)) { |
| 228 | printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n"); | 229 | pr_info("TCP_RESET illegal for non-tcp\n"); |
| 229 | return false; | 230 | return -EINVAL; |
| 230 | } | 231 | } |
| 231 | } | 232 | } |
| 232 | return true; | 233 | return 0; |
| 233 | } | 234 | } |
| 234 | 235 | ||
| 235 | static struct xt_target reject_tg6_reg __read_mostly = { | 236 | static struct xt_target reject_tg6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index ac0b7c629d78..89cccc5a9c92 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
| 12 | #include <linux/ip.h> | 12 | #include <linux/ip.h> |
| @@ -29,14 +29,14 @@ spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert) | |||
| 29 | { | 29 | { |
| 30 | bool r; | 30 | bool r; |
| 31 | 31 | ||
| 32 | pr_debug("ah spi_match:%c 0x%x <= 0x%x <= 0x%x", | 32 | pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n", |
| 33 | invert ? '!' : ' ', min, spi, max); | 33 | invert ? '!' : ' ', min, spi, max); |
| 34 | r = (spi >= min && spi <= max) ^ invert; | 34 | r = (spi >= min && spi <= max) ^ invert; |
| 35 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); | 35 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
| 36 | return r; | 36 | return r; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 39 | static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 40 | { | 40 | { |
| 41 | struct ip_auth_hdr _ah; | 41 | struct ip_auth_hdr _ah; |
| 42 | const struct ip_auth_hdr *ah; | 42 | const struct ip_auth_hdr *ah; |
| @@ -48,13 +48,13 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 48 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL); | 48 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL); |
| 49 | if (err < 0) { | 49 | if (err < 0) { |
| 50 | if (err != -ENOENT) | 50 | if (err != -ENOENT) |
| 51 | *par->hotdrop = true; | 51 | par->hotdrop = true; |
| 52 | return false; | 52 | return false; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); | 55 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
| 56 | if (ah == NULL) { | 56 | if (ah == NULL) { |
| 57 | *par->hotdrop = true; | 57 | par->hotdrop = true; |
| 58 | return false; | 58 | return false; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| @@ -87,15 +87,15 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 87 | !(ahinfo->hdrres && ah->reserved); | 87 | !(ahinfo->hdrres && ah->reserved); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static bool ah_mt6_check(const struct xt_mtchk_param *par) | 90 | static int ah_mt6_check(const struct xt_mtchk_param *par) |
| 91 | { | 91 | { |
| 92 | const struct ip6t_ah *ahinfo = par->matchinfo; | 92 | const struct ip6t_ah *ahinfo = par->matchinfo; |
| 93 | 93 | ||
| 94 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { | 94 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
| 95 | pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags); | 95 | pr_debug("unknown flags %X\n", ahinfo->invflags); |
| 96 | return false; | 96 | return -EINVAL; |
| 97 | } | 97 | } |
| 98 | return true; | 98 | return 0; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static struct xt_match ah_mt6_reg __read_mostly = { | 101 | static struct xt_match ah_mt6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index ca287f6d2bce..aab0706908c5 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c | |||
| @@ -20,14 +20,14 @@ MODULE_LICENSE("GPL"); | |||
| 20 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | 20 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
| 21 | 21 | ||
| 22 | static bool | 22 | static bool |
| 23 | eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 23 | eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 24 | { | 24 | { |
| 25 | unsigned char eui64[8]; | 25 | unsigned char eui64[8]; |
| 26 | 26 | ||
| 27 | if (!(skb_mac_header(skb) >= skb->head && | 27 | if (!(skb_mac_header(skb) >= skb->head && |
| 28 | skb_mac_header(skb) + ETH_HLEN <= skb->data) && | 28 | skb_mac_header(skb) + ETH_HLEN <= skb->data) && |
| 29 | par->fragoff != 0) { | 29 | par->fragoff != 0) { |
| 30 | *par->hotdrop = true; | 30 | par->hotdrop = true; |
| 31 | return false; | 31 | return false; |
| 32 | } | 32 | } |
| 33 | 33 | ||
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 7b91c2598ed5..eda898fda6ca 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
| 12 | #include <linux/ipv6.h> | 12 | #include <linux/ipv6.h> |
| @@ -27,7 +27,7 @@ static inline bool | |||
| 27 | id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) | 27 | id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) |
| 28 | { | 28 | { |
| 29 | bool r; | 29 | bool r; |
| 30 | pr_debug("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ', | 30 | pr_debug("id_match:%c 0x%x <= 0x%x <= 0x%x\n", invert ? '!' : ' ', |
| 31 | min, id, max); | 31 | min, id, max); |
| 32 | r = (id >= min && id <= max) ^ invert; | 32 | r = (id >= min && id <= max) ^ invert; |
| 33 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); | 33 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
| @@ -35,7 +35,7 @@ id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) | |||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | static bool | 37 | static bool |
| 38 | frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 38 | frag_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 39 | { | 39 | { |
| 40 | struct frag_hdr _frag; | 40 | struct frag_hdr _frag; |
| 41 | const struct frag_hdr *fh; | 41 | const struct frag_hdr *fh; |
| @@ -46,13 +46,13 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 46 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); | 46 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); |
| 47 | if (err < 0) { | 47 | if (err < 0) { |
| 48 | if (err != -ENOENT) | 48 | if (err != -ENOENT) |
| 49 | *par->hotdrop = true; | 49 | par->hotdrop = true; |
| 50 | return false; | 50 | return false; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); | 53 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
| 54 | if (fh == NULL) { | 54 | if (fh == NULL) { |
| 55 | *par->hotdrop = true; | 55 | par->hotdrop = true; |
| 56 | return false; | 56 | return false; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| @@ -102,15 +102,15 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 102 | (ntohs(fh->frag_off) & IP6_MF)); | 102 | (ntohs(fh->frag_off) & IP6_MF)); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static bool frag_mt6_check(const struct xt_mtchk_param *par) | 105 | static int frag_mt6_check(const struct xt_mtchk_param *par) |
| 106 | { | 106 | { |
| 107 | const struct ip6t_frag *fraginfo = par->matchinfo; | 107 | const struct ip6t_frag *fraginfo = par->matchinfo; |
| 108 | 108 | ||
| 109 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { | 109 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
| 110 | pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags); | 110 | pr_debug("unknown flags %X\n", fraginfo->invflags); |
| 111 | return false; | 111 | return -EINVAL; |
| 112 | } | 112 | } |
| 113 | return true; | 113 | return 0; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | static struct xt_match frag_mt6_reg __read_mostly = { | 116 | static struct xt_match frag_mt6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index cbe8dec9744b..59df051eaef6 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
| 12 | #include <linux/ipv6.h> | 12 | #include <linux/ipv6.h> |
| @@ -41,8 +41,10 @@ MODULE_ALIAS("ip6t_dst"); | |||
| 41 | * 5 -> RTALERT 2 x x | 41 | * 5 -> RTALERT 2 x x |
| 42 | */ | 42 | */ |
| 43 | 43 | ||
| 44 | static struct xt_match hbh_mt6_reg[] __read_mostly; | ||
| 45 | |||
| 44 | static bool | 46 | static bool |
| 45 | hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 47 | hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 46 | { | 48 | { |
| 47 | struct ipv6_opt_hdr _optsh; | 49 | struct ipv6_opt_hdr _optsh; |
| 48 | const struct ipv6_opt_hdr *oh; | 50 | const struct ipv6_opt_hdr *oh; |
| @@ -58,16 +60,18 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 58 | unsigned int optlen; | 60 | unsigned int optlen; |
| 59 | int err; | 61 | int err; |
| 60 | 62 | ||
| 61 | err = ipv6_find_hdr(skb, &ptr, par->match->data, NULL); | 63 | err = ipv6_find_hdr(skb, &ptr, |
| 64 | (par->match == &hbh_mt6_reg[0]) ? | ||
| 65 | NEXTHDR_HOP : NEXTHDR_DEST, NULL); | ||
| 62 | if (err < 0) { | 66 | if (err < 0) { |
| 63 | if (err != -ENOENT) | 67 | if (err != -ENOENT) |
| 64 | *par->hotdrop = true; | 68 | par->hotdrop = true; |
| 65 | return false; | 69 | return false; |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 68 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | 72 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); |
| 69 | if (oh == NULL) { | 73 | if (oh == NULL) { |
| 70 | *par->hotdrop = true; | 74 | par->hotdrop = true; |
| 71 | return false; | 75 | return false; |
| 72 | } | 76 | } |
| 73 | 77 | ||
| @@ -141,11 +145,11 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 141 | } | 145 | } |
| 142 | 146 | ||
| 143 | /* Step to the next */ | 147 | /* Step to the next */ |
| 144 | pr_debug("len%04X \n", optlen); | 148 | pr_debug("len%04X\n", optlen); |
| 145 | 149 | ||
| 146 | if ((ptr > skb->len - optlen || hdrlen < optlen) && | 150 | if ((ptr > skb->len - optlen || hdrlen < optlen) && |
| 147 | temp < optinfo->optsnr - 1) { | 151 | temp < optinfo->optsnr - 1) { |
| 148 | pr_debug("new pointer is too large! \n"); | 152 | pr_debug("new pointer is too large!\n"); |
| 149 | break; | 153 | break; |
| 150 | } | 154 | } |
| 151 | ptr += optlen; | 155 | ptr += optlen; |
| @@ -160,32 +164,32 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 160 | return false; | 164 | return false; |
| 161 | } | 165 | } |
| 162 | 166 | ||
| 163 | static bool hbh_mt6_check(const struct xt_mtchk_param *par) | 167 | static int hbh_mt6_check(const struct xt_mtchk_param *par) |
| 164 | { | 168 | { |
| 165 | const struct ip6t_opts *optsinfo = par->matchinfo; | 169 | const struct ip6t_opts *optsinfo = par->matchinfo; |
| 166 | 170 | ||
| 167 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | 171 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { |
| 168 | pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | 172 | pr_debug("unknown flags %X\n", optsinfo->invflags); |
| 169 | return false; | 173 | return -EINVAL; |
| 170 | } | 174 | } |
| 171 | 175 | ||
| 172 | if (optsinfo->flags & IP6T_OPTS_NSTRICT) { | 176 | if (optsinfo->flags & IP6T_OPTS_NSTRICT) { |
| 173 | pr_debug("ip6t_opts: Not strict - not implemented"); | 177 | pr_debug("Not strict - not implemented"); |
| 174 | return false; | 178 | return -EINVAL; |
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | return true; | 181 | return 0; |
| 178 | } | 182 | } |
| 179 | 183 | ||
| 180 | static struct xt_match hbh_mt6_reg[] __read_mostly = { | 184 | static struct xt_match hbh_mt6_reg[] __read_mostly = { |
| 181 | { | 185 | { |
| 186 | /* Note, hbh_mt6 relies on the order of hbh_mt6_reg */ | ||
| 182 | .name = "hbh", | 187 | .name = "hbh", |
| 183 | .family = NFPROTO_IPV6, | 188 | .family = NFPROTO_IPV6, |
| 184 | .match = hbh_mt6, | 189 | .match = hbh_mt6, |
| 185 | .matchsize = sizeof(struct ip6t_opts), | 190 | .matchsize = sizeof(struct ip6t_opts), |
| 186 | .checkentry = hbh_mt6_check, | 191 | .checkentry = hbh_mt6_check, |
| 187 | .me = THIS_MODULE, | 192 | .me = THIS_MODULE, |
| 188 | .data = NEXTHDR_HOP, | ||
| 189 | }, | 193 | }, |
| 190 | { | 194 | { |
| 191 | .name = "dst", | 195 | .name = "dst", |
| @@ -194,7 +198,6 @@ static struct xt_match hbh_mt6_reg[] __read_mostly = { | |||
| 194 | .matchsize = sizeof(struct ip6t_opts), | 198 | .matchsize = sizeof(struct ip6t_opts), |
| 195 | .checkentry = hbh_mt6_check, | 199 | .checkentry = hbh_mt6_check, |
| 196 | .me = THIS_MODULE, | 200 | .me = THIS_MODULE, |
| 197 | .data = NEXTHDR_DEST, | ||
| 198 | }, | 201 | }, |
| 199 | }; | 202 | }; |
| 200 | 203 | ||
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 91490ad9302c..54bd9790603f 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
| @@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Xtables: IPv6 header types match"); | |||
| 27 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | 27 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
| 28 | 28 | ||
| 29 | static bool | 29 | static bool |
| 30 | ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 30 | ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 31 | { | 31 | { |
| 32 | const struct ip6t_ipv6header_info *info = par->matchinfo; | 32 | const struct ip6t_ipv6header_info *info = par->matchinfo; |
| 33 | unsigned int temp; | 33 | unsigned int temp; |
| @@ -118,16 +118,16 @@ ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 118 | } | 118 | } |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static bool ipv6header_mt6_check(const struct xt_mtchk_param *par) | 121 | static int ipv6header_mt6_check(const struct xt_mtchk_param *par) |
| 122 | { | 122 | { |
| 123 | const struct ip6t_ipv6header_info *info = par->matchinfo; | 123 | const struct ip6t_ipv6header_info *info = par->matchinfo; |
| 124 | 124 | ||
| 125 | /* invflags is 0 or 0xff in hard mode */ | 125 | /* invflags is 0 or 0xff in hard mode */ |
| 126 | if ((!info->modeflag) && info->invflags != 0x00 && | 126 | if ((!info->modeflag) && info->invflags != 0x00 && |
| 127 | info->invflags != 0xFF) | 127 | info->invflags != 0xFF) |
| 128 | return false; | 128 | return -EINVAL; |
| 129 | 129 | ||
| 130 | return true; | 130 | return 0; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static struct xt_match ipv6header_mt6_reg __read_mostly = { | 133 | static struct xt_match ipv6header_mt6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c index aafe4e66577b..0c90c66b1992 100644 --- a/net/ipv6/netfilter/ip6t_mh.c +++ b/net/ipv6/netfilter/ip6t_mh.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | * Based on net/netfilter/xt_tcpudp.c | 11 | * Based on net/netfilter/xt_tcpudp.c |
| 12 | * | 12 | * |
| 13 | */ | 13 | */ |
| 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 14 | #include <linux/types.h> | 15 | #include <linux/types.h> |
| 15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
| @@ -24,12 +25,6 @@ | |||
| 24 | MODULE_DESCRIPTION("Xtables: IPv6 Mobility Header match"); | 25 | MODULE_DESCRIPTION("Xtables: IPv6 Mobility Header match"); |
| 25 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
| 26 | 27 | ||
| 27 | #ifdef DEBUG_IP_FIREWALL_USER | ||
| 28 | #define duprintf(format, args...) printk(format , ## args) | ||
| 29 | #else | ||
| 30 | #define duprintf(format, args...) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* Returns 1 if the type is matched by the range, 0 otherwise */ | 28 | /* Returns 1 if the type is matched by the range, 0 otherwise */ |
| 34 | static inline bool | 29 | static inline bool |
| 35 | type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert) | 30 | type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert) |
| @@ -37,7 +32,7 @@ type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert) | |||
| 37 | return (type >= min && type <= max) ^ invert; | 32 | return (type >= min && type <= max) ^ invert; |
| 38 | } | 33 | } |
| 39 | 34 | ||
| 40 | static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 35 | static bool mh_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 41 | { | 36 | { |
| 42 | struct ip6_mh _mh; | 37 | struct ip6_mh _mh; |
| 43 | const struct ip6_mh *mh; | 38 | const struct ip6_mh *mh; |
| @@ -51,15 +46,15 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 51 | if (mh == NULL) { | 46 | if (mh == NULL) { |
| 52 | /* We've been asked to examine this packet, and we | 47 | /* We've been asked to examine this packet, and we |
| 53 | can't. Hence, no choice but to drop. */ | 48 | can't. Hence, no choice but to drop. */ |
| 54 | duprintf("Dropping evil MH tinygram.\n"); | 49 | pr_debug("Dropping evil MH tinygram.\n"); |
| 55 | *par->hotdrop = true; | 50 | par->hotdrop = true; |
| 56 | return false; | 51 | return false; |
| 57 | } | 52 | } |
| 58 | 53 | ||
| 59 | if (mh->ip6mh_proto != IPPROTO_NONE) { | 54 | if (mh->ip6mh_proto != IPPROTO_NONE) { |
| 60 | duprintf("Dropping invalid MH Payload Proto: %u\n", | 55 | pr_debug("Dropping invalid MH Payload Proto: %u\n", |
| 61 | mh->ip6mh_proto); | 56 | mh->ip6mh_proto); |
| 62 | *par->hotdrop = true; | 57 | par->hotdrop = true; |
| 63 | return false; | 58 | return false; |
| 64 | } | 59 | } |
| 65 | 60 | ||
| @@ -67,12 +62,12 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 67 | !!(mhinfo->invflags & IP6T_MH_INV_TYPE)); | 62 | !!(mhinfo->invflags & IP6T_MH_INV_TYPE)); |
| 68 | } | 63 | } |
| 69 | 64 | ||
| 70 | static bool mh_mt6_check(const struct xt_mtchk_param *par) | 65 | static int mh_mt6_check(const struct xt_mtchk_param *par) |
| 71 | { | 66 | { |
| 72 | const struct ip6t_mh *mhinfo = par->matchinfo; | 67 | const struct ip6t_mh *mhinfo = par->matchinfo; |
| 73 | 68 | ||
| 74 | /* Must specify no unknown invflags */ | 69 | /* Must specify no unknown invflags */ |
| 75 | return !(mhinfo->invflags & ~IP6T_MH_INV_MASK); | 70 | return (mhinfo->invflags & ~IP6T_MH_INV_MASK) ? -EINVAL : 0; |
| 76 | } | 71 | } |
| 77 | 72 | ||
| 78 | static struct xt_match mh_mt6_reg __read_mostly = { | 73 | static struct xt_match mh_mt6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index b77307fc8743..d8488c50a8e0 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
| 12 | #include <linux/ipv6.h> | 12 | #include <linux/ipv6.h> |
| @@ -29,14 +29,14 @@ static inline bool | |||
| 29 | segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) | 29 | segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) |
| 30 | { | 30 | { |
| 31 | bool r; | 31 | bool r; |
| 32 | pr_debug("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x", | 32 | pr_debug("segsleft_match:%c 0x%x <= 0x%x <= 0x%x\n", |
| 33 | invert ? '!' : ' ', min, id, max); | 33 | invert ? '!' : ' ', min, id, max); |
| 34 | r = (id >= min && id <= max) ^ invert; | 34 | r = (id >= min && id <= max) ^ invert; |
| 35 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); | 35 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
| 36 | return r; | 36 | return r; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | 39 | static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
| 40 | { | 40 | { |
| 41 | struct ipv6_rt_hdr _route; | 41 | struct ipv6_rt_hdr _route; |
| 42 | const struct ipv6_rt_hdr *rh; | 42 | const struct ipv6_rt_hdr *rh; |
| @@ -52,13 +52,13 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 52 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL); | 52 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL); |
| 53 | if (err < 0) { | 53 | if (err < 0) { |
| 54 | if (err != -ENOENT) | 54 | if (err != -ENOENT) |
| 55 | *par->hotdrop = true; | 55 | par->hotdrop = true; |
| 56 | return false; | 56 | return false; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); | 59 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); |
| 60 | if (rh == NULL) { | 60 | if (rh == NULL) { |
| 61 | *par->hotdrop = true; | 61 | par->hotdrop = true; |
| 62 | return false; | 62 | return false; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| @@ -183,23 +183,23 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 183 | return false; | 183 | return false; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static bool rt_mt6_check(const struct xt_mtchk_param *par) | 186 | static int rt_mt6_check(const struct xt_mtchk_param *par) |
| 187 | { | 187 | { |
| 188 | const struct ip6t_rt *rtinfo = par->matchinfo; | 188 | const struct ip6t_rt *rtinfo = par->matchinfo; |
| 189 | 189 | ||
| 190 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { | 190 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { |
| 191 | pr_debug("ip6t_rt: unknown flags %X\n", rtinfo->invflags); | 191 | pr_debug("unknown flags %X\n", rtinfo->invflags); |
| 192 | return false; | 192 | return -EINVAL; |
| 193 | } | 193 | } |
| 194 | if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) && | 194 | if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) && |
| 195 | (!(rtinfo->flags & IP6T_RT_TYP) || | 195 | (!(rtinfo->flags & IP6T_RT_TYP) || |
| 196 | (rtinfo->rt_type != 0) || | 196 | (rtinfo->rt_type != 0) || |
| 197 | (rtinfo->invflags & IP6T_RT_INV_TYP))) { | 197 | (rtinfo->invflags & IP6T_RT_INV_TYP))) { |
| 198 | pr_debug("`--rt-type 0' required before `--rt-0-*'"); | 198 | pr_debug("`--rt-type 0' required before `--rt-0-*'"); |
| 199 | return false; | 199 | return -EINVAL; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | return true; | 202 | return 0; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static struct xt_match rt_mt6_reg __read_mostly = { | 205 | static struct xt_match rt_mt6_reg __read_mostly = { |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index ad378efd0eb8..c9e37c8fd62c 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
| 14 | #include <linux/netfilter_ipv6/ip6_tables.h> | 14 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 15 | #include <linux/slab.h> | ||
| 15 | 16 | ||
| 16 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
| 17 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 18 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
| @@ -21,99 +22,26 @@ MODULE_DESCRIPTION("ip6tables filter table"); | |||
| 21 | (1 << NF_INET_FORWARD) | \ | 22 | (1 << NF_INET_FORWARD) | \ |
| 22 | (1 << NF_INET_LOCAL_OUT)) | 23 | (1 << NF_INET_LOCAL_OUT)) |
| 23 | 24 | ||
| 24 | static struct | ||
| 25 | { | ||
| 26 | struct ip6t_replace repl; | ||
| 27 | struct ip6t_standard entries[3]; | ||
| 28 | struct ip6t_error term; | ||
| 29 | } initial_table __net_initdata = { | ||
| 30 | .repl = { | ||
| 31 | .name = "filter", | ||
| 32 | .valid_hooks = FILTER_VALID_HOOKS, | ||
| 33 | .num_entries = 4, | ||
| 34 | .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), | ||
| 35 | .hook_entry = { | ||
| 36 | [NF_INET_LOCAL_IN] = 0, | ||
| 37 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
| 38 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 | ||
| 39 | }, | ||
| 40 | .underflow = { | ||
| 41 | [NF_INET_LOCAL_IN] = 0, | ||
| 42 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
| 43 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 | ||
| 44 | }, | ||
| 45 | }, | ||
| 46 | .entries = { | ||
| 47 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
| 48 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
| 49 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
| 50 | }, | ||
| 51 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const struct xt_table packet_filter = { | 25 | static const struct xt_table packet_filter = { |
| 55 | .name = "filter", | 26 | .name = "filter", |
| 56 | .valid_hooks = FILTER_VALID_HOOKS, | 27 | .valid_hooks = FILTER_VALID_HOOKS, |
| 57 | .me = THIS_MODULE, | 28 | .me = THIS_MODULE, |
| 58 | .af = NFPROTO_IPV6, | 29 | .af = NFPROTO_IPV6, |
| 30 | .priority = NF_IP6_PRI_FILTER, | ||
| 59 | }; | 31 | }; |
| 60 | 32 | ||
| 61 | /* The work comes in here from netfilter.c. */ | 33 | /* The work comes in here from netfilter.c. */ |
| 62 | static unsigned int | 34 | static unsigned int |
| 63 | ip6t_in_hook(unsigned int hook, | 35 | ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, |
| 64 | struct sk_buff *skb, | 36 | const struct net_device *in, const struct net_device *out, |
| 65 | const struct net_device *in, | 37 | int (*okfn)(struct sk_buff *)) |
| 66 | const struct net_device *out, | ||
| 67 | int (*okfn)(struct sk_buff *)) | ||
| 68 | { | ||
| 69 | return ip6t_do_table(skb, hook, in, out, | ||
| 70 | dev_net(in)->ipv6.ip6table_filter); | ||
| 71 | } | ||
| 72 | |||
| 73 | static unsigned int | ||
| 74 | ip6t_local_out_hook(unsigned int hook, | ||
| 75 | struct sk_buff *skb, | ||
| 76 | const struct net_device *in, | ||
| 77 | const struct net_device *out, | ||
| 78 | int (*okfn)(struct sk_buff *)) | ||
| 79 | { | 38 | { |
| 80 | #if 0 | 39 | const struct net *net = dev_net((in != NULL) ? in : out); |
| 81 | /* root is playing with raw sockets. */ | ||
| 82 | if (skb->len < sizeof(struct iphdr) || | ||
| 83 | ip_hdrlen(skb) < sizeof(struct iphdr)) { | ||
| 84 | if (net_ratelimit()) | ||
| 85 | printk("ip6t_hook: happy cracking.\n"); | ||
| 86 | return NF_ACCEPT; | ||
| 87 | } | ||
| 88 | #endif | ||
| 89 | 40 | ||
| 90 | return ip6t_do_table(skb, hook, in, out, | 41 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); |
| 91 | dev_net(out)->ipv6.ip6table_filter); | ||
| 92 | } | 42 | } |
| 93 | 43 | ||
| 94 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 44 | static struct nf_hook_ops *filter_ops __read_mostly; |
| 95 | { | ||
| 96 | .hook = ip6t_in_hook, | ||
| 97 | .owner = THIS_MODULE, | ||
| 98 | .pf = NFPROTO_IPV6, | ||
| 99 | .hooknum = NF_INET_LOCAL_IN, | ||
| 100 | .priority = NF_IP6_PRI_FILTER, | ||
| 101 | }, | ||
| 102 | { | ||
| 103 | .hook = ip6t_in_hook, | ||
| 104 | .owner = THIS_MODULE, | ||
| 105 | .pf = NFPROTO_IPV6, | ||
| 106 | .hooknum = NF_INET_FORWARD, | ||
| 107 | .priority = NF_IP6_PRI_FILTER, | ||
| 108 | }, | ||
| 109 | { | ||
| 110 | .hook = ip6t_local_out_hook, | ||
| 111 | .owner = THIS_MODULE, | ||
| 112 | .pf = NFPROTO_IPV6, | ||
| 113 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 114 | .priority = NF_IP6_PRI_FILTER, | ||
| 115 | }, | ||
| 116 | }; | ||
| 117 | 45 | ||
| 118 | /* Default to forward because I got too much mail already. */ | 46 | /* Default to forward because I got too much mail already. */ |
| 119 | static int forward = NF_ACCEPT; | 47 | static int forward = NF_ACCEPT; |
| @@ -121,9 +49,18 @@ module_param(forward, bool, 0000); | |||
| 121 | 49 | ||
| 122 | static int __net_init ip6table_filter_net_init(struct net *net) | 50 | static int __net_init ip6table_filter_net_init(struct net *net) |
| 123 | { | 51 | { |
| 124 | /* Register table */ | 52 | struct ip6t_replace *repl; |
| 53 | |||
| 54 | repl = ip6t_alloc_initial_table(&packet_filter); | ||
| 55 | if (repl == NULL) | ||
| 56 | return -ENOMEM; | ||
| 57 | /* Entry 1 is the FORWARD hook */ | ||
| 58 | ((struct ip6t_standard *)repl->entries)[1].target.verdict = | ||
| 59 | -forward - 1; | ||
| 60 | |||
| 125 | net->ipv6.ip6table_filter = | 61 | net->ipv6.ip6table_filter = |
| 126 | ip6t_register_table(net, &packet_filter, &initial_table.repl); | 62 | ip6t_register_table(net, &packet_filter, repl); |
| 63 | kfree(repl); | ||
| 127 | if (IS_ERR(net->ipv6.ip6table_filter)) | 64 | if (IS_ERR(net->ipv6.ip6table_filter)) |
| 128 | return PTR_ERR(net->ipv6.ip6table_filter); | 65 | return PTR_ERR(net->ipv6.ip6table_filter); |
| 129 | return 0; | 66 | return 0; |
| @@ -131,7 +68,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) | |||
| 131 | 68 | ||
| 132 | static void __net_exit ip6table_filter_net_exit(struct net *net) | 69 | static void __net_exit ip6table_filter_net_exit(struct net *net) |
| 133 | { | 70 | { |
| 134 | ip6t_unregister_table(net->ipv6.ip6table_filter); | 71 | ip6t_unregister_table(net, net->ipv6.ip6table_filter); |
| 135 | } | 72 | } |
| 136 | 73 | ||
| 137 | static struct pernet_operations ip6table_filter_net_ops = { | 74 | static struct pernet_operations ip6table_filter_net_ops = { |
| @@ -144,21 +81,20 @@ static int __init ip6table_filter_init(void) | |||
| 144 | int ret; | 81 | int ret; |
| 145 | 82 | ||
| 146 | if (forward < 0 || forward > NF_MAX_VERDICT) { | 83 | if (forward < 0 || forward > NF_MAX_VERDICT) { |
| 147 | printk("iptables forward must be 0 or 1\n"); | 84 | pr_err("iptables forward must be 0 or 1\n"); |
| 148 | return -EINVAL; | 85 | return -EINVAL; |
| 149 | } | 86 | } |
| 150 | 87 | ||
| 151 | /* Entry 1 is the FORWARD hook */ | ||
| 152 | initial_table.entries[1].target.verdict = -forward - 1; | ||
| 153 | |||
| 154 | ret = register_pernet_subsys(&ip6table_filter_net_ops); | 88 | ret = register_pernet_subsys(&ip6table_filter_net_ops); |
| 155 | if (ret < 0) | 89 | if (ret < 0) |
| 156 | return ret; | 90 | return ret; |
| 157 | 91 | ||
| 158 | /* Register hooks */ | 92 | /* Register hooks */ |
| 159 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 93 | filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook); |
| 160 | if (ret < 0) | 94 | if (IS_ERR(filter_ops)) { |
| 95 | ret = PTR_ERR(filter_ops); | ||
| 161 | goto cleanup_table; | 96 | goto cleanup_table; |
| 97 | } | ||
| 162 | 98 | ||
| 163 | return ret; | 99 | return ret; |
| 164 | 100 | ||
| @@ -169,7 +105,7 @@ static int __init ip6table_filter_init(void) | |||
| 169 | 105 | ||
| 170 | static void __exit ip6table_filter_fini(void) | 106 | static void __exit ip6table_filter_fini(void) |
| 171 | { | 107 | { |
| 172 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 108 | xt_hook_unlink(&packet_filter, filter_ops); |
| 173 | unregister_pernet_subsys(&ip6table_filter_net_ops); | 109 | unregister_pernet_subsys(&ip6table_filter_net_ops); |
| 174 | } | 110 | } |
| 175 | 111 | ||
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index a929c19d30e3..679a0a3b7b3c 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/netfilter_ipv6/ip6_tables.h> | 12 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | 14 | ||
| 14 | MODULE_LICENSE("GPL"); | 15 | MODULE_LICENSE("GPL"); |
| 15 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 16 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
| @@ -21,80 +22,17 @@ MODULE_DESCRIPTION("ip6tables mangle table"); | |||
| 21 | (1 << NF_INET_LOCAL_OUT) | \ | 22 | (1 << NF_INET_LOCAL_OUT) | \ |
| 22 | (1 << NF_INET_POST_ROUTING)) | 23 | (1 << NF_INET_POST_ROUTING)) |
| 23 | 24 | ||
| 24 | static const struct | ||
| 25 | { | ||
| 26 | struct ip6t_replace repl; | ||
| 27 | struct ip6t_standard entries[5]; | ||
| 28 | struct ip6t_error term; | ||
| 29 | } initial_table __net_initdata = { | ||
| 30 | .repl = { | ||
| 31 | .name = "mangle", | ||
| 32 | .valid_hooks = MANGLE_VALID_HOOKS, | ||
| 33 | .num_entries = 6, | ||
| 34 | .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), | ||
| 35 | .hook_entry = { | ||
| 36 | [NF_INET_PRE_ROUTING] = 0, | ||
| 37 | [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), | ||
| 38 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, | ||
| 39 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | ||
| 40 | [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, | ||
| 41 | }, | ||
| 42 | .underflow = { | ||
| 43 | [NF_INET_PRE_ROUTING] = 0, | ||
| 44 | [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), | ||
| 45 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, | ||
| 46 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | ||
| 47 | [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, | ||
| 48 | }, | ||
| 49 | }, | ||
| 50 | .entries = { | ||
| 51 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ | ||
| 52 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
| 53 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
| 54 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
| 55 | IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ | ||
| 56 | }, | ||
| 57 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
| 58 | }; | ||
| 59 | |||
| 60 | static const struct xt_table packet_mangler = { | 25 | static const struct xt_table packet_mangler = { |
| 61 | .name = "mangle", | 26 | .name = "mangle", |
| 62 | .valid_hooks = MANGLE_VALID_HOOKS, | 27 | .valid_hooks = MANGLE_VALID_HOOKS, |
| 63 | .me = THIS_MODULE, | 28 | .me = THIS_MODULE, |
| 64 | .af = NFPROTO_IPV6, | 29 | .af = NFPROTO_IPV6, |
| 30 | .priority = NF_IP6_PRI_MANGLE, | ||
| 65 | }; | 31 | }; |
| 66 | 32 | ||
| 67 | /* The work comes in here from netfilter.c. */ | ||
| 68 | static unsigned int | ||
| 69 | ip6t_in_hook(unsigned int hook, | ||
| 70 | struct sk_buff *skb, | ||
| 71 | const struct net_device *in, | ||
| 72 | const struct net_device *out, | ||
| 73 | int (*okfn)(struct sk_buff *)) | ||
| 74 | { | ||
| 75 | return ip6t_do_table(skb, hook, in, out, | ||
| 76 | dev_net(in)->ipv6.ip6table_mangle); | ||
| 77 | } | ||
| 78 | |||
| 79 | static unsigned int | ||
| 80 | ip6t_post_routing_hook(unsigned int hook, | ||
| 81 | struct sk_buff *skb, | ||
| 82 | const struct net_device *in, | ||
| 83 | const struct net_device *out, | ||
| 84 | int (*okfn)(struct sk_buff *)) | ||
| 85 | { | ||
| 86 | return ip6t_do_table(skb, hook, in, out, | ||
| 87 | dev_net(out)->ipv6.ip6table_mangle); | ||
| 88 | } | ||
| 89 | |||
| 90 | static unsigned int | 33 | static unsigned int |
| 91 | ip6t_local_out_hook(unsigned int hook, | 34 | ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) |
| 92 | struct sk_buff *skb, | ||
| 93 | const struct net_device *in, | ||
| 94 | const struct net_device *out, | ||
| 95 | int (*okfn)(struct sk_buff *)) | ||
| 96 | { | 35 | { |
| 97 | |||
| 98 | unsigned int ret; | 36 | unsigned int ret; |
| 99 | struct in6_addr saddr, daddr; | 37 | struct in6_addr saddr, daddr; |
| 100 | u_int8_t hop_limit; | 38 | u_int8_t hop_limit; |
| @@ -105,7 +43,7 @@ ip6t_local_out_hook(unsigned int hook, | |||
| 105 | if (skb->len < sizeof(struct iphdr) || | 43 | if (skb->len < sizeof(struct iphdr) || |
| 106 | ip_hdrlen(skb) < sizeof(struct iphdr)) { | 44 | ip_hdrlen(skb) < sizeof(struct iphdr)) { |
| 107 | if (net_ratelimit()) | 45 | if (net_ratelimit()) |
| 108 | printk("ip6t_hook: happy cracking.\n"); | 46 | pr_warning("ip6t_hook: happy cracking.\n"); |
| 109 | return NF_ACCEPT; | 47 | return NF_ACCEPT; |
| 110 | } | 48 | } |
| 111 | #endif | 49 | #endif |
| @@ -119,7 +57,7 @@ ip6t_local_out_hook(unsigned int hook, | |||
| 119 | /* flowlabel and prio (includes version, which shouldn't change either */ | 57 | /* flowlabel and prio (includes version, which shouldn't change either */ |
| 120 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); | 58 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); |
| 121 | 59 | ||
| 122 | ret = ip6t_do_table(skb, hook, in, out, | 60 | ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, |
| 123 | dev_net(out)->ipv6.ip6table_mangle); | 61 | dev_net(out)->ipv6.ip6table_mangle); |
| 124 | 62 | ||
| 125 | if (ret != NF_DROP && ret != NF_STOLEN && | 63 | if (ret != NF_DROP && ret != NF_STOLEN && |
| @@ -132,49 +70,33 @@ ip6t_local_out_hook(unsigned int hook, | |||
| 132 | return ret; | 70 | return ret; |
| 133 | } | 71 | } |
| 134 | 72 | ||
| 135 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 73 | /* The work comes in here from netfilter.c. */ |
| 136 | { | 74 | static unsigned int |
| 137 | .hook = ip6t_in_hook, | 75 | ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, |
| 138 | .owner = THIS_MODULE, | 76 | const struct net_device *in, const struct net_device *out, |
| 139 | .pf = NFPROTO_IPV6, | 77 | int (*okfn)(struct sk_buff *)) |
| 140 | .hooknum = NF_INET_PRE_ROUTING, | 78 | { |
| 141 | .priority = NF_IP6_PRI_MANGLE, | 79 | if (hook == NF_INET_LOCAL_OUT) |
| 142 | }, | 80 | return ip6t_mangle_out(skb, out); |
| 143 | { | 81 | if (hook == NF_INET_POST_ROUTING) |
| 144 | .hook = ip6t_in_hook, | 82 | return ip6t_do_table(skb, hook, in, out, |
| 145 | .owner = THIS_MODULE, | 83 | dev_net(out)->ipv6.ip6table_mangle); |
| 146 | .pf = NFPROTO_IPV6, | 84 | /* INPUT/FORWARD */ |
| 147 | .hooknum = NF_INET_LOCAL_IN, | 85 | return ip6t_do_table(skb, hook, in, out, |
| 148 | .priority = NF_IP6_PRI_MANGLE, | 86 | dev_net(in)->ipv6.ip6table_mangle); |
| 149 | }, | 87 | } |
| 150 | { | ||
| 151 | .hook = ip6t_in_hook, | ||
| 152 | .owner = THIS_MODULE, | ||
| 153 | .pf = NFPROTO_IPV6, | ||
| 154 | .hooknum = NF_INET_FORWARD, | ||
| 155 | .priority = NF_IP6_PRI_MANGLE, | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .hook = ip6t_local_out_hook, | ||
| 159 | .owner = THIS_MODULE, | ||
| 160 | .pf = NFPROTO_IPV6, | ||
| 161 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 162 | .priority = NF_IP6_PRI_MANGLE, | ||
| 163 | }, | ||
| 164 | { | ||
| 165 | .hook = ip6t_post_routing_hook, | ||
| 166 | .owner = THIS_MODULE, | ||
| 167 | .pf = NFPROTO_IPV6, | ||
| 168 | .hooknum = NF_INET_POST_ROUTING, | ||
| 169 | .priority = NF_IP6_PRI_MANGLE, | ||
| 170 | }, | ||
| 171 | }; | ||
| 172 | 88 | ||
| 89 | static struct nf_hook_ops *mangle_ops __read_mostly; | ||
| 173 | static int __net_init ip6table_mangle_net_init(struct net *net) | 90 | static int __net_init ip6table_mangle_net_init(struct net *net) |
| 174 | { | 91 | { |
| 175 | /* Register table */ | 92 | struct ip6t_replace *repl; |
| 93 | |||
| 94 | repl = ip6t_alloc_initial_table(&packet_mangler); | ||
| 95 | if (repl == NULL) | ||
| 96 | return -ENOMEM; | ||
| 176 | net->ipv6.ip6table_mangle = | 97 | net->ipv6.ip6table_mangle = |
| 177 | ip6t_register_table(net, &packet_mangler, &initial_table.repl); | 98 | ip6t_register_table(net, &packet_mangler, repl); |
| 99 | kfree(repl); | ||
| 178 | if (IS_ERR(net->ipv6.ip6table_mangle)) | 100 | if (IS_ERR(net->ipv6.ip6table_mangle)) |
| 179 | return PTR_ERR(net->ipv6.ip6table_mangle); | 101 | return PTR_ERR(net->ipv6.ip6table_mangle); |
| 180 | return 0; | 102 | return 0; |
| @@ -182,7 +104,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) | |||
| 182 | 104 | ||
| 183 | static void __net_exit ip6table_mangle_net_exit(struct net *net) | 105 | static void __net_exit ip6table_mangle_net_exit(struct net *net) |
| 184 | { | 106 | { |
| 185 | ip6t_unregister_table(net->ipv6.ip6table_mangle); | 107 | ip6t_unregister_table(net, net->ipv6.ip6table_mangle); |
| 186 | } | 108 | } |
| 187 | 109 | ||
| 188 | static struct pernet_operations ip6table_mangle_net_ops = { | 110 | static struct pernet_operations ip6table_mangle_net_ops = { |
| @@ -199,9 +121,11 @@ static int __init ip6table_mangle_init(void) | |||
| 199 | return ret; | 121 | return ret; |
| 200 | 122 | ||
| 201 | /* Register hooks */ | 123 | /* Register hooks */ |
| 202 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 124 | mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook); |
| 203 | if (ret < 0) | 125 | if (IS_ERR(mangle_ops)) { |
| 126 | ret = PTR_ERR(mangle_ops); | ||
| 204 | goto cleanup_table; | 127 | goto cleanup_table; |
| 128 | } | ||
| 205 | 129 | ||
| 206 | return ret; | 130 | return ret; |
| 207 | 131 | ||
| @@ -212,7 +136,7 @@ static int __init ip6table_mangle_init(void) | |||
| 212 | 136 | ||
| 213 | static void __exit ip6table_mangle_fini(void) | 137 | static void __exit ip6table_mangle_fini(void) |
| 214 | { | 138 | { |
| 215 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 139 | xt_hook_unlink(&packet_mangler, mangle_ops); |
| 216 | unregister_pernet_subsys(&ip6table_mangle_net_ops); | 140 | unregister_pernet_subsys(&ip6table_mangle_net_ops); |
| 217 | } | 141 | } |
| 218 | 142 | ||
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index ed1a1180f3b3..5b9926a011bd 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
| @@ -5,88 +5,41 @@ | |||
| 5 | */ | 5 | */ |
| 6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 7 | #include <linux/netfilter_ipv6/ip6_tables.h> | 7 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 8 | #include <linux/slab.h> | ||
| 8 | 9 | ||
| 9 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) | 10 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) |
| 10 | 11 | ||
| 11 | static const struct | ||
| 12 | { | ||
| 13 | struct ip6t_replace repl; | ||
| 14 | struct ip6t_standard entries[2]; | ||
| 15 | struct ip6t_error term; | ||
| 16 | } initial_table __net_initdata = { | ||
| 17 | .repl = { | ||
| 18 | .name = "raw", | ||
| 19 | .valid_hooks = RAW_VALID_HOOKS, | ||
| 20 | .num_entries = 3, | ||
| 21 | .size = sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), | ||
| 22 | .hook_entry = { | ||
| 23 | [NF_INET_PRE_ROUTING] = 0, | ||
| 24 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) | ||
| 25 | }, | ||
| 26 | .underflow = { | ||
| 27 | [NF_INET_PRE_ROUTING] = 0, | ||
| 28 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) | ||
| 29 | }, | ||
| 30 | }, | ||
| 31 | .entries = { | ||
| 32 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ | ||
| 33 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
| 34 | }, | ||
| 35 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
| 36 | }; | ||
| 37 | |||
| 38 | static const struct xt_table packet_raw = { | 12 | static const struct xt_table packet_raw = { |
| 39 | .name = "raw", | 13 | .name = "raw", |
| 40 | .valid_hooks = RAW_VALID_HOOKS, | 14 | .valid_hooks = RAW_VALID_HOOKS, |
| 41 | .me = THIS_MODULE, | 15 | .me = THIS_MODULE, |
| 42 | .af = NFPROTO_IPV6, | 16 | .af = NFPROTO_IPV6, |
| 17 | .priority = NF_IP6_PRI_RAW, | ||
| 43 | }; | 18 | }; |
| 44 | 19 | ||
| 45 | /* The work comes in here from netfilter.c. */ | 20 | /* The work comes in here from netfilter.c. */ |
| 46 | static unsigned int | 21 | static unsigned int |
| 47 | ip6t_pre_routing_hook(unsigned int hook, | 22 | ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, |
| 48 | struct sk_buff *skb, | 23 | const struct net_device *in, const struct net_device *out, |
| 49 | const struct net_device *in, | 24 | int (*okfn)(struct sk_buff *)) |
| 50 | const struct net_device *out, | ||
| 51 | int (*okfn)(struct sk_buff *)) | ||
| 52 | { | 25 | { |
| 53 | return ip6t_do_table(skb, hook, in, out, | 26 | const struct net *net = dev_net((in != NULL) ? in : out); |
| 54 | dev_net(in)->ipv6.ip6table_raw); | ||
| 55 | } | ||
| 56 | 27 | ||
| 57 | static unsigned int | 28 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); |
| 58 | ip6t_local_out_hook(unsigned int hook, | ||
| 59 | struct sk_buff *skb, | ||
| 60 | const struct net_device *in, | ||
| 61 | const struct net_device *out, | ||
| 62 | int (*okfn)(struct sk_buff *)) | ||
| 63 | { | ||
| 64 | return ip6t_do_table(skb, hook, in, out, | ||
| 65 | dev_net(out)->ipv6.ip6table_raw); | ||
| 66 | } | 29 | } |
| 67 | 30 | ||
| 68 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 31 | static struct nf_hook_ops *rawtable_ops __read_mostly; |
| 69 | { | ||
| 70 | .hook = ip6t_pre_routing_hook, | ||
| 71 | .pf = NFPROTO_IPV6, | ||
| 72 | .hooknum = NF_INET_PRE_ROUTING, | ||
| 73 | .priority = NF_IP6_PRI_FIRST, | ||
| 74 | .owner = THIS_MODULE, | ||
| 75 | }, | ||
| 76 | { | ||
| 77 | .hook = ip6t_local_out_hook, | ||
| 78 | .pf = NFPROTO_IPV6, | ||
| 79 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 80 | .priority = NF_IP6_PRI_FIRST, | ||
| 81 | .owner = THIS_MODULE, | ||
| 82 | }, | ||
| 83 | }; | ||
| 84 | 32 | ||
| 85 | static int __net_init ip6table_raw_net_init(struct net *net) | 33 | static int __net_init ip6table_raw_net_init(struct net *net) |
| 86 | { | 34 | { |
| 87 | /* Register table */ | 35 | struct ip6t_replace *repl; |
| 36 | |||
| 37 | repl = ip6t_alloc_initial_table(&packet_raw); | ||
| 38 | if (repl == NULL) | ||
| 39 | return -ENOMEM; | ||
| 88 | net->ipv6.ip6table_raw = | 40 | net->ipv6.ip6table_raw = |
| 89 | ip6t_register_table(net, &packet_raw, &initial_table.repl); | 41 | ip6t_register_table(net, &packet_raw, repl); |
| 42 | kfree(repl); | ||
| 90 | if (IS_ERR(net->ipv6.ip6table_raw)) | 43 | if (IS_ERR(net->ipv6.ip6table_raw)) |
| 91 | return PTR_ERR(net->ipv6.ip6table_raw); | 44 | return PTR_ERR(net->ipv6.ip6table_raw); |
| 92 | return 0; | 45 | return 0; |
| @@ -94,7 +47,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) | |||
| 94 | 47 | ||
| 95 | static void __net_exit ip6table_raw_net_exit(struct net *net) | 48 | static void __net_exit ip6table_raw_net_exit(struct net *net) |
| 96 | { | 49 | { |
| 97 | ip6t_unregister_table(net->ipv6.ip6table_raw); | 50 | ip6t_unregister_table(net, net->ipv6.ip6table_raw); |
| 98 | } | 51 | } |
| 99 | 52 | ||
| 100 | static struct pernet_operations ip6table_raw_net_ops = { | 53 | static struct pernet_operations ip6table_raw_net_ops = { |
| @@ -111,9 +64,11 @@ static int __init ip6table_raw_init(void) | |||
| 111 | return ret; | 64 | return ret; |
| 112 | 65 | ||
| 113 | /* Register hooks */ | 66 | /* Register hooks */ |
| 114 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 67 | rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook); |
| 115 | if (ret < 0) | 68 | if (IS_ERR(rawtable_ops)) { |
| 69 | ret = PTR_ERR(rawtable_ops); | ||
| 116 | goto cleanup_table; | 70 | goto cleanup_table; |
| 71 | } | ||
| 117 | 72 | ||
| 118 | return ret; | 73 | return ret; |
| 119 | 74 | ||
| @@ -124,7 +79,7 @@ static int __init ip6table_raw_init(void) | |||
| 124 | 79 | ||
| 125 | static void __exit ip6table_raw_fini(void) | 80 | static void __exit ip6table_raw_fini(void) |
| 126 | { | 81 | { |
| 127 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 82 | xt_hook_unlink(&packet_raw, rawtable_ops); |
| 128 | unregister_pernet_subsys(&ip6table_raw_net_ops); | 83 | unregister_pernet_subsys(&ip6table_raw_net_ops); |
| 129 | } | 84 | } |
| 130 | 85 | ||
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 41b444c60934..91aa2b4d83c9 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | */ | 17 | */ |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/netfilter_ipv6/ip6_tables.h> | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 20 | #include <linux/slab.h> | ||
| 20 | 21 | ||
| 21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
| 22 | MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); | 23 | MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); |
| @@ -26,106 +27,37 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); | |||
| 26 | (1 << NF_INET_FORWARD) | \ | 27 | (1 << NF_INET_FORWARD) | \ |
| 27 | (1 << NF_INET_LOCAL_OUT) | 28 | (1 << NF_INET_LOCAL_OUT) |
| 28 | 29 | ||
| 29 | static const struct | ||
| 30 | { | ||
| 31 | struct ip6t_replace repl; | ||
| 32 | struct ip6t_standard entries[3]; | ||
| 33 | struct ip6t_error term; | ||
| 34 | } initial_table __net_initdata = { | ||
| 35 | .repl = { | ||
| 36 | .name = "security", | ||
| 37 | .valid_hooks = SECURITY_VALID_HOOKS, | ||
| 38 | .num_entries = 4, | ||
| 39 | .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), | ||
| 40 | .hook_entry = { | ||
| 41 | [NF_INET_LOCAL_IN] = 0, | ||
| 42 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
| 43 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, | ||
| 44 | }, | ||
| 45 | .underflow = { | ||
| 46 | [NF_INET_LOCAL_IN] = 0, | ||
| 47 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
| 48 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, | ||
| 49 | }, | ||
| 50 | }, | ||
| 51 | .entries = { | ||
| 52 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
| 53 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
| 54 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
| 55 | }, | ||
| 56 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
| 57 | }; | ||
| 58 | |||
| 59 | static const struct xt_table security_table = { | 30 | static const struct xt_table security_table = { |
| 60 | .name = "security", | 31 | .name = "security", |
| 61 | .valid_hooks = SECURITY_VALID_HOOKS, | 32 | .valid_hooks = SECURITY_VALID_HOOKS, |
| 62 | .me = THIS_MODULE, | 33 | .me = THIS_MODULE, |
| 63 | .af = NFPROTO_IPV6, | 34 | .af = NFPROTO_IPV6, |
| 35 | .priority = NF_IP6_PRI_SECURITY, | ||
| 64 | }; | 36 | }; |
| 65 | 37 | ||
| 66 | static unsigned int | 38 | static unsigned int |
| 67 | ip6t_local_in_hook(unsigned int hook, | 39 | ip6table_security_hook(unsigned int hook, struct sk_buff *skb, |
| 68 | struct sk_buff *skb, | 40 | const struct net_device *in, |
| 69 | const struct net_device *in, | 41 | const struct net_device *out, |
| 70 | const struct net_device *out, | 42 | int (*okfn)(struct sk_buff *)) |
| 71 | int (*okfn)(struct sk_buff *)) | ||
| 72 | { | ||
| 73 | return ip6t_do_table(skb, hook, in, out, | ||
| 74 | dev_net(in)->ipv6.ip6table_security); | ||
| 75 | } | ||
| 76 | |||
| 77 | static unsigned int | ||
| 78 | ip6t_forward_hook(unsigned int hook, | ||
| 79 | struct sk_buff *skb, | ||
| 80 | const struct net_device *in, | ||
| 81 | const struct net_device *out, | ||
| 82 | int (*okfn)(struct sk_buff *)) | ||
| 83 | { | 43 | { |
| 84 | return ip6t_do_table(skb, hook, in, out, | 44 | const struct net *net = dev_net((in != NULL) ? in : out); |
| 85 | dev_net(in)->ipv6.ip6table_security); | ||
| 86 | } | ||
| 87 | 45 | ||
| 88 | static unsigned int | 46 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); |
| 89 | ip6t_local_out_hook(unsigned int hook, | ||
| 90 | struct sk_buff *skb, | ||
| 91 | const struct net_device *in, | ||
| 92 | const struct net_device *out, | ||
| 93 | int (*okfn)(struct sk_buff *)) | ||
| 94 | { | ||
| 95 | /* TBD: handle short packets via raw socket */ | ||
| 96 | return ip6t_do_table(skb, hook, in, out, | ||
| 97 | dev_net(out)->ipv6.ip6table_security); | ||
| 98 | } | 47 | } |
| 99 | 48 | ||
| 100 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 49 | static struct nf_hook_ops *sectbl_ops __read_mostly; |
| 101 | { | ||
| 102 | .hook = ip6t_local_in_hook, | ||
| 103 | .owner = THIS_MODULE, | ||
| 104 | .pf = NFPROTO_IPV6, | ||
| 105 | .hooknum = NF_INET_LOCAL_IN, | ||
| 106 | .priority = NF_IP6_PRI_SECURITY, | ||
| 107 | }, | ||
| 108 | { | ||
| 109 | .hook = ip6t_forward_hook, | ||
| 110 | .owner = THIS_MODULE, | ||
| 111 | .pf = NFPROTO_IPV6, | ||
| 112 | .hooknum = NF_INET_FORWARD, | ||
| 113 | .priority = NF_IP6_PRI_SECURITY, | ||
| 114 | }, | ||
| 115 | { | ||
| 116 | .hook = ip6t_local_out_hook, | ||
| 117 | .owner = THIS_MODULE, | ||
| 118 | .pf = NFPROTO_IPV6, | ||
| 119 | .hooknum = NF_INET_LOCAL_OUT, | ||
| 120 | .priority = NF_IP6_PRI_SECURITY, | ||
| 121 | }, | ||
| 122 | }; | ||
| 123 | 50 | ||
| 124 | static int __net_init ip6table_security_net_init(struct net *net) | 51 | static int __net_init ip6table_security_net_init(struct net *net) |
| 125 | { | 52 | { |
| 126 | net->ipv6.ip6table_security = | 53 | struct ip6t_replace *repl; |
| 127 | ip6t_register_table(net, &security_table, &initial_table.repl); | ||
| 128 | 54 | ||
| 55 | repl = ip6t_alloc_initial_table(&security_table); | ||
| 56 | if (repl == NULL) | ||
| 57 | return -ENOMEM; | ||
| 58 | net->ipv6.ip6table_security = | ||
| 59 | ip6t_register_table(net, &security_table, repl); | ||
| 60 | kfree(repl); | ||
| 129 | if (IS_ERR(net->ipv6.ip6table_security)) | 61 | if (IS_ERR(net->ipv6.ip6table_security)) |
| 130 | return PTR_ERR(net->ipv6.ip6table_security); | 62 | return PTR_ERR(net->ipv6.ip6table_security); |
| 131 | 63 | ||
| @@ -134,7 +66,7 @@ static int __net_init ip6table_security_net_init(struct net *net) | |||
| 134 | 66 | ||
| 135 | static void __net_exit ip6table_security_net_exit(struct net *net) | 67 | static void __net_exit ip6table_security_net_exit(struct net *net) |
| 136 | { | 68 | { |
| 137 | ip6t_unregister_table(net->ipv6.ip6table_security); | 69 | ip6t_unregister_table(net, net->ipv6.ip6table_security); |
| 138 | } | 70 | } |
| 139 | 71 | ||
| 140 | static struct pernet_operations ip6table_security_net_ops = { | 72 | static struct pernet_operations ip6table_security_net_ops = { |
| @@ -150,9 +82,11 @@ static int __init ip6table_security_init(void) | |||
| 150 | if (ret < 0) | 82 | if (ret < 0) |
| 151 | return ret; | 83 | return ret; |
| 152 | 84 | ||
| 153 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 85 | sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook); |
| 154 | if (ret < 0) | 86 | if (IS_ERR(sectbl_ops)) { |
| 87 | ret = PTR_ERR(sectbl_ops); | ||
| 155 | goto cleanup_table; | 88 | goto cleanup_table; |
| 89 | } | ||
| 156 | 90 | ||
| 157 | return ret; | 91 | return ret; |
| 158 | 92 | ||
| @@ -163,7 +97,7 @@ cleanup_table: | |||
| 163 | 97 | ||
| 164 | static void __exit ip6table_security_fini(void) | 98 | static void __exit ip6table_security_fini(void) |
| 165 | { | 99 | { |
| 166 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 100 | xt_hook_unlink(&security_table, sectbl_ops); |
| 167 | unregister_pernet_subsys(&ip6table_security_net_ops); | 101 | unregister_pernet_subsys(&ip6table_security_net_ops); |
| 168 | } | 102 | } |
| 169 | 103 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 0956ebabbff2..ff43461704be 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <net/netfilter/nf_conntrack_l4proto.h> | 27 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| 28 | #include <net/netfilter/nf_conntrack_l3proto.h> | 28 | #include <net/netfilter/nf_conntrack_l3proto.h> |
| 29 | #include <net/netfilter/nf_conntrack_core.h> | 29 | #include <net/netfilter/nf_conntrack_core.h> |
| 30 | #include <net/netfilter/nf_conntrack_zones.h> | ||
| 30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
| 31 | #include <net/netfilter/nf_log.h> | 32 | #include <net/netfilter/nf_log.h> |
| 32 | 33 | ||
| @@ -191,15 +192,20 @@ out: | |||
| 191 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | 192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, |
| 192 | struct sk_buff *skb) | 193 | struct sk_buff *skb) |
| 193 | { | 194 | { |
| 195 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
| 196 | |||
| 197 | if (skb->nfct) | ||
| 198 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
| 199 | |||
| 194 | #ifdef CONFIG_BRIDGE_NETFILTER | 200 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 195 | if (skb->nf_bridge && | 201 | if (skb->nf_bridge && |
| 196 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | 202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) |
| 197 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; | 203 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; |
| 198 | #endif | 204 | #endif |
| 199 | if (hooknum == NF_INET_PRE_ROUTING) | 205 | if (hooknum == NF_INET_PRE_ROUTING) |
| 200 | return IP6_DEFRAG_CONNTRACK_IN; | 206 | return IP6_DEFRAG_CONNTRACK_IN + zone; |
| 201 | else | 207 | else |
| 202 | return IP6_DEFRAG_CONNTRACK_OUT; | 208 | return IP6_DEFRAG_CONNTRACK_OUT + zone; |
| 203 | 209 | ||
| 204 | } | 210 | } |
| 205 | 211 | ||
| @@ -212,7 +218,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
| 212 | struct sk_buff *reasm; | 218 | struct sk_buff *reasm; |
| 213 | 219 | ||
| 214 | /* Previously seen (loopback)? */ | 220 | /* Previously seen (loopback)? */ |
| 215 | if (skb->nfct) | 221 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) |
| 216 | return NF_ACCEPT; | 222 | return NF_ACCEPT; |
| 217 | 223 | ||
| 218 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | 224 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); |
| @@ -274,7 +280,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, | |||
| 274 | /* root is playing with raw sockets. */ | 280 | /* root is playing with raw sockets. */ |
| 275 | if (skb->len < sizeof(struct ipv6hdr)) { | 281 | if (skb->len < sizeof(struct ipv6hdr)) { |
| 276 | if (net_ratelimit()) | 282 | if (net_ratelimit()) |
| 277 | printk("ipv6_conntrack_local: packet too short\n"); | 283 | pr_notice("ipv6_conntrack_local: packet too short\n"); |
| 278 | return NF_ACCEPT; | 284 | return NF_ACCEPT; |
| 279 | } | 285 | } |
| 280 | return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn); | 286 | return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn); |
| @@ -400,37 +406,37 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
| 400 | 406 | ||
| 401 | ret = nf_ct_frag6_init(); | 407 | ret = nf_ct_frag6_init(); |
| 402 | if (ret < 0) { | 408 | if (ret < 0) { |
| 403 | printk("nf_conntrack_ipv6: can't initialize frag6.\n"); | 409 | pr_err("nf_conntrack_ipv6: can't initialize frag6.\n"); |
| 404 | return ret; | 410 | return ret; |
| 405 | } | 411 | } |
| 406 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); | 412 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); |
| 407 | if (ret < 0) { | 413 | if (ret < 0) { |
| 408 | printk("nf_conntrack_ipv6: can't register tcp.\n"); | 414 | pr_err("nf_conntrack_ipv6: can't register tcp.\n"); |
| 409 | goto cleanup_frag6; | 415 | goto cleanup_frag6; |
| 410 | } | 416 | } |
| 411 | 417 | ||
| 412 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); | 418 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); |
| 413 | if (ret < 0) { | 419 | if (ret < 0) { |
| 414 | printk("nf_conntrack_ipv6: can't register udp.\n"); | 420 | pr_err("nf_conntrack_ipv6: can't register udp.\n"); |
| 415 | goto cleanup_tcp; | 421 | goto cleanup_tcp; |
| 416 | } | 422 | } |
| 417 | 423 | ||
| 418 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6); | 424 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6); |
| 419 | if (ret < 0) { | 425 | if (ret < 0) { |
| 420 | printk("nf_conntrack_ipv6: can't register icmpv6.\n"); | 426 | pr_err("nf_conntrack_ipv6: can't register icmpv6.\n"); |
| 421 | goto cleanup_udp; | 427 | goto cleanup_udp; |
| 422 | } | 428 | } |
| 423 | 429 | ||
| 424 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); | 430 | ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); |
| 425 | if (ret < 0) { | 431 | if (ret < 0) { |
| 426 | printk("nf_conntrack_ipv6: can't register ipv6\n"); | 432 | pr_err("nf_conntrack_ipv6: can't register ipv6\n"); |
| 427 | goto cleanup_icmpv6; | 433 | goto cleanup_icmpv6; |
| 428 | } | 434 | } |
| 429 | 435 | ||
| 430 | ret = nf_register_hooks(ipv6_conntrack_ops, | 436 | ret = nf_register_hooks(ipv6_conntrack_ops, |
| 431 | ARRAY_SIZE(ipv6_conntrack_ops)); | 437 | ARRAY_SIZE(ipv6_conntrack_ops)); |
| 432 | if (ret < 0) { | 438 | if (ret < 0) { |
| 433 | printk("nf_conntrack_ipv6: can't register pre-routing defrag " | 439 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " |
| 434 | "hook.\n"); | 440 | "hook.\n"); |
| 435 | goto cleanup_ipv6; | 441 | goto cleanup_ipv6; |
| 436 | } | 442 | } |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index c7b8bd1d7984..1df3c8b6bf47 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <net/netfilter/nf_conntrack_tuple.h> | 23 | #include <net/netfilter/nf_conntrack_tuple.h> |
| 24 | #include <net/netfilter/nf_conntrack_l4proto.h> | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| 25 | #include <net/netfilter/nf_conntrack_core.h> | 25 | #include <net/netfilter/nf_conntrack_core.h> |
| 26 | #include <net/netfilter/nf_conntrack_zones.h> | ||
| 26 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | 27 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
| 27 | #include <net/netfilter/nf_log.h> | 28 | #include <net/netfilter/nf_log.h> |
| 28 | 29 | ||
| @@ -128,7 +129,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
| 128 | } | 129 | } |
| 129 | 130 | ||
| 130 | static int | 131 | static int |
| 131 | icmpv6_error_message(struct net *net, | 132 | icmpv6_error_message(struct net *net, struct nf_conn *tmpl, |
| 132 | struct sk_buff *skb, | 133 | struct sk_buff *skb, |
| 133 | unsigned int icmp6off, | 134 | unsigned int icmp6off, |
| 134 | enum ip_conntrack_info *ctinfo, | 135 | enum ip_conntrack_info *ctinfo, |
| @@ -137,6 +138,7 @@ icmpv6_error_message(struct net *net, | |||
| 137 | struct nf_conntrack_tuple intuple, origtuple; | 138 | struct nf_conntrack_tuple intuple, origtuple; |
| 138 | const struct nf_conntrack_tuple_hash *h; | 139 | const struct nf_conntrack_tuple_hash *h; |
| 139 | const struct nf_conntrack_l4proto *inproto; | 140 | const struct nf_conntrack_l4proto *inproto; |
| 141 | u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | ||
| 140 | 142 | ||
| 141 | NF_CT_ASSERT(skb->nfct == NULL); | 143 | NF_CT_ASSERT(skb->nfct == NULL); |
| 142 | 144 | ||
| @@ -163,7 +165,7 @@ icmpv6_error_message(struct net *net, | |||
| 163 | 165 | ||
| 164 | *ctinfo = IP_CT_RELATED; | 166 | *ctinfo = IP_CT_RELATED; |
| 165 | 167 | ||
| 166 | h = nf_conntrack_find_get(net, &intuple); | 168 | h = nf_conntrack_find_get(net, zone, &intuple); |
| 167 | if (!h) { | 169 | if (!h) { |
| 168 | pr_debug("icmpv6_error: no match\n"); | 170 | pr_debug("icmpv6_error: no match\n"); |
| 169 | return -NF_ACCEPT; | 171 | return -NF_ACCEPT; |
| @@ -179,7 +181,8 @@ icmpv6_error_message(struct net *net, | |||
| 179 | } | 181 | } |
| 180 | 182 | ||
| 181 | static int | 183 | static int |
| 182 | icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, | 184 | icmpv6_error(struct net *net, struct nf_conn *tmpl, |
| 185 | struct sk_buff *skb, unsigned int dataoff, | ||
| 183 | enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) | 186 | enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) |
| 184 | { | 187 | { |
| 185 | const struct icmp6hdr *icmp6h; | 188 | const struct icmp6hdr *icmp6h; |
| @@ -205,7 +208,7 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, | |||
| 205 | type = icmp6h->icmp6_type - 130; | 208 | type = icmp6h->icmp6_type - 130; |
| 206 | if (type >= 0 && type < sizeof(noct_valid_new) && | 209 | if (type >= 0 && type < sizeof(noct_valid_new) && |
| 207 | noct_valid_new[type]) { | 210 | noct_valid_new[type]) { |
| 208 | skb->nfct = &nf_conntrack_untracked.ct_general; | 211 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
| 209 | skb->nfctinfo = IP_CT_NEW; | 212 | skb->nfctinfo = IP_CT_NEW; |
| 210 | nf_conntrack_get(skb->nfct); | 213 | nf_conntrack_get(skb->nfct); |
| 211 | return NF_ACCEPT; | 214 | return NF_ACCEPT; |
| @@ -215,7 +218,7 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, | |||
| 215 | if (icmp6h->icmp6_type >= 128) | 218 | if (icmp6h->icmp6_type >= 128) |
| 216 | return NF_ACCEPT; | 219 | return NF_ACCEPT; |
| 217 | 220 | ||
| 218 | return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum); | 221 | return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); |
| 219 | } | 222 | } |
| 220 | 223 | ||
| 221 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 224 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 312c20adc83f..578f3c1a16db 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/ipv6.h> | 27 | #include <linux/ipv6.h> |
| 28 | #include <linux/icmpv6.h> | 28 | #include <linux/icmpv6.h> |
| 29 | #include <linux/random.h> | 29 | #include <linux/random.h> |
| 30 | #include <linux/slab.h> | ||
| 30 | 31 | ||
| 31 | #include <net/sock.h> | 32 | #include <net/sock.h> |
| 32 | #include <net/snmp.h> | 33 | #include <net/snmp.h> |
| @@ -45,9 +46,6 @@ | |||
| 45 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
| 46 | #include <linux/module.h> | 47 | #include <linux/module.h> |
| 47 | 48 | ||
| 48 | #define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */ | ||
| 49 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | ||
| 50 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | ||
| 51 | 49 | ||
| 52 | struct nf_ct_frag6_skb_cb | 50 | struct nf_ct_frag6_skb_cb |
| 53 | { | 51 | { |
| @@ -63,6 +61,7 @@ struct nf_ct_frag6_queue | |||
| 63 | struct inet_frag_queue q; | 61 | struct inet_frag_queue q; |
| 64 | 62 | ||
| 65 | __be32 id; /* fragment id */ | 63 | __be32 id; /* fragment id */ |
| 64 | u32 user; | ||
| 66 | struct in6_addr saddr; | 65 | struct in6_addr saddr; |
| 67 | struct in6_addr daddr; | 66 | struct in6_addr daddr; |
| 68 | 67 | ||
| @@ -114,16 +113,6 @@ static void nf_skb_free(struct sk_buff *skb) | |||
| 114 | kfree_skb(NFCT_FRAG6_CB(skb)->orig); | 113 | kfree_skb(NFCT_FRAG6_CB(skb)->orig); |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | /* Memory Tracking Functions. */ | ||
| 118 | static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work) | ||
| 119 | { | ||
| 120 | if (work) | ||
| 121 | *work -= skb->truesize; | ||
| 122 | atomic_sub(skb->truesize, &nf_init_frags.mem); | ||
| 123 | nf_skb_free(skb); | ||
| 124 | kfree_skb(skb); | ||
| 125 | } | ||
| 126 | |||
| 127 | /* Destruction primitives. */ | 116 | /* Destruction primitives. */ |
| 128 | 117 | ||
| 129 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) | 118 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) |
| @@ -202,7 +191,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
| 202 | int offset, end; | 191 | int offset, end; |
| 203 | 192 | ||
| 204 | if (fq->q.last_in & INET_FRAG_COMPLETE) { | 193 | if (fq->q.last_in & INET_FRAG_COMPLETE) { |
| 205 | pr_debug("Allready completed\n"); | 194 | pr_debug("Already completed\n"); |
| 206 | goto err; | 195 | goto err; |
| 207 | } | 196 | } |
| 208 | 197 | ||
| @@ -272,6 +261,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
| 272 | * in the chain of fragments so far. We must know where to put | 261 | * in the chain of fragments so far. We must know where to put |
| 273 | * this fragment, right? | 262 | * this fragment, right? |
| 274 | */ | 263 | */ |
| 264 | prev = fq->q.fragments_tail; | ||
| 265 | if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) { | ||
| 266 | next = NULL; | ||
| 267 | goto found; | ||
| 268 | } | ||
| 275 | prev = NULL; | 269 | prev = NULL; |
| 276 | for (next = fq->q.fragments; next != NULL; next = next->next) { | 270 | for (next = fq->q.fragments; next != NULL; next = next->next) { |
| 277 | if (NFCT_FRAG6_CB(next)->offset >= offset) | 271 | if (NFCT_FRAG6_CB(next)->offset >= offset) |
| @@ -279,71 +273,30 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
| 279 | prev = next; | 273 | prev = next; |
| 280 | } | 274 | } |
| 281 | 275 | ||
| 282 | /* We found where to put this one. Check for overlap with | 276 | found: |
| 283 | * preceding fragment, and, if needed, align things so that | 277 | /* RFC5722, Section 4: |
| 284 | * any overlaps are eliminated. | 278 | * When reassembling an IPv6 datagram, if |
| 285 | */ | 279 | * one or more its constituent fragments is determined to be an |
| 286 | if (prev) { | 280 | * overlapping fragment, the entire datagram (and any constituent |
| 287 | int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset; | 281 | * fragments, including those not yet received) MUST be silently |
| 288 | 282 | * discarded. | |
| 289 | if (i > 0) { | ||
| 290 | offset += i; | ||
| 291 | if (end <= offset) { | ||
| 292 | pr_debug("overlap\n"); | ||
| 293 | goto err; | ||
| 294 | } | ||
| 295 | if (!pskb_pull(skb, i)) { | ||
| 296 | pr_debug("Can't pull\n"); | ||
| 297 | goto err; | ||
| 298 | } | ||
| 299 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
| 300 | skb->ip_summed = CHECKSUM_NONE; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /* Look for overlap with succeeding segments. | ||
| 305 | * If we can merge fragments, do it. | ||
| 306 | */ | 283 | */ |
| 307 | while (next && NFCT_FRAG6_CB(next)->offset < end) { | ||
| 308 | /* overlap is 'i' bytes */ | ||
| 309 | int i = end - NFCT_FRAG6_CB(next)->offset; | ||
| 310 | 284 | ||
| 311 | if (i < next->len) { | 285 | /* Check for overlap with preceding fragment. */ |
| 312 | /* Eat head of the next overlapped fragment | 286 | if (prev && |
| 313 | * and leave the loop. The next ones cannot overlap. | 287 | (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0) |
| 314 | */ | 288 | goto discard_fq; |
| 315 | pr_debug("Eat head of the overlapped parts.: %d", i); | ||
| 316 | if (!pskb_pull(next, i)) | ||
| 317 | goto err; | ||
| 318 | |||
| 319 | /* next fragment */ | ||
| 320 | NFCT_FRAG6_CB(next)->offset += i; | ||
| 321 | fq->q.meat -= i; | ||
| 322 | if (next->ip_summed != CHECKSUM_UNNECESSARY) | ||
| 323 | next->ip_summed = CHECKSUM_NONE; | ||
| 324 | break; | ||
| 325 | } else { | ||
| 326 | struct sk_buff *free_it = next; | ||
| 327 | |||
| 328 | /* Old fragmnet is completely overridden with | ||
| 329 | * new one drop it. | ||
| 330 | */ | ||
| 331 | next = next->next; | ||
| 332 | 289 | ||
| 333 | if (prev) | 290 | /* Look for overlap with succeeding segment. */ |
| 334 | prev->next = next; | 291 | if (next && NFCT_FRAG6_CB(next)->offset < end) |
| 335 | else | 292 | goto discard_fq; |
| 336 | fq->q.fragments = next; | ||
| 337 | |||
| 338 | fq->q.meat -= free_it->len; | ||
| 339 | frag_kfree_skb(free_it, NULL); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | 293 | ||
| 343 | NFCT_FRAG6_CB(skb)->offset = offset; | 294 | NFCT_FRAG6_CB(skb)->offset = offset; |
| 344 | 295 | ||
| 345 | /* Insert this fragment in the chain of fragments. */ | 296 | /* Insert this fragment in the chain of fragments. */ |
| 346 | skb->next = next; | 297 | skb->next = next; |
| 298 | if (!next) | ||
| 299 | fq->q.fragments_tail = skb; | ||
| 347 | if (prev) | 300 | if (prev) |
| 348 | prev->next = skb; | 301 | prev->next = skb; |
| 349 | else | 302 | else |
| @@ -366,6 +319,8 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
| 366 | write_unlock(&nf_frags.lock); | 319 | write_unlock(&nf_frags.lock); |
| 367 | return 0; | 320 | return 0; |
| 368 | 321 | ||
| 322 | discard_fq: | ||
| 323 | fq_kill(fq); | ||
| 369 | err: | 324 | err: |
| 370 | return -1; | 325 | return -1; |
| 371 | } | 326 | } |
| @@ -443,7 +398,6 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 443 | skb_shinfo(head)->frag_list = head->next; | 398 | skb_shinfo(head)->frag_list = head->next; |
| 444 | skb_reset_transport_header(head); | 399 | skb_reset_transport_header(head); |
| 445 | skb_push(head, head->data - skb_network_header(head)); | 400 | skb_push(head, head->data - skb_network_header(head)); |
| 446 | atomic_sub(head->truesize, &nf_init_frags.mem); | ||
| 447 | 401 | ||
| 448 | for (fp=head->next; fp; fp = fp->next) { | 402 | for (fp=head->next; fp; fp = fp->next) { |
| 449 | head->data_len += fp->len; | 403 | head->data_len += fp->len; |
| @@ -453,8 +407,8 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 453 | else if (head->ip_summed == CHECKSUM_COMPLETE) | 407 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
| 454 | head->csum = csum_add(head->csum, fp->csum); | 408 | head->csum = csum_add(head->csum, fp->csum); |
| 455 | head->truesize += fp->truesize; | 409 | head->truesize += fp->truesize; |
| 456 | atomic_sub(fp->truesize, &nf_init_frags.mem); | ||
| 457 | } | 410 | } |
| 411 | atomic_sub(head->truesize, &nf_init_frags.mem); | ||
| 458 | 412 | ||
| 459 | head->next = NULL; | 413 | head->next = NULL; |
| 460 | head->dev = dev; | 414 | head->dev = dev; |
| @@ -468,10 +422,11 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 468 | head->csum); | 422 | head->csum); |
| 469 | 423 | ||
| 470 | fq->q.fragments = NULL; | 424 | fq->q.fragments = NULL; |
| 425 | fq->q.fragments_tail = NULL; | ||
| 471 | 426 | ||
| 472 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 427 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
| 473 | fp = skb_shinfo(head)->frag_list; | 428 | fp = skb_shinfo(head)->frag_list; |
| 474 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | 429 | if (fp && NFCT_FRAG6_CB(fp)->orig == NULL) |
| 475 | /* at above code, head skb is divided into two skbs. */ | 430 | /* at above code, head skb is divided into two skbs. */ |
| 476 | fp = fp->next; | 431 | fp = fp->next; |
| 477 | 432 | ||
| @@ -597,12 +552,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
| 597 | hdr = ipv6_hdr(clone); | 552 | hdr = ipv6_hdr(clone); |
| 598 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 553 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
| 599 | 554 | ||
| 600 | if (!(fhdr->frag_off & htons(0xFFF9))) { | ||
| 601 | pr_debug("Invalid fragment offset\n"); | ||
| 602 | /* It is not a fragmented frame */ | ||
| 603 | goto ret_orig; | ||
| 604 | } | ||
| 605 | |||
| 606 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | 555 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) |
| 607 | nf_ct_frag6_evictor(); | 556 | nf_ct_frag6_evictor(); |
| 608 | 557 | ||
| @@ -651,7 +600,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | |||
| 651 | s2 = s->next; | 600 | s2 = s->next; |
| 652 | s->next = NULL; | 601 | s->next = NULL; |
| 653 | 602 | ||
| 654 | NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn, | 603 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn, |
| 655 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | 604 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); |
| 656 | s = s2; | 605 | s = s2; |
| 657 | } | 606 | } |
| @@ -669,8 +618,8 @@ int nf_ct_frag6_init(void) | |||
| 669 | nf_frags.frag_expire = nf_ct_frag6_expire; | 618 | nf_frags.frag_expire = nf_ct_frag6_expire; |
| 670 | nf_frags.secret_interval = 10 * 60 * HZ; | 619 | nf_frags.secret_interval = 10 * 60 * HZ; |
| 671 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; | 620 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; |
| 672 | nf_init_frags.high_thresh = 256 * 1024; | 621 | nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
| 673 | nf_init_frags.low_thresh = 192 * 1024; | 622 | nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
| 674 | inet_frags_init_net(&nf_init_frags); | 623 | inet_frags_init_net(&nf_init_frags); |
| 675 | inet_frags_init(&nf_frags); | 624 | inet_frags_init(&nf_frags); |
| 676 | 625 | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index c9605c3ad91f..d082eaeefa25 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
| @@ -59,7 +59,7 @@ static const struct file_operations sockstat6_seq_fops = { | |||
| 59 | .release = single_release_net, | 59 | .release = single_release_net, |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | static struct snmp_mib snmp6_ipstats_list[] = { | 62 | static const struct snmp_mib snmp6_ipstats_list[] = { |
| 63 | /* ipv6 mib according to RFC 2465 */ | 63 | /* ipv6 mib according to RFC 2465 */ |
| 64 | SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), | 64 | SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), |
| 65 | SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), | 65 | SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), |
| @@ -92,11 +92,12 @@ static struct snmp_mib snmp6_ipstats_list[] = { | |||
| 92 | SNMP_MIB_SENTINEL | 92 | SNMP_MIB_SENTINEL |
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | static struct snmp_mib snmp6_icmp6_list[] = { | 95 | static const struct snmp_mib snmp6_icmp6_list[] = { |
| 96 | /* icmpv6 mib according to RFC 2466 */ | 96 | /* icmpv6 mib according to RFC 2466 */ |
| 97 | SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), | 97 | SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), |
| 98 | SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), | 98 | SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), |
| 99 | SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), | 99 | SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), |
| 100 | SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS), | ||
| 100 | SNMP_MIB_SENTINEL | 101 | SNMP_MIB_SENTINEL |
| 101 | }; | 102 | }; |
| 102 | 103 | ||
| @@ -120,7 +121,7 @@ static const char *const icmp6type2name[256] = { | |||
| 120 | }; | 121 | }; |
| 121 | 122 | ||
| 122 | 123 | ||
| 123 | static struct snmp_mib snmp6_udp6_list[] = { | 124 | static const struct snmp_mib snmp6_udp6_list[] = { |
| 124 | SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), | 125 | SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), |
| 125 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), | 126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), |
| 126 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), | 127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), |
| @@ -128,7 +129,7 @@ static struct snmp_mib snmp6_udp6_list[] = { | |||
| 128 | SNMP_MIB_SENTINEL | 129 | SNMP_MIB_SENTINEL |
| 129 | }; | 130 | }; |
| 130 | 131 | ||
| 131 | static struct snmp_mib snmp6_udplite6_list[] = { | 132 | static const struct snmp_mib snmp6_udplite6_list[] = { |
| 132 | SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), | 133 | SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), |
| 133 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | 134 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), |
| 134 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | 135 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), |
| @@ -136,7 +137,7 @@ static struct snmp_mib snmp6_udplite6_list[] = { | |||
| 136 | SNMP_MIB_SENTINEL | 137 | SNMP_MIB_SENTINEL |
| 137 | }; | 138 | }; |
| 138 | 139 | ||
| 139 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) | 140 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) |
| 140 | { | 141 | { |
| 141 | char name[32]; | 142 | char name[32]; |
| 142 | int i; | 143 | int i; |
| @@ -167,30 +168,41 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) | |||
| 167 | i & 0x100 ? "Out" : "In", i & 0xff); | 168 | i & 0x100 ? "Out" : "In", i & 0xff); |
| 168 | seq_printf(seq, "%-32s\t%lu\n", name, val); | 169 | seq_printf(seq, "%-32s\t%lu\n", name, val); |
| 169 | } | 170 | } |
| 170 | return; | ||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static inline void | 173 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, |
| 174 | snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) | 174 | const struct snmp_mib *itemlist) |
| 175 | { | 175 | { |
| 176 | int i; | 176 | int i; |
| 177 | for (i=0; itemlist[i].name; i++) | 177 | |
| 178 | for (i = 0; itemlist[i].name; i++) | ||
| 178 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, | 179 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, |
| 179 | snmp_fold_field(mib, itemlist[i].entry)); | 180 | snmp_fold_field(mib, itemlist[i].entry)); |
| 180 | } | 181 | } |
| 181 | 182 | ||
| 183 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, | ||
| 184 | const struct snmp_mib *itemlist, size_t syncpoff) | ||
| 185 | { | ||
| 186 | int i; | ||
| 187 | |||
| 188 | for (i = 0; itemlist[i].name; i++) | ||
| 189 | seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name, | ||
| 190 | snmp_fold_field64(mib, itemlist[i].entry, syncpoff)); | ||
| 191 | } | ||
| 192 | |||
| 182 | static int snmp6_seq_show(struct seq_file *seq, void *v) | 193 | static int snmp6_seq_show(struct seq_file *seq, void *v) |
| 183 | { | 194 | { |
| 184 | struct net *net = (struct net *)seq->private; | 195 | struct net *net = (struct net *)seq->private; |
| 185 | 196 | ||
| 186 | snmp6_seq_show_item(seq, (void **)net->mib.ipv6_statistics, | 197 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, |
| 187 | snmp6_ipstats_list); | 198 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); |
| 188 | snmp6_seq_show_item(seq, (void **)net->mib.icmpv6_statistics, | 199 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, |
| 189 | snmp6_icmp6_list); | 200 | snmp6_icmp6_list); |
| 190 | snmp6_seq_show_icmpv6msg(seq, (void **)net->mib.icmpv6msg_statistics); | 201 | snmp6_seq_show_icmpv6msg(seq, |
| 191 | snmp6_seq_show_item(seq, (void **)net->mib.udp_stats_in6, | 202 | (void __percpu **)net->mib.icmpv6msg_statistics); |
| 203 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, | ||
| 192 | snmp6_udp6_list); | 204 | snmp6_udp6_list); |
| 193 | snmp6_seq_show_item(seq, (void **)net->mib.udplite_stats_in6, | 205 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, |
| 194 | snmp6_udplite6_list); | 206 | snmp6_udplite6_list); |
| 195 | return 0; | 207 | return 0; |
| 196 | } | 208 | } |
| @@ -213,9 +225,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) | |||
| 213 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; | 225 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; |
| 214 | 226 | ||
| 215 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); | 227 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); |
| 216 | snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list); | 228 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, |
| 217 | snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); | 229 | snmp6_ipstats_list); |
| 218 | snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg); | 230 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6, |
| 231 | snmp6_icmp6_list); | ||
| 232 | snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg); | ||
| 219 | return 0; | 233 | return 0; |
| 220 | } | 234 | } |
| 221 | 235 | ||
| @@ -259,7 +273,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) | |||
| 259 | struct net *net = dev_net(idev->dev); | 273 | struct net *net = dev_net(idev->dev); |
| 260 | if (!net->mib.proc_net_devsnmp6) | 274 | if (!net->mib.proc_net_devsnmp6) |
| 261 | return -ENOENT; | 275 | return -ENOENT; |
| 262 | if (!idev || !idev->stats.proc_dir_entry) | 276 | if (!idev->stats.proc_dir_entry) |
| 263 | return -EINVAL; | 277 | return -EINVAL; |
| 264 | remove_proc_entry(idev->stats.proc_dir_entry->name, | 278 | remove_proc_entry(idev->stats.proc_dir_entry->name, |
| 265 | net->mib.proc_net_devsnmp6); | 279 | net->mib.proc_net_devsnmp6); |
| @@ -267,7 +281,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) | |||
| 267 | return 0; | 281 | return 0; |
| 268 | } | 282 | } |
| 269 | 283 | ||
| 270 | static int ipv6_proc_init_net(struct net *net) | 284 | static int __net_init ipv6_proc_init_net(struct net *net) |
| 271 | { | 285 | { |
| 272 | if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, | 286 | if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, |
| 273 | &sockstat6_seq_fops)) | 287 | &sockstat6_seq_fops)) |
| @@ -288,7 +302,7 @@ proc_dev_snmp6_fail: | |||
| 288 | return -ENOMEM; | 302 | return -ENOMEM; |
| 289 | } | 303 | } |
| 290 | 304 | ||
| 291 | static void ipv6_proc_exit_net(struct net *net) | 305 | static void __net_exit ipv6_proc_exit_net(struct net *net) |
| 292 | { | 306 | { |
| 293 | proc_net_remove(net, "sockstat6"); | 307 | proc_net_remove(net, "sockstat6"); |
| 294 | proc_net_remove(net, "dev_snmp6"); | 308 | proc_net_remove(net, "dev_snmp6"); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 926ce8eeffaf..e677937a07fc 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
| 22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 23 | #include <linux/socket.h> | 23 | #include <linux/socket.h> |
| 24 | #include <linux/slab.h> | ||
| 24 | #include <linux/sockios.h> | 25 | #include <linux/sockios.h> |
| 25 | #include <linux/net.h> | 26 | #include <linux/net.h> |
| 26 | #include <linux/in6.h> | 27 | #include <linux/in6.h> |
| @@ -380,7 +381,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | |||
| 380 | } | 381 | } |
| 381 | 382 | ||
| 382 | /* Charge it to the socket. */ | 383 | /* Charge it to the socket. */ |
| 383 | if (sock_queue_rcv_skb(sk, skb) < 0) { | 384 | if (ip_queue_rcv_skb(sk, skb) < 0) { |
| 384 | kfree_skb(skb); | 385 | kfree_skb(skb); |
| 385 | return NET_RX_DROP; | 386 | return NET_RX_DROP; |
| 386 | } | 387 | } |
| @@ -460,6 +461,9 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 460 | if (flags & MSG_ERRQUEUE) | 461 | if (flags & MSG_ERRQUEUE) |
| 461 | return ipv6_recv_error(sk, msg, len); | 462 | return ipv6_recv_error(sk, msg, len); |
| 462 | 463 | ||
| 464 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) | ||
| 465 | return ipv6_recv_rxpmtu(sk, msg, len); | ||
| 466 | |||
| 463 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 467 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
| 464 | if (!skb) | 468 | if (!skb) |
| 465 | goto out; | 469 | goto out; |
| @@ -598,31 +602,33 @@ out: | |||
| 598 | } | 602 | } |
| 599 | 603 | ||
| 600 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | 604 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, |
| 601 | struct flowi *fl, struct rt6_info *rt, | 605 | struct flowi *fl, struct dst_entry **dstp, |
| 602 | unsigned int flags) | 606 | unsigned int flags) |
| 603 | { | 607 | { |
| 604 | struct ipv6_pinfo *np = inet6_sk(sk); | 608 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 605 | struct ipv6hdr *iph; | 609 | struct ipv6hdr *iph; |
| 606 | struct sk_buff *skb; | 610 | struct sk_buff *skb; |
| 607 | int err; | 611 | int err; |
| 612 | struct rt6_info *rt = (struct rt6_info *)*dstp; | ||
| 608 | 613 | ||
| 609 | if (length > rt->u.dst.dev->mtu) { | 614 | if (length > rt->dst.dev->mtu) { |
| 610 | ipv6_local_error(sk, EMSGSIZE, fl, rt->u.dst.dev->mtu); | 615 | ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu); |
| 611 | return -EMSGSIZE; | 616 | return -EMSGSIZE; |
| 612 | } | 617 | } |
| 613 | if (flags&MSG_PROBE) | 618 | if (flags&MSG_PROBE) |
| 614 | goto out; | 619 | goto out; |
| 615 | 620 | ||
| 616 | skb = sock_alloc_send_skb(sk, | 621 | skb = sock_alloc_send_skb(sk, |
| 617 | length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15, | 622 | length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15, |
| 618 | flags & MSG_DONTWAIT, &err); | 623 | flags & MSG_DONTWAIT, &err); |
| 619 | if (skb == NULL) | 624 | if (skb == NULL) |
| 620 | goto error; | 625 | goto error; |
| 621 | skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev)); | 626 | skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev)); |
| 622 | 627 | ||
| 623 | skb->priority = sk->sk_priority; | 628 | skb->priority = sk->sk_priority; |
| 624 | skb->mark = sk->sk_mark; | 629 | skb->mark = sk->sk_mark; |
| 625 | skb_dst_set(skb, dst_clone(&rt->u.dst)); | 630 | skb_dst_set(skb, &rt->dst); |
| 631 | *dstp = NULL; | ||
| 626 | 632 | ||
| 627 | skb_put(skb, length); | 633 | skb_put(skb, length); |
| 628 | skb_reset_network_header(skb); | 634 | skb_reset_network_header(skb); |
| @@ -636,8 +642,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | |||
| 636 | goto error_fault; | 642 | goto error_fault; |
| 637 | 643 | ||
| 638 | IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); | 644 | IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); |
| 639 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, | 645 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, |
| 640 | dst_output); | 646 | rt->dst.dev, dst_output); |
| 641 | if (err > 0) | 647 | if (err > 0) |
| 642 | err = net_xmit_errno(err); | 648 | err = net_xmit_errno(err); |
| 643 | if (err) | 649 | if (err) |
| @@ -721,7 +727,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 721 | { | 727 | { |
| 722 | struct ipv6_txoptions opt_space; | 728 | struct ipv6_txoptions opt_space; |
| 723 | struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; | 729 | struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; |
| 724 | struct in6_addr *daddr, *final_p = NULL, final; | 730 | struct in6_addr *daddr, *final_p, final; |
| 725 | struct inet_sock *inet = inet_sk(sk); | 731 | struct inet_sock *inet = inet_sk(sk); |
| 726 | struct ipv6_pinfo *np = inet6_sk(sk); | 732 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 727 | struct raw6_sock *rp = raw6_sk(sk); | 733 | struct raw6_sock *rp = raw6_sk(sk); |
| @@ -732,6 +738,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 732 | int addr_len = msg->msg_namelen; | 738 | int addr_len = msg->msg_namelen; |
| 733 | int hlimit = -1; | 739 | int hlimit = -1; |
| 734 | int tclass = -1; | 740 | int tclass = -1; |
| 741 | int dontfrag = -1; | ||
| 735 | u16 proto; | 742 | u16 proto; |
| 736 | int err; | 743 | int err; |
| 737 | 744 | ||
| @@ -810,7 +817,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 810 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 817 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
| 811 | opt->tot_len = sizeof(struct ipv6_txoptions); | 818 | opt->tot_len = sizeof(struct ipv6_txoptions); |
| 812 | 819 | ||
| 813 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass); | 820 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, |
| 821 | &tclass, &dontfrag); | ||
| 814 | if (err < 0) { | 822 | if (err < 0) { |
| 815 | fl6_sock_release(flowlabel); | 823 | fl6_sock_release(flowlabel); |
| 816 | return err; | 824 | return err; |
| @@ -841,13 +849,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 841 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 849 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
| 842 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 850 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
| 843 | 851 | ||
| 844 | /* merge ip6_build_xmit from ip6_output */ | 852 | final_p = fl6_update_dst(&fl, opt, &final); |
| 845 | if (opt && opt->srcrt) { | ||
| 846 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 847 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 848 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 849 | final_p = &final; | ||
| 850 | } | ||
| 851 | 853 | ||
| 852 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 854 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
| 853 | fl.oif = np->mcast_oif; | 855 | fl.oif = np->mcast_oif; |
| @@ -879,17 +881,20 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 879 | if (tclass < 0) | 881 | if (tclass < 0) |
| 880 | tclass = np->tclass; | 882 | tclass = np->tclass; |
| 881 | 883 | ||
| 884 | if (dontfrag < 0) | ||
| 885 | dontfrag = np->dontfrag; | ||
| 886 | |||
| 882 | if (msg->msg_flags&MSG_CONFIRM) | 887 | if (msg->msg_flags&MSG_CONFIRM) |
| 883 | goto do_confirm; | 888 | goto do_confirm; |
| 884 | 889 | ||
| 885 | back_from_confirm: | 890 | back_from_confirm: |
| 886 | if (inet->hdrincl) { | 891 | if (inet->hdrincl) |
| 887 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags); | 892 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags); |
| 888 | } else { | 893 | else { |
| 889 | lock_sock(sk); | 894 | lock_sock(sk); |
| 890 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, | 895 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, |
| 891 | len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, | 896 | len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, |
| 892 | msg->msg_flags); | 897 | msg->msg_flags, dontfrag); |
| 893 | 898 | ||
| 894 | if (err) | 899 | if (err) |
| 895 | ip6_flush_pending_frames(sk); | 900 | ip6_flush_pending_frames(sk); |
| @@ -1275,7 +1280,7 @@ static const struct file_operations raw6_seq_fops = { | |||
| 1275 | .release = seq_release_net, | 1280 | .release = seq_release_net, |
| 1276 | }; | 1281 | }; |
| 1277 | 1282 | ||
| 1278 | static int raw6_init_net(struct net *net) | 1283 | static int __net_init raw6_init_net(struct net *net) |
| 1279 | { | 1284 | { |
| 1280 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) | 1285 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) |
| 1281 | return -ENOMEM; | 1286 | return -ENOMEM; |
| @@ -1283,7 +1288,7 @@ static int raw6_init_net(struct net *net) | |||
| 1283 | return 0; | 1288 | return 0; |
| 1284 | } | 1289 | } |
| 1285 | 1290 | ||
| 1286 | static void raw6_exit_net(struct net *net) | 1291 | static void __net_exit raw6_exit_net(struct net *net) |
| 1287 | { | 1292 | { |
| 1288 | proc_net_remove(net, "raw6"); | 1293 | proc_net_remove(net, "raw6"); |
| 1289 | } | 1294 | } |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2cddea3bd6be..64cfef1b0a4c 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/random.h> | 41 | #include <linux/random.h> |
| 42 | #include <linux/jhash.h> | 42 | #include <linux/jhash.h> |
| 43 | #include <linux/skbuff.h> | 43 | #include <linux/skbuff.h> |
| 44 | #include <linux/slab.h> | ||
| 44 | 45 | ||
| 45 | #include <net/sock.h> | 46 | #include <net/sock.h> |
| 46 | #include <net/snmp.h> | 47 | #include <net/snmp.h> |
| @@ -148,16 +149,6 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) | |||
| 148 | } | 149 | } |
| 149 | EXPORT_SYMBOL(ip6_frag_match); | 150 | EXPORT_SYMBOL(ip6_frag_match); |
| 150 | 151 | ||
| 151 | /* Memory Tracking Functions. */ | ||
| 152 | static inline void frag_kfree_skb(struct netns_frags *nf, | ||
| 153 | struct sk_buff *skb, int *work) | ||
| 154 | { | ||
| 155 | if (work) | ||
| 156 | *work -= skb->truesize; | ||
| 157 | atomic_sub(skb->truesize, &nf->mem); | ||
| 158 | kfree_skb(skb); | ||
| 159 | } | ||
| 160 | |||
| 161 | void ip6_frag_init(struct inet_frag_queue *q, void *a) | 152 | void ip6_frag_init(struct inet_frag_queue *q, void *a) |
| 162 | { | 153 | { |
| 163 | struct frag_queue *fq = container_of(q, struct frag_queue, q); | 154 | struct frag_queue *fq = container_of(q, struct frag_queue, q); |
| @@ -228,7 +219,7 @@ static void ip6_frag_expire(unsigned long data) | |||
| 228 | pointer directly, device might already disappeared. | 219 | pointer directly, device might already disappeared. |
| 229 | */ | 220 | */ |
| 230 | fq->q.fragments->dev = dev; | 221 | fq->q.fragments->dev = dev; |
| 231 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); | 222 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); |
| 232 | out_rcu_unlock: | 223 | out_rcu_unlock: |
| 233 | rcu_read_unlock(); | 224 | rcu_read_unlock(); |
| 234 | out: | 225 | out: |
| @@ -237,8 +228,7 @@ out: | |||
| 237 | } | 228 | } |
| 238 | 229 | ||
| 239 | static __inline__ struct frag_queue * | 230 | static __inline__ struct frag_queue * |
| 240 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | 231 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) |
| 241 | struct inet6_dev *idev) | ||
| 242 | { | 232 | { |
| 243 | struct inet_frag_queue *q; | 233 | struct inet_frag_queue *q; |
| 244 | struct ip6_create_arg arg; | 234 | struct ip6_create_arg arg; |
| @@ -254,13 +244,9 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
| 254 | 244 | ||
| 255 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 245 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
| 256 | if (q == NULL) | 246 | if (q == NULL) |
| 257 | goto oom; | 247 | return NULL; |
| 258 | 248 | ||
| 259 | return container_of(q, struct frag_queue, q); | 249 | return container_of(q, struct frag_queue, q); |
| 260 | |||
| 261 | oom: | ||
| 262 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS); | ||
| 263 | return NULL; | ||
| 264 | } | 250 | } |
| 265 | 251 | ||
| 266 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 252 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
| @@ -340,6 +326,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 340 | * in the chain of fragments so far. We must know where to put | 326 | * in the chain of fragments so far. We must know where to put |
| 341 | * this fragment, right? | 327 | * this fragment, right? |
| 342 | */ | 328 | */ |
| 329 | prev = fq->q.fragments_tail; | ||
| 330 | if (!prev || FRAG6_CB(prev)->offset < offset) { | ||
| 331 | next = NULL; | ||
| 332 | goto found; | ||
| 333 | } | ||
| 343 | prev = NULL; | 334 | prev = NULL; |
| 344 | for(next = fq->q.fragments; next != NULL; next = next->next) { | 335 | for(next = fq->q.fragments; next != NULL; next = next->next) { |
| 345 | if (FRAG6_CB(next)->offset >= offset) | 336 | if (FRAG6_CB(next)->offset >= offset) |
| @@ -347,63 +338,30 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 347 | prev = next; | 338 | prev = next; |
| 348 | } | 339 | } |
| 349 | 340 | ||
| 350 | /* We found where to put this one. Check for overlap with | 341 | found: |
| 351 | * preceding fragment, and, if needed, align things so that | 342 | /* RFC5722, Section 4: |
| 352 | * any overlaps are eliminated. | 343 | * When reassembling an IPv6 datagram, if |
| 344 | * one or more its constituent fragments is determined to be an | ||
| 345 | * overlapping fragment, the entire datagram (and any constituent | ||
| 346 | * fragments, including those not yet received) MUST be silently | ||
| 347 | * discarded. | ||
| 353 | */ | 348 | */ |
| 354 | if (prev) { | ||
| 355 | int i = (FRAG6_CB(prev)->offset + prev->len) - offset; | ||
| 356 | 349 | ||
| 357 | if (i > 0) { | 350 | /* Check for overlap with preceding fragment. */ |
| 358 | offset += i; | 351 | if (prev && |
| 359 | if (end <= offset) | 352 | (FRAG6_CB(prev)->offset + prev->len) - offset > 0) |
| 360 | goto err; | 353 | goto discard_fq; |
| 361 | if (!pskb_pull(skb, i)) | ||
| 362 | goto err; | ||
| 363 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
| 364 | skb->ip_summed = CHECKSUM_NONE; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | 354 | ||
| 368 | /* Look for overlap with succeeding segments. | 355 | /* Look for overlap with succeeding segment. */ |
| 369 | * If we can merge fragments, do it. | 356 | if (next && FRAG6_CB(next)->offset < end) |
| 370 | */ | 357 | goto discard_fq; |
| 371 | while (next && FRAG6_CB(next)->offset < end) { | ||
| 372 | int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */ | ||
| 373 | |||
| 374 | if (i < next->len) { | ||
| 375 | /* Eat head of the next overlapped fragment | ||
| 376 | * and leave the loop. The next ones cannot overlap. | ||
| 377 | */ | ||
| 378 | if (!pskb_pull(next, i)) | ||
| 379 | goto err; | ||
| 380 | FRAG6_CB(next)->offset += i; /* next fragment */ | ||
| 381 | fq->q.meat -= i; | ||
| 382 | if (next->ip_summed != CHECKSUM_UNNECESSARY) | ||
| 383 | next->ip_summed = CHECKSUM_NONE; | ||
| 384 | break; | ||
| 385 | } else { | ||
| 386 | struct sk_buff *free_it = next; | ||
| 387 | |||
| 388 | /* Old fragment is completely overridden with | ||
| 389 | * new one drop it. | ||
| 390 | */ | ||
| 391 | next = next->next; | ||
| 392 | |||
| 393 | if (prev) | ||
| 394 | prev->next = next; | ||
| 395 | else | ||
| 396 | fq->q.fragments = next; | ||
| 397 | |||
| 398 | fq->q.meat -= free_it->len; | ||
| 399 | frag_kfree_skb(fq->q.net, free_it, NULL); | ||
| 400 | } | ||
| 401 | } | ||
| 402 | 358 | ||
| 403 | FRAG6_CB(skb)->offset = offset; | 359 | FRAG6_CB(skb)->offset = offset; |
| 404 | 360 | ||
| 405 | /* Insert this fragment in the chain of fragments. */ | 361 | /* Insert this fragment in the chain of fragments. */ |
| 406 | skb->next = next; | 362 | skb->next = next; |
| 363 | if (!next) | ||
| 364 | fq->q.fragments_tail = skb; | ||
| 407 | if (prev) | 365 | if (prev) |
| 408 | prev->next = skb; | 366 | prev->next = skb; |
| 409 | else | 367 | else |
| @@ -435,6 +393,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
| 435 | write_unlock(&ip6_frags.lock); | 393 | write_unlock(&ip6_frags.lock); |
| 436 | return -1; | 394 | return -1; |
| 437 | 395 | ||
| 396 | discard_fq: | ||
| 397 | fq_kill(fq); | ||
| 438 | err: | 398 | err: |
| 439 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 399 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
| 440 | IPSTATS_MIB_REASMFAILS); | 400 | IPSTATS_MIB_REASMFAILS); |
| @@ -470,6 +430,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
| 470 | goto out_oom; | 430 | goto out_oom; |
| 471 | 431 | ||
| 472 | fp->next = head->next; | 432 | fp->next = head->next; |
| 433 | if (!fp->next) | ||
| 434 | fq->q.fragments_tail = fp; | ||
| 473 | prev->next = fp; | 435 | prev->next = fp; |
| 474 | 436 | ||
| 475 | skb_morph(head, fq->q.fragments); | 437 | skb_morph(head, fq->q.fragments); |
| @@ -528,7 +490,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
| 528 | skb_shinfo(head)->frag_list = head->next; | 490 | skb_shinfo(head)->frag_list = head->next; |
| 529 | skb_reset_transport_header(head); | 491 | skb_reset_transport_header(head); |
| 530 | skb_push(head, head->data - skb_network_header(head)); | 492 | skb_push(head, head->data - skb_network_header(head)); |
| 531 | atomic_sub(head->truesize, &fq->q.net->mem); | ||
| 532 | 493 | ||
| 533 | for (fp=head->next; fp; fp = fp->next) { | 494 | for (fp=head->next; fp; fp = fp->next) { |
| 534 | head->data_len += fp->len; | 495 | head->data_len += fp->len; |
| @@ -538,8 +499,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
| 538 | else if (head->ip_summed == CHECKSUM_COMPLETE) | 499 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
| 539 | head->csum = csum_add(head->csum, fp->csum); | 500 | head->csum = csum_add(head->csum, fp->csum); |
| 540 | head->truesize += fp->truesize; | 501 | head->truesize += fp->truesize; |
| 541 | atomic_sub(fp->truesize, &fq->q.net->mem); | ||
| 542 | } | 502 | } |
| 503 | atomic_sub(head->truesize, &fq->q.net->mem); | ||
| 543 | 504 | ||
| 544 | head->next = NULL; | 505 | head->next = NULL; |
| 545 | head->dev = dev; | 506 | head->dev = dev; |
| @@ -557,6 +518,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
| 557 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); | 518 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); |
| 558 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
| 559 | fq->q.fragments = NULL; | 520 | fq->q.fragments = NULL; |
| 521 | fq->q.fragments_tail = NULL; | ||
| 560 | return 1; | 522 | return 1; |
| 561 | 523 | ||
| 562 | out_oversize: | 524 | out_oversize: |
| @@ -606,8 +568,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
| 606 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 568 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) |
| 607 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); | 569 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); |
| 608 | 570 | ||
| 609 | if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, | 571 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); |
| 610 | ip6_dst_idev(skb_dst(skb)))) != NULL) { | 572 | if (fq != NULL) { |
| 611 | int ret; | 573 | int ret; |
| 612 | 574 | ||
| 613 | spin_lock(&fq->q.lock); | 575 | spin_lock(&fq->q.lock); |
| @@ -672,7 +634,7 @@ static struct ctl_table ip6_frags_ctl_table[] = { | |||
| 672 | { } | 634 | { } |
| 673 | }; | 635 | }; |
| 674 | 636 | ||
| 675 | static int ip6_frags_ns_sysctl_register(struct net *net) | 637 | static int __net_init ip6_frags_ns_sysctl_register(struct net *net) |
| 676 | { | 638 | { |
| 677 | struct ctl_table *table; | 639 | struct ctl_table *table; |
| 678 | struct ctl_table_header *hdr; | 640 | struct ctl_table_header *hdr; |
| @@ -702,7 +664,7 @@ err_alloc: | |||
| 702 | return -ENOMEM; | 664 | return -ENOMEM; |
| 703 | } | 665 | } |
| 704 | 666 | ||
| 705 | static void ip6_frags_ns_sysctl_unregister(struct net *net) | 667 | static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net) |
| 706 | { | 668 | { |
| 707 | struct ctl_table *table; | 669 | struct ctl_table *table; |
| 708 | 670 | ||
| @@ -745,10 +707,10 @@ static inline void ip6_frags_sysctl_unregister(void) | |||
| 745 | } | 707 | } |
| 746 | #endif | 708 | #endif |
| 747 | 709 | ||
| 748 | static int ipv6_frags_init_net(struct net *net) | 710 | static int __net_init ipv6_frags_init_net(struct net *net) |
| 749 | { | 711 | { |
| 750 | net->ipv6.frags.high_thresh = 256 * 1024; | 712 | net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
| 751 | net->ipv6.frags.low_thresh = 192 * 1024; | 713 | net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
| 752 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; | 714 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; |
| 753 | 715 | ||
| 754 | inet_frags_init_net(&net->ipv6.frags); | 716 | inet_frags_init_net(&net->ipv6.frags); |
| @@ -756,7 +718,7 @@ static int ipv6_frags_init_net(struct net *net) | |||
| 756 | return ip6_frags_ns_sysctl_register(net); | 718 | return ip6_frags_ns_sysctl_register(net); |
| 757 | } | 719 | } |
| 758 | 720 | ||
| 759 | static void ipv6_frags_exit_net(struct net *net) | 721 | static void __net_exit ipv6_frags_exit_net(struct net *net) |
| 760 | { | 722 | { |
| 761 | ip6_frags_ns_sysctl_unregister(net); | 723 | ip6_frags_ns_sysctl_unregister(net); |
| 762 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); | 724 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c2bd74c5f8d9..a275c6e1e25c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/proc_fs.h> | 40 | #include <linux/proc_fs.h> |
| 41 | #include <linux/seq_file.h> | 41 | #include <linux/seq_file.h> |
| 42 | #include <linux/nsproxy.h> | 42 | #include <linux/nsproxy.h> |
| 43 | #include <linux/slab.h> | ||
| 43 | #include <net/net_namespace.h> | 44 | #include <net/net_namespace.h> |
| 44 | #include <net/snmp.h> | 45 | #include <net/snmp.h> |
| 45 | #include <net/ipv6.h> | 46 | #include <net/ipv6.h> |
| @@ -125,16 +126,14 @@ static struct dst_ops ip6_dst_blackhole_ops = { | |||
| 125 | }; | 126 | }; |
| 126 | 127 | ||
| 127 | static struct rt6_info ip6_null_entry_template = { | 128 | static struct rt6_info ip6_null_entry_template = { |
| 128 | .u = { | 129 | .dst = { |
| 129 | .dst = { | 130 | .__refcnt = ATOMIC_INIT(1), |
| 130 | .__refcnt = ATOMIC_INIT(1), | 131 | .__use = 1, |
| 131 | .__use = 1, | 132 | .obsolete = -1, |
| 132 | .obsolete = -1, | 133 | .error = -ENETUNREACH, |
| 133 | .error = -ENETUNREACH, | 134 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
| 134 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 135 | .input = ip6_pkt_discard, |
| 135 | .input = ip6_pkt_discard, | 136 | .output = ip6_pkt_discard_out, |
| 136 | .output = ip6_pkt_discard_out, | ||
| 137 | } | ||
| 138 | }, | 137 | }, |
| 139 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 138 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
| 140 | .rt6i_protocol = RTPROT_KERNEL, | 139 | .rt6i_protocol = RTPROT_KERNEL, |
| @@ -148,16 +147,14 @@ static int ip6_pkt_prohibit(struct sk_buff *skb); | |||
| 148 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); | 147 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); |
| 149 | 148 | ||
| 150 | static struct rt6_info ip6_prohibit_entry_template = { | 149 | static struct rt6_info ip6_prohibit_entry_template = { |
| 151 | .u = { | 150 | .dst = { |
| 152 | .dst = { | 151 | .__refcnt = ATOMIC_INIT(1), |
| 153 | .__refcnt = ATOMIC_INIT(1), | 152 | .__use = 1, |
| 154 | .__use = 1, | 153 | .obsolete = -1, |
| 155 | .obsolete = -1, | 154 | .error = -EACCES, |
| 156 | .error = -EACCES, | 155 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
| 157 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 156 | .input = ip6_pkt_prohibit, |
| 158 | .input = ip6_pkt_prohibit, | 157 | .output = ip6_pkt_prohibit_out, |
| 159 | .output = ip6_pkt_prohibit_out, | ||
| 160 | } | ||
| 161 | }, | 158 | }, |
| 162 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 159 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
| 163 | .rt6i_protocol = RTPROT_KERNEL, | 160 | .rt6i_protocol = RTPROT_KERNEL, |
| @@ -166,16 +163,14 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
| 166 | }; | 163 | }; |
| 167 | 164 | ||
| 168 | static struct rt6_info ip6_blk_hole_entry_template = { | 165 | static struct rt6_info ip6_blk_hole_entry_template = { |
| 169 | .u = { | 166 | .dst = { |
| 170 | .dst = { | 167 | .__refcnt = ATOMIC_INIT(1), |
| 171 | .__refcnt = ATOMIC_INIT(1), | 168 | .__use = 1, |
| 172 | .__use = 1, | 169 | .obsolete = -1, |
| 173 | .obsolete = -1, | 170 | .error = -EINVAL, |
| 174 | .error = -EINVAL, | 171 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
| 175 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 172 | .input = dst_discard, |
| 176 | .input = dst_discard, | 173 | .output = dst_discard, |
| 177 | .output = dst_discard, | ||
| 178 | } | ||
| 179 | }, | 174 | }, |
| 180 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 175 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
| 181 | .rt6i_protocol = RTPROT_KERNEL, | 176 | .rt6i_protocol = RTPROT_KERNEL, |
| @@ -248,7 +243,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net, | |||
| 248 | if (!oif && ipv6_addr_any(saddr)) | 243 | if (!oif && ipv6_addr_any(saddr)) |
| 249 | goto out; | 244 | goto out; |
| 250 | 245 | ||
| 251 | for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { | 246 | for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) { |
| 252 | struct net_device *dev = sprt->rt6i_dev; | 247 | struct net_device *dev = sprt->rt6i_dev; |
| 253 | 248 | ||
| 254 | if (oif) { | 249 | if (oif) { |
| @@ -315,7 +310,6 @@ static void rt6_probe(struct rt6_info *rt) | |||
| 315 | #else | 310 | #else |
| 316 | static inline void rt6_probe(struct rt6_info *rt) | 311 | static inline void rt6_probe(struct rt6_info *rt) |
| 317 | { | 312 | { |
| 318 | return; | ||
| 319 | } | 313 | } |
| 320 | #endif | 314 | #endif |
| 321 | 315 | ||
| @@ -407,10 +401,10 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn, | |||
| 407 | 401 | ||
| 408 | match = NULL; | 402 | match = NULL; |
| 409 | for (rt = rr_head; rt && rt->rt6i_metric == metric; | 403 | for (rt = rr_head; rt && rt->rt6i_metric == metric; |
| 410 | rt = rt->u.dst.rt6_next) | 404 | rt = rt->dst.rt6_next) |
| 411 | match = find_match(rt, oif, strict, &mpri, match); | 405 | match = find_match(rt, oif, strict, &mpri, match); |
| 412 | for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric; | 406 | for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric; |
| 413 | rt = rt->u.dst.rt6_next) | 407 | rt = rt->dst.rt6_next) |
| 414 | match = find_match(rt, oif, strict, &mpri, match); | 408 | match = find_match(rt, oif, strict, &mpri, match); |
| 415 | 409 | ||
| 416 | return match; | 410 | return match; |
| @@ -432,7 +426,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | |||
| 432 | 426 | ||
| 433 | if (!match && | 427 | if (!match && |
| 434 | (strict & RT6_LOOKUP_F_REACHABLE)) { | 428 | (strict & RT6_LOOKUP_F_REACHABLE)) { |
| 435 | struct rt6_info *next = rt0->u.dst.rt6_next; | 429 | struct rt6_info *next = rt0->dst.rt6_next; |
| 436 | 430 | ||
| 437 | /* no entries matched; do round-robin */ | 431 | /* no entries matched; do round-robin */ |
| 438 | if (!next || next->rt6i_metric != rt0->rt6i_metric) | 432 | if (!next || next->rt6i_metric != rt0->rt6i_metric) |
| @@ -517,7 +511,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
| 517 | rt->rt6i_expires = jiffies + HZ * lifetime; | 511 | rt->rt6i_expires = jiffies + HZ * lifetime; |
| 518 | rt->rt6i_flags |= RTF_EXPIRES; | 512 | rt->rt6i_flags |= RTF_EXPIRES; |
| 519 | } | 513 | } |
| 520 | dst_release(&rt->u.dst); | 514 | dst_release(&rt->dst); |
| 521 | } | 515 | } |
| 522 | return 0; | 516 | return 0; |
| 523 | } | 517 | } |
| @@ -555,7 +549,7 @@ restart: | |||
| 555 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); | 549 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); |
| 556 | BACKTRACK(net, &fl->fl6_src); | 550 | BACKTRACK(net, &fl->fl6_src); |
| 557 | out: | 551 | out: |
| 558 | dst_use(&rt->u.dst, jiffies); | 552 | dst_use(&rt->dst, jiffies); |
| 559 | read_unlock_bh(&table->tb6_lock); | 553 | read_unlock_bh(&table->tb6_lock); |
| 560 | return rt; | 554 | return rt; |
| 561 | 555 | ||
| @@ -643,7 +637,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad | |||
| 643 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | 637 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); |
| 644 | rt->rt6i_dst.plen = 128; | 638 | rt->rt6i_dst.plen = 128; |
| 645 | rt->rt6i_flags |= RTF_CACHE; | 639 | rt->rt6i_flags |= RTF_CACHE; |
| 646 | rt->u.dst.flags |= DST_HOST; | 640 | rt->dst.flags |= DST_HOST; |
| 647 | 641 | ||
| 648 | #ifdef CONFIG_IPV6_SUBTREES | 642 | #ifdef CONFIG_IPV6_SUBTREES |
| 649 | if (rt->rt6i_src.plen && saddr) { | 643 | if (rt->rt6i_src.plen && saddr) { |
| @@ -676,8 +670,8 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad | |||
| 676 | 670 | ||
| 677 | if (net_ratelimit()) | 671 | if (net_ratelimit()) |
| 678 | printk(KERN_WARNING | 672 | printk(KERN_WARNING |
| 679 | "Neighbour table overflow.\n"); | 673 | "ipv6: Neighbour table overflow.\n"); |
| 680 | dst_free(&rt->u.dst); | 674 | dst_free(&rt->dst); |
| 681 | return NULL; | 675 | return NULL; |
| 682 | } | 676 | } |
| 683 | rt->rt6i_nexthop = neigh; | 677 | rt->rt6i_nexthop = neigh; |
| @@ -694,7 +688,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
| 694 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | 688 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); |
| 695 | rt->rt6i_dst.plen = 128; | 689 | rt->rt6i_dst.plen = 128; |
| 696 | rt->rt6i_flags |= RTF_CACHE; | 690 | rt->rt6i_flags |= RTF_CACHE; |
| 697 | rt->u.dst.flags |= DST_HOST; | 691 | rt->dst.flags |= DST_HOST; |
| 698 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); | 692 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); |
| 699 | } | 693 | } |
| 700 | return rt; | 694 | return rt; |
| @@ -726,7 +720,7 @@ restart: | |||
| 726 | rt->rt6i_flags & RTF_CACHE) | 720 | rt->rt6i_flags & RTF_CACHE) |
| 727 | goto out; | 721 | goto out; |
| 728 | 722 | ||
| 729 | dst_hold(&rt->u.dst); | 723 | dst_hold(&rt->dst); |
| 730 | read_unlock_bh(&table->tb6_lock); | 724 | read_unlock_bh(&table->tb6_lock); |
| 731 | 725 | ||
| 732 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 726 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| @@ -739,10 +733,10 @@ restart: | |||
| 739 | #endif | 733 | #endif |
| 740 | } | 734 | } |
| 741 | 735 | ||
| 742 | dst_release(&rt->u.dst); | 736 | dst_release(&rt->dst); |
| 743 | rt = nrt ? : net->ipv6.ip6_null_entry; | 737 | rt = nrt ? : net->ipv6.ip6_null_entry; |
| 744 | 738 | ||
| 745 | dst_hold(&rt->u.dst); | 739 | dst_hold(&rt->dst); |
| 746 | if (nrt) { | 740 | if (nrt) { |
| 747 | err = ip6_ins_rt(nrt); | 741 | err = ip6_ins_rt(nrt); |
| 748 | if (!err) | 742 | if (!err) |
| @@ -756,7 +750,7 @@ restart: | |||
| 756 | * Race condition! In the gap, when table->tb6_lock was | 750 | * Race condition! In the gap, when table->tb6_lock was |
| 757 | * released someone could insert this route. Relookup. | 751 | * released someone could insert this route. Relookup. |
| 758 | */ | 752 | */ |
| 759 | dst_release(&rt->u.dst); | 753 | dst_release(&rt->dst); |
| 760 | goto relookup; | 754 | goto relookup; |
| 761 | 755 | ||
| 762 | out: | 756 | out: |
| @@ -764,11 +758,11 @@ out: | |||
| 764 | reachable = 0; | 758 | reachable = 0; |
| 765 | goto restart_2; | 759 | goto restart_2; |
| 766 | } | 760 | } |
| 767 | dst_hold(&rt->u.dst); | 761 | dst_hold(&rt->dst); |
| 768 | read_unlock_bh(&table->tb6_lock); | 762 | read_unlock_bh(&table->tb6_lock); |
| 769 | out2: | 763 | out2: |
| 770 | rt->u.dst.lastuse = jiffies; | 764 | rt->dst.lastuse = jiffies; |
| 771 | rt->u.dst.__use++; | 765 | rt->dst.__use++; |
| 772 | 766 | ||
| 773 | return rt; | 767 | return rt; |
| 774 | } | 768 | } |
| @@ -814,20 +808,13 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | |||
| 814 | { | 808 | { |
| 815 | int flags = 0; | 809 | int flags = 0; |
| 816 | 810 | ||
| 817 | if (rt6_need_strict(&fl->fl6_dst)) | 811 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) |
| 818 | flags |= RT6_LOOKUP_F_IFACE; | 812 | flags |= RT6_LOOKUP_F_IFACE; |
| 819 | 813 | ||
| 820 | if (!ipv6_addr_any(&fl->fl6_src)) | 814 | if (!ipv6_addr_any(&fl->fl6_src)) |
| 821 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 815 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
| 822 | else if (sk) { | 816 | else if (sk) |
| 823 | unsigned int prefs = inet6_sk(sk)->srcprefs; | 817 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); |
| 824 | if (prefs & IPV6_PREFER_SRC_TMP) | ||
| 825 | flags |= RT6_LOOKUP_F_SRCPREF_TMP; | ||
| 826 | if (prefs & IPV6_PREFER_SRC_PUBLIC) | ||
| 827 | flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC; | ||
| 828 | if (prefs & IPV6_PREFER_SRC_COA) | ||
| 829 | flags |= RT6_LOOKUP_F_SRCPREF_COA; | ||
| 830 | } | ||
| 831 | 818 | ||
| 832 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); | 819 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); |
| 833 | } | 820 | } |
| @@ -842,15 +829,15 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
| 842 | struct dst_entry *new = NULL; | 829 | struct dst_entry *new = NULL; |
| 843 | 830 | ||
| 844 | if (rt) { | 831 | if (rt) { |
| 845 | new = &rt->u.dst; | 832 | new = &rt->dst; |
| 846 | 833 | ||
| 847 | atomic_set(&new->__refcnt, 1); | 834 | atomic_set(&new->__refcnt, 1); |
| 848 | new->__use = 1; | 835 | new->__use = 1; |
| 849 | new->input = dst_discard; | 836 | new->input = dst_discard; |
| 850 | new->output = dst_discard; | 837 | new->output = dst_discard; |
| 851 | 838 | ||
| 852 | memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); | 839 | memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); |
| 853 | new->dev = ort->u.dst.dev; | 840 | new->dev = ort->dst.dev; |
| 854 | if (new->dev) | 841 | if (new->dev) |
| 855 | dev_hold(new->dev); | 842 | dev_hold(new->dev); |
| 856 | rt->rt6i_idev = ort->rt6i_idev; | 843 | rt->rt6i_idev = ort->rt6i_idev; |
| @@ -886,7 +873,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
| 886 | 873 | ||
| 887 | rt = (struct rt6_info *) dst; | 874 | rt = (struct rt6_info *) dst; |
| 888 | 875 | ||
| 889 | if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 876 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) |
| 890 | return dst; | 877 | return dst; |
| 891 | 878 | ||
| 892 | return NULL; | 879 | return NULL; |
| @@ -897,24 +884,29 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) | |||
| 897 | struct rt6_info *rt = (struct rt6_info *) dst; | 884 | struct rt6_info *rt = (struct rt6_info *) dst; |
| 898 | 885 | ||
| 899 | if (rt) { | 886 | if (rt) { |
| 900 | if (rt->rt6i_flags & RTF_CACHE) | 887 | if (rt->rt6i_flags & RTF_CACHE) { |
| 901 | ip6_del_rt(rt); | 888 | if (rt6_check_expired(rt)) { |
| 902 | else | 889 | ip6_del_rt(rt); |
| 890 | dst = NULL; | ||
| 891 | } | ||
| 892 | } else { | ||
| 903 | dst_release(dst); | 893 | dst_release(dst); |
| 894 | dst = NULL; | ||
| 895 | } | ||
| 904 | } | 896 | } |
| 905 | return NULL; | 897 | return dst; |
| 906 | } | 898 | } |
| 907 | 899 | ||
| 908 | static void ip6_link_failure(struct sk_buff *skb) | 900 | static void ip6_link_failure(struct sk_buff *skb) |
| 909 | { | 901 | { |
| 910 | struct rt6_info *rt; | 902 | struct rt6_info *rt; |
| 911 | 903 | ||
| 912 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); | 904 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); |
| 913 | 905 | ||
| 914 | rt = (struct rt6_info *) skb_dst(skb); | 906 | rt = (struct rt6_info *) skb_dst(skb); |
| 915 | if (rt) { | 907 | if (rt) { |
| 916 | if (rt->rt6i_flags&RTF_CACHE) { | 908 | if (rt->rt6i_flags&RTF_CACHE) { |
| 917 | dst_set_expires(&rt->u.dst, 0); | 909 | dst_set_expires(&rt->dst, 0); |
| 918 | rt->rt6i_flags |= RTF_EXPIRES; | 910 | rt->rt6i_flags |= RTF_EXPIRES; |
| 919 | } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) | 911 | } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) |
| 920 | rt->rt6i_node->fn_sernum = -1; | 912 | rt->rt6i_node->fn_sernum = -1; |
| @@ -988,14 +980,14 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
| 988 | rt->rt6i_dev = dev; | 980 | rt->rt6i_dev = dev; |
| 989 | rt->rt6i_idev = idev; | 981 | rt->rt6i_idev = idev; |
| 990 | rt->rt6i_nexthop = neigh; | 982 | rt->rt6i_nexthop = neigh; |
| 991 | atomic_set(&rt->u.dst.__refcnt, 1); | 983 | atomic_set(&rt->dst.__refcnt, 1); |
| 992 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; | 984 | rt->dst.metrics[RTAX_HOPLIMIT-1] = 255; |
| 993 | rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | 985 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); |
| 994 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); | 986 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); |
| 995 | rt->u.dst.output = ip6_output; | 987 | rt->dst.output = ip6_output; |
| 996 | 988 | ||
| 997 | #if 0 /* there's no chance to use these for ndisc */ | 989 | #if 0 /* there's no chance to use these for ndisc */ |
| 998 | rt->u.dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST | 990 | rt->dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST |
| 999 | ? DST_HOST | 991 | ? DST_HOST |
| 1000 | : 0; | 992 | : 0; |
| 1001 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 993 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
| @@ -1003,14 +995,14 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
| 1003 | #endif | 995 | #endif |
| 1004 | 996 | ||
| 1005 | spin_lock_bh(&icmp6_dst_lock); | 997 | spin_lock_bh(&icmp6_dst_lock); |
| 1006 | rt->u.dst.next = icmp6_dst_gc_list; | 998 | rt->dst.next = icmp6_dst_gc_list; |
| 1007 | icmp6_dst_gc_list = &rt->u.dst; | 999 | icmp6_dst_gc_list = &rt->dst; |
| 1008 | spin_unlock_bh(&icmp6_dst_lock); | 1000 | spin_unlock_bh(&icmp6_dst_lock); |
| 1009 | 1001 | ||
| 1010 | fib6_force_start_gc(net); | 1002 | fib6_force_start_gc(net); |
| 1011 | 1003 | ||
| 1012 | out: | 1004 | out: |
| 1013 | return &rt->u.dst; | 1005 | return &rt->dst; |
| 1014 | } | 1006 | } |
| 1015 | 1007 | ||
| 1016 | int icmp6_dst_gc(void) | 1008 | int icmp6_dst_gc(void) |
| @@ -1092,11 +1084,11 @@ static int ipv6_get_mtu(struct net_device *dev) | |||
| 1092 | int mtu = IPV6_MIN_MTU; | 1084 | int mtu = IPV6_MIN_MTU; |
| 1093 | struct inet6_dev *idev; | 1085 | struct inet6_dev *idev; |
| 1094 | 1086 | ||
| 1095 | idev = in6_dev_get(dev); | 1087 | rcu_read_lock(); |
| 1096 | if (idev) { | 1088 | idev = __in6_dev_get(dev); |
| 1089 | if (idev) | ||
| 1097 | mtu = idev->cnf.mtu6; | 1090 | mtu = idev->cnf.mtu6; |
| 1098 | in6_dev_put(idev); | 1091 | rcu_read_unlock(); |
| 1099 | } | ||
| 1100 | return mtu; | 1092 | return mtu; |
| 1101 | } | 1093 | } |
| 1102 | 1094 | ||
| @@ -1105,12 +1097,15 @@ int ip6_dst_hoplimit(struct dst_entry *dst) | |||
| 1105 | int hoplimit = dst_metric(dst, RTAX_HOPLIMIT); | 1097 | int hoplimit = dst_metric(dst, RTAX_HOPLIMIT); |
| 1106 | if (hoplimit < 0) { | 1098 | if (hoplimit < 0) { |
| 1107 | struct net_device *dev = dst->dev; | 1099 | struct net_device *dev = dst->dev; |
| 1108 | struct inet6_dev *idev = in6_dev_get(dev); | 1100 | struct inet6_dev *idev; |
| 1109 | if (idev) { | 1101 | |
| 1102 | rcu_read_lock(); | ||
| 1103 | idev = __in6_dev_get(dev); | ||
| 1104 | if (idev) | ||
| 1110 | hoplimit = idev->cnf.hop_limit; | 1105 | hoplimit = idev->cnf.hop_limit; |
| 1111 | in6_dev_put(idev); | 1106 | else |
| 1112 | } else | ||
| 1113 | hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; | 1107 | hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; |
| 1108 | rcu_read_unlock(); | ||
| 1114 | } | 1109 | } |
| 1115 | return hoplimit; | 1110 | return hoplimit; |
| 1116 | } | 1111 | } |
| @@ -1161,7 +1156,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1161 | goto out; | 1156 | goto out; |
| 1162 | } | 1157 | } |
| 1163 | 1158 | ||
| 1164 | rt->u.dst.obsolete = -1; | 1159 | rt->dst.obsolete = -1; |
| 1165 | rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ? | 1160 | rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ? |
| 1166 | jiffies + clock_t_to_jiffies(cfg->fc_expires) : | 1161 | jiffies + clock_t_to_jiffies(cfg->fc_expires) : |
| 1167 | 0; | 1162 | 0; |
| @@ -1173,16 +1168,16 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1173 | addr_type = ipv6_addr_type(&cfg->fc_dst); | 1168 | addr_type = ipv6_addr_type(&cfg->fc_dst); |
| 1174 | 1169 | ||
| 1175 | if (addr_type & IPV6_ADDR_MULTICAST) | 1170 | if (addr_type & IPV6_ADDR_MULTICAST) |
| 1176 | rt->u.dst.input = ip6_mc_input; | 1171 | rt->dst.input = ip6_mc_input; |
| 1177 | else | 1172 | else |
| 1178 | rt->u.dst.input = ip6_forward; | 1173 | rt->dst.input = ip6_forward; |
| 1179 | 1174 | ||
| 1180 | rt->u.dst.output = ip6_output; | 1175 | rt->dst.output = ip6_output; |
| 1181 | 1176 | ||
| 1182 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); | 1177 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
| 1183 | rt->rt6i_dst.plen = cfg->fc_dst_len; | 1178 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
| 1184 | if (rt->rt6i_dst.plen == 128) | 1179 | if (rt->rt6i_dst.plen == 128) |
| 1185 | rt->u.dst.flags = DST_HOST; | 1180 | rt->dst.flags = DST_HOST; |
| 1186 | 1181 | ||
| 1187 | #ifdef CONFIG_IPV6_SUBTREES | 1182 | #ifdef CONFIG_IPV6_SUBTREES |
| 1188 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); | 1183 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
| @@ -1210,9 +1205,9 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1210 | goto out; | 1205 | goto out; |
| 1211 | } | 1206 | } |
| 1212 | } | 1207 | } |
| 1213 | rt->u.dst.output = ip6_pkt_discard_out; | 1208 | rt->dst.output = ip6_pkt_discard_out; |
| 1214 | rt->u.dst.input = ip6_pkt_discard; | 1209 | rt->dst.input = ip6_pkt_discard; |
| 1215 | rt->u.dst.error = -ENETUNREACH; | 1210 | rt->dst.error = -ENETUNREACH; |
| 1216 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; | 1211 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; |
| 1217 | goto install_route; | 1212 | goto install_route; |
| 1218 | } | 1213 | } |
| @@ -1246,7 +1241,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1246 | goto out; | 1241 | goto out; |
| 1247 | if (dev) { | 1242 | if (dev) { |
| 1248 | if (dev != grt->rt6i_dev) { | 1243 | if (dev != grt->rt6i_dev) { |
| 1249 | dst_release(&grt->u.dst); | 1244 | dst_release(&grt->dst); |
| 1250 | goto out; | 1245 | goto out; |
| 1251 | } | 1246 | } |
| 1252 | } else { | 1247 | } else { |
| @@ -1257,7 +1252,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
| 1257 | } | 1252 | } |
| 1258 | if (!(grt->rt6i_flags&RTF_GATEWAY)) | 1253 | if (!(grt->rt6i_flags&RTF_GATEWAY)) |
| 1259 | err = 0; | 1254 | err = 0; |
| 1260 | dst_release(&grt->u.dst); | 1255 | dst_release(&grt->dst); |
| 1261 | 1256 | ||
| 1262 | if (err) | 1257 | if (err) |
| 1263 | goto out; | 1258 | goto out; |
| @@ -1296,18 +1291,18 @@ install_route: | |||
| 1296 | goto out; | 1291 | goto out; |
| 1297 | } | 1292 | } |
| 1298 | 1293 | ||
| 1299 | rt->u.dst.metrics[type - 1] = nla_get_u32(nla); | 1294 | rt->dst.metrics[type - 1] = nla_get_u32(nla); |
| 1300 | } | 1295 | } |
| 1301 | } | 1296 | } |
| 1302 | } | 1297 | } |
| 1303 | 1298 | ||
| 1304 | if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0) | 1299 | if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0) |
| 1305 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1; | 1300 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; |
| 1306 | if (!dst_mtu(&rt->u.dst)) | 1301 | if (!dst_mtu(&rt->dst)) |
| 1307 | rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); | 1302 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); |
| 1308 | if (!dst_metric(&rt->u.dst, RTAX_ADVMSS)) | 1303 | if (!dst_metric(&rt->dst, RTAX_ADVMSS)) |
| 1309 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); | 1304 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); |
| 1310 | rt->u.dst.dev = dev; | 1305 | rt->dst.dev = dev; |
| 1311 | rt->rt6i_idev = idev; | 1306 | rt->rt6i_idev = idev; |
| 1312 | rt->rt6i_table = table; | 1307 | rt->rt6i_table = table; |
| 1313 | 1308 | ||
| @@ -1321,7 +1316,7 @@ out: | |||
| 1321 | if (idev) | 1316 | if (idev) |
| 1322 | in6_dev_put(idev); | 1317 | in6_dev_put(idev); |
| 1323 | if (rt) | 1318 | if (rt) |
| 1324 | dst_free(&rt->u.dst); | 1319 | dst_free(&rt->dst); |
| 1325 | return err; | 1320 | return err; |
| 1326 | } | 1321 | } |
| 1327 | 1322 | ||
| @@ -1338,7 +1333,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) | |||
| 1338 | write_lock_bh(&table->tb6_lock); | 1333 | write_lock_bh(&table->tb6_lock); |
| 1339 | 1334 | ||
| 1340 | err = fib6_del(rt, info); | 1335 | err = fib6_del(rt, info); |
| 1341 | dst_release(&rt->u.dst); | 1336 | dst_release(&rt->dst); |
| 1342 | 1337 | ||
| 1343 | write_unlock_bh(&table->tb6_lock); | 1338 | write_unlock_bh(&table->tb6_lock); |
| 1344 | 1339 | ||
| @@ -1371,7 +1366,7 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
| 1371 | &cfg->fc_src, cfg->fc_src_len); | 1366 | &cfg->fc_src, cfg->fc_src_len); |
| 1372 | 1367 | ||
| 1373 | if (fn) { | 1368 | if (fn) { |
| 1374 | for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) { | 1369 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
| 1375 | if (cfg->fc_ifindex && | 1370 | if (cfg->fc_ifindex && |
| 1376 | (rt->rt6i_dev == NULL || | 1371 | (rt->rt6i_dev == NULL || |
| 1377 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) | 1372 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) |
| @@ -1381,7 +1376,7 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
| 1381 | continue; | 1376 | continue; |
| 1382 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) | 1377 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
| 1383 | continue; | 1378 | continue; |
| 1384 | dst_hold(&rt->u.dst); | 1379 | dst_hold(&rt->dst); |
| 1385 | read_unlock_bh(&table->tb6_lock); | 1380 | read_unlock_bh(&table->tb6_lock); |
| 1386 | 1381 | ||
| 1387 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); | 1382 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); |
| @@ -1423,7 +1418,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, | |||
| 1423 | read_lock_bh(&table->tb6_lock); | 1418 | read_lock_bh(&table->tb6_lock); |
| 1424 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 1419 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
| 1425 | restart: | 1420 | restart: |
| 1426 | for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) { | 1421 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
| 1427 | /* | 1422 | /* |
| 1428 | * Current route is on-link; redirect is always invalid. | 1423 | * Current route is on-link; redirect is always invalid. |
| 1429 | * | 1424 | * |
| @@ -1447,7 +1442,7 @@ restart: | |||
| 1447 | rt = net->ipv6.ip6_null_entry; | 1442 | rt = net->ipv6.ip6_null_entry; |
| 1448 | BACKTRACK(net, &fl->fl6_src); | 1443 | BACKTRACK(net, &fl->fl6_src); |
| 1449 | out: | 1444 | out: |
| 1450 | dst_hold(&rt->u.dst); | 1445 | dst_hold(&rt->dst); |
| 1451 | 1446 | ||
| 1452 | read_unlock_bh(&table->tb6_lock); | 1447 | read_unlock_bh(&table->tb6_lock); |
| 1453 | 1448 | ||
| @@ -1515,10 +1510,10 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
| 1515 | * Look, redirects are sent only in response to data packets, | 1510 | * Look, redirects are sent only in response to data packets, |
| 1516 | * so that this nexthop apparently is reachable. --ANK | 1511 | * so that this nexthop apparently is reachable. --ANK |
| 1517 | */ | 1512 | */ |
| 1518 | dst_confirm(&rt->u.dst); | 1513 | dst_confirm(&rt->dst); |
| 1519 | 1514 | ||
| 1520 | /* Duplicate redirect: silently ignore. */ | 1515 | /* Duplicate redirect: silently ignore. */ |
| 1521 | if (neigh == rt->u.dst.neighbour) | 1516 | if (neigh == rt->dst.neighbour) |
| 1522 | goto out; | 1517 | goto out; |
| 1523 | 1518 | ||
| 1524 | nrt = ip6_rt_copy(rt); | 1519 | nrt = ip6_rt_copy(rt); |
| @@ -1531,20 +1526,20 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
| 1531 | 1526 | ||
| 1532 | ipv6_addr_copy(&nrt->rt6i_dst.addr, dest); | 1527 | ipv6_addr_copy(&nrt->rt6i_dst.addr, dest); |
| 1533 | nrt->rt6i_dst.plen = 128; | 1528 | nrt->rt6i_dst.plen = 128; |
| 1534 | nrt->u.dst.flags |= DST_HOST; | 1529 | nrt->dst.flags |= DST_HOST; |
| 1535 | 1530 | ||
| 1536 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); | 1531 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); |
| 1537 | nrt->rt6i_nexthop = neigh_clone(neigh); | 1532 | nrt->rt6i_nexthop = neigh_clone(neigh); |
| 1538 | /* Reset pmtu, it may be better */ | 1533 | /* Reset pmtu, it may be better */ |
| 1539 | nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); | 1534 | nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); |
| 1540 | nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), | 1535 | nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), |
| 1541 | dst_mtu(&nrt->u.dst)); | 1536 | dst_mtu(&nrt->dst)); |
| 1542 | 1537 | ||
| 1543 | if (ip6_ins_rt(nrt)) | 1538 | if (ip6_ins_rt(nrt)) |
| 1544 | goto out; | 1539 | goto out; |
| 1545 | 1540 | ||
| 1546 | netevent.old = &rt->u.dst; | 1541 | netevent.old = &rt->dst; |
| 1547 | netevent.new = &nrt->u.dst; | 1542 | netevent.new = &nrt->dst; |
| 1548 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1543 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
| 1549 | 1544 | ||
| 1550 | if (rt->rt6i_flags&RTF_CACHE) { | 1545 | if (rt->rt6i_flags&RTF_CACHE) { |
| @@ -1553,8 +1548,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
| 1553 | } | 1548 | } |
| 1554 | 1549 | ||
| 1555 | out: | 1550 | out: |
| 1556 | dst_release(&rt->u.dst); | 1551 | dst_release(&rt->dst); |
| 1557 | return; | ||
| 1558 | } | 1552 | } |
| 1559 | 1553 | ||
| 1560 | /* | 1554 | /* |
| @@ -1562,18 +1556,17 @@ out: | |||
| 1562 | * i.e. Path MTU discovery | 1556 | * i.e. Path MTU discovery |
| 1563 | */ | 1557 | */ |
| 1564 | 1558 | ||
| 1565 | void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | 1559 | static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, |
| 1566 | struct net_device *dev, u32 pmtu) | 1560 | struct net *net, u32 pmtu, int ifindex) |
| 1567 | { | 1561 | { |
| 1568 | struct rt6_info *rt, *nrt; | 1562 | struct rt6_info *rt, *nrt; |
| 1569 | struct net *net = dev_net(dev); | ||
| 1570 | int allfrag = 0; | 1563 | int allfrag = 0; |
| 1571 | 1564 | ||
| 1572 | rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0); | 1565 | rt = rt6_lookup(net, daddr, saddr, ifindex, 0); |
| 1573 | if (rt == NULL) | 1566 | if (rt == NULL) |
| 1574 | return; | 1567 | return; |
| 1575 | 1568 | ||
| 1576 | if (pmtu >= dst_mtu(&rt->u.dst)) | 1569 | if (pmtu >= dst_mtu(&rt->dst)) |
| 1577 | goto out; | 1570 | goto out; |
| 1578 | 1571 | ||
| 1579 | if (pmtu < IPV6_MIN_MTU) { | 1572 | if (pmtu < IPV6_MIN_MTU) { |
| @@ -1591,7 +1584,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1591 | They are sent only in response to data packets, | 1584 | They are sent only in response to data packets, |
| 1592 | so that this nexthop apparently is reachable. --ANK | 1585 | so that this nexthop apparently is reachable. --ANK |
| 1593 | */ | 1586 | */ |
| 1594 | dst_confirm(&rt->u.dst); | 1587 | dst_confirm(&rt->dst); |
| 1595 | 1588 | ||
| 1596 | /* Host route. If it is static, it would be better | 1589 | /* Host route. If it is static, it would be better |
| 1597 | not to override it, but add new one, so that | 1590 | not to override it, but add new one, so that |
| @@ -1599,10 +1592,10 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1599 | would return automatically. | 1592 | would return automatically. |
| 1600 | */ | 1593 | */ |
| 1601 | if (rt->rt6i_flags & RTF_CACHE) { | 1594 | if (rt->rt6i_flags & RTF_CACHE) { |
| 1602 | rt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1595 | rt->dst.metrics[RTAX_MTU-1] = pmtu; |
| 1603 | if (allfrag) | 1596 | if (allfrag) |
| 1604 | rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1597 | rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
| 1605 | dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1598 | dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); |
| 1606 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; | 1599 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; |
| 1607 | goto out; | 1600 | goto out; |
| 1608 | } | 1601 | } |
| @@ -1618,9 +1611,9 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1618 | nrt = rt6_alloc_clone(rt, daddr); | 1611 | nrt = rt6_alloc_clone(rt, daddr); |
| 1619 | 1612 | ||
| 1620 | if (nrt) { | 1613 | if (nrt) { |
| 1621 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1614 | nrt->dst.metrics[RTAX_MTU-1] = pmtu; |
| 1622 | if (allfrag) | 1615 | if (allfrag) |
| 1623 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1616 | nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
| 1624 | 1617 | ||
| 1625 | /* According to RFC 1981, detecting PMTU increase shouldn't be | 1618 | /* According to RFC 1981, detecting PMTU increase shouldn't be |
| 1626 | * happened within 5 mins, the recommended timer is 10 mins. | 1619 | * happened within 5 mins, the recommended timer is 10 mins. |
| @@ -1628,13 +1621,34 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
| 1628 | * which is 10 mins. After 10 mins the decreased pmtu is expired | 1621 | * which is 10 mins. After 10 mins the decreased pmtu is expired |
| 1629 | * and detecting PMTU increase will be automatically happened. | 1622 | * and detecting PMTU increase will be automatically happened. |
| 1630 | */ | 1623 | */ |
| 1631 | dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1624 | dst_set_expires(&nrt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); |
| 1632 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | 1625 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; |
| 1633 | 1626 | ||
| 1634 | ip6_ins_rt(nrt); | 1627 | ip6_ins_rt(nrt); |
| 1635 | } | 1628 | } |
| 1636 | out: | 1629 | out: |
| 1637 | dst_release(&rt->u.dst); | 1630 | dst_release(&rt->dst); |
| 1631 | } | ||
| 1632 | |||
| 1633 | void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | ||
| 1634 | struct net_device *dev, u32 pmtu) | ||
| 1635 | { | ||
| 1636 | struct net *net = dev_net(dev); | ||
| 1637 | |||
| 1638 | /* | ||
| 1639 | * RFC 1981 states that a node "MUST reduce the size of the packets it | ||
| 1640 | * is sending along the path" that caused the Packet Too Big message. | ||
| 1641 | * Since it's not possible in the general case to determine which | ||
| 1642 | * interface was used to send the original packet, we update the MTU | ||
| 1643 | * on the interface that will be used to send future packets. We also | ||
| 1644 | * update the MTU on the interface that received the Packet Too Big in | ||
| 1645 | * case the original packet was forced out that interface with | ||
| 1646 | * SO_BINDTODEVICE or similar. This is the next best thing to the | ||
| 1647 | * correct behaviour, which would be to update the MTU on all | ||
| 1648 | * interfaces. | ||
| 1649 | */ | ||
| 1650 | rt6_do_pmtu_disc(daddr, saddr, net, pmtu, 0); | ||
| 1651 | rt6_do_pmtu_disc(daddr, saddr, net, pmtu, dev->ifindex); | ||
| 1638 | } | 1652 | } |
| 1639 | 1653 | ||
| 1640 | /* | 1654 | /* |
| @@ -1647,18 +1661,18 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
| 1647 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1661 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); |
| 1648 | 1662 | ||
| 1649 | if (rt) { | 1663 | if (rt) { |
| 1650 | rt->u.dst.input = ort->u.dst.input; | 1664 | rt->dst.input = ort->dst.input; |
| 1651 | rt->u.dst.output = ort->u.dst.output; | 1665 | rt->dst.output = ort->dst.output; |
| 1652 | 1666 | ||
| 1653 | memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); | 1667 | memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); |
| 1654 | rt->u.dst.error = ort->u.dst.error; | 1668 | rt->dst.error = ort->dst.error; |
| 1655 | rt->u.dst.dev = ort->u.dst.dev; | 1669 | rt->dst.dev = ort->dst.dev; |
| 1656 | if (rt->u.dst.dev) | 1670 | if (rt->dst.dev) |
| 1657 | dev_hold(rt->u.dst.dev); | 1671 | dev_hold(rt->dst.dev); |
| 1658 | rt->rt6i_idev = ort->rt6i_idev; | 1672 | rt->rt6i_idev = ort->rt6i_idev; |
| 1659 | if (rt->rt6i_idev) | 1673 | if (rt->rt6i_idev) |
| 1660 | in6_dev_hold(rt->rt6i_idev); | 1674 | in6_dev_hold(rt->rt6i_idev); |
| 1661 | rt->u.dst.lastuse = jiffies; | 1675 | rt->dst.lastuse = jiffies; |
| 1662 | rt->rt6i_expires = 0; | 1676 | rt->rt6i_expires = 0; |
| 1663 | 1677 | ||
| 1664 | ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); | 1678 | ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); |
| @@ -1692,14 +1706,14 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
| 1692 | if (!fn) | 1706 | if (!fn) |
| 1693 | goto out; | 1707 | goto out; |
| 1694 | 1708 | ||
| 1695 | for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) { | 1709 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
| 1696 | if (rt->rt6i_dev->ifindex != ifindex) | 1710 | if (rt->rt6i_dev->ifindex != ifindex) |
| 1697 | continue; | 1711 | continue; |
| 1698 | if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) | 1712 | if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) |
| 1699 | continue; | 1713 | continue; |
| 1700 | if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) | 1714 | if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) |
| 1701 | continue; | 1715 | continue; |
| 1702 | dst_hold(&rt->u.dst); | 1716 | dst_hold(&rt->dst); |
| 1703 | break; | 1717 | break; |
| 1704 | } | 1718 | } |
| 1705 | out: | 1719 | out: |
| @@ -1747,14 +1761,14 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
| 1747 | return NULL; | 1761 | return NULL; |
| 1748 | 1762 | ||
| 1749 | write_lock_bh(&table->tb6_lock); | 1763 | write_lock_bh(&table->tb6_lock); |
| 1750 | for (rt = table->tb6_root.leaf; rt; rt=rt->u.dst.rt6_next) { | 1764 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { |
| 1751 | if (dev == rt->rt6i_dev && | 1765 | if (dev == rt->rt6i_dev && |
| 1752 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1766 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
| 1753 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1767 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
| 1754 | break; | 1768 | break; |
| 1755 | } | 1769 | } |
| 1756 | if (rt) | 1770 | if (rt) |
| 1757 | dst_hold(&rt->u.dst); | 1771 | dst_hold(&rt->dst); |
| 1758 | write_unlock_bh(&table->tb6_lock); | 1772 | write_unlock_bh(&table->tb6_lock); |
| 1759 | return rt; | 1773 | return rt; |
| 1760 | } | 1774 | } |
| @@ -1793,9 +1807,9 @@ void rt6_purge_dflt_routers(struct net *net) | |||
| 1793 | 1807 | ||
| 1794 | restart: | 1808 | restart: |
| 1795 | read_lock_bh(&table->tb6_lock); | 1809 | read_lock_bh(&table->tb6_lock); |
| 1796 | for (rt = table->tb6_root.leaf; rt; rt = rt->u.dst.rt6_next) { | 1810 | for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { |
| 1797 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1811 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
| 1798 | dst_hold(&rt->u.dst); | 1812 | dst_hold(&rt->dst); |
| 1799 | read_unlock_bh(&table->tb6_lock); | 1813 | read_unlock_bh(&table->tb6_lock); |
| 1800 | ip6_del_rt(rt); | 1814 | ip6_del_rt(rt); |
| 1801 | goto restart; | 1815 | goto restart; |
| @@ -1873,7 +1887,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
| 1873 | switch (ipstats_mib_noroutes) { | 1887 | switch (ipstats_mib_noroutes) { |
| 1874 | case IPSTATS_MIB_INNOROUTES: | 1888 | case IPSTATS_MIB_INNOROUTES: |
| 1875 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); | 1889 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); |
| 1876 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) { | 1890 | if (type == IPV6_ADDR_ANY) { |
| 1877 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), | 1891 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), |
| 1878 | IPSTATS_MIB_INADDRERRORS); | 1892 | IPSTATS_MIB_INADDRERRORS); |
| 1879 | break; | 1893 | break; |
| @@ -1884,7 +1898,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
| 1884 | ipstats_mib_noroutes); | 1898 | ipstats_mib_noroutes); |
| 1885 | break; | 1899 | break; |
| 1886 | } | 1900 | } |
| 1887 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); | 1901 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); |
| 1888 | kfree_skb(skb); | 1902 | kfree_skb(skb); |
| 1889 | return 0; | 1903 | return 0; |
| 1890 | } | 1904 | } |
| @@ -1933,15 +1947,15 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
| 1933 | dev_hold(net->loopback_dev); | 1947 | dev_hold(net->loopback_dev); |
| 1934 | in6_dev_hold(idev); | 1948 | in6_dev_hold(idev); |
| 1935 | 1949 | ||
| 1936 | rt->u.dst.flags = DST_HOST; | 1950 | rt->dst.flags = DST_HOST; |
| 1937 | rt->u.dst.input = ip6_input; | 1951 | rt->dst.input = ip6_input; |
| 1938 | rt->u.dst.output = ip6_output; | 1952 | rt->dst.output = ip6_output; |
| 1939 | rt->rt6i_dev = net->loopback_dev; | 1953 | rt->rt6i_dev = net->loopback_dev; |
| 1940 | rt->rt6i_idev = idev; | 1954 | rt->rt6i_idev = idev; |
| 1941 | rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | 1955 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); |
| 1942 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); | 1956 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); |
| 1943 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1; | 1957 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; |
| 1944 | rt->u.dst.obsolete = -1; | 1958 | rt->dst.obsolete = -1; |
| 1945 | 1959 | ||
| 1946 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 1960 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
| 1947 | if (anycast) | 1961 | if (anycast) |
| @@ -1950,7 +1964,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
| 1950 | rt->rt6i_flags |= RTF_LOCAL; | 1964 | rt->rt6i_flags |= RTF_LOCAL; |
| 1951 | neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); | 1965 | neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); |
| 1952 | if (IS_ERR(neigh)) { | 1966 | if (IS_ERR(neigh)) { |
| 1953 | dst_free(&rt->u.dst); | 1967 | dst_free(&rt->dst); |
| 1954 | 1968 | ||
| 1955 | /* We are casting this because that is the return | 1969 | /* We are casting this because that is the return |
| 1956 | * value type. But an errno encoded pointer is the | 1970 | * value type. But an errno encoded pointer is the |
| @@ -1965,7 +1979,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
| 1965 | rt->rt6i_dst.plen = 128; | 1979 | rt->rt6i_dst.plen = 128; |
| 1966 | rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); | 1980 | rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); |
| 1967 | 1981 | ||
| 1968 | atomic_set(&rt->u.dst.__refcnt, 1); | 1982 | atomic_set(&rt->dst.__refcnt, 1); |
| 1969 | 1983 | ||
| 1970 | return rt; | 1984 | return rt; |
| 1971 | } | 1985 | } |
| @@ -2036,12 +2050,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
| 2036 | PMTU discouvery. | 2050 | PMTU discouvery. |
| 2037 | */ | 2051 | */ |
| 2038 | if (rt->rt6i_dev == arg->dev && | 2052 | if (rt->rt6i_dev == arg->dev && |
| 2039 | !dst_metric_locked(&rt->u.dst, RTAX_MTU) && | 2053 | !dst_metric_locked(&rt->dst, RTAX_MTU) && |
| 2040 | (dst_mtu(&rt->u.dst) >= arg->mtu || | 2054 | (dst_mtu(&rt->dst) >= arg->mtu || |
| 2041 | (dst_mtu(&rt->u.dst) < arg->mtu && | 2055 | (dst_mtu(&rt->dst) < arg->mtu && |
| 2042 | dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) { | 2056 | dst_mtu(&rt->dst) == idev->cnf.mtu6))) { |
| 2043 | rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu; | 2057 | rt->dst.metrics[RTAX_MTU-1] = arg->mtu; |
| 2044 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu); | 2058 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu); |
| 2045 | } | 2059 | } |
| 2046 | return 0; | 2060 | return 0; |
| 2047 | } | 2061 | } |
| @@ -2255,20 +2269,20 @@ static int rt6_fill_node(struct net *net, | |||
| 2255 | #endif | 2269 | #endif |
| 2256 | NLA_PUT_U32(skb, RTA_IIF, iif); | 2270 | NLA_PUT_U32(skb, RTA_IIF, iif); |
| 2257 | } else if (dst) { | 2271 | } else if (dst) { |
| 2258 | struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst); | 2272 | struct inet6_dev *idev = ip6_dst_idev(&rt->dst); |
| 2259 | struct in6_addr saddr_buf; | 2273 | struct in6_addr saddr_buf; |
| 2260 | if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, | 2274 | if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, |
| 2261 | dst, 0, &saddr_buf) == 0) | 2275 | dst, 0, &saddr_buf) == 0) |
| 2262 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2276 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
| 2263 | } | 2277 | } |
| 2264 | 2278 | ||
| 2265 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2279 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) |
| 2266 | goto nla_put_failure; | 2280 | goto nla_put_failure; |
| 2267 | 2281 | ||
| 2268 | if (rt->u.dst.neighbour) | 2282 | if (rt->dst.neighbour) |
| 2269 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); | 2283 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key); |
| 2270 | 2284 | ||
| 2271 | if (rt->u.dst.dev) | 2285 | if (rt->dst.dev) |
| 2272 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); | 2286 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
| 2273 | 2287 | ||
| 2274 | NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); | 2288 | NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); |
| @@ -2280,8 +2294,8 @@ static int rt6_fill_node(struct net *net, | |||
| 2280 | else | 2294 | else |
| 2281 | expires = INT_MAX; | 2295 | expires = INT_MAX; |
| 2282 | 2296 | ||
| 2283 | if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, | 2297 | if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, |
| 2284 | expires, rt->u.dst.error) < 0) | 2298 | expires, rt->dst.error) < 0) |
| 2285 | goto nla_put_failure; | 2299 | goto nla_put_failure; |
| 2286 | 2300 | ||
| 2287 | return nlmsg_end(skb, nlh); | 2301 | return nlmsg_end(skb, nlh); |
| @@ -2367,7 +2381,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
| 2367 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | 2381 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); |
| 2368 | 2382 | ||
| 2369 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); | 2383 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); |
| 2370 | skb_dst_set(skb, &rt->u.dst); | 2384 | skb_dst_set(skb, &rt->dst); |
| 2371 | 2385 | ||
| 2372 | err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, | 2386 | err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, |
| 2373 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2387 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
| @@ -2419,12 +2433,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
| 2419 | struct net *net = dev_net(dev); | 2433 | struct net *net = dev_net(dev); |
| 2420 | 2434 | ||
| 2421 | if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { | 2435 | if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { |
| 2422 | net->ipv6.ip6_null_entry->u.dst.dev = dev; | 2436 | net->ipv6.ip6_null_entry->dst.dev = dev; |
| 2423 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); | 2437 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); |
| 2424 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2438 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
| 2425 | net->ipv6.ip6_prohibit_entry->u.dst.dev = dev; | 2439 | net->ipv6.ip6_prohibit_entry->dst.dev = dev; |
| 2426 | net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); | 2440 | net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); |
| 2427 | net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev; | 2441 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; |
| 2428 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); | 2442 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); |
| 2429 | #endif | 2443 | #endif |
| 2430 | } | 2444 | } |
| @@ -2467,8 +2481,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
| 2467 | seq_puts(m, "00000000000000000000000000000000"); | 2481 | seq_puts(m, "00000000000000000000000000000000"); |
| 2468 | } | 2482 | } |
| 2469 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2483 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
| 2470 | rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt), | 2484 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
| 2471 | rt->u.dst.__use, rt->rt6i_flags, | 2485 | rt->dst.__use, rt->rt6i_flags, |
| 2472 | rt->rt6i_dev ? rt->rt6i_dev->name : ""); | 2486 | rt->rt6i_dev ? rt->rt6i_dev->name : ""); |
| 2473 | return 0; | 2487 | return 0; |
| 2474 | } | 2488 | } |
| @@ -2586,7 +2600,7 @@ ctl_table ipv6_route_table_template[] = { | |||
| 2586 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, | 2600 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, |
| 2587 | .maxlen = sizeof(int), | 2601 | .maxlen = sizeof(int), |
| 2588 | .mode = 0644, | 2602 | .mode = 0644, |
| 2589 | .proc_handler = proc_dointvec_jiffies, | 2603 | .proc_handler = proc_dointvec, |
| 2590 | }, | 2604 | }, |
| 2591 | { | 2605 | { |
| 2592 | .procname = "mtu_expires", | 2606 | .procname = "mtu_expires", |
| @@ -2600,7 +2614,7 @@ ctl_table ipv6_route_table_template[] = { | |||
| 2600 | .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, | 2614 | .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, |
| 2601 | .maxlen = sizeof(int), | 2615 | .maxlen = sizeof(int), |
| 2602 | .mode = 0644, | 2616 | .mode = 0644, |
| 2603 | .proc_handler = proc_dointvec_jiffies, | 2617 | .proc_handler = proc_dointvec, |
| 2604 | }, | 2618 | }, |
| 2605 | { | 2619 | { |
| 2606 | .procname = "gc_min_interval_ms", | 2620 | .procname = "gc_min_interval_ms", |
| @@ -2612,7 +2626,7 @@ ctl_table ipv6_route_table_template[] = { | |||
| 2612 | { } | 2626 | { } |
| 2613 | }; | 2627 | }; |
| 2614 | 2628 | ||
| 2615 | struct ctl_table *ipv6_route_sysctl_init(struct net *net) | 2629 | struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) |
| 2616 | { | 2630 | { |
| 2617 | struct ctl_table *table; | 2631 | struct ctl_table *table; |
| 2618 | 2632 | ||
| @@ -2637,7 +2651,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) | |||
| 2637 | } | 2651 | } |
| 2638 | #endif | 2652 | #endif |
| 2639 | 2653 | ||
| 2640 | static int ip6_route_net_init(struct net *net) | 2654 | static int __net_init ip6_route_net_init(struct net *net) |
| 2641 | { | 2655 | { |
| 2642 | int ret = -ENOMEM; | 2656 | int ret = -ENOMEM; |
| 2643 | 2657 | ||
| @@ -2649,9 +2663,9 @@ static int ip6_route_net_init(struct net *net) | |||
| 2649 | GFP_KERNEL); | 2663 | GFP_KERNEL); |
| 2650 | if (!net->ipv6.ip6_null_entry) | 2664 | if (!net->ipv6.ip6_null_entry) |
| 2651 | goto out_ip6_dst_ops; | 2665 | goto out_ip6_dst_ops; |
| 2652 | net->ipv6.ip6_null_entry->u.dst.path = | 2666 | net->ipv6.ip6_null_entry->dst.path = |
| 2653 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2667 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
| 2654 | net->ipv6.ip6_null_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; | 2668 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
| 2655 | 2669 | ||
| 2656 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2670 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
| 2657 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2671 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
| @@ -2659,18 +2673,18 @@ static int ip6_route_net_init(struct net *net) | |||
| 2659 | GFP_KERNEL); | 2673 | GFP_KERNEL); |
| 2660 | if (!net->ipv6.ip6_prohibit_entry) | 2674 | if (!net->ipv6.ip6_prohibit_entry) |
| 2661 | goto out_ip6_null_entry; | 2675 | goto out_ip6_null_entry; |
| 2662 | net->ipv6.ip6_prohibit_entry->u.dst.path = | 2676 | net->ipv6.ip6_prohibit_entry->dst.path = |
| 2663 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2677 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
| 2664 | net->ipv6.ip6_prohibit_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; | 2678 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
| 2665 | 2679 | ||
| 2666 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2680 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
| 2667 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2681 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
| 2668 | GFP_KERNEL); | 2682 | GFP_KERNEL); |
| 2669 | if (!net->ipv6.ip6_blk_hole_entry) | 2683 | if (!net->ipv6.ip6_blk_hole_entry) |
| 2670 | goto out_ip6_prohibit_entry; | 2684 | goto out_ip6_prohibit_entry; |
| 2671 | net->ipv6.ip6_blk_hole_entry->u.dst.path = | 2685 | net->ipv6.ip6_blk_hole_entry->dst.path = |
| 2672 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2686 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
| 2673 | net->ipv6.ip6_blk_hole_entry->u.dst.ops = &net->ipv6.ip6_dst_ops; | 2687 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
| 2674 | #endif | 2688 | #endif |
| 2675 | 2689 | ||
| 2676 | net->ipv6.sysctl.flush_delay = 0; | 2690 | net->ipv6.sysctl.flush_delay = 0; |
| @@ -2702,7 +2716,7 @@ out_ip6_dst_ops: | |||
| 2702 | goto out; | 2716 | goto out; |
| 2703 | } | 2717 | } |
| 2704 | 2718 | ||
| 2705 | static void ip6_route_net_exit(struct net *net) | 2719 | static void __net_exit ip6_route_net_exit(struct net *net) |
| 2706 | { | 2720 | { |
| 2707 | #ifdef CONFIG_PROC_FS | 2721 | #ifdef CONFIG_PROC_FS |
| 2708 | proc_net_remove(net, "ipv6_route"); | 2722 | proc_net_remove(net, "ipv6_route"); |
| @@ -2745,12 +2759,12 @@ int __init ip6_route_init(void) | |||
| 2745 | /* Registering of the loopback is done before this portion of code, | 2759 | /* Registering of the loopback is done before this portion of code, |
| 2746 | * the loopback reference in rt6_info will not be taken, do it | 2760 | * the loopback reference in rt6_info will not be taken, do it |
| 2747 | * manually for init_net */ | 2761 | * manually for init_net */ |
| 2748 | init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev; | 2762 | init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; |
| 2749 | init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | 2763 | init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); |
| 2750 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2764 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
| 2751 | init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev; | 2765 | init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; |
| 2752 | init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | 2766 | init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); |
| 2753 | init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev; | 2767 | init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; |
| 2754 | init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | 2768 | init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); |
| 2755 | #endif | 2769 | #endif |
| 2756 | ret = fib6_init(); | 2770 | ret = fib6_init(); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 976e68244b99..4699cd3c3118 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/netdevice.h> | 28 | #include <linux/netdevice.h> |
| 29 | #include <linux/if_arp.h> | 29 | #include <linux/if_arp.h> |
| 30 | #include <linux/icmp.h> | 30 | #include <linux/icmp.h> |
| 31 | #include <linux/slab.h> | ||
| 31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 33 | #include <linux/netfilter_ipv4.h> | 34 | #include <linux/netfilter_ipv4.h> |
| @@ -62,7 +63,6 @@ | |||
| 62 | #define HASH_SIZE 16 | 63 | #define HASH_SIZE 16 |
| 63 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
| 64 | 65 | ||
| 65 | static void ipip6_fb_tunnel_init(struct net_device *dev); | ||
| 66 | static void ipip6_tunnel_init(struct net_device *dev); | 66 | static void ipip6_tunnel_init(struct net_device *dev); |
| 67 | static void ipip6_tunnel_setup(struct net_device *dev); | 67 | static void ipip6_tunnel_setup(struct net_device *dev); |
| 68 | 68 | ||
| @@ -249,8 +249,6 @@ failed: | |||
| 249 | return NULL; | 249 | return NULL; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | static DEFINE_SPINLOCK(ipip6_prl_lock); | ||
| 253 | |||
| 254 | #define for_each_prl_rcu(start) \ | 252 | #define for_each_prl_rcu(start) \ |
| 255 | for (prl = rcu_dereference(start); \ | 253 | for (prl = rcu_dereference(start); \ |
| 256 | prl; \ | 254 | prl; \ |
| @@ -340,7 +338,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
| 340 | if (a->addr == htonl(INADDR_ANY)) | 338 | if (a->addr == htonl(INADDR_ANY)) |
| 341 | return -EINVAL; | 339 | return -EINVAL; |
| 342 | 340 | ||
| 343 | spin_lock(&ipip6_prl_lock); | 341 | ASSERT_RTNL(); |
| 344 | 342 | ||
| 345 | for (p = t->prl; p; p = p->next) { | 343 | for (p = t->prl; p; p = p->next) { |
| 346 | if (p->addr == a->addr) { | 344 | if (p->addr == a->addr) { |
| @@ -364,14 +362,12 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
| 364 | goto out; | 362 | goto out; |
| 365 | } | 363 | } |
| 366 | 364 | ||
| 367 | INIT_RCU_HEAD(&p->rcu_head); | ||
| 368 | p->next = t->prl; | 365 | p->next = t->prl; |
| 369 | p->addr = a->addr; | 366 | p->addr = a->addr; |
| 370 | p->flags = a->flags; | 367 | p->flags = a->flags; |
| 371 | t->prl_count++; | 368 | t->prl_count++; |
| 372 | rcu_assign_pointer(t->prl, p); | 369 | rcu_assign_pointer(t->prl, p); |
| 373 | out: | 370 | out: |
| 374 | spin_unlock(&ipip6_prl_lock); | ||
| 375 | return err; | 371 | return err; |
| 376 | } | 372 | } |
| 377 | 373 | ||
| @@ -398,7 +394,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
| 398 | struct ip_tunnel_prl_entry *x, **p; | 394 | struct ip_tunnel_prl_entry *x, **p; |
| 399 | int err = 0; | 395 | int err = 0; |
| 400 | 396 | ||
| 401 | spin_lock(&ipip6_prl_lock); | 397 | ASSERT_RTNL(); |
| 402 | 398 | ||
| 403 | if (a && a->addr != htonl(INADDR_ANY)) { | 399 | if (a && a->addr != htonl(INADDR_ANY)) { |
| 404 | for (p = &t->prl; *p; p = &(*p)->next) { | 400 | for (p = &t->prl; *p; p = &(*p)->next) { |
| @@ -420,7 +416,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
| 420 | } | 416 | } |
| 421 | } | 417 | } |
| 422 | out: | 418 | out: |
| 423 | spin_unlock(&ipip6_prl_lock); | ||
| 424 | return err; | 419 | return err; |
| 425 | } | 420 | } |
| 426 | 421 | ||
| @@ -567,11 +562,9 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 567 | kfree_skb(skb); | 562 | kfree_skb(skb); |
| 568 | return 0; | 563 | return 0; |
| 569 | } | 564 | } |
| 570 | tunnel->dev->stats.rx_packets++; | 565 | |
| 571 | tunnel->dev->stats.rx_bytes += skb->len; | 566 | skb_tunnel_rx(skb, tunnel->dev); |
| 572 | skb->dev = tunnel->dev; | 567 | |
| 573 | skb_dst_drop(skb); | ||
| 574 | nf_reset(skb); | ||
| 575 | ipip6_ecn_decapsulate(iph, skb); | 568 | ipip6_ecn_decapsulate(iph, skb); |
| 576 | netif_rx(skb); | 569 | netif_rx(skb); |
| 577 | rcu_read_unlock(); | 570 | rcu_read_unlock(); |
| @@ -719,7 +712,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 719 | stats->tx_carrier_errors++; | 712 | stats->tx_carrier_errors++; |
| 720 | goto tx_error_icmp; | 713 | goto tx_error_icmp; |
| 721 | } | 714 | } |
| 722 | tdev = rt->u.dst.dev; | 715 | tdev = rt->dst.dev; |
| 723 | 716 | ||
| 724 | if (tdev == dev) { | 717 | if (tdev == dev) { |
| 725 | ip_rt_put(rt); | 718 | ip_rt_put(rt); |
| @@ -728,7 +721,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 728 | } | 721 | } |
| 729 | 722 | ||
| 730 | if (df) { | 723 | if (df) { |
| 731 | mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); | 724 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); |
| 732 | 725 | ||
| 733 | if (mtu < 68) { | 726 | if (mtu < 68) { |
| 734 | stats->collisions++; | 727 | stats->collisions++; |
| @@ -745,7 +738,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 745 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); | 738 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); |
| 746 | 739 | ||
| 747 | if (skb->len > mtu) { | 740 | if (skb->len > mtu) { |
| 748 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 741 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 749 | ip_rt_put(rt); | 742 | ip_rt_put(rt); |
| 750 | goto tx_error; | 743 | goto tx_error; |
| 751 | } | 744 | } |
| @@ -787,7 +780,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
| 787 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 780 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
| 788 | IPCB(skb)->flags = 0; | 781 | IPCB(skb)->flags = 0; |
| 789 | skb_dst_drop(skb); | 782 | skb_dst_drop(skb); |
| 790 | skb_dst_set(skb, &rt->u.dst); | 783 | skb_dst_set(skb, &rt->dst); |
| 791 | 784 | ||
| 792 | /* | 785 | /* |
| 793 | * Push down and install the IPIP header. | 786 | * Push down and install the IPIP header. |
| @@ -836,7 +829,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
| 836 | .proto = IPPROTO_IPV6 }; | 829 | .proto = IPPROTO_IPV6 }; |
| 837 | struct rtable *rt; | 830 | struct rtable *rt; |
| 838 | if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 831 | if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { |
| 839 | tdev = rt->u.dst.dev; | 832 | tdev = rt->dst.dev; |
| 840 | ip_rt_put(rt); | 833 | ip_rt_put(rt); |
| 841 | } | 834 | } |
| 842 | dev->flags |= IFF_POINTOPOINT; | 835 | dev->flags |= IFF_POINTOPOINT; |
| @@ -1120,7 +1113,7 @@ static void ipip6_tunnel_init(struct net_device *dev) | |||
| 1120 | ipip6_tunnel_bind_dev(dev); | 1113 | ipip6_tunnel_bind_dev(dev); |
| 1121 | } | 1114 | } |
| 1122 | 1115 | ||
| 1123 | static void ipip6_fb_tunnel_init(struct net_device *dev) | 1116 | static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) |
| 1124 | { | 1117 | { |
| 1125 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1118 | struct ip_tunnel *tunnel = netdev_priv(dev); |
| 1126 | struct iphdr *iph = &tunnel->parms.iph; | 1119 | struct iphdr *iph = &tunnel->parms.iph; |
| @@ -1145,7 +1138,7 @@ static struct xfrm_tunnel sit_handler = { | |||
| 1145 | .priority = 1, | 1138 | .priority = 1, |
| 1146 | }; | 1139 | }; |
| 1147 | 1140 | ||
| 1148 | static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) | 1141 | static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) |
| 1149 | { | 1142 | { |
| 1150 | int prio; | 1143 | int prio; |
| 1151 | 1144 | ||
| @@ -1162,7 +1155,7 @@ static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) | |||
| 1162 | } | 1155 | } |
| 1163 | } | 1156 | } |
| 1164 | 1157 | ||
| 1165 | static int sit_init_net(struct net *net) | 1158 | static int __net_init sit_init_net(struct net *net) |
| 1166 | { | 1159 | { |
| 1167 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1160 | struct sit_net *sitn = net_generic(net, sit_net_id); |
| 1168 | int err; | 1161 | int err; |
| @@ -1195,7 +1188,7 @@ err_alloc_dev: | |||
| 1195 | return err; | 1188 | return err; |
| 1196 | } | 1189 | } |
| 1197 | 1190 | ||
| 1198 | static void sit_exit_net(struct net *net) | 1191 | static void __net_exit sit_exit_net(struct net *net) |
| 1199 | { | 1192 | { |
| 1200 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1193 | struct sit_net *sitn = net_generic(net, sit_net_id); |
| 1201 | LIST_HEAD(list); | 1194 | LIST_HEAD(list); |
| @@ -1228,15 +1221,14 @@ static int __init sit_init(void) | |||
| 1228 | 1221 | ||
| 1229 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); | 1222 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); |
| 1230 | 1223 | ||
| 1231 | if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) { | ||
| 1232 | printk(KERN_INFO "sit init: Can't add protocol\n"); | ||
| 1233 | return -EAGAIN; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | err = register_pernet_device(&sit_net_ops); | 1224 | err = register_pernet_device(&sit_net_ops); |
| 1237 | if (err < 0) | 1225 | if (err < 0) |
| 1238 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | 1226 | return err; |
| 1239 | 1227 | err = xfrm4_tunnel_register(&sit_handler, AF_INET6); | |
| 1228 | if (err < 0) { | ||
| 1229 | unregister_pernet_device(&sit_net_ops); | ||
| 1230 | printk(KERN_INFO "sit init: Can't add protocol\n"); | ||
| 1231 | } | ||
| 1240 | return err; | 1232 | return err; |
| 1241 | } | 1233 | } |
| 1242 | 1234 | ||
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 7208a06576c6..09fd34f0dbf2 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
| @@ -27,28 +27,17 @@ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; | |||
| 27 | #define COOKIEBITS 24 /* Upper bits store count */ | 27 | #define COOKIEBITS 24 /* Upper bits store count */ |
| 28 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 28 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
| 29 | 29 | ||
| 30 | /* | 30 | /* Table must be sorted. */ |
| 31 | * This table has to be sorted and terminated with (__u16)-1. | ||
| 32 | * XXX generate a better table. | ||
| 33 | * Unresolved Issues: HIPPI with a 64k MSS is not well supported. | ||
| 34 | * | ||
| 35 | * Taken directly from ipv4 implementation. | ||
| 36 | * Should this list be modified for ipv6 use or is it close enough? | ||
| 37 | * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart | ||
| 38 | */ | ||
| 39 | static __u16 const msstab[] = { | 31 | static __u16 const msstab[] = { |
| 40 | 64 - 1, | 32 | 64, |
| 41 | 256 - 1, | 33 | 512, |
| 42 | 512 - 1, | 34 | 536, |
| 43 | 536 - 1, | 35 | 1280 - 60, |
| 44 | 1024 - 1, | 36 | 1480 - 60, |
| 45 | 1440 - 1, | 37 | 1500 - 60, |
| 46 | 1460 - 1, | 38 | 4460 - 60, |
| 47 | 4312 - 1, | 39 | 9000 - 60, |
| 48 | (__u16)-1 | ||
| 49 | }; | 40 | }; |
| 50 | /* The number doesn't include the -1 terminator */ | ||
| 51 | #define NUM_MSS (ARRAY_SIZE(msstab) - 1) | ||
| 52 | 41 | ||
| 53 | /* | 42 | /* |
| 54 | * This (misnamed) value is the age of syncookie which is permitted. | 43 | * This (misnamed) value is the age of syncookie which is permitted. |
| @@ -134,9 +123,11 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) | |||
| 134 | 123 | ||
| 135 | tcp_synq_overflow(sk); | 124 | tcp_synq_overflow(sk); |
| 136 | 125 | ||
| 137 | for (mssind = 0; mss > msstab[mssind + 1]; mssind++) | 126 | for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--) |
| 138 | ; | 127 | if (mss >= msstab[mssind]) |
| 139 | *mssp = msstab[mssind] + 1; | 128 | break; |
| 129 | |||
| 130 | *mssp = msstab[mssind]; | ||
| 140 | 131 | ||
| 141 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); | 132 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); |
| 142 | 133 | ||
| @@ -154,7 +145,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie) | |||
| 154 | th->source, th->dest, seq, | 145 | th->source, th->dest, seq, |
| 155 | jiffies / (HZ * 60), COUNTER_TRIES); | 146 | jiffies / (HZ * 60), COUNTER_TRIES); |
| 156 | 147 | ||
| 157 | return mssind < NUM_MSS ? msstab[mssind] + 1 : 0; | 148 | return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; |
| 158 | } | 149 | } |
| 159 | 150 | ||
| 160 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | 151 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) |
| @@ -173,8 +164,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 173 | int mss; | 164 | int mss; |
| 174 | struct dst_entry *dst; | 165 | struct dst_entry *dst; |
| 175 | __u8 rcv_wscale; | 166 | __u8 rcv_wscale; |
| 167 | bool ecn_ok; | ||
| 176 | 168 | ||
| 177 | if (!sysctl_tcp_syncookies || !th->ack) | 169 | if (!sysctl_tcp_syncookies || !th->ack || th->rst) |
| 178 | goto out; | 170 | goto out; |
| 179 | 171 | ||
| 180 | if (tcp_synq_no_recent_overflow(sk) || | 172 | if (tcp_synq_no_recent_overflow(sk) || |
| @@ -189,8 +181,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 189 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 181 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
| 190 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0); | 182 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0); |
| 191 | 183 | ||
| 192 | if (tcp_opt.saw_tstamp) | 184 | if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) |
| 193 | cookie_check_timestamp(&tcp_opt); | 185 | goto out; |
| 194 | 186 | ||
| 195 | ret = NULL; | 187 | ret = NULL; |
| 196 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); | 188 | req = inet6_reqsk_alloc(&tcp6_request_sock_ops); |
| @@ -224,9 +216,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 224 | 216 | ||
| 225 | req->expires = 0UL; | 217 | req->expires = 0UL; |
| 226 | req->retrans = 0; | 218 | req->retrans = 0; |
| 227 | ireq->ecn_ok = 0; | 219 | ireq->ecn_ok = ecn_ok; |
| 228 | ireq->snd_wscale = tcp_opt.snd_wscale; | 220 | ireq->snd_wscale = tcp_opt.snd_wscale; |
| 229 | ireq->rcv_wscale = tcp_opt.rcv_wscale; | ||
| 230 | ireq->sack_ok = tcp_opt.sack_ok; | 221 | ireq->sack_ok = tcp_opt.sack_ok; |
| 231 | ireq->wscale_ok = tcp_opt.wscale_ok; | 222 | ireq->wscale_ok = tcp_opt.wscale_ok; |
| 232 | ireq->tstamp_ok = tcp_opt.saw_tstamp; | 223 | ireq->tstamp_ok = tcp_opt.saw_tstamp; |
| @@ -240,17 +231,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 240 | * me if there is a preferred way. | 231 | * me if there is a preferred way. |
| 241 | */ | 232 | */ |
| 242 | { | 233 | { |
| 243 | struct in6_addr *final_p = NULL, final; | 234 | struct in6_addr *final_p, final; |
| 244 | struct flowi fl; | 235 | struct flowi fl; |
| 245 | memset(&fl, 0, sizeof(fl)); | 236 | memset(&fl, 0, sizeof(fl)); |
| 246 | fl.proto = IPPROTO_TCP; | 237 | fl.proto = IPPROTO_TCP; |
| 247 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); | 238 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); |
| 248 | if (np->opt && np->opt->srcrt) { | 239 | final_p = fl6_update_dst(&fl, np->opt, &final); |
| 249 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | ||
| 250 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 251 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 252 | final_p = &final; | ||
| 253 | } | ||
| 254 | ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); | 240 | ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); |
| 255 | fl.oif = sk->sk_bound_dev_if; | 241 | fl.oif = sk->sk_bound_dev_if; |
| 256 | fl.mark = sk->sk_mark; | 242 | fl.mark = sk->sk_mark; |
| @@ -269,7 +255,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
| 269 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); | 255 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); |
| 270 | tcp_select_initial_window(tcp_full_space(sk), req->mss, | 256 | tcp_select_initial_window(tcp_full_space(sk), req->mss, |
| 271 | &req->rcv_wnd, &req->window_clamp, | 257 | &req->rcv_wnd, &req->window_clamp, |
| 272 | ireq->wscale_ok, &rcv_wscale); | 258 | ireq->wscale_ok, &rcv_wscale, |
| 259 | dst_metric(dst, RTAX_INITRWND)); | ||
| 273 | 260 | ||
| 274 | ireq->rcv_wscale = rcv_wscale; | 261 | ireq->rcv_wscale = rcv_wscale; |
| 275 | 262 | ||
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index c690736885b4..fa1d8f4e0051 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/sysctl.h> | 9 | #include <linux/sysctl.h> |
| 10 | #include <linux/in6.h> | 10 | #include <linux/in6.h> |
| 11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
| 12 | #include <linux/slab.h> | ||
| 12 | #include <net/ndisc.h> | 13 | #include <net/ndisc.h> |
| 13 | #include <net/ipv6.h> | 14 | #include <net/ipv6.h> |
| 14 | #include <net/addrconf.h> | 15 | #include <net/addrconf.h> |
| @@ -55,7 +56,7 @@ struct ctl_path net_ipv6_ctl_path[] = { | |||
| 55 | }; | 56 | }; |
| 56 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); | 57 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); |
| 57 | 58 | ||
| 58 | static int ipv6_sysctl_net_init(struct net *net) | 59 | static int __net_init ipv6_sysctl_net_init(struct net *net) |
| 59 | { | 60 | { |
| 60 | struct ctl_table *ipv6_table; | 61 | struct ctl_table *ipv6_table; |
| 61 | struct ctl_table *ipv6_route_table; | 62 | struct ctl_table *ipv6_route_table; |
| @@ -98,7 +99,7 @@ out_ipv6_table: | |||
| 98 | goto out; | 99 | goto out; |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | static void ipv6_sysctl_net_exit(struct net *net) | 102 | static void __net_exit ipv6_sysctl_net_exit(struct net *net) |
| 102 | { | 103 | { |
| 103 | struct ctl_table *ipv6_table; | 104 | struct ctl_table *ipv6_table; |
| 104 | struct ctl_table *ipv6_route_table; | 105 | struct ctl_table *ipv6_route_table; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index febfd595a40d..fe6d40418c0b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/jhash.h> | 38 | #include <linux/jhash.h> |
| 39 | #include <linux/ipsec.h> | 39 | #include <linux/ipsec.h> |
| 40 | #include <linux/times.h> | 40 | #include <linux/times.h> |
| 41 | #include <linux/slab.h> | ||
| 41 | 42 | ||
| 42 | #include <linux/ipv6.h> | 43 | #include <linux/ipv6.h> |
| 43 | #include <linux/icmpv6.h> | 44 | #include <linux/icmpv6.h> |
| @@ -74,6 +75,9 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 74 | struct request_sock *req); | 75 | struct request_sock *req); |
| 75 | 76 | ||
| 76 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 77 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
| 78 | static void __tcp_v6_send_check(struct sk_buff *skb, | ||
| 79 | struct in6_addr *saddr, | ||
| 80 | struct in6_addr *daddr); | ||
| 77 | 81 | ||
| 78 | static const struct inet_connection_sock_af_ops ipv6_mapped; | 82 | static const struct inet_connection_sock_af_ops ipv6_mapped; |
| 79 | static const struct inet_connection_sock_af_ops ipv6_specific; | 83 | static const struct inet_connection_sock_af_ops ipv6_specific; |
| @@ -125,7 +129,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 125 | struct inet_connection_sock *icsk = inet_csk(sk); | 129 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 126 | struct ipv6_pinfo *np = inet6_sk(sk); | 130 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 127 | struct tcp_sock *tp = tcp_sk(sk); | 131 | struct tcp_sock *tp = tcp_sk(sk); |
| 128 | struct in6_addr *saddr = NULL, *final_p = NULL, final; | 132 | struct in6_addr *saddr = NULL, *final_p, final; |
| 129 | struct flowi fl; | 133 | struct flowi fl; |
| 130 | struct dst_entry *dst; | 134 | struct dst_entry *dst; |
| 131 | int addr_type; | 135 | int addr_type; |
| @@ -246,12 +250,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 246 | fl.fl_ip_dport = usin->sin6_port; | 250 | fl.fl_ip_dport = usin->sin6_port; |
| 247 | fl.fl_ip_sport = inet->inet_sport; | 251 | fl.fl_ip_sport = inet->inet_sport; |
| 248 | 252 | ||
| 249 | if (np->opt && np->opt->srcrt) { | 253 | final_p = fl6_update_dst(&fl, np->opt, &final); |
| 250 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | ||
| 251 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 252 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 253 | final_p = &final; | ||
| 254 | } | ||
| 255 | 254 | ||
| 256 | security_sk_classify_flow(sk, &fl); | 255 | security_sk_classify_flow(sk, &fl); |
| 257 | 256 | ||
| @@ -349,6 +348,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 349 | if (sk->sk_state == TCP_CLOSE) | 348 | if (sk->sk_state == TCP_CLOSE) |
| 350 | goto out; | 349 | goto out; |
| 351 | 350 | ||
| 351 | if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
| 352 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
| 353 | goto out; | ||
| 354 | } | ||
| 355 | |||
| 352 | tp = tcp_sk(sk); | 356 | tp = tcp_sk(sk); |
| 353 | seq = ntohl(th->seq); | 357 | seq = ntohl(th->seq); |
| 354 | if (sk->sk_state != TCP_LISTEN && | 358 | if (sk->sk_state != TCP_LISTEN && |
| @@ -468,7 +472,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 468 | struct ipv6_pinfo *np = inet6_sk(sk); | 472 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 469 | struct sk_buff * skb; | 473 | struct sk_buff * skb; |
| 470 | struct ipv6_txoptions *opt = NULL; | 474 | struct ipv6_txoptions *opt = NULL; |
| 471 | struct in6_addr * final_p = NULL, final; | 475 | struct in6_addr * final_p, final; |
| 472 | struct flowi fl; | 476 | struct flowi fl; |
| 473 | struct dst_entry *dst; | 477 | struct dst_entry *dst; |
| 474 | int err = -1; | 478 | int err = -1; |
| @@ -485,12 +489,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 485 | security_req_classify_flow(req, &fl); | 489 | security_req_classify_flow(req, &fl); |
| 486 | 490 | ||
| 487 | opt = np->opt; | 491 | opt = np->opt; |
| 488 | if (opt && opt->srcrt) { | 492 | final_p = fl6_update_dst(&fl, opt, &final); |
| 489 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 490 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 491 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 492 | final_p = &final; | ||
| 493 | } | ||
| 494 | 493 | ||
| 495 | err = ip6_dst_lookup(sk, &dst, &fl); | 494 | err = ip6_dst_lookup(sk, &dst, &fl); |
| 496 | if (err) | 495 | if (err) |
| @@ -502,14 +501,10 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
| 502 | 501 | ||
| 503 | skb = tcp_make_synack(sk, dst, req, rvp); | 502 | skb = tcp_make_synack(sk, dst, req, rvp); |
| 504 | if (skb) { | 503 | if (skb) { |
| 505 | struct tcphdr *th = tcp_hdr(skb); | 504 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
| 506 | |||
| 507 | th->check = tcp_v6_check(skb->len, | ||
| 508 | &treq->loc_addr, &treq->rmt_addr, | ||
| 509 | csum_partial(th, skb->len, skb->csum)); | ||
| 510 | 505 | ||
| 511 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 506 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
| 512 | err = ip6_xmit(sk, skb, &fl, opt, 0); | 507 | err = ip6_xmit(sk, skb, &fl, opt); |
| 513 | err = net_xmit_eval(err); | 508 | err = net_xmit_eval(err); |
| 514 | } | 509 | } |
| 515 | 510 | ||
| @@ -520,6 +515,13 @@ done: | |||
| 520 | return err; | 515 | return err; |
| 521 | } | 516 | } |
| 522 | 517 | ||
| 518 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | ||
| 519 | struct request_values *rvp) | ||
| 520 | { | ||
| 521 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
| 522 | return tcp_v6_send_synack(sk, req, rvp); | ||
| 523 | } | ||
| 524 | |||
| 523 | static inline void syn_flood_warning(struct sk_buff *skb) | 525 | static inline void syn_flood_warning(struct sk_buff *skb) |
| 524 | { | 526 | { |
| 525 | #ifdef CONFIG_SYN_COOKIES | 527 | #ifdef CONFIG_SYN_COOKIES |
| @@ -592,7 +594,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, | |||
| 592 | kfree(newkey); | 594 | kfree(newkey); |
| 593 | return -ENOMEM; | 595 | return -ENOMEM; |
| 594 | } | 596 | } |
| 595 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | 597 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); |
| 596 | } | 598 | } |
| 597 | if (tcp_alloc_md5sig_pool(sk) == NULL) { | 599 | if (tcp_alloc_md5sig_pool(sk) == NULL) { |
| 598 | kfree(newkey); | 600 | kfree(newkey); |
| @@ -729,7 +731,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
| 729 | return -ENOMEM; | 731 | return -ENOMEM; |
| 730 | 732 | ||
| 731 | tp->md5sig_info = p; | 733 | tp->md5sig_info = p; |
| 732 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; | 734 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); |
| 733 | } | 735 | } |
| 734 | 736 | ||
| 735 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); | 737 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); |
| @@ -876,7 +878,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
| 876 | 878 | ||
| 877 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 879 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 878 | if (net_ratelimit()) { | 880 | if (net_ratelimit()) { |
| 879 | printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", | 881 | printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", |
| 880 | genhash ? "failed" : "mismatch", | 882 | genhash ? "failed" : "mismatch", |
| 881 | &ip6h->saddr, ntohs(th->source), | 883 | &ip6h->saddr, ntohs(th->source), |
| 882 | &ip6h->daddr, ntohs(th->dest)); | 884 | &ip6h->daddr, ntohs(th->dest)); |
| @@ -890,10 +892,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
| 890 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { | 892 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { |
| 891 | .family = AF_INET6, | 893 | .family = AF_INET6, |
| 892 | .obj_size = sizeof(struct tcp6_request_sock), | 894 | .obj_size = sizeof(struct tcp6_request_sock), |
| 893 | .rtx_syn_ack = tcp_v6_send_synack, | 895 | .rtx_syn_ack = tcp_v6_rtx_synack, |
| 894 | .send_ack = tcp_v6_reqsk_send_ack, | 896 | .send_ack = tcp_v6_reqsk_send_ack, |
| 895 | .destructor = tcp_v6_reqsk_destructor, | 897 | .destructor = tcp_v6_reqsk_destructor, |
| 896 | .send_reset = tcp_v6_send_reset | 898 | .send_reset = tcp_v6_send_reset, |
| 899 | .syn_ack_timeout = tcp_syn_ack_timeout, | ||
| 897 | }; | 900 | }; |
| 898 | 901 | ||
| 899 | #ifdef CONFIG_TCP_MD5SIG | 902 | #ifdef CONFIG_TCP_MD5SIG |
| @@ -909,22 +912,29 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |||
| 909 | .twsk_destructor= tcp_twsk_destructor, | 912 | .twsk_destructor= tcp_twsk_destructor, |
| 910 | }; | 913 | }; |
| 911 | 914 | ||
| 912 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 915 | static void __tcp_v6_send_check(struct sk_buff *skb, |
| 916 | struct in6_addr *saddr, struct in6_addr *daddr) | ||
| 913 | { | 917 | { |
| 914 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 915 | struct tcphdr *th = tcp_hdr(skb); | 918 | struct tcphdr *th = tcp_hdr(skb); |
| 916 | 919 | ||
| 917 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 920 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 918 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 921 | th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); |
| 919 | skb->csum_start = skb_transport_header(skb) - skb->head; | 922 | skb->csum_start = skb_transport_header(skb) - skb->head; |
| 920 | skb->csum_offset = offsetof(struct tcphdr, check); | 923 | skb->csum_offset = offsetof(struct tcphdr, check); |
| 921 | } else { | 924 | } else { |
| 922 | th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, | 925 | th->check = tcp_v6_check(skb->len, saddr, daddr, |
| 923 | csum_partial(th, th->doff<<2, | 926 | csum_partial(th, th->doff << 2, |
| 924 | skb->csum)); | 927 | skb->csum)); |
| 925 | } | 928 | } |
| 926 | } | 929 | } |
| 927 | 930 | ||
| 931 | static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) | ||
| 932 | { | ||
| 933 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 934 | |||
| 935 | __tcp_v6_send_check(skb, &np->saddr, &np->daddr); | ||
| 936 | } | ||
| 937 | |||
| 928 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | 938 | static int tcp_v6_gso_send_check(struct sk_buff *skb) |
| 929 | { | 939 | { |
| 930 | struct ipv6hdr *ipv6h; | 940 | struct ipv6hdr *ipv6h; |
| @@ -937,11 +947,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
| 937 | th = tcp_hdr(skb); | 947 | th = tcp_hdr(skb); |
| 938 | 948 | ||
| 939 | th->check = 0; | 949 | th->check = 0; |
| 940 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
| 941 | IPPROTO_TCP, 0); | ||
| 942 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
| 943 | skb->csum_offset = offsetof(struct tcphdr, check); | ||
| 944 | skb->ip_summed = CHECKSUM_PARTIAL; | 950 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 951 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
| 945 | return 0; | 952 | return 0; |
| 946 | } | 953 | } |
| 947 | 954 | ||
| @@ -1006,7 +1013,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1006 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); | 1013 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); |
| 1007 | 1014 | ||
| 1008 | t1 = (struct tcphdr *) skb_push(buff, tot_len); | 1015 | t1 = (struct tcphdr *) skb_push(buff, tot_len); |
| 1009 | skb_reset_transport_header(skb); | 1016 | skb_reset_transport_header(buff); |
| 1010 | 1017 | ||
| 1011 | /* Swap the send and the receive. */ | 1018 | /* Swap the send and the receive. */ |
| 1012 | memset(t1, 0, sizeof(*t1)); | 1019 | memset(t1, 0, sizeof(*t1)); |
| @@ -1038,15 +1045,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1038 | } | 1045 | } |
| 1039 | #endif | 1046 | #endif |
| 1040 | 1047 | ||
| 1041 | buff->csum = csum_partial(t1, tot_len, 0); | ||
| 1042 | |||
| 1043 | memset(&fl, 0, sizeof(fl)); | 1048 | memset(&fl, 0, sizeof(fl)); |
| 1044 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1049 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); |
| 1045 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1050 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); |
| 1046 | 1051 | ||
| 1047 | t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | 1052 | buff->ip_summed = CHECKSUM_PARTIAL; |
| 1048 | tot_len, IPPROTO_TCP, | 1053 | buff->csum = 0; |
| 1049 | buff->csum); | 1054 | |
| 1055 | __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst); | ||
| 1050 | 1056 | ||
| 1051 | fl.proto = IPPROTO_TCP; | 1057 | fl.proto = IPPROTO_TCP; |
| 1052 | fl.oif = inet6_iif(skb); | 1058 | fl.oif = inet6_iif(skb); |
| @@ -1061,7 +1067,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
| 1061 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { | 1067 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { |
| 1062 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { | 1068 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { |
| 1063 | skb_dst_set(buff, dst); | 1069 | skb_dst_set(buff, dst); |
| 1064 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); | 1070 | ip6_xmit(ctl_sk, buff, &fl, NULL); |
| 1065 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 1071 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
| 1066 | if (rst) | 1072 | if (rst) |
| 1067 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 1073 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); |
| @@ -1151,7 +1157,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
| 1151 | } | 1157 | } |
| 1152 | 1158 | ||
| 1153 | #ifdef CONFIG_SYN_COOKIES | 1159 | #ifdef CONFIG_SYN_COOKIES |
| 1154 | if (!th->rst && !th->syn && th->ack) | 1160 | if (!th->syn) |
| 1155 | sk = cookie_v6_check(sk, skb); | 1161 | sk = cookie_v6_check(sk, skb); |
| 1156 | #endif | 1162 | #endif |
| 1157 | return sk; | 1163 | return sk; |
| @@ -1224,12 +1230,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1224 | goto drop_and_free; | 1230 | goto drop_and_free; |
| 1225 | 1231 | ||
| 1226 | /* Secret recipe starts with IP addresses */ | 1232 | /* Secret recipe starts with IP addresses */ |
| 1227 | d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | 1233 | d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0]; |
| 1228 | *mess++ ^= *d++; | 1234 | *mess++ ^= *d++; |
| 1229 | *mess++ ^= *d++; | 1235 | *mess++ ^= *d++; |
| 1230 | *mess++ ^= *d++; | 1236 | *mess++ ^= *d++; |
| 1231 | *mess++ ^= *d++; | 1237 | *mess++ ^= *d++; |
| 1232 | d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | 1238 | d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0]; |
| 1233 | *mess++ ^= *d++; | 1239 | *mess++ ^= *d++; |
| 1234 | *mess++ ^= *d++; | 1240 | *mess++ ^= *d++; |
| 1235 | *mess++ ^= *d++; | 1241 | *mess++ ^= *d++; |
| @@ -1263,13 +1269,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1263 | treq = inet6_rsk(req); | 1269 | treq = inet6_rsk(req); |
| 1264 | ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); | 1270 | ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); |
| 1265 | ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); | 1271 | ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); |
| 1266 | if (!want_cookie) | 1272 | if (!want_cookie || tmp_opt.tstamp_ok) |
| 1267 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1273 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
| 1268 | 1274 | ||
| 1269 | if (want_cookie) { | 1275 | if (!isn) { |
| 1270 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | ||
| 1271 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1272 | } else if (!isn) { | ||
| 1273 | if (ipv6_opt_accepted(sk, skb) || | 1276 | if (ipv6_opt_accepted(sk, skb) || |
| 1274 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1277 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
| 1275 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1278 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
| @@ -1282,8 +1285,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1282 | if (!sk->sk_bound_dev_if && | 1285 | if (!sk->sk_bound_dev_if && |
| 1283 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1286 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
| 1284 | treq->iif = inet6_iif(skb); | 1287 | treq->iif = inet6_iif(skb); |
| 1285 | 1288 | if (!want_cookie) { | |
| 1286 | isn = tcp_v6_init_sequence(skb); | 1289 | isn = tcp_v6_init_sequence(skb); |
| 1290 | } else { | ||
| 1291 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | ||
| 1292 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
| 1293 | } | ||
| 1287 | } | 1294 | } |
| 1288 | tcp_rsk(req)->snt_isn = isn; | 1295 | tcp_rsk(req)->snt_isn = isn; |
| 1289 | 1296 | ||
| @@ -1376,18 +1383,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1376 | goto out_overflow; | 1383 | goto out_overflow; |
| 1377 | 1384 | ||
| 1378 | if (dst == NULL) { | 1385 | if (dst == NULL) { |
| 1379 | struct in6_addr *final_p = NULL, final; | 1386 | struct in6_addr *final_p, final; |
| 1380 | struct flowi fl; | 1387 | struct flowi fl; |
| 1381 | 1388 | ||
| 1382 | memset(&fl, 0, sizeof(fl)); | 1389 | memset(&fl, 0, sizeof(fl)); |
| 1383 | fl.proto = IPPROTO_TCP; | 1390 | fl.proto = IPPROTO_TCP; |
| 1384 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 1391 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); |
| 1385 | if (opt && opt->srcrt) { | 1392 | final_p = fl6_update_dst(&fl, opt, &final); |
| 1386 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 1387 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 1388 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 1389 | final_p = &final; | ||
| 1390 | } | ||
| 1391 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | 1393 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); |
| 1392 | fl.oif = sk->sk_bound_dev_if; | 1394 | fl.oif = sk->sk_bound_dev_if; |
| 1393 | fl.mark = sk->sk_mark; | 1395 | fl.mark = sk->sk_mark; |
| @@ -1667,6 +1669,7 @@ ipv6_pktoptions: | |||
| 1667 | static int tcp_v6_rcv(struct sk_buff *skb) | 1669 | static int tcp_v6_rcv(struct sk_buff *skb) |
| 1668 | { | 1670 | { |
| 1669 | struct tcphdr *th; | 1671 | struct tcphdr *th; |
| 1672 | struct ipv6hdr *hdr; | ||
| 1670 | struct sock *sk; | 1673 | struct sock *sk; |
| 1671 | int ret; | 1674 | int ret; |
| 1672 | struct net *net = dev_net(skb->dev); | 1675 | struct net *net = dev_net(skb->dev); |
| @@ -1693,12 +1696,13 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
| 1693 | goto bad_packet; | 1696 | goto bad_packet; |
| 1694 | 1697 | ||
| 1695 | th = tcp_hdr(skb); | 1698 | th = tcp_hdr(skb); |
| 1699 | hdr = ipv6_hdr(skb); | ||
| 1696 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | 1700 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); |
| 1697 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | 1701 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + |
| 1698 | skb->len - th->doff*4); | 1702 | skb->len - th->doff*4); |
| 1699 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | 1703 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); |
| 1700 | TCP_SKB_CB(skb)->when = 0; | 1704 | TCP_SKB_CB(skb)->when = 0; |
| 1701 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); | 1705 | TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr); |
| 1702 | TCP_SKB_CB(skb)->sacked = 0; | 1706 | TCP_SKB_CB(skb)->sacked = 0; |
| 1703 | 1707 | ||
| 1704 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); | 1708 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); |
| @@ -1709,6 +1713,11 @@ process: | |||
| 1709 | if (sk->sk_state == TCP_TIME_WAIT) | 1713 | if (sk->sk_state == TCP_TIME_WAIT) |
| 1710 | goto do_time_wait; | 1714 | goto do_time_wait; |
| 1711 | 1715 | ||
| 1716 | if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { | ||
| 1717 | NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP); | ||
| 1718 | goto discard_and_relse; | ||
| 1719 | } | ||
| 1720 | |||
| 1712 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1721 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
| 1713 | goto discard_and_relse; | 1722 | goto discard_and_relse; |
| 1714 | 1723 | ||
| @@ -1732,8 +1741,11 @@ process: | |||
| 1732 | if (!tcp_prequeue(sk, skb)) | 1741 | if (!tcp_prequeue(sk, skb)) |
| 1733 | ret = tcp_v6_do_rcv(sk, skb); | 1742 | ret = tcp_v6_do_rcv(sk, skb); |
| 1734 | } | 1743 | } |
| 1735 | } else | 1744 | } else if (unlikely(sk_add_backlog(sk, skb))) { |
| 1736 | sk_add_backlog(sk, skb); | 1745 | bh_unlock_sock(sk); |
| 1746 | NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP); | ||
| 1747 | goto discard_and_relse; | ||
| 1748 | } | ||
| 1737 | bh_unlock_sock(sk); | 1749 | bh_unlock_sock(sk); |
| 1738 | 1750 | ||
| 1739 | sock_put(sk); | 1751 | sock_put(sk); |
| @@ -2105,7 +2117,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { | |||
| 2105 | }, | 2117 | }, |
| 2106 | }; | 2118 | }; |
| 2107 | 2119 | ||
| 2108 | int tcp6_proc_init(struct net *net) | 2120 | int __net_init tcp6_proc_init(struct net *net) |
| 2109 | { | 2121 | { |
| 2110 | return tcp_proc_register(net, &tcp6_seq_afinfo); | 2122 | return tcp_proc_register(net, &tcp6_seq_afinfo); |
| 2111 | } | 2123 | } |
| @@ -2130,6 +2142,8 @@ struct proto tcpv6_prot = { | |||
| 2130 | .setsockopt = tcp_setsockopt, | 2142 | .setsockopt = tcp_setsockopt, |
| 2131 | .getsockopt = tcp_getsockopt, | 2143 | .getsockopt = tcp_getsockopt, |
| 2132 | .recvmsg = tcp_recvmsg, | 2144 | .recvmsg = tcp_recvmsg, |
| 2145 | .sendmsg = tcp_sendmsg, | ||
| 2146 | .sendpage = tcp_sendpage, | ||
| 2133 | .backlog_rcv = tcp_v6_do_rcv, | 2147 | .backlog_rcv = tcp_v6_do_rcv, |
| 2134 | .hash = tcp_v6_hash, | 2148 | .hash = tcp_v6_hash, |
| 2135 | .unhash = inet_unhash, | 2149 | .unhash = inet_unhash, |
| @@ -2148,6 +2162,7 @@ struct proto tcpv6_prot = { | |||
| 2148 | .twsk_prot = &tcp6_timewait_sock_ops, | 2162 | .twsk_prot = &tcp6_timewait_sock_ops, |
| 2149 | .rsk_prot = &tcp6_request_sock_ops, | 2163 | .rsk_prot = &tcp6_request_sock_ops, |
| 2150 | .h.hashinfo = &tcp_hashinfo, | 2164 | .h.hashinfo = &tcp_hashinfo, |
| 2165 | .no_autobind = true, | ||
| 2151 | #ifdef CONFIG_COMPAT | 2166 | #ifdef CONFIG_COMPAT |
| 2152 | .compat_setsockopt = compat_tcp_setsockopt, | 2167 | .compat_setsockopt = compat_tcp_setsockopt, |
| 2153 | .compat_getsockopt = compat_tcp_getsockopt, | 2168 | .compat_getsockopt = compat_tcp_getsockopt, |
| @@ -2174,18 +2189,18 @@ static struct inet_protosw tcpv6_protosw = { | |||
| 2174 | INET_PROTOSW_ICSK, | 2189 | INET_PROTOSW_ICSK, |
| 2175 | }; | 2190 | }; |
| 2176 | 2191 | ||
| 2177 | static int tcpv6_net_init(struct net *net) | 2192 | static int __net_init tcpv6_net_init(struct net *net) |
| 2178 | { | 2193 | { |
| 2179 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, | 2194 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, |
| 2180 | SOCK_RAW, IPPROTO_TCP, net); | 2195 | SOCK_RAW, IPPROTO_TCP, net); |
| 2181 | } | 2196 | } |
| 2182 | 2197 | ||
| 2183 | static void tcpv6_net_exit(struct net *net) | 2198 | static void __net_exit tcpv6_net_exit(struct net *net) |
| 2184 | { | 2199 | { |
| 2185 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); | 2200 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); |
| 2186 | } | 2201 | } |
| 2187 | 2202 | ||
| 2188 | static void tcpv6_net_exit_batch(struct list_head *net_exit_list) | 2203 | static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) |
| 2189 | { | 2204 | { |
| 2190 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); | 2205 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); |
| 2191 | } | 2206 | } |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 51e2832d13a6..fc3c86a47452 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
| 26 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
| 27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
| 28 | #include <linux/slab.h> | ||
| 28 | #include <net/ipv6.h> | 29 | #include <net/ipv6.h> |
| 29 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
| 30 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
| @@ -98,7 +99,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
| 98 | if (!handler->handler(skb)) | 99 | if (!handler->handler(skb)) |
| 99 | return 0; | 100 | return 0; |
| 100 | 101 | ||
| 101 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 102 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
| 102 | 103 | ||
| 103 | drop: | 104 | drop: |
| 104 | kfree_skb(skb); | 105 | kfree_skb(skb); |
| @@ -116,7 +117,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
| 116 | if (!handler->handler(skb)) | 117 | if (!handler->handler(skb)) |
| 117 | return 0; | 118 | return 0; |
| 118 | 119 | ||
| 119 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 120 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
| 120 | 121 | ||
| 121 | drop: | 122 | drop: |
| 122 | kfree_skb(skb); | 123 | kfree_skb(skb); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 69ebdbe78c47..5acb3560ff15 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| 36 | #include <linux/skbuff.h> | 36 | #include <linux/skbuff.h> |
| 37 | #include <linux/slab.h> | ||
| 37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
| 38 | 39 | ||
| 39 | #include <net/ndisc.h> | 40 | #include <net/ndisc.h> |
| @@ -90,9 +91,9 @@ static unsigned int udp6_portaddr_hash(struct net *net, | |||
| 90 | if (ipv6_addr_any(addr6)) | 91 | if (ipv6_addr_any(addr6)) |
| 91 | hash = jhash_1word(0, mix); | 92 | hash = jhash_1word(0, mix); |
| 92 | else if (ipv6_addr_v4mapped(addr6)) | 93 | else if (ipv6_addr_v4mapped(addr6)) |
| 93 | hash = jhash_1word(addr6->s6_addr32[3], mix); | 94 | hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix); |
| 94 | else | 95 | else |
| 95 | hash = jhash2(addr6->s6_addr32, 4, mix); | 96 | hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix); |
| 96 | 97 | ||
| 97 | return hash ^ port; | 98 | return hash ^ port; |
| 98 | } | 99 | } |
| @@ -110,6 +111,15 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
| 110 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); | 111 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 114 | static void udp_v6_rehash(struct sock *sk) | ||
| 115 | { | ||
| 116 | u16 new_hash = udp6_portaddr_hash(sock_net(sk), | ||
| 117 | &inet6_sk(sk)->rcv_saddr, | ||
| 118 | inet_sk(sk)->inet_num); | ||
| 119 | |||
| 120 | udp_lib_rehash(sk, new_hash); | ||
| 121 | } | ||
| 122 | |||
| 113 | static inline int compute_score(struct sock *sk, struct net *net, | 123 | static inline int compute_score(struct sock *sk, struct net *net, |
| 114 | unsigned short hnum, | 124 | unsigned short hnum, |
| 115 | struct in6_addr *saddr, __be16 sport, | 125 | struct in6_addr *saddr, __be16 sport, |
| @@ -258,8 +268,8 @@ static struct sock *__udp6_lib_lookup(struct net *net, | |||
| 258 | if (hslot->count < hslot2->count) | 268 | if (hslot->count < hslot2->count) |
| 259 | goto begin; | 269 | goto begin; |
| 260 | 270 | ||
| 261 | result = udp6_lib_lookup2(net, &in6addr_any, sport, | 271 | result = udp6_lib_lookup2(net, saddr, sport, |
| 262 | daddr, hnum, dif, | 272 | &in6addr_any, hnum, dif, |
| 263 | hslot2, slot2); | 273 | hslot2, slot2); |
| 264 | } | 274 | } |
| 265 | rcu_read_unlock(); | 275 | rcu_read_unlock(); |
| @@ -322,11 +332,12 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 322 | struct ipv6_pinfo *np = inet6_sk(sk); | 332 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 323 | struct inet_sock *inet = inet_sk(sk); | 333 | struct inet_sock *inet = inet_sk(sk); |
| 324 | struct sk_buff *skb; | 334 | struct sk_buff *skb; |
| 325 | unsigned int ulen, copied; | 335 | unsigned int ulen; |
| 326 | int peeked; | 336 | int peeked; |
| 327 | int err; | 337 | int err; |
| 328 | int is_udplite = IS_UDPLITE(sk); | 338 | int is_udplite = IS_UDPLITE(sk); |
| 329 | int is_udp4; | 339 | int is_udp4; |
| 340 | bool slow; | ||
| 330 | 341 | ||
| 331 | if (addr_len) | 342 | if (addr_len) |
| 332 | *addr_len=sizeof(struct sockaddr_in6); | 343 | *addr_len=sizeof(struct sockaddr_in6); |
| @@ -334,6 +345,9 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 334 | if (flags & MSG_ERRQUEUE) | 345 | if (flags & MSG_ERRQUEUE) |
| 335 | return ipv6_recv_error(sk, msg, len); | 346 | return ipv6_recv_error(sk, msg, len); |
| 336 | 347 | ||
| 348 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) | ||
| 349 | return ipv6_recv_rxpmtu(sk, msg, len); | ||
| 350 | |||
| 337 | try_again: | 351 | try_again: |
| 338 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), | 352 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |
| 339 | &peeked, &err); | 353 | &peeked, &err); |
| @@ -341,10 +355,9 @@ try_again: | |||
| 341 | goto out; | 355 | goto out; |
| 342 | 356 | ||
| 343 | ulen = skb->len - sizeof(struct udphdr); | 357 | ulen = skb->len - sizeof(struct udphdr); |
| 344 | copied = len; | 358 | if (len > ulen) |
| 345 | if (copied > ulen) | 359 | len = ulen; |
| 346 | copied = ulen; | 360 | else if (len < ulen) |
| 347 | else if (copied < ulen) | ||
| 348 | msg->msg_flags |= MSG_TRUNC; | 361 | msg->msg_flags |= MSG_TRUNC; |
| 349 | 362 | ||
| 350 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | 363 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); |
| @@ -355,14 +368,14 @@ try_again: | |||
| 355 | * coverage checksum (UDP-Lite), do it before the copy. | 368 | * coverage checksum (UDP-Lite), do it before the copy. |
| 356 | */ | 369 | */ |
| 357 | 370 | ||
| 358 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 371 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
| 359 | if (udp_lib_checksum_complete(skb)) | 372 | if (udp_lib_checksum_complete(skb)) |
| 360 | goto csum_copy_err; | 373 | goto csum_copy_err; |
| 361 | } | 374 | } |
| 362 | 375 | ||
| 363 | if (skb_csum_unnecessary(skb)) | 376 | if (skb_csum_unnecessary(skb)) |
| 364 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 377 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
| 365 | msg->msg_iov, copied ); | 378 | msg->msg_iov,len); |
| 366 | else { | 379 | else { |
| 367 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 380 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
| 368 | if (err == -EINVAL) | 381 | if (err == -EINVAL) |
| @@ -411,7 +424,7 @@ try_again: | |||
| 411 | datagram_recv_ctl(sk, msg, skb); | 424 | datagram_recv_ctl(sk, msg, skb); |
| 412 | } | 425 | } |
| 413 | 426 | ||
| 414 | err = copied; | 427 | err = len; |
| 415 | if (flags & MSG_TRUNC) | 428 | if (flags & MSG_TRUNC) |
| 416 | err = ulen; | 429 | err = ulen; |
| 417 | 430 | ||
| @@ -421,7 +434,7 @@ out: | |||
| 421 | return err; | 434 | return err; |
| 422 | 435 | ||
| 423 | csum_copy_err: | 436 | csum_copy_err: |
| 424 | lock_sock(sk); | 437 | slow = lock_sock_fast(sk); |
| 425 | if (!skb_kill_datagram(sk, skb, flags)) { | 438 | if (!skb_kill_datagram(sk, skb, flags)) { |
| 426 | if (is_udp4) | 439 | if (is_udp4) |
| 427 | UDP_INC_STATS_USER(sock_net(sk), | 440 | UDP_INC_STATS_USER(sock_net(sk), |
| @@ -430,7 +443,7 @@ csum_copy_err: | |||
| 430 | UDP6_INC_STATS_USER(sock_net(sk), | 443 | UDP6_INC_STATS_USER(sock_net(sk), |
| 431 | UDP_MIB_INERRORS, is_udplite); | 444 | UDP_MIB_INERRORS, is_udplite); |
| 432 | } | 445 | } |
| 433 | release_sock(sk); | 446 | unlock_sock_fast(sk, slow); |
| 434 | 447 | ||
| 435 | if (flags & MSG_DONTWAIT) | 448 | if (flags & MSG_DONTWAIT) |
| 436 | return -EAGAIN; | 449 | return -EAGAIN; |
| @@ -511,7 +524,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
| 511 | goto drop; | 524 | goto drop; |
| 512 | } | 525 | } |
| 513 | 526 | ||
| 514 | if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { | 527 | if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) { |
| 515 | /* Note that an ENOMEM error is charged twice */ | 528 | /* Note that an ENOMEM error is charged twice */ |
| 516 | if (rc == -ENOMEM) | 529 | if (rc == -ENOMEM) |
| 517 | UDP6_INC_STATS_BH(sock_net(sk), | 530 | UDP6_INC_STATS_BH(sock_net(sk), |
| @@ -581,19 +594,27 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
| 581 | 594 | ||
| 582 | sk = stack[i]; | 595 | sk = stack[i]; |
| 583 | if (skb1) { | 596 | if (skb1) { |
| 597 | if (sk_rcvqueues_full(sk, skb)) { | ||
| 598 | kfree_skb(skb1); | ||
| 599 | goto drop; | ||
| 600 | } | ||
| 584 | bh_lock_sock(sk); | 601 | bh_lock_sock(sk); |
| 585 | if (!sock_owned_by_user(sk)) | 602 | if (!sock_owned_by_user(sk)) |
| 586 | udpv6_queue_rcv_skb(sk, skb1); | 603 | udpv6_queue_rcv_skb(sk, skb1); |
| 587 | else | 604 | else if (sk_add_backlog(sk, skb1)) { |
| 588 | sk_add_backlog(sk, skb1); | 605 | kfree_skb(skb1); |
| 606 | bh_unlock_sock(sk); | ||
| 607 | goto drop; | ||
| 608 | } | ||
| 589 | bh_unlock_sock(sk); | 609 | bh_unlock_sock(sk); |
| 590 | } else { | 610 | continue; |
| 591 | atomic_inc(&sk->sk_drops); | ||
| 592 | UDP6_INC_STATS_BH(sock_net(sk), | ||
| 593 | UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk)); | ||
| 594 | UDP6_INC_STATS_BH(sock_net(sk), | ||
| 595 | UDP_MIB_INERRORS, IS_UDPLITE(sk)); | ||
| 596 | } | 611 | } |
| 612 | drop: | ||
| 613 | atomic_inc(&sk->sk_drops); | ||
| 614 | UDP6_INC_STATS_BH(sock_net(sk), | ||
| 615 | UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk)); | ||
| 616 | UDP6_INC_STATS_BH(sock_net(sk), | ||
| 617 | UDP_MIB_INERRORS, IS_UDPLITE(sk)); | ||
| 597 | } | 618 | } |
| 598 | } | 619 | } |
| 599 | /* | 620 | /* |
| @@ -681,15 +702,14 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | |||
| 681 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 702 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
| 682 | int proto) | 703 | int proto) |
| 683 | { | 704 | { |
| 705 | struct net *net = dev_net(skb->dev); | ||
| 684 | struct sock *sk; | 706 | struct sock *sk; |
| 685 | struct udphdr *uh; | 707 | struct udphdr *uh; |
| 686 | struct net_device *dev = skb->dev; | ||
| 687 | struct in6_addr *saddr, *daddr; | 708 | struct in6_addr *saddr, *daddr; |
| 688 | u32 ulen = 0; | 709 | u32 ulen = 0; |
| 689 | struct net *net = dev_net(skb->dev); | ||
| 690 | 710 | ||
| 691 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 711 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
| 692 | goto short_packet; | 712 | goto discard; |
| 693 | 713 | ||
| 694 | saddr = &ipv6_hdr(skb)->saddr; | 714 | saddr = &ipv6_hdr(skb)->saddr; |
| 695 | daddr = &ipv6_hdr(skb)->daddr; | 715 | daddr = &ipv6_hdr(skb)->daddr; |
| @@ -745,7 +765,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
| 745 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, | 765 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, |
| 746 | proto == IPPROTO_UDPLITE); | 766 | proto == IPPROTO_UDPLITE); |
| 747 | 767 | ||
| 748 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 768 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
| 749 | 769 | ||
| 750 | kfree_skb(skb); | 770 | kfree_skb(skb); |
| 751 | return 0; | 771 | return 0; |
| @@ -753,19 +773,32 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
| 753 | 773 | ||
| 754 | /* deliver */ | 774 | /* deliver */ |
| 755 | 775 | ||
| 776 | if (sk_rcvqueues_full(sk, skb)) { | ||
| 777 | sock_put(sk); | ||
| 778 | goto discard; | ||
| 779 | } | ||
| 756 | bh_lock_sock(sk); | 780 | bh_lock_sock(sk); |
| 757 | if (!sock_owned_by_user(sk)) | 781 | if (!sock_owned_by_user(sk)) |
| 758 | udpv6_queue_rcv_skb(sk, skb); | 782 | udpv6_queue_rcv_skb(sk, skb); |
| 759 | else | 783 | else if (sk_add_backlog(sk, skb)) { |
| 760 | sk_add_backlog(sk, skb); | 784 | atomic_inc(&sk->sk_drops); |
| 785 | bh_unlock_sock(sk); | ||
| 786 | sock_put(sk); | ||
| 787 | goto discard; | ||
| 788 | } | ||
| 761 | bh_unlock_sock(sk); | 789 | bh_unlock_sock(sk); |
| 762 | sock_put(sk); | 790 | sock_put(sk); |
| 763 | return 0; | 791 | return 0; |
| 764 | 792 | ||
| 765 | short_packet: | 793 | short_packet: |
| 766 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", | 794 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n", |
| 767 | proto == IPPROTO_UDPLITE ? "-Lite" : "", | 795 | proto == IPPROTO_UDPLITE ? "-Lite" : "", |
| 768 | ulen, skb->len); | 796 | saddr, |
| 797 | ntohs(uh->source), | ||
| 798 | ulen, | ||
| 799 | skb->len, | ||
| 800 | daddr, | ||
| 801 | ntohs(uh->dest)); | ||
| 769 | 802 | ||
| 770 | discard: | 803 | discard: |
| 771 | UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); | 804 | UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); |
| @@ -903,7 +936,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 903 | struct inet_sock *inet = inet_sk(sk); | 936 | struct inet_sock *inet = inet_sk(sk); |
| 904 | struct ipv6_pinfo *np = inet6_sk(sk); | 937 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 905 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; | 938 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; |
| 906 | struct in6_addr *daddr, *final_p = NULL, final; | 939 | struct in6_addr *daddr, *final_p, final; |
| 907 | struct ipv6_txoptions *opt = NULL; | 940 | struct ipv6_txoptions *opt = NULL; |
| 908 | struct ip6_flowlabel *flowlabel = NULL; | 941 | struct ip6_flowlabel *flowlabel = NULL; |
| 909 | struct flowi fl; | 942 | struct flowi fl; |
| @@ -912,6 +945,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 912 | int ulen = len; | 945 | int ulen = len; |
| 913 | int hlimit = -1; | 946 | int hlimit = -1; |
| 914 | int tclass = -1; | 947 | int tclass = -1; |
| 948 | int dontfrag = -1; | ||
| 915 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 949 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
| 916 | int err; | 950 | int err; |
| 917 | int connected = 0; | 951 | int connected = 0; |
| @@ -1042,7 +1076,8 @@ do_udp_sendmsg: | |||
| 1042 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1076 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
| 1043 | opt->tot_len = sizeof(*opt); | 1077 | opt->tot_len = sizeof(*opt); |
| 1044 | 1078 | ||
| 1045 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass); | 1079 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, |
| 1080 | &tclass, &dontfrag); | ||
| 1046 | if (err < 0) { | 1081 | if (err < 0) { |
| 1047 | fl6_sock_release(flowlabel); | 1082 | fl6_sock_release(flowlabel); |
| 1048 | return err; | 1083 | return err; |
| @@ -1071,14 +1106,9 @@ do_udp_sendmsg: | |||
| 1071 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 1106 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
| 1072 | fl.fl_ip_sport = inet->inet_sport; | 1107 | fl.fl_ip_sport = inet->inet_sport; |
| 1073 | 1108 | ||
| 1074 | /* merge ip6_build_xmit from ip6_output */ | 1109 | final_p = fl6_update_dst(&fl, opt, &final); |
| 1075 | if (opt && opt->srcrt) { | 1110 | if (final_p) |
| 1076 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | ||
| 1077 | ipv6_addr_copy(&final, &fl.fl6_dst); | ||
| 1078 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | ||
| 1079 | final_p = &final; | ||
| 1080 | connected = 0; | 1111 | connected = 0; |
| 1081 | } | ||
| 1082 | 1112 | ||
| 1083 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { | 1113 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { |
| 1084 | fl.oif = np->mcast_oif; | 1114 | fl.oif = np->mcast_oif; |
| @@ -1113,6 +1143,9 @@ do_udp_sendmsg: | |||
| 1113 | if (tclass < 0) | 1143 | if (tclass < 0) |
| 1114 | tclass = np->tclass; | 1144 | tclass = np->tclass; |
| 1115 | 1145 | ||
| 1146 | if (dontfrag < 0) | ||
| 1147 | dontfrag = np->dontfrag; | ||
| 1148 | |||
| 1116 | if (msg->msg_flags&MSG_CONFIRM) | 1149 | if (msg->msg_flags&MSG_CONFIRM) |
| 1117 | goto do_confirm; | 1150 | goto do_confirm; |
| 1118 | back_from_confirm: | 1151 | back_from_confirm: |
| @@ -1136,7 +1169,7 @@ do_append_data: | |||
| 1136 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, | 1169 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, |
| 1137 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, | 1170 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, |
| 1138 | (struct rt6_info*)dst, | 1171 | (struct rt6_info*)dst, |
| 1139 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); | 1172 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag); |
| 1140 | if (err) | 1173 | if (err) |
| 1141 | udp_v6_flush_pending_frames(sk); | 1174 | udp_v6_flush_pending_frames(sk); |
| 1142 | else if (!corkreq) | 1175 | else if (!corkreq) |
| @@ -1396,7 +1429,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
| 1396 | }, | 1429 | }, |
| 1397 | }; | 1430 | }; |
| 1398 | 1431 | ||
| 1399 | int udp6_proc_init(struct net *net) | 1432 | int __net_init udp6_proc_init(struct net *net) |
| 1400 | { | 1433 | { |
| 1401 | return udp_proc_register(net, &udp6_seq_afinfo); | 1434 | return udp_proc_register(net, &udp6_seq_afinfo); |
| 1402 | } | 1435 | } |
| @@ -1423,6 +1456,7 @@ struct proto udpv6_prot = { | |||
| 1423 | .backlog_rcv = udpv6_queue_rcv_skb, | 1456 | .backlog_rcv = udpv6_queue_rcv_skb, |
| 1424 | .hash = udp_lib_hash, | 1457 | .hash = udp_lib_hash, |
| 1425 | .unhash = udp_lib_unhash, | 1458 | .unhash = udp_lib_unhash, |
| 1459 | .rehash = udp_v6_rehash, | ||
| 1426 | .get_port = udp_v6_get_port, | 1460 | .get_port = udp_v6_get_port, |
| 1427 | .memory_allocated = &udp_memory_allocated, | 1461 | .memory_allocated = &udp_memory_allocated, |
| 1428 | .sysctl_mem = sysctl_udp_mem, | 1462 | .sysctl_mem = sysctl_udp_mem, |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 6ea6938919e6..5f48fadc27f7 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
| @@ -104,12 +104,12 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { | |||
| 104 | }, | 104 | }, |
| 105 | }; | 105 | }; |
| 106 | 106 | ||
| 107 | static int udplite6_proc_init_net(struct net *net) | 107 | static int __net_init udplite6_proc_init_net(struct net *net) |
| 108 | { | 108 | { |
| 109 | return udp_proc_register(net, &udplite6_seq_afinfo); | 109 | return udp_proc_register(net, &udplite6_seq_afinfo); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static void udplite6_proc_exit_net(struct net *net) | 112 | static void __net_exit udplite6_proc_exit_net(struct net *net) |
| 113 | { | 113 | { |
| 114 | udp_proc_unregister(net, &udplite6_seq_afinfo); | 114 | udp_proc_unregister(net, &udplite6_seq_afinfo); |
| 115 | } | 115 | } |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 9084582d236b..f8c3cf842f53 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
| @@ -42,7 +42,7 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) | |||
| 42 | ipv6_hdr(skb)->payload_len = htons(skb->len); | 42 | ipv6_hdr(skb)->payload_len = htons(skb->len); |
| 43 | __skb_push(skb, skb->data - skb_network_header(skb)); | 43 | __skb_push(skb, skb->data - skb_network_header(skb)); |
| 44 | 44 | ||
| 45 | NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, | 45 | NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, |
| 46 | ip6_rcv_finish); | 46 | ip6_rcv_finish); |
| 47 | return -1; | 47 | return -1; |
| 48 | } | 48 | } |
| @@ -101,7 +101,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | |||
| 101 | break; | 101 | break; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | x = xfrm_state_lookup_byaddr(net, dst, src, proto, AF_INET6); | 104 | x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); |
| 105 | if (!x) | 105 | if (!x) |
| 106 | continue; | 106 | continue; |
| 107 | 107 | ||
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 3927832227b9..b809812c8d30 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/gfp.h> | ||
| 8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index c4f4eef032a3..6434bd5ce088 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
| @@ -38,7 +38,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) | |||
| 38 | 38 | ||
| 39 | if (!skb->local_df && skb->len > mtu) { | 39 | if (!skb->local_df && skb->len > mtu) { |
| 40 | skb->dev = dst->dev; | 40 | skb->dev = dst->dev; |
| 41 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 41 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
| 42 | ret = -EMSGSIZE; | 42 | ret = -EMSGSIZE; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| @@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
| 90 | 90 | ||
| 91 | int xfrm6_output(struct sk_buff *skb) | 91 | int xfrm6_output(struct sk_buff *skb) |
| 92 | { | 92 | { |
| 93 | return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev, | 93 | return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, |
| 94 | xfrm6_output_finish); | 94 | skb_dst(skb)->dev, xfrm6_output_finish); |
| 95 | } | 95 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index dbdc696f5fc5..6baeabbbca82 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -67,36 +67,6 @@ static int xfrm6_get_saddr(struct net *net, | |||
| 67 | return 0; | 67 | return 0; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static struct dst_entry * | ||
| 71 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | ||
| 72 | { | ||
| 73 | struct dst_entry *dst; | ||
| 74 | |||
| 75 | /* Still not clear if we should set fl->fl6_{src,dst}... */ | ||
| 76 | read_lock_bh(&policy->lock); | ||
| 77 | for (dst = policy->bundles; dst; dst = dst->next) { | ||
| 78 | struct xfrm_dst *xdst = (struct xfrm_dst*)dst; | ||
| 79 | struct in6_addr fl_dst_prefix, fl_src_prefix; | ||
| 80 | |||
| 81 | ipv6_addr_prefix(&fl_dst_prefix, | ||
| 82 | &fl->fl6_dst, | ||
| 83 | xdst->u.rt6.rt6i_dst.plen); | ||
| 84 | ipv6_addr_prefix(&fl_src_prefix, | ||
| 85 | &fl->fl6_src, | ||
| 86 | xdst->u.rt6.rt6i_src.plen); | ||
| 87 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && | ||
| 88 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && | ||
| 89 | xfrm_bundle_ok(policy, xdst, fl, AF_INET6, | ||
| 90 | (xdst->u.rt6.rt6i_dst.plen != 128 || | ||
| 91 | xdst->u.rt6.rt6i_src.plen != 128))) { | ||
| 92 | dst_clone(dst); | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | read_unlock_bh(&policy->lock); | ||
| 97 | return dst; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int xfrm6_get_tos(struct flowi *fl) | 70 | static int xfrm6_get_tos(struct flowi *fl) |
| 101 | { | 71 | { |
| 102 | return 0; | 72 | return 0; |
| @@ -116,14 +86,15 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
| 116 | return 0; | 86 | return 0; |
| 117 | } | 87 | } |
| 118 | 88 | ||
| 119 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 89 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| 90 | struct flowi *fl) | ||
| 120 | { | 91 | { |
| 121 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | 92 | struct rt6_info *rt = (struct rt6_info*)xdst->route; |
| 122 | 93 | ||
| 123 | xdst->u.dst.dev = dev; | 94 | xdst->u.dst.dev = dev; |
| 124 | dev_hold(dev); | 95 | dev_hold(dev); |
| 125 | 96 | ||
| 126 | xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev); | 97 | xdst->u.rt6.rt6i_idev = in6_dev_get(dev); |
| 127 | if (!xdst->u.rt6.rt6i_idev) | 98 | if (!xdst->u.rt6.rt6i_idev) |
| 128 | return -ENODEV; | 99 | return -ENODEV; |
| 129 | 100 | ||
| @@ -153,6 +124,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
| 153 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; | 124 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; |
| 154 | 125 | ||
| 155 | memset(fl, 0, sizeof(struct flowi)); | 126 | memset(fl, 0, sizeof(struct flowi)); |
| 127 | fl->mark = skb->mark; | ||
| 128 | |||
| 156 | ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr); | 129 | ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr); |
| 157 | ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr); | 130 | ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr); |
| 158 | 131 | ||
| @@ -290,7 +263,6 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
| 290 | .dst_ops = &xfrm6_dst_ops, | 263 | .dst_ops = &xfrm6_dst_ops, |
| 291 | .dst_lookup = xfrm6_dst_lookup, | 264 | .dst_lookup = xfrm6_dst_lookup, |
| 292 | .get_saddr = xfrm6_get_saddr, | 265 | .get_saddr = xfrm6_get_saddr, |
| 293 | .find_bundle = __xfrm6_find_bundle, | ||
| 294 | .decode_session = _decode_session6, | 266 | .decode_session = _decode_session6, |
| 295 | .get_tos = xfrm6_get_tos, | 267 | .get_tos = xfrm6_get_tos, |
| 296 | .init_path = xfrm6_init_path, | 268 | .init_path = xfrm6_init_path, |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index f417b77fa0e1..a67575d472a3 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
| @@ -20,23 +20,27 @@ | |||
| 20 | #include <net/addrconf.h> | 20 | #include <net/addrconf.h> |
| 21 | 21 | ||
| 22 | static void | 22 | static void |
| 23 | __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, | 23 | __xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl) |
| 24 | struct xfrm_tmpl *tmpl, | ||
| 25 | xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
| 26 | { | 24 | { |
| 27 | /* Initialize temporary selector matching only | 25 | /* Initialize temporary selector matching only |
| 28 | * to current session. */ | 26 | * to current session. */ |
| 29 | ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); | 27 | ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst); |
| 30 | ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); | 28 | ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src); |
| 31 | x->sel.dport = xfrm_flowi_dport(fl); | 29 | sel->dport = xfrm_flowi_dport(fl); |
| 32 | x->sel.dport_mask = htons(0xffff); | 30 | sel->dport_mask = htons(0xffff); |
| 33 | x->sel.sport = xfrm_flowi_sport(fl); | 31 | sel->sport = xfrm_flowi_sport(fl); |
| 34 | x->sel.sport_mask = htons(0xffff); | 32 | sel->sport_mask = htons(0xffff); |
| 35 | x->sel.family = AF_INET6; | 33 | sel->family = AF_INET6; |
| 36 | x->sel.prefixlen_d = 128; | 34 | sel->prefixlen_d = 128; |
| 37 | x->sel.prefixlen_s = 128; | 35 | sel->prefixlen_s = 128; |
| 38 | x->sel.proto = fl->proto; | 36 | sel->proto = fl->proto; |
| 39 | x->sel.ifindex = fl->oif; | 37 | sel->ifindex = fl->oif; |
| 38 | } | ||
| 39 | |||
| 40 | static void | ||
| 41 | xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl, | ||
| 42 | xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
| 43 | { | ||
| 40 | x->id = tmpl->id; | 44 | x->id = tmpl->id; |
| 41 | if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) | 45 | if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) |
| 42 | memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); | 46 | memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); |
| @@ -168,6 +172,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { | |||
| 168 | .eth_proto = htons(ETH_P_IPV6), | 172 | .eth_proto = htons(ETH_P_IPV6), |
| 169 | .owner = THIS_MODULE, | 173 | .owner = THIS_MODULE, |
| 170 | .init_tempsel = __xfrm6_init_tempsel, | 174 | .init_tempsel = __xfrm6_init_tempsel, |
| 175 | .init_temprop = xfrm6_init_temprop, | ||
| 171 | .tmpl_sort = __xfrm6_tmpl_sort, | 176 | .tmpl_sort = __xfrm6_tmpl_sort, |
| 172 | .state_sort = __xfrm6_state_sort, | 177 | .state_sort = __xfrm6_state_sort, |
| 173 | .output = xfrm6_output, | 178 | .output = xfrm6_output, |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 438831d33593..2ce3a8278f26 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/xfrm.h> | 25 | #include <linux/xfrm.h> |
| 26 | #include <linux/slab.h> | ||
| 26 | #include <linux/rculist.h> | 27 | #include <linux/rculist.h> |
| 27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
| 28 | #include <net/xfrm.h> | 29 | #include <net/xfrm.h> |
| @@ -30,6 +31,25 @@ | |||
| 30 | #include <linux/ipv6.h> | 31 | #include <linux/ipv6.h> |
| 31 | #include <linux/icmpv6.h> | 32 | #include <linux/icmpv6.h> |
| 32 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
| 34 | #include <net/netns/generic.h> | ||
| 35 | |||
| 36 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
| 37 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
| 38 | |||
| 39 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
| 40 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
| 41 | |||
| 42 | struct xfrm6_tunnel_net { | ||
| 43 | struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
| 44 | struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
| 45 | u32 spi; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int xfrm6_tunnel_net_id __read_mostly; | ||
| 49 | static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) | ||
| 50 | { | ||
| 51 | return net_generic(net, xfrm6_tunnel_net_id); | ||
| 52 | } | ||
| 33 | 53 | ||
| 34 | /* | 54 | /* |
| 35 | * xfrm_tunnel_spi things are for allocating unique id ("spi") | 55 | * xfrm_tunnel_spi things are for allocating unique id ("spi") |
| @@ -46,19 +66,8 @@ struct xfrm6_tunnel_spi { | |||
| 46 | 66 | ||
| 47 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); | 67 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); |
| 48 | 68 | ||
| 49 | static u32 xfrm6_tunnel_spi; | ||
| 50 | |||
| 51 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
| 52 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
| 53 | |||
| 54 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 69 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; |
| 55 | 70 | ||
| 56 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
| 57 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
| 58 | |||
| 59 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
| 60 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
| 61 | |||
| 62 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 71 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
| 63 | { | 72 | { |
| 64 | unsigned h; | 73 | unsigned h; |
| @@ -76,50 +85,14 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) | |||
| 76 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 85 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
| 77 | } | 86 | } |
| 78 | 87 | ||
| 79 | 88 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | |
| 80 | static int xfrm6_tunnel_spi_init(void) | ||
| 81 | { | ||
| 82 | int i; | ||
| 83 | |||
| 84 | xfrm6_tunnel_spi = 0; | ||
| 85 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", | ||
| 86 | sizeof(struct xfrm6_tunnel_spi), | ||
| 87 | 0, SLAB_HWCACHE_ALIGN, | ||
| 88 | NULL); | ||
| 89 | if (!xfrm6_tunnel_spi_kmem) | ||
| 90 | return -ENOMEM; | ||
| 91 | |||
| 92 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
| 93 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); | ||
| 94 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
| 95 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static void xfrm6_tunnel_spi_fini(void) | ||
| 100 | { | ||
| 101 | int i; | ||
| 102 | |||
| 103 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { | ||
| 104 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) | ||
| 105 | return; | ||
| 106 | } | ||
| 107 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { | ||
| 108 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | rcu_barrier(); | ||
| 112 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
| 113 | xfrm6_tunnel_spi_kmem = NULL; | ||
| 114 | } | ||
| 115 | |||
| 116 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | ||
| 117 | { | 89 | { |
| 90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
| 118 | struct xfrm6_tunnel_spi *x6spi; | 91 | struct xfrm6_tunnel_spi *x6spi; |
| 119 | struct hlist_node *pos; | 92 | struct hlist_node *pos; |
| 120 | 93 | ||
| 121 | hlist_for_each_entry_rcu(x6spi, pos, | 94 | hlist_for_each_entry_rcu(x6spi, pos, |
| 122 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
| 123 | list_byaddr) { | 96 | list_byaddr) { |
| 124 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 97 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
| 125 | return x6spi; | 98 | return x6spi; |
| @@ -128,13 +101,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 128 | return NULL; | 101 | return NULL; |
| 129 | } | 102 | } |
| 130 | 103 | ||
| 131 | __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | 104 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) |
| 132 | { | 105 | { |
| 133 | struct xfrm6_tunnel_spi *x6spi; | 106 | struct xfrm6_tunnel_spi *x6spi; |
| 134 | u32 spi; | 107 | u32 spi; |
| 135 | 108 | ||
| 136 | rcu_read_lock_bh(); | 109 | rcu_read_lock_bh(); |
| 137 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 110 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
| 138 | spi = x6spi ? x6spi->spi : 0; | 111 | spi = x6spi ? x6spi->spi : 0; |
| 139 | rcu_read_unlock_bh(); | 112 | rcu_read_unlock_bh(); |
| 140 | return htonl(spi); | 113 | return htonl(spi); |
| @@ -142,14 +115,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
| 142 | 115 | ||
| 143 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 116 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
| 144 | 117 | ||
| 145 | static int __xfrm6_tunnel_spi_check(u32 spi) | 118 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) |
| 146 | { | 119 | { |
| 120 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
| 147 | struct xfrm6_tunnel_spi *x6spi; | 121 | struct xfrm6_tunnel_spi *x6spi; |
| 148 | int index = xfrm6_tunnel_spi_hash_byspi(spi); | 122 | int index = xfrm6_tunnel_spi_hash_byspi(spi); |
| 149 | struct hlist_node *pos; | 123 | struct hlist_node *pos; |
| 150 | 124 | ||
| 151 | hlist_for_each_entry(x6spi, pos, | 125 | hlist_for_each_entry(x6spi, pos, |
| 152 | &xfrm6_tunnel_spi_byspi[index], | 126 | &xfrm6_tn->spi_byspi[index], |
| 153 | list_byspi) { | 127 | list_byspi) { |
| 154 | if (x6spi->spi == spi) | 128 | if (x6spi->spi == spi) |
| 155 | return -1; | 129 | return -1; |
| @@ -157,61 +131,61 @@ static int __xfrm6_tunnel_spi_check(u32 spi) | |||
| 157 | return index; | 131 | return index; |
| 158 | } | 132 | } |
| 159 | 133 | ||
| 160 | static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 134 | static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
| 161 | { | 135 | { |
| 136 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
| 162 | u32 spi; | 137 | u32 spi; |
| 163 | struct xfrm6_tunnel_spi *x6spi; | 138 | struct xfrm6_tunnel_spi *x6spi; |
| 164 | int index; | 139 | int index; |
| 165 | 140 | ||
| 166 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || | 141 | if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || |
| 167 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) | 142 | xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) |
| 168 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; | 143 | xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; |
| 169 | else | 144 | else |
| 170 | xfrm6_tunnel_spi++; | 145 | xfrm6_tn->spi++; |
| 171 | 146 | ||
| 172 | for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { | 147 | for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { |
| 173 | index = __xfrm6_tunnel_spi_check(spi); | 148 | index = __xfrm6_tunnel_spi_check(net, spi); |
| 174 | if (index >= 0) | 149 | if (index >= 0) |
| 175 | goto alloc_spi; | 150 | goto alloc_spi; |
| 176 | } | 151 | } |
| 177 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { | 152 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { |
| 178 | index = __xfrm6_tunnel_spi_check(spi); | 153 | index = __xfrm6_tunnel_spi_check(net, spi); |
| 179 | if (index >= 0) | 154 | if (index >= 0) |
| 180 | goto alloc_spi; | 155 | goto alloc_spi; |
| 181 | } | 156 | } |
| 182 | spi = 0; | 157 | spi = 0; |
| 183 | goto out; | 158 | goto out; |
| 184 | alloc_spi: | 159 | alloc_spi: |
| 185 | xfrm6_tunnel_spi = spi; | 160 | xfrm6_tn->spi = spi; |
| 186 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); | 161 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); |
| 187 | if (!x6spi) | 162 | if (!x6spi) |
| 188 | goto out; | 163 | goto out; |
| 189 | 164 | ||
| 190 | INIT_RCU_HEAD(&x6spi->rcu_head); | ||
| 191 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); | 165 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); |
| 192 | x6spi->spi = spi; | 166 | x6spi->spi = spi; |
| 193 | atomic_set(&x6spi->refcnt, 1); | 167 | atomic_set(&x6spi->refcnt, 1); |
| 194 | 168 | ||
| 195 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); | 169 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); |
| 196 | 170 | ||
| 197 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 171 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
| 198 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 172 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); |
| 199 | out: | 173 | out: |
| 200 | return spi; | 174 | return spi; |
| 201 | } | 175 | } |
| 202 | 176 | ||
| 203 | __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 177 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
| 204 | { | 178 | { |
| 205 | struct xfrm6_tunnel_spi *x6spi; | 179 | struct xfrm6_tunnel_spi *x6spi; |
| 206 | u32 spi; | 180 | u32 spi; |
| 207 | 181 | ||
| 208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); | 182 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
| 209 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 183 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
| 210 | if (x6spi) { | 184 | if (x6spi) { |
| 211 | atomic_inc(&x6spi->refcnt); | 185 | atomic_inc(&x6spi->refcnt); |
| 212 | spi = x6spi->spi; | 186 | spi = x6spi->spi; |
| 213 | } else | 187 | } else |
| 214 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 188 | spi = __xfrm6_tunnel_alloc_spi(net, saddr); |
| 215 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); | 189 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
| 216 | 190 | ||
| 217 | return htonl(spi); | 191 | return htonl(spi); |
| @@ -225,15 +199,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head) | |||
| 225 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | 199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); |
| 226 | } | 200 | } |
| 227 | 201 | ||
| 228 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 202 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) |
| 229 | { | 203 | { |
| 204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
| 230 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
| 231 | struct hlist_node *pos, *n; | 206 | struct hlist_node *pos, *n; |
| 232 | 207 | ||
| 233 | spin_lock_bh(&xfrm6_tunnel_spi_lock); | 208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
| 234 | 209 | ||
| 235 | hlist_for_each_entry_safe(x6spi, pos, n, | 210 | hlist_for_each_entry_safe(x6spi, pos, n, |
| 236 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
| 237 | list_byaddr) | 212 | list_byaddr) |
| 238 | { | 213 | { |
| 239 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 214 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
| @@ -263,10 +238,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
| 263 | 238 | ||
| 264 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 239 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
| 265 | { | 240 | { |
| 241 | struct net *net = dev_net(skb->dev); | ||
| 266 | struct ipv6hdr *iph = ipv6_hdr(skb); | 242 | struct ipv6hdr *iph = ipv6_hdr(skb); |
| 267 | __be32 spi; | 243 | __be32 spi; |
| 268 | 244 | ||
| 269 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 245 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); |
| 270 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; | 246 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; |
| 271 | } | 247 | } |
| 272 | 248 | ||
| @@ -326,7 +302,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x) | |||
| 326 | 302 | ||
| 327 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) | 303 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) |
| 328 | { | 304 | { |
| 329 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 305 | struct net *net = xs_net(x); |
| 306 | |||
| 307 | xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); | ||
| 330 | } | 308 | } |
| 331 | 309 | ||
| 332 | static const struct xfrm_type xfrm6_tunnel_type = { | 310 | static const struct xfrm_type xfrm6_tunnel_type = { |
| @@ -351,34 +329,73 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { | |||
| 351 | .priority = 2, | 329 | .priority = 2, |
| 352 | }; | 330 | }; |
| 353 | 331 | ||
| 332 | static int __net_init xfrm6_tunnel_net_init(struct net *net) | ||
| 333 | { | ||
| 334 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
| 335 | unsigned int i; | ||
| 336 | |||
| 337 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
| 338 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); | ||
| 339 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
| 340 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); | ||
| 341 | xfrm6_tn->spi = 0; | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | ||
| 347 | { | ||
| 348 | } | ||
| 349 | |||
| 350 | static struct pernet_operations xfrm6_tunnel_net_ops = { | ||
| 351 | .init = xfrm6_tunnel_net_init, | ||
| 352 | .exit = xfrm6_tunnel_net_exit, | ||
| 353 | .id = &xfrm6_tunnel_net_id, | ||
| 354 | .size = sizeof(struct xfrm6_tunnel_net), | ||
| 355 | }; | ||
| 356 | |||
| 354 | static int __init xfrm6_tunnel_init(void) | 357 | static int __init xfrm6_tunnel_init(void) |
| 355 | { | 358 | { |
| 356 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) | 359 | int rv; |
| 357 | goto err; | 360 | |
| 358 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) | 361 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", |
| 359 | goto unreg; | 362 | sizeof(struct xfrm6_tunnel_spi), |
| 360 | if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) | 363 | 0, SLAB_HWCACHE_ALIGN, |
| 361 | goto dereg6; | 364 | NULL); |
| 362 | if (xfrm6_tunnel_spi_init() < 0) | 365 | if (!xfrm6_tunnel_spi_kmem) |
| 363 | goto dereg46; | 366 | return -ENOMEM; |
| 367 | rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
| 368 | if (rv < 0) | ||
| 369 | goto out_pernet; | ||
| 370 | rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); | ||
| 371 | if (rv < 0) | ||
| 372 | goto out_type; | ||
| 373 | rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); | ||
| 374 | if (rv < 0) | ||
| 375 | goto out_xfrm6; | ||
| 376 | rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); | ||
| 377 | if (rv < 0) | ||
| 378 | goto out_xfrm46; | ||
| 364 | return 0; | 379 | return 0; |
| 365 | 380 | ||
| 366 | dereg46: | 381 | out_xfrm46: |
| 367 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | ||
| 368 | dereg6: | ||
| 369 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 382 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
| 370 | unreg: | 383 | out_xfrm6: |
| 371 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 384 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 372 | err: | 385 | out_type: |
| 373 | return -EAGAIN; | 386 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
| 387 | out_pernet: | ||
| 388 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
| 389 | return rv; | ||
| 374 | } | 390 | } |
| 375 | 391 | ||
| 376 | static void __exit xfrm6_tunnel_fini(void) | 392 | static void __exit xfrm6_tunnel_fini(void) |
| 377 | { | 393 | { |
| 378 | xfrm6_tunnel_spi_fini(); | ||
| 379 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | 394 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); |
| 380 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 395 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
| 381 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 396 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 397 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
| 398 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
| 382 | } | 399 | } |
| 383 | 400 | ||
| 384 | module_init(xfrm6_tunnel_init); | 401 | module_init(xfrm6_tunnel_init); |
