F: doc/android/fastboot*.rst
F: include/fastboot.h
F: include/fastboot-internal.h
-F: include/net/fastboot.h
+F: include/net/fastboot_tcp.h
+F: include/net/fastboot_udp.h
F: drivers/fastboot/
F: drivers/usb/gadget/f_fastboot.c
-F: net/fastboot.c
+F: net/fastboot_tcp.c
+F: net/fastboot_udp.c
F: test/dm/fastboot.c
FPGA
return CMD_RET_FAILURE;
}
- err = net_loop(FASTBOOT);
+ err = net_loop(FASTBOOT_UDP);
if (err < 0) {
printf("fastboot udp error: %d\n", err);
return CMD_RET_SUCCESS;
}
+static int do_fastboot_tcp(int argc, char *const argv[],
+ uintptr_t buf_addr, size_t buf_size)
+{
+ int err;
+
+ if (!IS_ENABLED(CONFIG_TCP_FUNCTION_FASTBOOT)) {
+ pr_err("Fastboot TCP not enabled\n");
+ return CMD_RET_FAILURE;
+ }
+
+ err = net_loop(FASTBOOT_TCP);
+
+ if (err < 0) {
+ printf("fastboot tcp error: %d\n", err);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
static int do_fastboot_usb(int argc, char *const argv[],
uintptr_t buf_addr, size_t buf_size)
{
if (!strcmp(argv[1], "udp"))
return do_fastboot_udp(argc, argv, buf_addr, buf_size);
-
+ if (!strcmp(argv[1], "tcp"))
+ return do_fastboot_tcp(argc, argv, buf_addr, buf_size);
if (!strcmp(argv[1], "usb")) {
argv++;
argc--;
bool
imply ANDROID_BOOT_IMAGE
imply CMD_FASTBOOT
+ help
+ Fastboot is a protocol used in Android devices for
+ communicating between the device and a computer during
+ the bootloader stage. It allows the user to flash the
+ device firmware and unlock the bootloader.
+ More information about the protocol and usecases:
+ https://android.googlesource.com/platform/system/core/+/refs/heads/master/fastboot/
config USB_FUNCTION_FASTBOOT
bool "Enable USB fastboot gadget"
help
The fastboot protocol requires a UDP port number.
+config TCP_FUNCTION_FASTBOOT
+ depends on NET
+ select FASTBOOT
+ bool "Enable fastboot protocol over TCP"
+ help
+ This enables the fastboot protocol over TCP.
+
if FASTBOOT
config FASTBOOT_BUF_ADDR
#include <command.h>
#include <env.h>
#include <fastboot.h>
-#include <net/fastboot.h>
/**
* fastboot_buf_addr - base address of the fastboot download buffer
enum proto_t {
BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP,
- NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET
+ NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP,
+ WOL, UDP, NCSI, WGET
};
extern char net_boot_file_name[1024];/* Boot File name */
+++ /dev/null
-/* SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (C) 2016 The Android Open Source Project
- */
-
-#ifndef __NET_FASTBOOT_H__
-#define __NET_FASTBOOT_H__
-
-/**********************************************************************/
-/*
- * Global functions and variables.
- */
-
-/**
- * Wait for incoming fastboot comands.
- */
-void fastboot_start_server(void);
-
-/**********************************************************************/
-
-#endif /* __NET_FASTBOOT_H__ */
--- /dev/null
+/* SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2023 The Android Open Source Project
+ */
+
+#ifndef __NET_FASTBOOT_TCP_H__
+#define __NET_FASTBOOT_TCP_H__
+
+/**
+ * Wait for incoming tcp fastboot comands.
+ */
+void fastboot_tcp_start_server(void);
+
+#endif /* __NET_FASTBOOT_TCP_H__ */
--- /dev/null
+/* SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#ifndef __NET_FASTBOOT_H__
+#define __NET_FASTBOOT_H__
+
+/**
+ * Wait for incoming UDP fastboot comands.
+ */
+void fastboot_udp_start_server(void);
+
+#endif /* __NET_FASTBOOT_H__ */
obj-$(CONFIG_CMD_RARP) += rarp.o
obj-$(CONFIG_CMD_SNTP) += sntp.o
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
-obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o
+obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot_udp.o
+obj-$(CONFIG_TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o
obj-$(CONFIG_CMD_WOL) += wol.o
obj-$(CONFIG_PROT_UDP) += udp.o
obj-$(CONFIG_PROT_TCP) += tcp.o
--- /dev/null
+// 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)
+{
+ 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_handle_command(command, response);
+ fastboot_tcp_send_message(response, strlen(response));
+ }
+ 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);
+}
#include <command.h>
#include <fastboot.h>
#include <net.h>
-#include <net/fastboot.h>
+#include <net/fastboot_udp.h>
enum {
FASTBOOT_ERROR = 0,
}
}
-void fastboot_start_server(void)
+void fastboot_udp_start_server(void)
{
printf("Using %s device\n", eth_get_name());
printf("Listening for fastboot command on %pI4\n", &net_ip);
#include <net.h>
#include <net6.h>
#include <ndisc.h>
-#include <net/fastboot.h>
+#include <net/fastboot_udp.h>
+#include <net/fastboot_tcp.h>
#include <net/tftp.h>
#include <net/ncsi.h>
#if defined(CONFIG_CMD_PCAP)
tftp_start_server();
break;
#endif
-#ifdef CONFIG_UDP_FUNCTION_FASTBOOT
- case FASTBOOT:
- fastboot_start_server();
+#if defined(CONFIG_UDP_FUNCTION_FASTBOOT)
+ case FASTBOOT_UDP:
+ fastboot_udp_start_server();
+ break;
+#endif
+#if defined(CONFIG_TCP_FUNCTION_FASTBOOT)
+ case FASTBOOT_TCP:
+ fastboot_tcp_start_server();
break;
#endif
#if defined(CONFIG_CMD_DHCP)
/* Fall through */
case NETCONS:
- case FASTBOOT:
+ case FASTBOOT_UDP:
+ case FASTBOOT_TCP:
case TFTPSRV:
if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
if (!memcmp(&net_link_local_ip6, &net_null_addr_ip6,