diff options
Diffstat (limited to 'net/ipv6/mcast.c')
| -rw-r--r-- | net/ipv6/mcast.c | 367 |
1 files changed, 153 insertions, 214 deletions
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); |
