[IPv4] UFO: prevent generation of chained skb destined to UFO device
Problem: ip_append_data() could wrongly generate a chained skb for devices which support UFO. When sk_write_queue is not empty (e.g. MSG_MORE), __instead__ of appending data into the next nr_frag of the queued skb, a new chained skb is created. I would normally assume UFO device should get data in nr_frags and not in frag_list. Later the udp4_hwcsum_outgoing() resets csum to NONE and skb_gso_segment() has oops. Proposal: 1. Even length is less than mtu, employ ip_ufo_append_data() and append data to the __existed__ skb in the sk_write_queue. 2. ip_ufo_append_data() is fixed due to a wrong manipulation of peek-ing and later enqueue-ing of the same skb. Now, enqueuing is always performed, because on error the further ip_flush_pending_frames() would release the queued skb. Signed-off-by: Kostya B <bkostya@hotmail.com> Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3a8209d19d
commit
be9164e769
|
@ -753,23 +753,15 @@ static inline int ip_ufo_append_data(struct sock *sk,
|
|||
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
skb->csum = 0;
|
||||
sk->sk_sndmsg_off = 0;
|
||||
}
|
||||
|
||||
err = skb_append_datato_frags(sk,skb, getfrag, from,
|
||||
(length - transhdrlen));
|
||||
if (!err) {
|
||||
/* specify the length of each IP datagram fragment*/
|
||||
/* specify the length of each IP datagram fragment */
|
||||
skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
|
||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* There is not enough support do UFO ,
|
||||
* so follow normal path
|
||||
*/
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
|
||||
return skb_append_datato_frags(sk, skb, getfrag, from,
|
||||
(length - transhdrlen));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -863,9 +855,9 @@ int ip_append_data(struct sock *sk,
|
|||
csummode = CHECKSUM_PARTIAL;
|
||||
|
||||
inet->cork.length += length;
|
||||
if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
|
||||
(rt->u.dst.dev->features & NETIF_F_UFO)) {
|
||||
|
||||
if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
|
||||
(sk->sk_protocol == IPPROTO_UDP) &&
|
||||
(rt->u.dst.dev->features & NETIF_F_UFO)) {
|
||||
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
|
||||
fragheaderlen, transhdrlen, mtu,
|
||||
flags);
|
||||
|
|
Loading…
Reference in New Issue