tcp: move features to separate files
[vpp.git] / src / vnet / tcp / tcp_packet.h
1 /*
2  * Copyright (c) 2016-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef included_tcp_packet_h
17 #define included_tcp_packet_h
18
19 #include <vnet/vnet.h>
20
21 /* TCP flags bit 0 first. */
22 #define foreach_tcp_flag                                \
23   _ (FIN) /**< No more data from sender. */             \
24   _ (SYN) /**< Synchronize sequence numbers. */         \
25   _ (RST) /**< Reset the connection. */                 \
26   _ (PSH) /**< Push function. */                        \
27   _ (ACK) /**< Ack field significant. */                \
28   _ (URG) /**< Urgent pointer field significant. */     \
29   _ (ECE) /**< ECN-echo. Receiver got CE packet */      \
30   _ (CWR) /**< Sender reduced congestion window */
31
32 enum
33 {
34 #define _(f) TCP_FLAG_BIT_##f,
35   foreach_tcp_flag
36 #undef _
37     TCP_N_FLAG_BITS,
38 };
39
40 enum
41 {
42 #define _(f) TCP_FLAG_##f = 1 << TCP_FLAG_BIT_##f,
43   foreach_tcp_flag
44 #undef _
45 };
46
47 typedef struct _tcp_header
48 {
49   union
50   {
51     struct
52     {
53       u16 src_port; /**< Source port. */
54       u16 dst_port; /**< Destination port. */
55     };
56     struct
57     {
58       u16 src, dst;
59     };
60   };
61
62   u32 seq_number;       /**< Sequence number of the first data octet in this
63                          *   segment, except when SYN is present. If SYN
64                          *   is present the seq number is is the ISN and the
65                          *   first data octet is ISN+1 */
66   u32 ack_number;       /**< Acknowledgement number if ACK is set. It contains
67                          *   the value of the next sequence number the sender
68                          *   of the segment is expecting to receive. */
69   u8 data_offset_and_reserved;
70   u8 flags;             /**< Flags: see the macro above */
71   u16 window;           /**< Number of bytes sender is willing to receive. */
72
73   u16 checksum;         /**< Checksum of TCP pseudo header and data. */
74   u16 urgent_pointer;   /**< Seq number of the byte after the urgent data. */
75 } __attribute__ ((packed)) tcp_header_t;
76
77 /* Flag tests that return 0 or !0 */
78 #define tcp_doff(_th) ((_th)->data_offset_and_reserved >> 4)
79 #define tcp_fin(_th) ((_th)->flags & TCP_FLAG_FIN)
80 #define tcp_syn(_th) ((_th)->flags & TCP_FLAG_SYN)
81 #define tcp_rst(_th) ((_th)->flags & TCP_FLAG_RST)
82 #define tcp_psh(_th) ((_th)->flags & TCP_FLAG_PSH)
83 #define tcp_ack(_th) ((_th)->flags & TCP_FLAG_ACK)
84 #define tcp_urg(_th) ((_th)->flags & TCP_FLAG_URG)
85 #define tcp_ece(_th) ((_th)->flags & TCP_FLAG_ECE)
86 #define tcp_cwr(_th) ((_th)->flags & TCP_FLAG_CWR)
87
88 /* Flag tests that return 0 or 1 */
89 #define tcp_is_syn(_th) !!((_th)->flags & TCP_FLAG_SYN)
90 #define tcp_is_fin(_th) !!((_th)->flags & TCP_FLAG_FIN)
91
92 always_inline int
93 tcp_header_bytes (tcp_header_t * t)
94 {
95   return tcp_doff (t) * sizeof (u32);
96 }
97
98 /*
99  * TCP options.
100  */
101
102 typedef enum tcp_option_type
103 {
104   TCP_OPTION_EOL = 0,                   /**< End of options. */
105   TCP_OPTION_NOOP = 1,                  /**< No operation. */
106   TCP_OPTION_MSS = 2,                   /**< Limit MSS. */
107   TCP_OPTION_WINDOW_SCALE = 3,          /**< Window scale. */
108   TCP_OPTION_SACK_PERMITTED = 4,        /**< Selective Ack permitted. */
109   TCP_OPTION_SACK_BLOCK = 5,            /**< Selective Ack block. */
110   TCP_OPTION_TIMESTAMP = 8,             /**< Timestamps. */
111   TCP_OPTION_UTO = 28,                  /**< User timeout. */
112   TCP_OPTION_AO = 29,                   /**< Authentication Option. */
113 } tcp_option_type_t;
114
115 #define foreach_tcp_options_flag                                        \
116   _ (MSS)               /**< MSS advertised in SYN */                   \
117   _ (TSTAMP)            /**< Timestamp capability advertised in SYN */  \
118   _ (WSCALE)            /**< Wnd scale capability advertised in SYN */  \
119   _ (SACK_PERMITTED)    /**< SACK capability advertised in SYN */       \
120   _ (SACK)              /**< SACK present */
121
122 enum
123 {
124 #define _(f) TCP_OPTS_FLAG_BIT_##f,
125   foreach_tcp_options_flag
126 #undef _
127     TCP_OPTIONS_N_FLAG_BITS,
128 };
129
130 enum
131 {
132 #define _(f) TCP_OPTS_FLAG_##f = 1 << TCP_OPTS_FLAG_BIT_##f,
133   foreach_tcp_options_flag
134 #undef _
135 };
136
137 typedef struct _sack_block
138 {
139   u32 start;            /**< Start sequence number */
140   u32 end;              /**< End sequence number (first outside) */
141 } sack_block_t;
142
143 typedef struct
144 {
145   u8 flags;             /** Option flags, see above */
146   u8 wscale;            /**< Window scale advertised */
147   u16 mss;              /**< Maximum segment size advertised */
148   u32 tsval;            /**< Timestamp value */
149   u32 tsecr;            /**< Echoed/reflected time stamp */
150   sack_block_t *sacks;  /**< SACK blocks */
151   u8 n_sack_blocks;     /**< Number of SACKs blocks */
152 } tcp_options_t;
153
154 /* Flag tests that return 0 or !0 */
155 #define tcp_opts_mss(_to) ((_to)->flags & TCP_OPTS_FLAG_MSS)
156 #define tcp_opts_tstamp(_to) ((_to)->flags & TCP_OPTS_FLAG_TSTAMP)
157 #define tcp_opts_wscale(_to) ((_to)->flags & TCP_OPTS_FLAG_WSCALE)
158 #define tcp_opts_sack(_to) ((_to)->flags & TCP_OPTS_FLAG_SACK)
159 #define tcp_opts_sack_permitted(_to) ((_to)->flags & TCP_OPTS_FLAG_SACK_PERMITTED)
160
161 /* TCP option lengths */
162 #define TCP_OPTION_LEN_EOL              1
163 #define TCP_OPTION_LEN_NOOP             1
164 #define TCP_OPTION_LEN_MSS              4
165 #define TCP_OPTION_LEN_WINDOW_SCALE     3
166 #define TCP_OPTION_LEN_SACK_PERMITTED   2
167 #define TCP_OPTION_LEN_TIMESTAMP        10
168 #define TCP_OPTION_LEN_SACK_BLOCK        8
169
170 #define TCP_HDR_LEN_MAX                 60
171 #define TCP_WND_MAX                     65535U
172 #define TCP_MAX_WND_SCALE               14      /* See RFC 1323 */
173 #define TCP_OPTS_ALIGN                  4
174 #define TCP_OPTS_MAX_SACK_BLOCKS        3
175
176 /* Modulo arithmetic for TCP sequence numbers */
177 #define seq_lt(_s1, _s2) ((i32)((_s1)-(_s2)) < 0)
178 #define seq_leq(_s1, _s2) ((i32)((_s1)-(_s2)) <= 0)
179 #define seq_gt(_s1, _s2) ((i32)((_s1)-(_s2)) > 0)
180 #define seq_geq(_s1, _s2) ((i32)((_s1)-(_s2)) >= 0)
181 #define seq_max(_s1, _s2) (seq_gt((_s1), (_s2)) ? (_s1) : (_s2))
182
183 /* Modulo arithmetic for timestamps */
184 #define timestamp_lt(_t1, _t2) ((i32)((_t1)-(_t2)) < 0)
185 #define timestamp_leq(_t1, _t2) ((i32)((_t1)-(_t2)) <= 0)
186
187 /**
188  * Parse TCP header options.
189  *
190  * @param th TCP header
191  * @param to TCP options data structure to be populated
192  * @param is_syn set if packet is syn
193  * @return -1 if parsing failed
194  */
195 always_inline int
196 tcp_options_parse (tcp_header_t * th, tcp_options_t * to, u8 is_syn)
197 {
198   const u8 *data;
199   u8 opt_len, opts_len, kind;
200   int j;
201   sack_block_t b;
202
203   opts_len = (tcp_doff (th) << 2) - sizeof (tcp_header_t);
204   data = (const u8 *) (th + 1);
205
206   /* Zero out all flags but those set in SYN */
207   to->flags &= (TCP_OPTS_FLAG_SACK_PERMITTED | TCP_OPTS_FLAG_WSCALE
208                 | TCP_OPTS_FLAG_TSTAMP | TCP_OPTS_FLAG_MSS);
209
210   for (; opts_len > 0; opts_len -= opt_len, data += opt_len)
211     {
212       kind = data[0];
213
214       /* Get options length */
215       if (kind == TCP_OPTION_EOL)
216         break;
217       else if (kind == TCP_OPTION_NOOP)
218         {
219           opt_len = 1;
220           continue;
221         }
222       else
223         {
224           /* broken options */
225           if (opts_len < 2)
226             return -1;
227           opt_len = data[1];
228
229           /* weird option length */
230           if (opt_len < 2 || opt_len > opts_len)
231             return -1;
232         }
233
234       /* Parse options */
235       switch (kind)
236         {
237         case TCP_OPTION_MSS:
238           if (!is_syn)
239             break;
240           if ((opt_len == TCP_OPTION_LEN_MSS) && tcp_syn (th))
241             {
242               to->flags |= TCP_OPTS_FLAG_MSS;
243               to->mss = clib_net_to_host_u16 (*(u16 *) (data + 2));
244             }
245           break;
246         case TCP_OPTION_WINDOW_SCALE:
247           if (!is_syn)
248             break;
249           if ((opt_len == TCP_OPTION_LEN_WINDOW_SCALE) && tcp_syn (th))
250             {
251               to->flags |= TCP_OPTS_FLAG_WSCALE;
252               to->wscale = data[2];
253               if (to->wscale > TCP_MAX_WND_SCALE)
254                 to->wscale = TCP_MAX_WND_SCALE;
255             }
256           break;
257         case TCP_OPTION_TIMESTAMP:
258           if (is_syn)
259             to->flags |= TCP_OPTS_FLAG_TSTAMP;
260           if ((to->flags & TCP_OPTS_FLAG_TSTAMP)
261               && opt_len == TCP_OPTION_LEN_TIMESTAMP)
262             {
263               to->tsval = clib_net_to_host_u32 (*(u32 *) (data + 2));
264               to->tsecr = clib_net_to_host_u32 (*(u32 *) (data + 6));
265             }
266           break;
267         case TCP_OPTION_SACK_PERMITTED:
268           if (!is_syn)
269             break;
270           if (opt_len == TCP_OPTION_LEN_SACK_PERMITTED && tcp_syn (th))
271             to->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
272           break;
273         case TCP_OPTION_SACK_BLOCK:
274           /* If SACK permitted was not advertised or a SYN, break */
275           if ((to->flags & TCP_OPTS_FLAG_SACK_PERMITTED) == 0 || tcp_syn (th))
276             break;
277
278           /* If too short or not correctly formatted, break */
279           if (opt_len < 10 || ((opt_len - 2) % TCP_OPTION_LEN_SACK_BLOCK))
280             break;
281
282           to->flags |= TCP_OPTS_FLAG_SACK;
283           to->n_sack_blocks = (opt_len - 2) / TCP_OPTION_LEN_SACK_BLOCK;
284           vec_reset_length (to->sacks);
285           for (j = 0; j < to->n_sack_blocks; j++)
286             {
287               b.start = clib_net_to_host_u32 (*(u32 *) (data + 2 + 8 * j));
288               b.end = clib_net_to_host_u32 (*(u32 *) (data + 6 + 8 * j));
289               vec_add1 (to->sacks, b);
290             }
291           break;
292         default:
293           /* Nothing to see here */
294           continue;
295         }
296     }
297   return 0;
298 }
299
300 /**
301  * Write TCP options to segment.
302  *
303  * @param data  buffer where to write the options
304  * @param opts  options to write
305  * @return      length of options written
306  */
307 always_inline u32
308 tcp_options_write (u8 * data, tcp_options_t * opts)
309 {
310   u32 opts_len = 0;
311   u32 buf, seq_len = 4;
312
313   if (tcp_opts_mss (opts))
314     {
315       *data++ = TCP_OPTION_MSS;
316       *data++ = TCP_OPTION_LEN_MSS;
317       buf = clib_host_to_net_u16 (opts->mss);
318       clib_memcpy_fast (data, &buf, sizeof (opts->mss));
319       data += sizeof (opts->mss);
320       opts_len += TCP_OPTION_LEN_MSS;
321     }
322
323   if (tcp_opts_wscale (opts))
324     {
325       *data++ = TCP_OPTION_WINDOW_SCALE;
326       *data++ = TCP_OPTION_LEN_WINDOW_SCALE;
327       *data++ = opts->wscale;
328       opts_len += TCP_OPTION_LEN_WINDOW_SCALE;
329     }
330
331   if (tcp_opts_sack_permitted (opts))
332     {
333       *data++ = TCP_OPTION_SACK_PERMITTED;
334       *data++ = TCP_OPTION_LEN_SACK_PERMITTED;
335       opts_len += TCP_OPTION_LEN_SACK_PERMITTED;
336     }
337
338   if (tcp_opts_tstamp (opts))
339     {
340       *data++ = TCP_OPTION_TIMESTAMP;
341       *data++ = TCP_OPTION_LEN_TIMESTAMP;
342       buf = clib_host_to_net_u32 (opts->tsval);
343       clib_memcpy_fast (data, &buf, sizeof (opts->tsval));
344       data += sizeof (opts->tsval);
345       buf = clib_host_to_net_u32 (opts->tsecr);
346       clib_memcpy_fast (data, &buf, sizeof (opts->tsecr));
347       data += sizeof (opts->tsecr);
348       opts_len += TCP_OPTION_LEN_TIMESTAMP;
349     }
350
351   if (tcp_opts_sack (opts))
352     {
353       int i;
354
355       if (opts->n_sack_blocks != 0)
356         {
357           *data++ = TCP_OPTION_SACK_BLOCK;
358           *data++ = 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
359           for (i = 0; i < opts->n_sack_blocks; i++)
360             {
361               buf = clib_host_to_net_u32 (opts->sacks[i].start);
362               clib_memcpy_fast (data, &buf, seq_len);
363               data += seq_len;
364               buf = clib_host_to_net_u32 (opts->sacks[i].end);
365               clib_memcpy_fast (data, &buf, seq_len);
366               data += seq_len;
367             }
368           opts_len += 2 + opts->n_sack_blocks * TCP_OPTION_LEN_SACK_BLOCK;
369         }
370     }
371
372   /* Terminate TCP options */
373   if (opts_len % 4)
374     {
375       *data++ = TCP_OPTION_EOL;
376       opts_len += TCP_OPTION_LEN_EOL;
377     }
378
379   /* Pad with zeroes to a u32 boundary */
380   while (opts_len % 4)
381     {
382       *data++ = TCP_OPTION_NOOP;
383       opts_len += TCP_OPTION_LEN_NOOP;
384     }
385   return opts_len;
386 }
387
388 #endif /* included_tcp_packet_h */
389
390 /*
391  * fd.io coding-style-patch-verification: ON
392  *
393  * Local Variables:
394  * eval: (c-set-style "gnu")
395  * End:
396  */