Skip to main content

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_traits::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/// Iterates over the [`NetifMulticastAddress`] structs from [`Ip6::ip6_get_multicast_addresses()`].
60#[derive(Default, Debug, Clone)]
61pub struct NetifMulticastAddressIterator<'a>(Option<&'a NetifMulticastAddress>);
62
63impl<'a> Iterator for NetifMulticastAddressIterator<'a> {
64    type Item = &'a NetifMulticastAddress;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        if let Some(addr_ref) = self.0 {
68            // SAFETY: The `otNetifMulticastAddress` pointer used here comes
69            //         from `otIp6GetMulticastAddresses`, which is guaranteed
70            //         to have valid values for `mNext`.
71            self.0 = unsafe { NetifMulticastAddress::ref_from_ot_ptr(addr_ref.0.mNext) };
72            Some(addr_ref)
73        } else {
74            None
75        }
76    }
77}
78
79/// Methods from the [OpenThread "IPv6" Module](https://openthread.io/reference/group/api-ip6).
80pub trait Ip6 {
81    /// Functional equivalent of [`otsys::otIp6Send`](crate::otsys::otIp6Send).
82    ///
83    /// Returns [`Error::InvalidArgs`] if the message origin is
84    /// [`Origin::ThreadNetif`](ot::message::Origin::ThreadNetif).
85    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result;
86
87    /// Similar to [`ip6_send()`], but takes a byte slice instead
88    /// of an [`OtMessageBox`](crate::OtMessageBox).
89    ///
90    /// `origin` tells OpenThread where the packet came from, which determines
91    /// the security checks it applies. Packets from a host network stack that
92    /// may forward traffic from the infrastructure network must use
93    /// [`Origin::HostUntrusted`](ot::message::Origin::HostUntrusted).
94    /// Returns [`Error::InvalidArgs`] for
95    /// [`Origin::ThreadNetif`](ot::message::Origin::ThreadNetif).
96    fn ip6_send_data(&self, data: &[u8], origin: ot::message::Origin) -> Result;
97
98    /// Similar to [`ip6_send_data()`], but sends the packet without layer-2 security.
99    fn ip6_send_data_direct(&self, data: &[u8], origin: ot::message::Origin) -> Result;
100
101    /// Functional equivalent of [`otsys::otIp6IsEnabled`](crate::otsys::otIp6IsEnabled).
102    fn ip6_is_enabled(&self) -> bool;
103
104    /// Functional equivalent of [`otsys::otIp6SetEnabled`](crate::otsys::otIp6SetEnabled).
105    fn ip6_set_enabled(&self, enabled: bool) -> Result;
106
107    /// Functional equivalent of
108    /// [`otsys::otIp6AddUnicastAddress`](crate::otsys::otIp6AddUnicastAddress).
109    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result;
110
111    /// Functional equivalent of
112    /// [`otsys::otIp6RemoveUnicastAddress`](crate::otsys::otIp6RemoveUnicastAddress).
113    fn ip6_remove_unicast_address(&self, addr: &Ip6Address) -> Result;
114
115    /// Functional equivalent of
116    /// [`otsys::otIp6SubscribeMulticastAddress`](crate::otsys::otIp6SubscribeMulticastAddress).
117    fn ip6_join_multicast_group(&self, addr: &Ip6Address) -> Result;
118
119    /// Functional equivalent of
120    /// [`otsys::otIp6UnsubscribeMulticastAddress`](crate::otsys::otIp6UnsubscribeMulticastAddress).
121    fn ip6_leave_multicast_group(&self, addr: &Ip6Address) -> Result;
122
123    /// Sets the IPv6 receive callback closure. Functional equivalent of
124    /// [`otsys::otIp6SetReceiveCallback`](crate::otsys::otIp6SetReceiveCallback).
125    ///
126    /// The closure will ultimately be executed via
127    /// [`ot::Tasklets::process`](crate::ot::Tasklets::process).
128    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
129    where
130        F: FnMut(OtMessageBox<'_>) + 'a;
131
132    /// Sets the IPv6 address callback closure. Functional equivalent of
133    /// [`otsys::otIp6SetAddressCallback`](crate::otsys::otIp6SetAddressCallback).
134    ///
135    /// The closure takes two arguments:
136    ///
137    ///  * An instance of [`ot::Ip6AddressInfo`](crate::ot::Ip6AddressInfo).
138    ///  * A `bool` indicating if the address is being added (`true`) or removed (`false`).
139    ///
140    /// The closure will ultimately be executed via
141    /// [`ot::Tasklets::process`](crate::ot::Tasklets::process).
142    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
143    where
144        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a;
145
146    /// Functional equivalent of [`otsys::otIp6IsSlaacEnabled`](crate::otsys::otIp6IsSlaacEnabled).
147    fn ip6_is_slaac_enabled(&self) -> bool;
148
149    /// Functional equivalent of
150    /// [`otsys::otIp6SetSlaacEnabled`](crate::otsys::otIp6SetSlaacEnabled).
151    fn ip6_set_slaac_enabled(&self, enabled: bool);
152
153    /// Functional equivalent of
154    /// [`otsys::otIcmp6GetEchoMode`](crate::otsys::otIcmp6GetEchoMode).
155    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode;
156
157    /// Functional equivalent of
158    /// [`otsys::otIcmp6SetEchoMode`](crate::otsys::otIcmp6SetEchoMode).
159    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode);
160
161    /// Functional equivalent of
162    /// [`otsys::otIp6SetReceiveFilterEnabled`](crate::otsys::otIp6SetReceiveFilterEnabled).
163    fn ip6_set_receive_filter_enabled(&self, enabled: bool);
164
165    /// Functional equivalent of
166    /// [`otsys::otIp6IsReceiveFilterEnabled`](crate::otsys::otIp6IsReceiveFilterEnabled).
167    fn ip6_is_receive_filter_enabled(&self) -> bool;
168
169    /// Functional equivalent of
170    /// [`otsys::otIp6GetBorderRoutingCounters`](crate::otsys::otIp6GetBorderRoutingCounters).
171    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters;
172
173    /// Functional equivalent of
174    /// [`otsys::otIp6GetUnicastAddresses`](crate::otsys::otIp6GetUnicastAddresses).
175    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_>;
176
177    /// Functional equivalent of
178    /// [`otsys::otIp6GetMulticastAddresses`](crate::otsys::otIp6GetMulticastAddresses).
179    fn ip6_get_multicast_addresses(&self) -> NetifMulticastAddressIterator<'_>;
180}
181
182impl<T: Ip6 + ot::Boxable> Ip6 for ot::Box<T> {
183    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result<()> {
184        self.as_ref().ip6_send(message)
185    }
186
187    fn ip6_send_data(&self, data: &[u8], origin: ot::message::Origin) -> Result {
188        self.as_ref().ip6_send_data(data, origin)
189    }
190
191    fn ip6_send_data_direct(&self, data: &[u8], origin: ot::message::Origin) -> Result {
192        self.as_ref().ip6_send_data_direct(data, origin)
193    }
194
195    fn ip6_is_enabled(&self) -> bool {
196        self.as_ref().ip6_is_enabled()
197    }
198
199    fn ip6_set_enabled(&self, enabled: bool) -> Result {
200        self.as_ref().ip6_set_enabled(enabled)
201    }
202
203    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result {
204        self.as_ref().ip6_add_unicast_address(addr)
205    }
206
207    fn ip6_remove_unicast_address(&self, addr: &std::net::Ipv6Addr) -> Result {
208        self.as_ref().ip6_remove_unicast_address(addr)
209    }
210
211    fn ip6_join_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
212        self.as_ref().ip6_join_multicast_group(addr)
213    }
214
215    fn ip6_leave_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
216        self.as_ref().ip6_join_multicast_group(addr)
217    }
218
219    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
220    where
221        F: FnMut(OtMessageBox<'_>) + 'a,
222    {
223        self.as_ref().ip6_set_receive_fn(f)
224    }
225
226    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
227    where
228        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a,
229    {
230        self.as_ref().ip6_set_address_fn(f)
231    }
232
233    fn ip6_is_slaac_enabled(&self) -> bool {
234        self.as_ref().ip6_is_slaac_enabled()
235    }
236
237    fn ip6_set_slaac_enabled(&self, enabled: bool) {
238        self.as_ref().ip6_set_slaac_enabled(enabled);
239    }
240
241    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode {
242        self.as_ref().icmp6_get_echo_mode()
243    }
244
245    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode) {
246        self.as_ref().icmp6_set_echo_mode(mode)
247    }
248
249    fn ip6_set_receive_filter_enabled(&self, enabled: bool) {
250        self.as_ref().ip6_set_receive_filter_enabled(enabled);
251    }
252
253    fn ip6_is_receive_filter_enabled(&self) -> bool {
254        self.as_ref().ip6_is_receive_filter_enabled()
255    }
256
257    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters {
258        self.as_ref().ip6_get_border_routing_counters()
259    }
260
261    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_> {
262        self.as_ref().ip6_get_unicast_addresses()
263    }
264
265    fn ip6_get_multicast_addresses(&self) -> NetifMulticastAddressIterator<'_> {
266        self.as_ref().ip6_get_multicast_addresses()
267    }
268}
269
270impl Ip6 for Instance {
271    fn ip6_send(&self, message: OtMessageBox<'_>) -> Result {
272        // `otIp6Send()` rejects messages originating from the Thread netif
273        // without taking ownership of them, which would leak the message once
274        // `take_ot_ptr()` has been called. Reject them here instead so that
275        // `message` is dropped (and freed) normally.
276        if message.origin() == ot::message::Origin::ThreadNetif {
277            return Err(Error::InvalidArgs);
278        }
279        Error::from(unsafe { otIp6Send(self.as_ot_ptr(), message.take_ot_ptr()) }).into()
280    }
281
282    fn ip6_send_data(&self, data: &[u8], origin: ot::message::Origin) -> Result {
283        if origin == ot::message::Origin::ThreadNetif {
284            return Err(Error::InvalidArgs);
285        }
286        if let Ok(mut msg) = Message::ip6_new_from_bytes(self, data, None) {
287            msg.set_origin(origin);
288            self.ip6_send(msg)
289        } else if self.get_buffer_info().0.mFreeBuffers == 0 {
290            Err(ot::Error::NoBufs)
291        } else {
292            Err(ot::Error::Failed)
293        }
294    }
295
296    fn ip6_send_data_direct(&self, data: &[u8], origin: ot::message::Origin) -> Result {
297        if origin == ot::message::Origin::ThreadNetif {
298            return Err(Error::InvalidArgs);
299        }
300        if let Ok(mut msg) = Message::ip6_new_from_bytes(self, data, None) {
301            msg.set_direct_transmission(true);
302            msg.set_origin(origin);
303            self.ip6_send(msg)
304        } else if self.get_buffer_info().0.mFreeBuffers == 0 {
305            Err(ot::Error::NoBufs)
306        } else {
307            Err(ot::Error::Failed)
308        }
309    }
310
311    fn ip6_is_enabled(&self) -> bool {
312        unsafe { otIp6IsEnabled(self.as_ot_ptr()) }
313    }
314
315    fn ip6_set_enabled(&self, enabled: bool) -> Result {
316        Error::from(unsafe { otIp6SetEnabled(self.as_ot_ptr(), enabled) }).into()
317    }
318
319    fn ip6_add_unicast_address(&self, addr: &NetifAddress) -> Result {
320        Error::from(unsafe { otIp6AddUnicastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) }).into()
321    }
322
323    fn ip6_remove_unicast_address(&self, addr: &std::net::Ipv6Addr) -> Result {
324        Error::from(unsafe { otIp6RemoveUnicastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) }).into()
325    }
326
327    fn ip6_join_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
328        Error::from(unsafe { otIp6SubscribeMulticastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) })
329            .into()
330    }
331
332    fn ip6_leave_multicast_group(&self, addr: &std::net::Ipv6Addr) -> Result {
333        Error::from(unsafe { otIp6UnsubscribeMulticastAddress(self.as_ot_ptr(), addr.as_ot_ptr()) })
334            .into()
335    }
336
337    fn ip6_set_receive_fn<'a, F>(&'a self, f: Option<F>)
338    where
339        F: FnMut(OtMessageBox<'_>) + 'a,
340    {
341        unsafe extern "C" fn _ot_ip6_receive_callback<'a, F: FnMut(OtMessageBox<'_>) + 'a>(
342            message: *mut otMessage,
343            context: *mut ::std::os::raw::c_void,
344        ) {
345            trace!("_ot_ip6_receive_callback");
346
347            // Convert the `*otMessage` into an `ot::Box<ot::Message>`.
348            let message = unsafe { OtMessageBox::from_ot_ptr(message) }
349                .expect("_ot_ip6_receive_callback: Got NULL otMessage");
350
351            // Reconstitute a reference to our closure.
352            let sender = unsafe { &mut *(context as *mut F) };
353
354            sender(message)
355        }
356
357        let (fn_ptr, fn_box, cb): (_, _, otIp6ReceiveCallback) = if let Some(f) = f {
358            let mut x = Box::new(f);
359
360            (
361                x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
362                Some(x as Box<dyn FnMut(OtMessageBox<'_>) + 'a>),
363                Some(_ot_ip6_receive_callback::<F>),
364            )
365        } else {
366            (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
367        };
368
369        unsafe {
370            otIp6SetReceiveCallback(self.as_ot_ptr(), cb, fn_ptr);
371
372            // Make sure our object eventually gets cleaned up.
373            // Here we must also transmute our closure to have a 'static lifetime.
374            // We need to do this because the borrow checker cannot infer the
375            // proper lifetime for the singleton instance backing, but
376            // this is guaranteed by the API.
377            self.borrow_backing().ip6_receive_fn.set(std::mem::transmute::<
378                Option<Box<dyn FnMut(OtMessageBox<'_>) + 'a>>,
379                Option<Box<dyn FnMut(OtMessageBox<'_>) + 'static>>,
380            >(fn_box));
381        }
382    }
383
384    fn ip6_set_address_fn<'a, F>(&'a self, f: Option<F>)
385    where
386        F: for<'r> FnMut(Ip6AddressInfo<'r>, bool) + 'a,
387    {
388        unsafe extern "C" fn _ot_ip6_address_callback<
389            'a,
390            F: FnMut(Ip6AddressInfo<'_>, bool) + 'a,
391        >(
392            info: *const otIp6AddressInfo,
393            is_added: bool,
394            context: *mut ::std::os::raw::c_void,
395        ) {
396            trace!("_ot_ip6_address_callback");
397
398            // Convert the `*otIp6AddressInfo` into an `&ot::Ip6AddressInfo`.
399            let info = unsafe { *Ip6AddressInfo::ref_from_ot_ptr(info).unwrap() };
400
401            // Reconstitute a reference to our closure.
402            let sender = unsafe { &mut *(context as *mut F) };
403
404            sender(info, is_added)
405        }
406
407        let (fn_ptr, fn_box, cb): (_, _, otIp6AddressCallback) = if let Some(f) = f {
408            let mut x = Box::new(f);
409
410            (
411                x.as_mut() as *mut F as *mut ::std::os::raw::c_void,
412                Some(x as Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'a>),
413                Some(_ot_ip6_address_callback::<F>),
414            )
415        } else {
416            (std::ptr::null_mut() as *mut ::std::os::raw::c_void, None, None)
417        };
418
419        unsafe {
420            otIp6SetAddressCallback(self.as_ot_ptr(), cb, fn_ptr);
421
422            // Make sure our object eventually gets cleaned up.
423            // Here we must also transmute our closure to have a 'static lifetime.
424            // We need to do this because the borrow checker cannot infer the
425            // proper lifetime for the singleton instance backing, but
426            // this is guaranteed by the API.
427            self.borrow_backing().ip6_address_fn.set(std::mem::transmute::<
428                Option<Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'a>>,
429                Option<Box<dyn FnMut(Ip6AddressInfo<'_>, bool) + 'static>>,
430            >(fn_box));
431        }
432    }
433
434    fn ip6_is_slaac_enabled(&self) -> bool {
435        unsafe { otIp6IsSlaacEnabled(self.as_ot_ptr()) }
436    }
437
438    fn ip6_set_slaac_enabled(&self, enabled: bool) {
439        unsafe { otIp6SetSlaacEnabled(self.as_ot_ptr(), enabled) }
440    }
441
442    fn icmp6_get_echo_mode(&self) -> Icmp6EchoMode {
443        unsafe { otIcmp6GetEchoMode(self.as_ot_ptr()) }.into()
444    }
445
446    fn icmp6_set_echo_mode(&self, mode: Icmp6EchoMode) {
447        unsafe { otIcmp6SetEchoMode(self.as_ot_ptr(), mode.into()) }
448    }
449
450    fn ip6_set_receive_filter_enabled(&self, enabled: bool) {
451        unsafe { otIp6SetReceiveFilterEnabled(self.as_ot_ptr(), enabled) }
452    }
453
454    fn ip6_is_receive_filter_enabled(&self) -> bool {
455        unsafe { otIp6IsReceiveFilterEnabled(self.as_ot_ptr()) }
456    }
457
458    fn ip6_get_border_routing_counters(&self) -> &BorderRoutingCounters {
459        unsafe {
460            BorderRoutingCounters::ref_from_ot_ptr(otIp6GetBorderRoutingCounters(self.as_ot_ptr()))
461                .unwrap()
462        }
463    }
464
465    fn ip6_get_unicast_addresses(&self) -> NetifAddressIterator<'_> {
466        NetifAddressIterator(unsafe {
467            NetifAddress::ref_from_ot_ptr(otIp6GetUnicastAddresses(self.as_ot_ptr()))
468        })
469    }
470
471    fn ip6_get_multicast_addresses(&self) -> NetifMulticastAddressIterator<'_> {
472        NetifMulticastAddressIterator(unsafe {
473            NetifMulticastAddress::ref_from_ot_ptr(otIp6GetMulticastAddresses(self.as_ot_ptr()))
474        })
475    }
476}