|
@@ -586,20 +586,22 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|
frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
|
|
frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
|
|
&ipv6_hdr(skb)->saddr);
|
|
&ipv6_hdr(skb)->saddr);
|
|
|
|
|
|
|
|
+ hroom = LL_RESERVED_SPACE(rt->dst.dev);
|
|
if (skb_has_frag_list(skb)) {
|
|
if (skb_has_frag_list(skb)) {
|
|
int first_len = skb_pagelen(skb);
|
|
int first_len = skb_pagelen(skb);
|
|
struct sk_buff *frag2;
|
|
struct sk_buff *frag2;
|
|
|
|
|
|
if (first_len - hlen > mtu ||
|
|
if (first_len - hlen > mtu ||
|
|
((first_len - hlen) & 7) ||
|
|
((first_len - hlen) & 7) ||
|
|
- skb_cloned(skb))
|
|
|
|
|
|
+ skb_cloned(skb) ||
|
|
|
|
+ skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
|
|
goto slow_path;
|
|
goto slow_path;
|
|
|
|
|
|
skb_walk_frags(skb, frag) {
|
|
skb_walk_frags(skb, frag) {
|
|
/* Correct geometry. */
|
|
/* Correct geometry. */
|
|
if (frag->len > mtu ||
|
|
if (frag->len > mtu ||
|
|
((frag->len & 7) && frag->next) ||
|
|
((frag->len & 7) && frag->next) ||
|
|
- skb_headroom(frag) < hlen)
|
|
|
|
|
|
+ skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
|
|
goto slow_path_clean;
|
|
goto slow_path_clean;
|
|
|
|
|
|
/* Partially cloned skb? */
|
|
/* Partially cloned skb? */
|
|
@@ -616,8 +618,6 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|
|
|
|
|
err = 0;
|
|
err = 0;
|
|
offset = 0;
|
|
offset = 0;
|
|
- frag = skb_shinfo(skb)->frag_list;
|
|
|
|
- skb_frag_list_init(skb);
|
|
|
|
/* BUILD HEADER */
|
|
/* BUILD HEADER */
|
|
|
|
|
|
*prevhdr = NEXTHDR_FRAGMENT;
|
|
*prevhdr = NEXTHDR_FRAGMENT;
|
|
@@ -625,8 +625,11 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|
if (!tmp_hdr) {
|
|
if (!tmp_hdr) {
|
|
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
IPSTATS_MIB_FRAGFAILS);
|
|
IPSTATS_MIB_FRAGFAILS);
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ err = -ENOMEM;
|
|
|
|
+ goto fail;
|
|
}
|
|
}
|
|
|
|
+ frag = skb_shinfo(skb)->frag_list;
|
|
|
|
+ skb_frag_list_init(skb);
|
|
|
|
|
|
__skb_pull(skb, hlen);
|
|
__skb_pull(skb, hlen);
|
|
fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
|
|
fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
|
|
@@ -723,7 +726,6 @@ slow_path:
|
|
*/
|
|
*/
|
|
|
|
|
|
*prevhdr = NEXTHDR_FRAGMENT;
|
|
*prevhdr = NEXTHDR_FRAGMENT;
|
|
- hroom = LL_RESERVED_SPACE(rt->dst.dev);
|
|
|
|
troom = rt->dst.dev->needed_tailroom;
|
|
troom = rt->dst.dev->needed_tailroom;
|
|
|
|
|
|
/*
|
|
/*
|