diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 59df872e2f4d..e6f931997996 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -116,8 +116,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
116 | } | 116 | } |
117 | rcu_read_unlock_bh(); | 117 | rcu_read_unlock_bh(); |
118 | 118 | ||
119 | IP6_INC_STATS_BH(dev_net(dst->dev), | 119 | IP6_INC_STATS(dev_net(dst->dev), |
120 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 120 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
121 | kfree_skb(skb); | 121 | kfree_skb(skb); |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | } | 123 | } |
@@ -1193,11 +1193,35 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1193 | 1193 | ||
1194 | fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + | 1194 | fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + |
1195 | (opt ? opt->opt_nflen : 0); | 1195 | (opt ? opt->opt_nflen : 0); |
1196 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1196 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - |
1197 | sizeof(struct frag_hdr); | ||
1197 | 1198 | ||
1198 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1199 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
1199 | if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { | 1200 | unsigned int maxnonfragsize, headersize; |
1200 | ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen); | 1201 | |
1202 | headersize = sizeof(struct ipv6hdr) + | ||
1203 | (opt ? opt->tot_len : 0) + | ||
1204 | (dst_allfrag(&rt->dst) ? | ||
1205 | sizeof(struct frag_hdr) : 0) + | ||
1206 | rt->rt6i_nfheader_len; | ||
1207 | |||
1208 | maxnonfragsize = (np->pmtudisc >= IPV6_PMTUDISC_DO) ? | ||
1209 | mtu : sizeof(struct ipv6hdr) + IPV6_MAXPLEN; | ||
1210 | |||
1211 | /* dontfrag active */ | ||
1212 | if ((cork->length + length > mtu - headersize) && dontfrag && | ||
1213 | (sk->sk_protocol == IPPROTO_UDP || | ||
1214 | sk->sk_protocol == IPPROTO_RAW)) { | ||
1215 | ipv6_local_rxpmtu(sk, fl6, mtu - headersize + | ||
1216 | sizeof(struct ipv6hdr)); | ||
1217 | goto emsgsize; | ||
1218 | } | ||
1219 | |||
1220 | if (cork->length + length > maxnonfragsize - headersize) { | ||
1221 | emsgsize: | ||
1222 | ipv6_local_error(sk, EMSGSIZE, fl6, | ||
1223 | mtu - headersize + | ||
1224 | sizeof(struct ipv6hdr)); | ||
1201 | return -EMSGSIZE; | 1225 | return -EMSGSIZE; |
1202 | } | 1226 | } |
1203 | } | 1227 | } |
@@ -1222,12 +1246,6 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1222 | * --yoshfuji | 1246 | * --yoshfuji |
1223 | */ | 1247 | */ |
1224 | 1248 | ||
1225 | if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP || | ||
1226 | sk->sk_protocol == IPPROTO_RAW)) { | ||
1227 | ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); | ||
1228 | return -EMSGSIZE; | ||
1229 | } | ||
1230 | |||
1231 | skb = skb_peek_tail(&sk->sk_write_queue); | 1249 | skb = skb_peek_tail(&sk->sk_write_queue); |
1232 | cork->length += length; | 1250 | cork->length += length; |
1233 | if (((length > mtu) || | 1251 | if (((length > mtu) || |