const struct in6_addr *daddr = &hdr->daddr;
        struct udphdr *uh = (struct udphdr *)(skb->data+offset);
        struct sock *sk;
+       int harderr;
        int err;
        struct net *net = dev_net(skb->dev);
 
                return;
        }
 
+       harderr = icmpv6_err_convert(type, code, &err);
+       np = inet6_sk(sk);
+
        if (type == ICMPV6_PKT_TOOBIG) {
                if (!ip6_sk_accept_pmtu(sk))
                        goto out;
                ip6_sk_update_pmtu(skb, sk, info);
+               if (np->pmtudisc != IPV6_PMTUDISC_DONT)
+                       harderr = 1;
        }
        if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
                goto out;
        }
 
-       np = inet6_sk(sk);
-
-       if (!icmpv6_err_convert(type, code, &err) && !np->recverr)
-               goto out;
-
-       if (sk->sk_state != TCP_ESTABLISHED && !np->recverr)
-               goto out;
-
-       if (np->recverr)
+       if (!np->recverr) {
+               if (!harderr || sk->sk_state != TCP_ESTABLISHED)
+                       goto out;
+       } else {
                ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
+       }
 
        sk->sk_err = err;
        sk->sk_error_report(sk);