xref: /freebsd/sys/netinet/tcp_ecn.c (revision 2d05a1c8)
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