[PATCH 2.5.72] Igmp w/o linearize.
From: Stephen Hemminger <hidden>
Date: 2003-06-25 16:32:16
Here is the updated igmp patch, thanks to dlstevens for testing this. # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1386 -> 1.1387 # net/ipv4/igmp.c 1.26 -> 1.27 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/06/25 shemminger@osdl.org 1.1387 # IGMP no linearize # -------------------------------------------- # diff -Nru a/net/ipv4/igmp.c b/net/ipv4/igmp.c
--- a/net/ipv4/igmp.c Wed Jun 25 09:27:47 2003
+++ b/net/ipv4/igmp.c Wed Jun 25 09:27:47 2003@@ -757,9 +757,10 @@ read_unlock(&in_dev->lock); } -static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih, +static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, int len) { + struct igmphdr *ih = skb->h.igmph; struct igmpv3_query *ih3 = (struct igmpv3_query *)ih; struct ip_mc_list *im; u32 group = ih->group;
@@ -790,6 +791,17 @@ } else if (len < 12) { return; /* ignore bogus packet; freed by caller */ } else { /* v3 */ + if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) + return; + + ih3 = (struct igmpv3_query *) skb->h.raw; + if (ih3->nsrcs) { + if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) + + ntohs(ih3->nsrcs)*sizeof(__u32))) + return; + ih3 = (struct igmpv3_query *) skb->h.raw; + } + max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); if (!max_delay) max_delay = 1; /* can't mod w/ 0 */
@@ -838,7 +850,7 @@ int igmp_rcv(struct sk_buff *skb) { /* This basically follows the spec line by line -- see RFC1112 */ - struct igmphdr *ih = skb->h.igmph; + struct igmphdr *ih; struct in_device *in_dev = in_dev_get(skb->dev); int len = skb->len;
@@ -847,23 +859,17 @@ return 0; } - if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) { - kfree_skb(skb); - return -ENOMEM; - } - ih = skb->h.igmph; - } - - if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) { + if (!pskb_may_pull(skb, sizeof(struct igmphdr)) || + (u16)csum_fold(skb_checksum(skb, 0, len, 0))) { in_dev_put(in_dev); kfree_skb(skb); return 0; } + ih = skb->h.igmph; switch (ih->type) { case IGMP_HOST_MEMBERSHIP_QUERY: - igmp_heard_query(in_dev, ih, len); + igmp_heard_query(in_dev, skb, len); break; case IGMP_HOST_MEMBERSHIP_REPORT: case IGMPV2_HOST_MEMBERSHIP_REPORT: