1aa97dd1cSKonstantin Ananyev/*
27e18fa1bSKonstantin Ananyev * Copyright (c) 2016-2017  Intel Corporation.
3aa97dd1cSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
4aa97dd1cSKonstantin Ananyev * you may not use this file except in compliance with the License.
5aa97dd1cSKonstantin Ananyev * You may obtain a copy of the License at:
6aa97dd1cSKonstantin Ananyev *
7aa97dd1cSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
8aa97dd1cSKonstantin Ananyev *
9aa97dd1cSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
10aa97dd1cSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
11aa97dd1cSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12aa97dd1cSKonstantin Ananyev * See the License for the specific language governing permissions and
13aa97dd1cSKonstantin Ananyev * limitations under the License.
14aa97dd1cSKonstantin Ananyev */
15aa97dd1cSKonstantin Ananyev
16aa97dd1cSKonstantin Ananyev#ifndef _TCP_MISC_H_
17aa97dd1cSKonstantin Ananyev#define _TCP_MISC_H_
18aa97dd1cSKonstantin Ananyev
19aa97dd1cSKonstantin Ananyev#include "net_misc.h"
20aa97dd1cSKonstantin Ananyev#include <rte_tcp.h>
21aa97dd1cSKonstantin Ananyev#include <rte_cycles.h>
22aa97dd1cSKonstantin Ananyev
23aa97dd1cSKonstantin Ananyev#ifdef __cplusplus
24aa97dd1cSKonstantin Ananyevextern "C" {
25aa97dd1cSKonstantin Ananyev#endif
26aa97dd1cSKonstantin Ananyev
27aa97dd1cSKonstantin Ananyev/*
28aa97dd1cSKonstantin Ananyev * TCP protocols related structures/functions definitions.
29aa97dd1cSKonstantin Ananyev * Main purpose to simplify (and optimise) processing and representation
30aa97dd1cSKonstantin Ananyev * of protocol related data.
31aa97dd1cSKonstantin Ananyev */
32aa97dd1cSKonstantin Ananyev
33aa97dd1cSKonstantin Ananyev#define	TCP_WSCALE_DEFAULT	7
34aa97dd1cSKonstantin Ananyev#define	TCP_WSCALE_NONE		0
35aa97dd1cSKonstantin Ananyev
36aa97dd1cSKonstantin Ananyev#define	TCP_TX_HDR_MAX	(sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_MAX)
37aa97dd1cSKonstantin Ananyev
38aa97dd1cSKonstantin Ananyev/* max header size for normal data+ack packet */
39aa97dd1cSKonstantin Ananyev#define	TCP_TX_HDR_DACK	(sizeof(struct tcp_hdr) + TCP_TX_OPT_LEN_TMS)
40aa97dd1cSKonstantin Ananyev
41aa97dd1cSKonstantin Ananyev#define	TCP4_MIN_MSS	536
42aa97dd1cSKonstantin Ananyev
43aa97dd1cSKonstantin Ananyev#define	TCP6_MIN_MSS	1220
44aa97dd1cSKonstantin Ananyev
45aa97dd1cSKonstantin Ananyev/* default MTU, no TCP options. */
46aa97dd1cSKonstantin Ananyev#define TCP4_NOP_MSS	\
47aa97dd1cSKonstantin Ananyev	(ETHER_MTU - sizeof(struct ipv4_hdr) - sizeof(struct tcp_hdr))
48aa97dd1cSKonstantin Ananyev
49aa97dd1cSKonstantin Ananyev#define TCP6_NOP_MSS	\
50aa97dd1cSKonstantin Ananyev	(ETHER_MTU - sizeof(struct ipv6_hdr) - sizeof(struct tcp_hdr))
51aa97dd1cSKonstantin Ananyev
52aa97dd1cSKonstantin Ananyev/* default MTU, TCP options present */
53aa97dd1cSKonstantin Ananyev#define TCP4_OP_MSS	(TCP4_NOP_MSS - TCP_TX_OPT_LEN_MAX)
54aa97dd1cSKonstantin Ananyev
55aa97dd1cSKonstantin Ananyev#define TCP6_OP_MSS	(TCP6_NOP_MSS - TCP_TX_OPT_LEN_MAX)
56aa97dd1cSKonstantin Ananyev
577e18fa1bSKonstantin Ananyev/* Initial Window Configuration parameter, probably will be configured during
587e18fa1bSKonstantin Ananyev * the startup in future */
597e18fa1bSKonstantin Ananyev#define TCP_INITIAL_CWND_MAX 14600
607e18fa1bSKonstantin Ananyev
61aa97dd1cSKonstantin Ananyev/*
62aa97dd1cSKonstantin Ananyev * TCP flags
63aa97dd1cSKonstantin Ananyev */
64aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_FIN	0x01
65aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_SYN	0x02
66aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_RST	0x04
67aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_PSH	0x08
68aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_ACK	0x10
69aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_URG	0x20
70aa97dd1cSKonstantin Ananyev
71aa97dd1cSKonstantin Ananyev/* TCP flags mask. */
72aa97dd1cSKonstantin Ananyev#define	TCP_FLAG_MASK	UINT8_MAX
73aa97dd1cSKonstantin Ananyev
74aa97dd1cSKonstantin Ananyevunion typflg {
75aa97dd1cSKonstantin Ananyev	uint16_t raw;
76aa97dd1cSKonstantin Ananyev	struct {
77aa97dd1cSKonstantin Ananyev		uint8_t type;  /* TLE_V4/TLE_V6 */
78aa97dd1cSKonstantin Ananyev		uint8_t flags; /* TCP header flags */
79aa97dd1cSKonstantin Ananyev	};
80aa97dd1cSKonstantin Ananyev};
81aa97dd1cSKonstantin Ananyev
82aa97dd1cSKonstantin Ananyevunion pkt_info {
83aa97dd1cSKonstantin Ananyev	rte_xmm_t raw;
84aa97dd1cSKonstantin Ananyev	struct {
85aa97dd1cSKonstantin Ananyev		union typflg tf;
86aa97dd1cSKonstantin Ananyev		uint16_t csf;  /* checksum flags */
87aa97dd1cSKonstantin Ananyev		union l4_ports port;
88aa97dd1cSKonstantin Ananyev		union {
89aa97dd1cSKonstantin Ananyev			union ipv4_addrs addr4;
90aa97dd1cSKonstantin Ananyev			const union ipv6_addrs *addr6;
91aa97dd1cSKonstantin Ananyev		};
92aa97dd1cSKonstantin Ananyev	};
93aa97dd1cSKonstantin Ananyev};
94aa97dd1cSKonstantin Ananyev
95aa97dd1cSKonstantin Ananyevunion seg_info {
96aa97dd1cSKonstantin Ananyev	rte_xmm_t raw;
97aa97dd1cSKonstantin Ananyev	struct {
98aa97dd1cSKonstantin Ananyev		uint32_t seq;
99aa97dd1cSKonstantin Ananyev		uint32_t ack;
100aa97dd1cSKonstantin Ananyev		uint16_t wnd;
1017e18fa1bSKonstantin Ananyev		uint16_t mss; /* valid only at SYN time */
102aa97dd1cSKonstantin Ananyev	};
103aa97dd1cSKonstantin Ananyev};
104aa97dd1cSKonstantin Ananyev
105aa97dd1cSKonstantin Ananyevunion seqlen {
106aa97dd1cSKonstantin Ananyev	uint64_t raw;
107aa97dd1cSKonstantin Ananyev	struct {
108aa97dd1cSKonstantin Ananyev		uint32_t seq;
109aa97dd1cSKonstantin Ananyev		uint32_t len;
110aa97dd1cSKonstantin Ananyev	};
111aa97dd1cSKonstantin Ananyev};
112aa97dd1cSKonstantin Ananyev
113aa97dd1cSKonstantin Ananyev#define	TCP_DATA_ALIGN	4
114aa97dd1cSKonstantin Ananyev
115aa97dd1cSKonstantin Ananyev#define	TCP_DATA_OFFSET	4
116aa97dd1cSKonstantin Ananyev
117aa97dd1cSKonstantin Ananyev/*
118aa97dd1cSKonstantin Ananyev * recognizable options.
119aa97dd1cSKonstantin Ananyev */
120aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KIND_EOL	0x00
121aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KIND_NOP	0x01
122aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KIND_MSS	0x02
123aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KIND_WSC	0x03
124aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KIND_TMS	0x08
125aa97dd1cSKonstantin Ananyev
126aa97dd1cSKonstantin Ananyev#define	TCP_OPT_LEN_EOL		0x01
127aa97dd1cSKonstantin Ananyev#define	TCP_OPT_LEN_NOP		0x01
128aa97dd1cSKonstantin Ananyev#define	TCP_OPT_LEN_MSS		0x04
129aa97dd1cSKonstantin Ananyev#define	TCP_OPT_LEN_WSC		0x03
130aa97dd1cSKonstantin Ananyev#define	TCP_OPT_LEN_TMS		0x0a
131aa97dd1cSKonstantin Ananyev
132aa97dd1cSKonstantin Ananyev#define	TCP_TX_OPT_LEN_MAX	\
133aa97dd1cSKonstantin Ananyev	RTE_ALIGN_CEIL(TCP_OPT_LEN_MSS + TCP_OPT_LEN_WSC + TCP_OPT_LEN_TMS + \
134aa97dd1cSKonstantin Ananyev		TCP_OPT_LEN_EOL, TCP_DATA_ALIGN)
135aa97dd1cSKonstantin Ananyev
136aa97dd1cSKonstantin Ananyev/*
137aa97dd1cSKonstantin Ananyev * recomended format for TSOPT from RFC 1323, appendix A:
138aa97dd1cSKonstantin Ananyev *  +--------+--------+--------+--------+
139aa97dd1cSKonstantin Ananyev *  |   NOP  |  NOP   |  TSopt |   10   |
140aa97dd1cSKonstantin Ananyev *  +--------+--------+--------+--------+
141aa97dd1cSKonstantin Ananyev *  |          TSval   timestamp        |
142aa97dd1cSKonstantin Ananyev *  +--------+--------+--------+--------+
143aa97dd1cSKonstantin Ananyev *  |          TSecr   timestamp        |
144aa97dd1cSKonstantin Ananyev *  +--------+--------+--------+--------+
145aa97dd1cSKonstantin Ananyev */
146aa97dd1cSKonstantin Ananyev#define	TCP_TX_OPT_LEN_TMS	(TCP_OPT_LEN_TMS + 2 * TCP_OPT_LEN_NOP)
147aa97dd1cSKonstantin Ananyev
148aa97dd1cSKonstantin Ananyev#define TCP_OPT_TMS_HDR		(rte_be_to_cpu_32( \
149aa97dd1cSKonstantin Ananyev	TCP_OPT_KIND_NOP << 3 * CHAR_BIT | \
150aa97dd1cSKonstantin Ananyev	TCP_OPT_KIND_NOP << 2 * CHAR_BIT | \
151aa97dd1cSKonstantin Ananyev	TCP_OPT_KIND_TMS << CHAR_BIT | \
152aa97dd1cSKonstantin Ananyev	TCP_OPT_LEN_TMS))
153aa97dd1cSKonstantin Ananyev
154aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KL(k, l)	(rte_be_to_cpu_16((k) << CHAR_BIT | (l)))
155aa97dd1cSKonstantin Ananyev
156aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KL_MSS		TCP_OPT_KL(TCP_OPT_KIND_MSS, TCP_OPT_LEN_MSS)
157aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KL_WSC		TCP_OPT_KL(TCP_OPT_KIND_WSC, TCP_OPT_LEN_WSC)
158aa97dd1cSKonstantin Ananyev#define	TCP_OPT_KL_TMS		TCP_OPT_KL(TCP_OPT_KIND_TMS, TCP_OPT_LEN_TMS)
159aa97dd1cSKonstantin Ananyev
160aa97dd1cSKonstantin Ananyev/*
161aa97dd1cSKonstantin Ananyev * Timestamp option.
162aa97dd1cSKonstantin Ananyev */
163aa97dd1cSKonstantin Ananyevunion tsopt {
164aa97dd1cSKonstantin Ananyev	uint64_t raw;
165aa97dd1cSKonstantin Ananyev	struct {
166aa97dd1cSKonstantin Ananyev		uint32_t val;
167aa97dd1cSKonstantin Ananyev		uint32_t ecr;
168aa97dd1cSKonstantin Ananyev	};
169aa97dd1cSKonstantin Ananyev};
170aa97dd1cSKonstantin Ananyev
171aa97dd1cSKonstantin Ananyevstruct tcpopt {
172aa97dd1cSKonstantin Ananyev	union {
173aa97dd1cSKonstantin Ananyev		uint16_t raw;
174aa97dd1cSKonstantin Ananyev		struct {
175aa97dd1cSKonstantin Ananyev			uint8_t kind;
176aa97dd1cSKonstantin Ananyev			uint8_t len;
177aa97dd1cSKonstantin Ananyev		};
178aa97dd1cSKonstantin Ananyev	} kl;
179aa97dd1cSKonstantin Ananyev	union {
180aa97dd1cSKonstantin Ananyev		uint16_t mss;
181aa97dd1cSKonstantin Ananyev		uint8_t  wscale;
182aa97dd1cSKonstantin Ananyev		union tsopt ts;
183aa97dd1cSKonstantin Ananyev	};
184aa97dd1cSKonstantin Ananyev} __attribute__((__packed__));
185aa97dd1cSKonstantin Ananyev
186aa97dd1cSKonstantin Ananyevstruct syn_opts {
187aa97dd1cSKonstantin Ananyev	uint16_t mss;
188aa97dd1cSKonstantin Ananyev	uint8_t  wscale;
189aa97dd1cSKonstantin Ananyev	union tsopt ts;
190aa97dd1cSKonstantin Ananyev};
191aa97dd1cSKonstantin Ananyev
192aa97dd1cSKonstantin Ananyevstruct resp_info {
193aa97dd1cSKonstantin Ananyev	uint32_t flags;
194aa97dd1cSKonstantin Ananyev};
195aa97dd1cSKonstantin Ananyev
196aa97dd1cSKonstantin Ananyev
197aa97dd1cSKonstantin Ananyev/* window update information (RFC 793 WL1, WL2) */
198aa97dd1cSKonstantin Ananyevunion wui {
199aa97dd1cSKonstantin Ananyev	uint64_t raw;
2006e95f5ecSKonstantin Ananyev	struct {
201aa97dd1cSKonstantin Ananyev		uint32_t wl1;
202aa97dd1cSKonstantin Ananyev		uint32_t wl2;
203aa97dd1cSKonstantin Ananyev	};
204aa97dd1cSKonstantin Ananyev};
205aa97dd1cSKonstantin Ananyev
206aa97dd1cSKonstantin Ananyev/*
207aa97dd1cSKonstantin Ananyev * helper structure: holds aggregated information about group
208aa97dd1cSKonstantin Ananyev * of processed data+ack packets.
209aa97dd1cSKonstantin Ananyev */
210aa97dd1cSKonstantin Ananyevstruct dack_info {
211aa97dd1cSKonstantin Ananyev	struct {                    /* # of received segments with: */
212aa97dd1cSKonstantin Ananyev		uint32_t data;      /* incoming data */
213aa97dd1cSKonstantin Ananyev		uint32_t ack;       /* newly acked data */
214aa97dd1cSKonstantin Ananyev		uint32_t dup;       /* duplicate acks */
215aa97dd1cSKonstantin Ananyev		uint32_t badseq;    /* bad seq/ack */
216aa97dd1cSKonstantin Ananyev		uint32_t ofo;       /* OFO incoming data */
217aa97dd1cSKonstantin Ananyev	} segs;
218aa97dd1cSKonstantin Ananyev	uint32_t ack;       /* highest received ACK */
219aa97dd1cSKonstantin Ananyev	union tsopt ts;     /* TS of highest ACK */
220aa97dd1cSKonstantin Ananyev	union wui wu;       /* window update information */
221aa97dd1cSKonstantin Ananyev	uint32_t wnd;
222aa97dd1cSKonstantin Ananyev	struct {               /* 3 duplicate ACKs were observed after */
223aa97dd1cSKonstantin Ananyev		uint32_t seg;  /* # of meaningful ACK segments */
224aa97dd1cSKonstantin Ananyev		uint32_t ack;  /* ACK sequence */
225aa97dd1cSKonstantin Ananyev	} dup3;
226aa97dd1cSKonstantin Ananyev};
227aa97dd1cSKonstantin Ananyev
228aa97dd1cSKonstantin Ananyev/* get current timestamp in ms */
229aa97dd1cSKonstantin Ananyevstatic inline uint32_t
2307e18fa1bSKonstantin Ananyevtcp_get_tms(uint32_t mshift)
231aa97dd1cSKonstantin Ananyev{
2327e18fa1bSKonstantin Ananyev	uint64_t ts;
2337e18fa1bSKonstantin Ananyev	ts = rte_get_tsc_cycles() >> mshift;
234aa97dd1cSKonstantin Ananyev	return ts;
235aa97dd1cSKonstantin Ananyev}
236aa97dd1cSKonstantin Ananyev
237aa97dd1cSKonstantin Ananyevstatic inline int
238aa97dd1cSKonstantin Ananyevtcp_seq_lt(uint32_t l, uint32_t r)
239aa97dd1cSKonstantin Ananyev{
240aa97dd1cSKonstantin Ananyev	return (int32_t)(l - r) < 0;
241aa97dd1cSKonstantin Ananyev}
242aa97dd1cSKonstantin Ananyev
243aa97dd1cSKonstantin Ananyevstatic inline int
244aa97dd1cSKonstantin Ananyevtcp_seq_leq(uint32_t l, uint32_t r)
245aa97dd1cSKonstantin Ananyev{
246aa97dd1cSKonstantin Ananyev	return (int32_t)(l - r) <= 0;
247aa97dd1cSKonstantin Ananyev}
248aa97dd1cSKonstantin Ananyev
24917f6b7adSJielong Zhoustatic inline uint32_t
25017f6b7adSJielong Zhoutcp_seq_min(uint32_t l, uint32_t r)
25117f6b7adSJielong Zhou{
25217f6b7adSJielong Zhou	if (tcp_seq_lt(l, r))
25317f6b7adSJielong Zhou		return l;
25417f6b7adSJielong Zhou	else
25517f6b7adSJielong Zhou		return r;
25617f6b7adSJielong Zhou}
257aa97dd1cSKonstantin Ananyev
258aa97dd1cSKonstantin Ananyevstatic inline void
259aa97dd1cSKonstantin Ananyevget_seg_info(const struct tcp_hdr *th, union seg_info *si)
260aa97dd1cSKonstantin Ananyev{
261aa97dd1cSKonstantin Ananyev	__m128i v;
2627e18fa1bSKonstantin Ananyev	const  __m128i bswap_mask =
2637e18fa1bSKonstantin Ananyev		_mm_set_epi8(UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX,
2647e18fa1bSKonstantin Ananyev			UINT8_MAX, UINT8_MAX, 10, 11,
2657e18fa1bSKonstantin Ananyev			4, 5, 6, 7,
2667e18fa1bSKonstantin Ananyev			0, 1, 2, 3);
267aa97dd1cSKonstantin Ananyev
268aa97dd1cSKonstantin Ananyev	v = _mm_loadu_si128((const __m128i *)&th->sent_seq);
269aa97dd1cSKonstantin Ananyev	si->raw.x = _mm_shuffle_epi8(v, bswap_mask);
270aa97dd1cSKonstantin Ananyev}
271aa97dd1cSKonstantin Ananyev
272aa97dd1cSKonstantin Ananyevstatic inline void
273aa97dd1cSKonstantin Ananyevget_syn_opts(struct syn_opts *so, uintptr_t p, uint32_t len)
274aa97dd1cSKonstantin Ananyev{
275aa97dd1cSKonstantin Ananyev	uint32_t i, kind;
276aa97dd1cSKonstantin Ananyev	const struct tcpopt *opt;
277aa97dd1cSKonstantin Ananyev
278aa97dd1cSKonstantin Ananyev	memset(so, 0, sizeof(*so));
279aa97dd1cSKonstantin Ananyev
280aa97dd1cSKonstantin Ananyev	i = 0;
281aa97dd1cSKonstantin Ananyev	while (i < len) {
282aa97dd1cSKonstantin Ananyev		opt = (const struct tcpopt *)(p + i);
283aa97dd1cSKonstantin Ananyev		kind = opt->kl.kind;
284aa97dd1cSKonstantin Ananyev		if (kind == TCP_OPT_KIND_EOL)
285aa97dd1cSKonstantin Ananyev			return;
286aa97dd1cSKonstantin Ananyev		else if (kind == TCP_OPT_KIND_NOP)
287aa97dd1cSKonstantin Ananyev			i += sizeof(opt->kl.kind);
288aa97dd1cSKonstantin Ananyev		else {
289aa97dd1cSKonstantin Ananyev			i += opt->kl.len;
290aa97dd1cSKonstantin Ananyev			if (i <= len) {
291aa97dd1cSKonstantin Ananyev				if (opt->kl.raw == TCP_OPT_KL_MSS)
292aa97dd1cSKonstantin Ananyev					so->mss = rte_be_to_cpu_16(opt->mss);
293aa97dd1cSKonstantin Ananyev				else if (opt->kl.raw == TCP_OPT_KL_WSC)
294aa97dd1cSKonstantin Ananyev					so->wscale = opt->wscale;
295aa97dd1cSKonstantin Ananyev				else if (opt->kl.raw == TCP_OPT_KL_TMS) {
296aa97dd1cSKonstantin Ananyev					so->ts.val =
297aa97dd1cSKonstantin Ananyev						rte_be_to_cpu_32(opt->ts.val);
298aa97dd1cSKonstantin Ananyev					so->ts.ecr =
299aa97dd1cSKonstantin Ananyev						rte_be_to_cpu_32(opt->ts.ecr);
300aa97dd1cSKonstantin Ananyev				}
301aa97dd1cSKonstantin Ananyev			}
302aa97dd1cSKonstantin Ananyev		}
303aa97dd1cSKonstantin Ananyev	}
304aa97dd1cSKonstantin Ananyev}
305aa97dd1cSKonstantin Ananyev
306aa97dd1cSKonstantin Ananyev/*
307aa97dd1cSKonstantin Ananyev * generates SYN options, assumes that there are
308aa97dd1cSKonstantin Ananyev * at least TCP_TX_OPT_LEN_MAX bytes available.
309aa97dd1cSKonstantin Ananyev */
310aa97dd1cSKonstantin Ananyevstatic inline void
311aa97dd1cSKonstantin Ananyevfill_syn_opts(void *p, const struct syn_opts *so)
312aa97dd1cSKonstantin Ananyev{
313aa97dd1cSKonstantin Ananyev	uint8_t *to;
314aa97dd1cSKonstantin Ananyev	struct tcpopt *opt;
315aa97dd1cSKonstantin Ananyev
316aa97dd1cSKonstantin Ananyev	to = (uint8_t *)p;
317aa97dd1cSKonstantin Ananyev
318aa97dd1cSKonstantin Ananyev	/* setup MSS*/
319aa97dd1cSKonstantin Ananyev	opt = (struct tcpopt *)to;
320aa97dd1cSKonstantin Ananyev	opt->kl.raw = TCP_OPT_KL_MSS;
321aa97dd1cSKonstantin Ananyev	opt->mss = rte_cpu_to_be_16(so->mss);
322aa97dd1cSKonstantin Ananyev
323aa97dd1cSKonstantin Ananyev	to += TCP_OPT_LEN_MSS;
324aa97dd1cSKonstantin Ananyev	opt = (struct tcpopt *)to;
325aa97dd1cSKonstantin Ananyev
326aa97dd1cSKonstantin Ananyev	/* setup TMS*/
327aa97dd1cSKonstantin Ananyev	if (so->ts.val != 0) {
328aa97dd1cSKonstantin Ananyev
329aa97dd1cSKonstantin Ananyev		opt->kl.raw = TCP_OPT_KL_TMS;
330aa97dd1cSKonstantin Ananyev		opt->ts.val = rte_cpu_to_be_32(so->ts.val);
331aa97dd1cSKonstantin Ananyev		opt->ts.ecr = rte_cpu_to_be_32(so->ts.ecr);
332aa97dd1cSKonstantin Ananyev
333aa97dd1cSKonstantin Ananyev		to += TCP_OPT_LEN_TMS;
334aa97dd1cSKonstantin Ananyev		opt = (struct tcpopt *)to;
335aa97dd1cSKonstantin Ananyev	}
336aa97dd1cSKonstantin Ananyev
337aa97dd1cSKonstantin Ananyev	/* setup TMS*/
338aa97dd1cSKonstantin Ananyev	if (so->wscale != 0) {
339aa97dd1cSKonstantin Ananyev
340aa97dd1cSKonstantin Ananyev		opt->kl.raw = TCP_OPT_KL_WSC;
341aa97dd1cSKonstantin Ananyev		opt->wscale = so->wscale;
342aa97dd1cSKonstantin Ananyev
343aa97dd1cSKonstantin Ananyev		to += TCP_OPT_LEN_WSC;
344aa97dd1cSKonstantin Ananyev		opt = (struct tcpopt *)to;
345aa97dd1cSKonstantin Ananyev	}
346aa97dd1cSKonstantin Ananyev
347aa97dd1cSKonstantin Ananyev	to[0] = TCP_OPT_KIND_EOL;
348aa97dd1cSKonstantin Ananyev}
349aa97dd1cSKonstantin Ananyev
350aa97dd1cSKonstantin Ananyev/*
351aa97dd1cSKonstantin Ananyev * generate TMS option, for non SYN packet, make sure
352aa97dd1cSKonstantin Ananyev * there at least TCP_TX_OPT_LEN_TMS available.
353aa97dd1cSKonstantin Ananyev */
354aa97dd1cSKonstantin Ananyevstatic inline void
355aa97dd1cSKonstantin Ananyevfill_tms_opts(void *p, uint32_t val, uint32_t ecr)
356aa97dd1cSKonstantin Ananyev{
357aa97dd1cSKonstantin Ananyev	uint32_t *opt;
358aa97dd1cSKonstantin Ananyev
359aa97dd1cSKonstantin Ananyev	opt = (uint32_t *)p;
360aa97dd1cSKonstantin Ananyev	opt[0] = TCP_OPT_TMS_HDR;
361aa97dd1cSKonstantin Ananyev	opt[1] = rte_cpu_to_be_32(val);
362aa97dd1cSKonstantin Ananyev	opt[2] = rte_cpu_to_be_32(ecr);
363aa97dd1cSKonstantin Ananyev}
364aa97dd1cSKonstantin Ananyev
365aa97dd1cSKonstantin Ananyevstatic inline union tsopt
366aa97dd1cSKonstantin Ananyevget_tms_opts(uintptr_t p, uint32_t len)
367aa97dd1cSKonstantin Ananyev{
368