diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 865d75214a9a..9e1bd374875e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -928,23 +928,32 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
928 | return 1; | 928 | return 1; |
929 | #else | 929 | #else |
930 | struct udp_sock *up = udp_sk(sk); | 930 | struct udp_sock *up = udp_sk(sk); |
931 | struct udphdr *uh = skb->h.uh; | 931 | struct udphdr *uh; |
932 | struct iphdr *iph; | 932 | struct iphdr *iph; |
933 | int iphlen, len; | 933 | int iphlen, len; |
934 | 934 | ||
935 | __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr); | 935 | __u8 *udpdata; |
936 | __be32 *udpdata32 = (__be32 *)udpdata; | 936 | __be32 *udpdata32; |
937 | __u16 encap_type = up->encap_type; | 937 | __u16 encap_type = up->encap_type; |
938 | 938 | ||
939 | /* if we're overly short, let UDP handle it */ | 939 | /* if we're overly short, let UDP handle it */ |
940 | if (udpdata > skb->tail) | 940 | len = skb->len - sizeof(struct udphdr); |
941 | if (len <= 0) | ||
941 | return 1; | 942 | return 1; |
942 | 943 | ||
943 | /* if this is not encapsulated socket, then just return now */ | 944 | /* if this is not encapsulated socket, then just return now */ |
944 | if (!encap_type) | 945 | if (!encap_type) |
945 | return 1; | 946 | return 1; |
946 | 947 | ||
947 | len = skb->tail - udpdata; | 948 | /* If this is a paged skb, make sure we pull up |
949 | * whatever data we need to look at. */ | ||
950 | if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) | ||
951 | return 1; | ||
952 | |||
953 | /* Now we can get the pointers */ | ||
954 | uh = skb->h.uh; | ||
955 | udpdata = (__u8 *)uh + sizeof(struct udphdr); | ||
956 | udpdata32 = (__be32 *)udpdata; | ||
948 | 957 | ||
949 | switch (encap_type) { | 958 | switch (encap_type) { |
950 | default: | 959 | default: |