aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/mcast.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-07 17:05:02 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-09 21:06:14 -0400
commit96b52e61be1ad4d4f8de39b9deaf253da804ea3b (patch)
tree7751b360813e7c821b3eb3439651edcbc77f5eae /net/ipv6/mcast.c
parent97859160c5158a97a4b976a2d7bc74cf2223afe0 (diff)
ipv6: mcast: RCU conversions
- ipv6_sock_mc_join() : doesnt touch dev refcount - ipv6_sock_mc_drop() : doesnt touch dev/idev refcounts - ip6_mc_find_dev() becomes ip6_mc_find_dev_rcu() (called from rcu), and doesnt touch dev/idev refcounts - ipv6_sock_mc_close() : doesnt touch dev/idev refcounts - ip6_mc_source() uses ip6_mc_find_dev_rcu() - ip6_mc_msfilter() uses ip6_mc_find_dev_rcu() - ip6_mc_msfget() uses ip6_mc_find_dev_rcu() - ipv6_dev_mc_dec(), ipv6_chk_mcast_addr(), igmp6_event_query(), igmp6_event_report(), mld_sendpack(), igmp6_send() dont touch idev refcount Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r--net/ipv6/mcast.c183
1 files changed, 87 insertions, 96 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 8752e8084806..3e36d1538b6e 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -152,18 +152,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
152 mc_lst->next = NULL; 152 mc_lst->next = NULL;
153 ipv6_addr_copy(&mc_lst->addr, addr); 153 ipv6_addr_copy(&mc_lst->addr, addr);
154 154
155 rcu_read_lock();
155 if (ifindex == 0) { 156 if (ifindex == 0) {
156 struct rt6_info *rt; 157 struct rt6_info *rt;
157 rt = rt6_lookup(net, addr, NULL, 0, 0); 158 rt = rt6_lookup(net, addr, NULL, 0, 0);
158 if (rt) { 159 if (rt) {
159 dev = rt->rt6i_dev; 160 dev = rt->rt6i_dev;
160 dev_hold(dev);
161 dst_release(&rt->u.dst); 161 dst_release(&rt->u.dst);
162 } 162 }
163 } else 163 } else
164 dev = dev_get_by_index(net, ifindex); 164 dev = dev_get_by_index_rcu(net, ifindex);
165 165
166 if (dev == NULL) { 166 if (dev == NULL) {
167 rcu_read_unlock();
167 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 168 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
168 return -ENODEV; 169 return -ENODEV;
169 } 170 }
@@ -180,8 +181,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
180 err = ipv6_dev_mc_inc(dev, addr); 181 err = ipv6_dev_mc_inc(dev, addr);
181 182
182 if (err) { 183 if (err) {
184 rcu_read_unlock();
183 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 185 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
184 dev_put(dev);
185 return err; 186 return err;
186 } 187 }
187 188
@@ -190,7 +191,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
190 np->ipv6_mc_list = mc_lst; 191 np->ipv6_mc_list = mc_lst;
191 write_unlock_bh(&ipv6_sk_mc_lock); 192 write_unlock_bh(&ipv6_sk_mc_lock);
192 193
193 dev_put(dev); 194 rcu_read_unlock();
194 195
195 return 0; 196 return 0;
196} 197}
@@ -213,18 +214,17 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
213 *lnk = mc_lst->next; 214 *lnk = mc_lst->next;
214 write_unlock_bh(&ipv6_sk_mc_lock); 215 write_unlock_bh(&ipv6_sk_mc_lock);
215 216
216 dev = dev_get_by_index(net, mc_lst->ifindex); 217 rcu_read_lock();
218 dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
217 if (dev != NULL) { 219 if (dev != NULL) {
218 struct inet6_dev *idev = in6_dev_get(dev); 220 struct inet6_dev *idev = __in6_dev_get(dev);
219 221
220 (void) ip6_mc_leave_src(sk, mc_lst, idev); 222 (void) ip6_mc_leave_src(sk, mc_lst, idev);
221 if (idev) { 223 if (idev)
222 __ipv6_dev_mc_dec(idev, &mc_lst->addr); 224 __ipv6_dev_mc_dec(idev, &mc_lst->addr);
223 in6_dev_put(idev);
224 }
225 dev_put(dev);
226 } else 225 } else
227 (void) ip6_mc_leave_src(sk, mc_lst, NULL); 226 (void) ip6_mc_leave_src(sk, mc_lst, NULL);
227 rcu_read_unlock();
228 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 228 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
229 return 0; 229 return 0;
230 } 230 }
@@ -234,43 +234,36 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
234 return -EADDRNOTAVAIL; 234 return -EADDRNOTAVAIL;
235} 235}
236 236
237static struct inet6_dev *ip6_mc_find_dev(struct net *net, 237/* called with rcu_read_lock() */
238 struct in6_addr *group, 238static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
239 int ifindex) 239 struct in6_addr *group,
240 int ifindex)
240{ 241{
241 struct net_device *dev = NULL; 242 struct net_device *dev = NULL;
242 struct inet6_dev *idev = NULL; 243 struct inet6_dev *idev = NULL;
243 244
244 if (ifindex == 0) { 245 if (ifindex == 0) {
245 struct rt6_info *rt; 246 struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0);
246 247
247 rt = rt6_lookup(net, group, NULL, 0, 0);
248 if (rt) { 248 if (rt) {
249 dev = rt->rt6i_dev; 249 dev = rt->rt6i_dev;
250 dev_hold(dev); 250 dev_hold(dev);
251 dst_release(&rt->u.dst); 251 dst_release(&rt->u.dst);
252 } 252 }
253 } else 253 } else
254 dev = dev_get_by_index(net, ifindex); 254 dev = dev_get_by_index_rcu(net, ifindex);
255 255
256 if (!dev) 256 if (!dev)
257 goto nodev; 257 return NULL;
258 idev = in6_dev_get(dev); 258 idev = __in6_dev_get(dev);
259 if (!idev) 259 if (!idev)
260 goto release; 260 return NULL;;
261 read_lock_bh(&idev->lock); 261 read_lock_bh(&idev->lock);
262 if (idev->dead) 262 if (idev->dead) {
263 goto unlock_release; 263 read_unlock_bh(&idev->lock);
264 264 return NULL;
265 }
265 return idev; 266 return idev;
266
267unlock_release:
268 read_unlock_bh(&idev->lock);
269 in6_dev_put(idev);
270release:
271 dev_put(dev);
272nodev:
273 return NULL;
274} 267}
275 268
276void ipv6_sock_mc_close(struct sock *sk) 269void ipv6_sock_mc_close(struct sock *sk)
@@ -286,19 +279,17 @@ void ipv6_sock_mc_close(struct sock *sk)
286 np->ipv6_mc_list = mc_lst->next; 279 np->ipv6_mc_list = mc_lst->next;
287 write_unlock_bh(&ipv6_sk_mc_lock); 280 write_unlock_bh(&ipv6_sk_mc_lock);
288 281
289 dev = dev_get_by_index(net, mc_lst->ifindex); 282 rcu_read_lock();
283 dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
290 if (dev) { 284 if (dev) {
291 struct inet6_dev *idev = in6_dev_get(dev); 285 struct inet6_dev *idev = __in6_dev_get(dev);
292 286
293 (void) ip6_mc_leave_src(sk, mc_lst, idev); 287 (void) ip6_mc_leave_src(sk, mc_lst, idev);
294 if (idev) { 288 if (idev)
295 __ipv6_dev_mc_dec(idev, &mc_lst->addr); 289 __ipv6_dev_mc_dec(idev, &mc_lst->addr);
296 in6_dev_put(idev);
297 }
298 dev_put(dev);
299 } else 290 } else
300 (void) ip6_mc_leave_src(sk, mc_lst, NULL); 291 (void) ip6_mc_leave_src(sk, mc_lst, NULL);
301 292 rcu_read_unlock();
302 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 293 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
303 294
304 write_lock_bh(&ipv6_sk_mc_lock); 295 write_lock_bh(&ipv6_sk_mc_lock);
@@ -327,14 +318,17 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
327 if (!ipv6_addr_is_multicast(group)) 318 if (!ipv6_addr_is_multicast(group))
328 return -EINVAL; 319 return -EINVAL;
329 320
330 idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface); 321 rcu_read_lock();
331 if (!idev) 322 idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface);
323 if (!idev) {
324 rcu_read_unlock();
332 return -ENODEV; 325 return -ENODEV;
326 }
333 dev = idev->dev; 327 dev = idev->dev;
334 328
335 err = -EADDRNOTAVAIL; 329 err = -EADDRNOTAVAIL;
336 330
337 read_lock_bh(&ipv6_sk_mc_lock); 331 read_lock(&ipv6_sk_mc_lock);
338 for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { 332 for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
339 if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) 333 if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
340 continue; 334 continue;
@@ -358,7 +352,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
358 pmc->sfmode = omode; 352 pmc->sfmode = omode;
359 } 353 }
360 354
361 write_lock_bh(&pmc->sflock); 355 write_lock(&pmc->sflock);
362 pmclocked = 1; 356 pmclocked = 1;
363 357
364 psl = pmc->sflist; 358 psl = pmc->sflist;
@@ -433,11 +427,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
433 ip6_mc_add_src(idev, group, omode, 1, source, 1); 427 ip6_mc_add_src(idev, group, omode, 1, source, 1);
434done: 428done:
435 if (pmclocked) 429 if (pmclocked)
436 write_unlock_bh(&pmc->sflock); 430 write_unlock(&pmc->sflock);
437 read_unlock_bh(&ipv6_sk_mc_lock); 431 read_unlock(&ipv6_sk_mc_lock);
438 read_unlock_bh(&idev->lock); 432 read_unlock_bh(&idev->lock);
439 in6_dev_put(idev); 433 rcu_read_unlock();
440 dev_put(dev);
441 if (leavegroup) 434 if (leavegroup)
442 return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); 435 return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
443 return err; 436 return err;
@@ -463,14 +456,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
463 gsf->gf_fmode != MCAST_EXCLUDE) 456 gsf->gf_fmode != MCAST_EXCLUDE)
464 return -EINVAL; 457 return -EINVAL;
465 458
466 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);
467 461
468 if (!idev) 462 if (!idev) {
463 rcu_read_unlock();
469 return -ENODEV; 464 return -ENODEV;
465 }
470 dev = idev->dev; 466 dev = idev->dev;
471 467
472 err = 0; 468 err = 0;
473 read_lock_bh(&ipv6_sk_mc_lock); 469 read_lock(&ipv6_sk_mc_lock);
474 470
475 if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { 471 if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
476 leavegroup = 1; 472 leavegroup = 1;
@@ -512,7 +508,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
512 (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);
513 } 509 }
514 510
515 write_lock_bh(&pmc->sflock); 511 write_lock(&pmc->sflock);
516 psl = pmc->sflist; 512 psl = pmc->sflist;
517 if (psl) { 513 if (psl) {
518 (void) ip6_mc_del_src(idev, group, pmc->sfmode, 514 (void) ip6_mc_del_src(idev, group, pmc->sfmode,
@@ -522,13 +518,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
522 (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);
523 pmc->sflist = newpsl; 519 pmc->sflist = newpsl;
524 pmc->sfmode = gsf->gf_fmode; 520 pmc->sfmode = gsf->gf_fmode;
525 write_unlock_bh(&pmc->sflock); 521 write_unlock(&pmc->sflock);
526 err = 0; 522 err = 0;
527done: 523done:
528 read_unlock_bh(&ipv6_sk_mc_lock); 524 read_unlock(&ipv6_sk_mc_lock);
529 read_unlock_bh(&idev->lock); 525 read_unlock_bh(&idev->lock);
530 in6_dev_put(idev); 526 rcu_read_unlock();
531 dev_put(dev);
532 if (leavegroup) 527 if (leavegroup)
533 err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group); 528 err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
534 return err; 529 return err;
@@ -551,11 +546,13 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
551 if (!ipv6_addr_is_multicast(group)) 546 if (!ipv6_addr_is_multicast(group))
552 return -EINVAL; 547 return -EINVAL;
553 548
554 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);
555 551
556 if (!idev) 552 if (!idev) {
553 rcu_read_unlock();
557 return -ENODEV; 554 return -ENODEV;
558 555 }
559 dev = idev->dev; 556 dev = idev->dev;
560 557
561 err = -EADDRNOTAVAIL; 558 err = -EADDRNOTAVAIL;
@@ -577,8 +574,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
577 psl = pmc->sflist; 574 psl = pmc->sflist;
578 count = psl ? psl->sl_count : 0; 575 count = psl ? psl->sl_count : 0;
579 read_unlock_bh(&idev->lock); 576 read_unlock_bh(&idev->lock);
580 in6_dev_put(idev); 577 rcu_read_unlock();
581 dev_put(dev);
582 578
583 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; 579 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
584 gsf->gf_numsrc = count; 580 gsf->gf_numsrc = count;
@@ -604,8 +600,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
604 return 0; 600 return 0;
605done: 601done:
606 read_unlock_bh(&idev->lock); 602 read_unlock_bh(&idev->lock);
607 in6_dev_put(idev); 603 rcu_read_unlock();
608 dev_put(dev);
609 return err; 604 return err;
610} 605}
611 606
@@ -822,6 +817,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
822 struct ifmcaddr6 *mc; 817 struct ifmcaddr6 *mc;
823 struct inet6_dev *idev; 818 struct inet6_dev *idev;
824 819
820 /* we need to take a reference on idev */
825 idev = in6_dev_get(dev); 821 idev = in6_dev_get(dev);
826 822
827 if (idev == NULL) 823 if (idev == NULL)
@@ -860,7 +856,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
860 setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); 856 setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
861 857
862 ipv6_addr_copy(&mc->mca_addr, addr); 858 ipv6_addr_copy(&mc->mca_addr, addr);
863 mc->idev = idev; 859 mc->idev = idev; /* (reference taken) */
864 mc->mca_users = 1; 860 mc->mca_users = 1;
865 /* mca_stamp should be updated upon changes */ 861 /* mca_stamp should be updated upon changes */
866 mc->mca_cstamp = mc->mca_tstamp = jiffies; 862 mc->mca_cstamp = mc->mca_tstamp = jiffies;
@@ -915,16 +911,18 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
915 911
916int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) 912int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
917{ 913{
918 struct inet6_dev *idev = in6_dev_get(dev); 914 struct inet6_dev *idev;
919 int err; 915 int err;
920 916
921 if (!idev) 917 rcu_read_lock();
922 return -ENODEV;
923
924 err = __ipv6_dev_mc_dec(idev, addr);
925 918
926 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);
927 924
925 rcu_read_unlock();
928 return err; 926 return err;
929} 927}
930 928
@@ -965,7 +963,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
965 struct ifmcaddr6 *mc; 963 struct ifmcaddr6 *mc;
966 int rv = 0; 964 int rv = 0;
967 965
968 idev = in6_dev_get(dev); 966 rcu_read_lock();
967 idev = __in6_dev_get(dev);
969 if (idev) { 968 if (idev) {
970 read_lock_bh(&idev->lock); 969 read_lock_bh(&idev->lock);
971 for (mc = idev->mc_list; mc; mc=mc->next) { 970 for (mc = idev->mc_list; mc; mc=mc->next) {
@@ -992,8 +991,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
992 rv = 1; /* don't filter unspecified source */ 991 rv = 1; /* don't filter unspecified source */
993 } 992 }
994 read_unlock_bh(&idev->lock); 993 read_unlock_bh(&idev->lock);
995 in6_dev_put(idev);
996 } 994 }
995 rcu_read_unlock();
997 return rv; 996 return rv;
998} 997}
999 998
@@ -1104,6 +1103,7 @@ static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
1104 return 1; 1103 return 1;
1105} 1104}
1106 1105
1106/* called with rcu_read_lock() */
1107int igmp6_event_query(struct sk_buff *skb) 1107int igmp6_event_query(struct sk_buff *skb)
1108{ 1108{
1109 struct mld2_query *mlh2 = NULL; 1109 struct mld2_query *mlh2 = NULL;
@@ -1127,7 +1127,7 @@ int igmp6_event_query(struct sk_buff *skb)
1127 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) 1127 if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
1128 return -EINVAL; 1128 return -EINVAL;
1129 1129
1130 idev = in6_dev_get(skb->dev); 1130 idev = __in6_dev_get(skb->dev);
1131 1131
1132 if (idev == NULL) 1132 if (idev == NULL)
1133 return 0; 1133 return 0;
@@ -1137,10 +1137,8 @@ int igmp6_event_query(struct sk_buff *skb)
1137 group_type = ipv6_addr_type(group); 1137 group_type = ipv6_addr_type(group);
1138 1138
1139 if (group_type != IPV6_ADDR_ANY && 1139 if (group_type != IPV6_ADDR_ANY &&
1140 !(group_type&IPV6_ADDR_MULTICAST)) { 1140 !(group_type&IPV6_ADDR_MULTICAST))
1141 in6_dev_put(idev);
1142 return -EINVAL; 1141 return -EINVAL;
1143 }
1144 1142
1145 if (len == 24) { 1143 if (len == 24) {
1146 int switchback; 1144 int switchback;
@@ -1161,10 +1159,9 @@ int igmp6_event_query(struct sk_buff *skb)
1161 } else if (len >= 28) { 1159 } else if (len >= 28) {
1162 int srcs_offset = sizeof(struct mld2_query) - 1160 int srcs_offset = sizeof(struct mld2_query) -
1163 sizeof(struct icmp6hdr); 1161 sizeof(struct icmp6hdr);
1164 if (!pskb_may_pull(skb, srcs_offset)) { 1162 if (!pskb_may_pull(skb, srcs_offset))
1165 in6_dev_put(idev);
1166 return -EINVAL; 1163 return -EINVAL;
1167 } 1164
1168 mlh2 = (struct mld2_query *)skb_transport_header(skb); 1165 mlh2 = (struct mld2_query *)skb_transport_header(skb);
1169 max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000; 1166 max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
1170 if (!max_delay) 1167 if (!max_delay)
@@ -1173,28 +1170,23 @@ int igmp6_event_query(struct sk_buff *skb)
1173 if (mlh2->mld2q_qrv) 1170 if (mlh2->mld2q_qrv)
1174 idev->mc_qrv = mlh2->mld2q_qrv; 1171 idev->mc_qrv = mlh2->mld2q_qrv;
1175 if (group_type == IPV6_ADDR_ANY) { /* general query */ 1172 if (group_type == IPV6_ADDR_ANY) { /* general query */
1176 if (mlh2->mld2q_nsrcs) { 1173 if (mlh2->mld2q_nsrcs)
1177 in6_dev_put(idev);
1178 return -EINVAL; /* no sources allowed */ 1174 return -EINVAL; /* no sources allowed */
1179 } 1175
1180 mld_gq_start_timer(idev); 1176 mld_gq_start_timer(idev);
1181 in6_dev_put(idev);
1182 return 0; 1177 return 0;
1183 } 1178 }
1184 /* mark sources to include, if group & source-specific */ 1179 /* mark sources to include, if group & source-specific */
1185 if (mlh2->mld2q_nsrcs != 0) { 1180 if (mlh2->mld2q_nsrcs != 0) {
1186 if (!pskb_may_pull(skb, srcs_offset + 1181 if (!pskb_may_pull(skb, srcs_offset +
1187 ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) { 1182 ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr)))
1188 in6_dev_put(idev);
1189 return -EINVAL; 1183 return -EINVAL;
1190 } 1184
1191 mlh2 = (struct mld2_query *)skb_transport_header(skb); 1185 mlh2 = (struct mld2_query *)skb_transport_header(skb);
1192 mark = 1; 1186 mark = 1;
1193 } 1187 }
1194 } else { 1188 } else
1195 in6_dev_put(idev);
1196 return -EINVAL; 1189 return -EINVAL;
1197 }
1198 1190
1199 read_lock_bh(&idev->lock); 1191 read_lock_bh(&idev->lock);
1200 if (group_type == IPV6_ADDR_ANY) { 1192 if (group_type == IPV6_ADDR_ANY) {
@@ -1227,12 +1219,11 @@ int igmp6_event_query(struct sk_buff *skb)
1227 } 1219 }
1228 } 1220 }
1229 read_unlock_bh(&idev->lock); 1221 read_unlock_bh(&idev->lock);
1230 in6_dev_put(idev);
1231 1222
1232 return 0; 1223 return 0;
1233} 1224}
1234 1225
1235 1226/* called with rcu_read_lock() */
1236int igmp6_event_report(struct sk_buff *skb) 1227int igmp6_event_report(struct sk_buff *skb)
1237{ 1228{
1238 struct ifmcaddr6 *ma; 1229 struct ifmcaddr6 *ma;
@@ -1260,7 +1251,7 @@ int igmp6_event_report(struct sk_buff *skb)
1260 !(addr_type&IPV6_ADDR_LINKLOCAL)) 1251 !(addr_type&IPV6_ADDR_LINKLOCAL))
1261 return -EINVAL; 1252 return -EINVAL;
1262 1253
1263 idev = in6_dev_get(skb->dev); 1254 idev = __in6_dev_get(skb->dev);
1264 if (idev == NULL) 1255 if (idev == NULL)
1265 return -ENODEV; 1256 return -ENODEV;
1266 1257
@@ -1280,7 +1271,6 @@ int igmp6_event_report(struct sk_buff *skb)
1280 } 1271 }
1281 } 1272 }
1282 read_unlock_bh(&idev->lock); 1273 read_unlock_bh(&idev->lock);
1283 in6_dev_put(idev);
1284 return 0; 1274 return 0;
1285} 1275}
1286 1276
@@ -1396,12 +1386,14 @@ static void mld_sendpack(struct sk_buff *skb)
1396 struct mld2_report *pmr = 1386 struct mld2_report *pmr =
1397 (struct mld2_report *)skb_transport_header(skb); 1387 (struct mld2_report *)skb_transport_header(skb);
1398 int payload_len, mldlen; 1388 int payload_len, mldlen;
1399 struct inet6_dev *idev = in6_dev_get(skb->dev); 1389 struct inet6_dev *idev;
1400 struct net *net = dev_net(skb->dev); 1390 struct net *net = dev_net(skb->dev);
1401 int err; 1391 int err;
1402 struct flowi fl; 1392 struct flowi fl;
1403 struct dst_entry *dst; 1393 struct dst_entry *dst;
1404 1394
1395 rcu_read_lock();
1396 idev = __in6_dev_get(skb->dev);
1405 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); 1397 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
1406 1398
1407 payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); 1399 payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
@@ -1441,8 +1433,7 @@ out:
1441 } else 1433 } else
1442 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS); 1434 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
1443 1435
1444 if (likely(idev != NULL)) 1436 rcu_read_unlock();
1445 in6_dev_put(idev);
1446 return; 1437 return;
1447 1438
1448err_out: 1439err_out:
@@ -1779,7 +1770,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1779 IPPROTO_ICMPV6, 1770 IPPROTO_ICMPV6,
1780 csum_partial(hdr, len, 0)); 1771 csum_partial(hdr, len, 0));
1781 1772
1782 idev = in6_dev_get(skb->dev); 1773 rcu_read_lock();
1774 idev = __in6_dev_get(skb->dev);
1783 1775
1784 dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); 1776 dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
1785 if (!dst) { 1777 if (!dst) {
@@ -1806,8 +1798,7 @@ out:
1806 } else 1798 } else
1807 IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); 1799 IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
1808 1800
1809 if (likely(idev != NULL)) 1801 rcu_read_unlock();
1810 in6_dev_put(idev);
1811 return; 1802 return;
1812 1803
1813err_out: 1804err_out: