Commit be9164e7 authored by Kostya B's avatar Kostya B Committed by David S. Miller

[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: default avatarKostya B <bkostya@hotmail.com>
Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3a8209d1
...@@ -753,23 +753,15 @@ static inline int ip_ufo_append_data(struct sock *sk, ...@@ -753,23 +753,15 @@ static inline int ip_ufo_append_data(struct sock *sk,
skb->ip_summed = CHECKSUM_PARTIAL; skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum = 0; skb->csum = 0;
sk->sk_sndmsg_off = 0; sk->sk_sndmsg_off = 0;
}
err = skb_append_datato_frags(sk,skb, getfrag, from, /* specify the length of each IP datagram fragment */
(length - transhdrlen));
if (!err) {
/* specify the length of each IP datagram fragment*/
skb_shinfo(skb)->gso_size = mtu - fragheaderlen; skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP; skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
__skb_queue_tail(&sk->sk_write_queue, skb); __skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
} }
/* There is not enough support do UFO ,
* so follow normal path return skb_append_datato_frags(sk, skb, getfrag, from,
*/ (length - transhdrlen));
kfree_skb(skb);
return err;
} }
/* /*
...@@ -863,9 +855,9 @@ int ip_append_data(struct sock *sk, ...@@ -863,9 +855,9 @@ int ip_append_data(struct sock *sk,
csummode = CHECKSUM_PARTIAL; csummode = CHECKSUM_PARTIAL;
inet->cork.length += length; inet->cork.length += length;
if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
(rt->u.dst.dev->features & NETIF_F_UFO)) { (sk->sk_protocol == IPPROTO_UDP) &&
(rt->u.dst.dev->features & NETIF_F_UFO)) {
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len, err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
fragheaderlen, transhdrlen, mtu, fragheaderlen, transhdrlen, mtu,
flags); flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment