Add support for fastboot command over UDP
The Raspberry Pi does not support USB device mode, so fastboot over
USB does not work. This patch adds support for and partially
implements the device side fastboot UDP protocol as a U-boot command.
It requires an ip address set and ethernet initialized.
- Modify U-boot fastboot command to do fastboot over UDP
- Add net/fastboot.c, which implements fastboot server functions
- Handle QUERY and INIT fastboot packets
- Add CONFIG_UDP_FUNCION_FASTBOOT to enable fastboot over UDP
Bug: 31887729
Test: Tested with fastboot, responds correctly to query and init
packets.
Change-Id: I4045abaf7a4455d756b7c1c00215afaa90c70a6e
This commit is contained in:
parent
83a51ebaaa
commit
965eda410b
|
|
@ -11,18 +11,37 @@
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
#include <g_dnl.h>
|
#include <g_dnl.h>
|
||||||
|
#include <net.h>
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
|
||||||
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_USB_FUNCTION_FASTBOOT
|
||||||
int controller_index;
|
int controller_index;
|
||||||
char *usb_controller;
|
char *usb_controller;
|
||||||
int ret;
|
int ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
usb_controller = argv[1];
|
if (!strcmp(argv[1], "udp")) {
|
||||||
|
#ifndef CONFIG_UDP_FUNCTION_FASTBOOT
|
||||||
|
error("Fastboot UDP not enabled\n");
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
return do_fastboot_udp(cmdtp, flag, argc, argv);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "usb") || argc < 3)
|
||||||
|
return CMD_RET_USAGE;
|
||||||
|
|
||||||
|
#ifndef CONFIG_USB_FUNCTION_FASTBOOT
|
||||||
|
error("Fastboot USB not enabled\n");
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
usb_controller = argv[2];
|
||||||
controller_index = simple_strtoul(usb_controller, NULL, 0);
|
controller_index = simple_strtoul(usb_controller, NULL, 0);
|
||||||
|
|
||||||
ret = board_usb_init(controller_index, USB_INIT_DEVICE);
|
ret = board_usb_init(controller_index, USB_INIT_DEVICE);
|
||||||
|
|
@ -59,11 +78,14 @@ exit:
|
||||||
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
|
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
U_BOOT_CMD(
|
U_BOOT_CMD(
|
||||||
fastboot, 2, 1, do_fastboot,
|
fastboot, 3, 1, do_fastboot,
|
||||||
"use USB Fastboot protocol",
|
"use USB or UDP Fastboot protocol",
|
||||||
"<USB_controller>\n"
|
"[usb,udp] <USB_controller>\n"
|
||||||
" - run as a fastboot usb device"
|
" - run as a fastboot usb or udp device\n"
|
||||||
|
" usb: specify <USB_controller>\n"
|
||||||
|
" udp: requires ip_addr set and ethernet initialized\n"
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,25 @@ config USB_FUNCTION_FASTBOOT
|
||||||
help
|
help
|
||||||
This enables the USB part of the fastboot gadget.
|
This enables the USB part of the fastboot gadget.
|
||||||
|
|
||||||
|
config UDP_FUNCTION_FASTBOOT
|
||||||
|
select NET
|
||||||
|
bool "Enable fastboot protocol over UDP"
|
||||||
|
help
|
||||||
|
This enables the fastboot protocol over UDP.
|
||||||
|
|
||||||
config CMD_FASTBOOT
|
config CMD_FASTBOOT
|
||||||
bool "Enable FASTBOOT command"
|
bool "Enable FASTBOOT command"
|
||||||
|
depends on USB_FUNCTION_FASTBOOT || UDP_FUNCTION_FASTBOOT
|
||||||
help
|
help
|
||||||
This enables the command "fastboot" which enables the Android
|
This enables the command "fastboot" which enables the Android
|
||||||
fastboot mode for the platform's USB device. Fastboot is a USB
|
fastboot mode for the platform. Fastboot is a protocol for
|
||||||
protocol for downloading images, flashing and device control
|
downloading images, flashing and device control used on
|
||||||
used on Android devices.
|
Android devices. Fastboot requires either network stack
|
||||||
|
enabled or support for acting as a USB device.
|
||||||
|
|
||||||
See doc/README.android-fastboot for more information.
|
See doc/README.android-fastboot for more information.
|
||||||
|
|
||||||
if USB_FUNCTION_FASTBOOT
|
if USB_FUNCTION_FASTBOOT || UDP_FUNCTION_FASTBOOT
|
||||||
|
|
||||||
config FASTBOOT_BUF_ADDR
|
config FASTBOOT_BUF_ADDR
|
||||||
hex "Define FASTBOOT buffer address"
|
hex "Define FASTBOOT buffer address"
|
||||||
|
|
@ -74,29 +82,6 @@ config FASTBOOT_FLASH_MMC_DEV
|
||||||
regarding the non-volatile storage device. Define this to
|
regarding the non-volatile storage device. Define this to
|
||||||
the eMMC device that fastboot should use to store the image.
|
the eMMC device that fastboot should use to store the image.
|
||||||
|
|
||||||
config FASTBOOT_GPT_NAME
|
endif # USB_FUNCTION_FASTBOOT || UDP_FUNCTION_FASTBOOT
|
||||||
string "Target name for updating GPT"
|
|
||||||
depends on FASTBOOT_FLASH
|
|
||||||
default "gpt"
|
|
||||||
help
|
|
||||||
The fastboot "flash" command supports writing the downloaded
|
|
||||||
image to the Protective MBR and the Primary GUID Partition
|
|
||||||
Table. (Additionally, this downloaded image is post-processed
|
|
||||||
to generate and write the Backup GUID Partition Table.)
|
|
||||||
This occurs when the specified "partition name" on the
|
|
||||||
"fastboot flash" command line matches the value defined here.
|
|
||||||
The default target name for updating GPT is "gpt".
|
|
||||||
|
|
||||||
config FASTBOOT_MBR_NAME
|
|
||||||
string "Target name for updating MBR"
|
|
||||||
depends on FASTBOOT_FLASH
|
|
||||||
default "mbr"
|
|
||||||
help
|
|
||||||
The fastboot "flash" command allows to write the downloaded image
|
|
||||||
to the Master Boot Record. This occurs when the "partition name"
|
|
||||||
specified on the "fastboot flash" command line matches the value
|
|
||||||
defined here. The default target name for updating MBR is "mbr".
|
|
||||||
|
|
||||||
endif # USB_FUNCTION_FASTBOOT
|
|
||||||
|
|
||||||
endif # FASTBOOT
|
endif # FASTBOOT
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,12 @@ U_BOOT_CMD(
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_UDP_FUNCTION_FASTBOOT
|
||||||
|
int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
return netboot_common(FASTBOOT, cmdtp, argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CMD_RARP
|
#ifdef CONFIG_CMD_RARP
|
||||||
int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
|
|
|
||||||
|
|
@ -538,7 +538,7 @@ extern int net_restart_wrap; /* Tried all network devices */
|
||||||
|
|
||||||
enum proto_t {
|
enum proto_t {
|
||||||
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
|
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
|
||||||
TFTPSRV, TFTPPUT, LINKLOCAL
|
TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT
|
||||||
};
|
};
|
||||||
|
|
||||||
extern char net_boot_file_name[1024];/* Boot File name */
|
extern char net_boot_file_name[1024];/* Boot File name */
|
||||||
|
|
@ -552,6 +552,10 @@ extern char *net_dns_resolve; /* The host to resolve */
|
||||||
extern char *net_dns_env_var; /* the env var to put the ip into */
|
extern char *net_dns_env_var; /* the env var to put the ip into */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_UDP_FUNCTION_FASTBOOT)
|
||||||
|
int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_CMD_PING)
|
#if defined(CONFIG_CMD_PING)
|
||||||
extern struct in_addr net_ping_ip; /* the ip address to ping */
|
extern struct in_addr net_ping_ip; /* the ip address to ping */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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__ */
|
||||||
|
|
@ -30,3 +30,4 @@ obj-$(CONFIG_CMD_NET) += tftp.o
|
||||||
# sprintf(buf, index ? "foo%d" : "foo", index)
|
# sprintf(buf, index ? "foo%d" : "foo", index)
|
||||||
# and this is intentional usage.
|
# and this is intentional usage.
|
||||||
CFLAGS_eth_common.o += -Wno-format-extra-args
|
CFLAGS_eth_common.o += -Wno-format-extra-args
|
||||||
|
obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <net/fastboot.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <version.h>
|
||||||
|
|
||||||
|
/* Fastboot port # defined in spec */
|
||||||
|
#define WELL_KNOWN_PORT 5554
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FASTBOOT_ERROR = 0,
|
||||||
|
FASTBOOT_QUERY = 1,
|
||||||
|
FASTBOOT_INIT = 2,
|
||||||
|
FASTBOOT_FASTBOOT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((packed)) fastboot_header {
|
||||||
|
uchar id;
|
||||||
|
uchar flags;
|
||||||
|
unsigned short seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PACKET_SIZE 1024
|
||||||
|
#define FASTBOOT_HEADER_SIZE sizeof(struct fastboot_header)
|
||||||
|
|
||||||
|
/* Sequence number sent for every packet */
|
||||||
|
static unsigned short fb_sequence_number = 1;
|
||||||
|
static const unsigned short fb_packet_size = PACKET_SIZE;
|
||||||
|
static const unsigned short fb_udp_version = 1;
|
||||||
|
|
||||||
|
/* Keep track of last packet for resubmission */
|
||||||
|
static uchar last_packet[PACKET_SIZE];
|
||||||
|
static unsigned int last_packet_len = 0;
|
||||||
|
|
||||||
|
static struct in_addr fastboot_remote_ip;
|
||||||
|
/* The UDP port at their end */
|
||||||
|
static int fastboot_remote_port;
|
||||||
|
/* The UDP port at our end */
|
||||||
|
static int fastboot_our_port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs and sends a packet in response to received fastboot packet
|
||||||
|
*
|
||||||
|
* @param fb_header Header for response packet
|
||||||
|
* @param retransmit Nonzero if sending last sent packet
|
||||||
|
*/
|
||||||
|
static void fastboot_send(struct fastboot_header fb_header, uchar retransmit)
|
||||||
|
{
|
||||||
|
uchar *packet;
|
||||||
|
uchar *packet_base;
|
||||||
|
int len = 0;
|
||||||
|
const char *error_msg = "An error occurred.";
|
||||||
|
short tmp;
|
||||||
|
struct fastboot_header fb_response_header = fb_header;
|
||||||
|
/*
|
||||||
|
* We will always be sending some sort of packet, so
|
||||||
|
* cobble together the packet headers now.
|
||||||
|
*/
|
||||||
|
packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
|
||||||
|
packet_base = packet;
|
||||||
|
|
||||||
|
/* Resend last packet */
|
||||||
|
if (retransmit) {
|
||||||
|
memcpy(packet, last_packet, last_packet_len);
|
||||||
|
net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
|
||||||
|
fastboot_remote_port, fastboot_our_port, last_packet_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_response_header.seq = htons(fb_response_header.seq);
|
||||||
|
memcpy(packet, &fb_response_header, sizeof(fb_response_header));
|
||||||
|
packet += sizeof(fb_response_header);
|
||||||
|
|
||||||
|
switch (fb_header.id) {
|
||||||
|
case FASTBOOT_QUERY:
|
||||||
|
tmp = htons(fb_sequence_number);
|
||||||
|
memcpy(packet, &tmp, sizeof(tmp));
|
||||||
|
packet += sizeof(tmp);
|
||||||
|
break;
|
||||||
|
case FASTBOOT_INIT:
|
||||||
|
tmp = htons(fb_udp_version);
|
||||||
|
memcpy(packet, &tmp, sizeof(tmp));
|
||||||
|
packet += sizeof(tmp);
|
||||||
|
tmp = htons(fb_packet_size);
|
||||||
|
memcpy(packet, &tmp, sizeof(tmp));
|
||||||
|
packet += sizeof(tmp);
|
||||||
|
break;
|
||||||
|
case FASTBOOT_ERROR:
|
||||||
|
memcpy(packet, error_msg, strlen(error_msg));
|
||||||
|
packet += strlen(error_msg);
|
||||||
|
break;
|
||||||
|
case FASTBOOT_FASTBOOT:
|
||||||
|
default:
|
||||||
|
error("ID %d not implemented.\n", fb_header.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = packet-packet_base;
|
||||||
|
|
||||||
|
/* Save packet for retransmitting */
|
||||||
|
last_packet_len = len;
|
||||||
|
memcpy(last_packet, packet_base, last_packet_len);
|
||||||
|
|
||||||
|
net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
|
||||||
|
fastboot_remote_port, fastboot_our_port, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Incoming UDP packet handler.
|
||||||
|
*
|
||||||
|
* @param packet Pointer to incoming UDP packet
|
||||||
|
* @param dport Destination UDP port
|
||||||
|
* @param sip Source IP address
|
||||||
|
* @param sport Source UDP port
|
||||||
|
* @param len Packet length
|
||||||
|
*/
|
||||||
|
static void fastboot_handler(uchar *packet, unsigned dport, struct in_addr sip,
|
||||||
|
unsigned sport, unsigned len)
|
||||||
|
{
|
||||||
|
struct fastboot_header fb_header;
|
||||||
|
|
||||||
|
if (dport != fastboot_our_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fastboot_remote_ip = sip;
|
||||||
|
fastboot_remote_port = sport;
|
||||||
|
|
||||||
|
if (len < FASTBOOT_HEADER_SIZE || len > PACKET_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(&fb_header, packet, sizeof(fb_header));
|
||||||
|
fb_header.flags = 0;
|
||||||
|
fb_header.seq = ntohs(fb_header.seq);
|
||||||
|
packet += sizeof(fb_header);
|
||||||
|
len -= sizeof(fb_header);
|
||||||
|
|
||||||
|
switch (fb_header.id) {
|
||||||
|
case FASTBOOT_QUERY:
|
||||||
|
fastboot_send(fb_header, 0);
|
||||||
|
break;
|
||||||
|
case FASTBOOT_INIT:
|
||||||
|
if (fb_header.seq == fb_sequence_number) {
|
||||||
|
fastboot_send(fb_header, 0);
|
||||||
|
fb_sequence_number++;
|
||||||
|
} else if (fb_header.seq == fb_sequence_number - 1) {
|
||||||
|
/* Retransmit last sent packet */
|
||||||
|
fastboot_send(fb_header, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FASTBOOT_FASTBOOT:
|
||||||
|
default:
|
||||||
|
error("ID %d not implemented.\n", fb_header.id);
|
||||||
|
fb_header.id = FASTBOOT_ERROR;
|
||||||
|
fastboot_send(fb_header, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fastboot_start_server(void)
|
||||||
|
{
|
||||||
|
printf("Using %s device\n", eth_get_name());
|
||||||
|
printf("Listening for fastboot command on %pI4\n", &net_ip);
|
||||||
|
|
||||||
|
fastboot_our_port = WELL_KNOWN_PORT;
|
||||||
|
|
||||||
|
net_set_udp_handler(fastboot_handler);
|
||||||
|
|
||||||
|
/* zero out server ether in case the server ip has changed */
|
||||||
|
memset(net_server_ethaddr, 0, 6);
|
||||||
|
}
|
||||||
|
|
@ -87,6 +87,9 @@
|
||||||
#include <environment.h>
|
#include <environment.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#if defined(CONFIG_UDP_FUNCTION_FASTBOOT)
|
||||||
|
#include <net/fastboot.h>
|
||||||
|
#endif
|
||||||
#include <net/tftp.h>
|
#include <net/tftp.h>
|
||||||
#if defined(CONFIG_LED_STATUS)
|
#if defined(CONFIG_LED_STATUS)
|
||||||
#include <miiphy.h>
|
#include <miiphy.h>
|
||||||
|
|
@ -453,6 +456,11 @@ restart:
|
||||||
tftp_start_server();
|
tftp_start_server();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_UDP_FUNCTION_FASTBOOT
|
||||||
|
case FASTBOOT:
|
||||||
|
fastboot_start_server();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#if defined(CONFIG_CMD_DHCP)
|
#if defined(CONFIG_CMD_DHCP)
|
||||||
case DHCP:
|
case DHCP:
|
||||||
bootp_reset();
|
bootp_reset();
|
||||||
|
|
@ -1324,6 +1332,7 @@ common:
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
|
||||||
case NETCONS:
|
case NETCONS:
|
||||||
|
case FASTBOOT:
|
||||||
case TFTPSRV:
|
case TFTPSRV:
|
||||||
if (net_ip.s_addr == 0) {
|
if (net_ip.s_addr == 0) {
|
||||||
puts("*** ERROR: `ipaddr' not set\n");
|
puts("*** ERROR: `ipaddr' not set\n");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue