aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c78
1 files changed, 36 insertions, 42 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3a692d529163..91fb4e8212f5 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -105,7 +105,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
105 } 105 }
106 106
107 rcu_read_lock_bh(); 107 rcu_read_lock_bh();
108 nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); 108 nexthop = rt6_nexthop((struct rt6_info *)dst);
109 neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); 109 neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
110 if (unlikely(!neigh)) 110 if (unlikely(!neigh))
111 neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); 111 neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
@@ -874,7 +874,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
874 */ 874 */
875 rt = (struct rt6_info *) *dst; 875 rt = (struct rt6_info *) *dst;
876 rcu_read_lock_bh(); 876 rcu_read_lock_bh();
877 n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr)); 877 n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt));
878 err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; 878 err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;
879 rcu_read_unlock_bh(); 879 rcu_read_unlock_bh();
880 880
@@ -1008,6 +1008,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1008 1008
1009{ 1009{
1010 struct sk_buff *skb; 1010 struct sk_buff *skb;
1011 struct frag_hdr fhdr;
1011 int err; 1012 int err;
1012 1013
1013 /* There is support for UDP large send offload by network 1014 /* There is support for UDP large send offload by network
@@ -1034,33 +1035,26 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1034 skb->transport_header = skb->network_header + fragheaderlen; 1035 skb->transport_header = skb->network_header + fragheaderlen;
1035 1036
1036 skb->protocol = htons(ETH_P_IPV6); 1037 skb->protocol = htons(ETH_P_IPV6);
1037 skb->ip_summed = CHECKSUM_PARTIAL;
1038 skb->csum = 0; 1038 skb->csum = 0;
1039 }
1040
1041 err = skb_append_datato_frags(sk,skb, getfrag, from,
1042 (length - transhdrlen));
1043 if (!err) {
1044 struct frag_hdr fhdr;
1045 1039
1046 /* Specify the length of each IPv6 datagram fragment.
1047 * It has to be a multiple of 8.
1048 */
1049 skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
1050 sizeof(struct frag_hdr)) & ~7;
1051 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
1052 ipv6_select_ident(&fhdr, rt);
1053 skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
1054 __skb_queue_tail(&sk->sk_write_queue, skb); 1040 __skb_queue_tail(&sk->sk_write_queue, skb);
1055 1041 } else if (skb_is_gso(skb)) {
1056 return 0; 1042 goto append;
1057 } 1043 }
1058 /* There is not enough support do UPD LSO,
1059 * so follow normal path
1060 */
1061 kfree_skb(skb);
1062 1044
1063 return err; 1045 skb->ip_summed = CHECKSUM_PARTIAL;
1046 /* Specify the length of each IPv6 datagram fragment.
1047 * It has to be a multiple of 8.
1048 */
1049 skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
1050 sizeof(struct frag_hdr)) & ~7;
1051 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
1052 ipv6_select_ident(&fhdr, rt);
1053 skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
1054
1055append:
1056 return skb_append_datato_frags(sk, skb, getfrag, from,
1057 (length - transhdrlen));
1064} 1058}
1065 1059
1066static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, 1060static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
@@ -1227,27 +1221,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1227 * --yoshfuji 1221 * --yoshfuji
1228 */ 1222 */
1229 1223
1230 cork->length += length; 1224 if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
1231 if (length > mtu) { 1225 sk->sk_protocol == IPPROTO_RAW)) {
1232 int proto = sk->sk_protocol; 1226 ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
1233 if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ 1227 return -EMSGSIZE;
1234 ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); 1228 }
1235 return -EMSGSIZE;
1236 }
1237
1238 if (proto == IPPROTO_UDP &&
1239 (rt->dst.dev->features & NETIF_F_UFO)) {
1240 1229
1241 err = ip6_ufo_append_data(sk, getfrag, from, length, 1230 skb = skb_peek_tail(&sk->sk_write_queue);
1242 hh_len, fragheaderlen, 1231 cork->length += length;
1243 transhdrlen, mtu, flags, rt); 1232 if (((length > mtu) ||
1244 if (err) 1233 (skb && skb_is_gso(skb))) &&
1245 goto error; 1234 (sk->sk_protocol == IPPROTO_UDP) &&
1246 return 0; 1235 (rt->dst.dev->features & NETIF_F_UFO)) {
1247 } 1236 err = ip6_ufo_append_data(sk, getfrag, from, length,
1237 hh_len, fragheaderlen,
1238 transhdrlen, mtu, flags, rt);
1239 if (err)
1240 goto error;
1241 return 0;
1248 } 1242 }
1249 1243
1250 if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) 1244 if (!skb)
1251 goto alloc_new_skb; 1245 goto alloc_new_skb;
1252 1246
1253 while (length > 0) { 1247 while (length > 0) {