pim_protocol/
control_frame.rs1use bytes::{Buf, BufMut, BytesMut};
4
5use pim_core::{FrameCodec, NodeId, PimError};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[repr(u8)]
9pub enum ControlType {
11 IpRequest = 0x01,
13 IpAssign = 0x02,
15 Goodbye = 0x03,
17 Rekey = 0x04,
19 Ping = 0x05,
21 Pong = 0x06,
23}
24
25impl ControlType {
26 pub fn from_u8(v: u8) -> Result<Self, PimError> {
28 match v {
29 0x01 => Ok(Self::IpRequest),
30 0x02 => Ok(Self::IpAssign),
31 0x03 => Ok(Self::Goodbye),
32 0x04 => Ok(Self::Rekey),
33 0x05 => Ok(Self::Ping),
34 0x06 => Ok(Self::Pong),
35 other => Err(PimError::Protocol(format!(
36 "unknown control type: 0x{other:02x}"
37 ))),
38 }
39 }
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum ControlFrame {
47 IpRequest {
49 requester_id: NodeId,
51 },
52 IpAssign {
54 assigned_ip: [u8; 4],
56 subnet_mask: u8,
58 gateway_ip: [u8; 4],
60 lease_seconds: u32,
62 },
63 Goodbye {
65 departing_id: NodeId,
67 reason: u8,
69 },
70 Rekey,
72 Ping {
74 nonce: u64,
76 },
77 Pong {
79 nonce: u64,
81 },
82}
83
84impl FrameCodec for ControlFrame {
85 fn encode(&self, buf: &mut BytesMut) {
86 match self {
87 ControlFrame::IpRequest { requester_id } => {
88 buf.put_u8(ControlType::IpRequest as u8);
89 buf.put_slice(requester_id.as_bytes());
90 }
91 ControlFrame::IpAssign {
92 assigned_ip,
93 subnet_mask,
94 gateway_ip,
95 lease_seconds,
96 } => {
97 buf.put_u8(ControlType::IpAssign as u8);
98 buf.put_slice(assigned_ip);
99 buf.put_u8(*subnet_mask);
100 buf.put_slice(gateway_ip);
101 buf.put_u32(*lease_seconds);
102 }
103 ControlFrame::Goodbye {
104 departing_id,
105 reason,
106 } => {
107 buf.put_u8(ControlType::Goodbye as u8);
108 buf.put_slice(departing_id.as_bytes());
109 buf.put_u8(*reason);
110 }
111 ControlFrame::Rekey => {
112 buf.put_u8(ControlType::Rekey as u8);
113 }
114 ControlFrame::Ping { nonce } => {
115 buf.put_u8(ControlType::Ping as u8);
116 buf.put_u64(*nonce);
117 }
118 ControlFrame::Pong { nonce } => {
119 buf.put_u8(ControlType::Pong as u8);
120 buf.put_u64(*nonce);
121 }
122 }
123 }
124
125 fn decode(buf: &mut BytesMut) -> Result<Self, PimError> {
126 if buf.is_empty() {
127 return Err(PimError::Protocol("control frame empty".into()));
128 }
129
130 let control_type = ControlType::from_u8(buf[0])?;
131
132 match control_type {
133 ControlType::IpRequest => {
134 if buf.len() < 17 {
135 return Err(PimError::Protocol("IpRequest too short".into()));
136 }
137 let mut id = [0u8; 16];
138 id.copy_from_slice(&buf[1..17]);
139 buf.advance(17);
140 Ok(ControlFrame::IpRequest {
141 requester_id: NodeId::from_bytes(id),
142 })
143 }
144 ControlType::IpAssign => {
145 if buf.len() < 14 {
146 return Err(PimError::Protocol("IpAssign too short".into()));
148 }
149 let mut assigned_ip = [0u8; 4];
150 assigned_ip.copy_from_slice(&buf[1..5]);
151 let subnet_mask = buf[5];
152 let mut gateway_ip = [0u8; 4];
153 gateway_ip.copy_from_slice(&buf[6..10]);
154 let lease_seconds = (&buf[10..14]).get_u32();
155 buf.advance(14);
156 Ok(ControlFrame::IpAssign {
157 assigned_ip,
158 subnet_mask,
159 gateway_ip,
160 lease_seconds,
161 })
162 }
163 ControlType::Goodbye => {
164 if buf.len() < 18 {
165 return Err(PimError::Protocol("Goodbye too short".into()));
167 }
168 let mut id = [0u8; 16];
169 id.copy_from_slice(&buf[1..17]);
170 let reason = buf[17];
171 buf.advance(18);
172 Ok(ControlFrame::Goodbye {
173 departing_id: NodeId::from_bytes(id),
174 reason,
175 })
176 }
177 ControlType::Rekey => {
178 buf.advance(1);
179 Ok(ControlFrame::Rekey)
180 }
181 ControlType::Ping => {
182 if buf.len() < 9 {
183 return Err(PimError::Protocol("Ping too short".into()));
184 }
185 let nonce = (&buf[1..9]).get_u64();
186 buf.advance(9);
187 Ok(ControlFrame::Ping { nonce })
188 }
189 ControlType::Pong => {
190 if buf.len() < 9 {
191 return Err(PimError::Protocol("Pong too short".into()));
192 }
193 let nonce = (&buf[1..9]).get_u64();
194 buf.advance(9);
195 Ok(ControlFrame::Pong { nonce })
196 }
197 }
198 }
199}
200
201#[cfg(test)]
202mod tests;