]>
Commit | Line | Data |
---|---|---|
a3bf193b YCLP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright 2017 Duncan Hare, all rights reserved. | |
4 | */ | |
5 | ||
6 | /* | |
7 | * General Desription: | |
8 | * | |
9 | * TCP support for the wget command, for fast file downloading. | |
10 | * | |
11 | * HTTP/TCP Receiver: | |
12 | * | |
13 | * Prerequisites: - own ethernet address | |
14 | * - own IP address | |
15 | * - Server IP address | |
16 | * - Server with TCP | |
17 | * - TCP application (eg wget) | |
18 | * Next Step HTTPS? | |
19 | */ | |
20 | #include <common.h> | |
21 | #include <command.h> | |
22 | #include <console.h> | |
23 | #include <env_internal.h> | |
24 | #include <errno.h> | |
25 | #include <net.h> | |
26 | #include <net/tcp.h> | |
27 | ||
28 | /* | |
29 | * TCP sliding window control used by us to request re-TX | |
30 | */ | |
31 | static struct tcp_sack_v tcp_lost; | |
32 | ||
33 | /* TCP option timestamp */ | |
34 | static u32 loc_timestamp; | |
35 | static u32 rmt_timestamp; | |
36 | ||
37 | static u32 tcp_seq_init; | |
38 | static u32 tcp_ack_edge; | |
39 | static u32 tcp_seq_max; | |
40 | ||
41 | static int tcp_activity_count; | |
42 | ||
43 | /* | |
44 | * Search for TCP_SACK and review the comments before the code section | |
45 | * TCP_SACK is the number of packets at the front of the stream | |
46 | */ | |
47 | ||
48 | enum pkt_state {PKT, NOPKT}; | |
49 | struct sack_r { | |
50 | struct sack_edges se; | |
51 | enum pkt_state st; | |
52 | }; | |
53 | ||
54 | static struct sack_r edge_a[TCP_SACK]; | |
55 | static unsigned int sack_idx; | |
56 | static unsigned int prev_len; | |
57 | ||
58 | /* | |
59 | * TCP lengths are stored as a rounded up number of 32 bit words. | |
60 | * Add 3 to length round up, rounded, then divided into the | |
61 | * length in 32 bit words. | |
62 | */ | |
63 | #define LEN_B_TO_DW(x) ((x) >> 2) | |
64 | #define ROUND_TCPHDR_LEN(x) (LEN_B_TO_DW((x) + 3)) | |
65 | #define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4) | |
66 | #define GET_TCP_HDR_LEN_IN_BYTES(x) ((x) >> 2) | |
67 | ||
68 | /* TCP connection state */ | |
69 | static enum tcp_state current_tcp_state; | |
70 | ||
71 | /* Current TCP RX packet handler */ | |
72 | static rxhand_tcp *tcp_packet_handler; | |
73 | ||
74 | /** | |
75 | * tcp_get_tcp_state() - get current TCP state | |
76 | * | |
77 | * Return: Current TCP state | |
78 | */ | |
79 | enum tcp_state tcp_get_tcp_state(void) | |
80 | { | |
81 | return current_tcp_state; | |
82 | } | |
83 | ||
84 | /** | |
85 | * tcp_set_tcp_state() - set current TCP state | |
86 | * @new_state: new TCP state | |
87 | */ | |
88 | void tcp_set_tcp_state(enum tcp_state new_state) | |
89 | { | |
90 | current_tcp_state = new_state; | |
91 | } | |
92 | ||
93 | static void dummy_handler(uchar *pkt, unsigned int dport, | |
94 | struct in_addr sip, unsigned int sport, | |
95 | unsigned int len) | |
96 | { | |
97 | } | |
98 | ||
99 | /** | |
100 | * tcp_set_tcp_handler() - set a handler to receive data | |
101 | * @f: handler | |
102 | */ | |
103 | void tcp_set_tcp_handler(rxhand_tcp *f) | |
104 | { | |
105 | debug_cond(DEBUG_INT_STATE, "--- net_loop TCP handler set (%p)\n", f); | |
106 | if (!f) | |
107 | tcp_packet_handler = dummy_handler; | |
108 | else | |
109 | tcp_packet_handler = f; | |
110 | } | |
111 | ||
112 | /** | |
113 | * tcp_set_pseudo_header() - set TCP pseudo header | |
114 | * @pkt: the packet | |
115 | * @src: source IP address | |
116 | * @dest: destinaion IP address | |
117 | * @tcp_len: tcp length | |
118 | * @pkt_len: packet length | |
119 | * | |
120 | * Return: the checksum of the packet | |
121 | */ | |
122 | u16 tcp_set_pseudo_header(uchar *pkt, struct in_addr src, struct in_addr dest, | |
123 | int tcp_len, int pkt_len) | |
124 | { | |
125 | union tcp_build_pkt *b = (union tcp_build_pkt *)pkt; | |
126 | int checksum_len; | |
127 | ||
128 | /* | |
129 | * Pseudo header | |
130 | * | |
131 | * Zero the byte after the last byte so that the header checksum | |
132 | * will always work. | |
133 | */ | |
134 | pkt[pkt_len] = 0; | |
135 | ||
136 | net_copy_ip((void *)&b->ph.p_src, &src); | |
137 | net_copy_ip((void *)&b->ph.p_dst, &dest); | |
138 | b->ph.rsvd = 0; | |
139 | b->ph.p = IPPROTO_TCP; | |
140 | b->ph.len = htons(tcp_len); | |
141 | checksum_len = tcp_len + PSEUDO_HDR_SIZE; | |
142 | ||
143 | debug_cond(DEBUG_DEV_PKT, | |
144 | "TCP Pesudo Header (to=%pI4, from=%pI4, Len=%d)\n", | |
145 | &b->ph.p_dst, &b->ph.p_src, checksum_len); | |
146 | ||
147 | return compute_ip_checksum(pkt + PSEUDO_PAD_SIZE, checksum_len); | |
148 | } | |
149 | ||
150 | /** | |
151 | * net_set_ack_options() - set TCP options in acknowledge packets | |
152 | * @b: the packet | |
153 | * | |
154 | * Return: TCP header length | |
155 | */ | |
156 | int net_set_ack_options(union tcp_build_pkt *b) | |
157 | { | |
158 | b->sack.hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE)); | |
159 | ||
160 | b->sack.t_opt.kind = TCP_O_TS; | |
161 | b->sack.t_opt.len = TCP_OPT_LEN_A; | |
162 | b->sack.t_opt.t_snd = htons(loc_timestamp); | |
163 | b->sack.t_opt.t_rcv = rmt_timestamp; | |
164 | b->sack.sack_v.kind = TCP_1_NOP; | |
165 | b->sack.sack_v.len = 0; | |
166 | ||
167 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) { | |
168 | if (tcp_lost.len > TCP_OPT_LEN_2) { | |
169 | debug_cond(DEBUG_DEV_PKT, "TCP ack opt lost.len %x\n", | |
170 | tcp_lost.len); | |
171 | b->sack.sack_v.len = tcp_lost.len; | |
172 | b->sack.sack_v.kind = TCP_V_SACK; | |
173 | b->sack.sack_v.hill[0].l = htonl(tcp_lost.hill[0].l); | |
174 | b->sack.sack_v.hill[0].r = htonl(tcp_lost.hill[0].r); | |
175 | ||
176 | /* | |
177 | * These SACK structures are initialized with NOPs to | |
178 | * provide TCP header alignment padding. There are 4 | |
179 | * SACK structures used for both header padding and | |
180 | * internally. | |
181 | */ | |
182 | b->sack.sack_v.hill[1].l = htonl(tcp_lost.hill[1].l); | |
183 | b->sack.sack_v.hill[1].r = htonl(tcp_lost.hill[1].r); | |
184 | b->sack.sack_v.hill[2].l = htonl(tcp_lost.hill[2].l); | |
185 | b->sack.sack_v.hill[2].r = htonl(tcp_lost.hill[2].r); | |
186 | b->sack.sack_v.hill[3].l = TCP_O_NOP; | |
187 | b->sack.sack_v.hill[3].r = TCP_O_NOP; | |
188 | } | |
189 | ||
190 | b->sack.hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE + | |
191 | TCP_TSOPT_SIZE + | |
192 | tcp_lost.len)); | |
193 | } else { | |
194 | b->sack.sack_v.kind = 0; | |
195 | b->sack.hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(ROUND_TCPHDR_LEN(TCP_HDR_SIZE + | |
196 | TCP_TSOPT_SIZE)); | |
197 | } | |
198 | ||
199 | /* | |
200 | * This returns the actual rounded up length of the | |
201 | * TCP header to add to the total packet length | |
202 | */ | |
203 | ||
204 | return GET_TCP_HDR_LEN_IN_BYTES(b->sack.hdr.tcp_hlen); | |
205 | } | |
206 | ||
207 | /** | |
208 | * net_set_ack_options() - set TCP options in SYN packets | |
209 | * @b: the packet | |
210 | */ | |
211 | void net_set_syn_options(union tcp_build_pkt *b) | |
212 | { | |
213 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) | |
214 | tcp_lost.len = 0; | |
215 | ||
216 | b->ip.hdr.tcp_hlen = 0xa0; | |
217 | ||
218 | b->ip.mss.kind = TCP_O_MSS; | |
219 | b->ip.mss.len = TCP_OPT_LEN_4; | |
220 | b->ip.mss.mss = htons(TCP_MSS); | |
221 | b->ip.scale.kind = TCP_O_SCL; | |
222 | b->ip.scale.scale = TCP_SCALE; | |
223 | b->ip.scale.len = TCP_OPT_LEN_3; | |
224 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) { | |
225 | b->ip.sack_p.kind = TCP_P_SACK; | |
226 | b->ip.sack_p.len = TCP_OPT_LEN_2; | |
227 | } else { | |
228 | b->ip.sack_p.kind = TCP_1_NOP; | |
229 | b->ip.sack_p.len = TCP_1_NOP; | |
230 | } | |
231 | b->ip.t_opt.kind = TCP_O_TS; | |
232 | b->ip.t_opt.len = TCP_OPT_LEN_A; | |
233 | loc_timestamp = get_ticks(); | |
234 | rmt_timestamp = 0; | |
235 | b->ip.t_opt.t_snd = 0; | |
236 | b->ip.t_opt.t_rcv = 0; | |
237 | b->ip.end = TCP_O_END; | |
238 | } | |
239 | ||
240 | int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, | |
241 | u8 action, u32 tcp_seq_num, u32 tcp_ack_num) | |
242 | { | |
243 | union tcp_build_pkt *b = (union tcp_build_pkt *)pkt; | |
244 | int pkt_hdr_len; | |
245 | int pkt_len; | |
246 | int tcp_len; | |
247 | ||
248 | /* | |
249 | * Header: 5 32 bit words. 4 bits TCP header Length, | |
250 | * 4 bits reserved options | |
251 | */ | |
252 | b->ip.hdr.tcp_flags = action; | |
253 | pkt_hdr_len = IP_TCP_HDR_SIZE; | |
254 | b->ip.hdr.tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE)); | |
255 | ||
256 | switch (action) { | |
257 | case TCP_SYN: | |
258 | debug_cond(DEBUG_DEV_PKT, | |
259 | "TCP Hdr:SYN (%pI4, %pI4, sq=%d, ak=%d)\n", | |
260 | &net_server_ip, &net_ip, | |
261 | tcp_seq_num, tcp_ack_num); | |
262 | tcp_activity_count = 0; | |
263 | net_set_syn_options(b); | |
264 | tcp_seq_num = 0; | |
265 | tcp_ack_num = 0; | |
266 | pkt_hdr_len = IP_TCP_O_SIZE; | |
267 | if (current_tcp_state == TCP_SYN_SENT) { /* Too many SYNs */ | |
268 | action = TCP_FIN; | |
269 | current_tcp_state = TCP_FIN_WAIT_1; | |
270 | } else { | |
271 | current_tcp_state = TCP_SYN_SENT; | |
272 | } | |
273 | break; | |
274 | case TCP_ACK: | |
275 | pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b); | |
276 | b->ip.hdr.tcp_flags = action; | |
277 | debug_cond(DEBUG_DEV_PKT, | |
278 | "TCP Hdr:ACK (%pI4, %pI4, s=%d, a=%d, A=%x)\n", | |
279 | &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num, | |
280 | action); | |
281 | break; | |
282 | case TCP_FIN: | |
283 | debug_cond(DEBUG_DEV_PKT, | |
284 | "TCP Hdr:FIN (%pI4, %pI4, s=%d, a=%d)\n", | |
285 | &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num); | |
286 | payload_len = 0; | |
287 | pkt_hdr_len = IP_TCP_HDR_SIZE; | |
288 | current_tcp_state = TCP_FIN_WAIT_1; | |
289 | break; | |
290 | ||
291 | /* Notify connection closing */ | |
292 | ||
293 | case (TCP_FIN | TCP_ACK): | |
294 | case (TCP_FIN | TCP_ACK | TCP_PUSH): | |
295 | if (current_tcp_state == TCP_CLOSE_WAIT) | |
296 | current_tcp_state = TCP_CLOSING; | |
297 | ||
298 | tcp_ack_edge++; | |
299 | debug_cond(DEBUG_DEV_PKT, | |
300 | "TCP Hdr:FIN ACK PSH(%pI4, %pI4, s=%d, a=%d, A=%x)\n", | |
301 | &net_server_ip, &net_ip, | |
302 | tcp_seq_num, tcp_ack_edge, action); | |
303 | fallthrough; | |
304 | default: | |
305 | pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b); | |
306 | b->ip.hdr.tcp_flags = action | TCP_PUSH | TCP_ACK; | |
307 | debug_cond(DEBUG_DEV_PKT, | |
308 | "TCP Hdr:dft (%pI4, %pI4, s=%d, a=%d, A=%x)\n", | |
309 | &net_server_ip, &net_ip, | |
310 | tcp_seq_num, tcp_ack_num, action); | |
311 | } | |
312 | ||
313 | pkt_len = pkt_hdr_len + payload_len; | |
314 | tcp_len = pkt_len - IP_HDR_SIZE; | |
315 | ||
316 | /* TCP Header */ | |
317 | b->ip.hdr.tcp_ack = htonl(tcp_ack_edge); | |
318 | b->ip.hdr.tcp_src = htons(sport); | |
319 | b->ip.hdr.tcp_dst = htons(dport); | |
320 | b->ip.hdr.tcp_seq = htonl(tcp_seq_num); | |
321 | tcp_seq_num = tcp_seq_num + payload_len; | |
322 | ||
323 | /* | |
324 | * TCP window size - TCP header variable tcp_win. | |
325 | * Change tcp_win only if you have an understanding of network | |
326 | * overrun, congestion, TCP segment sizes, TCP windows, TCP scale, | |
327 | * queuing theory and packet buffering. If there are too few buffers, | |
328 | * there will be data loss, recovery may work or the sending TCP, | |
329 | * the server, could abort the stream transmission. | |
330 | * MSS is governed by maximum Ethernet frame length. | |
331 | * The number of buffers is governed by the desire to have a queue of | |
332 | * full buffers to be processed at the destination to maximize | |
333 | * throughput. Temporary memory use for the boot phase on modern | |
334 | * SOCs is may not be considered a constraint to buffer space, if | |
335 | * it is, then the u-boot tftp or nfs kernel netboot should be | |
336 | * considered. | |
337 | */ | |
338 | b->ip.hdr.tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE); | |
339 | ||
340 | b->ip.hdr.tcp_xsum = 0; | |
341 | b->ip.hdr.tcp_ugr = 0; | |
342 | ||
343 | b->ip.hdr.tcp_xsum = tcp_set_pseudo_header(pkt, net_ip, net_server_ip, | |
344 | tcp_len, pkt_len); | |
345 | ||
346 | net_set_ip_header((uchar *)&b->ip, net_server_ip, net_ip, | |
347 | pkt_len, IPPROTO_TCP); | |
348 | ||
349 | return pkt_hdr_len; | |
350 | } | |
351 | ||
352 | /** | |
353 | * tcp_hole() - Selective Acknowledgment (Essential for fast stream transfer) | |
354 | * @tcp_seq_num: TCP sequence start number | |
355 | * @len: the length of sequence numbers | |
356 | * @tcp_seq_max: maximum of sequence numbers | |
357 | */ | |
358 | void tcp_hole(u32 tcp_seq_num, u32 len, u32 tcp_seq_max) | |
359 | { | |
360 | u32 idx_sack, sack_in; | |
361 | u32 sack_end = TCP_SACK - 1; | |
362 | u32 hill = 0; | |
363 | enum pkt_state expect = PKT; | |
364 | u32 seq = tcp_seq_num - tcp_seq_init; | |
365 | u32 hol_l = tcp_ack_edge - tcp_seq_init; | |
366 | u32 hol_r = 0; | |
367 | ||
368 | /* Place new seq number in correct place in receive array */ | |
369 | if (prev_len == 0) | |
370 | prev_len = len; | |
371 | ||
372 | idx_sack = sack_idx + ((tcp_seq_num - tcp_ack_edge) / prev_len); | |
373 | if (idx_sack < TCP_SACK) { | |
374 | edge_a[idx_sack].se.l = tcp_seq_num; | |
375 | edge_a[idx_sack].se.r = tcp_seq_num + len; | |
376 | edge_a[idx_sack].st = PKT; | |
377 | ||
378 | /* | |
379 | * The fin (last) packet is not the same length as data | |
380 | * packets, and if it's length is recorded and used for | |
381 | * array index calculation, calculation breaks. | |
382 | */ | |
383 | if (prev_len < len) | |
384 | prev_len = len; | |
385 | } | |
386 | ||
387 | debug_cond(DEBUG_DEV_PKT, | |
388 | "TCP 1 seq %d, edg %d, len %d, sack_idx %d, sack_end %d\n", | |
389 | seq, hol_l, len, sack_idx, sack_end); | |
390 | ||
391 | /* Right edge of contiguous stream, is the left edge of first hill */ | |
392 | hol_l = tcp_seq_num - tcp_seq_init; | |
393 | hol_r = hol_l + len; | |
394 | ||
395 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) | |
396 | tcp_lost.len = TCP_OPT_LEN_2; | |
397 | ||
398 | debug_cond(DEBUG_DEV_PKT, | |
399 | "TCP 1 in %d, seq %d, pkt_l %d, pkt_r %d, sack_idx %d, sack_end %d\n", | |
400 | idx_sack, seq, hol_l, hol_r, sack_idx, sack_end); | |
401 | ||
402 | for (sack_in = sack_idx; sack_in < sack_end && hill < TCP_SACK_HILLS; | |
403 | sack_in++) { | |
404 | switch (expect) { | |
405 | case NOPKT: | |
406 | switch (edge_a[sack_in].st) { | |
407 | case NOPKT: | |
408 | debug_cond(DEBUG_INT_STATE, "N"); | |
409 | break; | |
410 | case PKT: | |
411 | debug_cond(DEBUG_INT_STATE, "n"); | |
412 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) { | |
413 | tcp_lost.hill[hill].l = | |
414 | edge_a[sack_in].se.l; | |
415 | tcp_lost.hill[hill].r = | |
416 | edge_a[sack_in].se.r; | |
417 | } | |
418 | expect = PKT; | |
419 | break; | |
420 | } | |
421 | break; | |
422 | case PKT: | |
423 | switch (edge_a[sack_in].st) { | |
424 | case NOPKT: | |
425 | debug_cond(DEBUG_INT_STATE, "p"); | |
426 | if (sack_in > sack_idx && | |
427 | hill < TCP_SACK_HILLS) { | |
428 | hill++; | |
429 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK)) | |
430 | tcp_lost.len += TCP_OPT_LEN_8; | |
431 | } | |
432 | expect = NOPKT; | |
433 | break; | |
434 | case PKT: | |
435 | debug_cond(DEBUG_INT_STATE, "P"); | |
436 | ||
437 | if (tcp_ack_edge == edge_a[sack_in].se.l) { | |
438 | tcp_ack_edge = edge_a[sack_in].se.r; | |
439 | edge_a[sack_in].st = NOPKT; | |
440 | sack_idx++; | |
441 | } else { | |
442 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK) && | |
443 | hill < TCP_SACK_HILLS) | |
444 | tcp_lost.hill[hill].r = | |
445 | edge_a[sack_in].se.r; | |
446 | if (IS_ENABLED(CONFIG_PROT_TCP_SACK) && | |
447 | sack_in == sack_end - 1) | |
448 | tcp_lost.hill[hill].r = | |
449 | edge_a[sack_in].se.r; | |
450 | } | |
451 | break; | |
452 | } | |
453 | break; | |
454 | } | |
455 | } | |
456 | debug_cond(DEBUG_INT_STATE, "\n"); | |
457 | if (!IS_ENABLED(CONFIG_PROT_TCP_SACK) || tcp_lost.len <= TCP_OPT_LEN_2) | |
458 | sack_idx = 0; | |
459 | } | |
460 | ||
461 | /** | |
462 | * tcp_parse_options() - parsing TCP options | |
463 | * @o: pointer to the option field. | |
464 | * @o_len: length of the option field. | |
465 | */ | |
466 | void tcp_parse_options(uchar *o, int o_len) | |
467 | { | |
468 | struct tcp_t_opt *tsopt; | |
469 | uchar *p = o; | |
470 | ||
471 | /* | |
472 | * NOPs are options with a zero length, and thus are special. | |
473 | * All other options have length fields. | |
474 | */ | |
475 | for (p = o; p < (o + o_len); p = p + p[1]) { | |
476 | if (!p[1]) | |
477 | return; /* Finished processing options */ | |
478 | ||
479 | switch (p[0]) { | |
480 | case TCP_O_END: | |
481 | return; | |
482 | case TCP_O_MSS: | |
483 | case TCP_O_SCL: | |
484 | case TCP_P_SACK: | |
485 | case TCP_V_SACK: | |
486 | break; | |
487 | case TCP_O_TS: | |
488 | tsopt = (struct tcp_t_opt *)p; | |
489 | rmt_timestamp = tsopt->t_snd; | |
490 | return; | |
491 | } | |
492 | ||
493 | /* Process optional NOPs */ | |
494 | if (p[0] == TCP_O_NOP) | |
495 | p++; | |
496 | } | |
497 | } | |
498 | ||
499 | static u8 tcp_state_machine(u8 tcp_flags, u32 *tcp_seq_num, int payload_len) | |
500 | { | |
501 | u8 tcp_fin = tcp_flags & TCP_FIN; | |
502 | u8 tcp_syn = tcp_flags & TCP_SYN; | |
503 | u8 tcp_rst = tcp_flags & TCP_RST; | |
504 | u8 tcp_push = tcp_flags & TCP_PUSH; | |
505 | u8 tcp_ack = tcp_flags & TCP_ACK; | |
506 | u8 action = TCP_DATA; | |
507 | int i; | |
508 | ||
509 | /* | |
510 | * tcp_flags are examined to determine TX action in a given state | |
511 | * tcp_push is interpreted to mean "inform the app" | |
512 | * urg, ece, cer and nonce flags are not supported. | |
513 | * | |
514 | * exe and crw are use to signal and confirm knowledge of congestion. | |
515 | * This TCP only sends a file request and acks. If it generates | |
516 | * congestion, the network is broken. | |
517 | */ | |
518 | debug_cond(DEBUG_INT_STATE, "TCP STATE ENTRY %x\n", action); | |
519 | if (tcp_rst) { | |
520 | action = TCP_DATA; | |
521 | current_tcp_state = TCP_CLOSED; | |
522 | net_set_state(NETLOOP_FAIL); | |
523 | debug_cond(DEBUG_INT_STATE, "TCP Reset %x\n", tcp_flags); | |
524 | return TCP_RST; | |
525 | } | |
526 | ||
527 | switch (current_tcp_state) { | |
528 | case TCP_CLOSED: | |
529 | debug_cond(DEBUG_INT_STATE, "TCP CLOSED %x\n", tcp_flags); | |
530 | if (tcp_ack) | |
531 | action = TCP_DATA; | |
532 | else if (tcp_syn) | |
533 | action = TCP_RST; | |
534 | else if (tcp_fin) | |
535 | action = TCP_DATA; | |
536 | break; | |
537 | case TCP_SYN_SENT: | |
538 | debug_cond(DEBUG_INT_STATE, "TCP_SYN_SENT %x, %d\n", | |
539 | tcp_flags, *tcp_seq_num); | |
540 | if (tcp_fin) { | |
541 | action = action | TCP_PUSH; | |
542 | current_tcp_state = TCP_CLOSE_WAIT; | |
543 | } | |
544 | if (tcp_syn) { | |
545 | action = action | TCP_ACK | TCP_PUSH; | |
546 | if (tcp_ack) { | |
547 | tcp_seq_init = *tcp_seq_num; | |
548 | *tcp_seq_num = *tcp_seq_num + 1; | |
549 | tcp_seq_max = *tcp_seq_num; | |
550 | tcp_ack_edge = *tcp_seq_num; | |
551 | sack_idx = 0; | |
552 | edge_a[sack_idx].se.l = *tcp_seq_num; | |
553 | edge_a[sack_idx].se.r = *tcp_seq_num; | |
554 | prev_len = 0; | |
555 | current_tcp_state = TCP_ESTABLISHED; | |
556 | for (i = 0; i < TCP_SACK; i++) | |
557 | edge_a[i].st = NOPKT; | |
558 | } | |
559 | } else if (tcp_ack) { | |
560 | action = TCP_DATA; | |
561 | } | |
562 | ||
563 | break; | |
564 | case TCP_ESTABLISHED: | |
565 | debug_cond(DEBUG_INT_STATE, "TCP_ESTABLISHED %x\n", tcp_flags); | |
566 | if (*tcp_seq_num > tcp_seq_max) | |
567 | tcp_seq_max = *tcp_seq_num; | |
568 | if (payload_len > 0) { | |
569 | tcp_hole(*tcp_seq_num, payload_len, tcp_seq_max); | |
570 | tcp_fin = TCP_DATA; /* cause standalone FIN */ | |
571 | } | |
572 | ||
573 | if ((tcp_fin) && | |
574 | (!IS_ENABLED(CONFIG_PROT_TCP_SACK) || | |
575 | tcp_lost.len <= TCP_OPT_LEN_2)) { | |
576 | action = action | TCP_FIN | TCP_PUSH | TCP_ACK; | |
577 | current_tcp_state = TCP_CLOSE_WAIT; | |
578 | } else if (tcp_ack) { | |
579 | action = TCP_DATA; | |
580 | } | |
581 | ||
582 | if (tcp_syn) | |
583 | action = TCP_ACK + TCP_RST; | |
584 | else if (tcp_push) | |
585 | action = action | TCP_PUSH; | |
586 | break; | |
587 | case TCP_CLOSE_WAIT: | |
588 | debug_cond(DEBUG_INT_STATE, "TCP_CLOSE_WAIT (%x)\n", tcp_flags); | |
589 | action = TCP_DATA; | |
590 | break; | |
591 | case TCP_FIN_WAIT_2: | |
592 | debug_cond(DEBUG_INT_STATE, "TCP_FIN_WAIT_2 (%x)\n", tcp_flags); | |
593 | if (tcp_ack) { | |
594 | action = TCP_PUSH | TCP_ACK; | |
595 | current_tcp_state = TCP_CLOSED; | |
596 | puts("\n"); | |
597 | } else if (tcp_syn) { | |
598 | action = TCP_DATA; | |
599 | } else if (tcp_fin) { | |
600 | action = TCP_DATA; | |
601 | } | |
602 | break; | |
603 | case TCP_FIN_WAIT_1: | |
604 | debug_cond(DEBUG_INT_STATE, "TCP_FIN_WAIT_1 (%x)\n", tcp_flags); | |
605 | if (tcp_fin) { | |
606 | action = TCP_ACK | TCP_FIN; | |
607 | current_tcp_state = TCP_FIN_WAIT_2; | |
608 | } | |
609 | if (tcp_syn) | |
610 | action = TCP_RST; | |
611 | if (tcp_ack) { | |
612 | current_tcp_state = TCP_CLOSED; | |
613 | tcp_seq_num = tcp_seq_num + 1; | |
614 | } | |
615 | break; | |
616 | case TCP_CLOSING: | |
617 | debug_cond(DEBUG_INT_STATE, "TCP_CLOSING (%x)\n", tcp_flags); | |
618 | if (tcp_ack) { | |
619 | action = TCP_PUSH; | |
620 | current_tcp_state = TCP_CLOSED; | |
621 | puts("\n"); | |
622 | } else if (tcp_syn) { | |
623 | action = TCP_RST; | |
624 | } else if (tcp_fin) { | |
625 | action = TCP_DATA; | |
626 | } | |
627 | break; | |
628 | } | |
629 | return action; | |
630 | } | |
631 | ||
632 | /** | |
633 | * rxhand_tcp_f() - process receiving data and call data handler. | |
634 | * @b: the packet | |
635 | * @pkt_len: the length of packet. | |
636 | */ | |
637 | void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len) | |
638 | { | |
639 | int tcp_len = pkt_len - IP_HDR_SIZE; | |
640 | u16 tcp_rx_xsum = b->ip.hdr.ip_sum; | |
641 | u8 tcp_action = TCP_DATA; | |
642 | u32 tcp_seq_num, tcp_ack_num; | |
643 | struct in_addr action_and_state; | |
644 | int tcp_hdr_len, payload_len; | |
645 | ||
646 | /* Verify IP header */ | |
647 | debug_cond(DEBUG_DEV_PKT, | |
648 | "TCP RX in RX Sum (to=%pI4, from=%pI4, len=%d)\n", | |
649 | &b->ip.hdr.ip_src, &b->ip.hdr.ip_dst, pkt_len); | |
650 | ||
651 | b->ip.hdr.ip_src = net_server_ip; | |
652 | b->ip.hdr.ip_dst = net_ip; | |
653 | b->ip.hdr.ip_sum = 0; | |
654 | if (tcp_rx_xsum != compute_ip_checksum(b, IP_HDR_SIZE)) { | |
655 | debug_cond(DEBUG_DEV_PKT, | |
656 | "TCP RX IP xSum Error (%pI4, =%pI4, len=%d)\n", | |
657 | &net_ip, &net_server_ip, pkt_len); | |
658 | return; | |
659 | } | |
660 | ||
661 | /* Build pseudo header and verify TCP header */ | |
662 | tcp_rx_xsum = b->ip.hdr.tcp_xsum; | |
663 | b->ip.hdr.tcp_xsum = 0; | |
664 | if (tcp_rx_xsum != tcp_set_pseudo_header((uchar *)b, b->ip.hdr.ip_src, | |
665 | b->ip.hdr.ip_dst, tcp_len, | |
666 | pkt_len)) { | |
667 | debug_cond(DEBUG_DEV_PKT, | |
668 | "TCP RX TCP xSum Error (%pI4, %pI4, len=%d)\n", | |
669 | &net_ip, &net_server_ip, tcp_len); | |
670 | return; | |
671 | } | |
672 | ||
673 | tcp_hdr_len = GET_TCP_HDR_LEN_IN_BYTES(b->ip.hdr.tcp_hlen); | |
674 | payload_len = tcp_len - tcp_hdr_len; | |
675 | ||
676 | if (tcp_hdr_len > TCP_HDR_SIZE) | |
677 | tcp_parse_options((uchar *)b + IP_TCP_HDR_SIZE, | |
678 | tcp_hdr_len - TCP_HDR_SIZE); | |
679 | /* | |
680 | * Incoming sequence and ack numbers are server's view of the numbers. | |
681 | * The app must swap the numbers when responding. | |
682 | */ | |
683 | tcp_seq_num = ntohl(b->ip.hdr.tcp_seq); | |
684 | tcp_ack_num = ntohl(b->ip.hdr.tcp_ack); | |
685 | ||
686 | /* Packets are not ordered. Send to app as received. */ | |
687 | tcp_action = tcp_state_machine(b->ip.hdr.tcp_flags, | |
688 | &tcp_seq_num, payload_len); | |
689 | ||
690 | tcp_activity_count++; | |
691 | if (tcp_activity_count > TCP_ACTIVITY) { | |
692 | puts("| "); | |
693 | tcp_activity_count = 0; | |
694 | } | |
695 | ||
696 | if ((tcp_action & TCP_PUSH) || payload_len > 0) { | |
697 | debug_cond(DEBUG_DEV_PKT, | |
698 | "TCP Notify (action=%x, Seq=%d,Ack=%d,Pay%d)\n", | |
699 | tcp_action, tcp_seq_num, tcp_ack_num, payload_len); | |
700 | ||
701 | action_and_state.s_addr = tcp_action; | |
702 | (*tcp_packet_handler) ((uchar *)b + pkt_len - payload_len, | |
703 | tcp_seq_num, action_and_state, | |
704 | tcp_ack_num, payload_len); | |
705 | ||
706 | } else if (tcp_action != TCP_DATA) { | |
707 | debug_cond(DEBUG_DEV_PKT, | |
708 | "TCP Action (action=%x,Seq=%d,Ack=%d,Pay=%d)\n", | |
709 | tcp_action, tcp_seq_num, tcp_ack_num, payload_len); | |
710 | ||
711 | /* | |
712 | * Warning: Incoming Ack & Seq sequence numbers are transposed | |
713 | * here to outgoing Seq & Ack sequence numbers | |
714 | */ | |
715 | net_send_tcp_packet(0, ntohs(b->ip.hdr.tcp_src), | |
716 | ntohs(b->ip.hdr.tcp_dst), | |
717 | (tcp_action & (~TCP_PUSH)), | |
718 | tcp_seq_num, tcp_ack_num); | |
719 | } | |
720 | } |