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