diff options
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 45f9a2a42d56..a123a328aeb3 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -774,6 +774,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
774 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 774 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
775 | struct ipv6hdr *ipv6h; | 775 | struct ipv6hdr *ipv6h; |
776 | struct inet6_protocol *ops; | 776 | struct inet6_protocol *ops; |
777 | int proto; | ||
778 | struct frag_hdr *fptr; | ||
779 | unsigned int unfrag_ip6hlen; | ||
780 | u8 *prevhdr; | ||
781 | int offset = 0; | ||
777 | 782 | ||
778 | if (!(features & NETIF_F_V6_CSUM)) | 783 | if (!(features & NETIF_F_V6_CSUM)) |
779 | features &= ~NETIF_F_SG; | 784 | features &= ~NETIF_F_SG; |
@@ -793,10 +798,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
793 | __skb_pull(skb, sizeof(*ipv6h)); | 798 | __skb_pull(skb, sizeof(*ipv6h)); |
794 | segs = ERR_PTR(-EPROTONOSUPPORT); | 799 | segs = ERR_PTR(-EPROTONOSUPPORT); |
795 | 800 | ||
801 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
796 | rcu_read_lock(); | 802 | rcu_read_lock(); |
797 | ops = rcu_dereference(inet6_protos[ | 803 | ops = rcu_dereference(inet6_protos[proto]); |
798 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
799 | |||
800 | if (likely(ops && ops->gso_segment)) { | 804 | if (likely(ops && ops->gso_segment)) { |
801 | skb_reset_transport_header(skb); | 805 | skb_reset_transport_header(skb); |
802 | segs = ops->gso_segment(skb, features); | 806 | segs = ops->gso_segment(skb, features); |
@@ -810,6 +814,16 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
810 | ipv6h = ipv6_hdr(skb); | 814 | ipv6h = ipv6_hdr(skb); |
811 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | 815 | ipv6h->payload_len = htons(skb->len - skb->mac_len - |
812 | sizeof(*ipv6h)); | 816 | sizeof(*ipv6h)); |
817 | if (proto == IPPROTO_UDP) { | ||
818 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | ||
819 | fptr = (struct frag_hdr *)(skb_network_header(skb) + | ||
820 | unfrag_ip6hlen); | ||
821 | fptr->frag_off = htons(offset); | ||
822 | if (skb->next != NULL) | ||
823 | fptr->frag_off |= htons(IP6_MF); | ||
824 | offset += (ntohs(ipv6h->payload_len) - | ||
825 | sizeof(struct frag_hdr)); | ||
826 | } | ||
813 | } | 827 | } |
814 | 828 | ||
815 | out: | 829 | out: |