1use super::packet::{self, AuthConfig, ControlPacket, State};
7use anyhow::{bail, ensure, Result};
8use serde_json::{json, Value};
9use std::time::Duration;
10use tokio::time::Instant;
11
12pub const SLOW_TX_US: u32 = 1_000_000;
14pub const DEFAULT_DESIRED_MIN_TX_MS: u32 = 300;
15pub const DEFAULT_REQUIRED_MIN_RX_MS: u32 = 300;
16pub const DEFAULT_DETECT_MULT: u8 = 3;
17pub const MIN_INTERVAL_MS: u32 = 10;
19pub const MAX_INTERVAL_MS: u32 = 60_000;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct Timers {
23 pub desired_min_tx_us: u32,
24 pub required_min_rx_us: u32,
25 pub detect_mult: u8,
26}
27
28impl Default for Timers {
29 fn default() -> Self {
30 Self {
31 desired_min_tx_us: DEFAULT_DESIRED_MIN_TX_MS * 1000,
32 required_min_rx_us: DEFAULT_REQUIRED_MIN_RX_MS * 1000,
33 detect_mult: DEFAULT_DETECT_MULT,
34 }
35 }
36}
37
38impl Timers {
39 pub fn from_json(v: &Value, base: Timers) -> Result<Self> {
42 let ms = |key: &str, fallback: u32| -> Result<u32> {
43 match v.get(key) {
44 None | Some(Value::Null) => Ok(fallback),
45 Some(x) => {
46 let n = x
47 .as_u64()
48 .filter(|n| (MIN_INTERVAL_MS as u64..=MAX_INTERVAL_MS as u64).contains(n));
49 match n {
50 Some(n) => Ok(n as u32 * 1000),
51 None => bail!(
52 "{key} must be a whole number of milliseconds, {MIN_INTERVAL_MS}-{MAX_INTERVAL_MS}"
53 ),
54 }
55 }
56 }
57 };
58 let detect_mult = match v.get("detect_mult") {
59 None | Some(Value::Null) => base.detect_mult,
60 Some(x) => {
61 let n = x.as_u64().unwrap_or(0);
62 ensure!((1..=255).contains(&n), "detect_mult must be 1-255");
63 n as u8
64 }
65 };
66 Ok(Self {
67 desired_min_tx_us: ms("desired_min_tx_ms", base.desired_min_tx_us / 1000)?,
68 required_min_rx_us: ms("required_min_rx_ms", base.required_min_rx_us / 1000)?,
69 detect_mult,
70 })
71 }
72}
73
74#[derive(Debug, Default)]
76pub struct Received {
77 pub transition: Option<(State, State)>,
79 pub send_final: bool,
81}
82
83pub struct Session {
84 pub local_discr: u32,
85 pub remote_discr: u32,
86 pub state: State,
87 pub remote_state: State,
88 pub local_diag: u8,
89 pub configured: Timers,
91 advertised: Timers,
93 tx_in_force_us: u32,
96 rx_in_force_us: u32,
97 pub poll: bool,
98 pub remote_desired_min_tx_us: u32,
99 pub remote_min_rx_us: u32,
100 pub remote_detect_mult: u8,
101 pub passive: bool,
102 auth: Option<AuthConfig>,
103 xmit_seq: u32,
104 rcv_seq: Option<u32>,
105 pub last_rx: Option<Instant>,
106}
107
108impl Session {
109 pub fn new(
110 local_discr: u32,
111 configured: Timers,
112 auth: Option<AuthConfig>,
113 passive: bool,
114 ) -> Self {
115 let advertised = Timers {
116 desired_min_tx_us: configured.desired_min_tx_us.max(SLOW_TX_US),
117 ..configured
118 };
119 Self {
120 local_discr,
121 remote_discr: 0,
122 state: State::Down,
123 remote_state: State::Down,
124 local_diag: 0,
125 configured,
126 advertised,
127 tx_in_force_us: advertised.desired_min_tx_us,
128 rx_in_force_us: advertised.required_min_rx_us,
129 poll: false,
130 remote_desired_min_tx_us: 0,
131 remote_min_rx_us: 1,
133 remote_detect_mult: 0,
134 passive,
135 auth,
136 xmit_seq: rand::random(),
137 rcv_seq: None,
138 last_rx: None,
139 }
140 }
141
142 fn advertise(&mut self) {
145 let next = Timers {
146 desired_min_tx_us: if self.state == State::Up {
147 self.configured.desired_min_tx_us
148 } else {
149 self.configured.desired_min_tx_us.max(SLOW_TX_US)
150 },
151 ..self.configured
152 };
153 if next == self.advertised {
154 return;
155 }
156 if self.state == State::Up {
157 self.poll = true;
158 if next.desired_min_tx_us < self.tx_in_force_us {
159 self.tx_in_force_us = next.desired_min_tx_us;
160 }
161 if next.required_min_rx_us > self.rx_in_force_us {
162 self.rx_in_force_us = next.required_min_rx_us;
163 }
164 } else {
165 self.tx_in_force_us = next.desired_min_tx_us;
166 self.rx_in_force_us = next.required_min_rx_us;
167 }
168 self.advertised = next;
169 }
170
171 pub fn set_timers(&mut self, timers: Timers) {
172 self.configured = timers;
173 self.advertise();
174 }
175
176 fn set_state(&mut self, next: State, diag: u8) -> Option<(State, State)> {
177 if next == self.state {
178 return None;
179 }
180 let previous = self.state;
181 self.state = next;
182 self.local_diag = diag;
183 self.advertise();
184 Some((previous, next))
185 }
186
187 pub fn admin_down(&mut self, diag: u8) -> Option<(State, State)> {
188 self.set_state(State::AdminDown, diag)
189 }
190
191 pub fn admin_up(&mut self) -> Option<(State, State)> {
192 if self.state != State::AdminDown {
193 return None;
194 }
195 self.set_state(State::Down, 0)
196 }
197
198 pub fn receive(&mut self, bytes: &[u8], p: &ControlPacket, now: Instant) -> Result<Received> {
200 packet::verify(bytes, p, self.auth.as_ref())?;
201 if let (Some(config), Some(seq)) = (&self.auth, p.auth.as_ref().and_then(|a| a.sequence)) {
202 if let Some(last) = self.rcv_seq {
203 let window = 3 * p.detect_mult as u32;
204 let ahead = seq.wrapping_sub(last);
205 let ok = if config.kind.meticulous() {
206 (1..=window).contains(&ahead)
207 } else {
208 ahead <= window
209 };
210 ensure!(
211 ok,
212 "sequence number {seq} is outside the window after {last}"
213 );
214 }
215 self.rcv_seq = Some(seq);
216 }
217 let mut out = Received {
218 send_final: p.poll,
219 ..Default::default()
220 };
221 self.last_rx = Some(now);
222 self.remote_discr = p.my_discriminator;
223 self.remote_state = p.state;
224 self.remote_desired_min_tx_us = p.desired_min_tx_us;
225 self.remote_min_rx_us = p.required_min_rx_us;
226 self.remote_detect_mult = p.detect_mult;
227 if p.final_ && self.poll {
228 self.poll = false;
229 self.tx_in_force_us = self.advertised.desired_min_tx_us;
230 self.rx_in_force_us = self.advertised.required_min_rx_us;
231 }
232 if self.state == State::AdminDown {
233 return Ok(out);
234 }
235 out.transition = match (p.state, self.state) {
236 (State::AdminDown, local) if local != State::Down => self.set_state(State::Down, 3),
237 (State::AdminDown, _) => None,
238 (State::Down, State::Down) => self.set_state(State::Init, 0),
239 (State::Init, State::Down) => self.set_state(State::Up, 0),
240 (State::Init | State::Up, State::Init) => self.set_state(State::Up, 0),
241 (State::Down, State::Up) => self.set_state(State::Down, 3),
242 _ => None,
243 };
244 Ok(out)
245 }
246
247 pub fn packet(&mut self, final_: bool) -> Vec<u8> {
249 let p = ControlPacket {
250 diag: self.local_diag,
251 state: self.state,
252 poll: self.poll && !final_,
253 final_,
254 control_plane_independent: false,
255 demand: false,
256 detect_mult: self.advertised.detect_mult,
257 my_discriminator: self.local_discr,
258 your_discriminator: self.remote_discr,
259 desired_min_tx_us: self.advertised.desired_min_tx_us,
260 required_min_rx_us: self.advertised.required_min_rx_us,
261 required_min_echo_rx_us: 0,
262 auth: None,
263 };
264 let auth = self.auth.as_ref().map(|a| {
265 if a.kind != packet::AuthType::SimplePassword {
266 self.xmit_seq = self.xmit_seq.wrapping_add(1);
267 }
268 (a, self.xmit_seq)
269 });
270 p.encode(auth)
271 }
272
273 pub fn may_transmit(&self) -> bool {
276 !(self.passive && self.remote_discr == 0) && self.remote_min_rx_us != 0
277 }
278
279 pub fn next_interval(&self) -> Duration {
282 let base = self.tx_in_force_us.max(self.remote_min_rx_us) as u64;
283 let top = if self.advertised.detect_mult == 1 {
284 90
285 } else {
286 100
287 };
288 let pct = rand::random::<u64>() % (top - 75 + 1) + 75;
289 Duration::from_micros(base * pct / 100)
290 }
291
292 pub fn tx_interval_us(&self) -> u32 {
293 self.tx_in_force_us.max(self.remote_min_rx_us)
294 }
295
296 pub fn detection_time(&self) -> Duration {
298 Duration::from_micros(
299 self.remote_detect_mult as u64
300 * self.rx_in_force_us.max(self.remote_desired_min_tx_us) as u64,
301 )
302 }
303
304 pub fn detection_deadline(&self) -> Option<Instant> {
306 match self.state {
307 State::Init | State::Up => self.last_rx.map(|t| t + self.detection_time()),
308 _ => None,
309 }
310 }
311
312 pub fn detection_expired(&mut self) -> Option<(State, State)> {
315 self.remote_discr = 0;
316 self.rcv_seq = None;
317 self.set_state(State::Down, 1)
318 }
319
320 pub fn snapshot(&self) -> Value {
322 json!({
323 "state": self.state.name(),
324 "diag": packet::diag_name(self.local_diag),
325 "remote_state": self.remote_state.name(),
326 "local_discriminator": self.local_discr,
327 "remote_discriminator": self.remote_discr,
328 "desired_min_tx_ms": self.configured.desired_min_tx_us / 1000,
329 "required_min_rx_ms": self.configured.required_min_rx_us / 1000,
330 "detect_mult": self.configured.detect_mult,
331 "remote_desired_min_tx_ms": self.remote_desired_min_tx_us / 1000,
332 "remote_required_min_rx_ms": self.remote_min_rx_us / 1000,
333 "remote_detect_mult": self.remote_detect_mult,
334 "tx_interval_ms": self.tx_interval_us() / 1000,
335 "detection_time_ms": self.detection_time().as_millis() as u64,
336 "poll_in_progress": self.poll,
337 "authentication": self.auth.as_ref().map(|a| a.kind.name()),
338 })
339 }
340}