static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, struct tcphdr *tcph, int tcp_data_len) { struct sk_buff *parent = lro_desc->parent; __be32 *topt; lro_desc->pkt_aggr_cnt++; lro_desc->ip_tot_len += tcp_data_len; lro_desc->tcp_next_seq += tcp_data_len; lro_desc->tcp_window = tcph->window; lro_desc->tcp_ack = tcph->ack_seq; /* don't update tcp_rcv_tsval, would not work with PAWS */ if (lro_desc->tcp_saw_tstamp) { topt = (__be32 *) (tcph + 1); lro_desc->tcp_rcv_tsecr = *(topt + 2); } lro_desc->data_csum = csum_block_add(lro_desc->data_csum, lro_tcp_data_csum(iph, tcph, tcp_data_len), parent->len); parent->len += tcp_data_len; parent->data_len += tcp_data_len; if (tcp_data_len > lro_desc->mss) lro_desc->mss = tcp_data_len; }
/** * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer * @desc: sk_buff copy helper * @to: copy destination * @len: number of bytes to copy * * Same as skb_read_bits, but calculate a checksum at the same time. */ static size_t xdr_skb_read_and_csum_bits(struct xdr_skb_reader *desc, void *to, size_t len) { unsigned int pos; __wsum csum2; if (len > desc->count) len = desc->count; pos = desc->offset; csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0); desc->csum = csum_block_add(desc->csum, csum2, pos); desc->count -= len; desc->offset += len; return len; }
static inline void skb_copy_and_csum_datagram_kvec_dst(const struct sk_buff *skb, int offset, struct kvec_dst *dst, int len, unsigned int *csump) { int i, copy; int start = skb->len - skb->data_len; int pos = 0; /* Copy header. */ if ((copy = start-offset) > 0) { if (copy > len) copy = len; *csump = csum_and_copy_to_dst(dst, skb->data+offset, copy, *csump); if ((len -= copy) == 0) return; offset += copy; pos = copy; } for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { int end; BUG_TRAP(start <= offset+len); end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end-offset) > 0) { unsigned int csum2; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; struct page *page = frag->page; if (copy > len) copy = len; vaddr = kmap_atomic(page, KM_USER1); csum2 = csum_and_copy_to_dst(dst, vaddr + frag->page_offset + offset-start, copy, 0); kunmap_atomic(vaddr, KM_USER1); *csump = csum_block_add(*csump, csum2, pos); if (!(len -= copy)) return; offset += copy; pos += copy; } start = end; } if (skb_shinfo(skb)->frag_list) { struct sk_buff *list; for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { int end; BUG_TRAP(start <= offset+len); end = start + list->len; if ((copy = end-offset) > 0) { unsigned int csum2 = 0; if (copy > len) copy = len; skb_copy_and_csum_datagram_kvec_dst(list, offset-start, dst, copy, &csum2); *csump = csum_block_add(*csump, csum2, pos); if ((len -= copy) == 0) return; offset += copy; pos += copy; } start = end; } } }
int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int *csump) { int i, copy; int start = skb->len - skb->data_len; int pos = 0; /* Copy header. */ if ((copy = start-offset) > 0) { int err = 0; if (copy > len) copy = len; *csump = csum_and_copy_to_user(skb->data+offset, to, copy, *csump, &err); if (err) goto fault; if ((len -= copy) == 0) return 0; offset += copy; to += copy; pos = copy; } for (i=0; i<skb_shinfo(skb)->nr_frags; i++) { int end; BUG_TRAP(start <= offset+len); end = start + skb_shinfo(skb)->frags[i].size; if ((copy = end-offset) > 0) { unsigned int csum2; int err = 0; u8 *vaddr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; struct page *page = frag->page; if (copy > len) copy = len; vaddr = kmap(page); csum2 = csum_and_copy_to_user(vaddr + frag->page_offset + offset-start, to, copy, 0, &err); kunmap(page); if (err) goto fault; *csump = csum_block_add(*csump, csum2, pos); if (!(len -= copy)) return 0; offset += copy; to += copy; pos += copy; } start = end; } if (skb_shinfo(skb)->frag_list) { struct sk_buff *list; for (list = skb_shinfo(skb)->frag_list; list; list=list->next) { int end; BUG_TRAP(start <= offset+len); end = start + list->len; if ((copy = end-offset) > 0) { unsigned int csum2 = 0; if (copy > len) copy = len; if (skb_copy_and_csum_datagram(list, offset-start, to, copy, &csum2)) goto fault; *csump = csum_block_add(*csump, csum2, pos); if ((len -= copy) == 0) return 0; offset += copy; to += copy; pos += copy; } start = end; } } if (len == 0) return 0; fault: return -EFAULT; }