diff options
author | 1999-07-02 20:39:07 +0000 | |
---|---|---|
committer | 1999-07-02 20:39:07 +0000 | |
commit | a237783bf990a3ac2cc58476b3870547b43fe612 (patch) | |
tree | 0acf8b74d0292849eda10f49c5ef75b13d813006 | |
parent | consistent .Dd usage; proper format is: .Dd Month DD, YYYY (diff) | |
download | wireguard-openbsd-a237783bf990a3ac2cc58476b3870547b43fe612.tar.xz wireguard-openbsd-a237783bf990a3ac2cc58476b3870547b43fe612.zip |
Significant cleanups in the way TCP is made to handle multiple network
protocols.
"struct tcpiphdr" is now gone from much of the code, as are separate pointers
for ti and ti6. The result is fewer variables, which is generally a good thing.
Simple if(is_ipv6) ... else ... tests are gone in favor of a
switch(protocol family), which allows future new protocols to be added easily.
This also makes it possible for someone so inclined to re-implement TUBA (TCP
over CLNP?) and do it right instead of the kluged way it was done in 4.4.
The TCP header template is now referenced through a mbuf rather than done
through a data pointer and dtom()ed as needed. This is partly because dtom() is
evil and partly because max_linkhdr + IPv6 + TCP + MSS/TS/SACK opts won't fit
inside a packet header mbuf, so we need to grab a cluster for that (which the
code now does, if needed).
-rw-r--r-- | sys/netinet/tcp_debug.c | 7 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 648 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 209 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 125 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.c | 14 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 28 |
6 files changed, 628 insertions, 403 deletions
diff --git a/sys/netinet/tcp_debug.c b/sys/netinet/tcp_debug.c index a728744b64f..9adb1879804 100644 --- a/sys/netinet/tcp_debug.c +++ b/sys/netinet/tcp_debug.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_debug.c,v 1.4 1999/01/11 02:01:35 deraadt Exp $ */ +/* $OpenBSD: tcp_debug.c,v 1.5 1999/07/02 20:39:07 cmetz Exp $ */ /* $NetBSD: tcp_debug.c,v 1.10 1996/02/13 23:43:36 christos Exp $ */ /* @@ -92,10 +92,10 @@ int tcpconsdebug = 0; * Tcp debug routines */ void -tcp_trace(act, ostate, tp, ti, req, len) +tcp_trace(act, ostate, tp, headers, req, len) short act, ostate; struct tcpcb *tp; - struct tcpiphdr *ti; + caddr_t headers; int req; int len; { @@ -104,6 +104,7 @@ tcp_trace(act, ostate, tp, ti, req, len) int flags; #endif struct tcp_debug *td = &tcp_debug[tcp_debx++]; + struct tcpiphdr *ti = (struct tcpiphdr *)headers; #ifdef INET6 struct tcphdr *th; struct tcpipv6hdr *ti6 = (struct tcpipv6hdr *)ti; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 84d98320c0a..1d8e1000554 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.36 1999/06/11 19:46:39 pattonme Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.37 1999/07/02 20:39:07 cmetz Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -48,6 +48,12 @@ You should have received a copy of the license with this software. If you didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. */ +/* + * XXX - At this point, the TUBA support is likely to be hopelessly broken. + * That's the bad news. The good news is that doing it again and doing it + * right shouldn't be hard now that the IPv4 dependencies are isolated. + */ + #ifndef TUBA_INCLUDE #include <sys/param.h> #include <sys/systm.h> @@ -88,17 +94,19 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netinet6/ipv6_var.h> #include <netinet6/tcpipv6.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 ipv6)) #define M_V4_LEN(m) (M_PH_LEN(m) - sizeof(struct ip)) #endif /* INET6 */ +#ifdef INET6 +char tcp_savebuf[sizeof(struct ipv6) + sizeof(struct tcphdr)]; +#else /* INET6 */ +char tcp_savebuf[sizeof(struct ip) + sizeof(struct tcphdr)]; +#endif /* INET6 */ + int tcprexmtthresh = 3; -struct tcpiphdr tcp_saveti; int tcptv_keep_init = TCPTV_KEEP_INIT; extern u_long sb_max; @@ -307,7 +315,6 @@ tcp_input(m, va_alist) register struct mbuf *m; #endif { - register struct tcpiphdr *ti; register struct inpcb *inp; caddr_t optp = NULL; int optlen = 0; @@ -326,14 +333,19 @@ tcp_input(m, va_alist) int iphlen; va_list ap; register struct tcphdr *th; + unsigned int pf; #ifdef IPSEC struct tdb *tdb = NULL; #endif /* IPSEC */ + union { + caddr_t p; +#ifdef INET + struct ip *ip; +#endif /* INET */ #ifdef INET6 - struct in6_addr laddr6; - unsigned short is_ipv6; /* Type of incoming datagram. */ - struct ipv6 *ipv6 = NULL; -#endif /* INET6 */ + struct ipv6 *ipv6; +#endif /* INET */ + } nhu; va_start(ap, m); iphlen = va_arg(ap, int); @@ -350,87 +362,113 @@ tcp_input(m, va_alist) m->m_pkthdr.tdbi = NULL; } #endif /* IPSEC */ -#ifdef INET6 + /* - * Before we do ANYTHING, we have to figure out if it's TCP/IPv6 or - * TCP/IPv4. + * Before we do ANYTHING, we have to figure out what network protocol + * is underneath the TCP header in this packet. + * + * For IPv4 and IPv6, options don't really do anything at this layer + * and therefore are stripped off. */ - is_ipv6 = mtod(m, struct ip *)->ip_v == 6; +#if defined(INET) && defined(INET6) + switch(mtod(m, struct ip *)->ip_v) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case 4: + pf = PF_INET; + +#ifdef DIAGNOSTIC + if (iphlen < sizeof(struct ip)) { + m_freem(m); + return; + } +#endif /* DIAGNOSTIC */ + + if (iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } + break; +#endif /* INET */ +#ifdef INET6 + case 6: + pf = PF_INET6; + +#ifdef DIAGNOSTIC + if (iphlen < sizeof(struct ipv6)) { + m_freem(m); + return; + } +#endif /* DIAGNOSTIC */ + + if (iphlen > sizeof(struct ipv6)) { + ipv6_stripoptions(m, iphlen); + iphlen = sizeof(struct ipv6); + } + break; #endif /* INET6 */ + default: + m_freem(m); + return; + } /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. */ -#ifndef INET6 - ti = mtod(m, struct tcpiphdr *); -#else /* INET6 */ - if (!is_ipv6) -#endif /* INET6 */ - if (iphlen > sizeof (struct ip)) - ip_stripoptions(m, (struct mbuf *)0); if (m->m_len < iphlen + sizeof(struct tcphdr)) { if ((m = m_pullup2(m, iphlen + sizeof(struct tcphdr))) == 0) { tcpstat.tcps_rcvshort++; return; } -#ifndef INET6 - ti = mtod(m, struct tcpiphdr *); -#endif /* INET6 */ } tlen = m->m_pkthdr.len - iphlen; -#ifdef INET6 /* - * After that, do initial segment processing which is still very - * dependent on what IP version you're using. + * Checksum extended TCP header and data. */ +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + { + struct ipovly *ipovly; - if (is_ipv6) { -#ifdef DIAGNOSTIC - if (iphlen < sizeof(struct ipv6)) { - m_freem(m); - return; - } -#endif /* DIAGNOSTIC */ - - /* strip off any options */ - if (iphlen > sizeof(struct ipv6)) { - ipv6_stripoptions(m, iphlen); - iphlen = sizeof(struct ipv6); - } - - ti = NULL; - ipv6 = mtod(m, struct ipv6 *); + ipovly = mtod(m, struct ipovly *); - if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) { - tcpstat.tcps_rcvbadsum++; - goto drop; - } /* endif in6_cksum */ - } else { - ti = mtod(m, struct tcpiphdr *); -#endif /* INET6 */ + len = sizeof (struct ip) + tlen; + bzero(ipovly->ih_x1, sizeof ipovly->ih_x1); + ipovly->ih_len = (u_int16_t)tlen; + HTONS(ipovly->ih_len); - /* - * Checksum extended TCP header and data. - */ -#ifndef INET6 - tlen = ((struct ip *)ti)->ip_len; -#endif /* INET6 */ - len = sizeof (struct ip) + tlen; - bzero(ti->ti_x1, sizeof ti->ti_x1); - ti->ti_len = (u_int16_t)tlen; - HTONS(ti->ti_len); - if ((ti->ti_sum = in_cksum(m, len)) != 0) { - tcpstat.tcps_rcvbadsum++; - goto drop; - } + if (in_cksum(m, len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + } + break; +#endif /* INET */ #ifdef INET6 - } + case PF_INET6: + if (in6_cksum(m, IPPROTO_TCP, tlen, sizeof(struct ipv6))) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } /* endif in6_cksum */ + break; #endif /* INET6 */ + } + #endif /* TUBA_INCLUDE */ + nhu.p = mtod(m, caddr_t); th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen); /* @@ -449,12 +487,6 @@ tcp_input(m, va_alist) tcpstat.tcps_rcvshort++; return; } -#ifdef INET6 - if (is_ipv6) - ipv6 = mtod(m, struct ipv6 *); - else -#endif /* INET6 */ - ti = mtod(m, struct tcpiphdr *); th = (struct tcphdr *)(mtod(m, caddr_t) + iphlen); } optlen = off - sizeof (struct tcphdr); @@ -491,25 +523,51 @@ tcp_input(m, va_alist) * Locate pcb for segment. */ findpcb: +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + inp = in_pcbhashlookup(&tcbtable, nhu.ip->ip_src, th->th_sport, + nhu.ip->ip_dst, th->th_dport); + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) { - inp = in6_pcbhashlookup(&tcbtable, &ipv6->ipv6_src, th->th_sport, - &ipv6->ipv6_dst, th->th_dport); - } else + case PF_INET6: + inp = in6_pcbhashlookup(&tcbtable, nhu.ipv6->ipv6_src, + th->th_sport, nhu.ipv6->ipv6_dst, th->th_dport); + break; #endif /* INET6 */ - inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); + } + if (inp == 0) { ++tcpstat.tcps_pcbhashmiss; +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + inp = in_pcblookup(&tcbtable, &nhu.ip->ip_src, + th->th_sport, &nhu.ip->ip_dst, th->th_dport, + INPLOOKUP_WILDCARD); + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) - inp = in_pcblookup(&tcbtable, &ipv6->ipv6_src, - th->th_sport, &ipv6->ipv6_dst, th->th_dport, - INPLOOKUP_WILDCARD | INPLOOKUP_IPV6); - else + case PF_INET6: + inp = in_pcblookup(&tcbtable, &nhu.ipv6->ipv6_src, + th->th_sport, &nhu.ipv6->ipv6_dst, + th->th_dport, + INPLOOKUP_WILDCARD | INPLOOKUP_IPV6); + break; #endif /* INET6 */ - inp = in_pcblookup(&tcbtable, &ti->ti_src, ti->ti_sport, - &ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD); + } + /* * If the state is CLOSED (i.e., TCB does not exist) then * all data in the incoming segment is discarded. @@ -538,12 +596,8 @@ findpcb: if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { if (so->so_options & SO_DEBUG) { ostate = tp->t_state; -#ifdef INET6 - if (is_ipv6) - tcp_saveti6 = *(mtod(m, struct tcpipv6hdr *)); - else -#endif /* INET6 */ - tcp_saveti = *ti; + bcopy(mtod(m, caddr_t), tcp_savebuf, + iphlen + sizeof(struct tcphdr)); } if (so->so_options & SO_ACCEPTCONN) { struct socket *so1; @@ -591,48 +645,57 @@ findpcb: * to the new one. */ { - int flags = inp->inp_flags; - struct inpcb *oldinpcb = inp; + int flags = inp->inp_flags; + struct inpcb *oldinpcb = inp; - inp = (struct inpcb *)so->so_pcb; - inp->inp_flags |= (flags & (INP_IPV6 | INP_IPV6_UNDEC - | INP_IPV6_MAPPED)); - if ((inp->inp_flags & INP_IPV6) && - !(inp->inp_flags & INP_IPV6_MAPPED)) { - inp->inp_ipv6.ipv6_hoplimit = - oldinpcb->inp_ipv6.ipv6_hoplimit; - inp->inp_ipv6.ipv6_versfl = - oldinpcb->inp_ipv6.ipv6_versfl; - } + inp = (struct inpcb *)so->so_pcb; + inp->inp_flags |= + (flags & (INP_IPV6 | INP_IPV6_UNDEC + | INP_IPV6_MAPPED)); + if ((inp->inp_flags & INP_IPV6) && + !(inp->inp_flags & + INP_IPV6_MAPPED)) { + inp->inp_ipv6.ipv6_hoplimit = + oldinpcb->inp_ipv6. + ipv6_hoplimit; + inp->inp_ipv6.ipv6_versfl = + oldinpcb->inp_ipv6.ipv6_versfl; + } } #else /* INET6 */ inp = (struct inpcb *)so->so_pcb; #endif /* INET6 */ inp->inp_lport = th->th_dport; +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: #ifdef INET6 - if (is_ipv6) { - inp->inp_laddr6 = ipv6->ipv6_dst; - inp->inp_fflowinfo = htonl(0x0fffffff) & - ipv6->ipv6_versfl; - - /*inp->inp_options = ipv6_srcroute();*/ /* soon. */ - /* still need to tweak outbound options - processing to include this mbuf in - the right place and put the correct - NextHdr values in the right places. - XXX rja */ - } else { - if (inp->inp_flags & INP_IPV6) {/* v4 to v6 socket */ - CREATE_IPV6_MAPPED(inp->inp_laddr6, - ti->ti_dst.s_addr); - } else { + if (inp->inp_flags & INP_IPV6) { + /* v4 to v6 socket */ + CREATE_IPV6_MAPPED(inp->inp_laddr6, + nhu.ip->ip_dst.s_addr); + } else #endif /* INET6 */ - inp->inp_laddr = ti->ti_dst; - inp->inp_options = ip_srcroute(); -#if INET6 - } - }; + { + inp->inp_laddr = nhu.ip->ip_dst; + inp->inp_options = ip_srcroute(); + } + break; +#endif /* INET */ +#ifdef INET6 + case PF_INET6: + inp->inp_laddr6 = nhu.ipv6->ipv6_dst; + inp->inp_fflowinfo = htonl(0x0fffffff) & + nhu.ipv6->ipv6_versfl; + break; #endif /* INET6 */ + } + in_pcbrehash(inp); tp = intotcpcb(inp); tp->t_state = TCPS_LISTEN; @@ -640,7 +703,8 @@ findpcb: /* Compute proper scaling value from buffer space */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && - TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) + TCP_MAXWIN << tp->request_r_scale < + so->so_rcv.sb_hiwat) tp->request_r_scale++; } } @@ -652,12 +716,23 @@ findpcb: (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE && !(m->m_flags & M_CONF))) { #ifdef notyet +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0); + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) + case PF_INET6: ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0); - else + break; #endif /* INET6 */ - icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0); + } #endif /* notyet */ tcpstat.tcps_rcvnosec++; goto drop; @@ -849,10 +924,6 @@ findpcb: */ case TCPS_LISTEN: { struct mbuf *am; - register struct sockaddr_in *sin; -#ifdef INET6 - register struct sockaddr_in6 *sin6; -#endif /* INET6 */ if (tiflags & TH_RST) goto drop; @@ -861,17 +932,27 @@ findpcb: if ((tiflags & TH_SYN) == 0) goto drop; if (th->th_dport == th->th_sport) { +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + if (nhu.ip->ip_src.s_addr == + nhu.ip->ip_dst.s_addr) + goto drop; + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) { - if (IN6_ARE_ADDR_EQUAL(&ipv6->ipv6_src, &ipv6->ipv6_dst)) - goto drop; - } else { -#endif /* INET6 */ - if (ti->ti_dst.s_addr == ti->ti_src.s_addr) - goto drop; -#ifdef INET6 - } + case PF_INET6: + if (IN6_ARE_ADDR_EQUAL(&nhu.ipv6->ipv6_src, + &nhu.ipv6->ipv6_dst)) + goto drop; + break; #endif /* INET6 */ + } } /* @@ -881,118 +962,159 @@ findpcb: */ if (m->m_flags & (M_BCAST|M_MCAST)) goto drop; +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + if (nhu.ip->ip_dst.s_addr == INADDR_BROADCAST) + goto drop; + if (IN_MULTICAST(nhu.ip->ip_dst.s_addr)) + goto drop; + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) { - /* XXX What about IPv6 Anycasting ?? :-( rja */ - if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst)) + case PF_INET6: + if (IN6_IS_ADDR_MULTICAST(nhu.ipv6->ipv6_dst)) goto drop; - } else + break; #endif /* INET6 */ - if (IN_MULTICAST(ti->ti_dst.s_addr)) - goto drop; + } + am = m_get(M_DONTWAIT, MT_SONAME); /* XXX */ if (am == NULL) goto drop; + +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: #ifdef INET6 - if (is_ipv6) { - /* - * This is probably the place to set the tp->pf value. - * (Don't forget to do it in the v4 code as well!) - * - * Also, remember to blank out things like flowlabel, or - * set flowlabel for accepted sockets in v6. - * - * FURTHERMORE, this is PROBABLY the place where the whole - * business of key munging is set up for passive - * connections. - */ - am->m_len = sizeof(struct sockaddr_in6); - sin6 = mtod(am, struct sockaddr_in6 *); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_addr = ipv6->ipv6_src; - sin6->sin6_port = th->th_sport; - sin6->sin6_flowinfo = htonl(0x0fffffff) & - inp->inp_ipv6.ipv6_versfl; - laddr6 = inp->inp_laddr6; - if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) - inp->inp_laddr6 = ipv6->ipv6_dst; - /* This is a good optimization. */ - if (in6_pcbconnect(inp, am)) { - inp->inp_laddr6 = laddr6; - (void) m_free(am); - goto drop; - } /* endif in6_pcbconnect() */ - tp->pf = PF_INET6; - } else { - /* - * Letting v4 incoming datagrams to reach valid - * PF_INET6 sockets causes some overhead here. - */ - if (inp->inp_flags & INP_IPV6) { - if (!(inp->inp_flags & (INP_IPV6_UNDEC|INP_IPV6_MAPPED))) { - (void) m_free(am); - goto drop; - } - - am->m_len = sizeof(struct sockaddr_in6); - - sin6 = mtod(am, struct sockaddr_in6 *); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(*sin6); - CREATE_IPV6_MAPPED(sin6->sin6_addr, ti->ti_src.s_addr); - sin6->sin6_port = th->th_sport; - sin6->sin6_flowinfo = 0; - - laddr6 = inp->inp_laddr6; - if (inp->inp_laddr.s_addr == INADDR_ANY) - CREATE_IPV6_MAPPED(inp->inp_laddr6, ti->ti_dst.s_addr); - - /* - * The pcb initially has the v6 default hoplimit - * set. We're sending v4 packets so we need to set - * the v4 ttl and tos. - */ - inp->inp_ip.ip_ttl = ip_defttl; - inp->inp_ip.ip_tos = 0; - - if (in6_pcbconnect(inp, am)) { - inp->inp_laddr6 = laddr6; - (void) m_freem(am); - goto drop; - } - tp->pf = PF_INET; - } else { + /* + * Letting v4 incoming datagrams to reach valid + * PF_INET6 sockets causes some overhead here. + */ + if (inp->inp_flags & INP_IPV6) { + struct sockaddr_in6 sin6; + + if (!(inp->inp_flags & (INP_IPV6_UNDEC | + INP_IPV6_MAPPED))) { + m_freem(am); + goto drop; + } + + am->m_len = sizeof(struct sockaddr_in6); + sin6 = mtod(am, struct sockaddr_in6 *); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + CREATE_IPV6_MAPPED(sin6->sin6_addr, + nhu.ip->ip_src.s_addr); + sin6->sin6_port = th->th_sport; + sin6->sin6_flowinfo = 0; + + laddr6 = inp->inp_laddr6; + if (inp->inp_laddr.s_addr == INADDR_ANY) + break; + CREATE_IPV6_MAPPED(inp->inp_laddr6, + nhu.ip->ip_dst.s_addr); + + /* + * The pcb initially has the v6 default hop + * limit set. We're sending v4 packets, so we + * need to set the v4 ttl and tos. + */ + inp->inp_ip.ip_ttl = ip_defttl; + inp->inp_ip.ip_tos = 0; + + if (in6_pcbconnect(inp, am)) { + inp->inp_laddr6 = laddr6; + m_freem(am); + goto drop; + } + } else /* (inp->inp_flags & INP_IPV6) */ #endif /* INET6 */ - am->m_len = sizeof (struct sockaddr_in); - sin = mtod(am, struct sockaddr_in *); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ti->ti_src; - sin->sin_port = ti->ti_sport; - bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero)); - laddr = inp->inp_laddr; - if (inp->inp_laddr.s_addr == INADDR_ANY) - inp->inp_laddr = ti->ti_dst; - if (in_pcbconnect(inp, am)) { - inp->inp_laddr = laddr; - (void) m_free(am); - goto drop; - } - (void) m_free(am); + { + struct sockaddr_in *sin; + + am->m_len = sizeof(struct sockaddr_in); + sin = mtod(am, struct sockaddr_in *); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_addr = nhu.ip->ip_src; + sin->sin_port = th->th_sport; + bzero((caddr_t)sin->sin_zero, + sizeof(sin->sin_zero)); + laddr = inp->inp_laddr; + if (inp->inp_laddr.s_addr == INADDR_ANY) + inp->inp_laddr = nhu.ip->ip_dst; + if (in_pcbconnect(inp, am)) { + inp->inp_laddr = laddr; + m_free(am); + goto drop; + } + } /* (inp->inp_flags & INP_IPV6) */ + tp->pf = PF_INET; + break; +#endif /* INET */ #ifdef INET6 - } /* if (inp->inp_flags & INP_IPV6) */ - } /* if (is_ipv6) */ + case PF_INET6: + { + struct sockaddr_in6 sin6; + + /* + * This is probably the place to set the tp->pf + * value. (Don't forget to do it in the v4 code + * as well!) + * + * Also, remember to blank out things like + * flowlabel, or set flowlabel for accepted + * sockets in v6. + */ + + am->m_len = sizeof(struct sockaddr_in6); + sin6 = mtod(am, struct sockaddr_in6 *); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_addr = nhu.ipv6->ipv6_src; + sin6->sin6_port = th->th_sport; + sin6->sin6_flowinfo = htonl(0x0fffffff) & + inp->inp_ipv6.ipv6_versfl; + laddr6 = inp->inp_laddr6; + + if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) + inp->inp_laddr6 = nhu.ipv6->ipv6_dst; + /* This is a good optimization. */ + if (in6_pcbconnect(inp, am)) { + inp->inp_laddr6 = laddr6; + m_free(am); + goto drop; + } + } + + tp->pf = PF_INET6; + break; #endif /* INET6 */ + } + + m_free(am); tp->t_template = tcp_template(tp); if (tp->t_template == 0) { tp = tcp_drop(tp, ENOBUFS); dropsocket = 0; /* socket is already gone */ goto drop; } + if (optp) tcp_dooptions(tp, optp, optlen, th, &ts_present, &ts_val, &ts_ecr); + #ifdef TCP_SACK /* * If peer did not send a SACK_PERMITTED option (i.e., if @@ -1293,7 +1415,7 @@ trimthenstep6: * Close the tcb. */ if (tiflags & TH_RST) { - if (ti->ti_seq != tp->last_ack_sent) + if (th->th_seq != tp->last_ack_sent) goto drop; switch (tp->t_state) { @@ -1919,14 +2041,9 @@ dodata: /* XXX */ break; } } - if (so->so_options & SO_DEBUG) { -#ifdef INET6 - if (tp->pf == PF_INET6) - tcp_trace(TA_INPUT, ostate, tp, (struct tcpiphdr *) &tcp_saveti6, 0, tlen); - else -#endif /* INET6 */ - tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0, tlen); - } + + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, tcp_savebuf, 0, tlen); /* * Return any desired output. @@ -1967,26 +2084,36 @@ dropwithreset: */ if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST)) goto drop; +#if defined(INET) && defined(INET6) + switch(pf) { +#else /* defined(INET) && defined(INET6) */ + switch(-1) { + case -1: +#endif /* defined(INET) && defined(INET6) */ +#ifdef INET + case PF_INET: + if (mtod(m, struct ip *)->ip_dst.s_addr == INADDR_BROADCAST) + goto drop; + if (IN_MULTICAST(mtod(m, struct ip *)->ip_dst.s_addr)) + goto drop; + break; +#endif /* INET */ #ifdef INET6 - if (is_ipv6) { - /* For following calls to tcp_respond */ - ti = mtod(m, struct tcpiphdr *); - if (IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst)) - goto drop; - } else { + case PF_INET6: + if (IN6_IS_ADDR_MULTICAST(&mtod(m, struct ipv6 *)->ipv6_dst)) + goto drop; + break; #endif /* INET6 */ - if (IN_MULTICAST(ti->ti_dst.s_addr)) - goto drop; -#ifdef INET6 } -#endif /* INET6 */ + if (tiflags & TH_ACK) - tcp_respond(tp, ti, m, (tcp_seq)0, th->th_ack, TH_RST); + tcp_respond(tp, mtod(m, caddr_t), m, (tcp_seq)0, th->th_ack, + TH_RST); else { if (tiflags & TH_SYN) tlen++; - tcp_respond(tp, ti, m, th->th_seq+tlen, (tcp_seq)0, - TH_RST|TH_ACK); + tcp_respond(tp, mtod(m, caddr_t), m, th->th_seq+tlen, + (tcp_seq)0, TH_RST|TH_ACK); } /* destroy temporarily created socket */ if (dropsocket) @@ -1997,14 +2124,8 @@ drop: /* * Drop space held by incoming segment and return. */ - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { -#ifdef INET6 - if (tp->pf == PF_INET6) - tcp_trace(TA_DROP, ostate, tp, (struct tcpiphdr *)&tcp_saveti6, 0, tlen); - else -#endif /* INET6 */ - tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0, tlen); - } + if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, tcp_savebuf, 0, tlen); m_freem(m); /* destroy temporarily created socket */ @@ -2095,6 +2216,7 @@ tcp_dooptions(tp, cp, cnt, th, ts_present, ts_val, ts_ecr) #endif } } + /* Update t_maxopd and t_maxseg after all options are processed */ if (th->th_flags & TH_SYN) (void) tcp_mss(tp, mss); /* sets t_maxseg */ diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 8b3c5c57683..724288a37e8 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_output.c,v 1.16 1999/01/11 02:01:36 deraadt Exp $ */ +/* $OpenBSD: tcp_output.c,v 1.17 1999/07/02 20:39:08 cmetz Exp $ */ /* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */ /* @@ -92,12 +92,6 @@ extern int tcprexmtthresh; #endif #ifdef TCP_SACK -#define MAX_TCPOPTLEN 40 /* need 40 at least for 3 SACKs + TIMESTAMP */ -#else -#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ -#endif - -#ifdef TCP_SACK #ifdef TCP_SACK_DEBUG void tcp_print_holes(tp) @@ -181,11 +175,7 @@ tcp_output(tp) register long len, win; int off, flags, error; register struct mbuf *m; - register struct tcpiphdr *ti; register struct tcphdr *th; -#ifdef INET6 - register struct tcpipv6hdr *ti6 = NULL; -#endif /* INET6 */ u_char opt[MAX_TCPOPTLEN]; unsigned int optlen, hdrlen; int idle, sendalot; @@ -438,23 +428,31 @@ send: * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. - * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN - */ -#ifdef INET6 - /* - * For IPv6, this has changed to be: - * max_linkhdr + sizeof(struct tcphdr) + optlen + - * sizeof(struct ipv6) <= MHLEN - * This MIGHT be harder... + * max_linkhdr + sizeof(network header) + sizeof(struct tcphdr) + + * optlen <= MHLEN */ -#endif /* INET6 */ optlen = 0; + +#ifdef defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch(0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: /* If tp->pf is 0, then assume IPv4 unless not avail */ +#ifdef INET + case PF_INET: + hdrlen = sizeof(struct ip) + sizeof(struct tcphdr); + break; +#endif /* INET */ #ifdef INET6 - if (tp->pf == PF_INET6) /* if tp->pf is 0, then assume IPv4. */ - hdrlen = sizeof(struct tcphdr) + sizeof(struct ipv6); - else + case PF_INET6: + hdrlen = sizeof(struct ipv6) + sizeof(struct tcphdr); + break; #endif /* INET6 */ - hdrlen = sizeof (struct tcpiphdr); + default: + return (EPFNOSUPPORT); + } + if (flags & TH_SYN) { tp->snd_nxt = tp->iss; if ((tp->t_flags & TF_NOOPT) == 0) { @@ -539,6 +537,11 @@ send: } #endif /* TCP_SACK */ +#ifdef DIAGNOSTIC + if (optlen > MAX_TCPOPTLEN) + panic("tcp_output: options too long"); +#endif /* DIAGNOSTIC */ + hdrlen += optlen; /* @@ -630,31 +633,17 @@ send: m->m_len = hdrlen; } m->m_pkthdr.rcvif = (struct ifnet *)0; -#ifdef INET6 - if (tp->pf == PF_INET6) { - ti6 = mtod(m, struct tcpipv6hdr *); - ti = NULL; - - if (!tp->t_template) - panic("tcp_output"); - - bcopy((caddr_t)tp->t_template, (caddr_t)ti6, - sizeof (struct tcpipv6hdr)); - - th = &ti6->ti6_t; - } else -#endif /* INET6 */ - { - ti = mtod(m, struct tcpiphdr *); - - if (tp->t_template == 0) - panic("tcp_output"); - - bcopy((caddr_t)tp->t_template, (caddr_t)ti, - sizeof (struct tcpiphdr)); - th = &ti->ti_t; - }; + if (!tp->t_template) + panic("tcp_output"); +#ifdef DIAGNOSTIC + if (tp->t_template->m_len != hdrlen - optlen) + panic("tcp_output: template len != hdrlen - optlen"); +#endif /* DIAGNOSTIC */ + bcopy(mtod(tp->t_template, caddr_t), mtod(m, caddr_t), + tp->t_template->m_len); + th = (struct tcphdr *)(mtod(m, caddr_t) + tp->t_template->m_len - + sizeof(struct tcphdr)); /* * Fill in fields, remembering maximum advertised @@ -734,22 +723,46 @@ send: */ tp->snd_up = tp->snd_una; /* drag it along */ + /* Put TCP length in pseudo-header */ +#ifdef defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch(0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + if (len + optlen) + mtod(m, struct ipovly *)->ih_len = htons((u_int16_t)( + sizeof (struct tcphdr) + optlen + len)); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + break; +#endif /* INET6 */ + } + /* * Put TCP length in extended header, and then * checksum extended header and data. */ +#ifdef defined(INET) && defined(INET6) + switch (tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch (0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + th->th_sum = in_cksum(m, (int)(hdrlen + len)); + break; +#endif /* INET */ #ifdef INET6 - if (tp->pf == PF_INET6) { - th->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(struct tcphdr) + optlen + len, - sizeof(struct ipv6)); - } else + case AF_INET6: + th->th_sum = in6_cksum(m, IPPROTO_TCP, hdrlen + len); + break; #endif /* INET6 */ - { - if (len + optlen) - ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + - optlen + len)); - ti->ti_sum = in_cksum(m, (int)(hdrlen + len)); } /* @@ -828,12 +841,8 @@ send: * Trace. */ if (so->so_options & SO_DEBUG) -#if INET6 - tcp_trace(TA_OUTPUT, tp->t_state, tp, - (tp->pf == AF_INET6) ? (struct tcpiphdr *)ti6 : ti, 0, len); -#else - tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0, len); -#endif + tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, caddr_t), 0, + len); /* * Fill in IP length and desired time to live and @@ -842,36 +851,58 @@ send: * the template, but need a way to checksum without them. */ m->m_pkthdr.len = hdrlen + len; -#ifdef TUBA - if (tp->t_tuba_pcb) - error = tuba_output(m, tp); - else -#endif -#ifdef INET6 - if (tp->pf == PF_INET6) { - ((struct ipv6 *)ti6)->ipv6_length = m->m_pkthdr.len - sizeof(struct ipv6); - /* Following fields are already grabbed from the tcp_template. */ - /* ((struct ipv6 *)ti6)->ipv6_versfl = ntohl(0x60000000); - ((struct ipv6 *)ti6)->ipv6_nexthdr = IPPROTO_TCP; - ((struct ipv6 *)ti6)->ipv6_hoplimit = - tp->t_inpcb->inp_ipv6.ipv6_hoplimit;*/ +#ifdef defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch(0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + { + struct ip *ip; + + ip = mtod(m, struct ip *); + ip->ip_len = m->m_pkthdr.len; + ip->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; + ip->ip_tos = tp->t_inpcb->inp_ip.ip_tos; + } - error = ipv6_output(m, &tp->t_inpcb->inp_route6, (so->so_options & SO_DONTROUTE), NULL, NULL, tp->t_inpcb->inp_socket); - } else + error = ip_output(m, tp->t_inpcb->inp_options, + &tp->t_inpcb->inp_route, so->so_options & SO_DONTROUTE, + 0, tp->t_inpcb); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + { + struct ipv6 *ipv6; + + ipv6->ipv6_length = m->m_pkthdr.len - + sizeof(struct ipv6); + ipv6->ipv6_nexthdr = IPPROTO_TCP; + } + + error = ipv6_output(m, &tp->t_inpcb->inp_route6, + (so->so_options & SO_DONTROUTE), NULL, NULL, + tp->t_inpcb->inp_socket); + break; #endif /* INET6 */ - { - ((struct ip *)ti)->ip_len = m->m_pkthdr.len; - ((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; /* XXX */ - ((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos; /* XXX */ - error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - so->so_options & SO_DONTROUTE, 0, tp->t_inpcb); +#ifdef TUBA + case AF_ISO: + if (tp->t_tuba_pcb) + error = tuba_output(m, tp); + break; +#endif /* TUBA */ + } + #if defined(TCP_SACK) && defined(TCP_FACK) /* Update snd_awnd to reflect the new data that was sent. */ - tp->snd_awnd = tcp_seq_subtract(tp->snd_max, tp->snd_fack) + - tp->retran_data; -#endif - } + tp->snd_awnd = tcp_seq_subtract(tp->snd_max, tp->snd_fack) + + tp->retran_data; +#endif /* defined(TCP_SACK) && defined(TCP_FACK) */ + if (error) { out: if (error == ENOBUFS) { diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 0a1aff645e5..64fb6c7e098 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_subr.c,v 1.14 1999/02/17 00:14:26 deraadt Exp $ */ +/* $OpenBSD: tcp_subr.c,v 1.15 1999/07/02 20:39:08 cmetz Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* @@ -81,6 +81,10 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <sys/domain.h> #endif /* INET6 */ +#if defined(INET) && defined(INET6) +#define defined(INET) && defined(INET6) 1 +#endif /* defined(INET) && defined(INET6) */ + /* patchable/settable parameters for tcp */ int tcp_mssdflt = TCP_MSS; int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; @@ -154,55 +158,99 @@ tcp_init() * for the TCP header. Also, we made the former tcpiphdr header pointer * into just an IP overlay pointer, with casting as appropriate for v6. rja */ -struct tcpiphdr * +struct mbuf * tcp_template(tp) struct tcpcb *tp; { register struct inpcb *inp = tp->t_inpcb; register struct mbuf *m; - register struct tcpiphdr *n; register struct tcphdr *th; -#ifdef INET6 - register struct tcpipv6hdr *ti6; - register struct ipv6 *ipv6; -#endif /* INET6 */ - if ((n = tp->t_template) == 0) { + if ((m = tp->t_template) == 0) { m = m_get(M_DONTWAIT, MT_HEADER); if (m == NULL) return (0); + +#ifdef defined(INET) && defined(INET6) + switch (tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch (0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + m->m_len = sizeof(struct ip); + break; +#endif /* INET */ #ifdef INET6 - if (tp->pf == PF_INET6) - m->m_len = sizeof (struct tcphdr) + sizeof(struct ipv6); - else + case AF_INET6: + m->m_len = sizeof(struct ipv6); + break; #endif /* INET6 */ - m->m_len = sizeof (struct tcpiphdr); - n = mtod(m, struct tcpiphdr *); + } + m->m_len += sizeof (struct tcphdr); + + /* + * The link header, network header, TCP header, and TCP options + * all must fit in this mbuf. For now, assume the worst case of + * TCP options size. Eventually, compute this from tp flags. + */ + if (m->m_len + MAX_TCPOPTLEN + max_linkhdr >= MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_free(m); + return (0); + } + } } + +#ifdef defined(INET) && defined(INET6) + switch(tp->pf) { +#else /* defined(INET) && defined(INET6) */ + switch(0) { +#endif /* defined(INET) && defined(INET6) */ + case 0: +#ifdef INET + case AF_INET: + { + struct ipovly *ipovly; + + ipovly = mtod(m, struct ipovly *); + + bzero(ipovly->ih_x1, sizeof ipovly->ih_x1); + ipovly->ih_pr = IPPROTO_TCP; + ipovly->ih_len = htons(sizeof (struct tcpiphdr) - + sizeof (struct ip)); + ipovly->ih_src = inp->inp_laddr; + ipovly->ih_dst = inp->inp_faddr; + + th = (struct tcphdr *)(mtod(m, caddr_t) + + sizeof(struct ip)); + } + break; +#endif /* INET */ #ifdef INET6 - if (tp->pf == PF_INET6) { + case AF_INET6: + { + struct ipv6 *ipv6; - ti6 = (struct tcpipv6hdr *)n; - ipv6 = (struct ipv6 *)n; - th = &ti6->ti6_t; - - ipv6->ipv6_src = inp->inp_laddr6; - ipv6->ipv6_dst = inp->inp_faddr6; - ipv6->ipv6_versfl = htonl(0x60000000) | - (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff)); - - ipv6->ipv6_nexthdr = IPPROTO_TCP; - ipv6->ipv6_length = htons(sizeof(struct tcphdr)); /*XXX*/ - ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit; - } else + ipv6 = mtod(m, struct ipv6 *); + + ipv6->ipv6_src = inp->inp_laddr6; + ipv6->ipv6_dst = inp->inp_faddr6; + ipv6->ipv6_versfl = htonl(0x60000000) | + (inp->inp_ipv6.ipv6_versfl & + htonl(0x0fffffff)); + + ipv6->ipv6_nexthdr = IPPROTO_TCP; + ipv6->ipv6_length = htons(sizeof(struct tcphdr)); + ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit; + + th = (struct tcphdr *)(mtod(m, caddr_t) + + sizeof(struct ipv6)); + } + break; #endif /* INET6 */ - { - th = &n->ti_t; - bzero(n->ti_x1, sizeof n->ti_x1); - n->ti_pr = IPPROTO_TCP; - n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); - n->ti_src = inp->inp_laddr; - n->ti_dst = inp->inp_faddr; } th->th_sport = inp->inp_lport; @@ -215,7 +263,7 @@ tcp_template(tp) th->th_win = 0; th->th_sum = 0; th->th_urp = 0; - return (n); + return (m); } /* @@ -235,9 +283,9 @@ tcp_template(tp) /* This function looks hairy, because it was so IPv4-dependent. */ #endif /* INET6 */ void -tcp_respond(tp, ti, m, ack, seq, flags) +tcp_respond(tp, template, m, ack, seq, flags) struct tcpcb *tp; - register struct tcpiphdr *ti; + caddr_t template; register struct mbuf *m; tcp_seq ack, seq; int flags; @@ -246,6 +294,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) int win = 0; struct route *ro = 0; register struct tcphdr *th; + register struct tcpiphdr *ti = (struct tcpiphdr *)template; #ifdef INET6 int is_ipv6 = 0; /* true iff IPv6 */ #endif /* INET6 */ @@ -600,7 +649,7 @@ tcp_close(tp) } #endif if (tp->t_template) - (void) m_free(dtom(tp->t_template)); + (void) m_free(tp->t_template); free(tp, M_PCB); inp->inp_ppcb = 0; soisdisconnected(so); diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index c281fda1841..e8017b293b3 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_timer.c,v 1.12 1999/04/21 21:38:58 provos Exp $ */ +/* $OpenBSD: tcp_timer.c,v 1.13 1999/07/02 20:39:08 cmetz Exp $ */ /* $NetBSD: tcp_timer.c,v 1.14 1996/02/13 23:44:09 christos Exp $ */ /* @@ -349,11 +349,15 @@ tcp_timers(tp, timer) * The keepalive packet must have nonzero length * to get a 4.2 host to respond. */ - tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, - tp->rcv_nxt - 1, tp->snd_una - 1, 0); + tcp_respond(tp, + mtod(tp->t_template, caddr_t), + (struct mbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); #else - tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, - tp->rcv_nxt, tp->snd_una - 1, 0); + tcp_respond(tp, + mtod(tp->t_template, caddr_t), + (struct mbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); #endif tp->t_timer[TCPT_KEEP] = tcp_keepintvl; } else diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 38e82edc26c..de6ee75474f 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_usrreq.c,v 1.33 1999/03/24 02:28:21 cmetz Exp $ */ +/* $OpenBSD: tcp_usrreq.c,v 1.34 1999/07/02 20:39:08 cmetz Exp $ */ /* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */ /* @@ -466,7 +466,7 @@ tcp_usrreq(so, req, m, nam, control) panic("tcp_usrreq"); } if (tp && (so->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req, 0); + tcp_trace(TA_USER, ostate, tp, (caddr_t)0, req, 0); splx(s); return (error); } @@ -531,7 +531,13 @@ tcp_ctloutput(op, so, level, optname, mp) break; case TCP_MAXSEG: - if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) + if (m == NULL || m->m_len < sizeof (int)) { + error = EINVAL; + break; + } + + i = *mtod(m, int *); + if (i > 0 && i <= tp->t_maxseg) tp->t_maxseg = i; else error = EINVAL; @@ -539,8 +545,20 @@ tcp_ctloutput(op, so, level, optname, mp) #ifdef TCP_SACK case TCP_SACK_DISABLE: - i = *mtod(m, int *); - tp->sack_disable = i; + if (m == NULL || m->m_len < sizeof (int)) { + error = EINVAL; + break; + } + + if (TCPS_HAVEESTABLISHED(tp->t_state)) { + error = EPERM; + break; + } + + if (*mtod(m, int *)) + tp->sack_disable = 1; + else + tp->sack_disable = 0; break; #endif default: |