return hoplimit;
 }
 
-static inline int ip_skb_dst_mtu(struct sk_buff *skb)
+static inline bool ip_sk_accept_pmtu(const struct sock *sk)
 {
-       struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
+       return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE;
+}
 
-       return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
-              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+static inline bool ip_sk_use_pmtu(const struct sock *sk)
+{
+       return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE;
+}
+
+static inline int ip_skb_dst_mtu(const struct sk_buff *skb)
+{
+       return (!skb->sk || ip_sk_use_pmtu(skb->sk)) ?
+              dst_mtu(skb_dst(skb)) : skb_dst(skb)->dev->mtu;
 }
 
 #endif /* _ROUTE_H */
 
 #define IP_PMTUDISC_WANT               1       /* Use per route hints  */
 #define IP_PMTUDISC_DO                 2       /* Always DF            */
 #define IP_PMTUDISC_PROBE              3       /* Ignore dst pmtu      */
+/* Always use interface mtu (ignores dst pmtu) but don't set DF flag.
+ * Also incoming ICMP frag_needed notifications will be ignored on
+ * this socket to prevent accepting spoofed ones.
+ */
+#define IP_PMTUDISC_INTERFACE          4
 
 #define IP_MULTICAST_IF                        32
 #define IP_MULTICAST_TTL               33
 
        mtu = dst_mtu(dst);
 
        if (inet->pmtudisc != IP_PMTUDISC_DONT &&
+           ip_sk_accept_pmtu(sk) &&
            inet_csk(sk)->icsk_pmtu_cookie > mtu) {
                dccp_sync_mss(sk, mtu);
 
 
 static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
                         struct ipcm_cookie *ipc, struct rtable **rtp)
 {
-       struct inet_sock *inet = inet_sk(sk);
        struct ip_options_rcu *opt;
        struct rtable *rt;
 
         * We steal reference to this route, caller should not release it
         */
        *rtp = NULL;
-       cork->fragsize = inet->pmtudisc == IP_PMTUDISC_PROBE ?
-                        rt->dst.dev->mtu : dst_mtu(&rt->dst);
+       cork->fragsize = ip_sk_use_pmtu(sk) ?
+                        dst_mtu(&rt->dst) : rt->dst.dev->mtu;
        cork->dst = &rt->dst;
        cork->length = 0;
        cork->ttl = ipc->ttl;
        /* DF bit is set when we want to see DF on outgoing frames.
         * If local_df is set too, we still allow to fragment this frame
         * locally. */
-       if (inet->pmtudisc >= IP_PMTUDISC_DO ||
+       if (inet->pmtudisc == IP_PMTUDISC_DO ||
+           inet->pmtudisc == IP_PMTUDISC_PROBE ||
            (skb->len <= dst_mtu(&rt->dst) &&
             ip_dont_fragment(sk, &rt->dst)))
                df = htons(IP_DF);
 
                inet->nodefrag = val ? 1 : 0;
                break;
        case IP_MTU_DISCOVER:
-               if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
+               if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_INTERFACE)
                        goto e_inval;
                inet->pmtudisc = val;
                break;
 
        bool new = false;
 
        bh_lock_sock(sk);
+
+       if (!ip_sk_accept_pmtu(sk))
+               goto out;
+
        rt = (struct rtable *) __sk_dst_get(sk);
 
        if (sock_owned_by_user(sk) || !rt) {
 
        mtu = dst_mtu(dst);
 
        if (inet->pmtudisc != IP_PMTUDISC_DONT &&
+           ip_sk_accept_pmtu(sk) &&
            inet_csk(sk)->icsk_pmtu_cookie > mtu) {
                tcp_sync_mss(sk, mtu);