capsules_extra/net/ipv6/ipv6_recv.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
5use crate::net::ipv6::IP6Header;
6use crate::net::sixlowpan::sixlowpan_state::SixlowpanRxClient;
7
8use kernel::debug;
9use kernel::utilities::cells::OptionalCell;
10use kernel::ErrorCode;
11
12// To provide some context for the entire rx chain:
13/*
14- The radio in the kernel has a single `RxClient`, which is set as the mac layer
15 (awake_mac, typically)
16- The mac layer (i.e. `AwakeMac`) has a single `RxClient`, which is the
17 mac_device(`ieee802154::Framer::framer`)
18- The Mac device has a single receive client - `MuxMac` (virtual MAC device).
19- The `MuxMac` can have multiple "users" which are of type `MacUser`
20- Any received packet is passed to ALL MacUsers, which are expected to filter
21 packets themselves accordingly.
22- Right now, we initialize two MacUsers in the kernel (in main.rs/components).
23 These are the 'radio_mac', which is the MacUser for the RadioDriver that
24 enables the userland interface to directly send 802154 frames, and udp_mac,
25 the mac layer that is ultimately associated with the udp userland interface.
26- The udp_mac MacUser has a single receive client, which is the `sixlowpan_state` struct
27- `sixlowpan_state` has a single rx_client, which in our case is a single struct that
28 implements the `ip_receive ` trait.
29- the `ip_receive` implementing struct (`IP6RecvStruct`) has a single client, which is
30 udp_recv, a `UDPReceive` struct.
31- The UDPReceive struct is a field of the UDPDriver, which ultimately passes the
32 packets up to userland.
33*/
34
35pub trait IP6RecvClient {
36 fn receive(&self, header: IP6Header, payload: &[u8]);
37}
38
39/// Receiver trait for IPv6.
40///
41/// Currently only one implementation of this trait should exist,
42/// as we do not multiplex received packets based on the address.
43/// The receiver receives IP packets destined for any local address.
44/// The receiver should drop any packets with destination addresses
45/// that are not among the local addresses of this device.
46pub trait IP6Receiver<'a> {
47 fn set_client(&self, client: &'a dyn IP6RecvClient);
48}
49
50pub struct IP6RecvStruct<'a> {
51 client: OptionalCell<&'a dyn IP6RecvClient>,
52}
53
54impl<'a> IP6Receiver<'a> for IP6RecvStruct<'a> {
55 fn set_client(&self, client: &'a dyn IP6RecvClient) {
56 self.client.set(client);
57 }
58}
59
60impl<'a> IP6RecvStruct<'a> {
61 pub fn new() -> IP6RecvStruct<'a> {
62 IP6RecvStruct {
63 client: OptionalCell::empty(),
64 }
65 }
66}
67
68impl SixlowpanRxClient for IP6RecvStruct<'_> {
69 fn receive(&self, buf: &[u8], len: usize, result: Result<(), ErrorCode>) {
70 // TODO: Drop here?
71 if len > buf.len() || result != Ok(()) {
72 return;
73 }
74 match IP6Header::decode(buf).done() {
75 Some((offset, ip6_header)) => {
76 let checksum_result = ip6_header.check_transport_checksum(&buf[offset..len]);
77 if checksum_result == Err(ErrorCode::FAIL) {
78 debug!("cksum fail!: {:?}", checksum_result);
79 return; //Dropped.
80 }
81 // Note: Protocols for which checksum verification is not implemented (TCP, etc.)
82 // are automatically assumed as fine, rather than dropped
83
84 self.client
85 .map(|client| client.receive(ip6_header, &buf[offset..len]));
86 }
87 None => {
88 debug!("failed to decode ipv6 header");
89 // TODO: Report the error somewhere...
90 }
91 }
92 }
93}