Home | History | Annotate | Download | only in net
      1 // SPDX-License-Identifier: BSD-2-Clause
      2 /*
      3  * Copyright (C) 2016 The Android Open Source Project
      4  */
      5 
      6 #include <common.h>
      7 #include <fastboot.h>
      8 #include <net.h>
      9 #include <net/fastboot.h>
     10 
     11 /* Fastboot port # defined in spec */
     12 #define WELL_KNOWN_PORT 5554
     13 
     14 enum {
     15 	FASTBOOT_ERROR = 0,
     16 	FASTBOOT_QUERY = 1,
     17 	FASTBOOT_INIT = 2,
     18 	FASTBOOT_FASTBOOT = 3,
     19 };
     20 
     21 struct __packed fastboot_header {
     22 	uchar id;
     23 	uchar flags;
     24 	unsigned short seq;
     25 };
     26 
     27 #define PACKET_SIZE 1024
     28 #define DATA_SIZE (PACKET_SIZE - sizeof(struct fastboot_header))
     29 
     30 /* Sequence number sent for every packet */
     31 static unsigned short sequence_number = 1;
     32 static const unsigned short packet_size = PACKET_SIZE;
     33 static const unsigned short udp_version = 1;
     34 
     35 /* Keep track of last packet for resubmission */
     36 static uchar last_packet[PACKET_SIZE];
     37 static unsigned int last_packet_len;
     38 
     39 static struct in_addr fastboot_remote_ip;
     40 /* The UDP port at their end */
     41 static int fastboot_remote_port;
     42 /* The UDP port at our end */
     43 static int fastboot_our_port;
     44 
     45 static void boot_downloaded_image(void);
     46 
     47 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
     48 /**
     49  * fastboot_udp_send_info() - Send an INFO packet during long commands.
     50  *
     51  * @msg: String describing the reason for waiting
     52  */
     53 static void fastboot_udp_send_info(const char *msg)
     54 {
     55 	uchar *packet;
     56 	uchar *packet_base;
     57 	int len = 0;
     58 	char response[FASTBOOT_RESPONSE_LEN] = {0};
     59 
     60 	struct fastboot_header response_header = {
     61 		.id = FASTBOOT_FASTBOOT,
     62 		.flags = 0,
     63 		.seq = htons(sequence_number)
     64 	};
     65 	++sequence_number;
     66 	packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
     67 	packet_base = packet;
     68 
     69 	/* Write headers */
     70 	memcpy(packet, &response_header, sizeof(response_header));
     71 	packet += sizeof(response_header);
     72 	/* Write response */
     73 	fastboot_response("INFO", response, "%s", msg);
     74 	memcpy(packet, response, strlen(response));
     75 	packet += strlen(response);
     76 
     77 	len = packet - packet_base;
     78 
     79 	/* Save packet for retransmitting */
     80 	last_packet_len = len;
     81 	memcpy(last_packet, packet_base, last_packet_len);
     82 
     83 	net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
     84 			    fastboot_remote_port, fastboot_our_port, len);
     85 }
     86 
     87 /**
     88  * fastboot_timed_send_info() - Send INFO packet every 30 seconds
     89  *
     90  * @msg: String describing the reason for waiting
     91  *
     92  * Send an INFO packet during long commands based on timer. An INFO packet
     93  * is sent if the time is 30 seconds after start. Else, noop.
     94  */
     95 static void fastboot_timed_send_info(const char *msg)
     96 {
     97 	static ulong start;
     98 
     99 	/* Initialize timer */
    100 	if (start == 0)
    101 		start = get_timer(0);
    102 	ulong time = get_timer(start);
    103 	/* Send INFO packet to host every 30 seconds */
    104 	if (time >= 30000) {
    105 		start = get_timer(0);
    106 		fastboot_udp_send_info(msg);
    107 	}
    108 }
    109 #endif
    110 
    111 /**
    112  * fastboot_send() - Sends a packet in response to received fastboot packet
    113  *
    114  * @header: Header for response packet
    115  * @fastboot_data: Pointer to received fastboot data
    116  * @fastboot_data_len: Length of received fastboot data
    117  * @retransmit: Nonzero if sending last sent packet
    118  */
    119 static void fastboot_send(struct fastboot_header header, char *fastboot_data,
    120 			  unsigned int fastboot_data_len, uchar retransmit)
    121 {
    122 	uchar *packet;
    123 	uchar *packet_base;
    124 	int len = 0;
    125 	const char *error_msg = "An error occurred.";
    126 	short tmp;
    127 	struct fastboot_header response_header = header;
    128 	static char command[FASTBOOT_COMMAND_LEN];
    129 	static int cmd = -1;
    130 	static bool pending_command;
    131 	char response[FASTBOOT_RESPONSE_LEN] = {0};
    132 
    133 	/*
    134 	 * We will always be sending some sort of packet, so
    135 	 * cobble together the packet headers now.
    136 	 */
    137 	packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
    138 	packet_base = packet;
    139 
    140 	/* Resend last packet */
    141 	if (retransmit) {
    142 		memcpy(packet, last_packet, last_packet_len);
    143 		net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
    144 				    fastboot_remote_port, fastboot_our_port,
    145 				    last_packet_len);
    146 		return;
    147 	}
    148 
    149 	response_header.seq = htons(response_header.seq);
    150 	memcpy(packet, &response_header, sizeof(response_header));
    151 	packet += sizeof(response_header);
    152 
    153 	switch (header.id) {
    154 	case FASTBOOT_QUERY:
    155 		tmp = htons(sequence_number);
    156 		memcpy(packet, &tmp, sizeof(tmp));
    157 		packet += sizeof(tmp);
    158 		break;
    159 	case FASTBOOT_INIT:
    160 		tmp = htons(udp_version);
    161 		memcpy(packet, &tmp, sizeof(tmp));
    162 		packet += sizeof(tmp);
    163 		tmp = htons(packet_size);
    164 		memcpy(packet, &tmp, sizeof(tmp));
    165 		packet += sizeof(tmp);
    166 		break;
    167 	case FASTBOOT_ERROR:
    168 		memcpy(packet, error_msg, strlen(error_msg));
    169 		packet += strlen(error_msg);
    170 		break;
    171 	case FASTBOOT_FASTBOOT:
    172 		if (cmd == FASTBOOT_COMMAND_DOWNLOAD) {
    173 			if (!fastboot_data_len && !fastboot_data_remaining()) {
    174 				fastboot_data_complete(response);
    175 			} else {
    176 				fastboot_data_download(fastboot_data,
    177 						       fastboot_data_len,
    178 						       response);
    179 			}
    180 		} else if (!pending_command) {
    181 			strlcpy(command, fastboot_data,
    182 				min((size_t)fastboot_data_len + 1,
    183 				    sizeof(command)));
    184 			pending_command = true;
    185 		} else {
    186 			cmd = fastboot_handle_command(command, response);
    187 			pending_command = false;
    188 		}
    189 		/*
    190 		 * Sent some INFO packets, need to update sequence number in
    191 		 * header
    192 		 */
    193 		if (header.seq != sequence_number) {
    194 			response_header.seq = htons(sequence_number);
    195 			memcpy(packet_base, &response_header,
    196 			       sizeof(response_header));
    197 		}
    198 		/* Write response to packet */
    199 		memcpy(packet, response, strlen(response));
    200 		packet += strlen(response);
    201 		break;
    202 	default:
    203 		pr_err("ID %d not implemented.\n", header.id);
    204 		return;
    205 	}
    206 
    207 	len = packet - packet_base;
    208 
    209 	/* Save packet for retransmitting */
    210 	last_packet_len = len;
    211 	memcpy(last_packet, packet_base, last_packet_len);
    212 
    213 	net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
    214 			    fastboot_remote_port, fastboot_our_port, len);
    215 
    216 	/* Continue boot process after sending response */
    217 	if (!strncmp("OKAY", response, 4)) {
    218 		switch (cmd) {
    219 		case FASTBOOT_COMMAND_BOOT:
    220 			boot_downloaded_image();
    221 			break;
    222 
    223 		case FASTBOOT_COMMAND_CONTINUE:
    224 			net_set_state(NETLOOP_SUCCESS);
    225 			break;
    226 
    227 		case FASTBOOT_COMMAND_REBOOT:
    228 		case FASTBOOT_COMMAND_REBOOT_BOOTLOADER:
    229 			do_reset(NULL, 0, 0, NULL);
    230 			break;
    231 		}
    232 	}
    233 
    234 	if (!strncmp("OKAY", response, 4) || !strncmp("FAIL", response, 4))
    235 		cmd = -1;
    236 }
    237 
    238 /**
    239  * boot_downloaded_image() - Boots into downloaded image.
    240  */
    241 static void boot_downloaded_image(void)
    242 {
    243 	fastboot_boot();
    244 	net_set_state(NETLOOP_SUCCESS);
    245 }
    246 
    247 /**
    248  * fastboot_handler() - Incoming UDP packet handler.
    249  *
    250  * @packet: Pointer to incoming UDP packet
    251  * @dport: Destination UDP port
    252  * @sip: Source IP address
    253  * @sport: Source UDP port
    254  * @len: Packet length
    255  */
    256 static void fastboot_handler(uchar *packet, unsigned int dport,
    257 			     struct in_addr sip, unsigned int sport,
    258 			     unsigned int len)
    259 {
    260 	struct fastboot_header header;
    261 	char fastboot_data[DATA_SIZE] = {0};
    262 	unsigned int fastboot_data_len = 0;
    263 
    264 	if (dport != fastboot_our_port)
    265 		return;
    266 
    267 	fastboot_remote_ip = sip;
    268 	fastboot_remote_port = sport;
    269 
    270 	if (len < sizeof(struct fastboot_header) || len > PACKET_SIZE)
    271 		return;
    272 	memcpy(&header, packet, sizeof(header));
    273 	header.flags = 0;
    274 	header.seq = ntohs(header.seq);
    275 	packet += sizeof(header);
    276 	len -= sizeof(header);
    277 
    278 	switch (header.id) {
    279 	case FASTBOOT_QUERY:
    280 		fastboot_send(header, fastboot_data, 0, 0);
    281 		break;
    282 	case FASTBOOT_INIT:
    283 	case FASTBOOT_FASTBOOT:
    284 		fastboot_data_len = len;
    285 		if (len > 0)
    286 			memcpy(fastboot_data, packet, len);
    287 		if (header.seq == sequence_number) {
    288 			fastboot_send(header, fastboot_data,
    289 				      fastboot_data_len, 0);
    290 			sequence_number++;
    291 		} else if (header.seq == sequence_number - 1) {
    292 			/* Retransmit last sent packet */
    293 			fastboot_send(header, fastboot_data,
    294 				      fastboot_data_len, 1);
    295 		}
    296 		break;
    297 	default:
    298 		pr_err("ID %d not implemented.\n", header.id);
    299 		header.id = FASTBOOT_ERROR;
    300 		fastboot_send(header, fastboot_data, 0, 0);
    301 		break;
    302 	}
    303 }
    304 
    305 void fastboot_start_server(void)
    306 {
    307 	printf("Using %s device\n", eth_get_name());
    308 	printf("Listening for fastboot command on %pI4\n", &net_ip);
    309 
    310 	fastboot_our_port = WELL_KNOWN_PORT;
    311 
    312 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
    313 	fastboot_set_progress_callback(fastboot_timed_send_info);
    314 #endif
    315 	net_set_udp_handler(fastboot_handler);
    316 
    317 	/* zero out server ether in case the server ip has changed */
    318 	memset(net_server_ethaddr, 0, 6);
    319 }
    320