diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2003-05-29 00:35:19 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2003-05-29 00:35:19 +0000 |
commit | b420256ef32af4714b7678f09fab90aed7a10e41 (patch) | |
tree | 7b0e0f381b4d3b3b3e88a239bfcb250627bedf02 /sys/netinet/tcp_input.c | |
parent | a8dcbc5cc46a0135bded5e71bcc4d4e98a608a87 (diff) |
use m_pulldown not m_pullup2. fix some bugs in IPv6 tcp_trace().
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 226 |
1 files changed, 87 insertions, 139 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 950094c7264..940f09d267d 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.127 2003/05/19 02:03:28 dhartmei Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.128 2003/05/29 00:35:18 itojun Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -101,9 +101,6 @@ #include <netinet6/in6_var.h> #include <netinet6/nd6.h> -struct tcpiphdr tcp_saveti; -struct tcpipv6hdr tcp_saveti6; - /* for the packet header length in the mbuf */ #define M_PH_LEN(m) (((struct mbuf *)(m))->m_pkthdr.len) #define M_V6_LEN(m) (M_PH_LEN(m) - sizeof(struct ip6_hdr)) @@ -111,7 +108,6 @@ struct tcpipv6hdr tcp_saveti6; #endif /* INET6 */ int tcprexmtthresh = 3; -struct tcpiphdr tcp_saveti; int tcptv_keep_init = TCPTV_KEEP_INIT; extern u_long sb_max; @@ -417,7 +413,7 @@ tcp_input(struct mbuf *m, ...) u_long tiwin; u_int32_t ts_val, ts_ecr; int ts_present = 0; - int iphlen; + int iphlen, toff; va_list ap; struct tcphdr *th; #ifdef INET6 @@ -431,12 +427,13 @@ tcp_input(struct mbuf *m, ...) int error, s; #endif /* IPSEC */ int af; + struct mbuf *tcp_saveti = NULL; #ifdef TCP_ECN u_char iptos; #endif va_start(ap, m); - iphlen = va_arg(ap, int); + toff = va_arg(ap, int); va_end(ap); tcpstat.tcps_rcvtotal++; @@ -466,38 +463,68 @@ tcp_input(struct mbuf *m, ...) switch (af) { case AF_INET: #ifdef DIAGNOSTIC - if (iphlen < sizeof(struct ip)) { + if (toff < sizeof(struct ip)) { m_freem(m); return; } #endif /* DIAGNOSTIC */ - if (iphlen > sizeof(struct ip)) { -#if 0 /*XXX*/ - ip_stripoptions(m, (struct mbuf *)0); - iphlen = sizeof(struct ip); -#else - m_freem(m); + ip = mtod(m, struct ip *); + iphlen = sizeof(*ip); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; return; -#endif } + len = m->m_pkthdr.len; + tlen = len - toff; +#ifdef TCP_ECN + /* save ip_tos before clearing it for checksum */ + iptos = ip->ip_tos; +#endif break; #ifdef INET6 case AF_INET6: #ifdef DIAGNOSTIC - if (iphlen < sizeof(struct ip6_hdr)) { + if (toff < sizeof(struct ip6_hdr)) { m_freem(m); return; } #endif /* DIAGNOSTIC */ - if (iphlen > sizeof(struct ip6_hdr)) { -#if 0 /*XXX*/ - ipv6_stripoptions(m, iphlen); - iphlen = sizeof(struct ip6_hdr); -#else - m_freem(m); + ip6 = mtod(m, struct ip6_hdr *); + iphlen = sizeof(*ip6); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; return; + } + len = m->m_pkthdr.len; + tlen = len - toff; +#ifdef TCP_ECN + iptos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; #endif + + /* Be proactive about malicious use of IPv4 mapped address */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + /* XXX stat */ + goto drop; } + + /* + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; + } + break; #endif default: @@ -505,49 +532,19 @@ tcp_input(struct mbuf *m, ...) return; } - if (m->m_len < iphlen + sizeof(struct tcphdr)) { - m = m_pullup2(m, iphlen + sizeof(struct tcphdr)); - if (m == NULL) { - tcpstat.tcps_rcvshort++; - return; - } - } - - ip = NULL; -#ifdef INET6 - ip6 = NULL; -#endif switch (af) { case AF_INET: - { - struct tcpiphdr *ti; - - ip = mtod(m, struct ip *); -#if 1 - tlen = m->m_pkthdr.len - iphlen; -#else - tlen = ((struct ip *)ti)->ip_len; -#endif - ti = mtod(m, struct tcpiphdr *); - -#ifdef TCP_ECN - /* save ip_tos before clearing it for checksum */ - iptos = ip->ip_tos; -#endif /* * Checksum extended TCP header and data. */ - len = sizeof(struct ip) + tlen; - bzero(ti->ti_x1, sizeof ti->ti_x1); - ti->ti_len = (u_int16_t)tlen; - HTONS(ti->ti_len); + HTONS(ip->ip_len); if ((m->m_pkthdr.csum & M_TCP_CSUM_IN_OK) == 0) { if (m->m_pkthdr.csum & M_TCP_CSUM_IN_BAD) { tcpstat.tcps_inhwcsum++; tcpstat.tcps_rcvbadsum++; goto drop; } - if ((ti->ti_sum = in_cksum(m, len)) != 0) { + if (in4_cksum(m, IPPROTO_TCP, toff, tlen) != 0) { tcpstat.tcps_rcvbadsum++; goto drop; } @@ -556,35 +553,8 @@ tcp_input(struct mbuf *m, ...) tcpstat.tcps_inhwcsum++; } break; - } #ifdef INET6 case AF_INET6: - ip6 = mtod(m, struct ip6_hdr *); - tlen = m->m_pkthdr.len - iphlen; -#ifdef TCP_ECN - iptos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; -#endif - - /* Be proactive about malicious use of IPv4 mapped address */ - if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || - IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { - /* XXX stat */ - goto drop; - } - - /* - * Be proactive about unspecified IPv6 address in source. - * As we use all-zero to indicate unbounded/unconnected pcb, - * unspecified IPv6 address can be used to confuse us. - * - * Note that packets with unspecified IPv6 destination is - * already dropped in ip6_input. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { - /* XXX stat */ - goto drop; - } - /* * Checksum extended TCP header and data. */ @@ -597,8 +567,6 @@ tcp_input(struct mbuf *m, ...) } #endif /* TUBA_INCLUDE */ - th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen); - /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX @@ -610,25 +578,13 @@ tcp_input(struct mbuf *m, ...) } tlen -= off; if (off > sizeof(struct tcphdr)) { - if (m->m_len < iphlen + off) { - if ((m = m_pullup2(m, iphlen + off)) == NULL) { - tcpstat.tcps_rcvshort++; - return; - } - switch (af) { - case AF_INET: - ip = mtod(m, struct ip *); - break; -#ifdef INET6 - case AF_INET6: - ip6 = mtod(m, struct ip6_hdr *); - break; -#endif - } - th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, off); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; } optlen = off - sizeof(struct tcphdr); - optp = mtod(m, u_int8_t *) + iphlen + sizeof(struct tcphdr); + optp = mtod(m, u_int8_t *) + toff + sizeof(struct tcphdr); /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's @@ -716,16 +672,28 @@ findpcb: if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { if (so->so_options & SO_DEBUG) { ostate = tp->t_state; - switch (af) { -#ifdef INET6 - case AF_INET6: - tcp_saveti6 = *(mtod(m, struct tcpipv6hdr *)); - break; + tcp_saveti = NULL; + MGETHDR(tcp_saveti, M_DONTWAIT, MT_HEADER); + if (!tcp_saveti) + goto nosave; +#ifdef DIAGNOSTIC + if (iphlen + sizeof(struct tcphdr) > MCLBYTES) { + printf("cannot save to tcp_saveti\n"); + goto nosave; + } #endif - case AF_INET: - tcp_saveti = *(mtod(m, struct tcpiphdr *)); - break; + if (iphlen + sizeof(struct tcphdr) > MHLEN) { + MCLGET(tcp_saveti, M_DONTWAIT); + if ((tcp_saveti->m_flags & M_EXT) == 0) { + m_freem(tcp_saveti); + tcp_saveti = NULL; + goto nosave; + } } + m_copydata(m, 0, iphlen, mtod(tcp_saveti, caddr_t)); + m_copydata(m, toff, sizeof(struct tcphdr), + mtod(tcp_saveti, caddr_t) + iphlen); + nosave:; } if (so->so_options & SO_ACCEPTCONN) { struct socket *so1; @@ -883,7 +851,7 @@ findpcb: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); } else tdb = NULL; - ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN, + ipsp_spd_lookup(m, af, toff, &error, IPSP_DIRECTION_IN, tdb, inp); if (error) { splx(s); @@ -1080,7 +1048,7 @@ findpcb: if (so->so_state & SS_CANTRCVMORE) m_freem(m); else { - m_adj(m, iphlen + off); + m_adj(m, toff + off); sbappendstream(&so->so_rcv, m); } sorwakeup(so); @@ -1094,7 +1062,7 @@ findpcb: /* * Compute mbuf offset to TCP data segment. */ - hdroptlen = iphlen + off; + hdroptlen = toff + off; /* * Calculate amount of space in receive window, @@ -2242,20 +2210,8 @@ dodata: /* XXX */ break; } } - if (so->so_options & SO_DEBUG) { - switch (tp->pf) { -#ifdef INET6 - case PF_INET6: - tcp_trace(TA_INPUT, ostate, tp, (caddr_t) &tcp_saveti6, - 0, tlen); - break; -#endif /* INET6 */ - case PF_INET: - tcp_trace(TA_INPUT, ostate, tp, (caddr_t) &tcp_saveti, - 0, tlen); - break; - } - } + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, tcp_saveti, 0, tlen); /* * Return any desired output. @@ -2263,6 +2219,7 @@ dodata: /* XXX */ if (needoutput || (tp->t_flags & TF_ACKNOW)) { (void) tcp_output(tp); } + m_freem(tcp_saveti); return; dropafterack: @@ -2275,6 +2232,7 @@ dropafterack: m_freem(m); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); + m_freem(tcp_saveti); return; dropwithreset_ratelim: @@ -2324,27 +2282,17 @@ dropwithreset: /* destroy temporarily created socket */ if (dropsocket) (void) soabort(so); + m_freem(tcp_saveti); return; drop: /* * Drop space held by incoming segment and return. */ - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { - switch (tp->pf) { -#ifdef INET6 - case PF_INET6: - tcp_trace(TA_DROP, ostate, tp, (caddr_t) &tcp_saveti6, - 0, tlen); - break; -#endif /* INET6 */ - case PF_INET: - tcp_trace(TA_DROP, ostate, tp, (caddr_t) &tcp_saveti, - 0, tlen); - break; - } - } + if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, tcp_saveti, 0, tlen); + m_freem(tcp_saveti); m_freem(m); /* destroy temporarily created socket */ if (dropsocket) |