blob: 3ea25c997fcc3daf49d4602724cf16c9f76e041f [file] [log] [blame]
Dmitrii Merkurev308252d2023-04-12 19:49:30 +01001// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright (C) 2023 The Android Open Source Project
4 */
5
Dmitrii Merkurev308252d2023-04-12 19:49:30 +01006#include <fastboot.h>
7#include <net.h>
8#include <net/fastboot_tcp.h>
9#include <net/tcp.h>
10
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +030011#define FASTBOOT_TCP_PORT 5554
12
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010013static const unsigned short handshake_length = 4;
14static const uchar *handshake = "FB01";
15
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030016static char rxbuf[sizeof(u64) + FASTBOOT_COMMAND_LEN + 1];
17static char txbuf[sizeof(u64) + FASTBOOT_RESPONSE_LEN + 1];
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010018
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030019static u32 data_read;
20static u32 tx_last_offs, tx_last_len;
21
22static void tcp_stream_on_rcv_nxt_update(struct tcp_stream *tcp, u32 rx_bytes)
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010023{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030024 u64 cmd_size;
25 __be64 len_be;
26 char saved;
27 int fastboot_command_id, len;
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010028
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030029 if (!data_read && rx_bytes >= handshake_length) {
30 if (memcmp(rxbuf, handshake, handshake_length)) {
31 printf("fastboot: bad handshake\n");
32 tcp_stream_close(tcp);
33 return;
34 }
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010035
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030036 tx_last_offs = 0;
37 tx_last_len = handshake_length;
38 memcpy(txbuf, handshake, handshake_length);
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010039
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030040 data_read += handshake_length;
41 rx_bytes -= handshake_length;
42 if (rx_bytes > 0)
43 memmove(rxbuf, rxbuf + handshake_length, rx_bytes);
44 return;
45 }
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010046
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030047 if (rx_bytes < sizeof(u64))
48 return;
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010049
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030050 memcpy(&cmd_size, rxbuf, sizeof(u64));
51 cmd_size = __be64_to_cpu(cmd_size);
52 if (rx_bytes < sizeof(u64) + cmd_size)
53 return;
54
55 saved = rxbuf[sizeof(u64) + cmd_size];
56 rxbuf[sizeof(u64) + cmd_size] = '\0';
57 fastboot_command_id = fastboot_handle_command(rxbuf + sizeof(u64),
58 txbuf + sizeof(u64));
59 fastboot_handle_boot(fastboot_command_id,
60 strncmp("OKAY", txbuf + sizeof(u64), 4) != 0);
61 rxbuf[sizeof(u64) + cmd_size] = saved;
62
63 len = strlen(txbuf + sizeof(u64));
64 len_be = __cpu_to_be64(len);
65 memcpy(txbuf, &len_be, sizeof(u64));
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010066
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030067 tx_last_offs += tx_last_len;
68 tx_last_len = len + sizeof(u64);
69
70 data_read += sizeof(u64) + cmd_size;
71 rx_bytes -= sizeof(u64) + cmd_size;
72 if (rx_bytes > 0)
73 memmove(rxbuf, rxbuf + sizeof(u64) + cmd_size, rx_bytes);
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010074}
75
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030076static int tcp_stream_rx(struct tcp_stream *tcp, u32 rx_offs, void *buf, int len)
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010077{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030078 memcpy(rxbuf + rx_offs - data_read, buf, len);
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010079
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030080 return len;
81}
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010082
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030083static int tcp_stream_tx(struct tcp_stream *tcp, u32 tx_offs, void *buf, int maxlen)
84{
85 /* by design: tx_offs >= tx_last_offs */
86 if (tx_offs >= tx_last_offs + tx_last_len)
87 return 0;
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010088
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030089 maxlen = tx_last_offs + tx_last_len - tx_offs;
90 memcpy(buf, txbuf + (tx_offs - tx_last_offs), maxlen);
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010091
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030092 return maxlen;
Dmitrii Merkurev308252d2023-04-12 19:49:30 +010093}
94
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030095static int tcp_stream_on_create(struct tcp_stream *tcp)
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +030096{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030097 if (tcp->lport != FASTBOOT_TCP_PORT)
98 return 0;
99
100 data_read = 0;
101 tx_last_offs = 0;
102 tx_last_len = 0;
103
104 tcp->on_rcv_nxt_update = tcp_stream_on_rcv_nxt_update;
105 tcp->rx = tcp_stream_rx;
106 tcp->tx = tcp_stream_tx;
107
108 return 1;
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +0300109}
110
Dmitrii Merkurev308252d2023-04-12 19:49:30 +0100111void fastboot_tcp_start_server(void)
112{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300113 memset(net_server_ethaddr, 0, 6);
114 tcp_stream_set_on_create_handler(tcp_stream_on_create);
115
Dmitrii Merkurev308252d2023-04-12 19:49:30 +0100116 printf("Using %s device\n", eth_get_name());
117 printf("Listening for fastboot command on tcp %pI4\n", &net_ip);
Dmitrii Merkurev308252d2023-04-12 19:49:30 +0100118}