1use crate::prelude_internal::*;
6use anyhow::format_err;
7use num::FromPrimitive;
8use std::os::raw::c_char;
9
10const EPSKC_RANDOM_GEN_LEN: usize = 8;
13
14#[derive(
18 Debug,
19 Copy,
20 Clone,
21 Eq,
22 Ord,
23 PartialOrd,
24 PartialEq,
25 num_derive::FromPrimitive,
26 num_derive::ToPrimitive,
27)]
28pub enum BorderAgentEphemeralKeyState {
29 Disabled = OT_BORDER_AGENT_STATE_DISABLED as isize,
31
32 Stopped = OT_BORDER_AGENT_STATE_STOPPED as isize,
34
35 Started = OT_BORDER_AGENT_STATE_STARTED as isize,
37
38 Connected = OT_BORDER_AGENT_STATE_CONNECTED as isize,
40
41 Accepted = OT_BORDER_AGENT_STATE_ACCEPTED as isize,
43}
44
45impl From<otBorderAgentEphemeralKeyState> for BorderAgentEphemeralKeyState {
46 fn from(x: otBorderAgentEphemeralKeyState) -> Self {
47 Self::from_u32(x)
48 .unwrap_or_else(|| panic!("Unknown otBorderAgentEphemeralKeyState value: {x}"))
49 }
50}
51
52impl From<BorderAgentEphemeralKeyState> for otBorderAgentEphemeralKeyState {
53 fn from(x: BorderAgentEphemeralKeyState) -> Self {
54 x as otBorderAgentEphemeralKeyState
55 }
56}
57
58#[derive(Debug, PartialEq)]
59#[allow(missing_docs)]
60pub struct BorderAgentCounters {
61 pub epskc_activations: u32,
62 pub epskc_deactivation_clears: u32,
63 pub epskc_deactivation_timeouts: u32,
64 pub epskc_deactivation_max_attempts: u32,
65 pub epskc_deactivation_disconnects: u32,
66 pub epskc_invalid_ba_state_errors: u32,
67 pub epskc_invalid_args_errors: u32,
68 pub epskc_start_secure_session_errors: u32,
69 pub epskc_secure_session_successes: u32,
70 pub epskc_secure_session_failures: u32,
71 pub epskc_commissioner_petitions: u32,
72 pub pskc_secure_session_successes: u32,
73 pub pskc_secure_session_failures: u32,
74 pub pskc_commissioner_petitions: u32,
75 pub mgmt_active_gets: u32,
76 pub mgmt_pending_gets: u32,
77}
78
79impl BorderAgentCounters {
80 unsafe fn from_ot_counters(
81 counters: *const otBorderAgentCounters,
82 ) -> Option<BorderAgentCounters> {
83 counters.as_ref().map(|&counters| BorderAgentCounters {
84 epskc_activations: counters.mEpskcActivations,
85 epskc_deactivation_clears: counters.mEpskcDeactivationClears,
86 epskc_deactivation_timeouts: counters.mEpskcDeactivationTimeouts,
87 epskc_deactivation_max_attempts: counters.mEpskcDeactivationMaxAttempts,
88 epskc_deactivation_disconnects: counters.mEpskcDeactivationDisconnects,
89 epskc_invalid_ba_state_errors: counters.mEpskcInvalidBaStateErrors,
90 epskc_invalid_args_errors: counters.mEpskcInvalidArgsErrors,
91 epskc_start_secure_session_errors: counters.mEpskcStartSecureSessionErrors,
92 epskc_secure_session_successes: counters.mEpskcSecureSessionSuccesses,
93 epskc_secure_session_failures: counters.mEpskcSecureSessionFailures,
94 epskc_commissioner_petitions: counters.mEpskcCommissionerPetitions,
95 pskc_secure_session_successes: counters.mPskcSecureSessionSuccesses,
96 pskc_secure_session_failures: counters.mPskcSecureSessionFailures,
97 pskc_commissioner_petitions: counters.mPskcCommissionerPetitions,
98 mgmt_active_gets: counters.mMgmtActiveGets,
99 mgmt_pending_gets: counters.mMgmtPendingGets,
100 })
101 }
102}
103
104pub trait BorderAgent {
108 fn border_agent_is_active(&self) -> bool;
111
112 fn border_agent_get_udp_port(&self) -> u16;
115
116 fn border_agent_get_meshcop_service_txt_data(&self) -> Result<Vec<u8>>;
119
120 fn border_agent_ephemeral_key_get_state(&self) -> BorderAgentEphemeralKeyState;
123
124 fn border_agent_ephemeral_key_set_enabled(&self, enabled: bool);
127
128 fn border_agent_ephemeral_key_start(
131 &self,
132 key_string: &CStr,
133 timeout: u32,
134 port: u16,
135 ) -> Result;
136
137 fn border_agent_ephemeral_key_stop(&self);
140
141 fn border_agent_ephemeral_key_get_udp_port(&self) -> u16;
144
145 fn border_agent_set_ephemeral_key_callback<'a, F>(&'a self, f: Option<F>)
148 where
149 F: FnMut() + 'a;
150
151 fn border_agent_get_counters(&self) -> Option<BorderAgentCounters>;
154
155 fn border_agent_set_meshcop_service_changed_fn<'a, F>(&'a self, f: Option<F>)
157 where
158 F: FnMut() + 'a;
159}
160
161impl<T: BorderAgent + Boxable> BorderAgent for ot::Box<T> {
162 fn border_agent_is_active(&self) -> bool {
163 self.as_ref().border_agent_is_active()
164 }
165
166 fn border_agent_get_udp_port(&self) -> u16 {
167 self.as_ref().border_agent_get_udp_port()
168 }
169
170 fn border_agent_get_meshcop_service_txt_data(&self) -> Result<Vec<u8>> {
171 self.as_ref().border_agent_get_meshcop_service_txt_data()
172 }
173
174 fn border_agent_ephemeral_key_get_state(&self) -> BorderAgentEphemeralKeyState {
175 self.as_ref().border_agent_ephemeral_key_get_state()
176 }
177
178 fn border_agent_ephemeral_key_set_enabled(&self, enabled: bool) {
179 self.as_ref().border_agent_ephemeral_key_set_enabled(enabled)
180 }
181
182 fn border_agent_ephemeral_key_start(&self, key: &CStr, timeout: u32, port: u16) -> Result {
183 self.as_ref().border_agent_ephemeral_key_start(key, timeout, port)
184 }
185
186 fn border_agent_ephemeral_key_stop(&self) {
187 self.as_ref().border_agent_ephemeral_key_stop()
188 }
189
190 fn border_agent_ephemeral_key_get_udp_port(&self) -> u16 {
191 self.as_ref().border_agent_ephemeral_key_get_udp_port()
192 }
193
194 fn border_agent_set_ephemeral_key_callback<'a, F>(&'a self, f: Option<F>)
195 where
196 F: FnMut() + 'a,
197 {
198 self.as_ref().border_agent_set_ephemeral_key_callback(f)
199 }
200
201 fn border_agent_get_counters(&self) -> Option<BorderAgentCounters> {
202 self.as_ref().border_agent_get_counters()
203 }
204
205 fn border_agent_set_meshcop_service_changed_fn<'a, F>(&'a self, f: Option<F>)
206 where
207 F: FnMut() + 'a,
208 {
209 self.as_ref().border_agent_set_meshcop_service_changed_fn(f)
210 }
211}
212
213impl BorderAgent for Instance {
214 fn border_agent_is_active(&self) -> bool {
215 unsafe { otBorderAgentIsActive(self.as_ot_ptr()) }
216 }
217
218 fn border_agent_get_udp_port(&self) -> u16 {
219 unsafe { otBorderAgentGetUdpPort(self.as_ot_ptr()) }
220 }
221
222 fn border_agent_get_meshcop_service_txt_data(&self) -> Result<Vec<u8>> {
223 let mut txt_data = otBorderAgentMeshCoPServiceTxtData::default();
224 let result: Result = Error::from(unsafe {
225 otBorderAgentGetMeshCoPServiceTxtData(self.as_ot_ptr(), &mut txt_data)
226 })
227 .into();
228 result?;
229 Ok(txt_data.mData[..txt_data.mLength as usize].to_vec())
230 }
231
232 fn border_agent_ephemeral_key_get_state(&self) -> BorderAgentEphemeralKeyState {
233 unsafe { otBorderAgentEphemeralKeyGetState(self.as_ot_ptr()).into() }
234 }
235
236 fn border_agent_ephemeral_key_set_enabled(&self, enabled: bool) {
237 unsafe { otBorderAgentEphemeralKeySetEnabled(self.as_ot_ptr(), enabled) }
238 }
239
240 fn border_agent_ephemeral_key_start(&self, key: &CStr, timeout: u32, port: u16) -> Result {
241 unsafe {
242 Error::from(otBorderAgentEphemeralKeyStart(
243 self.as_ot_ptr(),
244 key.as_ptr(),
245 timeout,
246 port,
247 ))
248 .into()
249 }
250 }
251
252 fn border_agent_ephemeral_key_stop(&self) {
253 unsafe { otBorderAgentEphemeralKeyStop(self.as_ot_ptr()) }
254 }
255
256 fn border_agent_ephemeral_key_get_udp_port(&self) -> u16 {
257 unsafe { otBorderAgentEphemeralKeyGetUdpPort(self.as_ot_ptr()) }
258 }
259
260 fn border_agent_set_ephemeral_key_callback<'a, F>(&'a self, f: Option<F>)
261 where
262 F: FnMut() + 'a,
263 {
264 unsafe extern "C" fn _border_agent_set_ephemeral_key_callback<'a, F: FnMut() + 'a>(
265 context: *mut ::std::os::raw::c_void,
266 ) {
267 trace!("_border_agent_set_ephemeral_key_callback");
268
269 let sender = &mut *(context as *mut F);
271
272 sender()
273 }
274
275 let (fn_ptr, fn_box, cb): (_, _, otBorderAgentEphemeralKeyCallback) = if let Some(f) = f {
276 let mut x = Box::new(f);
277
278 (
279 x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
280 Some(x as Box<dyn FnMut() + 'a>),
281 Some(_border_agent_set_ephemeral_key_callback::<F>),
282 )
283 } else {
284 (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
285 };
286
287 unsafe {
288 otBorderAgentEphemeralKeySetCallback(self.as_ot_ptr(), cb, fn_ptr);
289
290 self.borrow_backing().ephemeral_key_callback.set(std::mem::transmute::<
296 Option<Box<dyn FnMut() + 'a>>,
297 Option<Box<dyn FnMut() + 'static>>,
298 >(fn_box));
299 }
300 }
301
302 fn border_agent_get_counters(&self) -> Option<BorderAgentCounters> {
303 unsafe { BorderAgentCounters::from_ot_counters(otBorderAgentGetCounters(self.as_ot_ptr())) }
304 }
305
306 fn border_agent_set_meshcop_service_changed_fn<'a, F>(&'a self, f: Option<F>)
307 where
308 F: FnMut() + 'a,
309 {
310 unsafe extern "C" fn _border_agent_set_meshcop_service_changed_callback<
311 'a,
312 F: FnMut() + 'a,
313 >(
314 context: *mut ::std::os::raw::c_void,
315 ) {
316 trace!("_border_agent_set_meshcop_service_changed_callback");
317
318 let sender = &mut *(context as *mut F);
320
321 sender()
322 }
323
324 let (fn_ptr, fn_box, cb): (_, _, otBorderAgentMeshCoPServiceChangedCallback) =
325 if let Some(f) = f {
326 let mut x = Box::new(f);
327
328 (
329 x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
330 Some(x as Box<dyn FnMut() + 'a>),
331 Some(_border_agent_set_meshcop_service_changed_callback::<F>),
332 )
333 } else {
334 (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
335 };
336
337 unsafe {
338 otBorderAgentSetMeshCoPServiceChangedCallback(self.as_ot_ptr(), cb, fn_ptr);
339
340 self.borrow_backing().meshcop_service_changed_callback.set(std::mem::transmute::<
346 Option<Box<dyn FnMut() + 'a>>,
347 Option<Box<dyn FnMut() + 'static>>,
348 >(fn_box));
349 }
350 }
351}
352
353pub fn create_ephemeral_key() -> Result<CString, anyhow::Error> {
357 let mut key: Vec<u8> = Vec::new();
358
359 for _ in 0..EPSKC_RANDOM_GEN_LEN {
361 loop {
362 let mut new_value: u8 = 0;
363 let rand_result = unsafe { otRandomCryptoFillBuffer(&mut new_value as *mut u8, 1) };
364
365 ot::Error::from(rand_result)
366 .into_result()
367 .map_err(|e| format_err!("Random number generation failed: {}", e))?;
368
369 if new_value < 250 {
370 key.push(b'0' + new_value % 10);
371 break;
372 }
373 }
374 }
375
376 let mut checksum_char: c_char = 0;
378 let checksum_result = unsafe {
379 otVerhoeffChecksumCalculate(key[0] as *const c_char, &mut checksum_char as *mut c_char)
380 };
381 ot::Error::from(checksum_result)
382 .into_result()
383 .map_err(|e| format_err!("Verhoeff checksum calculation failed: {}", e))?;
384
385 key.push(checksum_char as u8);
386 CString::new(key).map_err(|e| format_err!("Ephemeral key is not a valid string: {}", e))
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn test_counter_conversion_succeeds() {
395 let epskc_activations = 0;
396 let epskc_deactivation_clears = 1;
397 let epskc_deactivation_timeouts = 2;
398 let epskc_deactivation_max_attempts = 3;
399 let epskc_deactivation_disconnects = 4;
400 let epskc_invalid_ba_state_errors = 5;
401 let epskc_invalid_args_errors = 6;
402 let epskc_start_secure_session_errors = 7;
403 let epskc_secure_session_successes = 8;
404 let epskc_secure_session_failures = 9;
405 let epskc_commissioner_petitions = 10;
406 let pskc_secure_session_successes = 11;
407 let pskc_secure_session_failures = 12;
408 let pskc_commissioner_petitions = 13;
409 let mgmt_active_gets = 14;
410 let mgmt_pending_gets = 15;
411
412 let ot_counters = otBorderAgentCounters {
413 mEpskcActivations: epskc_activations,
414 mEpskcDeactivationClears: epskc_deactivation_clears,
415 mEpskcDeactivationTimeouts: epskc_deactivation_timeouts,
416 mEpskcDeactivationMaxAttempts: epskc_deactivation_max_attempts,
417 mEpskcDeactivationDisconnects: epskc_deactivation_disconnects,
418 mEpskcInvalidBaStateErrors: epskc_invalid_ba_state_errors,
419 mEpskcInvalidArgsErrors: epskc_invalid_args_errors,
420 mEpskcStartSecureSessionErrors: epskc_start_secure_session_errors,
421 mEpskcSecureSessionSuccesses: epskc_secure_session_successes,
422 mEpskcSecureSessionFailures: epskc_secure_session_failures,
423 mEpskcCommissionerPetitions: epskc_commissioner_petitions,
424 mPskcSecureSessionSuccesses: pskc_secure_session_successes,
425 mPskcSecureSessionFailures: pskc_secure_session_failures,
426 mPskcCommissionerPetitions: pskc_commissioner_petitions,
427 mMgmtActiveGets: mgmt_active_gets,
428 mMgmtPendingGets: mgmt_pending_gets,
429 };
430
431 let ot_counters_ptr: *const otBorderAgentCounters = &ot_counters;
432
433 let converted_counters = unsafe { BorderAgentCounters::from_ot_counters(ot_counters_ptr) }
434 .expect("Failed to convert OT Border Agent counters");
435
436 assert_eq!(
437 converted_counters,
438 BorderAgentCounters {
439 epskc_activations,
440 epskc_deactivation_clears,
441 epskc_deactivation_timeouts,
442 epskc_deactivation_max_attempts,
443 epskc_deactivation_disconnects,
444 epskc_invalid_ba_state_errors,
445 epskc_invalid_args_errors,
446 epskc_start_secure_session_errors,
447 epskc_secure_session_successes,
448 epskc_secure_session_failures,
449 epskc_commissioner_petitions,
450 pskc_secure_session_successes,
451 pskc_secure_session_failures,
452 pskc_commissioner_petitions,
453 mgmt_active_gets,
454 mgmt_pending_gets,
455 }
456 );
457 }
458
459 #[test]
460 fn test_counter_conversion_fails() {
461 let null_ptr: *const otBorderAgentCounters = std::ptr::null();
462 assert!(unsafe { BorderAgentCounters::from_ot_counters(null_ptr) }.is_none());
463 }
464}