mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-14 00:44:35 +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>
118 lines
2.8 KiB
C
118 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);
|
|
}
|