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