pim_protocol/
route_frame.rs1use bytes::{Buf, BufMut, BytesMut};
4
5use pim_core::{FrameCodec, NodeId, PimError};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct RouteEntry {
10 pub destination: NodeId,
12 pub hops: u8,
14 pub flags: u8,
16 pub mesh_ip: [u8; 4],
18}
19
20impl RouteEntry {
21 pub fn is_gateway(&self) -> bool {
23 self.flags & 0x01 != 0
24 }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct RouteUpdateFrame {
32 pub origin_id: NodeId,
34 pub sequence: u64,
36 pub entries: Vec<RouteEntry>,
38 pub signature: [u8; 64],
40}
41
42const HEADER_SIZE: usize = 16 + 8 + 2; const ENTRY_SIZE: usize = 16 + 1 + 1 + 4; const SIGNATURE_SIZE: usize = 64;
45const MAX_ENTRIES: u16 = 1000;
46
47impl FrameCodec for RouteUpdateFrame {
48 fn encode(&self, buf: &mut BytesMut) {
49 buf.put_slice(self.origin_id.as_bytes());
50 buf.put_u64(self.sequence);
51 buf.put_u16(self.entries.len() as u16);
52 for entry in &self.entries {
53 buf.put_slice(entry.destination.as_bytes());
54 buf.put_u8(entry.hops);
55 buf.put_u8(entry.flags);
56 buf.put_slice(&entry.mesh_ip);
57 }
58 buf.put_slice(&self.signature);
59 }
60
61 fn decode(buf: &mut BytesMut) -> Result<Self, PimError> {
62 if buf.len() < HEADER_SIZE {
63 return Err(PimError::Protocol(
64 "route update too short for header".into(),
65 ));
66 }
67
68 let mut origin_bytes = [0u8; 16];
69 origin_bytes.copy_from_slice(&buf[0..16]);
70 let origin_id = NodeId::from_bytes(origin_bytes);
71
72 let sequence = (&buf[16..24]).get_u64();
73 let entry_count = (&buf[24..26]).get_u16();
74
75 if entry_count > MAX_ENTRIES {
76 return Err(PimError::Protocol(format!(
77 "too many route entries: {entry_count}, max {MAX_ENTRIES}"
78 )));
79 }
80
81 let total = HEADER_SIZE + (entry_count as usize * ENTRY_SIZE) + SIGNATURE_SIZE;
82 if buf.len() < total {
83 return Err(PimError::Protocol(format!(
84 "route update truncated: need {total}, have {}",
85 buf.len()
86 )));
87 }
88
89 let mut entries = Vec::with_capacity(entry_count as usize);
90 let mut offset = HEADER_SIZE;
91 for _ in 0..entry_count {
92 let mut dest = [0u8; 16];
93 dest.copy_from_slice(&buf[offset..offset + 16]);
94 let hops = buf[offset + 16];
95 let flags = buf[offset + 17];
96 let mut mesh_ip = [0u8; 4];
97 mesh_ip.copy_from_slice(&buf[offset + 18..offset + 22]);
98 entries.push(RouteEntry {
99 destination: NodeId::from_bytes(dest),
100 hops,
101 flags,
102 mesh_ip,
103 });
104 offset += ENTRY_SIZE;
105 }
106
107 let mut signature = [0u8; 64];
108 signature.copy_from_slice(&buf[offset..offset + SIGNATURE_SIZE]);
109
110 buf.advance(total);
111
112 Ok(RouteUpdateFrame {
113 origin_id,
114 sequence,
115 entries,
116 signature,
117 })
118 }
119}
120
121#[cfg(test)]
122mod tests;