|
@@ -1015,6 +1015,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
|
|
|
* udp datagram
|
|
|
*/
|
|
|
if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
|
|
|
+ struct frag_hdr fhdr;
|
|
|
+
|
|
|
skb = sock_alloc_send_skb(sk,
|
|
|
hh_len + fragheaderlen + transhdrlen + 20,
|
|
|
(flags & MSG_DONTWAIT), &err);
|
|
@@ -1036,12 +1038,6 @@ static inline int ip6_ufo_append_data(struct sock *sk,
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
|
|
skb->ip_summed = CHECKSUM_PARTIAL;
|
|
|
skb->csum = 0;
|
|
|
- }
|
|
|
-
|
|
|
- err = skb_append_datato_frags(sk,skb, getfrag, from,
|
|
|
- (length - transhdrlen));
|
|
|
- if (!err) {
|
|
|
- struct frag_hdr fhdr;
|
|
|
|
|
|
/* Specify the length of each IPv6 datagram fragment.
|
|
|
* It has to be a multiple of 8.
|
|
@@ -1052,15 +1048,10 @@ static inline int ip6_ufo_append_data(struct sock *sk,
|
|
|
ipv6_select_ident(&fhdr, rt);
|
|
|
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
|
|
|
__skb_queue_tail(&sk->sk_write_queue, skb);
|
|
|
-
|
|
|
- return 0;
|
|
|
}
|
|
|
- /* There is not enough support do UPD LSO,
|
|
|
- * so follow normal path
|
|
|
- */
|
|
|
- kfree_skb(skb);
|
|
|
|
|
|
- return err;
|
|
|
+ return skb_append_datato_frags(sk, skb, getfrag, from,
|
|
|
+ (length - transhdrlen));
|
|
|
}
|
|
|
|
|
|
static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
|
|
@@ -1227,27 +1218,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
|
|
* --yoshfuji
|
|
|
*/
|
|
|
|
|
|
- cork->length += length;
|
|
|
- if (length > mtu) {
|
|
|
- int proto = sk->sk_protocol;
|
|
|
- if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
|
|
|
- ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
|
|
|
- return -EMSGSIZE;
|
|
|
- }
|
|
|
-
|
|
|
- if (proto == IPPROTO_UDP &&
|
|
|
- (rt->dst.dev->features & NETIF_F_UFO)) {
|
|
|
+ if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
+ sk->sk_protocol == IPPROTO_RAW)) {
|
|
|
+ ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
|
|
|
+ return -EMSGSIZE;
|
|
|
+ }
|
|
|
|
|
|
- err = ip6_ufo_append_data(sk, getfrag, from, length,
|
|
|
- hh_len, fragheaderlen,
|
|
|
- transhdrlen, mtu, flags, rt);
|
|
|
- if (err)
|
|
|
- goto error;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ skb = skb_peek_tail(&sk->sk_write_queue);
|
|
|
+ cork->length += length;
|
|
|
+ if (((length > mtu) ||
|
|
|
+ (skb && skb_is_gso(skb))) &&
|
|
|
+ (sk->sk_protocol == IPPROTO_UDP) &&
|
|
|
+ (rt->dst.dev->features & NETIF_F_UFO)) {
|
|
|
+ err = ip6_ufo_append_data(sk, getfrag, from, length,
|
|
|
+ hh_len, fragheaderlen,
|
|
|
+ transhdrlen, mtu, flags, rt);
|
|
|
+ if (err)
|
|
|
+ goto error;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
|
|
|
+ if (!skb)
|
|
|
goto alloc_new_skb;
|
|
|
|
|
|
while (length > 0) {
|