Skip to main content

openthread/ot/
backbone_router.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::prelude_internal::*;
6
7/// Iterator type for multicast listeners.
8#[allow(missing_debug_implementations)]
9pub struct MulticastListenerIterator<'a, T: ?Sized> {
10    ot_instance: &'a T,
11    ot_listener_iter: otBackboneRouterMulticastListenerIterator,
12}
13
14impl<T: ?Sized + BackboneRouter> Iterator for MulticastListenerIterator<'_, T> {
15    type Item = BackboneRouterMulticastListenerInfo;
16    fn next(&mut self) -> Option<Self::Item> {
17        self.ot_instance.multicast_listener_get_next(&mut self.ot_listener_iter)
18    }
19}
20
21/// Methods from the [OpenThread "Backbone Router" Module][1].
22/// Currently only multicast routing related methods are added.
23///
24/// [1]: https://openthread.io/reference/group/api-backbone-router
25pub trait BackboneRouter {
26    /// Functional equilvanet of
27    /// [`otsys::otBackboneRouterSetEnabled`](crate::otsys::otBackboneRouterSetEnabled).
28    fn set_backbone_router_enabled(&self, enable: bool);
29
30    /// Functional equivalent of
31    /// [`otsys::otBackboneRouterMulticastListenerGetNext`](crate::otsys::otBackboneRouterMulticastListenerGetNext).
32    // TODO: Determine if the underlying implementation of
33    //       this method has undefined behavior when network data
34    //       is being mutated while iterating. If it is undefined,
35    //       we may need to make it unsafe and provide a safe method
36    //       that collects the results.
37    fn multicast_listener_get_next(
38        &self,
39        listener_iter: &mut otBackboneRouterMulticastListenerIterator,
40    ) -> Option<BackboneRouterMulticastListenerInfo>;
41
42    /// Functional equivalent of
43    /// [`otsys::otBackboneRouterSetMulticastListenerCallback`](crate::otsys::otBackboneRouterSetMulticastListenerCallback).
44    fn set_multicast_listener_callback<'a, F>(&'a self, f: Option<F>)
45    where
46        F: FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a;
47
48    /// Returns an iterator for iterating over multicast listeners.
49    fn iter_multicast_listeners(&self) -> MulticastListenerIterator<'_, Self> {
50        MulticastListenerIterator {
51            ot_instance: self,
52            ot_listener_iter: OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT
53                .try_into()
54                .unwrap(),
55        }
56    }
57}
58
59impl<T: BackboneRouter + Boxable> BackboneRouter for ot::Box<T> {
60    fn set_backbone_router_enabled(&self, enable: bool) {
61        self.as_ref().set_backbone_router_enabled(enable)
62    }
63
64    fn multicast_listener_get_next(
65        &self,
66        listener_iter: &mut otBackboneRouterMulticastListenerIterator,
67    ) -> Option<BackboneRouterMulticastListenerInfo> {
68        self.as_ref().multicast_listener_get_next(listener_iter)
69    }
70
71    fn set_multicast_listener_callback<'a, F>(&'a self, f: Option<F>)
72    where
73        F: FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a,
74    {
75        self.as_ref().set_multicast_listener_callback(f)
76    }
77}
78
79impl BackboneRouter for Instance {
80    fn set_backbone_router_enabled(&self, enable: bool) {
81        unsafe { otBackboneRouterSetEnabled(self.as_ot_ptr(), enable) }
82    }
83
84    fn multicast_listener_get_next(
85        &self,
86        listener_iter: &mut otBackboneRouterMulticastListenerIterator,
87    ) -> Option<BackboneRouterMulticastListenerInfo> {
88        unsafe {
89            let mut ret = BackboneRouterMulticastListenerInfo::default();
90            match Error::from(otBackboneRouterMulticastListenerGetNext(
91                self.as_ot_ptr(),
92                listener_iter as *mut otBackboneRouterMulticastListenerIterator,
93                ret.as_ot_mut_ptr(),
94            )) {
95                Error::NotFound => None,
96                Error::None => Some(ret),
97                err => {
98                    // If something's wrong in OpenThread when iterate multicast listeners,
99                    // do not crash `lowpan-ot-driver`.
100                    warn!(
101                        "Unexpected error from otBackboneRouterMulticastListenerIterator: {err:?}"
102                    );
103                    None
104                }
105            }
106        }
107    }
108
109    fn set_multicast_listener_callback<'a, F>(&'a self, f: Option<F>)
110    where
111        F: FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a,
112    {
113        unsafe extern "C" fn _ot_backbone_router_multicast_listener_callback<
114            'a,
115            F: FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a,
116        >(
117            context: *mut ::std::os::raw::c_void,
118            event: otBackboneRouterMulticastListenerEvent,
119            address: *const otIp6Address,
120        ) {
121            trace!("_ot_backbone_router_multicast_listener_callback");
122
123            // Convert the `*otIp6Address` into an `&ot::Ip6AddressInfo`.
124            let address = unsafe { Ip6Address::ref_from_ot_ptr(address).unwrap() };
125
126            // Convert `otBackboneRouterMulticastListenerCallback` to
127            // `BackboneRouterMulticastListenerEvent`
128            let event = BackboneRouterMulticastListenerEvent::from(event);
129
130            // Reconstitute a reference to our closure.
131            let sender = unsafe { &mut *(context as *mut F) };
132
133            sender(event, address)
134        }
135
136        let (fn_ptr, fn_box, cb): (_, _, otBackboneRouterMulticastListenerCallback) =
137            if let Some(f) = f {
138                let mut x = Box::new(f);
139
140                (
141                    x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
142                    Some(
143                        x as Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a>,
144                    ),
145                    Some(_ot_backbone_router_multicast_listener_callback::<F>),
146                )
147            } else {
148                (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
149            };
150
151        unsafe {
152            otBackboneRouterSetMulticastListenerCallback(self.as_ot_ptr(), cb, fn_ptr);
153
154            // Make sure our object eventually gets cleaned up.
155            // Here we must also transmute our closure to have a 'static lifetime.
156            // We need to do this because the borrow checker cannot infer the
157            // proper lifetime for the singleton instance backing, but
158            // this is guaranteed by the API.
159            self.borrow_backing().multicast_listener_callback.set(std::mem::transmute::<
160                Option<Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'a>>,
161                Option<Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address) + 'static>>,
162            >(fn_box));
163        }
164    }
165}