diff options
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r-- | net/ipv4/igmp.c | 38 |
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 | ||
818 | static void igmp_heard_report(struct in_device *in_dev, __be32 group) | 818 | /* return true if packet was dropped */ |
819 | static 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 | ||
837 | static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | 839 | /* return true if packet was dropped */ |
840 | static 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 | ||
999 | drop: | 1004 | drop: |
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 | } |
1907 | EXPORT_SYMBOL(ip_mc_leave_group); | ||
1899 | 1908 | ||
1900 | int ip_mc_source(int add, int omode, struct sock *sk, struct | 1909 | int 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; |