From: Dmitrii Merkurev Date: Wed, 12 Apr 2023 18:49:29 +0000 (+0100) Subject: net: support being a TCP server to unblock TCP fastboot X-Git-Url: http://git.dujemihanovic.xyz/img/static/git-logo.png?a=commitdiff_plain;h=08fb8da371331c747c265d999bcb3426e3d2d0b3;p=u-boot.git net: support being a TCP server to unblock TCP fastboot Make following changes to unblock TCP fastboot support: 1. Implement being a TCP server support 2. Introduce dedicated TCP traffic handler (get rid of UDP signature) 3. Ensure seq_num and ack_num are respected in net_send_tcp_packet function (make sure existing wget_cmd code is reflected with the fix) Signed-off-by: Dmitrii Merkurev Cc: Ying-Chun Liu (PaulLiu) Cc: Simon Glass Сс: Joe Hershberger Сс: Ramon Fried Reviewed-by: Ying-Chun Liu (PaulLiu) Reviewed-by: Simon Glass Reviewed-by: Ramon Fried --- diff --git a/include/net/tcp.h b/include/net/tcp.h index 322551694f..c29d4ce24a 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -259,6 +259,7 @@ union tcp_build_pkt { * enum tcp_state - TCP State machine states for connection * @TCP_CLOSED: Need to send SYN to connect * @TCP_SYN_SENT: Trying to connect, waiting for SYN ACK + * @TCP_SYN_RECEIVED: Initial SYN received, waiting for ACK * @TCP_ESTABLISHED: both server & client have a connection * @TCP_CLOSE_WAIT: Rec FIN, passed to app for FIN, ACK rsp * @TCP_CLOSING: Rec FIN, sent FIN, ACK waiting for ACK @@ -268,6 +269,7 @@ union tcp_build_pkt { enum tcp_state { TCP_CLOSED, TCP_SYN_SENT, + TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSE_WAIT, TCP_CLOSING, @@ -283,14 +285,18 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, /** * rxhand_tcp() - An incoming packet handler. * @pkt: pointer to the application packet - * @dport: destination UDP port + * @dport: destination TCP port * @sip: source IP address - * @sport: source UDP port + * @sport: source TCP port + * @tcp_seq_num: TCP sequential number + * @tcp_ack_num: TCP acknowledgment number + * @action: TCP action (SYN, ACK, FIN, etc) * @len: packet length */ -typedef void rxhand_tcp(uchar *pkt, unsigned int dport, - struct in_addr sip, unsigned int sport, - unsigned int len); +typedef void rxhand_tcp(uchar *pkt, u16 dport, + struct in_addr sip, u16 sport, + u32 tcp_seq_num, u32 tcp_ack_num, + u8 action, unsigned int len); void tcp_set_tcp_handler(rxhand_tcp *f); void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int len); diff --git a/net/tcp.c b/net/tcp.c index 8d338c72e8..a713e1dd60 100644 --- a/net/tcp.c +++ b/net/tcp.c @@ -36,7 +36,6 @@ static u32 rmt_timestamp; static u32 tcp_seq_init; static u32 tcp_ack_edge; -static u32 tcp_seq_max; static int tcp_activity_count; @@ -90,9 +89,10 @@ void tcp_set_tcp_state(enum tcp_state new_state) current_tcp_state = new_state; } -static void dummy_handler(uchar *pkt, unsigned int dport, - struct in_addr sip, unsigned int sport, - unsigned int len) +static void dummy_handler(uchar *pkt, u16 dport, + struct in_addr sip, u16 sport, + u32 tcp_seq_num, u32 tcp_ack_num, + u8 action, unsigned int len) { } @@ -256,7 +256,7 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, switch (action) { case TCP_SYN: debug_cond(DEBUG_DEV_PKT, - "TCP Hdr:SYN (%pI4, %pI4, sq=%d, ak=%d)\n", + "TCP Hdr:SYN (%pI4, %pI4, sq=%u, ak=%u)\n", &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num); tcp_activity_count = 0; @@ -271,41 +271,46 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, current_tcp_state = TCP_SYN_SENT; } break; + case TCP_SYN | TCP_ACK: case TCP_ACK: pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b); b->ip.hdr.tcp_flags = action; debug_cond(DEBUG_DEV_PKT, - "TCP Hdr:ACK (%pI4, %pI4, s=%d, a=%d, A=%x)\n", + "TCP Hdr:ACK (%pI4, %pI4, s=%u, a=%u, A=%x)\n", &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num, action); break; case TCP_FIN: debug_cond(DEBUG_DEV_PKT, - "TCP Hdr:FIN (%pI4, %pI4, s=%d, a=%d)\n", + "TCP Hdr:FIN (%pI4, %pI4, s=%u, a=%u)\n", &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num); payload_len = 0; pkt_hdr_len = IP_TCP_HDR_SIZE; current_tcp_state = TCP_FIN_WAIT_1; break; - + case TCP_RST | TCP_ACK: + case TCP_RST: + debug_cond(DEBUG_DEV_PKT, + "TCP Hdr:RST (%pI4, %pI4, s=%u, a=%u)\n", + &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num); + current_tcp_state = TCP_CLOSED; + break; /* Notify connection closing */ - case (TCP_FIN | TCP_ACK): case (TCP_FIN | TCP_ACK | TCP_PUSH): if (current_tcp_state == TCP_CLOSE_WAIT) current_tcp_state = TCP_CLOSING; - tcp_ack_edge++; debug_cond(DEBUG_DEV_PKT, - "TCP Hdr:FIN ACK PSH(%pI4, %pI4, s=%d, a=%d, A=%x)\n", + "TCP Hdr:FIN ACK PSH(%pI4, %pI4, s=%u, a=%u, A=%x)\n", &net_server_ip, &net_ip, - tcp_seq_num, tcp_ack_edge, action); + tcp_seq_num, tcp_ack_num, action); fallthrough; default: pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options(b); b->ip.hdr.tcp_flags = action | TCP_PUSH | TCP_ACK; debug_cond(DEBUG_DEV_PKT, - "TCP Hdr:dft (%pI4, %pI4, s=%d, a=%d, A=%x)\n", + "TCP Hdr:dft (%pI4, %pI4, s=%u, a=%u, A=%x)\n", &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num, action); } @@ -313,12 +318,12 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, pkt_len = pkt_hdr_len + payload_len; tcp_len = pkt_len - IP_HDR_SIZE; + tcp_ack_edge = tcp_ack_num; /* TCP Header */ b->ip.hdr.tcp_ack = htonl(tcp_ack_edge); b->ip.hdr.tcp_src = htons(sport); b->ip.hdr.tcp_dst = htons(dport); b->ip.hdr.tcp_seq = htonl(tcp_seq_num); - tcp_seq_num = tcp_seq_num + payload_len; /* * TCP window size - TCP header variable tcp_win. @@ -353,9 +358,8 @@ int tcp_set_tcp_header(uchar *pkt, int dport, int sport, int payload_len, * tcp_hole() - Selective Acknowledgment (Essential for fast stream transfer) * @tcp_seq_num: TCP sequence start number * @len: the length of sequence numbers - * @tcp_seq_max: maximum of sequence numbers */ -void tcp_hole(u32 tcp_seq_num, u32 len, u32 tcp_seq_max) +void tcp_hole(u32 tcp_seq_num, u32 len) { u32 idx_sack, sack_in; u32 sack_end = TCP_SACK - 1; @@ -496,7 +500,7 @@ void tcp_parse_options(uchar *o, int o_len) } } -static u8 tcp_state_machine(u8 tcp_flags, u32 *tcp_seq_num, int payload_len) +static u8 tcp_state_machine(u8 tcp_flags, u32 tcp_seq_num, int payload_len) { u8 tcp_fin = tcp_flags & TCP_FIN; u8 tcp_syn = tcp_flags & TCP_SYN; @@ -527,46 +531,44 @@ static u8 tcp_state_machine(u8 tcp_flags, u32 *tcp_seq_num, int payload_len) switch (current_tcp_state) { case TCP_CLOSED: debug_cond(DEBUG_INT_STATE, "TCP CLOSED %x\n", tcp_flags); - if (tcp_ack) - action = TCP_DATA; - else if (tcp_syn) - action = TCP_RST; - else if (tcp_fin) + if (tcp_syn) { + action = TCP_SYN | TCP_ACK; + tcp_seq_init = tcp_seq_num; + tcp_ack_edge = tcp_seq_num + 1; + current_tcp_state = TCP_SYN_RECEIVED; + } else if (tcp_ack || tcp_fin) { action = TCP_DATA; + } break; + case TCP_SYN_RECEIVED: case TCP_SYN_SENT: - debug_cond(DEBUG_INT_STATE, "TCP_SYN_SENT %x, %d\n", - tcp_flags, *tcp_seq_num); + debug_cond(DEBUG_INT_STATE, "TCP_SYN_SENT | TCP_SYN_RECEIVED %x, %u\n", + tcp_flags, tcp_seq_num); if (tcp_fin) { action = action | TCP_PUSH; current_tcp_state = TCP_CLOSE_WAIT; - } - if (tcp_syn) { - action = action | TCP_ACK | TCP_PUSH; - if (tcp_ack) { - tcp_seq_init = *tcp_seq_num; - *tcp_seq_num = *tcp_seq_num + 1; - tcp_seq_max = *tcp_seq_num; - tcp_ack_edge = *tcp_seq_num; - sack_idx = 0; - edge_a[sack_idx].se.l = *tcp_seq_num; - edge_a[sack_idx].se.r = *tcp_seq_num; - prev_len = 0; - current_tcp_state = TCP_ESTABLISHED; - for (i = 0; i < TCP_SACK; i++) - edge_a[i].st = NOPKT; - } - } else if (tcp_ack) { + } else if (tcp_ack || (tcp_syn && tcp_ack)) { + action |= TCP_ACK; + tcp_seq_init = tcp_seq_num; + tcp_ack_edge = tcp_seq_num + 1; + sack_idx = 0; + edge_a[sack_idx].se.l = tcp_ack_edge; + edge_a[sack_idx].se.r = tcp_ack_edge; + prev_len = 0; + current_tcp_state = TCP_ESTABLISHED; + for (i = 0; i < TCP_SACK; i++) + edge_a[i].st = NOPKT; + + if (tcp_syn && tcp_ack) + action |= TCP_PUSH; + } else { action = TCP_DATA; } - break; case TCP_ESTABLISHED: debug_cond(DEBUG_INT_STATE, "TCP_ESTABLISHED %x\n", tcp_flags); - if (*tcp_seq_num > tcp_seq_max) - tcp_seq_max = *tcp_seq_num; if (payload_len > 0) { - tcp_hole(*tcp_seq_num, payload_len, tcp_seq_max); + tcp_hole(tcp_seq_num, payload_len); tcp_fin = TCP_DATA; /* cause standalone FIN */ } @@ -603,15 +605,14 @@ static u8 tcp_state_machine(u8 tcp_flags, u32 *tcp_seq_num, int payload_len) case TCP_FIN_WAIT_1: debug_cond(DEBUG_INT_STATE, "TCP_FIN_WAIT_1 (%x)\n", tcp_flags); if (tcp_fin) { + tcp_ack_edge++; action = TCP_ACK | TCP_FIN; current_tcp_state = TCP_FIN_WAIT_2; } if (tcp_syn) action = TCP_RST; - if (tcp_ack) { + if (tcp_ack) current_tcp_state = TCP_CLOSED; - tcp_seq_num = tcp_seq_num + 1; - } break; case TCP_CLOSING: debug_cond(DEBUG_INT_STATE, "TCP_CLOSING (%x)\n", tcp_flags); @@ -640,7 +641,6 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len) u16 tcp_rx_xsum = b->ip.hdr.ip_sum; u8 tcp_action = TCP_DATA; u32 tcp_seq_num, tcp_ack_num; - struct in_addr action_and_state; int tcp_hdr_len, payload_len; /* Verify IP header */ @@ -685,7 +685,7 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len) /* Packets are not ordered. Send to app as received. */ tcp_action = tcp_state_machine(b->ip.hdr.tcp_flags, - &tcp_seq_num, payload_len); + tcp_seq_num, payload_len); tcp_activity_count++; if (tcp_activity_count > TCP_ACTIVITY) { @@ -695,18 +695,17 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len) if ((tcp_action & TCP_PUSH) || payload_len > 0) { debug_cond(DEBUG_DEV_PKT, - "TCP Notify (action=%x, Seq=%d,Ack=%d,Pay%d)\n", + "TCP Notify (action=%x, Seq=%u,Ack=%u,Pay%d)\n", tcp_action, tcp_seq_num, tcp_ack_num, payload_len); - action_and_state.s_addr = tcp_action; - (*tcp_packet_handler) ((uchar *)b + pkt_len - payload_len, - tcp_seq_num, action_and_state, - tcp_ack_num, payload_len); + (*tcp_packet_handler) ((uchar *)b + pkt_len - payload_len, b->ip.hdr.tcp_dst, + b->ip.hdr.ip_src, b->ip.hdr.tcp_src, tcp_seq_num, + tcp_ack_num, tcp_action, payload_len); } else if (tcp_action != TCP_DATA) { debug_cond(DEBUG_DEV_PKT, - "TCP Action (action=%x,Seq=%d,Ack=%d,Pay=%d)\n", - tcp_action, tcp_seq_num, tcp_ack_num, payload_len); + "TCP Action (action=%x,Seq=%u,Ack=%u,Pay=%d)\n", + tcp_action, tcp_ack_num, tcp_ack_edge, payload_len); /* * Warning: Incoming Ack & Seq sequence numbers are transposed @@ -715,6 +714,6 @@ void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len) net_send_tcp_packet(0, ntohs(b->ip.hdr.tcp_src), ntohs(b->ip.hdr.tcp_dst), (tcp_action & (~TCP_PUSH)), - tcp_seq_num, tcp_ack_num); + tcp_ack_num, tcp_ack_edge); } } diff --git a/net/wget.c b/net/wget.c index eebdf80eb5..2dbfeb1a1d 100644 --- a/net/wget.c +++ b/net/wget.c @@ -88,8 +88,8 @@ static void wget_send_stored(void) { u8 action = retry_action; int len = retry_len; - unsigned int tcp_ack_num = retry_tcp_ack_num + len; - unsigned int tcp_seq_num = retry_tcp_seq_num; + unsigned int tcp_ack_num = retry_tcp_seq_num + (len == 0 ? 1 : len); + unsigned int tcp_seq_num = retry_tcp_ack_num; uchar *ptr, *offset; switch (current_wget_state) { @@ -130,8 +130,8 @@ static void wget_send_stored(void) } } -static void wget_send(u8 action, unsigned int tcp_ack_num, - unsigned int tcp_seq_num, int len) +static void wget_send(u8 action, unsigned int tcp_seq_num, + unsigned int tcp_ack_num, int len) { retry_action = action; retry_tcp_ack_num = tcp_ack_num; @@ -178,10 +178,8 @@ static void wget_timeout_handler(void) #define PKT_QUEUE_PACKET_SIZE 0x800 static void wget_connected(uchar *pkt, unsigned int tcp_seq_num, - struct in_addr action_and_state, - unsigned int tcp_ack_num, unsigned int len) + u8 action, unsigned int tcp_ack_num, unsigned int len) { - u8 action = action_and_state.s_addr; uchar *pkt_in_q; char *pos; int hlen, i; @@ -268,22 +266,25 @@ static void wget_connected(uchar *pkt, unsigned int tcp_seq_num, } /** - * wget_handler() - handler of wget - * @pkt: the pointer to the payload - * @tcp_seq_num: tcp sequence number - * @action_and_state: TCP state - * @tcp_ack_num: tcp acknowledge number - * @len: length of the payload + * wget_handler() - TCP handler of wget + * @pkt: pointer to the application packet + * @dport: destination TCP port + * @sip: source IP address + * @sport: source TCP port + * @tcp_seq_num: TCP sequential number + * @tcp_ack_num: TCP acknowledgment number + * @action: TCP action (SYN, ACK, FIN, etc) + * @len: packet length * * In the "application push" invocation, the TCP header with all * its information is pointed to by the packet pointer. */ -static void wget_handler(uchar *pkt, unsigned int tcp_seq_num, - struct in_addr action_and_state, - unsigned int tcp_ack_num, unsigned int len) +static void wget_handler(uchar *pkt, u16 dport, + struct in_addr sip, u16 sport, + u32 tcp_seq_num, u32 tcp_ack_num, + u8 action, unsigned int len) { enum tcp_state wget_tcp_state = tcp_get_tcp_state(); - u8 action = action_and_state.s_addr; net_set_timeout_handler(wget_timeout, wget_timeout_handler); packets++; @@ -294,7 +295,7 @@ static void wget_handler(uchar *pkt, unsigned int tcp_seq_num, break; case WGET_CONNECTING: debug_cond(DEBUG_WGET, - "wget: Connecting In len=%x, Seq=%x, Ack=%x\n", + "wget: Connecting In len=%x, Seq=%u, Ack=%u\n", len, tcp_seq_num, tcp_ack_num); if (!len) { if (wget_tcp_state == TCP_ESTABLISHED) { @@ -310,14 +311,13 @@ static void wget_handler(uchar *pkt, unsigned int tcp_seq_num, } break; case WGET_CONNECTED: - debug_cond(DEBUG_WGET, "wget: Connected seq=%x, len=%x\n", + debug_cond(DEBUG_WGET, "wget: Connected seq=%u, len=%x\n", tcp_seq_num, len); if (!len) { wget_fail("Image not found, no data returned\n", tcp_seq_num, tcp_ack_num, action); } else { - wget_connected(pkt, tcp_seq_num, action_and_state, - tcp_ack_num, len); + wget_connected(pkt, tcp_seq_num, action, tcp_ack_num, len); } break; case WGET_TRANSFERRING: @@ -338,6 +338,7 @@ static void wget_handler(uchar *pkt, unsigned int tcp_seq_num, wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num, len); fallthrough; case TCP_SYN_SENT: + case TCP_SYN_RECEIVED: case TCP_CLOSING: case TCP_FIN_WAIT_1: case TCP_CLOSED: