svn commit: r319654 - stable/11/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Wed Jun 7 12:50:56 UTC 2017
Author: tuexen
Date: Wed Jun 7 12:50:54 2017
New Revision: 319654
URL: https://svnweb.freebsd.org/changeset/base/319654
Log:
MFC r319556:
Fix the ICMP6 handling for TCP.
The ICMP6 packets might not be contained in a single mbuf. So don't
assume this. Keep the IPv4 and IPv6 code in sync and make explicit
that the syncache code only need the TCP sequence number, not the
complete TCP header.
Approved by: re (marius)
Modified:
stable/11/sys/netinet/tcp_subr.c
stable/11/sys/netinet/tcp_syncache.c
stable/11/sys/netinet/tcp_syncache.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/netinet/tcp_subr.c
==============================================================================
--- stable/11/sys/netinet/tcp_subr.c Wed Jun 7 11:43:36 2017 (r319653)
+++ stable/11/sys/netinet/tcp_subr.c Wed Jun 7 12:50:54 2017 (r319654)
@@ -1966,16 +1966,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ icmp_tcp_seq = th->th_seq;
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -1983,7 +1983,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
* in the route to the suggested new
* value (if given) and then notify.
*/
- mtu = ntohs(icp->icmp_nextmtu);
+ mtu = ntohs(icp->icmp_nextmtu);
/*
* If no alternative MTU was
* proposed, try the next smaller
@@ -2014,16 +2014,17 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
inetctlerrmap[cmd]);
}
}
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fport = th->th_dport;
inc.inc_lport = th->th_sport;
inc.inc_faddr = faddr;
inc.inc_laddr = ip->ip_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET */
@@ -2033,7 +2034,6 @@ void
tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
{
struct in6_addr *dst;
- struct tcphdr *th;
struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify;
struct ip6_hdr *ip6;
struct mbuf *m;
@@ -2043,11 +2043,14 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
struct ip6ctlparam *ip6cp = NULL;
const struct sockaddr_in6 *sa6_src = NULL;
struct in_conninfo inc;
+ struct tcp_ports {
+ uint16_t th_sport;
+ uint16_t th_dport;
+ } t_ports;
tcp_seq icmp_tcp_seq;
unsigned int mtu;
unsigned int off;
-
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
@@ -2096,27 +2099,31 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
/* Check if we can safely get the ports from the tcp hdr */
if (m == NULL ||
(m->m_pkthdr.len <
- (int32_t) (off + offsetof(struct tcphdr, th_seq)))) {
+ (int32_t) (off + sizeof(struct tcp_ports)))) {
return;
}
-
- th = (struct tcphdr *) mtodo(ip6cp->ip6c_m, ip6cp->ip6c_off);
+ bzero(&t_ports, sizeof(struct tcp_ports));
+ m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports);
INP_INFO_RLOCK(&V_tcbinfo);
- inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, th->th_dport,
- &ip6->ip6_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
+ inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport,
+ &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL);
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ off += sizeof(struct tcp_ports);
+ if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) {
+ goto out;
+ }
+ m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -2133,22 +2140,20 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
*/
if (mtu < IPV6_MMTU)
mtu = IPV6_MMTU - 8;
-
-
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
inc.inc6_faddr = *dst;
if (in6_setscope(&inc.inc6_faddr,
m->m_pkthdr.rcvif, NULL))
- goto unlock_inp;
-
+ goto out;
/*
* Only process the offered MTU if it
* is smaller than the current one.
*/
if (mtu < tp->t_maxseg +
- (sizeof (*th) + sizeof (*ip6))) {
+ sizeof (struct tcphdr) +
+ sizeof (struct ip6_hdr)) {
tcp_hc_updatemtu(&inc, mtu);
tcp_mtudisc(inp, mtu);
ICMP6STAT_INC(icp6s_pmtuchg);
@@ -2158,19 +2163,19 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
inet6ctlerrmap[cmd]);
}
}
-unlock_inp:
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
- inc.inc_fport = th->th_dport;
- inc.inc_lport = th->th_sport;
+ inc.inc_fport = t_ports.th_dport;
+ inc.inc_lport = t_ports.th_sport;
inc.inc6_faddr = *dst;
inc.inc6_laddr = ip6->ip6_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET6 */
Modified: stable/11/sys/netinet/tcp_syncache.c
==============================================================================
--- stable/11/sys/netinet/tcp_syncache.c Wed Jun 7 11:43:36 2017 (r319653)
+++ stable/11/sys/netinet/tcp_syncache.c Wed Jun 7 12:50:54 2017 (r319654)
@@ -594,7 +594,7 @@ syncache_badack(struct in_conninfo *inc)
}
void
-syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
+syncache_unreach(struct in_conninfo *inc, tcp_seq th_seq)
{
struct syncache *sc;
struct syncache_head *sch;
@@ -605,7 +605,7 @@ syncache_unreach(struct in_conninfo *inc, struct tcphd
goto done;
/* If the sequence number != sc_iss, then it's a bogus ICMP msg */
- if (ntohl(th->th_seq) != sc->sc_iss)
+ if (ntohl(th_seq) != sc->sc_iss)
goto done;
/*
Modified: stable/11/sys/netinet/tcp_syncache.h
==============================================================================
--- stable/11/sys/netinet/tcp_syncache.h Wed Jun 7 11:43:36 2017 (r319653)
+++ stable/11/sys/netinet/tcp_syncache.h Wed Jun 7 12:50:54 2017 (r319654)
@@ -38,7 +38,7 @@ void syncache_init(void);
#ifdef VIMAGE
void syncache_destroy(void);
#endif
-void syncache_unreach(struct in_conninfo *, struct tcphdr *);
+void syncache_unreach(struct in_conninfo *, tcp_seq);
int syncache_expand(struct in_conninfo *, struct tcpopt *,
struct tcphdr *, struct socket **, struct mbuf *);
int syncache_add(struct in_conninfo *, struct tcpopt *,
More information about the svn-src-stable-11
mailing list