Skip to main content

mediatek_optical/
protocol.rs

1//! Validated live MT19 boot signature, separate from update receiver detection.
2use crate::{Chip, Identity};
3/// Required response bytes were not returned.
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub struct Incomplete;
6impl core::fmt::Display for Incomplete {
7    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
8        f.write_str("required INQUIRY or boot-banner bytes were not returned")
9    }
10}
11#[cfg(feature = "std")]
12impl std::error::Error for Incomplete {}
13/// A complete boot-banner signature. It does not prove update support or mode.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Evidence {
16    identity: Identity,
17}
18impl Evidence {
19    /// Parse the boot label at the start of a complete 32-byte ROM window.
20    /// Bytes after its NUL terminator are firmware instructions, not string padding.
21    /// Names and descriptor labels do not select a chip.
22    pub fn parse(inquiry: &[u8], banner: &[u8]) -> Result<Option<Self>, Incomplete> {
23        if inquiry.len() < crate::INQUIRY_LEN || banner.len() != crate::layout::BANNER.len {
24            return Err(Incomplete);
25        }
26        if inquiry[0] & 0x1f != 5
27            || &banner[..4] != b"MT19"
28            || &banner[6..12] != b" Boot "
29            || Chip::from_digits(banner[4], banner[5]).is_none()
30        {
31            return Ok(None);
32        }
33        let end = banner.iter().position(|b| *b == 0).unwrap_or(banner.len());
34        if end <= 12 || !banner[..end].iter().all(|b| (0x20..=0x7e).contains(b)) {
35            return Ok(None);
36        }
37        Ok(Some(Self {
38            identity: Identity::parse(inquiry, banner, &[]).ok_or(Incomplete)?,
39        }))
40    }
41    /// Parsed identity with a chip established by the boot signature.
42    pub fn identity(&self) -> &Identity {
43        &self.identity
44    }
45}