summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/tcp_output.c')
-rw-r--r--sys/netinet/tcp_output.c209
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) {