-/**
- * skb_pull_rcsum - pull skb and update receive checksum
- * @skb: buffer to update
- * @start: start of data before pull
- * @len: length of data pulled
- *
- * This function performs an skb_pull on the packet and updates
- * update the CHECKSUM_HW checksum. It should be used on receive
- * path processing instead of skb_pull unless you know that the
- * checksum difference is zero (e.g., a valid IP header) or you
- * are setting ip_summed to CHECKSUM_NONE.
- */
-unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
-{
- BUG_ON(len > skb->len);
- skb->len -= len;
- BUG_ON(skb->len < skb->data_len);
- skb_postpull_rcsum(skb, skb->data, len);
- return skb->data += len;
-}
-
-EXPORT_SYMBOL_GPL(skb_pull_rcsum);
-
-/**
- * skb_segment - Perform protocol segmentation on skb.
- * @skb: buffer to segment
- * @features: features for the output path (see dev->features)
- *
- * This function performs segmentation on the given skb. It returns
- * the segment at the given position. It returns NULL if there are
- * no more segments to generate, or when an error is encountered.
- */
-struct sk_buff *skb_segment(struct sk_buff *skb, int features)
-{
- struct sk_buff *segs = NULL;
- struct sk_buff *tail = NULL;
- unsigned int mss = skb_shinfo(skb)->gso_size;
- unsigned int doffset = skb->data - skb->mac.raw;
- unsigned int offset = doffset;
- unsigned int headroom;
- unsigned int len;
- int sg = features & NETIF_F_SG;
- int nfrags = skb_shinfo(skb)->nr_frags;
- int err = -ENOMEM;
- int i = 0;
- int pos;
-
- __skb_push(skb, doffset);
- headroom = skb_headroom(skb);
- pos = skb_headlen(skb);
-
- do {
- struct sk_buff *nskb;
- skb_frag_t *frag;
- int hsize;
- int k;
- int size;
-
- len = skb->len - offset;
- if (len > mss)
- len = mss;
-
- hsize = skb_headlen(skb) - offset;
- if (hsize < 0)
- hsize = 0;
- if (hsize > len || !sg)
- hsize = len;
-
- nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC);
- if (unlikely(!nskb))
- goto err;
-
- if (segs)
- tail->next = nskb;
- else
- segs = nskb;
- tail = nskb;
-
- nskb->dev = skb->dev;
- nskb->priority = skb->priority;
- nskb->protocol = skb->protocol;
- nskb->dst = dst_clone(skb->dst);
- memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
- nskb->pkt_type = skb->pkt_type;
- nskb->mac_len = skb->mac_len;
-
- skb_reserve(nskb, headroom);
- nskb->mac.raw = nskb->data;
- nskb->nh.raw = nskb->data + skb->mac_len;
- nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
- memcpy(skb_put(nskb, doffset), skb->data, doffset);
-
- if (!sg) {
- nskb->csum = skb_copy_and_csum_bits(skb, offset,
- skb_put(nskb, len),
- len, 0);
- continue;
- }
-
- frag = skb_shinfo(nskb)->frags;
- k = 0;
-
- nskb->ip_summed = CHECKSUM_HW;
- nskb->csum = skb->csum;
- memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
-
- while (pos < offset + len) {
- BUG_ON(i >= nfrags);
-
- *frag = skb_shinfo(skb)->frags[i];
- get_page(frag->page);
- size = frag->size;
-
- if (pos < offset) {
- frag->page_offset += offset - pos;
- frag->size -= offset - pos;
- }
-
- k++;
-
- if (pos + size <= offset + len) {
- i++;
- pos += size;
- } else {
- frag->size -= pos + size - (offset + len);
- break;
- }
-
- frag++;
- }
-
- skb_shinfo(nskb)->nr_frags = k;
- nskb->data_len = len - hsize;
- nskb->len += nskb->data_len;
- nskb->truesize += nskb->data_len;
- } while ((offset += len) < skb->len);
-
- return segs;
-
-err:
- while ((skb = segs)) {
- segs = skb->next;
- kfree(skb);
- }
- return ERR_PTR(err);
-}
-
-EXPORT_SYMBOL_GPL(skb_segment);
-