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.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 625bca510c8..2453d4c132c 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_output.c,v 1.49 2002/03/08 03:49:58 provos Exp $ */
+/* $OpenBSD: tcp_output.c,v 1.50 2002/05/16 14:10:51 kjc Exp $ */
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
/*
@@ -237,6 +237,9 @@ tcp_output(tp)
#ifdef TCP_SIGNATURE
unsigned int sigoff;
#endif /* TCP_SIGNATURE */
+#ifdef TCP_ECN
+ int needect;
+#endif
#if defined(TCP_SACK) && defined(TCP_SIGNATURE) && defined(DIAGNOSTIC)
if (!tp->sack_disable && (tp->t_flags & TF_SIGNATURE))
@@ -815,6 +818,39 @@ send:
bcopy((caddr_t)opt, (caddr_t)(th + 1), optlen);
th->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
}
+#ifdef TCP_ECN
+ if (tcp_do_ecn) {
+ /*
+ * if we have received congestion experienced segs,
+ * set ECE bit.
+ */
+ if (tp->t_flags & TF_RCVD_CE) {
+ flags |= TH_ECE;
+ tcpstat.tcps_ecn_sndece++;
+ }
+ if (!(tp->t_flags & TF_DISABLE_ECN)) {
+ /*
+ * if this is a SYN seg, set ECE and CWR.
+ * set only ECE for SYN-ACK if peer supports ECN.
+ */
+ if ((flags & (TH_SYN|TH_ACK)) == TH_SYN)
+ flags |= (TH_ECE|TH_CWR);
+ else if ((tp->t_flags & TF_ECN_PERMIT) &&
+ (flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK))
+ flags |= TH_ECE;
+ }
+ /*
+ * if we have reduced the congestion window, notify
+ * the peer by setting CWR bit.
+ */
+ if ((tp->t_flags & TF_ECN_PERMIT) &&
+ (tp->t_flags & TF_SEND_CWR)) {
+ flags |= TH_CWR;
+ tp->t_flags &= ~TF_SEND_CWR;
+ tcpstat.tcps_ecn_sndcwr++;
+ }
+ }
+#endif
th->th_flags = flags;
/*
@@ -1038,6 +1074,23 @@ send:
*/
m->m_pkthdr.len = hdrlen + len;
+#ifdef TCP_ECN
+ /*
+ * if peer is ECN capable, set the ECT bit in the IP header.
+ * but don't set ECT for a pure ack, a retransmit or a window probe.
+ */
+ needect = 0;
+ if (tcp_do_ecn && (tp->t_flags & TF_ECN_PERMIT)) {
+ if (len == 0 || SEQ_LT(tp->snd_nxt, tp->snd_max) ||
+ (tp->t_force && len == 1)) {
+ /* don't set ECT */
+ } else {
+ needect = 1;
+ tcpstat.tcps_ecn_sndect++;
+ }
+ }
+#endif
+
switch (tp->pf) {
case 0: /*default to PF_INET*/
#ifdef INET
@@ -1049,6 +1102,10 @@ send:
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;
+#ifdef TCP_ECN
+ if (needect)
+ ip->ip_tos |= IPTOS_ECN_ECT0;
+#endif
}
error = ip_output(m, tp->t_inpcb->inp_options,
&tp->t_inpcb->inp_route,
@@ -1067,6 +1124,10 @@ send:
sizeof(struct ip6_hdr);
ipv6->ip6_nxt = IPPROTO_TCP;
ipv6->ip6_hlim = in6_selecthlim(tp->t_inpcb, NULL);
+#ifdef TCP_ECN
+ if (needect)
+ ipv6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << 20);
+#endif
}
error = ip6_output(m, tp->t_inpcb->inp_outputopts6,
&tp->t_inpcb->inp_route6,