diff options
Diffstat (limited to 'net/ipv4/udp_offload.c')
-rw-r--r-- | net/ipv4/udp_offload.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index b15c78ac3f23..d4f2daca0c33 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
@@ -214,6 +214,13 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, | |||
214 | return segs; | 214 | return segs; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* GSO partial and frag_list segmentation only requires splitting | ||
218 | * the frame into an MSS multiple and possibly a remainder, both | ||
219 | * cases return a GSO skb. So update the mss now. | ||
220 | */ | ||
221 | if (skb_is_gso(segs)) | ||
222 | mss *= skb_shinfo(segs)->gso_segs; | ||
223 | |||
217 | seg = segs; | 224 | seg = segs; |
218 | uh = udp_hdr(seg); | 225 | uh = udp_hdr(seg); |
219 | 226 | ||
@@ -232,6 +239,12 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, | |||
232 | uh->len = newlen; | 239 | uh->len = newlen; |
233 | uh->check = check; | 240 | uh->check = check; |
234 | 241 | ||
242 | if (seg->ip_summed == CHECKSUM_PARTIAL) | ||
243 | gso_reset_checksum(seg, ~check); | ||
244 | else | ||
245 | uh->check = gso_make_checksum(seg, ~check) ? : | ||
246 | CSUM_MANGLED_0; | ||
247 | |||
235 | seg = seg->next; | 248 | seg = seg->next; |
236 | uh = udp_hdr(seg); | 249 | uh = udp_hdr(seg); |
237 | } | 250 | } |
@@ -244,6 +257,11 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, | |||
244 | uh->len = newlen; | 257 | uh->len = newlen; |
245 | uh->check = check; | 258 | uh->check = check; |
246 | 259 | ||
260 | if (seg->ip_summed == CHECKSUM_PARTIAL) | ||
261 | gso_reset_checksum(seg, ~check); | ||
262 | else | ||
263 | uh->check = gso_make_checksum(seg, ~check) ? : CSUM_MANGLED_0; | ||
264 | |||
247 | /* update refcount for the packet */ | 265 | /* update refcount for the packet */ |
248 | refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc); | 266 | refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc); |
249 | 267 | ||
@@ -251,15 +269,6 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, | |||
251 | } | 269 | } |
252 | EXPORT_SYMBOL_GPL(__udp_gso_segment); | 270 | EXPORT_SYMBOL_GPL(__udp_gso_segment); |
253 | 271 | ||
254 | static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb, | ||
255 | netdev_features_t features) | ||
256 | { | ||
257 | if (!can_checksum_protocol(features, htons(ETH_P_IP))) | ||
258 | return ERR_PTR(-EIO); | ||
259 | |||
260 | return __udp_gso_segment(gso_skb, features); | ||
261 | } | ||
262 | |||
263 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | 272 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, |
264 | netdev_features_t features) | 273 | netdev_features_t features) |
265 | { | 274 | { |
@@ -283,7 +292,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
283 | goto out; | 292 | goto out; |
284 | 293 | ||
285 | if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) | 294 | if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) |
286 | return __udp4_gso_segment(skb, features); | 295 | return __udp_gso_segment(skb, features); |
287 | 296 | ||
288 | mss = skb_shinfo(skb)->gso_size; | 297 | mss = skb_shinfo(skb)->gso_size; |
289 | if (unlikely(skb->len <= mss)) | 298 | if (unlikely(skb->len <= mss)) |