|
@@ -1193,11 +1193,35 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
|
|
|
|
|
fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
|
|
|
(opt ? opt->opt_nflen : 0);
|
|
|
- maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
|
|
|
+ maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
|
|
|
+ sizeof(struct frag_hdr);
|
|
|
|
|
|
if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
|
|
|
- if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) {
|
|
|
- ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen);
|
|
|
+ unsigned int maxnonfragsize, headersize;
|
|
|
+
|
|
|
+ headersize = sizeof(struct ipv6hdr) +
|
|
|
+ (opt ? opt->tot_len : 0) +
|
|
|
+ (dst_allfrag(&rt->dst) ?
|
|
|
+ sizeof(struct frag_hdr) : 0) +
|
|
|
+ rt->rt6i_nfheader_len;
|
|
|
+
|
|
|
+ maxnonfragsize = (np->pmtudisc >= IPV6_PMTUDISC_DO) ?
|
|
|
+ mtu : sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
|
|
|
+
|
|
|
+ /* dontfrag active */
|
|
|
+ if ((cork->length + length > mtu - headersize) && dontfrag &&
|
|
|
+ (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
+ sk->sk_protocol == IPPROTO_RAW)) {
|
|
|
+ ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
|
|
|
+ sizeof(struct ipv6hdr));
|
|
|
+ goto emsgsize;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cork->length + length > maxnonfragsize - headersize) {
|
|
|
+emsgsize:
|
|
|
+ ipv6_local_error(sk, EMSGSIZE, fl6,
|
|
|
+ mtu - headersize +
|
|
|
+ sizeof(struct ipv6hdr));
|
|
|
return -EMSGSIZE;
|
|
|
}
|
|
|
}
|
|
@@ -1222,12 +1246,6 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
|
|
|
* --yoshfuji
|
|
|
*/
|
|
|
|
|
|
- if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
- sk->sk_protocol == IPPROTO_RAW)) {
|
|
|
- ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
|
|
|
- return -EMSGSIZE;
|
|
|
- }
|
|
|
-
|
|
|
skb = skb_peek_tail(&sk->sk_write_queue);
|
|
|
cork->length += length;
|
|
|
if (((length > mtu) ||
|