-static int inet_gso_send_check(struct sk_buff *skb)
-{
- struct iphdr *iph;
- struct net_protocol *ops;
- int proto;
- int ihl;
- int err = -EINVAL;
-
- if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
- goto out;
-
- iph = skb->nh.iph;
- ihl = iph->ihl * 4;
- if (ihl < sizeof(*iph))
- goto out;
-
- if (unlikely(!pskb_may_pull(skb, ihl)))
- goto out;
-
- skb->h.raw = __skb_pull(skb, ihl);
- iph = skb->nh.iph;
- proto = iph->protocol & (MAX_INET_PROTOS - 1);
- err = -EPROTONOSUPPORT;
-
- rcu_read_lock();
- ops = rcu_dereference(inet_protos[proto]);
- if (likely(ops && ops->gso_send_check))
- err = ops->gso_send_check(skb);
- rcu_read_unlock();
-
-out:
- return err;
-}
-
-static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
-{
- struct sk_buff *segs = ERR_PTR(-EINVAL);
- struct iphdr *iph;
- struct net_protocol *ops;
- int proto;
- int ihl;
- int id;
-
- if (unlikely(skb_shinfo(skb)->gso_type &
- ~(SKB_GSO_TCPV4 |
- SKB_GSO_UDP |
- SKB_GSO_DODGY |
- SKB_GSO_TCP_ECN |
- 0)))
- goto out;
-
- if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
- goto out;
-
- iph = skb->nh.iph;
- ihl = iph->ihl * 4;
- if (ihl < sizeof(*iph))
- goto out;
-
- if (unlikely(!pskb_may_pull(skb, ihl)))
- goto out;
-
- skb->h.raw = __skb_pull(skb, ihl);
- iph = skb->nh.iph;
- id = ntohs(iph->id);
- proto = iph->protocol & (MAX_INET_PROTOS - 1);
- segs = ERR_PTR(-EPROTONOSUPPORT);
-
- rcu_read_lock();
- ops = rcu_dereference(inet_protos[proto]);
- if (likely(ops && ops->gso_segment))
- segs = ops->gso_segment(skb, features);
- rcu_read_unlock();
-
- if (!segs || unlikely(IS_ERR(segs)))
- goto out;
-
- skb = segs;
- do {
- iph = skb->nh.iph;
- iph->id = htons(id++);
- iph->tot_len = htons(skb->len - skb->mac_len);
- iph->check = 0;
- iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
- } while ((skb = skb->next));
-
-out:
- return segs;
-}
-