umsh_ulcp_device/
bridge.rs1use heapless::String;
3use umsh_ulcp::{
4 Status,
5 bridge::{DEFAULT_PORT, HOST_MAX, valid_host},
6 ids::prop,
7};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct BridgeConfig {
11 pub enabled: bool,
12 pub host: String<HOST_MAX>,
13 pub port: u16,
14 pub server_key: Option<[u8; 32]>,
15}
16
17impl Default for BridgeConfig {
18 fn default() -> Self {
19 Self {
20 enabled: false,
21 host: String::new(),
22 port: DEFAULT_PORT,
23 server_key: None,
24 }
25 }
26}
27
28impl BridgeConfig {
29 pub fn configured(&self) -> bool {
30 !self.host.is_empty() && self.server_key.is_some()
31 }
32
33 pub fn set(&mut self, key: u32, value: &[u8]) -> Result<(), Status> {
34 match key {
35 prop::BRIDGE_ENABLED => {
36 self.enabled = match value {
37 [0] => false,
38 [1] => true,
39 _ => return Err(Status::INVALID_ARGUMENT),
40 }
41 }
42 prop::BRIDGE_HOST => {
43 let bytes = value.strip_suffix(&[0]).ok_or(Status::INVALID_ARGUMENT)?;
44 let host = core::str::from_utf8(bytes).map_err(|_| Status::INVALID_ARGUMENT)?;
45 if !valid_host(host) {
46 return Err(Status::INVALID_ARGUMENT);
47 }
48 self.host = String::try_from(host).map_err(|_| Status::NOMEM)?;
49 }
50 prop::BRIDGE_PORT => {
51 let port =
52 u16::from_le_bytes(value.try_into().map_err(|_| Status::INVALID_ARGUMENT)?);
53 if port == 0 {
54 return Err(Status::INVALID_ARGUMENT);
55 }
56 self.port = port;
57 }
58 prop::BRIDGE_SERVER_KEY => {
59 self.server_key = if value.is_empty() {
60 None
61 } else {
62 let bytes: [u8; 32] = value.try_into().map_err(|_| Status::INVALID_ARGUMENT)?;
63 let key = ed25519_dalek::VerifyingKey::from_bytes(&bytes)
64 .map_err(|_| Status::INVALID_ARGUMENT)?;
65 if key.is_weak() || key.to_edwards().compress().to_bytes() != bytes {
66 return Err(Status::INVALID_ARGUMENT);
67 }
68 Some(bytes)
69 };
70 }
71 _ => return Err(Status::PROP_NOT_FOUND),
72 }
73 Ok(())
74 }
75
76 pub fn encode(&self, key: u32, out: &mut [u8]) -> Option<usize> {
77 let bytes: &[u8] = match key {
78 prop::BRIDGE_ENABLED => &[self.enabled as u8],
79 prop::BRIDGE_PORT => &self.port.to_le_bytes(),
80 prop::BRIDGE_SERVER_KEY => self.server_key.as_ref().map_or(&[], |k| k.as_slice()),
81 prop::BRIDGE_HOST => {
82 let len = self.host.len();
83 out.get_mut(..len + 1)?[..len].copy_from_slice(self.host.as_bytes());
84 out[len] = 0;
85 return Some(len + 1);
86 }
87 _ => return None,
88 };
89 out.get_mut(..bytes.len())?.copy_from_slice(bytes);
90 Some(bytes.len())
91 }
92}