openthread/ot/
ip6.rs

1// Copyright 2021 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/// Functional equivalent of [`otsys::otIcmp6EchoMode`](crate::otsys::otIcmp6EchoMode).
8#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, num_derive::FromPrimitive)]
9pub enum Icmp6EchoMode {
10    /// ICMPv6 Echo processing enabled for unicast and multicast requests.
11    HandleAll = OT_ICMP6_ECHO_HANDLER_ALL as isize,
12
13    /// ICMPv6 Echo processing disabled.
14    HandleDisabled = OT_ICMP6_ECHO_HANDLER_DISABLED as isize,
15
16    /// ICMPv6 Echo processing enabled only for multicast requests only.
17    HandleMulticastOnly = OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY as isize,
18
19    /// ICMPv6 Echo processing enabled only for unicast requests only.
20    HandleUnicastOnly = OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY as isize,
21
22    /// ICMPv6 Echo processing enabled for RLOC/ALOC destinations only
23    HandleRlocAlocOnly = OT_ICMP6_ECHO_HANDLER_RLOC_ALOC_ONLY as isize,
24}
25
26impl From<otIcmp6EchoMode> for Icmp6EchoMode {
27    fn from(x: otIcmp6EchoMode) -> Self {
28        use num::FromPrimitive;
29        Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otIcmp6EchoMode value: {x}"))
30    }
31}
32
33impl From<Icmp6EchoMode> for otIcmp6EchoMode {
34    fn from(x: Icmp6EchoMode) -> Self {
35        x as otIcmp6EchoMode
36    }
37}
38
39/// Iterates over the [`NetifAddress`] structs from [`Ip6::ip6_get_unicast_addresses()`].
40#[derive(Default, Debug, Clone)]
41pub struct NetifAddressIterator<'a>(Option<&'a NetifAddress>);
42
43impl<'a> Iterator for NetifAddressIterator<'a> {
44    type Item = &'a NetifAddress;
45
46    fn next(&mut self) -> Option<Self::Item> {
47        if let Some(addr_ref) = self.0 {
48            // SAFETY: The `otNetifAddress` pointer used here comes
49            //         from `otIp6GetUnicastAddresses`, which is guaranteed
50            //         to have valid values for `mNext`.
51            self.0 = unsafe { NetifAddress::ref_from_ot_ptr(addr_ref.0.mNext) };
52            Some(addr_ref)
53        } else {
54            None
55        }
56    }
57}
58
59/// Methods from the [OpenThread "IPv6" Module](https://openthread.io/reference/group/api-ip6).
60pub trait Ip6 {
61    /// Functional equivalent of [`otsys::otIp6Send`](crate::otsys::otIp6Send).
62    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result;
63
64    /// Similar to [`ip6_send()`], but takes a byte slice instead
65    /// of an [`OtMessageBox`](crate::OtMessageBox).
66    fn ip6_send_data(&self, data: &[u8]) -> Result;
67
68    /// Similar to [`ip6_send_data()`], but sends the packet without layer-2 security.
69    fn ip6_send_data_direct(&self, data: &[u8]) -> Result;
70
71    /// Functional equivalent of [`otsys::otIp6IsEnabled`](crate::otsys::otIp6IsEnabled).
72    fn ip6_is_enabled(&self) -> bool;
73
74    /// Functional equivalent of [`otsys::otIp6SetEnabled`](crate::otsys::otIp6SetEnabled).
75    fn ip6_set_enabled(&self, enabled: bool) -> Result;
76
77    /// Functional equivalent of
78    /// [`otsys::otIp6AddUnicastAddress`](crate::otsys::otIp6AddUnicastAddress).
79    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result;
80
81    /// Functional equivalent of
82    /// [`otsys::otIp6RemoveUnicastAddress`](crate::otsys::otIp6RemoveUnicastAddress).
83    fn ip6_remove_unicast_address(&self, addr: &Ip6Address) -> Result;
84
85    /// Functional equivalent of
86    /// [`otsys::otIp6SubscribeMulticastAddress`](crate::otsys::otIp6SubscribeMulticastAddress).
87    fn ip6_join_multicast_group(&self, addr: &Ip6Address) -> Result;
88
89    /// Functional equivalent of
90    /// [`otsys::otIp6UnsubscribeMulticastAddress`](crate::otsys::otIp6UnsubscribeMulticastAddress).
91    fn ip6_leave_multicast_group(&self, addr: &Ip6Address) -> Result;
92
93    /// Sets the IPv6 receive callback closure. Functional equivalent of
94    /// [`otsys::otIp6SetReceiveCallback`](crate::otsys::otIp6SetReceiveCallback).
95    ///
96    /// The closure will ultimately be executed via
97    /// [`ot::Tasklets::process`](crate::ot::Tasklets::process).
98    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
99    where
100        F: FnMut(OtMessageBox<'_>) + 'a;
101
102    /// Sets the IPv6 address callback closure. Functional equivalent of
103    /// [`otsys::otIp6SetAddressCallback`](crate::otsys::otIp6SetAddressCallback).
104    ///
105    /// The closure takes two arguments:
106    ///
107    ///  * An instance of [`ot::Ip6AddressInfo`](crate::ot::Ip6AddressInfo).
108    ///  * A `bool` indicating if the address is being added (`true`) or removed (`false`).
109    ///
110    /// The closure will ultimately be executed via
111    /// [`ot::Tasklets::process`](crate::ot::Tasklets::process).
112    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
113    where
114        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a;
115
116    /// Functional equivalent of [`otsys::otIp6IsSlaacEnabled`](crate::otsys::otIp6IsSlaacEnabled).
117    fn ip6_is_slaac_enabled(&self) -> bool;
118
119    /// Functional equivalent of
120    /// [`otsys::otIp6SetSlaacEnabled`](crate::otsys::otIp6SetSlaacEnabled).
121    fn ip6_set_slaac_enabled(&self, enabled: bool);
122
123    /// Functional equivalent of
124    /// [`otsys::otIcmp6GetEchoMode`](crate::otsys::otIcmp6GetEchoMode).
125    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode;
126
127    /// Functional equivalent of
128    /// [`otsys::otIcmp6SetEchoMode`](crate::otsys::otIcmp6SetEchoMode).
129    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode);
130
131    /// Functional equivalent of
132    /// [`otsys::otIp6SetReceiveFilterEnabled`](crate::otsys::otIp6SetReceiveFilterEnabled).
133    fn ip6_set_receive_filter_enabled(&self, enabled: bool);
134
135    /// Functional equivalent of
136    /// [`otsys::otIp6IsReceiveFilterEnabled`](crate::otsys::otIp6IsReceiveFilterEnabled).
137    fn ip6_is_receive_filter_enabled(&self) -> bool;
138
139    /// Functional equivalent of
140    /// [`otsys::otIp6GetBorderRoutingCounters`](crate::otsys::otIp6GetBorderRoutingCounters).
141    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters;
142
143    /// Functional equivalent of
144    /// [`otsys::otIp6GetUnicastAddresses`](crate::otsys::otIp6GetUnicastAddresses).
145    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_>;
146}
147
148impl<T: Ip6 + ot::Boxable> Ip6 for ot::Box<T> {
149    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result<()> {
150        self.as_ref().ip6_send(message)
151    }
152
153    fn ip6_send_data(&self, data: &[u8]) -> Result {
154        self.as_ref().ip6_send_data(data)
155    }
156
157    fn ip6_send_data_direct(&self, data: &[u8]) -> Result {
158        self.as_ref().ip6_send_data_direct(data)
159    }
160
161    fn ip6_is_enabled(&self) -> bool {
162        self.as_ref().ip6_is_enabled()
163    }
164
165    fn ip6_set_enabled(&self, enabled: bool) -> Result {
166        self.as_ref().ip6_set_enabled(enabled)
167    }
168
169    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result {
170        self.as_ref().ip6_add_unicast_address(addr)
171    }
172
173    fn ip6_remove_unicast_address(&self, addr: &std::net::Ipv6Addr) -> Result {
174        self.as_ref().ip6_remove_unicast_address(addr)
175    }
176
177    fn ip6_join_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
178        self.as_ref().ip6_join_multicast_group(addr)
179    }
180
181    fn ip6_leave_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
182        self.as_ref().ip6_join_multicast_group(addr)
183    }
184
185    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
186    where
187        F: FnMut(OtMessageBox<'_>) + 'a,
188    {
189        self.as_ref().ip6_set_receive_fn(f)
190    }
191
192    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
193    where
194        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a,
195    {
196        self.as_ref().ip6_set_address_fn(f)
197    }
198
199    fn ip6_is_slaac_enabled(&self) -> bool {
200        self.as_ref().ip6_is_slaac_enabled()
201    }
202
203    fn ip6_set_slaac_enabled(&self, enabled: bool) {
204        self.as_ref().ip6_set_slaac_enabled(enabled);
205    }
206
207    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode {
208        self.as_ref().icmp6_get_echo_mode()
209    }
210
211    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode) {
212        self.as_ref().icmp6_set_echo_mode(mode)
213    }
214
215    fn ip6_set_receive_filter_enabled(&self, enabled: bool) {
216        self.as_ref().ip6_set_receive_filter_enabled(enabled);
217    }
218
219    fn ip6_is_receive_filter_enabled(&self) -> bool {
220        self.as_ref().ip6_is_receive_filter_enabled()
221    }
222
223    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters {
224        self.as_ref().ip6_get_border_routing_counters()
225    }
226
227    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_> {
228        self.as_ref().ip6_get_unicast_addresses()
229    }
230}
231
232impl Ip6 for Instance {
233    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result {
234        Error::from(unsafe { otIp6Send(self.as_ot_ptr(), message.take_ot_ptr()) }).into()
235    }
236
237    fn ip6_send_data(&self, data: &[u8]) -> Result {
238        if let Ok(msg) = Message::ip6_new_from_bytes(self, data, None) {
239            self.ip6_send(msg)
240        } else if self.get_buffer_info().0.mFreeBuffers == 0 {
241            Err(ot::Error::NoBufs)
242        } else {
243            Err(ot::Error::Failed)
244        }
245    }
246
247    fn ip6_send_data_direct(&self, data: &[u8]) -> Result {
248        if let Ok(mut msg) = Message::ip6_new_from_bytes(self, data, None) {
249            msg.set_direct_transmission(true);
250            self.ip6_send(msg)
251        } else if self.get_buffer_info().0.mFreeBuffers == 0 {
252            Err(ot::Error::NoBufs)
253        } else {
254            Err(ot::Error::Failed)
255        }
256    }
257
258    fn ip6_is_enabled(&self) -> bool {
259        unsafe { otIp6IsEnabled(self.as_ot_ptr()) }
260    }
261
262    fn ip6_set_enabled(&self, enabled: bool) -> Result {
263        Error::from(unsafe { otIp6SetEnabled(self.as_ot_ptr(), enabled) }).into()
264    }
265
266    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result {
267        Error::from(unsafe { otIp6AddUnicastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) }).into()
268    }
269
270    fn ip6_remove_unicast_address(&self, addr: &std::net::Ipv6Addr) -> Result {
271        Error::from(unsafe { otIp6RemoveUnicastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) }).into()
272    }
273
274    fn ip6_join_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
275        Error::from(unsafe { otIp6SubscribeMulticastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) })
276            .into()
277    }
278
279    fn ip6_leave_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
280        Error::from(unsafe { otIp6UnsubscribeMulticastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) })
281            .into()
282    }
283
284    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
285    where
286        F: FnMut(OtMessageBox<'_>) + 'a,
287    {
288        unsafe extern "C" fn _ot_ip6_receive_callback<'a, F: FnMut(OtMessageBox<'_>) + 'a>(
289            message: *mut otMessage,
290            context: *mut ::std::os::raw::c_void,
291        ) {
292            trace!("_ot_ip6_receive_callback");
293
294            // Convert the `*otMessage` into an `ot::Box<ot::Message>`.
295            let message = OtMessageBox::from_ot_ptr(message)
296                .expect("_ot_ip6_receive_callback: Got NULL otMessage");
297
298            // Reconstitute a reference to our closure.
299            let sender = &mut *(context as *mut F);
300
301            sender(message)
302        }
303
304        let (fn_ptr, fn_box, cb): (_, _, otIp6ReceiveCallback) = if let Some(f) = f {
305            let mut x = Box::new(f);
306
307            (
308                x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
309                Some(x as Box<dyn FnMut(OtMessageBox<'_>) + 'a>),
310                Some(_ot_ip6_receive_callback::<F>),
311            )
312        } else {
313            (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
314        };
315
316        unsafe {
317            otIp6SetReceiveCallback(self.as_ot_ptr(), cb, fn_ptr);
318
319            // Make sure our object eventually gets cleaned up.
320            // Here we must also transmute our closure to have a 'static lifetime.
321            // We need to do this because the borrow checker cannot infer the
322            // proper lifetime for the singleton instance backing, but
323            // this is guaranteed by the API.
324            self.borrow_backing().ip6_receive_fn.set(std::mem::transmute::<
325                Option<Box<dyn FnMut(OtMessageBox<'_>) + 'a>>,
326                Option<Box<dyn FnMut(OtMessageBox<'_>) + 'static>>,
327            >(fn_box));
328        }
329    }
330
331    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
332    where
333        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a,
334    {
335        unsafe extern "C" fn _ot_ip6_address_callback<
336            'a,
337            F: FnMut(Ip6AddressInfo<'_>, bool) + 'a,
338        >(
339            info: *const otIp6AddressInfo,
340            is_added: bool,
341            context: *mut ::std::os::raw::c_void,
342        ) {
343            trace!("_ot_ip6_address_callback");
344
345            // Convert the `*otIp6AddressInfo` into an `&ot::Ip6AddressInfo`.
346            let info = *Ip6AddressInfo::ref_from_ot_ptr(info).unwrap();
347
348            // Reconstitute a reference to our closure.
349            let sender = &mut *(context as *mut F);
350
351            sender(info, is_added)
352        }
353
354        let (fn_ptr, fn_box, cb): (_, _, otIp6AddressCallback) = if let Some(f) = f {
355            let mut x = Box::new(f);
356
357            (
358                x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
359                Some(x as Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'a>),
360                Some(_ot_ip6_address_callback::<F>),
361            )
362        } else {
363            (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
364        };
365
366        unsafe {
367            otIp6SetAddressCallback(self.as_ot_ptr(), cb, fn_ptr);
368
369            // Make sure our object eventually gets cleaned up.
370            // Here we must also transmute our closure to have a 'static lifetime.
371            // We need to do this because the borrow checker cannot infer the
372            // proper lifetime for the singleton instance backing, but
373            // this is guaranteed by the API.
374            self.borrow_backing().ip6_address_fn.set(std::mem::transmute::<
375                Option<Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'a>>,
376                Option<Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'static>>,
377            >(fn_box));
378        }
379    }
380
381    fn ip6_is_slaac_enabled(&self) -> bool {
382        unsafe { otIp6IsSlaacEnabled(self.as_ot_ptr()) }
383    }
384
385    fn ip6_set_slaac_enabled(&self, enabled: bool) {
386        unsafe { otIp6SetSlaacEnabled(self.as_ot_ptr(), enabled) }
387    }
388
389    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode {
390        unsafe { otIcmp6GetEchoMode(self.as_ot_ptr()) }.into()
391    }
392
393    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode) {
394        unsafe { otIcmp6SetEchoMode(self.as_ot_ptr(), mode.into()) }
395    }
396
397    fn ip6_set_receive_filter_enabled(&self, enabled: bool) {
398        unsafe { otIp6SetReceiveFilterEnabled(self.as_ot_ptr(), enabled) }
399    }
400
401    fn ip6_is_receive_filter_enabled(&self) -> bool {
402        unsafe { otIp6IsReceiveFilterEnabled(self.as_ot_ptr()) }
403    }
404
405    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters {
406        unsafe {
407            BorderRoutingCounters::ref_from_ot_ptr(otIp6GetBorderRoutingCounters(self.as_ot_ptr()))
408                .unwrap()
409        }
410    }
411
412    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_> {
413        NetifAddressIterator(unsafe {
414            NetifAddress::ref_from_ot_ptr(otIp6GetUnicastAddresses(self.as_ot_ptr()))
415        })
416    }
417}