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}