aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/af_inet6.c
diff options
context:
space:
mode:
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 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
815out: 829out: