diff options
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) { |