int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup);
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
- netdev_features_t features,
- __sum16 check);
+ netdev_features_t features);
static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
{
EXPORT_SYMBOL(skb_udp_tunnel_segment);
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
- netdev_features_t features,
- __sum16 check)
+ netdev_features_t features)
{
struct sock *sk = gso_skb->sk;
unsigned int sum_truesize = 0;
unsigned int hdrlen;
struct udphdr *uh;
unsigned int mss;
+ __sum16 check;
+ __be16 newlen;
mss = skb_shinfo(gso_skb)->gso_size;
if (gso_skb->len <= sizeof(*uh) + mss)
return segs;
}
+ uh = udp_hdr(segs);
+
+ /* compute checksum adjustment based on old length versus new */
+ newlen = htons(sizeof(*uh) + mss);
+ check = csum16_add(csum16_sub(uh->check, uh->len), newlen);
+
for (seg = segs; seg; seg = seg->next) {
uh = udp_hdr(seg);
- uh->len = htons(seg->len - hdrlen);
- uh->check = check;
/* last packet can be partial gso_size */
- if (!seg->next)
- csum_replace2(&uh->check, htons(mss),
- htons(seg->len - hdrlen - sizeof(*uh)));
+ if (!seg->next) {
+ newlen = htons(seg->len - hdrlen);
+ check = csum16_add(csum16_sub(uh->check, uh->len),
+ newlen);
+ }
+
+ uh->len = newlen;
+ uh->check = check;
- uh->check = ~uh->check;
seg->destructor = sock_wfree;
seg->sk = sk;
sum_truesize += seg->truesize;
static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
{
- const struct iphdr *iph = ip_hdr(gso_skb);
- unsigned int mss = skb_shinfo(gso_skb)->gso_size;
-
if (!can_checksum_protocol(features, htons(ETH_P_IP)))
return ERR_PTR(-EIO);
- return __udp_gso_segment(gso_skb, features,
- udp_v4_check(sizeof(struct udphdr) + mss,
- iph->saddr, iph->daddr, 0));
+ return __udp_gso_segment(gso_skb, features);
}
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
static struct sk_buff *__udp6_gso_segment(struct sk_buff *gso_skb,
netdev_features_t features)
{
- const struct ipv6hdr *ip6h = ipv6_hdr(gso_skb);
- unsigned int mss = skb_shinfo(gso_skb)->gso_size;
-
if (!can_checksum_protocol(features, htons(ETH_P_IPV6)))
return ERR_PTR(-EIO);
- return __udp_gso_segment(gso_skb, features,
- udp_v6_check(sizeof(struct udphdr) + mss,
- &ip6h->saddr, &ip6h->daddr, 0));
+ return __udp_gso_segment(gso_skb, features);
}
static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,