capsules_extra/net/icmpv6/
icmpv6_send.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Definition and implementation of a simple ICMPv6 sending
6//! interface.
7//!
8//! The [ICMP6Sender](trait.ICMP6Sender.html) trait provides an
9//! interface for an upper layer to send an ICMPv6 packet, and the
10//! [ICMP6SendClient](trait.ICMP6SendClient.html) trait is implemented
11//! by the upper layer to allow them to receive the `send_done`
12//! callback once transmission has completed.
13// - Author: Conor McAvity <cmcavity@stanford.edu>
14
15use crate::net::icmpv6::ICMP6Header;
16use crate::net::ipv6::ip_utils::IPAddr;
17use crate::net::ipv6::ipv6_send::{IP6SendClient, IP6Sender};
18use crate::net::ipv6::TransportHeader;
19use crate::net::network_capabilities::NetworkCapability;
20
21use kernel::utilities::cells::OptionalCell;
22use kernel::utilities::leasable_buffer::SubSliceMut;
23use kernel::ErrorCode;
24
25/// A trait for a client of an `ICMP6Sender`.
26pub trait ICMP6SendClient {
27    /// A client callback invoked after an ICMP6Sender has completed sending
28    /// a requested packet.
29    fn send_done(&self, result: Result<(), ErrorCode>);
30}
31
32/// A trait that defines an interface for sending ICMPv6 packets.
33pub trait ICMP6Sender<'a> {
34    /// Sets the client for the `ICMP6Sender` instance.
35    ///
36    /// # Arguments
37    ///
38    /// `client` - The `ICMP6SendClient` instance to be set as the client
39    /// of the `ICMP6Sender` instance
40    fn set_client(&self, client: &'a dyn ICMP6SendClient);
41
42    /// Constructs and sends an IP packet from provided ICMPv6 header
43    /// and payload.
44    ///
45    /// # Arguments
46    ///
47    /// `dest` - The destination IP address
48    /// `icmp_header` - The ICMPv6 header to be sent
49    /// `buf` - The byte array containing the ICMPv6 payload
50    ///
51    /// # Return Value
52    ///
53    /// This function returns a code reporting either success or any
54    /// synchronous errors. Note that any asynchronous errors are returned
55    /// via the callback.
56    fn send(
57        &self,
58        dest: IPAddr,
59        icmp_header: ICMP6Header,
60        buf: &'static mut [u8],
61        net_cap: &'static NetworkCapability,
62    ) -> Result<(), ErrorCode>;
63}
64
65/// A struct that implements the `ICMP6Sender` trait.
66pub struct ICMP6SendStruct<'a, T: IP6Sender<'a>> {
67    ip_send_struct: &'a T,
68    client: OptionalCell<&'a dyn ICMP6SendClient>,
69}
70
71impl<'a, T: IP6Sender<'a>> ICMP6SendStruct<'a, T> {
72    pub fn new(ip_send_struct: &'a T) -> ICMP6SendStruct<'a, T> {
73        ICMP6SendStruct {
74            ip_send_struct,
75            client: OptionalCell::empty(),
76        }
77    }
78}
79
80impl<'a, T: IP6Sender<'a>> ICMP6Sender<'a> for ICMP6SendStruct<'a, T> {
81    fn set_client(&self, client: &'a dyn ICMP6SendClient) {
82        self.client.set(client);
83    }
84
85    fn send(
86        &self,
87        dest: IPAddr,
88        mut icmp_header: ICMP6Header,
89        buf: &'static mut [u8],
90        net_cap: &'static NetworkCapability,
91    ) -> Result<(), ErrorCode> {
92        let total_len = buf.len() + icmp_header.get_hdr_size();
93        icmp_header.set_len(total_len as u16);
94        let transport_header = TransportHeader::ICMP(icmp_header);
95        self.ip_send_struct
96            .send_to(dest, transport_header, &SubSliceMut::new(buf), net_cap)
97    }
98}
99
100impl<'a, T: IP6Sender<'a>> IP6SendClient for ICMP6SendStruct<'a, T> {
101    /// Forwards callback received from the `IP6Sender` to the
102    /// `ICMP6SendClient`.
103    fn send_done(&self, result: Result<(), ErrorCode>) {
104        self.client.map(|client| client.send_done(result));
105    }
106}