return ip_route_input_common(skb, dst, src, tos, devin, true);
 }
 
-extern void            ip_rt_send_redirect(struct sk_buff *skb);
+extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
+                            int oif, u32 mark, u8 protocol, int flow_flags);
+extern void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu);
+extern void ip_rt_send_redirect(struct sk_buff *skb);
 
 extern unsigned int            inet_addr_type(struct net *net, __be32 addr);
 extern unsigned int            inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr);
 
                return;
        pr_debug("pmtu discovery on SA AH/%08x/%08x\n",
                 ntohl(ah->spi), ntohl(iph->daddr));
+       ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
        xfrm_state_put(x);
 }
 
 
                return;
        NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
                 ntohl(esph->spi), ntohl(iph->daddr));
+       ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
        xfrm_state_put(x);
 }
 
 
                case ICMP_PORT_UNREACH:
                        /* Impossible event. */
                        return;
-               case ICMP_FRAG_NEEDED:
-                       /* Soft state for pmtu is maintained by IP core. */
-                       return;
                default:
                        /* All others are translated to HOST_UNREACH.
                           rfc2003 contains "deep thoughts" about NET_UNREACH,
                                flags & GRE_KEY ?
                                *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
                                p[1]);
-       if (t == NULL || t->parms.iph.daddr == 0 ||
+       if (t == NULL)
+               goto out;
+
+       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+               ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+                                t->parms.link, 0, IPPROTO_GRE, 0);
+               goto out;
+       }
+
+       if (t->parms.iph.daddr == 0 ||
            ipv4_is_multicast(t->parms.iph.daddr))
                goto out;
 
 
                return;
        NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n",
                 spi, &iph->daddr);
+       ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
        xfrm_state_put(x);
 }
 
 
                case ICMP_PORT_UNREACH:
                        /* Impossible event. */
                        return 0;
-               case ICMP_FRAG_NEEDED:
-                       /* Soft state for pmtu is maintained by IP core. */
-                       return 0;
                default:
                        /* All others are translated to HOST_UNREACH.
                           rfc2003 contains "deep thoughts" about NET_UNREACH,
 
        rcu_read_lock();
        t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
-       if (t == NULL || t->parms.iph.daddr == 0)
+       if (t == NULL)
+               goto out;
+
+       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+               ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+                                t->dev->ifindex, 0, IPPROTO_IPIP, 0);
+               err = 0;
+               goto out;
+       }
+
+       if (t->parms.iph.daddr == 0)
                goto out;
 
        err = 0;
 
                break;
        case ICMP_DEST_UNREACH:
                if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+                       ipv4_sk_update_pmtu(skb, sk, info);
                        if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
                                err = EMSGSIZE;
                                harderr = 1;
 
        int err = 0;
        int harderr = 0;
 
+       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
+               ipv4_sk_update_pmtu(skb, sk, info);
+
        /* Report error on raw socket, if:
           1. User requested ip_recverr.
           2. Socket is connected (otherwise the error indication
 
        }
 }
 
+void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
+                     int oif, u32 mark, u8 protocol, int flow_flags)
+{
+       const struct iphdr *iph = (const struct iphdr *)skb->data;
+       struct flowi4 fl4;
+       struct rtable *rt;
+
+       flowi4_init_output(&fl4, oif, mark, RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
+                          protocol, flow_flags | FLOWI_FLAG_PRECOW_METRICS,
+                          iph->daddr, iph->saddr, 0, 0);
+       rt = __ip_route_output_key(net, &fl4);
+       if (!IS_ERR(rt)) {
+               ip_rt_update_pmtu(&rt->dst, mtu);
+               ip_rt_put(rt);
+       }
+}
+EXPORT_SYMBOL_GPL(ipv4_update_pmtu);
+
+void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+
+       return ipv4_update_pmtu(skb, sock_net(sk), mtu,
+                               sk->sk_bound_dev_if, sk->sk_mark,
+                               inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+                               inet_sk_flowi_flags(sk));
+}
+EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
 
 static void ipv4_validate_peer(struct rtable *rt)
 {
 
                break;
        case ICMP_DEST_UNREACH:
                if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+                       ipv4_sk_update_pmtu(skb, sk, info);
                        if (inet->pmtudisc != IP_PMTUDISC_DONT) {
                                err = EMSGSIZE;
                                harderr = 1;
 
                case ICMP_PORT_UNREACH:
                        /* Impossible event. */
                        return 0;
-               case ICMP_FRAG_NEEDED:
-                       /* Soft state for pmtu is maintained by IP core. */
-                       return 0;
                default:
                        /* All others are translated to HOST_UNREACH.
                           rfc2003 contains "deep thoughts" about NET_UNREACH,
                                skb->dev,
                                iph->daddr,
                                iph->saddr);
-       if (t == NULL || t->parms.iph.daddr == 0)
+       if (t == NULL)
+               goto out;
+
+       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+               ipv4_update_pmtu(skb, dev_net(skb->dev), info,
+                                t->dev->ifindex, 0, IPPROTO_IPV6, 0);
+               err = 0;
+               goto out;
+       }
+
+       if (t->parms.iph.daddr == 0)
                goto out;
 
        err = 0;