mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-09-03 04:51:35 +02:00
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"' I failed to notice that b4 noticed it was based on next and so took that as the base commit and merged that part of next to master. This reverts commit c8ffd1356d42223cbb8c86280a083cc3c93e6426, reversing changes made to 2ee6f3a5f7550de3599faef9704e166e5dcace35. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
147 lines
3.7 KiB
C
147 lines
3.7 KiB
C
// SPDX-License-Identifier: BSD-2-Clause
|
|
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <fastboot.h>
|
|
#include <net.h>
|
|
#include <net/fastboot_tcp.h>
|
|
#include <net/tcp.h>
|
|
|
|
static char command[FASTBOOT_COMMAND_LEN] = {0};
|
|
static char response[FASTBOOT_RESPONSE_LEN] = {0};
|
|
|
|
static const unsigned short handshake_length = 4;
|
|
static const uchar *handshake = "FB01";
|
|
|
|
static u16 curr_sport;
|
|
static u16 curr_dport;
|
|
static u32 curr_tcp_seq_num;
|
|
static u32 curr_tcp_ack_num;
|
|
static unsigned int curr_request_len;
|
|
static enum fastboot_tcp_state {
|
|
FASTBOOT_CLOSED,
|
|
FASTBOOT_CONNECTED,
|
|
FASTBOOT_DISCONNECTING
|
|
} state = FASTBOOT_CLOSED;
|
|
|
|
static void fastboot_tcp_answer(u8 action, unsigned int len)
|
|
{
|
|
const u32 response_seq_num = curr_tcp_ack_num;
|
|
const u32 response_ack_num = curr_tcp_seq_num +
|
|
(curr_request_len > 0 ? curr_request_len : 1);
|
|
|
|
net_send_tcp_packet(len, htons(curr_sport), htons(curr_dport),
|
|
action, response_seq_num, response_ack_num);
|
|
}
|
|
|
|
static void fastboot_tcp_reset(void)
|
|
{
|
|
fastboot_tcp_answer(TCP_RST, 0);
|
|
state = FASTBOOT_CLOSED;
|
|
}
|
|
|
|
static void fastboot_tcp_send_packet(u8 action, const uchar *data, unsigned int len)
|
|
{
|
|
uchar *pkt = net_get_async_tx_pkt_buf();
|
|
|
|
memset(pkt, '\0', PKTSIZE);
|
|
pkt += net_eth_hdr_size() + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
|
|
memcpy(pkt, data, len);
|
|
fastboot_tcp_answer(action, len);
|
|
memset(pkt, '\0', PKTSIZE);
|
|
}
|
|
|
|
static void fastboot_tcp_send_message(const char *message, unsigned int len)
|
|
{
|
|
__be64 len_be = __cpu_to_be64(len);
|
|
uchar *pkt = net_get_async_tx_pkt_buf();
|
|
|
|
memset(pkt, '\0', PKTSIZE);
|
|
pkt += net_eth_hdr_size() + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
|
|
// Put first 8 bytes as a big endian message length
|
|
memcpy(pkt, &len_be, 8);
|
|
pkt += 8;
|
|
memcpy(pkt, message, len);
|
|
fastboot_tcp_answer(TCP_ACK | TCP_PUSH, len + 8);
|
|
memset(pkt, '\0', PKTSIZE);
|
|
}
|
|
|
|
static void fastboot_tcp_handler_ipv4(uchar *pkt, u16 dport,
|
|
struct in_addr sip, u16 sport,
|
|
u32 tcp_seq_num, u32 tcp_ack_num,
|
|
u8 action, unsigned int len)
|
|
{
|
|
int fastboot_command_id;
|
|
u64 command_size;
|
|
u8 tcp_fin = action & TCP_FIN;
|
|
u8 tcp_push = action & TCP_PUSH;
|
|
|
|
curr_sport = sport;
|
|
curr_dport = dport;
|
|
curr_tcp_seq_num = tcp_seq_num;
|
|
curr_tcp_ack_num = tcp_ack_num;
|
|
curr_request_len = len;
|
|
|
|
switch (state) {
|
|
case FASTBOOT_CLOSED:
|
|
if (tcp_push) {
|
|
if (len != handshake_length ||
|
|
strlen(pkt) != handshake_length ||
|
|
memcmp(pkt, handshake, handshake_length) != 0) {
|
|
fastboot_tcp_reset();
|
|
break;
|
|
}
|
|
fastboot_tcp_send_packet(TCP_ACK | TCP_PUSH,
|
|
handshake, handshake_length);
|
|
state = FASTBOOT_CONNECTED;
|
|
}
|
|
break;
|
|
case FASTBOOT_CONNECTED:
|
|
if (tcp_fin) {
|
|
fastboot_tcp_answer(TCP_FIN | TCP_ACK, 0);
|
|
state = FASTBOOT_DISCONNECTING;
|
|
break;
|
|
}
|
|
if (tcp_push) {
|
|
// First 8 bytes is big endian message length
|
|
command_size = __be64_to_cpu(*(u64 *)pkt);
|
|
len -= 8;
|
|
pkt += 8;
|
|
|
|
// Only single packet messages are supported ATM
|
|
if (strlen(pkt) != command_size) {
|
|
fastboot_tcp_reset();
|
|
break;
|
|
}
|
|
strlcpy(command, pkt, len + 1);
|
|
fastboot_command_id = fastboot_handle_command(command, response);
|
|
fastboot_tcp_send_message(response, strlen(response));
|
|
fastboot_handle_boot(fastboot_command_id,
|
|
strncmp("OKAY", response, 4) == 0);
|
|
}
|
|
break;
|
|
case FASTBOOT_DISCONNECTING:
|
|
if (tcp_push)
|
|
state = FASTBOOT_CLOSED;
|
|
break;
|
|
}
|
|
|
|
memset(command, 0, FASTBOOT_COMMAND_LEN);
|
|
memset(response, 0, FASTBOOT_RESPONSE_LEN);
|
|
curr_sport = 0;
|
|
curr_dport = 0;
|
|
curr_tcp_seq_num = 0;
|
|
curr_tcp_ack_num = 0;
|
|
curr_request_len = 0;
|
|
}
|
|
|
|
void fastboot_tcp_start_server(void)
|
|
{
|
|
printf("Using %s device\n", eth_get_name());
|
|
printf("Listening for fastboot command on tcp %pI4\n", &net_ip);
|
|
|
|
tcp_set_tcp_handler(fastboot_tcp_handler_ipv4);
|
|
}
|