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 unsafe { 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 = unsafe { &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 = unsafe { &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 key_string: String = key.iter().map(|digit| digit.to_string()).collect();
378
379 let mut checksum_char: c_char = 0;
381 let decimal_string = CString::new(key_string)
382 .map_err(|e| format_err!("Ephemeral key string contains a null byte:: {}", e))?;
383 let checksum_result = unsafe {
384 otVerhoeffChecksumCalculate(decimal_string.as_ptr(), &mut checksum_char as *mut c_char)
385 };
386 ot::Error::from(checksum_result)
387 .into_result()
388 .map_err(|e| format_err!("Verhoeff checksum calculation failed: {}", e))?;
389
390 key.push(checksum_char as u8);
391 CString::new(key).map_err(|e| format_err!("Ephemeral key is not a valid string: {}", e))
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_counter_conversion_succeeds() {
400 let epskc_activations = 0;
401 let epskc_deactivation_clears = 1;
402 let epskc_deactivation_timeouts = 2;
403 let epskc_deactivation_max_attempts = 3;
404 let epskc_deactivation_disconnects = 4;
405 let epskc_invalid_ba_state_errors = 5;
406 let epskc_invalid_args_errors = 6;
407 let epskc_start_secure_session_errors = 7;
408 let epskc_secure_session_successes = 8;
409 let epskc_secure_session_failures = 9;
410 let epskc_commissioner_petitions = 10;
411 let pskc_secure_session_successes = 11;
412 let pskc_secure_session_failures = 12;
413 let pskc_commissioner_petitions = 13;
414 let mgmt_active_gets = 14;
415 let mgmt_pending_gets = 15;
416
417 let ot_counters = otBorderAgentCounters {
418 mEpskcActivations: epskc_activations,
419 mEpskcDeactivationClears: epskc_deactivation_clears,
420 mEpskcDeactivationTimeouts: epskc_deactivation_timeouts,
421 mEpskcDeactivationMaxAttempts: epskc_deactivation_max_attempts,
422 mEpskcDeactivationDisconnects: epskc_deactivation_disconnects,
423 mEpskcInvalidBaStateErrors: epskc_invalid_ba_state_errors,
424 mEpskcInvalidArgsErrors: epskc_invalid_args_errors,
425 mEpskcStartSecureSessionErrors: epskc_start_secure_session_errors,
426 mEpskcSecureSessionSuccesses: epskc_secure_session_successes,
427 mEpskcSecureSessionFailures: epskc_secure_session_failures,
428 mEpskcCommissionerPetitions: epskc_commissioner_petitions,
429 mPskcSecureSessionSuccesses: pskc_secure_session_successes,
430 mPskcSecureSessionFailures: pskc_secure_session_failures,
431 mPskcCommissionerPetitions: pskc_commissioner_petitions,
432 mMgmtActiveGets: mgmt_active_gets,
433 mMgmtPendingGets: mgmt_pending_gets,
434 };
435
436 let ot_counters_ptr: *const otBorderAgentCounters = &ot_counters;
437
438 let converted_counters = unsafe { BorderAgentCounters::from_ot_counters(ot_counters_ptr) }
439 .expect("Failed to convert OT Border Agent counters");
440
441 assert_eq!(
442 converted_counters,
443 BorderAgentCounters {
444 epskc_activations,
445 epskc_deactivation_clears,
446 epskc_deactivation_timeouts,
447 epskc_deactivation_max_attempts,
448 epskc_deactivation_disconnects,
449 epskc_invalid_ba_state_errors,
450 epskc_invalid_args_errors,
451 epskc_start_secure_session_errors,
452 epskc_secure_session_successes,
453 epskc_secure_session_failures,
454 epskc_commissioner_petitions,
455 pskc_secure_session_successes,
456 pskc_secure_session_failures,
457 pskc_commissioner_petitions,
458 mgmt_active_gets,
459 mgmt_pending_gets,
460 }
461 );
462 }
463
464 #[test]
465 fn test_counter_conversion_fails() {
466 let null_ptr: *const otBorderAgentCounters = std::ptr::null();
467 assert!(unsafe { BorderAgentCounters::from_ot_counters(null_ptr) }.is_none());
468 }
469}