diff options
-rw-r--r-- | sys/netinet/ip_icmp.c | 46 | ||||
-rw-r--r-- | sys/netinet/ip_icmp.h | 1 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 43 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 43 |
4 files changed, 74 insertions, 59 deletions
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 4547886..c57b684 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -125,7 +125,6 @@ int icmpprintfs = 0; static void icmp_reflect(struct mbuf *); static void icmp_send(struct mbuf *, struct mbuf *); -static int ip_next_mtu(int, int); extern struct protosw inetsw[]; @@ -407,49 +406,6 @@ icmp_input(m, off) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; - - /* - * MTU discovery: - * If we got a needfrag and there is a host route to the - * original destination, and the MTU is not locked, then - * set the MTU in the route to the suggested new value - * (if given) and then notify as usual. The ULPs will - * notice that the MTU has changed and adapt accordingly. - * 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 don't update the MTU value. - * - * XXX: All this should be done in tcp_mtudisc() because - * the way we do it now, everyone can send us bogus ICMP - * MSGSIZE packets for any destination. By doing this far - * higher in the chain we have a matching tcp connection. - * Thus spoofing is much harder. However there is no easy - * non-hackish way to pass the new MTU up to tcp_mtudisc(). - * Also see next XXX regarding IPv4 AH TCP. - */ - if (code == PRC_MSGSIZE) { - int mtu; - struct in_conninfo inc; - - bzero(&inc, sizeof(inc)); - inc.inc_flags = 0; /* IPv4 */ - inc.inc_faddr = icmpsrc.sin_addr; - - mtu = ntohs(icp->icmp_nextmtu); - if (!mtu) - mtu = ip_next_mtu(mtu, 1); - - if (mtu >= max(296, (tcp_minmss + - sizeof(struct tcpiphdr)))) - tcp_hc_updatemtu(&inc, mtu); - -#ifdef DEBUG_MTUDISC - printf("MTU for %s reduced to %d\n", - inet_ntoa(icmpsrc.sin_addr), mtu); -#endif - } - /* * XXX if the packet contains [IPv4 AH TCP], we can't make a * notification to TCP layer. @@ -831,7 +787,7 @@ iptime() * given current value MTU. If DIR is less than zero, a larger plateau * is returned; otherwise, a smaller value is returned. */ -static int +int ip_next_mtu(mtu, dir) int mtu; int dir; diff --git a/sys/netinet/ip_icmp.h b/sys/netinet/ip_icmp.h index 9d58529..6acff63 100644 --- a/sys/netinet/ip_icmp.h +++ b/sys/netinet/ip_icmp.h @@ -193,6 +193,7 @@ struct icmp { #ifdef _KERNEL void icmp_error(struct mbuf *, int, int, n_long, struct ifnet *); void icmp_input(struct mbuf *, int); +int ip_next_mtu(int, int); #endif #endif diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 02e753a..474aa52 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -76,6 +76,7 @@ #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> #endif +#include <netinet/ip_icmp.h> #include <netinet/tcp.h> #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> @@ -1110,8 +1111,10 @@ tcp_ctlinput(cmd, sa, vip) struct inpcb *inp; struct tcpcb *tp; struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; - tcp_seq icmp_seq; - int s; + struct icmp *icp; + struct in_conninfo inc; + tcp_seq icmp_tcp_seq; + int mtu, s; faddr = ((struct sockaddr_in *)sa)->sin_addr; if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) @@ -1143,6 +1146,8 @@ tcp_ctlinput(cmd, sa, vip) return; if (ip != NULL) { s = splnet(); + icp = (struct icmp *)((caddr_t)ip + - offsetof(struct icmp, icmp_ip)); th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); INP_INFO_WLOCK(&tcbinfo); @@ -1151,17 +1156,41 @@ tcp_ctlinput(cmd, sa, vip) if (inp != NULL) { INP_LOCK(inp); if (inp->inp_socket != NULL) { - icmp_seq = htonl(th->th_seq); + icmp_tcp_seq = htonl(th->th_seq); tp = intotcpcb(inp); - if (SEQ_GEQ(icmp_seq, tp->snd_una) && - SEQ_LT(icmp_seq, tp->snd_max)) + if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) && + SEQ_LT(icmp_tcp_seq, tp->snd_max)) { + if (cmd == PRC_MSGSIZE) { + /* + * MTU discovery: + * 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 (!mtu) + mtu = ip_next_mtu(mtu, 1); + if (mtu >= max(296, (tcp_minmss + + sizeof(struct tcpiphdr)))) + tcp_hc_updatemtu(&inc, mtu); + } + inp = (*notify)(inp, inetctlerrmap[cmd]); + } } if (inp != NULL) INP_UNLOCK(inp); } else { - struct in_conninfo inc; - inc.inc_fport = th->th_dport; inc.inc_lport = th->th_sport; inc.inc_faddr = faddr; diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 02e753a..474aa52 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -76,6 +76,7 @@ #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> #endif +#include <netinet/ip_icmp.h> #include <netinet/tcp.h> #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> @@ -1110,8 +1111,10 @@ tcp_ctlinput(cmd, sa, vip) struct inpcb *inp; struct tcpcb *tp; struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; - tcp_seq icmp_seq; - int s; + struct icmp *icp; + struct in_conninfo inc; + tcp_seq icmp_tcp_seq; + int mtu, s; faddr = ((struct sockaddr_in *)sa)->sin_addr; if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) @@ -1143,6 +1146,8 @@ tcp_ctlinput(cmd, sa, vip) return; if (ip != NULL) { s = splnet(); + icp = (struct icmp *)((caddr_t)ip + - offsetof(struct icmp, icmp_ip)); th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); INP_INFO_WLOCK(&tcbinfo); @@ -1151,17 +1156,41 @@ tcp_ctlinput(cmd, sa, vip) if (inp != NULL) { INP_LOCK(inp); if (inp->inp_socket != NULL) { - icmp_seq = htonl(th->th_seq); + icmp_tcp_seq = htonl(th->th_seq); tp = intotcpcb(inp); - if (SEQ_GEQ(icmp_seq, tp->snd_una) && - SEQ_LT(icmp_seq, tp->snd_max)) + if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) && + SEQ_LT(icmp_tcp_seq, tp->snd_max)) { + if (cmd == PRC_MSGSIZE) { + /* + * MTU discovery: + * 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 (!mtu) + mtu = ip_next_mtu(mtu, 1); + if (mtu >= max(296, (tcp_minmss + + sizeof(struct tcpiphdr)))) + tcp_hc_updatemtu(&inc, mtu); + } + inp = (*notify)(inp, inetctlerrmap[cmd]); + } } if (inp != NULL) INP_UNLOCK(inp); } else { - struct in_conninfo inc; - inc.inc_fport = th->th_dport; inc.inc_lport = th->th_sport; inc.inc_faddr = faddr; |