1f7220c48SRichard Scheffenegger /*-
2f7220c48SRichard Scheffenegger * SPDX-License-Identifier: BSD-3-Clause
3f7220c48SRichard Scheffenegger *
4f7220c48SRichard Scheffenegger * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
5f7220c48SRichard Scheffenegger * The Regents of the University of California. All rights reserved.
6f7220c48SRichard Scheffenegger * Copyright (c) 2007-2008,2010
7f7220c48SRichard Scheffenegger * Swinburne University of Technology, Melbourne, Australia.
8f7220c48SRichard Scheffenegger * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
9f7220c48SRichard Scheffenegger * Copyright (c) 2010 The FreeBSD Foundation
10f7220c48SRichard Scheffenegger * Copyright (c) 2010-2011 Juniper Networks, Inc.
11f7220c48SRichard Scheffenegger * Copyright (c) 2019 Richard Scheffenegger <srichard@netapp.com>
12f7220c48SRichard Scheffenegger * All rights reserved.
13f7220c48SRichard Scheffenegger *
14f7220c48SRichard Scheffenegger * Portions of this software were developed at the Centre for Advanced Internet
15f7220c48SRichard Scheffenegger * Architectures, Swinburne University of Technology, by Lawrence Stewart,
16f7220c48SRichard Scheffenegger * James Healy and David Hayes, made possible in part by a grant from the Cisco
17f7220c48SRichard Scheffenegger * University Research Program Fund at Community Foundation Silicon Valley.
18f7220c48SRichard Scheffenegger *
19f7220c48SRichard Scheffenegger * Portions of this software were developed at the Centre for Advanced
20f7220c48SRichard Scheffenegger * Internet Architectures, Swinburne University of Technology, Melbourne,
21f7220c48SRichard Scheffenegger * Australia by David Hayes under sponsorship from the FreeBSD Foundation.
22f7220c48SRichard Scheffenegger *
23f7220c48SRichard Scheffenegger * Portions of this software were developed by Robert N. M. Watson under
24f7220c48SRichard Scheffenegger * contract to Juniper Networks, Inc.
25f7220c48SRichard Scheffenegger *
26f7220c48SRichard Scheffenegger * Redistribution and use in source and binary forms, with or without
27f7220c48SRichard Scheffenegger * modification, are permitted provided that the following conditions
28f7220c48SRichard Scheffenegger * are met:
29f7220c48SRichard Scheffenegger * 1. Redistributions of source code must retain the above copyright
30f7220c48SRichard Scheffenegger * notice, this list of conditions and the following disclaimer.
31f7220c48SRichard Scheffenegger * 2. Redistributions in binary form must reproduce the above copyright
32f7220c48SRichard Scheffenegger * notice, this list of conditions and the following disclaimer in the
33f7220c48SRichard Scheffenegger * documentation and/or other materials provided with the distribution.
34f7220c48SRichard Scheffenegger * 3. Neither the name of the University nor the names of its contributors
35f7220c48SRichard Scheffenegger * may be used to endorse or promote products derived from this software
36f7220c48SRichard Scheffenegger * without specific prior written permission.
37f7220c48SRichard Scheffenegger *
38f7220c48SRichard Scheffenegger * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39f7220c48SRichard Scheffenegger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40f7220c48SRichard Scheffenegger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41f7220c48SRichard Scheffenegger * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42f7220c48SRichard Scheffenegger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43f7220c48SRichard Scheffenegger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44f7220c48SRichard Scheffenegger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45f7220c48SRichard Scheffenegger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46f7220c48SRichard Scheffenegger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47f7220c48SRichard Scheffenegger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48f7220c48SRichard Scheffenegger * SUCH DAMAGE.
49f7220c48SRichard Scheffenegger */
50f7220c48SRichard Scheffenegger
51f7220c48SRichard Scheffenegger /*
52f7220c48SRichard Scheffenegger * Utility functions to deal with Explicit Congestion Notification in TCP
53f7220c48SRichard Scheffenegger * implementing the essential parts of the Accurate ECN extension
54f7220c48SRichard Scheffenegger * https://tools.ietf.org/html/draft-ietf-tcpm-accurate-ecn-09
55f7220c48SRichard Scheffenegger */
56f7220c48SRichard Scheffenegger
57f7220c48SRichard Scheffenegger #include <sys/cdefs.h>
58f7220c48SRichard Scheffenegger #include "opt_inet.h"
59f7220c48SRichard Scheffenegger #include "opt_inet6.h"
60f7220c48SRichard Scheffenegger
61f7220c48SRichard Scheffenegger #include <sys/param.h>
62f7220c48SRichard Scheffenegger #include <sys/systm.h>
63f7220c48SRichard Scheffenegger #include <sys/kernel.h>
64f7220c48SRichard Scheffenegger #include <sys/sysctl.h>
65f7220c48SRichard Scheffenegger #include <sys/malloc.h>
66f7220c48SRichard Scheffenegger #include <sys/mbuf.h>
67f7220c48SRichard Scheffenegger #include <sys/socket.h>
68f7220c48SRichard Scheffenegger #include <sys/socketvar.h>
69f7220c48SRichard Scheffenegger
70f7220c48SRichard Scheffenegger #include <machine/cpu.h>
71f7220c48SRichard Scheffenegger
72f7220c48SRichard Scheffenegger #include <vm/uma.h>
73f7220c48SRichard Scheffenegger
74f7220c48SRichard Scheffenegger #include <net/if.h>
75f7220c48SRichard Scheffenegger #include <net/if_var.h>
76f7220c48SRichard Scheffenegger #include <net/route.h>
77f7220c48SRichard Scheffenegger #include <net/vnet.h>
78f7220c48SRichard Scheffenegger
79f7220c48SRichard Scheffenegger #include <netinet/in.h>
80f7220c48SRichard Scheffenegger #include <netinet/in_systm.h>
81f7220c48SRichard Scheffenegger #include <netinet/ip.h>
82f7220c48SRichard Scheffenegger #include <netinet/in_var.h>
83f7220c48SRichard Scheffenegger #include <netinet/in_pcb.h>
84f7220c48SRichard Scheffenegger #include <netinet/ip_var.h>
85f7220c48SRichard Scheffenegger #include <netinet/ip6.h>
86f7220c48SRichard Scheffenegger #include <netinet/icmp6.h>
87f7220c48SRichard Scheffenegger #include <netinet6/nd6.h>
88f7220c48SRichard Scheffenegger #include <netinet6/ip6_var.h>
89f7220c48SRichard Scheffenegger #include <netinet6/in6_pcb.h>
90f7220c48SRichard Scheffenegger #include <netinet/tcp.h>
91f7220c48SRichard Scheffenegger #include <netinet/tcp_fsm.h>
92f7220c48SRichard Scheffenegger #include <netinet/tcp_seq.h>
93f7220c48SRichard Scheffenegger #include <netinet/tcp_var.h>
94f7220c48SRichard Scheffenegger #include <netinet/tcp_syncache.h>
95f7220c48SRichard Scheffenegger #include <netinet/tcp_timer.h>
96f7220c48SRichard Scheffenegger #include <netinet/tcpip.h>
97f7220c48SRichard Scheffenegger #include <netinet/tcp_ecn.h>
98f7220c48SRichard Scheffenegger
99fc262fd3SRichard Scheffenegger static inline int tcp_ecn_get_ace(uint16_t);
100fc262fd3SRichard Scheffenegger static inline void tcp_ecn_set_ace(uint16_t *, uint32_t);
101fc262fd3SRichard Scheffenegger
102004bb636SRichard Scheffenegger static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, ecn,
103004bb636SRichard Scheffenegger CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
104004bb636SRichard Scheffenegger "TCP ECN");
105004bb636SRichard Scheffenegger
106004bb636SRichard Scheffenegger VNET_DEFINE(int, tcp_do_ecn) = 2;
107004bb636SRichard Scheffenegger SYSCTL_INT(_net_inet_tcp_ecn, OID_AUTO, enable,
108004bb636SRichard Scheffenegger CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_do_ecn), 0,
109004bb636SRichard Scheffenegger "TCP ECN support");
110004bb636SRichard Scheffenegger
111004bb636SRichard Scheffenegger VNET_DEFINE(int, tcp_ecn_maxretries) = 1;
112004bb636SRichard Scheffenegger SYSCTL_INT(_net_inet_tcp_ecn, OID_AUTO, maxretries,
113004bb636SRichard Scheffenegger CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_ecn_maxretries), 0,
114004bb636SRichard Scheffenegger "Max retries before giving up on ECN");
115f7220c48SRichard Scheffenegger
116f7220c48SRichard Scheffenegger /*
117f7220c48SRichard Scheffenegger * Process incoming SYN,ACK packet
118f7220c48SRichard Scheffenegger */
119f7220c48SRichard Scheffenegger void
tcp_ecn_input_syn_sent(struct tcpcb * tp,uint16_t thflags,int iptos)120f7220c48SRichard Scheffenegger tcp_ecn_input_syn_sent(struct tcpcb *tp, uint16_t thflags, int iptos)
121f7220c48SRichard Scheffenegger {
122fc262fd3SRichard Scheffenegger switch (V_tcp_do_ecn) {
123fc262fd3SRichard Scheffenegger case 0:
1244012ef77SRichard Scheffenegger return;
125fc262fd3SRichard Scheffenegger case 1:
126fc262fd3SRichard Scheffenegger /* FALLTHROUGH */
127fc262fd3SRichard Scheffenegger case 2:
1284012ef77SRichard Scheffenegger /* RFC3168 ECN handling */
1294012ef77SRichard Scheffenegger if ((thflags & (TH_CWR | TH_ECE)) == (0 | TH_ECE)) {
130f7220c48SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
13183c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ACE_PERMIT;
1321790549dSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
133f7220c48SRichard Scheffenegger }
134fc262fd3SRichard Scheffenegger break;
135fc262fd3SRichard Scheffenegger case 3:
136fc262fd3SRichard Scheffenegger /* FALLTHROUGH */
137fc262fd3SRichard Scheffenegger case 4:
138*2d05a1c8SRichard Scheffenegger /*
139*2d05a1c8SRichard Scheffenegger * Decoding Accurate ECN according to
140fc262fd3SRichard Scheffenegger * table in section 3.1.1
141*2d05a1c8SRichard Scheffenegger *
142*2d05a1c8SRichard Scheffenegger * On the SYN,ACK, process the AccECN
1434012ef77SRichard Scheffenegger * flags indicating the state the SYN
1444012ef77SRichard Scheffenegger * was delivered.
1454012ef77SRichard Scheffenegger * Reactions to Path ECN mangling can
1464012ef77SRichard Scheffenegger * come here.
1474012ef77SRichard Scheffenegger */
1484012ef77SRichard Scheffenegger switch (thflags & (TH_AE | TH_CWR | TH_ECE)) {
1494012ef77SRichard Scheffenegger /* RFC3168 SYN */
1504012ef77SRichard Scheffenegger case (0|0|TH_ECE):
1514012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
15283c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ACE_PERMIT;
1534012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
1544012ef77SRichard Scheffenegger break;
1554012ef77SRichard Scheffenegger /* non-ECT SYN */
1564012ef77SRichard Scheffenegger case (0|TH_CWR|0):
1574012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
15883c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_PERMIT;
1594012ef77SRichard Scheffenegger tp->t_scep = 5;
1604012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
1614012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_nect);
1624012ef77SRichard Scheffenegger break;
1634012ef77SRichard Scheffenegger /* ECT0 SYN */
1644012ef77SRichard Scheffenegger case (TH_AE|0|0):
1654012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
16683c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_PERMIT;
1674012ef77SRichard Scheffenegger tp->t_scep = 5;
1684012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
1694012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_ect0);
1704012ef77SRichard Scheffenegger break;
1714012ef77SRichard Scheffenegger /* ECT1 SYN */
1724012ef77SRichard Scheffenegger case (0|TH_CWR|TH_ECE):
1734012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
17483c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_PERMIT;
1754012ef77SRichard Scheffenegger tp->t_scep = 5;
1764012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
1774012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_ect1);
1784012ef77SRichard Scheffenegger break;
1794012ef77SRichard Scheffenegger /* CE SYN */
1804012ef77SRichard Scheffenegger case (TH_AE|TH_CWR|0):
1814012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
18283c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_PERMIT;
1834012ef77SRichard Scheffenegger tp->t_scep = 6;
1844012ef77SRichard Scheffenegger /*
1854012ef77SRichard Scheffenegger * reduce the IW to 2 MSS (to
1864012ef77SRichard Scheffenegger * account for delayed acks) if
1874012ef77SRichard Scheffenegger * the SYN,ACK was CE marked
1884012ef77SRichard Scheffenegger */
1894012ef77SRichard Scheffenegger tp->snd_cwnd = 2 * tcp_maxseg(tp);
1904012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
1914012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_nect);
1924012ef77SRichard Scheffenegger break;
1934012ef77SRichard Scheffenegger default:
19483c1ec92SRichard Scheffenegger tp->t_flags2 &= ~(TF2_ECN_PERMIT | TF2_ACE_PERMIT);
1954012ef77SRichard Scheffenegger break;
1964012ef77SRichard Scheffenegger }
1974012ef77SRichard Scheffenegger /*
1984012ef77SRichard Scheffenegger * Set the AccECN Codepoints on
1994012ef77SRichard Scheffenegger * the outgoing <ACK> to the ECN
2004012ef77SRichard Scheffenegger * state of the <SYN,ACK>
2014012ef77SRichard Scheffenegger * according to table 3 in the
2024012ef77SRichard Scheffenegger * AccECN draft
2034012ef77SRichard Scheffenegger */
2044012ef77SRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
2054012ef77SRichard Scheffenegger case (IPTOS_ECN_NOTECT):
2064012ef77SRichard Scheffenegger tp->t_rcep = 0b010;
2074012ef77SRichard Scheffenegger break;
2084012ef77SRichard Scheffenegger case (IPTOS_ECN_ECT0):
2094012ef77SRichard Scheffenegger tp->t_rcep = 0b100;
2104012ef77SRichard Scheffenegger break;
2114012ef77SRichard Scheffenegger case (IPTOS_ECN_ECT1):
2124012ef77SRichard Scheffenegger tp->t_rcep = 0b011;
2134012ef77SRichard Scheffenegger break;
2144012ef77SRichard Scheffenegger case (IPTOS_ECN_CE):
2154012ef77SRichard Scheffenegger tp->t_rcep = 0b110;
2164012ef77SRichard Scheffenegger break;
2174012ef77SRichard Scheffenegger }
218fc262fd3SRichard Scheffenegger break;
2194012ef77SRichard Scheffenegger }
220f7220c48SRichard Scheffenegger }
221f7220c48SRichard Scheffenegger
222f7220c48SRichard Scheffenegger /*
223f7220c48SRichard Scheffenegger * Handle parallel SYN for ECN
224f7220c48SRichard Scheffenegger */
225f7220c48SRichard Scheffenegger void
tcp_ecn_input_parallel_syn(struct tcpcb * tp,uint16_t thflags,int iptos)226f7220c48SRichard Scheffenegger tcp_ecn_input_parallel_syn(struct tcpcb *tp, uint16_t thflags, int iptos)
227f7220c48SRichard Scheffenegger {
228f7220c48SRichard Scheffenegger if (thflags & TH_ACK)
229f7220c48SRichard Scheffenegger return;
230fc262fd3SRichard Scheffenegger switch (V_tcp_do_ecn) {
231fc262fd3SRichard Scheffenegger case 0:
232f7220c48SRichard Scheffenegger return;
233fc262fd3SRichard Scheffenegger case 1:
234fc262fd3SRichard Scheffenegger /* FALLTHROUGH */
235fc262fd3SRichard Scheffenegger case 2:
236f7220c48SRichard Scheffenegger /* RFC3168 ECN handling */
237f7220c48SRichard Scheffenegger if ((thflags & (TH_CWR | TH_ECE)) == (TH_CWR | TH_ECE)) {
238f7220c48SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
23983c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ACE_PERMIT;
240f7220c48SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_SND_ECE;
2411790549dSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
242f7220c48SRichard Scheffenegger }
243fc262fd3SRichard Scheffenegger break;
244fc262fd3SRichard Scheffenegger case 3:
245fc262fd3SRichard Scheffenegger /* FALLTHROUGH */
246fc262fd3SRichard Scheffenegger case 4:
2474012ef77SRichard Scheffenegger /* AccECN handling */
2484012ef77SRichard Scheffenegger switch (thflags & (TH_AE | TH_CWR | TH_ECE)) {
2494012ef77SRichard Scheffenegger default:
2504012ef77SRichard Scheffenegger case (0|0|0):
25183c1ec92SRichard Scheffenegger tp->t_flags2 &= ~(TF2_ECN_PERMIT | TF2_ACE_PERMIT);
2524012ef77SRichard Scheffenegger break;
2534012ef77SRichard Scheffenegger case (0|TH_CWR|TH_ECE):
2544012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
25583c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ACE_PERMIT;
2564012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_SND_ECE;
2574012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
2584012ef77SRichard Scheffenegger break;
2594012ef77SRichard Scheffenegger case (TH_AE|TH_CWR|TH_ECE):
2604012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
26183c1ec92SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_PERMIT;
2624012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
2634012ef77SRichard Scheffenegger /*
2644012ef77SRichard Scheffenegger * Set the AccECN Codepoints on
2654012ef77SRichard Scheffenegger * the outgoing <ACK> to the ECN
2664012ef77SRichard Scheffenegger * state of the <SYN,ACK>
2674012ef77SRichard Scheffenegger * according to table 3 in the
2684012ef77SRichard Scheffenegger * AccECN draft
2694012ef77SRichard Scheffenegger */
2704012ef77SRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
2714012ef77SRichard Scheffenegger case (IPTOS_ECN_NOTECT):
2724012ef77SRichard Scheffenegger tp->t_rcep = 0b010;
2734012ef77SRichard Scheffenegger break;
2744012ef77SRichard Scheffenegger case (IPTOS_ECN_ECT0):
2754012ef77SRichard Scheffenegger tp->t_rcep = 0b100;
2764012ef77SRichard Scheffenegger break;
2774012ef77SRichard Scheffenegger case (IPTOS_ECN_ECT1):
2784012ef77SRichard Scheffenegger tp->t_rcep = 0b011;
2794012ef77SRichard Scheffenegger break;
2804012ef77SRichard Scheffenegger case (IPTOS_ECN_CE):
2814012ef77SRichard Scheffenegger tp->t_rcep = 0b110;
2824012ef77SRichard Scheffenegger break;
2834012ef77SRichard Scheffenegger }
2844012ef77SRichard Scheffenegger break;
2854012ef77SRichard Scheffenegger }
286fc262fd3SRichard Scheffenegger break;
287f7220c48SRichard Scheffenegger }
288f7220c48SRichard Scheffenegger }
289f7220c48SRichard Scheffenegger
290f7220c48SRichard Scheffenegger /*
291f7220c48SRichard Scheffenegger * TCP ECN processing.
292f7220c48SRichard Scheffenegger */
293f7220c48SRichard Scheffenegger int
tcp_ecn_input_segment(struct tcpcb * tp,uint16_t thflags,int tlen,int pkts,int iptos)294b1258b76SRichard Scheffenegger tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int tlen, int pkts, int iptos)
295f7220c48SRichard Scheffenegger {
296b1258b76SRichard Scheffenegger int delta_cep = 0;
297f7220c48SRichard Scheffenegger
298f7220c48SRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
299f7220c48SRichard Scheffenegger case IPTOS_ECN_CE:
3001a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvce);
301f7220c48SRichard Scheffenegger break;
302f7220c48SRichard Scheffenegger case IPTOS_ECN_ECT0:
3031a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvect0);
304f7220c48SRichard Scheffenegger break;
305f7220c48SRichard Scheffenegger case IPTOS_ECN_ECT1:
3061a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvect1);
307f7220c48SRichard Scheffenegger break;
308f7220c48SRichard Scheffenegger }
309f7220c48SRichard Scheffenegger
3101a70101aSRichard Scheffenegger if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT)) {
3114012ef77SRichard Scheffenegger if (tp->t_flags2 & TF2_ACE_PERMIT) {
3124012ef77SRichard Scheffenegger if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
3134012ef77SRichard Scheffenegger tp->t_rcep += 1;
3144012ef77SRichard Scheffenegger if (tp->t_flags2 & TF2_ECN_PERMIT) {
315b1258b76SRichard Scheffenegger delta_cep = (tcp_ecn_get_ace(thflags) + 8 -
316b1258b76SRichard Scheffenegger (tp->t_scep & 7)) & 7;
317b1258b76SRichard Scheffenegger if (delta_cep < pkts)
318b1258b76SRichard Scheffenegger delta_cep = pkts -
319b1258b76SRichard Scheffenegger ((pkts - delta_cep) & 7);
320b1258b76SRichard Scheffenegger tp->t_scep += delta_cep;
3214012ef77SRichard Scheffenegger } else {
3224012ef77SRichard Scheffenegger /*
3234012ef77SRichard Scheffenegger * process the final ACK of the 3WHS
3244012ef77SRichard Scheffenegger * see table 3 in draft-ietf-tcpm-accurate-ecn
3254012ef77SRichard Scheffenegger */
3264012ef77SRichard Scheffenegger switch (tcp_ecn_get_ace(thflags)) {
3274012ef77SRichard Scheffenegger case 0b010:
3284012ef77SRichard Scheffenegger /* nonECT SYN or SYN,ACK */
3297ea8d027SRichard Scheffenegger /* FALLTHROUGH */
3304012ef77SRichard Scheffenegger case 0b011:
3314012ef77SRichard Scheffenegger /* ECT1 SYN or SYN,ACK */
3327ea8d027SRichard Scheffenegger /* FALLTHROUGH */
3334012ef77SRichard Scheffenegger case 0b100:
3344012ef77SRichard Scheffenegger /* ECT0 SYN or SYN,ACK */
3354012ef77SRichard Scheffenegger tp->t_scep = 5;
3364012ef77SRichard Scheffenegger break;
3374012ef77SRichard Scheffenegger case 0b110:
3384012ef77SRichard Scheffenegger /* CE SYN or SYN,ACK */
3394012ef77SRichard Scheffenegger tp->t_scep = 6;
3404012ef77SRichard Scheffenegger tp->snd_cwnd = 2 * tcp_maxseg(tp);
3414012ef77SRichard Scheffenegger break;
3424012ef77SRichard Scheffenegger default:
3434012ef77SRichard Scheffenegger /* mangled AccECN handshake */
3444012ef77SRichard Scheffenegger tp->t_scep = 5;
3454012ef77SRichard Scheffenegger break;
3464012ef77SRichard Scheffenegger }
3474012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
3484012ef77SRichard Scheffenegger }
3494012ef77SRichard Scheffenegger } else {
350f7220c48SRichard Scheffenegger /* RFC3168 ECN handling */
35122c81cc5SRichard Scheffenegger if ((thflags & (TH_SYN | TH_ECE)) == TH_ECE) {
352b1258b76SRichard Scheffenegger delta_cep = 1;
35322c81cc5SRichard Scheffenegger tp->t_scep++;
35422c81cc5SRichard Scheffenegger }
355f7220c48SRichard Scheffenegger if (thflags & TH_CWR) {
356f7220c48SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_SND_ECE;
357f7220c48SRichard Scheffenegger tp->t_flags |= TF_ACKNOW;
358f7220c48SRichard Scheffenegger }
359f7220c48SRichard Scheffenegger if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
360f7220c48SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_SND_ECE;
3614012ef77SRichard Scheffenegger }
362f7220c48SRichard Scheffenegger
363f7220c48SRichard Scheffenegger /* Process a packet differently from RFC3168. */
364f7220c48SRichard Scheffenegger cc_ecnpkt_handler_flags(tp, thflags, iptos);
365f7220c48SRichard Scheffenegger }
366f7220c48SRichard Scheffenegger
367b1258b76SRichard Scheffenegger return delta_cep;
368f7220c48SRichard Scheffenegger }
369f7220c48SRichard Scheffenegger
370f7220c48SRichard Scheffenegger /*
371f7220c48SRichard Scheffenegger * Send ECN setup <SYN> packet header flags
372f7220c48SRichard Scheffenegger */
373f7220c48SRichard Scheffenegger uint16_t
tcp_ecn_output_syn_sent(struct tcpcb * tp)374f7220c48SRichard Scheffenegger tcp_ecn_output_syn_sent(struct tcpcb *tp)
375f7220c48SRichard Scheffenegger {
376f7220c48SRichard Scheffenegger uint16_t thflags = 0;
377f7220c48SRichard Scheffenegger
3784012ef77SRichard Scheffenegger if (V_tcp_do_ecn == 0)
3794012ef77SRichard Scheffenegger return thflags;
380f7220c48SRichard Scheffenegger if (V_tcp_do_ecn == 1) {
381f7220c48SRichard Scheffenegger /* Send a RFC3168 ECN setup <SYN> packet */
382f7220c48SRichard Scheffenegger if (tp->t_rxtshift >= 1) {
383f7220c48SRichard Scheffenegger if (tp->t_rxtshift <= V_tcp_ecn_maxretries)
384f7220c48SRichard Scheffenegger thflags = TH_ECE|TH_CWR;
385f7220c48SRichard Scheffenegger } else
386f7220c48SRichard Scheffenegger thflags = TH_ECE|TH_CWR;
387*2d05a1c8SRichard Scheffenegger } else if (V_tcp_do_ecn == 3) {
3884012ef77SRichard Scheffenegger /* Send an Accurate ECN setup <SYN> packet */
3894012ef77SRichard Scheffenegger if (tp->t_rxtshift >= 1) {
3904012ef77SRichard Scheffenegger if (tp->t_rxtshift <= V_tcp_ecn_maxretries)
3914012ef77SRichard Scheffenegger thflags = TH_ECE|TH_CWR|TH_AE;
3924012ef77SRichard Scheffenegger } else
3934012ef77SRichard Scheffenegger thflags = TH_ECE|TH_CWR|TH_AE;
394f7220c48SRichard Scheffenegger }
395f7220c48SRichard Scheffenegger
396f7220c48SRichard Scheffenegger return thflags;
397f7220c48SRichard Scheffenegger }
398f7220c48SRichard Scheffenegger
399f7220c48SRichard Scheffenegger /*
400f7220c48SRichard Scheffenegger * output processing of ECN feature
401f7220c48SRichard Scheffenegger * returning IP ECN header codepoint
402f7220c48SRichard Scheffenegger */
403f7220c48SRichard Scheffenegger int
tcp_ecn_output_established(struct tcpcb * tp,uint16_t * thflags,int len,bool rxmit)4042ff07d92SRichard Scheffenegger tcp_ecn_output_established(struct tcpcb *tp, uint16_t *thflags, int len, bool rxmit)
405f7220c48SRichard Scheffenegger {
406f7220c48SRichard Scheffenegger int ipecn = IPTOS_ECN_NOTECT;
407f7220c48SRichard Scheffenegger bool newdata;
408f7220c48SRichard Scheffenegger
409f7220c48SRichard Scheffenegger /*
410f7220c48SRichard Scheffenegger * If the peer has ECN, mark data packets with
411f7220c48SRichard Scheffenegger * ECN capable transmission (ECT).
412f7220c48SRichard Scheffenegger * Ignore pure control packets, retransmissions
413f7220c48SRichard Scheffenegger * and window probes.
414f7220c48SRichard Scheffenegger */
415f7220c48SRichard Scheffenegger newdata = (len > 0 && SEQ_GEQ(tp->snd_nxt, tp->snd_max) &&
4162ff07d92SRichard Scheffenegger !rxmit &&
417f7220c48SRichard Scheffenegger !((tp->t_flags & TF_FORCEDATA) && len == 1));
4184012ef77SRichard Scheffenegger /* RFC3168 ECN marking, only new data segments */
419f7220c48SRichard Scheffenegger if (newdata) {
420dc9daa04SRichard Scheffenegger if (tp->t_flags2 & TF2_ECN_USE_ECT1) {
421dc9daa04SRichard Scheffenegger ipecn = IPTOS_ECN_ECT1;
4221a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_sndect1);
423dc9daa04SRichard Scheffenegger } else {
424f7220c48SRichard Scheffenegger ipecn = IPTOS_ECN_ECT0;
4251a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_sndect0);
426f7220c48SRichard Scheffenegger }
427dc9daa04SRichard Scheffenegger }
428f7220c48SRichard Scheffenegger /*
429f7220c48SRichard Scheffenegger * Reply with proper ECN notifications.
430f7220c48SRichard Scheffenegger */
4314012ef77SRichard Scheffenegger if (tp->t_flags2 & TF2_ACE_PERMIT) {
432fc262fd3SRichard Scheffenegger tcp_ecn_set_ace(thflags, tp->t_rcep);
4334012ef77SRichard Scheffenegger if (!(tp->t_flags2 & TF2_ECN_PERMIT)) {
4344012ef77SRichard Scheffenegger /*
4354012ef77SRichard Scheffenegger * here we process the final
4364012ef77SRichard Scheffenegger * ACK of the 3WHS
4374012ef77SRichard Scheffenegger */
4384012ef77SRichard Scheffenegger if (tp->t_rcep == 0b110) {
4394012ef77SRichard Scheffenegger tp->t_rcep = 6;
4404012ef77SRichard Scheffenegger } else {
4414012ef77SRichard Scheffenegger tp->t_rcep = 5;
4424012ef77SRichard Scheffenegger }
4434012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
4444012ef77SRichard Scheffenegger }
4454012ef77SRichard Scheffenegger } else {
446f7220c48SRichard Scheffenegger if (newdata &&
447f7220c48SRichard Scheffenegger (tp->t_flags2 & TF2_ECN_SND_CWR)) {
448f7220c48SRichard Scheffenegger *thflags |= TH_CWR;
449f7220c48SRichard Scheffenegger tp->t_flags2 &= ~TF2_ECN_SND_CWR;
450f7220c48SRichard Scheffenegger }
451f7220c48SRichard Scheffenegger if (tp->t_flags2 & TF2_ECN_SND_ECE)
452f7220c48SRichard Scheffenegger *thflags |= TH_ECE;
4534012ef77SRichard Scheffenegger }
454f7220c48SRichard Scheffenegger
455f7220c48SRichard Scheffenegger return ipecn;
456f7220c48SRichard Scheffenegger }
457f7220c48SRichard Scheffenegger
458f7220c48SRichard Scheffenegger /*
459f7220c48SRichard Scheffenegger * Set up the ECN related tcpcb fields from
460f7220c48SRichard Scheffenegger * a syncache entry
461f7220c48SRichard Scheffenegger */
462f7220c48SRichard Scheffenegger void
tcp_ecn_syncache_socket(struct tcpcb * tp,struct syncache * sc)463f7220c48SRichard Scheffenegger tcp_ecn_syncache_socket(struct tcpcb *tp, struct syncache *sc)
464f7220c48SRichard Scheffenegger {
4653f169c54SRichard Scheffenegger if (sc->sc_flags & SCF_ECN_MASK) {
4663f169c54SRichard Scheffenegger switch (sc->sc_flags & SCF_ECN_MASK) {
467f7220c48SRichard Scheffenegger case SCF_ECN:
468f7220c48SRichard Scheffenegger tp->t_flags2 |= TF2_ECN_PERMIT;
469f7220c48SRichard Scheffenegger break;
4704012ef77SRichard Scheffenegger case SCF_ACE_N:
4717ea8d027SRichard Scheffenegger /* FALLTHROUGH */
4724012ef77SRichard Scheffenegger case SCF_ACE_0:
4737ea8d027SRichard Scheffenegger /* FALLTHROUGH */
4744012ef77SRichard Scheffenegger case SCF_ACE_1:
4754012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
4764012ef77SRichard Scheffenegger tp->t_scep = 5;
4774012ef77SRichard Scheffenegger tp->t_rcep = 5;
4784012ef77SRichard Scheffenegger break;
4794012ef77SRichard Scheffenegger case SCF_ACE_CE:
4804012ef77SRichard Scheffenegger tp->t_flags2 |= TF2_ACE_PERMIT;
4814012ef77SRichard Scheffenegger tp->t_scep = 6;
4824012ef77SRichard Scheffenegger tp->t_rcep = 6;
4834012ef77SRichard Scheffenegger break;
484f7220c48SRichard Scheffenegger }
485f7220c48SRichard Scheffenegger }
486f7220c48SRichard Scheffenegger }
487f7220c48SRichard Scheffenegger
488f7220c48SRichard Scheffenegger /*
489f7220c48SRichard Scheffenegger * Process a <SYN> packets ECN information, and provide the
490f7220c48SRichard Scheffenegger * syncache with the relevant information.
491f7220c48SRichard Scheffenegger */
492f7220c48SRichard Scheffenegger int
tcp_ecn_syncache_add(uint16_t thflags,int iptos)493f7220c48SRichard Scheffenegger tcp_ecn_syncache_add(uint16_t thflags, int iptos)
494f7220c48SRichard Scheffenegger {
495f7220c48SRichard Scheffenegger int scflags = 0;
496f7220c48SRichard Scheffenegger
4971a70101aSRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
4981a70101aSRichard Scheffenegger case IPTOS_ECN_CE:
4991a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvce);
5001a70101aSRichard Scheffenegger break;
5011a70101aSRichard Scheffenegger case IPTOS_ECN_ECT0:
5021a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvect0);
5031a70101aSRichard Scheffenegger break;
5041a70101aSRichard Scheffenegger case IPTOS_ECN_ECT1:
5051a70101aSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_rcvect1);
5061a70101aSRichard Scheffenegger break;
5071a70101aSRichard Scheffenegger }
5081a70101aSRichard Scheffenegger
5094012ef77SRichard Scheffenegger switch (thflags & (TH_AE|TH_CWR|TH_ECE)) {
510f7220c48SRichard Scheffenegger /* no ECN */
5114012ef77SRichard Scheffenegger case (0|0|0):
512f7220c48SRichard Scheffenegger break;
513f7220c48SRichard Scheffenegger /* legacy ECN */
5144012ef77SRichard Scheffenegger case (0|TH_CWR|TH_ECE):
515f7220c48SRichard Scheffenegger scflags = SCF_ECN;
516f7220c48SRichard Scheffenegger break;
5174012ef77SRichard Scheffenegger /* Accurate ECN */
5184012ef77SRichard Scheffenegger case (TH_AE|TH_CWR|TH_ECE):
5194012ef77SRichard Scheffenegger if ((V_tcp_do_ecn == 3) ||
5204012ef77SRichard Scheffenegger (V_tcp_do_ecn == 4)) {
5214012ef77SRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
5224012ef77SRichard Scheffenegger case IPTOS_ECN_CE:
5234012ef77SRichard Scheffenegger scflags = SCF_ACE_CE;
5244012ef77SRichard Scheffenegger break;
5254012ef77SRichard Scheffenegger case IPTOS_ECN_ECT0:
5264012ef77SRichard Scheffenegger scflags = SCF_ACE_0;
5274012ef77SRichard Scheffenegger break;
5284012ef77SRichard Scheffenegger case IPTOS_ECN_ECT1:
5294012ef77SRichard Scheffenegger scflags = SCF_ACE_1;
5304012ef77SRichard Scheffenegger break;
5314012ef77SRichard Scheffenegger case IPTOS_ECN_NOTECT:
5324012ef77SRichard Scheffenegger scflags = SCF_ACE_N;
5334012ef77SRichard Scheffenegger break;
5344012ef77SRichard Scheffenegger }
5354012ef77SRichard Scheffenegger } else
5364012ef77SRichard Scheffenegger scflags = SCF_ECN;
5374012ef77SRichard Scheffenegger break;
5384012ef77SRichard Scheffenegger /* Default Case (section 3.1.2) */
539f7220c48SRichard Scheffenegger default:
5404012ef77SRichard Scheffenegger if ((V_tcp_do_ecn == 3) ||
5414012ef77SRichard Scheffenegger (V_tcp_do_ecn == 4)) {
5424012ef77SRichard Scheffenegger switch (iptos & IPTOS_ECN_MASK) {
5434012ef77SRichard Scheffenegger case IPTOS_ECN_CE:
5444012ef77SRichard Scheffenegger scflags = SCF_ACE_CE;
5454012ef77SRichard Scheffenegger break;
5464012ef77SRichard Scheffenegger case IPTOS_ECN_ECT0:
5474012ef77SRichard Scheffenegger scflags = SCF_ACE_0;
5484012ef77SRichard Scheffenegger break;
5494012ef77SRichard Scheffenegger case IPTOS_ECN_ECT1:
5504012ef77SRichard Scheffenegger scflags = SCF_ACE_1;
5514012ef77SRichard Scheffenegger break;
5524012ef77SRichard Scheffenegger case IPTOS_ECN_NOTECT:
5534012ef77SRichard Scheffenegger scflags = SCF_ACE_N;
5544012ef77SRichard Scheffenegger break;
5554012ef77SRichard Scheffenegger }
5564012ef77SRichard Scheffenegger }
557f7220c48SRichard Scheffenegger break;
558f7220c48SRichard Scheffenegger }
559f7220c48SRichard Scheffenegger return scflags;
560f7220c48SRichard Scheffenegger }
561f7220c48SRichard Scheffenegger
562f7220c48SRichard Scheffenegger /*
563f7220c48SRichard Scheffenegger * Set up the ECN information for the <SYN,ACK> from
564f7220c48SRichard Scheffenegger * syncache information.
565f7220c48SRichard Scheffenegger */
566f7220c48SRichard Scheffenegger uint16_t
tcp_ecn_syncache_respond(uint16_t thflags,struct syncache * sc)567f7220c48SRichard Scheffenegger tcp_ecn_syncache_respond(uint16_t thflags, struct syncache *sc)
568f7220c48SRichard Scheffenegger {
569f7220c48SRichard Scheffenegger if ((thflags & TH_SYN) &&
5703f169c54SRichard Scheffenegger (sc->sc_flags & SCF_ECN_MASK)) {
5713f169c54SRichard Scheffenegger switch (sc->sc_flags & SCF_ECN_MASK) {
572f7220c48SRichard Scheffenegger case SCF_ECN:
5734012ef77SRichard Scheffenegger thflags |= (0 | 0 | TH_ECE);
5741790549dSRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
575f7220c48SRichard Scheffenegger break;
5764012ef77SRichard Scheffenegger case SCF_ACE_N:
5774012ef77SRichard Scheffenegger thflags |= (0 | TH_CWR | 0);
5784012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
5794012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_nect);
5804012ef77SRichard Scheffenegger break;
5814012ef77SRichard Scheffenegger case SCF_ACE_0:
5824012ef77SRichard Scheffenegger thflags |= (TH_AE | 0 | 0);
5834012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
5844012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_ect0);
5854012ef77SRichard Scheffenegger break;
5864012ef77SRichard Scheffenegger case SCF_ACE_1:
5874012ef77SRichard Scheffenegger thflags |= (0 | TH_ECE | TH_CWR);
5884012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
5894012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_ect1);
5904012ef77SRichard Scheffenegger break;
5914012ef77SRichard Scheffenegger case SCF_ACE_CE:
5924012ef77SRichard Scheffenegger thflags |= (TH_AE | TH_CWR | 0);
5934012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ecn_shs);
5944012ef77SRichard Scheffenegger TCPSTAT_INC(tcps_ace_ce);
5954012ef77SRichard Scheffenegger break;
596f7220c48SRichard Scheffenegger }
597f7220c48SRichard Scheffenegger }
598f7220c48SRichard Scheffenegger return thflags;
599f7220c48SRichard Scheffenegger }
6004012ef77SRichard Scheffenegger
601fc262fd3SRichard Scheffenegger static inline int
tcp_ecn_get_ace(uint16_t thflags)6024012ef77SRichard Scheffenegger tcp_ecn_get_ace(uint16_t thflags)
6034012ef77SRichard Scheffenegger {
604fc262fd3SRichard Scheffenegger return ((thflags & (TH_AE|TH_CWR|TH_ECE)) >> TH_ACE_SHIFT);
605fc262fd3SRichard Scheffenegger }
6064012ef77SRichard Scheffenegger
607fc262fd3SRichard Scheffenegger static inline void
tcp_ecn_set_ace(uint16_t * thflags,uint32_t t_rcep)608fc262fd3SRichard Scheffenegger tcp_ecn_set_ace(uint16_t *thflags, uint32_t t_rcep)
609fc262fd3SRichard Scheffenegger {
610fc262fd3SRichard Scheffenegger *thflags &= ~(TH_AE|TH_CWR|TH_ECE);
611fc262fd3SRichard Scheffenegger *thflags |= ((t_rcep << TH_ACE_SHIFT) & (TH_AE|TH_CWR|TH_ECE));
6124012ef77SRichard Scheffenegger }
613