@@ -81,7 +81,7 @@ static void mld_gq_timer_expire(unsigned long data);
81
81
static void mld_ifc_timer_expire (unsigned long data );
82
82
static void mld_ifc_event (struct inet6_dev * idev );
83
83
static void mld_add_delrec (struct inet6_dev * idev , struct ifmcaddr6 * pmc );
84
- static void mld_del_delrec (struct inet6_dev * idev , const struct in6_addr * addr );
84
+ static void mld_del_delrec (struct inet6_dev * idev , struct ifmcaddr6 * pmc );
85
85
static void mld_clear_delrec (struct inet6_dev * idev );
86
86
static bool mld_in_v1_mode (const struct inet6_dev * idev );
87
87
static int sf_setstate (struct ifmcaddr6 * pmc );
@@ -692,18 +692,16 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)
692
692
dev_mc_del (dev , buf );
693
693
}
694
694
695
- if (mc -> mca_flags & MAF_NOREPORT )
696
- goto done ;
697
695
spin_unlock_bh (& mc -> mca_lock );
696
+ if (mc -> mca_flags & MAF_NOREPORT )
697
+ return ;
698
698
699
699
if (!mc -> idev -> dead )
700
700
igmp6_leave_group (mc );
701
701
702
702
spin_lock_bh (& mc -> mca_lock );
703
703
if (del_timer (& mc -> mca_timer ))
704
704
atomic_dec (& mc -> mca_refcnt );
705
- done :
706
- ip6_mc_clear_src (mc );
707
705
spin_unlock_bh (& mc -> mca_lock );
708
706
}
709
707
@@ -748,10 +746,11 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
748
746
spin_unlock_bh (& idev -> mc_lock );
749
747
}
750
748
751
- static void mld_del_delrec (struct inet6_dev * idev , const struct in6_addr * pmca )
749
+ static void mld_del_delrec (struct inet6_dev * idev , struct ifmcaddr6 * im )
752
750
{
753
751
struct ifmcaddr6 * pmc , * pmc_prev ;
754
- struct ip6_sf_list * psf , * psf_next ;
752
+ struct ip6_sf_list * psf ;
753
+ struct in6_addr * pmca = & im -> mca_addr ;
755
754
756
755
spin_lock_bh (& idev -> mc_lock );
757
756
pmc_prev = NULL ;
@@ -768,14 +767,20 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
768
767
}
769
768
spin_unlock_bh (& idev -> mc_lock );
770
769
770
+ spin_lock_bh (& im -> mca_lock );
771
771
if (pmc ) {
772
- for (psf = pmc -> mca_tomb ; psf ; psf = psf_next ) {
773
- psf_next = psf -> sf_next ;
774
- kfree (psf );
772
+ im -> idev = pmc -> idev ;
773
+ im -> mca_crcount = idev -> mc_qrv ;
774
+ im -> mca_sfmode = pmc -> mca_sfmode ;
775
+ if (pmc -> mca_sfmode == MCAST_INCLUDE ) {
776
+ im -> mca_tomb = pmc -> mca_tomb ;
777
+ im -> mca_sources = pmc -> mca_sources ;
778
+ for (psf = im -> mca_sources ; psf ; psf = psf -> sf_next )
779
+ psf -> sf_crcount = im -> mca_crcount ;
775
780
}
776
781
in6_dev_put (pmc -> idev );
777
- kfree (pmc );
778
782
}
783
+ spin_unlock_bh (& im -> mca_lock );
779
784
}
780
785
781
786
static void mld_clear_delrec (struct inet6_dev * idev )
@@ -904,7 +909,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
904
909
mca_get (mc );
905
910
write_unlock_bh (& idev -> lock );
906
911
907
- mld_del_delrec (idev , & mc -> mca_addr );
912
+ mld_del_delrec (idev , mc );
908
913
igmp6_group_added (mc );
909
914
ma_put (mc );
910
915
return 0 ;
@@ -927,6 +932,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
927
932
write_unlock_bh (& idev -> lock );
928
933
929
934
igmp6_group_dropped (ma );
935
+ ip6_mc_clear_src (ma );
930
936
931
937
ma_put (ma );
932
938
return 0 ;
@@ -2501,15 +2507,17 @@ void ipv6_mc_down(struct inet6_dev *idev)
2501
2507
/* Withdraw multicast list */
2502
2508
2503
2509
read_lock_bh (& idev -> lock );
2504
- mld_ifc_stop_timer (idev );
2505
- mld_gq_stop_timer (idev );
2506
- mld_dad_stop_timer (idev );
2507
2510
2508
2511
for (i = idev -> mc_list ; i ; i = i -> next )
2509
2512
igmp6_group_dropped (i );
2510
- read_unlock_bh (& idev -> lock );
2511
2513
2512
- mld_clear_delrec (idev );
2514
+ /* Should stop timer after group drop. or we will
2515
+ * start timer again in mld_ifc_event()
2516
+ */
2517
+ mld_ifc_stop_timer (idev );
2518
+ mld_gq_stop_timer (idev );
2519
+ mld_dad_stop_timer (idev );
2520
+ read_unlock_bh (& idev -> lock );
2513
2521
}
2514
2522
2515
2523
static void ipv6_mc_reset (struct inet6_dev * idev )
@@ -2531,8 +2539,10 @@ void ipv6_mc_up(struct inet6_dev *idev)
2531
2539
2532
2540
read_lock_bh (& idev -> lock );
2533
2541
ipv6_mc_reset (idev );
2534
- for (i = idev -> mc_list ; i ; i = i -> next )
2542
+ for (i = idev -> mc_list ; i ; i = i -> next ) {
2543
+ mld_del_delrec (idev , i );
2535
2544
igmp6_group_added (i );
2545
+ }
2536
2546
read_unlock_bh (& idev -> lock );
2537
2547
}
2538
2548
@@ -2565,6 +2575,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
2565
2575
2566
2576
/* Deactivate timers */
2567
2577
ipv6_mc_down (idev );
2578
+ mld_clear_delrec (idev );
2568
2579
2569
2580
/* Delete all-nodes address. */
2570
2581
/* We cannot call ipv6_dev_mc_dec() directly, our caller in
@@ -2579,11 +2590,9 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
2579
2590
write_lock_bh (& idev -> lock );
2580
2591
while ((i = idev -> mc_list ) != NULL ) {
2581
2592
idev -> mc_list = i -> next ;
2582
- write_unlock_bh (& idev -> lock );
2583
2593
2584
- igmp6_group_dropped ( i );
2594
+ write_unlock_bh ( & idev -> lock );
2585
2595
ma_put (i );
2586
-
2587
2596
write_lock_bh (& idev -> lock );
2588
2597
}
2589
2598
write_unlock_bh (& idev -> lock );
0 commit comments