mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 03:58:17 +00:00 
			
		
		
		
	Changes:
 * Fix initial send sequence always zero issue
 * Use state machine close to RFC 9293. This should make TCP
   transfers more reliable (now we can upload a huge array
   of data from the board to external server)
 * Improve TCP framework a lot. This should make tcp client
   code much more simple.
 * rewrite wget with new tcp stack
 * rewrite fastboot_tcp with new tcp stack
It's quite hard to fix the initial send sequence (ISS) issue
with the separate patch. A naive attempt to fix an issue
inside the tcp_set_tcp_header() function will break tcp packet
retransmit logic in wget and other clients.
Example:
  Wget stores tcp_seq_num value before tcp_set_tcp_header() will
  be called and (on failure) retransmit the packet with the stored
  tcp_seq_num value. Thus:
    * the same ISS must allways be used (current case)
    * or tcp clients needs to generate a proper ISS when
      required.
A proper ISS fix will require a big redesing comparable with
a this one.
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: Simon Glass <sjg@chromium.org>
		
	
			
		
			
				
	
	
		
			119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: BSD-2-Clause
 | |
| /*
 | |
|  * Copyright (C) 2023 The Android Open Source Project
 | |
|  */
 | |
| 
 | |
| #include <fastboot.h>
 | |
| #include <net.h>
 | |
| #include <net/fastboot_tcp.h>
 | |
| #include <net/tcp.h>
 | |
| 
 | |
| #define FASTBOOT_TCP_PORT	5554
 | |
| 
 | |
| static const unsigned short handshake_length = 4;
 | |
| static const uchar *handshake = "FB01";
 | |
| 
 | |
| static char rxbuf[sizeof(u64) + FASTBOOT_COMMAND_LEN + 1];
 | |
| static char txbuf[sizeof(u64) + FASTBOOT_RESPONSE_LEN + 1];
 | |
| 
 | |
| static u32 data_read;
 | |
| static u32 tx_last_offs, tx_last_len;
 | |
| 
 | |
| static void tcp_stream_on_rcv_nxt_update(struct tcp_stream *tcp, u32 rx_bytes)
 | |
| {
 | |
| 	u64	cmd_size;
 | |
| 	__be64	len_be;
 | |
| 	char	saved;
 | |
| 	int	fastboot_command_id, len;
 | |
| 
 | |
| 	if (!data_read && rx_bytes >= handshake_length) {
 | |
| 		if (memcmp(rxbuf, handshake, handshake_length)) {
 | |
| 			printf("fastboot: bad handshake\n");
 | |
| 			tcp_stream_close(tcp);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		tx_last_offs = 0;
 | |
| 		tx_last_len = handshake_length;
 | |
| 		memcpy(txbuf, handshake, handshake_length);
 | |
| 
 | |
| 		data_read += handshake_length;
 | |
| 		rx_bytes -= handshake_length;
 | |
| 		if (rx_bytes > 0)
 | |
| 			memmove(rxbuf, rxbuf + handshake_length, rx_bytes);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (rx_bytes < sizeof(u64))
 | |
| 		return;
 | |
| 
 | |
| 	memcpy(&cmd_size, rxbuf, sizeof(u64));
 | |
| 	cmd_size = __be64_to_cpu(cmd_size);
 | |
| 	if (rx_bytes < sizeof(u64) + cmd_size)
 | |
| 		return;
 | |
| 
 | |
| 	saved = rxbuf[sizeof(u64) + cmd_size];
 | |
| 	rxbuf[sizeof(u64) + cmd_size] = '\0';
 | |
| 	fastboot_command_id = fastboot_handle_command(rxbuf + sizeof(u64),
 | |
| 						      txbuf + sizeof(u64));
 | |
| 	fastboot_handle_boot(fastboot_command_id,
 | |
| 			     strncmp("OKAY", txbuf + sizeof(u64), 4) != 0);
 | |
| 	rxbuf[sizeof(u64) + cmd_size] = saved;
 | |
| 
 | |
| 	len = strlen(txbuf + sizeof(u64));
 | |
| 	len_be = __cpu_to_be64(len);
 | |
| 	memcpy(txbuf, &len_be, sizeof(u64));
 | |
| 
 | |
| 	tx_last_offs += tx_last_len;
 | |
| 	tx_last_len = len + sizeof(u64);
 | |
| 
 | |
| 	data_read += sizeof(u64) + cmd_size;
 | |
| 	rx_bytes -= sizeof(u64) + cmd_size;
 | |
| 	if (rx_bytes > 0)
 | |
| 		memmove(rxbuf, rxbuf + sizeof(u64) + cmd_size, rx_bytes);
 | |
| }
 | |
| 
 | |
| static int tcp_stream_rx(struct tcp_stream *tcp, u32 rx_offs, void *buf, int len)
 | |
| {
 | |
| 	memcpy(rxbuf + rx_offs - data_read, buf, len);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| static int tcp_stream_tx(struct tcp_stream *tcp, u32 tx_offs, void *buf, int maxlen)
 | |
| {
 | |
| 	/* by design: tx_offs >= tx_last_offs */
 | |
| 	if (tx_offs >= tx_last_offs + tx_last_len)
 | |
| 		return 0;
 | |
| 
 | |
| 	maxlen = tx_last_offs + tx_last_len - tx_offs;
 | |
| 	memcpy(buf, txbuf + (tx_offs - tx_last_offs), maxlen);
 | |
| 
 | |
| 	return maxlen;
 | |
| }
 | |
| 
 | |
| static int tcp_stream_on_create(struct tcp_stream *tcp)
 | |
| {
 | |
| 	if (tcp->lport != FASTBOOT_TCP_PORT)
 | |
| 		return 0;
 | |
| 
 | |
| 	data_read = 0;
 | |
| 	tx_last_offs = 0;
 | |
| 	tx_last_len = 0;
 | |
| 
 | |
| 	tcp->on_rcv_nxt_update = tcp_stream_on_rcv_nxt_update;
 | |
| 	tcp->rx = tcp_stream_rx;
 | |
| 	tcp->tx = tcp_stream_tx;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| void fastboot_tcp_start_server(void)
 | |
| {
 | |
| 	memset(net_server_ethaddr, 0, 6);
 | |
| 	tcp_stream_set_on_create_handler(tcp_stream_on_create);
 | |
| 
 | |
| 	printf("Using %s device\n", eth_get_name());
 | |
| 	printf("Listening for fastboot command on tcp %pI4\n", &net_ip);
 | |
| }
 |