aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/af_inet6.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2009-07-09 04:10:04 -0400
committerDavid S. Miller <davem@davemloft.net>2009-07-12 17:29:29 -0400
commitba73542585a4a3c8a708f502e62e6e63dd74b66c (patch)
tree5dbb997e5f2f0eeb1cbc03000f8121b322b254cd /net/ipv6/af_inet6.c
parent7ea2f2c5a66e4e9a8d96296ac47ad895c467ee1d (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.c20
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
813out: 827out: