Index: netinet/ip_fastfwd.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fastfwd.c,v
retrieving revision 1.27
diff -u -p -r1.27 ip_fastfwd.c
--- netinet/ip_fastfwd.c	29 Mar 2005 13:43:09 -0000	1.27
+++ netinet/ip_fastfwd.c	25 Apr 2005 17:45:17 -0000
@@ -137,7 +137,7 @@ ip_findroute(struct route *ro, struct in
 		ipstat.ips_cantforward++;
 		if (rt)
 			RTFREE(rt);
-		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
+		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
 		return NULL;
 	}
 	return dst;
@@ -297,7 +297,7 @@ ip_fastforward(struct mbuf *m)
 			return 0;
 		else if (ip_doopts == 2) {
 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB,
-				0, NULL);
+				0, 0);
 			return 1;
 		}
 		/* else ignore IP options and continue */
@@ -407,7 +407,7 @@ passin:
 	if (!ipstealth) {
 #endif
 	if (ip->ip_ttl <= IPTTLDEC) {
-		icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);
+		icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, 0);
 		return 1;
 	}
 
@@ -512,7 +512,7 @@ passout:
 	 */
 	if ((ro.ro_rt->rt_flags & RTF_REJECT) &&
 	    ro.ro_rt->rt_rmx.rmx_expire >= time_second) {
-		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
+		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
 		goto consumed;
 	}
 
@@ -532,7 +532,7 @@ passout:
 	 * Check if media link state of interface is not down
 	 */
 	if (ifp->if_link_state == LINK_STATE_DOWN) {
-		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, NULL);
+		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
 		goto consumed;
 	}
 
@@ -563,7 +563,7 @@ passout:
 		if (ip->ip_off & IP_DF) {
 			ipstat.ips_cantfrag++;
 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
-				0, ifp);
+				0, mtu);
 			goto consumed;
 		} else {
 			/*
Index: netinet/ip_icmp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.99
diff -u -p -r1.99 ip_icmp.c
--- netinet/ip_icmp.c	21 Apr 2005 14:29:34 -0000	1.99
+++ netinet/ip_icmp.c	25 Apr 2005 17:45:18 -0000
@@ -133,11 +133,11 @@ extern	struct protosw inetsw[];
  * in response to bad packet ip.
  */
 void
-icmp_error(n, type, code, dest, destifp)
+icmp_error(n, type, code, dest, mtu)
 	struct mbuf *n;
 	int type, code;
 	n_long dest;
-	struct ifnet *destifp;
+	int mtu;
 {
 	register struct ip *oip = mtod(n, struct ip *), *nip;
 	register unsigned oiplen = oip->ip_hl << 2;
@@ -201,8 +201,8 @@ icmp_error(n, type, code, dest, destifp)
 			icp->icmp_pptr = code;
 			code = 0;
 		} else if (type == ICMP_UNREACH &&
-			code == ICMP_UNREACH_NEEDFRAG && destifp) {
-			icp->icmp_nextmtu = htons(destifp->if_mtu);
+			code == ICMP_UNREACH_NEEDFRAG && mtu) {
+			icp->icmp_nextmtu = htons(mtu);
 		}
 	}
 
Index: netinet/ip_icmp.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_icmp.h,v
retrieving revision 1.24
diff -u -p -r1.24 ip_icmp.h
--- netinet/ip_icmp.h	21 Apr 2005 14:29:34 -0000	1.24
+++ netinet/ip_icmp.h	25 Apr 2005 17:45:18 -0000
@@ -191,7 +191,7 @@ struct icmp {
 	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
 
 #ifdef _KERNEL
-void	icmp_error(struct mbuf *, int, int, n_long, struct ifnet *);
+void	icmp_error(struct mbuf *, int, int, n_long, int);
 void	icmp_input(struct mbuf *, int);
 int	ip_next_mtu(int, int);
 #endif
Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.300
diff -u -p -r1.300 ip_input.c
--- netinet/ip_input.c	8 Apr 2005 10:25:13 -0000	1.300
+++ netinet/ip_input.c	25 Apr 2005 17:45:18 -0000
@@ -1714,10 +1714,9 @@ ip_forward(struct mbuf *m, int srcrt)
 {
 	struct ip *ip = mtod(m, struct ip *);
 	struct in_ifaddr *ia = NULL;
-	int error, type = 0, code = 0;
 	struct mbuf *mcopy;
 	struct in_addr dest;
-	struct ifnet *destifp, dummyifp;
+	int error, type = 0, code = 0, mtu = 0;
 
 #ifdef DIAGNOSTIC
 	if (ipprintfs)
@@ -1853,7 +1852,6 @@ ip_forward(struct mbuf *m, int srcrt)
 	}
 	if (mcopy == NULL)
 		return;
-	destifp = NULL;
 
 	switch (error) {
 
@@ -1906,24 +1904,17 @@ ip_forward(struct mbuf *m, int srcrt)
 				/*
 				 * find the correct route for outer IPv4
 				 * header, compute tunnel MTU.
-				 *
-				 * XXX BUG ALERT
-				 * The "dummyifp" code relies upon the fact
-				 * that icmp_error() touches only ifp->if_mtu.
 				 */
-				/*XXX*/
-				destifp = NULL;
 				if (sp->req != NULL
 				 && sp->req->sav != NULL
 				 && sp->req->sav->sah != NULL) {
 					ro = &sp->req->sav->sah->sa_route;
 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
-						dummyifp.if_mtu =
+						mtu =
 						    ro->ro_rt->rt_rmx.rmx_mtu ?
 						    ro->ro_rt->rt_rmx.rmx_mtu :
 						    ro->ro_rt->rt_ifp->if_mtu;
-						dummyifp.if_mtu -= ipsechdr;
-						destifp = &dummyifp;
+						mtu -= ipsechdr;
 					}
 				}
 
@@ -1941,11 +1932,10 @@ ip_forward(struct mbuf *m, int srcrt)
 		 * to the minimum guaranteed routeable packet size and use
 		 * the same hack as IPSEC to setup a dummyifp for icmp.
 		 */
-		if (ia == NULL) {
-			dummyifp.if_mtu = IP_MSS;
-			destifp = &dummyifp;
-		} else
-			destifp = ia->ia_ifp;
+		if (ia == NULL)
+			mtu = IP_MSS;
+		else
+			mtu = ia->ia_ifp->if_mtu;
 #if defined(IPSEC) || defined(FAST_IPSEC)
 		}
 #endif /*IPSEC || FAST_IPSEC*/
@@ -1974,7 +1964,7 @@ ip_forward(struct mbuf *m, int srcrt)
 		m_freem(mcopy);
 		return;
 	}
-	icmp_error(mcopy, type, code, dest.s_addr, destifp);
+	icmp_error(mcopy, type, code, dest.s_addr, mtu);
 }
 
 void
Index: netinet/tcp_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.224
diff -u -p -r1.224 tcp_subr.c
--- netinet/tcp_subr.c	21 Apr 2005 20:11:01 -0000	1.224
+++ netinet/tcp_subr.c	25 Apr 2005 17:45:18 -0000
@@ -1168,22 +1168,31 @@ tcp_ctlinput(cmd, sa, vip)
 					     * If we got a needfrag set the MTU
 					     * in the route to the suggested new
 					     * value (if given) and then notify.
-					     * If no new MTU was suggested, then
-					     * we guess a new one less than the
-					     * current value.
-					     * If the new MTU is unreasonably
-					     * small (defined by sysctl tcp_minmss),
-					     * then we up the MTU value to minimum.
 					     */
 					    bzero(&inc, sizeof(inc));
 					    inc.inc_flags = 0;	/* IPv4 */
 					    inc.inc_faddr = faddr;
 
 					    mtu = ntohs(icp->icmp_nextmtu);
+					    /*
+					     * If no alternative MTU was
+					     * proposed, or it is unreasonably
+					     * small, fall back to the default
+					     * MTU.
+					     */
+					    if (mtu <= max(296, (tcp_minmss)
+						 + sizeof(struct tcpiphdr)))
+						mtu = 0;
 					    if (!mtu)
-						mtu = ip_next_mtu(mtu, 1);
-					    if (mtu >= max(296, (tcp_minmss
-						 + sizeof(struct tcpiphdr))))
+						mtu = tcp_mssdflt
+						 + sizeof(struct tcpiphdr);
+					    /*
+					     * Only cache the the MTU if it
+					     * is smaller than the interface
+					     * or route MTU.  tcp_mtudisc()
+					     * will do right thing by itself.
+					     */
+					    if (mtu <= tcp_maxmtu(&inc))
 						tcp_hc_updatemtu(&inc, mtu);
 					}
 
Index: contrib/pf/net/pf.c
===================================================================
RCS file: /home/ncvs/src/sys/contrib/pf/net/pf.c,v
retrieving revision 1.28
diff -u -p -r1.28 pf.c
--- contrib/pf/net/pf.c	22 Apr 2005 09:53:46 -0000	1.28
+++ contrib/pf/net/pf.c	25 Apr 2005 17:45:19 -0000
@@ -1624,9 +1624,7 @@ pf_send_icmp(struct mbuf *m, u_int8_t ty
 		NTOHS(ip->ip_len);
 		NTOHS(ip->ip_off);
 		PF_UNLOCK();
-#endif
-		icmp_error(m0, type, code, 0, (void *)NULL);
-#ifdef __FreeBSD__
+		icmp_error(m0, type, code, 0, 0);
 		PF_LOCK();
 #endif
 		break;
@@ -5412,10 +5410,8 @@ pf_route(struct mbuf **m, struct pf_rule
 			NTOHS(ip->ip_len);
 			NTOHS(ip->ip_off);
 			PF_UNLOCK();
-#endif
 			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
-			    ifp);
-#ifdef __FreeBSD__
+			    ifp->if_mtu);
 			PF_LOCK();
 #endif
 			goto done;
