diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2009-07-09 04:10:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-12 17:29:29 -0400 |
commit | ba73542585a4a3c8a708f502e62e6e63dd74b66c (patch) | |
tree | 5dbb997e5f2f0eeb1cbc03000f8121b322b254cd /net/ipv6/af_inet6.c | |
parent | 7ea2f2c5a66e4e9a8d96296ac47ad895c467ee1d (diff) |
udpv6: Handle large incoming UDP/IPv6 packets and support software UFO
- validate and forward GSO UDP/IPv6 packets from untrusted sources.
- do software UFO if the outgoing device doesn't support UFO.
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/af_inet6.c')
-rw-r--r-- | net/ipv6/af_inet6.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index caa0278d30a9..bf85d5f97032 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -772,6 +772,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
772 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 772 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
773 | struct ipv6hdr *ipv6h; | 773 | struct ipv6hdr *ipv6h; |
774 | struct inet6_protocol *ops; | 774 | struct inet6_protocol *ops; |
775 | int proto; | ||
776 | struct frag_hdr *fptr; | ||
777 | unsigned int unfrag_ip6hlen; | ||
778 | u8 *prevhdr; | ||
779 | int offset = 0; | ||
775 | 780 | ||
776 | if (!(features & NETIF_F_V6_CSUM)) | 781 | if (!(features & NETIF_F_V6_CSUM)) |
777 | features &= ~NETIF_F_SG; | 782 | features &= ~NETIF_F_SG; |
@@ -791,10 +796,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
791 | __skb_pull(skb, sizeof(*ipv6h)); | 796 | __skb_pull(skb, sizeof(*ipv6h)); |
792 | segs = ERR_PTR(-EPROTONOSUPPORT); | 797 | segs = ERR_PTR(-EPROTONOSUPPORT); |
793 | 798 | ||
799 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
794 | rcu_read_lock(); | 800 | rcu_read_lock(); |
795 | ops = rcu_dereference(inet6_protos[ | 801 | ops = rcu_dereference(inet6_protos[proto]); |
796 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
797 | |||
798 | if (likely(ops && ops->gso_segment)) { | 802 | if (likely(ops && ops->gso_segment)) { |
799 | skb_reset_transport_header(skb); | 803 | skb_reset_transport_header(skb); |
800 | segs = ops->gso_segment(skb, features); | 804 | segs = ops->gso_segment(skb, features); |
@@ -808,6 +812,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
808 | ipv6h = ipv6_hdr(skb); | 812 | ipv6h = ipv6_hdr(skb); |
809 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | 813 | ipv6h->payload_len = htons(skb->len - skb->mac_len - |
810 | sizeof(*ipv6h)); | 814 | sizeof(*ipv6h)); |
815 | if (proto == IPPROTO_UDP) { | ||
816 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
817 | fptr = (struct frag_hdr *)(skb_network_header(skb) + | ||
818 | unfrag_ip6hlen); | ||
819 | fptr->frag_off = htons(offset); | ||
820 | if (skb->next != NULL) | ||
821 | fptr->frag_off |= htons(IP6_MF); | ||
822 | offset += (ntohs(ipv6h->payload_len) - | ||
823 | sizeof(struct frag_hdr)); | ||
824 | } | ||
811 | } | 825 | } |
812 | 826 | ||
813 | out: | 827 | out: |