1 // SPDX-License-Identifier: BSD-2-Clause
3 * Copyright (C) 2016 The Android Open Source Project
10 #include <net/fastboot_udp.h>
11 #include <linux/printk.h>
17 FASTBOOT_FASTBOOT
= 3,
20 struct __packed fastboot_header
{
26 #define PACKET_SIZE 1024
27 #define DATA_SIZE (PACKET_SIZE - sizeof(struct fastboot_header))
29 /* Sequence number sent for every packet */
30 static unsigned short sequence_number
= 1;
31 static const unsigned short packet_size
= PACKET_SIZE
;
32 static const unsigned short udp_version
= 1;
34 /* Keep track of last packet for resubmission */
35 static uchar last_packet
[PACKET_SIZE
];
36 static unsigned int last_packet_len
;
38 static struct in_addr fastboot_remote_ip
;
39 /* The UDP port at their end */
40 static int fastboot_remote_port
;
41 /* The UDP port at our end */
42 static int fastboot_our_port
;
45 * fastboot_udp_send_response() - Send an response into UDP
47 * @response: Response to send
49 static void fastboot_udp_send_response(const char *response
)
55 struct fastboot_header response_header
= {
56 .id
= FASTBOOT_FASTBOOT
,
58 .seq
= htons(sequence_number
)
61 packet
= net_tx_packet
+ net_eth_hdr_size() + IP_UDP_HDR_SIZE
;
65 memcpy(packet
, &response_header
, sizeof(response_header
));
66 packet
+= sizeof(response_header
);
68 memcpy(packet
, response
, strlen(response
));
69 packet
+= strlen(response
);
71 len
= packet
- packet_base
;
73 /* Save packet for retransmitting */
74 last_packet_len
= len
;
75 memcpy(last_packet
, packet_base
, last_packet_len
);
77 net_send_udp_packet(net_server_ethaddr
, fastboot_remote_ip
,
78 fastboot_remote_port
, fastboot_our_port
, len
);
82 * fastboot_timed_send_info() - Send INFO packet every 30 seconds
84 * @msg: String describing the reason for waiting
86 * Send an INFO packet during long commands based on timer. An INFO packet
87 * is sent if the time is 30 seconds after start. Else, noop.
89 static void fastboot_timed_send_info(const char *msg
)
92 char response
[FASTBOOT_RESPONSE_LEN
] = {0};
94 /* Initialize timer */
97 ulong time
= get_timer(start
);
98 /* Send INFO packet to host every 30 seconds */
100 start
= get_timer(0);
101 fastboot_response("INFO", response
, "%s", msg
);
102 fastboot_udp_send_response(response
);
107 * fastboot_send() - Sends a packet in response to received fastboot packet
109 * @header: Header for response packet
110 * @fastboot_data: Pointer to received fastboot data
111 * @fastboot_data_len: Length of received fastboot data
112 * @retransmit: Nonzero if sending last sent packet
114 static void fastboot_send(struct fastboot_header header
, char *fastboot_data
,
115 unsigned int fastboot_data_len
, uchar retransmit
)
120 const char *error_msg
= "An error occurred.";
122 struct fastboot_header response_header
= header
;
123 static char command
[FASTBOOT_COMMAND_LEN
];
125 static bool pending_command
;
126 char response
[FASTBOOT_RESPONSE_LEN
] = {0};
129 * We will always be sending some sort of packet, so
130 * cobble together the packet headers now.
132 packet
= net_tx_packet
+ net_eth_hdr_size() + IP_UDP_HDR_SIZE
;
133 packet_base
= packet
;
135 /* Resend last packet */
137 memcpy(packet
, last_packet
, last_packet_len
);
138 net_send_udp_packet(net_server_ethaddr
, fastboot_remote_ip
,
139 fastboot_remote_port
, fastboot_our_port
,
144 response_header
.seq
= htons(response_header
.seq
);
145 memcpy(packet
, &response_header
, sizeof(response_header
));
146 packet
+= sizeof(response_header
);
150 tmp
= htons(sequence_number
);
151 memcpy(packet
, &tmp
, sizeof(tmp
));
152 packet
+= sizeof(tmp
);
155 tmp
= htons(udp_version
);
156 memcpy(packet
, &tmp
, sizeof(tmp
));
157 packet
+= sizeof(tmp
);
158 tmp
= htons(packet_size
);
159 memcpy(packet
, &tmp
, sizeof(tmp
));
160 packet
+= sizeof(tmp
);
163 memcpy(packet
, error_msg
, strlen(error_msg
));
164 packet
+= strlen(error_msg
);
166 case FASTBOOT_FASTBOOT
:
167 if (cmd
== FASTBOOT_COMMAND_DOWNLOAD
) {
168 if (!fastboot_data_len
&& !fastboot_data_remaining()) {
169 fastboot_data_complete(response
);
171 fastboot_data_download(fastboot_data
,
175 } else if (!pending_command
) {
176 strlcpy(command
, fastboot_data
,
177 min((size_t)fastboot_data_len
+ 1,
179 pending_command
= true;
181 cmd
= fastboot_handle_command(command
, response
);
182 pending_command
= false;
184 if (!strncmp(FASTBOOT_MULTIRESPONSE_START
, response
, 4)) {
186 /* Call handler to obtain next response */
187 fastboot_multiresponse(cmd
, response
);
190 * Send more responses or break to send
191 * final OKAY/FAIL response
193 if (strncmp("OKAY", response
, 4) &&
194 strncmp("FAIL", response
, 4))
195 fastboot_udp_send_response(response
);
202 * Sent some INFO packets, need to update sequence number in
205 if (header
.seq
!= sequence_number
) {
206 response_header
.seq
= htons(sequence_number
);
207 memcpy(packet_base
, &response_header
,
208 sizeof(response_header
));
210 /* Write response to packet */
211 memcpy(packet
, response
, strlen(response
));
212 packet
+= strlen(response
);
215 pr_err("ID %d not implemented.\n", header
.id
);
219 len
= packet
- packet_base
;
221 /* Save packet for retransmitting */
222 last_packet_len
= len
;
223 memcpy(last_packet
, packet_base
, last_packet_len
);
225 net_send_udp_packet(net_server_ethaddr
, fastboot_remote_ip
,
226 fastboot_remote_port
, fastboot_our_port
, len
);
228 fastboot_handle_boot(cmd
, strncmp("OKAY", response
, 4) == 0);
230 if (!strncmp("OKAY", response
, 4) || !strncmp("FAIL", response
, 4))
235 * fastboot_handler() - Incoming UDP packet handler.
237 * @packet: Pointer to incoming UDP packet
238 * @dport: Destination UDP port
239 * @sip: Source IP address
240 * @sport: Source UDP port
241 * @len: Packet length
243 static void fastboot_handler(uchar
*packet
, unsigned int dport
,
244 struct in_addr sip
, unsigned int sport
,
247 struct fastboot_header header
;
248 char fastboot_data
[DATA_SIZE
] = {0};
249 unsigned int fastboot_data_len
= 0;
251 if (dport
!= fastboot_our_port
)
254 fastboot_remote_ip
= sip
;
255 fastboot_remote_port
= sport
;
257 if (len
< sizeof(struct fastboot_header
) || len
> PACKET_SIZE
)
259 memcpy(&header
, packet
, sizeof(header
));
261 header
.seq
= ntohs(header
.seq
);
262 packet
+= sizeof(header
);
263 len
-= sizeof(header
);
267 fastboot_send(header
, fastboot_data
, 0, 0);
270 case FASTBOOT_FASTBOOT
:
271 fastboot_data_len
= len
;
273 memcpy(fastboot_data
, packet
, len
);
274 if (header
.seq
== sequence_number
) {
275 fastboot_send(header
, fastboot_data
,
276 fastboot_data_len
, 0);
278 } else if (header
.seq
== sequence_number
- 1) {
279 /* Retransmit last sent packet */
280 fastboot_send(header
, fastboot_data
,
281 fastboot_data_len
, 1);
285 pr_err("ID %d not implemented.\n", header
.id
);
286 header
.id
= FASTBOOT_ERROR
;
287 fastboot_send(header
, fastboot_data
, 0, 0);
292 void fastboot_udp_start_server(void)
294 printf("Using %s device\n", eth_get_name());
295 printf("Listening for fastboot command on %pI4\n", &net_ip
);
297 fastboot_our_port
= CONFIG_UDP_FUNCTION_FASTBOOT_PORT
;
299 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH
))
300 fastboot_set_progress_callback(fastboot_timed_send_info
);
302 net_set_udp_handler(fastboot_handler
);
304 /* zero out server ether in case the server ip has changed */
305 memset(net_server_ethaddr
, 0, 6);