diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 78 |
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 | |||
1055 | append: | ||
1056 | return skb_append_datato_frags(sk, skb, getfrag, from, | ||
1057 | (length - transhdrlen)); | ||
1064 | } | 1058 | } |
1065 | 1059 | ||
1066 | static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, | 1060 | static 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) { |