aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/igmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r--net/ipv4/igmp.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 6699f23e6f55..736ab70fd179 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -815,14 +815,15 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
815 return 1; 815 return 1;
816} 816}
817 817
818static void igmp_heard_report(struct in_device *in_dev, __be32 group) 818/* return true if packet was dropped */
819static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
819{ 820{
820 struct ip_mc_list *im; 821 struct ip_mc_list *im;
821 822
822 /* Timers are only set for non-local groups */ 823 /* Timers are only set for non-local groups */
823 824
824 if (group == IGMP_ALL_HOSTS) 825 if (group == IGMP_ALL_HOSTS)
825 return; 826 return false;
826 827
827 rcu_read_lock(); 828 rcu_read_lock();
828 for_each_pmc_rcu(in_dev, im) { 829 for_each_pmc_rcu(in_dev, im) {
@@ -832,9 +833,11 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group)
832 } 833 }
833 } 834 }
834 rcu_read_unlock(); 835 rcu_read_unlock();
836 return false;
835} 837}
836 838
837static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, 839/* return true if packet was dropped */
840static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
838 int len) 841 int len)
839{ 842{
840 struct igmphdr *ih = igmp_hdr(skb); 843 struct igmphdr *ih = igmp_hdr(skb);
@@ -866,7 +869,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
866 /* clear deleted report items */ 869 /* clear deleted report items */
867 igmpv3_clear_delrec(in_dev); 870 igmpv3_clear_delrec(in_dev);
868 } else if (len < 12) { 871 } else if (len < 12) {
869 return; /* ignore bogus packet; freed by caller */ 872 return true; /* ignore bogus packet; freed by caller */
870 } else if (IGMP_V1_SEEN(in_dev)) { 873 } else if (IGMP_V1_SEEN(in_dev)) {
871 /* This is a v3 query with v1 queriers present */ 874 /* This is a v3 query with v1 queriers present */
872 max_delay = IGMP_Query_Response_Interval; 875 max_delay = IGMP_Query_Response_Interval;
@@ -883,13 +886,13 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
883 max_delay = 1; /* can't mod w/ 0 */ 886 max_delay = 1; /* can't mod w/ 0 */
884 } else { /* v3 */ 887 } else { /* v3 */
885 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) 888 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
886 return; 889 return true;
887 890
888 ih3 = igmpv3_query_hdr(skb); 891 ih3 = igmpv3_query_hdr(skb);
889 if (ih3->nsrcs) { 892 if (ih3->nsrcs) {
890 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) 893 if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
891 + ntohs(ih3->nsrcs)*sizeof(__be32))) 894 + ntohs(ih3->nsrcs)*sizeof(__be32)))
892 return; 895 return true;
893 ih3 = igmpv3_query_hdr(skb); 896 ih3 = igmpv3_query_hdr(skb);
894 } 897 }
895 898
@@ -901,9 +904,9 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
901 in_dev->mr_qrv = ih3->qrv; 904 in_dev->mr_qrv = ih3->qrv;
902 if (!group) { /* general query */ 905 if (!group) { /* general query */
903 if (ih3->nsrcs) 906 if (ih3->nsrcs)
904 return; /* no sources allowed */ 907 return false; /* no sources allowed */
905 igmp_gq_start_timer(in_dev); 908 igmp_gq_start_timer(in_dev);
906 return; 909 return false;
907 } 910 }
908 /* mark sources to include, if group & source-specific */ 911 /* mark sources to include, if group & source-specific */
909 mark = ih3->nsrcs != 0; 912 mark = ih3->nsrcs != 0;
@@ -939,6 +942,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
939 igmp_mod_timer(im, max_delay); 942 igmp_mod_timer(im, max_delay);
940 } 943 }
941 rcu_read_unlock(); 944 rcu_read_unlock();
945 return false;
942} 946}
943 947
944/* called in rcu_read_lock() section */ 948/* called in rcu_read_lock() section */
@@ -948,6 +952,7 @@ int igmp_rcv(struct sk_buff *skb)
948 struct igmphdr *ih; 952 struct igmphdr *ih;
949 struct in_device *in_dev = __in_dev_get_rcu(skb->dev); 953 struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
950 int len = skb->len; 954 int len = skb->len;
955 bool dropped = true;
951 956
952 if (in_dev == NULL) 957 if (in_dev == NULL)
953 goto drop; 958 goto drop;
@@ -969,7 +974,7 @@ int igmp_rcv(struct sk_buff *skb)
969 ih = igmp_hdr(skb); 974 ih = igmp_hdr(skb);
970 switch (ih->type) { 975 switch (ih->type) {
971 case IGMP_HOST_MEMBERSHIP_QUERY: 976 case IGMP_HOST_MEMBERSHIP_QUERY:
972 igmp_heard_query(in_dev, skb, len); 977 dropped = igmp_heard_query(in_dev, skb, len);
973 break; 978 break;
974 case IGMP_HOST_MEMBERSHIP_REPORT: 979 case IGMP_HOST_MEMBERSHIP_REPORT:
975 case IGMPV2_HOST_MEMBERSHIP_REPORT: 980 case IGMPV2_HOST_MEMBERSHIP_REPORT:
@@ -979,7 +984,7 @@ int igmp_rcv(struct sk_buff *skb)
979 /* don't rely on MC router hearing unicast reports */ 984 /* don't rely on MC router hearing unicast reports */
980 if (skb->pkt_type == PACKET_MULTICAST || 985 if (skb->pkt_type == PACKET_MULTICAST ||
981 skb->pkt_type == PACKET_BROADCAST) 986 skb->pkt_type == PACKET_BROADCAST)
982 igmp_heard_report(in_dev, ih->group); 987 dropped = igmp_heard_report(in_dev, ih->group);
983 break; 988 break;
984 case IGMP_PIM: 989 case IGMP_PIM:
985#ifdef CONFIG_IP_PIMSM_V1 990#ifdef CONFIG_IP_PIMSM_V1
@@ -997,7 +1002,10 @@ int igmp_rcv(struct sk_buff *skb)
997 } 1002 }
998 1003
999drop: 1004drop:
1000 kfree_skb(skb); 1005 if (dropped)
1006 kfree_skb(skb);
1007 else
1008 consume_skb(skb);
1001 return 0; 1009 return 0;
1002} 1010}
1003 1011
@@ -1896,6 +1904,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
1896 rtnl_unlock(); 1904 rtnl_unlock();
1897 return ret; 1905 return ret;
1898} 1906}
1907EXPORT_SYMBOL(ip_mc_leave_group);
1899 1908
1900int ip_mc_source(int add, int omode, struct sock *sk, struct 1909int ip_mc_source(int add, int omode, struct sock *sk, struct
1901 ip_mreq_source *mreqs, int ifindex) 1910 ip_mreq_source *mreqs, int ifindex)
@@ -2435,6 +2444,8 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
2435 struct ip_mc_list *im = (struct ip_mc_list *)v; 2444 struct ip_mc_list *im = (struct ip_mc_list *)v;
2436 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); 2445 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
2437 char *querier; 2446 char *querier;
2447 long delta;
2448
2438#ifdef CONFIG_IP_MULTICAST 2449#ifdef CONFIG_IP_MULTICAST
2439 querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : 2450 querier = IGMP_V1_SEEN(state->in_dev) ? "V1" :
2440 IGMP_V2_SEEN(state->in_dev) ? "V2" : 2451 IGMP_V2_SEEN(state->in_dev) ? "V2" :
@@ -2448,11 +2459,12 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
2448 state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); 2459 state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
2449 } 2460 }
2450 2461
2462 delta = im->timer.expires - jiffies;
2451 seq_printf(seq, 2463 seq_printf(seq,
2452 "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n", 2464 "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n",
2453 im->multiaddr, im->users, 2465 im->multiaddr, im->users,
2454 im->tm_running, im->tm_running ? 2466 im->tm_running,
2455 jiffies_to_clock_t(im->timer.expires-jiffies) : 0, 2467 im->tm_running ? jiffies_delta_to_clock_t(delta) : 0,
2456 im->reporter); 2468 im->reporter);
2457 } 2469 }
2458 return 0; 2470 return 0;