void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
 int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
-__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
-                   __wsum csum);
 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
 int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
 __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
-
 struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
 
+struct skb_checksum_ops {
+       __wsum (*update)(const void *mem, int len, __wsum wsum);
+       __wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
+};
+
+__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
+                     __wsum csum, const struct skb_checksum_ops *ops);
+__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
+                   __wsum csum);
+
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
 {
 
 EXPORT_SYMBOL(skb_store_bits);
 
 /* Checksum skb data. */
-
-__wsum skb_checksum(const struct sk_buff *skb, int offset,
-                         int len, __wsum csum)
+__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
+                     __wsum csum, const struct skb_checksum_ops *ops)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               csum = csum_partial(skb->data + offset, copy, csum);
+               csum = ops->update(skb->data + offset, copy, csum);
                if ((len -= copy) == 0)
                        return csum;
                offset += copy;
                        if (copy > len)
                                copy = len;
                        vaddr = kmap_atomic(skb_frag_page(frag));
-                       csum2 = csum_partial(vaddr + frag->page_offset +
-                                            offset - start, copy, 0);
+                       csum2 = ops->update(vaddr + frag->page_offset +
+                                           offset - start, copy, 0);
                        kunmap_atomic(vaddr);
-                       csum = csum_block_add(csum, csum2, pos);
+                       csum = ops->combine(csum, csum2, pos, copy);
                        if (!(len -= copy))
                                return csum;
                        offset += copy;
                        __wsum csum2;
                        if (copy > len)
                                copy = len;
-                       csum2 = skb_checksum(frag_iter, offset - start,
-                                            copy, 0);
-                       csum = csum_block_add(csum, csum2, pos);
+                       csum2 = __skb_checksum(frag_iter, offset - start,
+                                              copy, 0, ops);
+                       csum = ops->combine(csum, csum2, pos, copy);
                        if ((len -= copy) == 0)
                                return csum;
                        offset += copy;
 
        return csum;
 }
+EXPORT_SYMBOL(__skb_checksum);
+
+__wsum skb_checksum(const struct sk_buff *skb, int offset,
+                   int len, __wsum csum)
+{
+       const struct skb_checksum_ops ops = {
+               .update  = csum_partial,
+               .combine = csum_block_add_ext,
+       };
+
+       return __skb_checksum(skb, offset, len, csum, &ops);
+}
 EXPORT_SYMBOL(skb_checksum);
 
 /* Both of above in one bottle. */