1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This library provides APIs for receiving, processing and replying to fastboot commands. To use
16 //! the library:
17 //!
18 //! 1. Provide a transport backend by implementing the `Transport` trait.
19 //!
20 //! ```
21 //!
22 //! struct FastbootTransport {}
23 //!
24 //! impl Transport<MyErrorType> for TestTransport {
25 //!     fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError> {
26 //!         todo!();
27 //!     }
28 //!
29 //!     fn send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError> {
30 //!         todo!();
31 //!     }
32 //! }
33 //! ```
34 //!
35 //! 2. Provide a fastboot command backend by implementing the `FastbootImplementation` trait.
36 //!    i.e.
37 //!
38 //! ```
39 //!
40 //! struct FastbootCommand {}
41 //!
42 //! impl FastbootImplementation for FastbootTest {
43 //!     fn get_var(
44 //!         &mut self,
45 //!         var: &str,
46 //!         args: Split<char>,
47 //!         out: &mut [u8],
48 //!     ) -> Result<usize, CommandError> {
49 //!         todo!();
50 //!     }
51 //!
52 //!     ...
53 //! }
54 //!```
55 //!
56 //! 3. Construct a `Fastboot` object with a given download buffer. Pass the transport, command
57 //!    implementation and call the `run()` method:
58 //!
59 //! ```
60 //! let mut fastboot_impl: FastbootCommand = ...;
61 //! let mut transport: TestTransport = ...;
62 //! let download_buffer: &mut [u8] = ...;
63 //! let mut fastboot = Fastboot::new(&mut download_buffer[..]);
64 //! let result = fastboot.run(&mut transport, &mut fastboot_impl, &[]);
65 //! ```
66 
67 #![cfg_attr(not(test), no_std)]
68 
69 use core::fmt::{Debug, Display, Error, Formatter, Write};
70 use core::str::{from_utf8, Split};
71 
72 pub const MAX_COMMAND_SIZE: usize = 4096;
73 pub const MAX_RESPONSE_SIZE: usize = 256;
74 const OKAY: &'static str = "OKAY";
75 
76 /// Transport errors.
77 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
78 pub enum TransportError {
79     InvalidHanshake,
80     InvalidState,
81     PacketSizeOverflow,
82     PacketSizeExceedMaximum,
83     NotEnoughUpload,
84     Others(&'static str),
85 }
86 
87 impl Display for TransportError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>88     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
89         write!(f, "{:?}", self)
90     }
91 }
92 
93 /// Implementation for Fastboot transport interfaces.
94 pub trait Transport {
95     /// Fetches the next fastboot packet into `out`.
96     ///
97     /// Returns the actual size of the packet on success.
98     ///
99     /// TODO(b/322540167): In the future, we may want to support using `[MaybeUninit<u8>]` as the
100     /// download buffer to avoid expensive initialization at the beginning. This would require an
101     /// interface where the implementation provides the buffer for us to copy instead of us.
receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError>102     fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError>;
103 
104     /// Sends a fastboot packet.
105     ///
106     /// The method assumes `packet` is sent or at least copied to queue after it returns, where
107     /// the buffer can go out of scope without affecting anything.
send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError>108     fn send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError>;
109 }
110 
111 /// For now, we hardcode the expected version, until we need to distinguish between multiple
112 /// versions.
113 const TCP_HANDSHAKE_MESSAGE: &[u8] = b"FB01";
114 
115 /// A trait representing a TCP stream reader/writer. Fastboot over TCP has additional handshake
116 /// process and uses a length-prefixed wire message format. It is recommended that caller
117 /// implements this trait instead of `Transport`, and uses the API `Fastboot::run_tcp_session()`
118 /// to perform fastboot over TCP. It internally handles handshake and wire message parsing.
119 pub trait TcpStream {
120     /// Reads to `out` for exactly `out.len()` number bytes from the TCP connection.
read_exact(&mut self, out: &mut [u8]) -> Result<(), TransportError>121     fn read_exact(&mut self, out: &mut [u8]) -> Result<(), TransportError>;
122 
123     /// Sends exactly `data.len()` number bytes from `data` to the TCP connection.
write_exact(&mut self, data: &[u8]) -> Result<(), TransportError>124     fn write_exact(&mut self, data: &[u8]) -> Result<(), TransportError>;
125 }
126 
127 /// `TcpTransport` implements `Transport` with a `TcpStream` object.
128 pub struct TcpTransport<'a>(&'a mut dyn TcpStream);
129 
130 impl<'a> TcpTransport<'a> {
131     /// Creates an instance from a newly connected TcpStream and performs handshake.
new_and_handshake(tcp_stream: &'a mut dyn TcpStream) -> Result<Self, TransportError>132     pub fn new_and_handshake(tcp_stream: &'a mut dyn TcpStream) -> Result<Self, TransportError> {
133         let mut handshake = [0u8; 4];
134         tcp_stream.write_exact(TCP_HANDSHAKE_MESSAGE)?;
135         tcp_stream.read_exact(&mut handshake[..])?;
136         match handshake == *TCP_HANDSHAKE_MESSAGE {
137             true => Ok(Self(tcp_stream)),
138             _ => Err(TransportError::InvalidHanshake),
139         }
140     }
141 }
142 
143 impl Transport for TcpTransport<'_> {
receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError>144     fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError> {
145         let mut length_prefix = [0u8; 8];
146         self.0.read_exact(&mut length_prefix[..])?;
147         let packet_size: usize = u64::from_be_bytes(length_prefix)
148             .try_into()
149             .map_err(|_| TransportError::PacketSizeOverflow)?;
150         match out.len() < packet_size {
151             true => Err(TransportError::PacketSizeExceedMaximum),
152             _ => {
153                 self.0.read_exact(&mut out[..packet_size])?;
154                 Ok(packet_size)
155             }
156         }
157     }
158 
send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError>159     fn send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError> {
160         self.0.write_exact(
161             &mut u64::try_from(packet.len())
162                 .map_err(|_| TransportError::PacketSizeOverflow)?
163                 .to_be_bytes()[..],
164         )?;
165         self.0.write_exact(packet)
166     }
167 }
168 
169 const COMMAND_ERROR_LENGTH: usize = MAX_RESPONSE_SIZE - 4;
170 
171 /// `CommandError` is the return error type for methods in trait `FastbootImplementation` when
172 /// they fail. It will be converted into string and sent as fastboot error message "FAIL<string>".
173 ///
174 /// Any type that implements `Display` trait can be converted into it. However, because fastboot
175 /// response message is limited to `MAX_RESPONSE_SIZE`. If the final displayed string length
176 /// exceeds it, the rest of the content is ignored.
177 pub struct CommandError(FormattedBytes<[u8; COMMAND_ERROR_LENGTH]>);
178 
179 impl CommandError {
180     /// Converts to string.
to_str(&self) -> &str181     pub fn to_str(&self) -> &str {
182         from_utf8(&self.0 .0[..self.0 .1]).unwrap_or("")
183     }
184 }
185 
186 impl Debug for CommandError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>187     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
188         write!(f, "{}", self.to_str())
189     }
190 }
191 
192 impl<T: Display> From<T> for CommandError {
from(val: T) -> Self193     fn from(val: T) -> Self {
194         let mut res = CommandError(FormattedBytes([0u8; COMMAND_ERROR_LENGTH], 0));
195         write!(res.0, "{}", val).unwrap();
196         res
197     }
198 }
199 
200 /// Implementation for Fastboot command backends.
201 pub trait FastbootImplementation {
202     /// Backend for `fastboot getvar ...`
203     ///
204     /// Gets the value of a variable specified by name and configuration represented by list of
205     /// additional arguments in `args`.
206     ///
207     /// Variable `max-download-size`, `version` are reserved by the library.
208     ///
209     /// # Args
210     ///
211     /// * `var`: Name of the variable.
212     /// * `args`: Additional arguments.
213     /// * `out`: Output buffer for storing the variable value.
214     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
215     ///
216     /// TODO(b/322540167): Figure out other reserved variables.
get_var( &mut self, var: &str, args: Split<char>, out: &mut [u8], utils: &mut FastbootUtils, ) -> Result<usize, CommandError>217     fn get_var(
218         &mut self,
219         var: &str,
220         args: Split<char>,
221         out: &mut [u8],
222         utils: &mut FastbootUtils,
223     ) -> Result<usize, CommandError>;
224 
225     /// A helper API for getting the value of a fastboot variable and decoding it into string.
get_var_as_str<'s>( &mut self, var: &str, args: Split<char>, out: &'s mut [u8], utils: &mut FastbootUtils, ) -> Result<&'s str, CommandError>226     fn get_var_as_str<'s>(
227         &mut self,
228         var: &str,
229         args: Split<char>,
230         out: &'s mut [u8],
231         utils: &mut FastbootUtils,
232     ) -> Result<&'s str, CommandError> {
233         let size = self.get_var(var, args, out, utils)?;
234         Ok(from_utf8(out.get(..size).ok_or("Invalid variable size")?)
235             .map_err(|_| "Value is not string")?)
236     }
237 
238     /// Backend for `fastboot getvar all`.
239     ///
240     /// Iterates all combinations of fastboot variable, configurations and values that need to be
241     /// included in the response to `fastboot getvar all`.
242     ///
243     /// # Args
244     ///
245     /// * `f`: A closure that takes 3 arguments: 1. variable name, 2. an array of string
246     ///   arguments and 3. the corresponding variable value. Implementation should call this for
247     ///   all combinations that need to be returned for `fastboot getvar all`. If `f` returns
248     ///   error, the implementation should return it immediately. For example the following
249     ///   implementation:
250     ///
251     ///   fn get_var_all(&mut self, f: F, utils: &mut FastbootUtils) -> Result<(), CommandError> {
252     ///       f("partition-size", &["boot_a"], /* size string of boot_a */)?;
253     ///       f("partition-size", &["boot_b"], /* size string of boot_b */)?;
254     ///       f("partition-size", &["init_boot_a"], /* size string of init_boot_a */)?;
255     ///       f("partition-size", &["init_boot_b"], /* size string of init_boot_b */)?;
256     ///       Ok(())
257     ///   }
258     ///
259     ///   will generates the following outputs for `fastboot getvar all`:
260     ///
261     ///   ...
262     ///   (bootloader) partition-size:boot_a: <size of boot_a>
263     ///   (bootloader) partition-size:boot_b: <size of boot_b>
264     ///   (bootloader) partition-size:init_boot_a: <size of init_boot_a>
265     ///   (bootloader) partition-size:init_boot_b: <size of init_boot_b>
266     ///   ...
267     ///
268     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
269     ///
270     /// TODO(b/322540167): This and `get_var()` contain duplicated logic. Investigate if there can
271     /// be better solutions for doing the combination traversal.
get_var_all( &mut self, f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>, utils: &mut FastbootUtils, ) -> Result<(), CommandError>272     fn get_var_all(
273         &mut self,
274         f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>,
275         utils: &mut FastbootUtils,
276     ) -> Result<(), CommandError>;
277 
278     /// Backend for `fastboot flash ...`
279     ///
280     /// # Args
281     ///
282     /// * `part`: Name of the partition.
283     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
flash(&mut self, part: &str, utils: &mut FastbootUtils) -> Result<(), CommandError>284     fn flash(&mut self, part: &str, utils: &mut FastbootUtils) -> Result<(), CommandError>;
285 
286     /// Backend for `fastboot get_staged ...`
287     ///
288     /// # Args
289     ///
290     /// * `upload_builder`: An instance of `UploadBuilder` for initiating and uploading data. For
291     ///   example:
292     ///
293     ///   ```
294     ///   fn upload(
295     ///       &mut self,
296     ///       upload_builder: UploadBuilder,
297     ///       utils: &mut FastbootUtils,
298     ///   ) -> Result<(), CommandError> {
299     ///       // Sends a total of 1024 bytes data.
300     ///       let mut uploader = upload_builder.start(1024)?;
301     ///       // Can upload in multiple batches.
302     ///       uploader.upload(&utils.download_buffer[..512])?;
303     ///       uploader.upload(&utils.download_buffer[512..])?;
304     ///       Ok(())
305     ///   }
306     ///   ```
307     ///
308     ///   If implementation fails to upload enough, or attempts to upload more than expected data
309     ///   with `Uploader::upload()`, an error will be returned.
310     ///
311     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
upload( &mut self, upload_builder: UploadBuilder, utils: &mut FastbootUtils, ) -> Result<(), CommandError>312     fn upload(
313         &mut self,
314         upload_builder: UploadBuilder,
315         utils: &mut FastbootUtils,
316     ) -> Result<(), CommandError>;
317 
318     /// Backend for `fastboot fetch ...`
319     ///
320     /// # Args
321     ///
322     /// * `part`: The partition name.
323     /// * `offset`: The offset into the partition for upload.
324     /// * `size`: The number of bytes to upload.
325     /// * `upload_builder`: An instance of `UploadBuilder` for initiating and uploading data.
326     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
fetch( &mut self, part: &str, offset: u64, size: u64, upload_builder: UploadBuilder, utils: &mut FastbootUtils, ) -> Result<(), CommandError>327     fn fetch(
328         &mut self,
329         part: &str,
330         offset: u64,
331         size: u64,
332         upload_builder: UploadBuilder,
333         utils: &mut FastbootUtils,
334     ) -> Result<(), CommandError>;
335 
336     /// Backend for `fastboot oem ...`.
337     ///
338     /// # Args
339     ///
340     /// * `cmd`: The OEM command string that comes after "oem ".
341     /// * `utils`: A mutable reference to an instance of `FastbootUtils`.
342     /// * `res`: The response buffer. Upon success, implementation can use the buffer to
343     ///   construct a valid UTF8 string which will be sent as "OKAY<string>"
344     ///
345     /// # Returns
346     ///
347     /// On success, returns the portion of `res` used by the construction of string message.
oem<'a>( &mut self, cmd: &str, utils: &mut FastbootUtils, res: &'a mut [u8], ) -> Result<&'a [u8], CommandError>348     fn oem<'a>(
349         &mut self,
350         cmd: &str,
351         utils: &mut FastbootUtils,
352         res: &'a mut [u8],
353     ) -> Result<&'a [u8], CommandError>;
354 
355     // TODO(b/322540167): Add methods for other commands.
356 }
357 
358 /// An internal convenient macro helper for `fastboot_okay`, `fastboot_fail` and `fastboot_info`.
359 macro_rules! fastboot_msg {
360     ( $arr:expr, $msg_type:expr, $( $x:expr ),* $(,)? ) => {
361         {
362             let mut formatted_bytes = FormattedBytes::new(&mut $arr[..]);
363             write!(formatted_bytes, $msg_type).unwrap();
364             write!(formatted_bytes, $($x,)*).unwrap();
365             let size = formatted_bytes.size();
366             &mut $arr[..size]
367         }
368     };
369 }
370 
371 /// An internal convenient macro that constructs a formatted fastboot OKAY message.
372 macro_rules! fastboot_okay {
373     ( $arr:expr, $( $x:expr ),* ) => { fastboot_msg!($arr, "OKAY", $($x,)*) };
374 }
375 
376 /// An internal convenient macro that constructs a formatted fastboot FAIL message.
377 macro_rules! fastboot_fail {
378     ( $arr:expr, $( $x:expr ),* ) => { fastboot_msg!($arr, "FAIL", $($x,)*) };
379 }
380 
381 /// An internal convenient macro that constructs a formatted fastboot INFO message.
382 macro_rules! fastboot_info {
383     ( $arr:expr, $( $x:expr ),* ) => { fastboot_msg!($arr, "INFO", $($x,)*) };
384 }
385 
386 /// `FastbootInfoSender` defines a method for sending Fastboot INFO messages.
387 ///
388 /// The trait is for user to implement their mock `FastbootUtils` for testing implementation
389 /// of the `FastbootImplementation` trait.
390 pub trait FastbootInfoSend {
391     /// Sends a Fastboot "INFO<`msg`>" packet
send(&mut self, msg: &str) -> Result<(), CommandError>392     fn send(&mut self, msg: &str) -> Result<(), CommandError>;
393 }
394 
395 /// `FastbootUtils` contains download data/buffer and a `FastbootInfoSend` trait object for sending
396 /// Fastboot INFO messages. It can be used in the implementation of `FastbootImplementation`.
397 pub struct FastbootUtils<'a> {
398     // TODO(b/328784766): Consider using arrayvec crate or similar instead of passing download
399     // buffer and size separately.
400     // The total download buffer.
401     download_buffer: &'a mut [u8],
402     // Current downloaded data size.
403     download_data_size: &'a mut usize,
404     /// When available, a trait object `FastbootInfoSend` for sending Fastboot INFO messages.
405     fb_info: Option<&'a mut dyn FastbootInfoSend>,
406 }
407 
408 impl<'a> FastbootUtils<'a> {
409     /// Creates a new instance.
new( download_buffer: &'a mut [u8], download_data_size: &'a mut usize, fb_info: Option<&'a mut dyn FastbootInfoSend>, ) -> Self410     pub fn new(
411         download_buffer: &'a mut [u8],
412         download_data_size: &'a mut usize,
413         fb_info: Option<&'a mut dyn FastbootInfoSend>,
414     ) -> Self {
415         Self { download_buffer, download_data_size, fb_info }
416     }
417 
418     /// Returns the current downloaded data.
download_data(&mut self) -> &mut [u8]419     pub fn download_data(&mut self) -> &mut [u8] {
420         &mut self.download_buffer[..*self.download_data_size]
421     }
422 
423     /// Returns the entire download buffer and the size of the download data. The method assumes
424     /// that callers will modify the download buffer and therefore will no longer consider the
425     /// download data valid, i.e. future calls of FastbootUtils::download_data() will only return
426     /// an empty slice.
take_download_buffer(&mut self) -> (&mut [u8], usize)427     pub fn take_download_buffer(&mut self) -> (&mut [u8], usize) {
428         let download_data_size = *self.download_data_size;
429         *self.download_data_size = 0;
430         (self.download_buffer, download_data_size)
431     }
432 
433     /// Sends a Fastboot INFO message.
434     ///
435     /// Returns Ok(true) if successful, Ok(false) if INFO messages are not supported in the context
436     /// of the current command, error otherwise.
info_send(&mut self, msg: &str) -> Result<bool, CommandError>437     pub fn info_send(&mut self, msg: &str) -> Result<bool, CommandError> {
438         match self.fb_info {
439             Some(ref mut send) => send.send(msg).map(|_| true),
440             _ => Ok(false),
441         }
442     }
443 }
444 
445 /// `FastbootInfoSender` is an internal type that implements `FastbootInfoSend` with a `Transport`
446 /// trait object.
447 struct FastbootInfoSender<'a> {
448     transport: &'a mut dyn Transport,
449     transport_error: Result<(), TransportError>,
450 }
451 
452 impl<'a> FastbootInfoSender<'a> {
453     /// Creates an new instance
new(transport: &'a mut dyn Transport) -> Self454     fn new(transport: &'a mut dyn Transport) -> Self {
455         Self { transport: transport, transport_error: Ok(()) }
456     }
457 
458     /// Returns the `Self:;transport_error`.
transport_error(&self) -> Result<(), TransportError>459     fn transport_error(&self) -> Result<(), TransportError> {
460         self.transport_error
461     }
462 }
463 
464 impl FastbootInfoSend for FastbootInfoSender<'_> {
send(&mut self, msg: &str) -> Result<(), CommandError>465     fn send(&mut self, msg: &str) -> Result<(), CommandError> {
466         self.transport_error?;
467         let mut res = [0u8; MAX_RESPONSE_SIZE];
468         self.transport_error = self.transport.send_packet(fastboot_info!(res, "{}", msg));
469         Ok(self.transport_error?)
470     }
471 }
472 
473 /// `UploadBuilder` can be consumed to create an `Uploader` for sending data to the host during
474 /// handling of command `fastboot get_staged`.
475 pub struct UploadBuilder<'a> {
476     remaining: &'a mut u64,
477     // `send` sends a bytes array as fastboot packet.
478     send: &'a mut dyn FnMut(&[u8]) -> Result<(), CommandError>,
479 }
480 
481 impl<'a> UploadBuilder<'a> {
482     /// Consumes the builder to create an `Uploader` to start uploading data.
start(self, data_size: u64) -> Result<Uploader<'a>, CommandError>483     pub fn start(self, data_size: u64) -> Result<Uploader<'a>, CommandError> {
484         let mut res = [0u8; 16];
485         (self.send)(snprintf!(res, "DATA{:08x}", data_size).as_bytes())?;
486         *self.remaining = data_size;
487         Ok(Uploader { remaining: self.remaining, send: self.send })
488     }
489 }
490 
491 /// `UploadBuilder` provides APIs for sending data from the device in response to
492 /// `fastboot get_staged`
493 pub struct Uploader<'a> {
494     remaining: &'a mut u64,
495     send: &'a mut dyn FnMut(&[u8]) -> Result<(), CommandError>,
496 }
497 
498 impl<'a> Uploader<'a> {
499     /// Uploads data. Returns error if accumulative amount exceeds `data_size` passed to
500     /// `UploadBuilder::start()`.
upload(&mut self, data: &[u8]) -> Result<(), CommandError>501     pub fn upload(&mut self, data: &[u8]) -> Result<(), CommandError> {
502         *self.remaining = self
503             .remaining
504             .checked_sub(data.len().try_into().map_err(|_| "")?)
505             .ok_or::<CommandError>("".into())?;
506         (self.send)(data)
507     }
508 }
509 
510 /// A helper function that creates an `UploadBuilder` from a `Transport` and runs a closure with
511 /// it. The helper internally checks that the closure uploads enough data it specifies.
with_upload_builder<F, R>( transport: &mut impl Transport, mut f: F, ) -> Result<Result<R, CommandError>, TransportError> where F: FnMut(UploadBuilder) -> Result<R, CommandError>,512 fn with_upload_builder<F, R>(
513     transport: &mut impl Transport,
514     mut f: F,
515 ) -> Result<Result<R, CommandError>, TransportError>
516 where
517     F: FnMut(UploadBuilder) -> Result<R, CommandError>,
518 {
519     let mut transport_error = Ok(());
520     let mut remaining = 0u64;
521     let mut send = |data: &[u8]| -> Result<(), CommandError> {
522         transport_error?;
523         transport_error = transport.send_packet(data);
524         Ok(transport_error?)
525     };
526     let upload_builder = UploadBuilder { remaining: &mut remaining, send: &mut send };
527     let res = f(upload_builder);
528     transport_error?;
529     // Failing to upload enough data should be considered a transport error. Because the remote
530     // host will hang as long as the connection is still active.
531     match remaining > 0 {
532         true => Err(TransportError::NotEnoughUpload),
533         _ => Ok(res),
534     }
535 }
536 
537 pub mod test_utils {
538     use crate::{CommandError, UploadBuilder};
539 
540     /// Runs a closure with a mock uploader for user implementation to test
541     /// `FastbootImplementation::upload()`.
542     ///
543     /// The mock uploader simply uploads to a user provided buffer.
544     ///
545     /// Returns the total uploaded size and remaining size.
with_mock_upload_builder<F>(buffer: &mut [u8], mut f: F) -> (usize, usize) where F: FnMut(UploadBuilder),546     pub fn with_mock_upload_builder<F>(buffer: &mut [u8], mut f: F) -> (usize, usize)
547     where
548         F: FnMut(UploadBuilder),
549     {
550         let mut remaining = 0u64;
551         let mut sent = 0;
552         let mut send = |data: &[u8]| -> Result<(), CommandError> {
553             // Skips the first 12 bytes "DATAXXXXXXXX" fastboot message.
554             match sent == 0 {
555                 true => {
556                     assert_eq!(data.len(), 12);
557                     assert!(data.starts_with(b"DATA"));
558                     sent += data.len()
559                 }
560                 _ => {
561                     buffer[sent - 12..][..data.len()].clone_from_slice(data);
562                     sent += data.len();
563                 }
564             };
565             Ok(())
566         };
567         f(UploadBuilder { remaining: &mut remaining, send: &mut send });
568         (core::cmp::max(sent, 12) - 12, remaining.try_into().unwrap())
569     }
570 }
571 
572 const MAX_DOWNLOAD_SIZE_NAME: &'static str = "max-download-size";
573 
574 /// State of the fastboot protocol.
575 enum ProtocolState {
576     Command,
577     Download,
578 }
579 
580 /// `Fastboot` provides methods for receiving/processing/replying fastboot commands from a
581 /// transport.
582 pub struct Fastboot<'a> {
583     state: ProtocolState,
584     download_buffer: &'a mut [u8],
585     downloaded_size: usize,
586     total_download_size: usize,
587 }
588 
589 impl<'a> Fastboot<'a> {
590     /// Creates an instance with a given download buffer.
new(download_buffer: &'a mut [u8]) -> Self591     pub fn new(download_buffer: &'a mut [u8]) -> Self {
592         Self {
593             state: ProtocolState::Command,
594             download_buffer: download_buffer,
595             downloaded_size: 0,
596             total_download_size: 0,
597         }
598     }
599 
600     /// Processes the next fastboot packet from a transport.
601     ///
602     /// # Args
603     ///
604     /// * `transport`: An implementation of `Transport`
605     /// * `fb_impl`: An implementation of `FastbootImplementation`.
606     ///
607     /// # Returns
608     ///
609     /// Returns error if any calls to `transport` methods return error.
610     /// Returns Ok(()) if transport doesn't have any next packet.
process_next_packet( &mut self, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>611     pub fn process_next_packet(
612         &mut self,
613         transport: &mut impl Transport,
614         fb_impl: &mut impl FastbootImplementation,
615     ) -> Result<(), TransportError> {
616         match self.state {
617             ProtocolState::Command => {
618                 let mut packet = [0u8; MAX_COMMAND_SIZE];
619                 let cmd_size = transport.receive_packet(&mut packet[..])?;
620                 if cmd_size == 0 {
621                     return Ok(());
622                 }
623 
624                 let mut res = [0u8; MAX_RESPONSE_SIZE];
625                 let cmd_str = match from_utf8(&packet[..cmd_size]) {
626                     Ok(s) => s,
627                     _ => {
628                         return transport.send_packet(fastboot_fail!(res, "Invalid Command"));
629                     }
630                 };
631                 let mut args = cmd_str.split(':');
632                 let Some(cmd) = args.next() else {
633                     return transport.send_packet(fastboot_fail!(res, "No command"));
634                 };
635                 match cmd {
636                     "getvar" => self.get_var(args, transport, fb_impl)?,
637                     "download" => self.download(args, transport, fb_impl)?,
638                     "flash" => self.flash(cmd_str, transport, fb_impl)?,
639                     "upload" => self.upload(transport, fb_impl)?,
640                     "fetch" => self.fetch(&cmd_str, args, transport, fb_impl)?,
641                     _ if cmd_str.starts_with("oem ") => {
642                         self.oem(&cmd_str[4..], transport, fb_impl)?;
643                     }
644                     _ => {
645                         return transport.send_packet(fastboot_fail!(res, "Command not found"));
646                     }
647                 }
648             }
649             ProtocolState::Download => {
650                 let (_, remains) = &mut self.download_buffer[..self.total_download_size]
651                     .split_at_mut(self.downloaded_size);
652                 match transport.receive_packet(remains) {
653                     Ok(size) if size > remains.len() => {
654                         let mut res = [0u8; MAX_RESPONSE_SIZE];
655                         transport.send_packet(
656                             snprintf!(res, "FAILMore data received then expected").as_bytes(),
657                         )?;
658                         self.total_download_size = 0;
659                         self.downloaded_size = 0;
660                         self.state = ProtocolState::Command;
661                     }
662                     Ok(size) => {
663                         self.downloaded_size = self.downloaded_size.checked_add(size).unwrap();
664                         if self.downloaded_size == self.total_download_size {
665                             self.state = ProtocolState::Command;
666                             transport.send_packet(OKAY.as_bytes())?;
667                         }
668                     }
669                     Err(e) => {
670                         self.total_download_size = 0;
671                         self.downloaded_size = 0;
672                         return Err(e);
673                     }
674                 }
675             }
676         };
677         Ok(())
678     }
679 
680     /// Fetches and processes the next fastboot command from the transport.
681     ///
682     /// Returns Ok(()) if transport doesn't have any next packet.
process_next_command( &mut self, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>683     pub fn process_next_command(
684         &mut self,
685         transport: &mut impl Transport,
686         fb_impl: &mut impl FastbootImplementation,
687     ) -> Result<(), TransportError> {
688         if !matches!(self.state, ProtocolState::Command) {
689             return Err(TransportError::InvalidState);
690         }
691         self.process_next_packet(transport, fb_impl)?;
692         // Keep processing until it is back to the command state.
693         while !matches!(self.state, ProtocolState::Command) {
694             self.process_next_packet(transport, fb_impl)?;
695         }
696         Ok(())
697     }
698 
699     /// Keeps polling and processing fastboot commands from the transport.
run( &mut self, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>700     pub fn run(
701         &mut self,
702         transport: &mut impl Transport,
703         fb_impl: &mut impl FastbootImplementation,
704     ) -> Result<(), TransportError> {
705         loop {
706             self.process_next_command(transport, fb_impl)?;
707         }
708     }
709 
710     /// Runs a fastboot over TCP session.
711     ///
712     /// The method performs fastboot over TCP handshake and then call `Self::run(...)`.
run_tcp_session( &mut self, tcp_stream: &mut dyn TcpStream, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>713     pub fn run_tcp_session(
714         &mut self,
715         tcp_stream: &mut dyn TcpStream,
716         fb_impl: &mut impl FastbootImplementation,
717     ) -> Result<(), TransportError> {
718         self.run(&mut TcpTransport::new_and_handshake(tcp_stream)?, fb_impl)
719     }
720 
721     /// Method for handling "fastboot getvar ..."
get_var( &mut self, mut args: Split<char>, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>722     fn get_var(
723         &mut self,
724         mut args: Split<char>,
725         transport: &mut impl Transport,
726         fb_impl: &mut impl FastbootImplementation,
727     ) -> Result<(), TransportError> {
728         let mut res = [0u8; MAX_RESPONSE_SIZE];
729         let Some(var) = args.next() else {
730             return transport.send_packet(fastboot_fail!(res, "Missing variable"));
731         };
732 
733         if var == "all" {
734             return self.get_var_all(transport, fb_impl);
735         } else if var == MAX_DOWNLOAD_SIZE_NAME {
736             return transport.send_packet(fastboot_okay!(res, "{:#x}", self.download_buffer.len()));
737         }
738 
739         let mut val = [0u8; MAX_RESPONSE_SIZE];
740         match self.get_var_str(var, args, &mut val[..], transport, fb_impl) {
741             Ok(s) => transport.send_packet(fastboot_okay!(res, "{}", s)),
742             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
743         }
744     }
745 
746     /// A helper for getting the string version of a fastboot variable value.
get_var_str<'s>( &mut self, var: &str, args: Split<char>, out: &'s mut [u8], transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<&'s str, CommandError>747     fn get_var_str<'s>(
748         &mut self,
749         var: &str,
750         args: Split<char>,
751         out: &'s mut [u8],
752         transport: &mut impl Transport,
753         fb_impl: &mut impl FastbootImplementation,
754     ) -> Result<&'s str, CommandError> {
755         let mut info_sender = FastbootInfoSender::new(transport);
756         let mut utils = self.utils(Some(&mut info_sender));
757         fb_impl.get_var_as_str(var, args, out, &mut utils)
758     }
759 
760     /// A wrapper of `get_var_all()` that first iterates reserved variables.
get_var_all_with_native( &mut self, fb_impl: &mut impl FastbootImplementation, f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>, ) -> Result<(), CommandError>761     fn get_var_all_with_native(
762         &mut self,
763         fb_impl: &mut impl FastbootImplementation,
764         f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>,
765     ) -> Result<(), CommandError> {
766         // Process the built-in MAX_DOWNLOAD_SIZE_NAME variable.
767         let mut size_str = [0u8; 32];
768         f(MAX_DOWNLOAD_SIZE_NAME, &[], snprintf!(size_str, "{:#x}", self.download_buffer.len()))?;
769         // Don't allow other custom INFO messages because variable values are sent as INFO
770         // messages.
771         fb_impl.get_var_all(f, &mut self.utils(None))
772     }
773 
774     /// Method for handling "fastboot getvar all"
get_var_all( &mut self, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>775     fn get_var_all(
776         &mut self,
777         transport: &mut impl Transport,
778         fb_impl: &mut impl FastbootImplementation,
779     ) -> Result<(), TransportError> {
780         let mut res = [0u8; MAX_RESPONSE_SIZE];
781         let mut transport_error = Ok(());
782         let get_res = self.get_var_all_with_native(fb_impl, &mut |name, args, val| {
783             let mut formatted_bytes = FormattedBytes::new(&mut res);
784             write!(formatted_bytes, "INFO{}", name).unwrap();
785             args.iter().for_each(|arg| write!(formatted_bytes, ":{}", arg).unwrap());
786             write!(formatted_bytes, ": {}", val).unwrap();
787             let size = formatted_bytes.size();
788             transport_error = transport.send_packet(&res[..size]);
789             Ok(transport_error?)
790         });
791         transport_error?;
792         match get_res {
793             Ok(()) => transport.send_packet(fastboot_okay!(res, "")),
794             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
795         }
796     }
797 
798     /// Method for handling "fastboot download:...".
download( &mut self, mut args: Split<char>, transport: &mut impl Transport, _: &mut impl FastbootImplementation, ) -> Result<(), TransportError>799     fn download(
800         &mut self,
801         mut args: Split<char>,
802         transport: &mut impl Transport,
803         _: &mut impl FastbootImplementation,
804     ) -> Result<(), TransportError> {
805         let mut res = [0u8; MAX_RESPONSE_SIZE];
806         let total_download_size = match (|| -> Result<usize, CommandError> {
807             usize::try_from(next_arg_u64(&mut args, Err("Not enough argument".into()))?)
808                 .map_err(|_| "Download size overflow".into())
809         })() {
810             Err(e) => return transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
811             Ok(v) => v,
812         };
813         if total_download_size > self.download_buffer.len() {
814             return transport.send_packet(fastboot_fail!(res, "Download size is too big"));
815         } else if total_download_size == 0 {
816             return transport.send_packet(fastboot_fail!(res, "Zero download size"));
817         }
818 
819         transport.send_packet(snprintf!(res, "DATA{:#x}", total_download_size).as_bytes())?;
820         self.total_download_size = total_download_size;
821         self.downloaded_size = 0;
822         self.state = ProtocolState::Download;
823         Ok(())
824     }
825 
826     /// Method for handling "fastboot flash ...".
flash( &mut self, cmd: &str, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>827     fn flash(
828         &mut self,
829         cmd: &str,
830         transport: &mut impl Transport,
831         fb_impl: &mut impl FastbootImplementation,
832     ) -> Result<(), TransportError> {
833         let mut res = [0u8; MAX_RESPONSE_SIZE];
834         match (|| -> Result<(), CommandError> {
835             let part =
836                 cmd.strip_prefix("flash:").ok_or::<CommandError>("Missing partition".into())?;
837             fb_impl.flash(part, &mut self.utils(Some(&mut FastbootInfoSender::new(transport))))
838         })() {
839             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
840             _ => transport.send_packet(fastboot_okay!(res, "")),
841         }
842     }
843 
844     /// Method for handling "fastboot get_staged ...".
upload( &mut self, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>845     fn upload(
846         &mut self,
847         transport: &mut impl Transport,
848         fb_impl: &mut impl FastbootImplementation,
849     ) -> Result<(), TransportError> {
850         let mut res = [0u8; MAX_RESPONSE_SIZE];
851         match with_upload_builder(transport, |upload_builder| {
852             // No INFO message should be sent during upload.
853             let mut utils = self.utils(None);
854             fb_impl.upload(upload_builder, &mut utils)
855         })? {
856             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
857             _ => transport.send_packet(fastboot_okay!(res, "")),
858         }
859     }
860 
861     /// Method for handling "fastboot fetch ...".
fetch( &mut self, cmd: &str, args: Split<char>, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>862     pub fn fetch(
863         &mut self,
864         cmd: &str,
865         args: Split<char>,
866         transport: &mut impl Transport,
867         fb_impl: &mut impl FastbootImplementation,
868     ) -> Result<(), TransportError> {
869         let mut res = [0u8; MAX_RESPONSE_SIZE];
870         match with_upload_builder(transport, |upload_builder| -> Result<(), CommandError> {
871             let cmd =
872                 cmd.strip_prefix("fetch:").ok_or::<CommandError>("Missing arguments".into())?;
873             if args.clone().count() < 3 {
874                 return Err("Not enough argments".into());
875             }
876             // Parses backward. Parses size, offset first and treats the remaining string as
877             // partition name. This allows ":" in partition name.
878             let mut rev = args.clone().rev();
879             let sz = next_arg(&mut rev, Err("Invalid argument".into()))?;
880             let off = next_arg(&mut rev, Err("Invalid argument".into()))?;
881             let part = &cmd[..cmd.len() - (off.len() + sz.len() + 2)];
882             // No INFO message should be sent during upload.
883             let mut utils = self.utils(None);
884             fb_impl.fetch(part, hex_to_u64(off)?, hex_to_u64(sz)?, upload_builder, &mut utils)
885         })? {
886             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
887             _ => transport.send_packet(fastboot_okay!(res, "")),
888         }
889     }
890 
891     /// Method for handling "fastboot oem ...".
oem( &mut self, cmd: &str, transport: &mut impl Transport, fb_impl: &mut impl FastbootImplementation, ) -> Result<(), TransportError>892     fn oem(
893         &mut self,
894         cmd: &str,
895         transport: &mut impl Transport,
896         fb_impl: &mut impl FastbootImplementation,
897     ) -> Result<(), TransportError> {
898         let mut info_sender = FastbootInfoSender::new(transport);
899         let mut utils = self.utils(Some(&mut info_sender));
900         let mut oem_out = [0u8; MAX_RESPONSE_SIZE - 4];
901         let oem_res = fb_impl.oem(cmd, &mut utils, &mut oem_out[..]);
902         info_sender.transport_error()?;
903         let mut res = [0u8; MAX_RESPONSE_SIZE];
904         match oem_res {
905             Ok(msg) => match from_utf8(msg) {
906                 Ok(s) => transport.send_packet(fastboot_okay!(res, "{}", s)),
907                 Err(e) => transport.send_packet(fastboot_fail!(res, "Invalid return string {}", e)),
908             },
909             Err(e) => transport.send_packet(fastboot_fail!(res, "{}", e.to_str())),
910         }
911     }
912 
913     /// Helper method to create an instance of `FastbootUtils`.
utils<'b>(&'b mut self, info: Option<&'b mut dyn FastbootInfoSend>) -> FastbootUtils<'b>914     fn utils<'b>(&'b mut self, info: Option<&'b mut dyn FastbootInfoSend>) -> FastbootUtils<'b> {
915         FastbootUtils::new(self.download_buffer, &mut self.total_download_size, info.map(|v| v))
916     }
917 }
918 
919 /// A helper data structure for writing formatted string to fixed size bytes array.
920 #[derive(Debug)]
921 pub struct FormattedBytes<T: AsMut<[u8]>>(T, usize);
922 
923 impl<T: AsMut<[u8]>> FormattedBytes<T> {
924     /// Create an instance.
new(buf: T) -> Self925     pub fn new(buf: T) -> Self {
926         Self(buf, 0)
927     }
928 
929     /// Get the size of content.
size(&self) -> usize930     pub fn size(&self) -> usize {
931         self.1
932     }
933 
append(&mut self, bytes: &[u8]) -> &mut [u8]934     pub fn append(&mut self, bytes: &[u8]) -> &mut [u8] {
935         let buf = &mut self.0.as_mut()[self.1..];
936         // Only write as much as the size of the bytes buffer. Additional write is silently
937         // ignored.
938         let to_write = core::cmp::min(buf.len(), bytes.len());
939         buf[..to_write].clone_from_slice(&bytes[..to_write]);
940         self.1 += to_write;
941         &mut self.0.as_mut()[..self.1]
942     }
943 }
944 
945 impl<T: AsMut<[u8]>> core::fmt::Write for FormattedBytes<T> {
write_str(&mut self, s: &str) -> core::fmt::Result946     fn write_str(&mut self, s: &str) -> core::fmt::Result {
947         self.append(s.as_bytes());
948         Ok(())
949     }
950 }
951 
952 /// A convenient macro that behaves similar to snprintf in C.
953 #[macro_export]
954 macro_rules! snprintf {
955     ( $arr:expr, $( $x:expr ),* ) => {
956         {
957             let mut formatted_bytes = FormattedBytes::new(&mut $arr[..]);
958             write!(formatted_bytes, $($x,)*).unwrap();
959             let size = formatted_bytes.size();
960             from_utf8(&$arr[..size]).unwrap()
961         }
962     };
963 }
964 
965 /// A helper to convert a hex string into u64.
hex_to_u64(s: &str) -> Result<u64, CommandError>966 pub(crate) fn hex_to_u64(s: &str) -> Result<u64, CommandError> {
967     Ok(u64::from_str_radix(s.strip_prefix("0x").unwrap_or(s), 16)?)
968 }
969 
970 /// A helper to check and fetch the next argument or fall back to the default if not available.
971 ///
972 /// # Args
973 ///
974 /// args: A string iterator.
975 /// default: This will be returned as it is if args doesn't have the next element(). Providing a
976 ///   Ok(str) is equivalent to providing a default value. Providing an Err() is equivalent to
977 ///   requiring that the next argument is mandatory.
next_arg<'a, T: Iterator<Item = &'a str>>( args: &mut T, default: Result<&'a str, CommandError>, ) -> Result<&'a str, CommandError>978 pub fn next_arg<'a, T: Iterator<Item = &'a str>>(
979     args: &mut T,
980     default: Result<&'a str, CommandError>,
981 ) -> Result<&'a str, CommandError> {
982     args.next().filter(|v| *v != "").ok_or("").or(default.map_err(|e| e.into()))
983 }
984 
985 /// A helper to check and fetch the next argument as a u64 hex string.
986 ///
987 /// # Args
988 ///
989 /// args: A string iterator.
990 /// default: This will be returned as it is if args doesn't have the next element(). Providing a
991 ///   Ok(u64) is equivalent to providing a default value. Providing an Err() is equivalent to
992 ///   requiring that the next argument is mandatory.
993 ///
994 /// Returns error if the next argument is not a valid hex string.
next_arg_u64<'a, T: Iterator<Item = &'a str>>( args: &mut T, default: Result<u64, CommandError>, ) -> Result<u64, CommandError>995 pub fn next_arg_u64<'a, T: Iterator<Item = &'a str>>(
996     args: &mut T,
997     default: Result<u64, CommandError>,
998 ) -> Result<u64, CommandError> {
999     match next_arg(args, Err("".into())) {
1000         Ok(v) => hex_to_u64(v),
1001         _ => default.map_err(|e| e.into()),
1002     }
1003 }
1004 
1005 #[cfg(test)]
1006 mod test {
1007     use super::*;
1008     use std::collections::{BTreeMap, VecDeque};
1009 
1010     #[derive(Default)]
1011     struct FastbootTest<'a> {
1012         // A mapping from (variable name, argument) to variable value.
1013         vars: BTreeMap<(&'static str, &'static [&'static str]), &'static str>,
1014         flash_cb: Option<&'a mut dyn FnMut(&str, &mut FastbootUtils) -> Result<(), CommandError>>,
1015         upload_cb: Option<
1016             &'a mut dyn FnMut(UploadBuilder, &mut FastbootUtils) -> Result<(), CommandError>,
1017         >,
1018         fetch_cb: Option<
1019             &'a mut dyn FnMut(
1020                 &str,
1021                 u64,
1022                 u64,
1023                 UploadBuilder,
1024                 &mut FastbootUtils,
1025             ) -> Result<(), CommandError>,
1026         >,
1027         oem_cb: Option<
1028             &'a mut dyn FnMut(&str, &mut FastbootUtils, &mut [u8]) -> Result<usize, CommandError>,
1029         >,
1030     }
1031 
1032     impl FastbootImplementation for FastbootTest<'_> {
get_var( &mut self, var: &str, args: Split<char>, out: &mut [u8], _: &mut FastbootUtils, ) -> Result<usize, CommandError>1033         fn get_var(
1034             &mut self,
1035             var: &str,
1036             args: Split<char>,
1037             out: &mut [u8],
1038             _: &mut FastbootUtils,
1039         ) -> Result<usize, CommandError> {
1040             let args = args.collect::<Vec<_>>();
1041             match self.vars.get(&(var, &args[..])) {
1042                 Some(v) => {
1043                     out[..v.len()].clone_from_slice(v.as_bytes());
1044                     Ok(v.len())
1045                 }
1046                 _ => Err("Not Found".into()),
1047             }
1048         }
1049 
get_var_all( &mut self, f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>, _: &mut FastbootUtils, ) -> Result<(), CommandError>1050         fn get_var_all(
1051             &mut self,
1052             f: &mut dyn FnMut(&str, &[&str], &str) -> Result<(), CommandError>,
1053             _: &mut FastbootUtils,
1054         ) -> Result<(), CommandError> {
1055             for ((var, config), value) in &self.vars {
1056                 f(var, config, value)?;
1057             }
1058             Ok(())
1059         }
1060 
flash(&mut self, part: &str, utils: &mut FastbootUtils) -> Result<(), CommandError>1061         fn flash(&mut self, part: &str, utils: &mut FastbootUtils) -> Result<(), CommandError> {
1062             (self.flash_cb.as_mut().unwrap())(part, utils)
1063         }
1064 
upload( &mut self, upload_builder: UploadBuilder, utils: &mut FastbootUtils, ) -> Result<(), CommandError>1065         fn upload(
1066             &mut self,
1067             upload_builder: UploadBuilder,
1068             utils: &mut FastbootUtils,
1069         ) -> Result<(), CommandError> {
1070             (self.upload_cb.as_mut().unwrap())(upload_builder, utils)
1071         }
1072 
fetch( &mut self, part: &str, offset: u64, size: u64, upload_builder: UploadBuilder, utils: &mut FastbootUtils, ) -> Result<(), CommandError>1073         fn fetch(
1074             &mut self,
1075             part: &str,
1076             offset: u64,
1077             size: u64,
1078             upload_builder: UploadBuilder,
1079             utils: &mut FastbootUtils,
1080         ) -> Result<(), CommandError> {
1081             (self.fetch_cb.as_mut().unwrap())(part, offset, size, upload_builder, utils)
1082         }
1083 
oem<'b>( &mut self, cmd: &str, utils: &mut FastbootUtils, res: &'b mut [u8], ) -> Result<&'b [u8], CommandError>1084         fn oem<'b>(
1085             &mut self,
1086             cmd: &str,
1087             utils: &mut FastbootUtils,
1088             res: &'b mut [u8],
1089         ) -> Result<&'b [u8], CommandError> {
1090             let sz = (self.oem_cb.as_mut().unwrap())(cmd, utils, res)?;
1091             Ok(&res[..sz])
1092         }
1093     }
1094 
1095     struct TestTransport {
1096         in_queue: VecDeque<Vec<u8>>,
1097         out_queue: VecDeque<Vec<u8>>,
1098     }
1099 
1100     impl TestTransport {
new() -> Self1101         fn new() -> Self {
1102             Self { in_queue: VecDeque::new(), out_queue: VecDeque::new() }
1103         }
1104 
add_input(&mut self, packet: &[u8])1105         fn add_input(&mut self, packet: &[u8]) {
1106             self.in_queue.push_back(packet.into());
1107         }
1108     }
1109 
1110     impl Transport for TestTransport {
receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError>1111         fn receive_packet(&mut self, out: &mut [u8]) -> Result<usize, TransportError> {
1112             match self.in_queue.pop_front() {
1113                 Some(v) => {
1114                     let size = core::cmp::min(out.len(), v.len());
1115                     out[..size].clone_from_slice(&v[..size]);
1116                     // Returns the input length so that we can test bogus download size.
1117                     Ok(v.len())
1118                 }
1119                 _ => Err(TransportError::Others("No more data")),
1120             }
1121         }
1122 
send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError>1123         fn send_packet(&mut self, packet: &[u8]) -> Result<(), TransportError> {
1124             self.out_queue.push_back(packet.into());
1125             Ok(())
1126         }
1127     }
1128 
1129     #[derive(Default)]
1130     struct TestTcpStream {
1131         in_queue: VecDeque<u8>,
1132         out_queue: VecDeque<u8>,
1133     }
1134 
1135     impl TestTcpStream {
1136         /// Adds bytes to input stream.
add_input(&mut self, data: &[u8])1137         fn add_input(&mut self, data: &[u8]) {
1138             data.iter().for_each(|v| self.in_queue.push_back(*v));
1139         }
1140 
1141         /// Adds a length pre-fixed bytes stream.
add_length_prefixed_input(&mut self, data: &[u8])1142         fn add_length_prefixed_input(&mut self, data: &[u8]) {
1143             self.add_input(&(data.len() as u64).to_be_bytes());
1144             self.add_input(data);
1145         }
1146     }
1147 
1148     impl TcpStream for TestTcpStream {
read_exact(&mut self, out: &mut [u8]) -> Result<(), TransportError>1149         fn read_exact(&mut self, out: &mut [u8]) -> Result<(), TransportError> {
1150             for ele in out {
1151                 *ele = self.in_queue.pop_front().ok_or(TransportError::Others("No more data"))?;
1152             }
1153             Ok(())
1154         }
1155 
write_exact(&mut self, data: &[u8]) -> Result<(), TransportError>1156         fn write_exact(&mut self, data: &[u8]) -> Result<(), TransportError> {
1157             data.iter().for_each(|v| self.out_queue.push_back(*v));
1158             Ok(())
1159         }
1160     }
1161 
1162     #[test]
test_non_exist_command()1163     fn test_non_exist_command() {
1164         let mut fastboot_impl: FastbootTest = Default::default();
1165         let mut download_buffer = vec![0u8; 1024];
1166         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1167         let mut transport = TestTransport::new();
1168         transport.add_input(b"non_exist");
1169         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1170         assert_eq!(transport.out_queue, [b"FAILCommand not found"]);
1171     }
1172 
1173     #[test]
test_non_ascii_command_string()1174     fn test_non_ascii_command_string() {
1175         let mut fastboot_impl: FastbootTest = Default::default();
1176         let mut download_buffer = vec![0u8; 1024];
1177         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1178         let mut transport = TestTransport::new();
1179         transport.add_input(b"\xff\xff\xff");
1180         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1181         assert_eq!(transport.out_queue, [b"FAILInvalid Command"]);
1182     }
1183 
1184     #[test]
test_get_var_max_download_size()1185     fn test_get_var_max_download_size() {
1186         let mut fastboot_impl: FastbootTest = Default::default();
1187         let mut download_buffer = vec![0u8; 1024];
1188         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1189         let mut transport = TestTransport::new();
1190         transport.add_input(b"getvar:max-download-size");
1191         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1192         assert_eq!(transport.out_queue, [b"OKAY0x400"]);
1193     }
1194 
1195     #[test]
test_get_var()1196     fn test_get_var() {
1197         let mut fastboot_impl: FastbootTest = Default::default();
1198         let vars: [((&str, &[&str]), &str); 4] = [
1199             (("var_0", &[]), "val_0"),
1200             (("var_1", &["a", "b"]), "val_1_a_b"),
1201             (("var_1", &["c", "d"]), "val_1_c_d"),
1202             (("var_2", &["e", "f"]), "val_2_e_f"),
1203         ];
1204         fastboot_impl.vars = BTreeMap::from(vars);
1205 
1206         let mut download_buffer = vec![0u8; 1024];
1207         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1208         let mut transport = TestTransport::new();
1209         transport.add_input(b"getvar:var_0");
1210         transport.add_input(b"getvar:var_1:a:b");
1211         transport.add_input(b"getvar:var_1:c:d");
1212         transport.add_input(b"getvar:var_1"); // Not Found
1213         transport.add_input(b"getvar:var_2:e:f");
1214         transport.add_input(b"getvar:var_3"); // Not Found
1215         transport.add_input(b"getvar"); // Not Found
1216 
1217         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1218         assert_eq!(
1219             transport.out_queue,
1220             VecDeque::<Vec<u8>>::from([
1221                 b"OKAYval_0".into(),
1222                 b"OKAYval_1_a_b".into(),
1223                 b"OKAYval_1_c_d".into(),
1224                 b"FAILNot Found".into(),
1225                 b"OKAYval_2_e_f".into(),
1226                 b"FAILNot Found".into(),
1227                 b"FAILMissing variable".into(),
1228             ])
1229         );
1230     }
1231 
1232     #[test]
test_get_var_all()1233     fn test_get_var_all() {
1234         let mut fastboot_impl: FastbootTest = Default::default();
1235         let vars: [((&str, &[&str]), &str); 4] = [
1236             (("var_0", &[]), "val_0"),
1237             (("var_1", &["a", "b"]), "val_1_a_b"),
1238             (("var_1", &["c", "d"]), "val_1_c_d"),
1239             (("var_2", &["e", "f"]), "val_2_e_f"),
1240         ];
1241         fastboot_impl.vars = BTreeMap::from(vars);
1242 
1243         let mut download_buffer = vec![0u8; 1024];
1244         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1245         let mut transport = TestTransport::new();
1246         transport.add_input(b"getvar:all");
1247         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1248         assert_eq!(
1249             transport.out_queue,
1250             VecDeque::<Vec<u8>>::from([
1251                 b"INFOmax-download-size: 0x400".into(),
1252                 b"INFOvar_0: val_0".into(),
1253                 b"INFOvar_1:a:b: val_1_a_b".into(),
1254                 b"INFOvar_1:c:d: val_1_c_d".into(),
1255                 b"INFOvar_2:e:f: val_2_e_f".into(),
1256                 b"OKAY".into(),
1257             ])
1258         );
1259     }
1260 
1261     #[test]
test_download()1262     fn test_download() {
1263         let mut fastboot_impl: FastbootTest = Default::default();
1264         let mut download_buffer = vec![0u8; 1024];
1265         let download_content: Vec<u8> =
1266             (0..download_buffer.len()).into_iter().map(|v| v as u8).collect();
1267         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1268         let mut transport = TestTransport::new();
1269         // Splits download into two batches.
1270         let (first, second) = download_content.as_slice().split_at(download_content.len() / 2);
1271         transport.add_input(format!("download:{:#x}", download_content.len()).as_bytes());
1272         transport.add_input(first);
1273         transport.add_input(second);
1274         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1275         assert_eq!(
1276             transport.out_queue,
1277             VecDeque::<Vec<u8>>::from([b"DATA0x400".into(), b"OKAY".into(),])
1278         );
1279         assert_eq!(download_buffer, download_content);
1280     }
1281 
1282     #[test]
test_download_not_enough_args()1283     fn test_download_not_enough_args() {
1284         let mut fastboot_impl: FastbootTest = Default::default();
1285         let mut download_buffer = vec![0u8; 1024];
1286         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1287         let mut transport = TestTransport::new();
1288         transport.add_input(b"download");
1289         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1290         assert_eq!(transport.out_queue, [b"FAILNot enough argument"]);
1291     }
1292 
1293     #[test]
test_download_invalid_hex_string()1294     fn test_download_invalid_hex_string() {
1295         let mut fastboot_impl: FastbootTest = Default::default();
1296         let mut download_buffer = vec![0u8; 1024];
1297         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1298         let mut transport = TestTransport::new();
1299         transport.add_input(b"download:hhh");
1300         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1301         assert_eq!(transport.out_queue.len(), 1);
1302         assert!(transport.out_queue[0].starts_with(b"FAIL"));
1303     }
1304 
test_download_size(download_buffer_size: usize, download_size: usize, msg: &str)1305     fn test_download_size(download_buffer_size: usize, download_size: usize, msg: &str) {
1306         let mut fastboot_impl: FastbootTest = Default::default();
1307         let mut download_buffer = vec![0u8; download_buffer_size];
1308         let mut transport = TestTransport::new();
1309         transport.add_input(format!("download:{:#x}", download_size).as_bytes());
1310         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1311         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1312         assert_eq!(transport.out_queue, VecDeque::<Vec<u8>>::from([msg.as_bytes().into()]));
1313     }
1314 
1315     #[test]
test_download_download_size_too_big()1316     fn test_download_download_size_too_big() {
1317         test_download_size(1024, 1025, "FAILDownload size is too big");
1318     }
1319 
1320     #[test]
test_download_zero_download_size()1321     fn test_download_zero_download_size() {
1322         test_download_size(1024, 0, "FAILZero download size");
1323     }
1324 
1325     #[test]
test_download_more_than_expected()1326     fn test_download_more_than_expected() {
1327         let mut fastboot_impl: FastbootTest = Default::default();
1328         let mut download_buffer = vec![0u8; 1024];
1329         let download_content: Vec<u8> = vec![0u8; download_buffer.len()];
1330         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1331         let mut transport = TestTransport::new();
1332         transport.add_input(format!("download:{:#x}", download_content.len() - 1).as_bytes());
1333         transport.add_input(&download_content[..]);
1334         // State should be reset to command state.
1335         transport.add_input(b"getvar:max-download-size");
1336         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1337         assert_eq!(
1338             transport.out_queue,
1339             VecDeque::<Vec<u8>>::from([
1340                 b"DATA0x3ff".into(),
1341                 b"FAILMore data received then expected".into(),
1342                 b"OKAY0x400".into(),
1343             ])
1344         );
1345     }
1346 
1347     #[test]
test_oem_cmd()1348     fn test_oem_cmd() {
1349         let mut fastboot_impl: FastbootTest = Default::default();
1350         const DOWNLOAD_BUFFER_LEN: usize = 2048;
1351         let mut download_buffer = vec![0u8; DOWNLOAD_BUFFER_LEN];
1352         let download_content: Vec<u8> = (0..1024).into_iter().map(|v| v as u8).collect();
1353         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1354         let mut transport = TestTransport::new();
1355         transport.add_input(format!("download:{:#x}", download_content.len()).as_bytes());
1356         transport.add_input(&download_content[..]);
1357         transport.add_input(b"oem oem-command");
1358 
1359         let mut oem_cb = |cmd: &str, utils: &mut FastbootUtils, res: &mut [u8]| {
1360             assert_eq!(cmd, "oem-command");
1361             assert_eq!(utils.download_buffer.len(), DOWNLOAD_BUFFER_LEN);
1362             assert_eq!(utils.download_data().to_vec(), download_content);
1363             assert!(utils.info_send("oem-info-1").unwrap());
1364             assert!(utils.info_send("oem-info-2").unwrap());
1365             Ok(snprintf!(res, "oem-return").len())
1366         };
1367         fastboot_impl.oem_cb = Some(&mut oem_cb);
1368         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1369         assert_eq!(
1370             transport.out_queue,
1371             VecDeque::<Vec<u8>>::from([
1372                 b"DATA0x400".into(),
1373                 b"OKAY".into(),
1374                 b"INFOoem-info-1".into(),
1375                 b"INFOoem-info-2".into(),
1376                 b"OKAYoem-return".into(),
1377             ])
1378         );
1379     }
1380 
1381     #[test]
test_flash()1382     fn test_flash() {
1383         let mut fastboot_impl: FastbootTest = Default::default();
1384         const DOWNLOAD_BUFFER_LEN: usize = 2048;
1385         let mut download_buffer = vec![0u8; DOWNLOAD_BUFFER_LEN];
1386         let download_content: Vec<u8> = (0..1024).into_iter().map(|v| v as u8).collect();
1387         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1388         let mut transport = TestTransport::new();
1389         transport.add_input(format!("download:{:#x}", download_content.len()).as_bytes());
1390         transport.add_input(&download_content[..]);
1391         transport.add_input(b"flash:boot_a:0::");
1392 
1393         let mut flash_cb = |part: &str, utils: &mut FastbootUtils| {
1394             assert_eq!(part, "boot_a:0::");
1395             assert_eq!(utils.download_data().to_vec(), download_content);
1396             Ok(())
1397         };
1398         fastboot_impl.flash_cb = Some(&mut flash_cb);
1399         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1400         assert_eq!(
1401             transport.out_queue,
1402             VecDeque::<Vec<u8>>::from([b"DATA0x400".into(), b"OKAY".into(), b"OKAY".into(),])
1403         );
1404     }
1405 
1406     #[test]
test_flash_missing_partition()1407     fn test_flash_missing_partition() {
1408         let mut fastboot_impl: FastbootTest = Default::default();
1409         let mut fastboot = Fastboot::new(&mut []);
1410         let mut transport = TestTransport::new();
1411         transport.add_input(b"flash");
1412         let mut flash_cb = |_: &str, _: &mut FastbootUtils| Ok(());
1413         fastboot_impl.flash_cb = Some(&mut flash_cb);
1414         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1415         assert_eq!(transport.out_queue, [b"FAILMissing partition"]);
1416     }
1417 
1418     #[test]
test_upload()1419     fn test_upload() {
1420         let mut fastboot_impl: FastbootTest = Default::default();
1421         const DOWNLOAD_BUFFER_LEN: usize = 2048;
1422         let mut download_buffer = vec![0u8; DOWNLOAD_BUFFER_LEN];
1423         let download_content: Vec<u8> = (0..1024).into_iter().map(|v| v as u8).collect();
1424         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1425         let mut transport = TestTransport::new();
1426         transport.add_input(format!("download:{:#x}", download_content.len()).as_bytes());
1427         transport.add_input(&download_content[..]);
1428         transport.add_input(b"upload");
1429 
1430         let mut upload_cb = |upload_builder: UploadBuilder, utils: &mut FastbootUtils| {
1431             assert_eq!(utils.download_buffer.len(), DOWNLOAD_BUFFER_LEN);
1432             assert_eq!(utils.download_data().to_vec(), download_content);
1433             let (download_buffer, download_len) = utils.take_download_buffer();
1434             let to_send = &mut download_buffer[..download_len];
1435             let mut uploader = upload_builder.start(u64::try_from(to_send.len()).unwrap()).unwrap();
1436             uploader.upload(&to_send[..download_len / 2]).unwrap();
1437             uploader.upload(&to_send[download_len / 2..]).unwrap();
1438             assert!(!utils.info_send("").unwrap());
1439             assert_eq!(utils.download_data().len(), 0);
1440             Ok(())
1441         };
1442         fastboot_impl.upload_cb = Some(&mut upload_cb);
1443         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1444         assert_eq!(
1445             transport.out_queue,
1446             VecDeque::<Vec<u8>>::from([
1447                 b"DATA0x400".into(),
1448                 b"OKAY".into(),
1449                 b"DATA00000400".into(),
1450                 download_content[..download_content.len() / 2].to_vec(),
1451                 download_content[download_content.len() / 2..].to_vec(),
1452                 b"OKAY".into(),
1453             ])
1454         );
1455     }
1456 
1457     #[test]
test_upload_not_enough_data()1458     fn test_upload_not_enough_data() {
1459         let mut fastboot_impl: FastbootTest = Default::default();
1460         let mut download_buffer = vec![0u8; 2048];
1461         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1462         let mut transport = TestTransport::new();
1463         transport.add_input(b"upload");
1464 
1465         let mut upload_cb = |upload_builder: UploadBuilder, _: &mut FastbootUtils| {
1466             let mut uploader = upload_builder.start(0x400).unwrap();
1467             uploader.upload(&[0u8; 0x400 - 1]).unwrap();
1468             Ok(())
1469         };
1470         fastboot_impl.upload_cb = Some(&mut upload_cb);
1471         assert!(fastboot.run(&mut transport, &mut fastboot_impl).is_err());
1472     }
1473 
1474     #[test]
test_upload_more_data()1475     fn test_upload_more_data() {
1476         let mut fastboot_impl: FastbootTest = Default::default();
1477         let mut download_buffer = vec![0u8; 2048];
1478         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1479         let mut transport = TestTransport::new();
1480         transport.add_input(b"upload");
1481 
1482         let mut upload_cb = |upload_builder: UploadBuilder, _: &mut FastbootUtils| {
1483             let mut uploader = upload_builder.start(0x400).unwrap();
1484             uploader.upload(&[0u8; 0x400 + 1])?;
1485             Ok(())
1486         };
1487         fastboot_impl.upload_cb = Some(&mut upload_cb);
1488         assert!(fastboot.run(&mut transport, &mut fastboot_impl).is_err());
1489     }
1490 
1491     #[test]
test_fetch()1492     fn test_fetch() {
1493         let mut fastboot_impl: FastbootTest = Default::default();
1494         let mut download_buffer = vec![0u8; 2048];
1495         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1496         let mut transport = TestTransport::new();
1497         transport.add_input(b"fetch:boot_a:0:::200:400");
1498 
1499         let mut fetch_cb = |part: &str,
1500                             offset: u64,
1501                             size: u64,
1502                             upload_builder: UploadBuilder,
1503                             _: &mut FastbootUtils| {
1504             assert_eq!(part, "boot_a:0::");
1505             assert_eq!(offset, 0x200);
1506             assert_eq!(size, 0x400);
1507             let mut uploader = upload_builder.start(size)?;
1508             uploader.upload(&vec![0u8; size.try_into().unwrap()][..])?;
1509             Ok(())
1510         };
1511         fastboot_impl.fetch_cb = Some(&mut fetch_cb);
1512         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1513         assert_eq!(
1514             transport.out_queue,
1515             VecDeque::<Vec<u8>>::from([
1516                 b"DATA00000400".into(),
1517                 [0u8; 0x400].to_vec(),
1518                 b"OKAY".into(),
1519             ])
1520         );
1521     }
1522 
1523     #[test]
test_fetch_invalid_args()1524     fn test_fetch_invalid_args() {
1525         let mut fastboot_impl: FastbootTest = Default::default();
1526         let mut download_buffer = vec![0u8; 2048];
1527         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1528         let mut transport = TestTransport::new();
1529         transport.add_input(b"fetch");
1530         transport.add_input(b"fetch:");
1531         transport.add_input(b"fetch:boot_a");
1532         transport.add_input(b"fetch:boot_a:200");
1533         transport.add_input(b"fetch:boot_a::400");
1534         transport.add_input(b"fetch:boot_a::");
1535         transport.add_input(b"fetch:boot_a:xxx:400");
1536         transport.add_input(b"fetch:boot_a:200:xxx");
1537         let mut fetch_cb =
1538             |_: &str, _: u64, _: u64, _: UploadBuilder, _: &mut FastbootUtils| Ok(());
1539         fastboot_impl.fetch_cb = Some(&mut fetch_cb);
1540         let _ = fastboot.run(&mut transport, &mut fastboot_impl);
1541         assert!(transport.out_queue.iter().all(|v| v.starts_with(b"FAIL")));
1542     }
1543 
1544     #[test]
test_fastboot_tcp()1545     fn test_fastboot_tcp() {
1546         let mut fastboot_impl: FastbootTest = Default::default();
1547         let mut download_buffer = vec![0u8; 1024];
1548         let download_content: Vec<u8> =
1549             (0..download_buffer.len()).into_iter().map(|v| v as u8).collect();
1550         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1551         let mut tcp_stream: TestTcpStream = Default::default();
1552         tcp_stream.add_input(TCP_HANDSHAKE_MESSAGE);
1553         // Add two commands and verify both are executed.
1554         tcp_stream.add_length_prefixed_input(b"getvar:max-download-size");
1555         tcp_stream.add_length_prefixed_input(
1556             format!("download:{:#x}", download_content.len()).as_bytes(),
1557         );
1558         tcp_stream.add_length_prefixed_input(&download_content[..]);
1559         let _ = fastboot.run_tcp_session(&mut tcp_stream, &mut fastboot_impl);
1560         let expected: &[&[u8]] = &[
1561             b"FB01",
1562             b"\x00\x00\x00\x00\x00\x00\x00\x09OKAY0x400",
1563             b"\x00\x00\x00\x00\x00\x00\x00\x09DATA0x400",
1564             b"\x00\x00\x00\x00\x00\x00\x00\x04OKAY",
1565         ];
1566         assert_eq!(tcp_stream.out_queue, VecDeque::from(expected.concat()));
1567         assert_eq!(download_buffer, download_content);
1568     }
1569 
1570     #[test]
test_fastboot_tcp_invalid_handshake()1571     fn test_fastboot_tcp_invalid_handshake() {
1572         let mut fastboot_impl: FastbootTest = Default::default();
1573         let mut download_buffer = vec![0u8; 1024];
1574         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1575         let mut tcp_stream: TestTcpStream = Default::default();
1576         tcp_stream.add_input(b"ABCD");
1577         assert_eq!(
1578             fastboot.run_tcp_session(&mut tcp_stream, &mut fastboot_impl).unwrap_err(),
1579             TransportError::InvalidHanshake
1580         );
1581     }
1582 
1583     #[test]
test_fastboot_tcp_packet_size_exceeds_maximum()1584     fn test_fastboot_tcp_packet_size_exceeds_maximum() {
1585         let mut fastboot_impl: FastbootTest = Default::default();
1586         let mut download_buffer = vec![0u8; 1024];
1587         let mut fastboot = Fastboot::new(&mut download_buffer[..]);
1588         let mut tcp_stream: TestTcpStream = Default::default();
1589         tcp_stream.add_input(TCP_HANDSHAKE_MESSAGE);
1590         tcp_stream.add_input(&(MAX_COMMAND_SIZE + 1).to_be_bytes());
1591         assert_eq!(
1592             fastboot.run_tcp_session(&mut tcp_stream, &mut fastboot_impl).unwrap_err(),
1593             TransportError::PacketSizeExceedMaximum
1594         );
1595     }
1596 }
1597