diff options
author | 1999-07-02 20:39:07 +0000 | |
---|---|---|
committer | 1999-07-02 20:39:07 +0000 | |
commit | a237783bf990a3ac2cc58476b3870547b43fe612 (patch) | |
tree | 0acf8b74d0292849eda10f49c5ef75b13d813006 /sys/netinet/tcp_output.c | |
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).
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r-- | sys/netinet/tcp_output.c | 209 |
1 files changed, 120 insertions, 89 deletions
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) { |