1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  */
5 
6 #include <command.h>
7 #include <fastboot.h>
8 #include <net.h>
9 #include <net/fastboot_udp.h>
10 #include <linux/printk.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_response() - Send an response into UDP
45  *
46  * @response: Response to send
47  */
fastboot_udp_send_response(const char * response)48 static void fastboot_udp_send_response(const char *response)
49 {
50 	uchar *packet;
51 	uchar *packet_base;
52 	int len = 0;
53 
54 	struct fastboot_header response_header = {
55 		.id = FASTBOOT_FASTBOOT,
56 		.flags = 0,
57 		.seq = htons(sequence_number)
58 	};
59 	++sequence_number;
60 	packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
61 	packet_base = packet;
62 
63 	/* Write headers */
64 	memcpy(packet, &response_header, sizeof(response_header));
65 	packet += sizeof(response_header);
66 	/* Write response */
67 	memcpy(packet, response, strlen(response));
68 	packet += strlen(response);
69 
70 	len = packet - packet_base;
71 
72 	/* Save packet for retransmitting */
73 	last_packet_len = len;
74 	memcpy(last_packet, packet_base, last_packet_len);
75 
76 	net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
77 			    fastboot_remote_port, fastboot_our_port, len);
78 }
79 
80 /**
81  * fastboot_timed_send_info() - Send INFO packet every 30 seconds
82  *
83  * @msg: String describing the reason for waiting
84  *
85  * Send an INFO packet during long commands based on timer. An INFO packet
86  * is sent if the time is 30 seconds after start. Else, noop.
87  */
fastboot_timed_send_info(const char * msg)88 static void fastboot_timed_send_info(const char *msg)
89 {
90 	static ulong start;
91 	char response[FASTBOOT_RESPONSE_LEN] = {0};
92 
93 	/* Initialize timer */
94 	if (start == 0)
95 		start = get_timer(0);
96 	ulong time = get_timer(start);
97 	/* Send INFO packet to host every 30 seconds */
98 	if (time >= 30000) {
99 		start = get_timer(0);
100 		fastboot_response("INFO", response, "%s", msg);
101 		fastboot_udp_send_response(response);
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 			if (!strncmp(FASTBOOT_MULTIRESPONSE_START, response, 4)) {
184 				while (1) {
185 					/* Call handler to obtain next response */
186 					fastboot_multiresponse(cmd, response);
187 
188 					/*
189 					 * Send more responses or break to send
190 					 * final OKAY/FAIL response
191 					 */
192 					if (strncmp("OKAY", response, 4) &&
193 					    strncmp("FAIL", response, 4))
194 						fastboot_udp_send_response(response);
195 					else
196 						break;
197 				}
198 			}
199 		}
200 		/*
201 		 * Sent some INFO packets, need to update sequence number in
202 		 * header
203 		 */
204 		if (header.seq != sequence_number) {
205 			response_header.seq = htons(sequence_number);
206 			memcpy(packet_base, &response_header,
207 			       sizeof(response_header));
208 		}
209 		/* Write response to packet */
210 		memcpy(packet, response, strlen(response));
211 		packet += strlen(response);
212 		break;
213 	default:
214 		pr_err("ID %d not implemented.\n", header.id);
215 		return;
216 	}
217 
218 	len = packet - packet_base;
219 
220 	/* Save packet for retransmitting */
221 	last_packet_len = len;
222 	memcpy(last_packet, packet_base, last_packet_len);
223 
224 	net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip,
225 			    fastboot_remote_port, fastboot_our_port, len);
226 
227 	fastboot_handle_boot(cmd, strncmp("OKAY", response, 4) == 0);
228 
229 	if (!strncmp("OKAY", response, 4) || !strncmp("FAIL", response, 4))
230 		cmd = -1;
231 }
232 
233 /**
234  * fastboot_handler() - Incoming UDP packet handler.
235  *
236  * @packet: Pointer to incoming UDP packet
237  * @dport: Destination UDP port
238  * @sip: Source IP address
239  * @sport: Source UDP port
240  * @len: Packet length
241  */
fastboot_handler(uchar * packet,unsigned int dport,struct in_addr sip,unsigned int sport,unsigned int len)242 static void fastboot_handler(uchar *packet, unsigned int dport,
243 			     struct in_addr sip, unsigned int sport,
244 			     unsigned int len)
245 {
246 	struct fastboot_header header;
247 	char fastboot_data[DATA_SIZE] = {0};
248 	unsigned int fastboot_data_len = 0;
249 
250 	if (dport != fastboot_our_port)
251 		return;
252 
253 	fastboot_remote_ip = sip;
254 	fastboot_remote_port = sport;
255 
256 	if (len < sizeof(struct fastboot_header) || len > PACKET_SIZE)
257 		return;
258 	memcpy(&header, packet, sizeof(header));
259 	header.flags = 0;
260 	header.seq = ntohs(header.seq);
261 	packet += sizeof(header);
262 	len -= sizeof(header);
263 
264 	switch (header.id) {
265 	case FASTBOOT_QUERY:
266 		fastboot_send(header, fastboot_data, 0, 0);
267 		break;
268 	case FASTBOOT_INIT:
269 	case FASTBOOT_FASTBOOT:
270 		fastboot_data_len = len;
271 		if (len > 0)
272 			memcpy(fastboot_data, packet, len);
273 		if (header.seq == sequence_number) {
274 			fastboot_send(header, fastboot_data,
275 				      fastboot_data_len, 0);
276 			sequence_number++;
277 		} else if (header.seq == sequence_number - 1) {
278 			/* Retransmit last sent packet */
279 			fastboot_send(header, fastboot_data,
280 				      fastboot_data_len, 1);
281 		}
282 		break;
283 	default:
284 		pr_err("ID %d not implemented.\n", header.id);
285 		header.id = FASTBOOT_ERROR;
286 		fastboot_send(header, fastboot_data, 0, 0);
287 		break;
288 	}
289 }
290 
fastboot_udp_start_server(void)291 void fastboot_udp_start_server(void)
292 {
293 	printf("Using %s device\n", eth_get_name());
294 	printf("Listening for fastboot command on %pI4\n", &net_ip);
295 
296 	fastboot_our_port = CONFIG_UDP_FUNCTION_FASTBOOT_PORT;
297 
298 	if (IS_ENABLED(CONFIG_FASTBOOT_FLASH))
299 		fastboot_set_progress_callback(fastboot_timed_send_info);
300 
301 	net_set_udp_handler(fastboot_handler);
302 
303 	/* zero out server ether in case the server ip has changed */
304 	memset(net_server_ethaddr, 0, 6);
305 }
306