Skip to main content

openthread/ot/
message.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
5//! Module for all things related to OpenThread messages.
6
7use crate::prelude_internal::*;
8use num_derive::FromPrimitive;
9
10/// Message Priority.
11/// Functional equivalent of [`otsys::otMessagePriority`](crate::otsys::otMessagePriority).
12#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, FromPrimitive)]
13pub enum Priority {
14    /// Low message priority.
15    /// Equivalent to [`crate::otsys::OT_MESSAGE_PRIORITY_LOW`]
16    Low = OT_MESSAGE_PRIORITY_LOW as isize,
17
18    /// Normal message priority.
19    /// Equivalent to [`crate::otsys::OT_MESSAGE_PRIORITY_NORMAL`]
20    ///
21    /// This is the default priority.
22    Normal = OT_MESSAGE_PRIORITY_NORMAL as isize,
23
24    /// High message priority.
25    /// Equivalent to [`crate::otsys::OT_MESSAGE_PRIORITY_HIGH`]
26    High = OT_MESSAGE_PRIORITY_HIGH as isize,
27}
28
29impl Default for Priority {
30    /// The default priority is `Priority::Normal`.
31    fn default() -> Self {
32        Priority::Normal
33    }
34}
35
36impl Priority {
37    /// Returns value as a [`otsys::otMessagePriority`](crate::otsys::otMessagePriority).
38    pub fn as_ot_message_priority(self) -> otMessagePriority {
39        self as otMessagePriority
40    }
41}
42
43impl From<otMessagePriority> for Priority {
44    fn from(x: otMessagePriority) -> Self {
45        use num_traits::FromPrimitive;
46        Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otMessagePriority value: {x}"))
47    }
48}
49
50impl From<Priority> for otMessagePriority {
51    fn from(x: Priority) -> Self {
52        x.as_ot_message_priority()
53    }
54}
55
56impl From<u8> for Priority {
57    fn from(x: u8) -> Self {
58        use num_traits::FromPrimitive;
59        Self::from_u8(x).unwrap_or_else(|| panic!("Unknown otMessagePriority value: {x}"))
60    }
61}
62
63impl From<Priority> for u8 {
64    #[allow(clippy::unnecessary_fallible_conversions)]
65    fn from(x: Priority) -> Self {
66        x.try_into().unwrap()
67    }
68}
69
70/// Message Origin.
71/// Functional equivalent of [`otsys::otMessageOrigin`](crate::otsys::otMessageOrigin).
72///
73/// OpenThread uses the origin to decide which security checks apply to a
74/// message. Messages injected from a host network stack that may forward
75/// traffic from an untrusted network must use [`Origin::HostUntrusted`].
76#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, FromPrimitive)]
77pub enum Origin {
78    /// Message received from the Thread network interface.
79    /// Equivalent to [`crate::otsys::OT_MESSAGE_ORIGIN_THREAD_NETIF`]
80    ThreadNetif = OT_MESSAGE_ORIGIN_THREAD_NETIF as isize,
81
82    /// Message from a trusted source on the host.
83    /// Equivalent to [`crate::otsys::OT_MESSAGE_ORIGIN_HOST_TRUSTED`]
84    ///
85    /// This is the origin OpenThread assigns to newly allocated messages.
86    HostTrusted = OT_MESSAGE_ORIGIN_HOST_TRUSTED as isize,
87
88    /// Message from an untrusted source on the host, such as a packet
89    /// forwarded from the infrastructure network by a Border Router.
90    /// Equivalent to [`crate::otsys::OT_MESSAGE_ORIGIN_HOST_UNTRUSTED`]
91    HostUntrusted = OT_MESSAGE_ORIGIN_HOST_UNTRUSTED as isize,
92}
93
94impl Origin {
95    /// Returns value as a [`otsys::otMessageOrigin`](crate::otsys::otMessageOrigin).
96    pub fn as_ot_message_origin(self) -> otMessageOrigin {
97        self as otMessageOrigin
98    }
99}
100
101impl From<otMessageOrigin> for Origin {
102    fn from(x: otMessageOrigin) -> Self {
103        use num_traits::FromPrimitive;
104        Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otMessageOrigin value: {x}"))
105    }
106}
107
108impl From<Origin> for otMessageOrigin {
109    fn from(x: Origin) -> Self {
110        x.as_ot_message_origin()
111    }
112}
113
114/// Message Info.
115/// Functional equivalent of `otsys::otMessageInfo`.
116#[derive(Clone)]
117#[repr(transparent)]
118pub struct Info(pub otMessageInfo);
119
120impl_ot_castable!(Info, otMessageInfo);
121
122impl AsRef<Info> for Info {
123    fn as_ref(&self) -> &Info {
124        self
125    }
126}
127
128impl Info {
129    /// Creates a new message info instance.
130    pub fn new(local: SockAddr, remote: SockAddr) -> Info {
131        Info(otMessageInfo {
132            mSockAddr: local.addr().into_ot(),
133            mPeerAddr: remote.addr().into_ot(),
134            mSockPort: local.port(),
135            mPeerPort: remote.port(),
136            ..otMessageInfo::default()
137        })
138    }
139
140    /// The ECN status of the packet, represented as in the IPv6 header.
141    pub fn ecn(&self) -> u8 {
142        self.0.mEcn()
143    }
144
145    /// Sets the the ECN status of the packet.
146    pub fn set_ecn(&mut self, ecn: u8) {
147        self.0.set_mEcn(ecn)
148    }
149
150    /// Gets the IPv6 Hop Limit value.
151    pub fn hop_limit(&self) -> u8 {
152        self.0.mHopLimit
153    }
154
155    /// Sets the IPv6 Hop Limit value.
156    pub fn set_hop_limit(&mut self, hop_limit: u8) {
157        self.0.mHopLimit = hop_limit
158    }
159
160    /// TRUE if packets sent/received via host interface, FALSE otherwise.
161    pub fn is_host_interface(&self) -> bool {
162        self.0.mIsHostInterface()
163    }
164
165    /// Set to TRUE if packets sent/received via host interface, FALSE otherwise.
166    pub fn set_host_interface(&mut self, host_interface: bool) {
167        self.0.set_mIsHostInterface(host_interface)
168    }
169
170    /// TRUE if allowing looping back multicast, FALSE otherwise.
171    pub fn multicast_loop(&self) -> bool {
172        self.0.mMulticastLoop()
173    }
174
175    /// Set to TRUE to allow looping back multicast, FALSE otherwise.
176    pub fn set_multicast_loop(&mut self, multicast_loop: bool) {
177        self.0.set_mMulticastLoop(multicast_loop)
178    }
179
180    /// TRUE if allowing IPv6 Hop Limit 0 in mHopLimit, FALSE otherwise.
181    pub fn allow_zero_hop_limit(&self) -> bool {
182        self.0.mAllowZeroHopLimit()
183    }
184
185    /// Set to TRUE to allow IPv6 Hop Limit 0 in mHopLimit, FALSE otherwise.
186    pub fn set_allow_zero_hop_limit(&mut self, allow_zero_hop_limit: bool) {
187        self.0.set_mAllowZeroHopLimit(allow_zero_hop_limit)
188    }
189
190    /// Local address and port.
191    pub fn sock_name(&self) -> SockAddr {
192        SockAddr::new(Ip6Address::from_ot(self.0.mSockAddr), self.0.mSockPort)
193    }
194
195    /// Remote address and port.
196    pub fn peer_name(&self) -> SockAddr {
197        SockAddr::new(Ip6Address::from_ot(self.0.mPeerAddr), self.0.mPeerPort)
198    }
199}
200
201impl std::fmt::Debug for Info {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        f.debug_struct("otMessageInfo")
204            .field("sock_name", &self.sock_name())
205            .field("peer_name", &self.peer_name())
206            .field("ecn", &self.ecn())
207            .field("hop_limit", &self.hop_limit())
208            .field("allow_zero_hop_limit", &self.allow_zero_hop_limit())
209            .field("multicast_loop", &self.multicast_loop())
210            .field("is_host_interface", &self.is_host_interface())
211            .finish()
212    }
213}
214
215/// Message Settings.
216/// Functional equivalent of `otsys::otMessageSettings`.
217#[derive(Debug, Clone)]
218#[repr(transparent)]
219pub struct Settings(pub otMessageSettings);
220
221impl_ot_castable!(Settings, otMessageSettings);
222
223impl AsRef<Settings> for Settings {
224    fn as_ref(&self) -> &Settings {
225        self
226    }
227}
228
229impl Default for Settings {
230    fn default() -> Self {
231        Settings(otMessageSettings {
232            mLinkSecurityEnabled: true,
233            mPriority: OT_MESSAGE_PRIORITY_NORMAL.try_into().unwrap(),
234        })
235    }
236}
237
238impl Settings {
239    /// Returns settings with the priority set as indicated.
240    pub fn set_priority(mut self, priority: Priority) -> Self {
241        self.0.mPriority = priority.into();
242        self
243    }
244
245    /// Returns settings with the link_security flag set as indicated.
246    pub fn set_link_security(mut self, enabled: bool) -> Self {
247        self.0.mLinkSecurityEnabled = enabled;
248        self
249    }
250}
251
252/// OpenThread Message. Functional equivalent of [`otsys::otMessage`](crate::otsys::otMessage).
253///
254/// This type cannot be instantiated directly: owned instances are
255/// passed around in an [`ot::Box<ot::Message>`], or [`OtMessageBox`](crate::OtMessageBox)
256/// for short.
257///
258/// `otMessage` instances keep a reference to their `otInstance`, so this type does not
259/// implement `Send` nor `Sync`.
260#[repr(transparent)]
261pub struct Message<'a>(otMessage, PhantomData<*mut otMessage>, PhantomData<&'a ()>);
262
263impl std::fmt::Debug for Message<'_> {
264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265        f.debug_struct("otMessage")
266            .field("otPtr", &self.as_ot_ptr())
267            .field("len", &self.len())
268            .field("offset", &self.offset())
269            .field("RSSI", &self.rssi())
270            .finish()
271    }
272}
273
274// SAFETY: `Message` transparently wraps around an opaque type and is
275//         never used by value nor passed by value.
276unsafe impl ot::Boxable for Message<'_> {
277    type OtType = otMessage;
278    unsafe fn finalize(&mut self) {
279        unsafe { otMessageFree(self.as_ot_ptr()) }
280    }
281}
282
283impl<'a> Message<'a> {
284    /// Functional equivalent of [`otsys::otIp6NewMessage`](crate::otsys::otIp6NewMessage).
285    pub fn ip6_new<T: ot::Boxable<OtType = otInstance>>(
286        instance: &'a T,
287        settings: Option<&Settings>,
288    ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
289        unsafe {
290            // This is safe because we own the `otMessage*` resulting from
291            // `otIp6NewMessage`. Safety is also dependent on the correctness
292            //  of the implementation of `otIp6NewMessage`.
293            ot::Box::from_ot_ptr(otIp6NewMessage(
294                instance.as_ot_ptr(),
295                settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
296            ))
297        }
298        .ok_or(ot::NoBufs)
299    }
300
301    /// Functional equivalent of
302    /// [`otsys::otIp6NewMessageFromBuffer`](crate::otsys::otIp6NewMessageFromBuffer).
303    ///
304    /// Note that, due to limitation in how the underlying method can report errors,
305    /// it is impossible to differentiate the "NoBufs" error condition from the "IPv6 header
306    /// malformed" error condition, hence the unusual error type.
307    pub fn ip6_new_from_bytes<T: ot::Boxable<OtType = otInstance>, D: AsRef<[u8]>>(
308        instance: &'a T,
309        data: D,
310        settings: Option<&Settings>,
311    ) -> Result<ot::Box<Message<'a>>, ot::MalformedOrNoBufs> {
312        let data = data.as_ref();
313        unsafe {
314            // SAFETY: This is safe because we own the `otMessage*` resulting from
315            //         `otIp6NewMessageFromBuffer`. Safety is also dependent on the correctness
316            //         of the implementation of `otIp6NewMessageFromBuffer`.
317            ot::Box::from_ot_ptr(otIp6NewMessageFromBuffer(
318                instance.as_ot_ptr(),
319                data.as_ptr(),
320                data.len().try_into().expect("ot::Message::ip6_new_from_bytes: Buffer too large"),
321                settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
322            ))
323        }
324        .ok_or(ot::MalformedOrNoBufs)
325    }
326
327    /// Functional equivalent of [`otsys::otIp4NewMessage`](crate::otsys::otIp4NewMessage).
328    pub fn ip4_new<T: ot::Boxable<OtType = otInstance>>(
329        instance: &'a T,
330        settings: Option<&Settings>,
331    ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
332        unsafe {
333            // This is safe because we own the `otMessage*` resulting from
334            // `otIp4NewMessage`. Safety is also dependent on the correctness
335            //  of the implementation of `otIp4NewMessage`.
336            ot::Box::from_ot_ptr(otIp4NewMessage(
337                instance.as_ot_ptr(),
338                settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
339            ))
340        }
341        .ok_or(ot::NoBufs)
342    }
343}
344
345impl<'a> Message<'a> {
346    /// Functional equivalent of [`otsys::otIp6NewMessage`](crate::otsys::otIp6NewMessage).
347    pub fn udp_new<T: ot::Boxable<OtType = otInstance>>(
348        instance: &'a T,
349        settings: Option<&Settings>,
350    ) -> Result<ot::Box<Message<'a>>, ot::NoBufs> {
351        unsafe {
352            // This is safe because we own the `otMessage*` resulting from
353            // `otUdpNewMessage`. Safety is also dependent on the correctness
354            //  of the implementation of `otUdpNewMessage`.
355            ot::Box::from_ot_ptr(otUdpNewMessage(
356                instance.as_ot_ptr(),
357                settings.map(|x| x.as_ref().as_ot_ptr()).unwrap_or(null()),
358            ))
359        }
360        .ok_or(ot::NoBufs)
361    }
362}
363
364impl Message<'_> {
365    /// Functional equivalent of [`otsys::otMessageAppend`](crate::otsys::otMessageAppend).
366    ///
367    /// The length of `data` must be less than 2^16, or else the method will return
368    /// an `Err` with [`ot::Error::InvalidArgs`].
369    pub fn append(&mut self, data: &[u8]) -> Result {
370        Error::from(unsafe {
371            // We verify that the length of the slice will fit into
372            // the length argument type, throwing an error if this is not possible.
373            otMessageAppend(
374                self.as_ot_ptr(),
375                data.as_ptr() as *const ::std::os::raw::c_void,
376                data.len().try_into().or(Err(Error::InvalidArgs))?,
377            )
378        })
379        .into()
380    }
381
382    /// Functional equivalent of
383    /// [`otsys::otMessageIsLinkSecurityEnabled`](crate::otsys::otMessageIsLinkSecurityEnabled).
384    pub fn is_link_security_enabled(&self) -> bool {
385        unsafe { otMessageIsLinkSecurityEnabled(self.as_ot_ptr()) }
386    }
387
388    /// Functional equivalent of [`otsys::otMessageGetLength`](crate::otsys::otMessageGetLength).
389    #[allow(clippy::len_without_is_empty)]
390    pub fn len(&self) -> usize {
391        unsafe { otMessageGetLength(self.as_ot_ptr()).into() }
392    }
393
394    /// Functional equivalent of [`otsys::otMessageSetLength`](crate::otsys::otMessageSetLength).
395    ///
396    /// In addition to the error codes outlined in `otsys::otMessageSetLength`, this method
397    /// will return `Err(Error::InvalidArgs)` if the `len` parameter is larger than 65,535 bytes.
398    pub fn set_len(&mut self, len: usize) -> Result {
399        Error::from(unsafe {
400            // SAFETY: We verify that the given length will fit into the
401            //         the length argument type, throwing an error if this is not possible.
402            otMessageSetLength(self.as_ot_ptr(), len.try_into().or(Err(Error::InvalidArgs))?)
403        })
404        .into()
405    }
406
407    /// Functional equivalent of [`otsys::otMessageGetOffset`](crate::otsys::otMessageGetOffset).
408    pub fn offset(&self) -> usize {
409        unsafe { otMessageGetOffset(self.as_ot_ptr()).into() }
410    }
411
412    /// Functional equivalent of [`otsys::otMessageSetOffset`](crate::otsys::otMessageSetOffset).
413    ///
414    /// Calling this method with an `offset` larger than or equal to exceed 2^16 will cause a panic.
415    pub fn set_offset(&mut self, offset: usize) {
416        unsafe {
417            // SAFETY: We verify that the given offset will fit into the
418            //         the offset argument type and panic if this is not possible.
419            otMessageSetOffset(
420                self.as_ot_ptr(),
421                offset.try_into().expect("ot::Message::set_offset: Offset too large"),
422            )
423        }
424    }
425
426    /// This function sets/forces the message to be forwarded using direct transmission.
427    /// Functional equivalent of
428    /// [`otsys::otMessageSetDirectTransmission`](crate::otsys::otMessageSetDirectTransmission).
429    ///
430    /// Default setting for a new message is `false`.
431    pub fn set_direct_transmission(&mut self, direct_transmission: bool) {
432        unsafe {
433            otMessageSetDirectTransmission(self.as_ot_ptr(), direct_transmission);
434        }
435    }
436
437    /// Functional equivalent of [`otsys::otMessageGetOrigin`](crate::otsys::otMessageGetOrigin).
438    pub fn origin(&self) -> Origin {
439        unsafe { otMessageGetOrigin(self.as_ot_ptr()) }.into()
440    }
441
442    /// Functional equivalent of [`otsys::otMessageSetOrigin`](crate::otsys::otMessageSetOrigin).
443    ///
444    /// Default origin for a new message is [`Origin::HostTrusted`].
445    pub fn set_origin(&mut self, origin: Origin) {
446        unsafe {
447            otMessageSetOrigin(self.as_ot_ptr(), origin.into());
448        }
449    }
450
451    /// Functional equivalent of [`otsys::otMessageGetRss`](crate::otsys::otMessageGetRss).
452    pub fn rssi(&self) -> Decibels {
453        unsafe { otMessageGetRss(self.as_ot_ptr()) }
454    }
455
456    /// Renders this message to a new `Vec<u8>` using
457    /// [`otsys::otMessageRead`](crate::otsys::otMessageRead).
458    pub fn to_vec(&self) -> Vec<u8> {
459        let mut buffer = Vec::with_capacity(self.len());
460        #[allow(clippy::uninit_vec)] // TODO(https://fxbug.dev/42177056)
461        unsafe {
462            buffer.set_len(self.len());
463            otMessageRead(
464                self.as_ot_ptr(),
465                0,
466                buffer.as_mut_ptr() as *mut core::ffi::c_void,
467                otMessageGetLength(self.as_ot_ptr()),
468            );
469        }
470        buffer
471    }
472}
473
474/// Message buffer info.
475/// Functional equivalent of [`otsys::otBufferInfo`](crate::otsys::otBufferInfo).
476#[derive(Debug, Default, Copy, Clone)]
477#[repr(transparent)]
478pub struct BufferInfo(pub otBufferInfo);
479
480impl_ot_castable!(BufferInfo, otBufferInfo);
481
482impl BufferInfo {
483    /// Total number of buffers in the messages pool.
484    pub fn total_buffers(&self) -> u16 {
485        self.0.mTotalBuffers
486    }
487
488    /// Number of free buffers.
489    pub fn free_buffers(&self) -> u16 {
490        self.0.mFreeBuffers
491    }
492
493    /// Maximum number of used buffers at the same time.
494    pub fn max_used_buffers(&self) -> u16 {
495        self.0.mMaxUsedBuffers
496    }
497
498    /// Info about 6LoWPAN send queue.
499    pub fn six_lo_send_queue(&self) -> &MessageQueueInfo {
500        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.m6loSendQueue) }.unwrap()
501    }
502
503    /// Info about 6LoWPAN reassembly queue.
504    pub fn six_lo_reassembly_queue(&self) -> &MessageQueueInfo {
505        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.m6loReassemblyQueue) }.unwrap()
506    }
507
508    /// Info about IPv6 send queue.
509    pub fn ip6_queue(&self) -> &MessageQueueInfo {
510        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mIp6Queue) }.unwrap()
511    }
512
513    /// Info about MPL send queue.
514    pub fn mpl_queue(&self) -> &MessageQueueInfo {
515        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mMplQueue) }.unwrap()
516    }
517
518    /// Info about MLE delayed message queue.
519    pub fn mle_queue(&self) -> &MessageQueueInfo {
520        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mMleQueue) }.unwrap()
521    }
522
523    /// Info about CoAP/TMF send queue.
524    pub fn coap_queue(&self) -> &MessageQueueInfo {
525        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mCoapQueue) }.unwrap()
526    }
527
528    /// Info about CoAP secure send queue.
529    pub fn coap_secure_queue(&self) -> &MessageQueueInfo {
530        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mCoapSecureQueue) }.unwrap()
531    }
532
533    /// Info about application CoAP send queue.
534    pub fn application_coap_queue(&self) -> &MessageQueueInfo {
535        unsafe { MessageQueueInfo::ref_from_ot_ptr(&self.0.mApplicationCoapQueue) }.unwrap()
536    }
537}
538
539/// Trait for probing message buffer internal metrics.
540pub trait MessageBuffer {
541    /// Functional equivalent of [`otsys::otMessageGetBufferInfo`](crate::otsys::otMessageGetBufferInfo).
542    fn get_buffer_info(&self) -> BufferInfo;
543}
544
545impl<T: MessageBuffer + Boxable> MessageBuffer for ot::Box<T> {
546    fn get_buffer_info(&self) -> BufferInfo {
547        self.as_ref().get_buffer_info()
548    }
549}
550
551impl MessageBuffer for Instance {
552    fn get_buffer_info(&self) -> BufferInfo {
553        let mut ret = BufferInfo::default();
554        unsafe {
555            otMessageGetBufferInfo(self.as_ot_ptr(), ret.as_ot_mut_ptr());
556        }
557        ret
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use super::*;
564
565    #[test]
566    fn test_origin_round_trips_through_ot_message_origin() {
567        for origin in [Origin::ThreadNetif, Origin::HostTrusted, Origin::HostUntrusted] {
568            assert_eq!(Origin::from(otMessageOrigin::from(origin)), origin);
569        }
570    }
571
572    #[test]
573    fn test_origin_matches_ot_constants() {
574        assert_eq!(otMessageOrigin::from(Origin::ThreadNetif), OT_MESSAGE_ORIGIN_THREAD_NETIF);
575        assert_eq!(otMessageOrigin::from(Origin::HostTrusted), OT_MESSAGE_ORIGIN_HOST_TRUSTED);
576        assert_eq!(otMessageOrigin::from(Origin::HostUntrusted), OT_MESSAGE_ORIGIN_HOST_UNTRUSTED);
577    }
578
579    #[test]
580    #[should_panic(expected = "Unknown otMessageOrigin value")]
581    fn test_origin_from_unknown_value_panics() {
582        let _ = Origin::from(OT_MESSAGE_ORIGIN_HOST_UNTRUSTED + 1);
583    }
584}