Skip to content

Commit 5ee728a

Browse files
authored
Merge pull request #889 from thvdveld/clean-up
Move interface logic into their logical files
2 parents 4877a39 + f25c66d commit 5ee728a

File tree

12 files changed

+420
-436
lines changed

12 files changed

+420
-436
lines changed

src/iface/interface/ethernet.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
1-
use super::check;
2-
use super::DispatchError;
3-
use super::EthernetPacket;
4-
use super::FragmentsBuffer;
5-
use super::InterfaceInner;
6-
use super::SocketSet;
7-
use core::result::Result;
8-
9-
use crate::phy::TxToken;
10-
use crate::wire::*;
1+
use super::*;
112

123
impl InterfaceInner {
13-
#[cfg(feature = "medium-ethernet")]
144
pub(super) fn process_ethernet<'frame>(
155
&mut self,
166
sockets: &mut SocketSet,
@@ -49,7 +39,6 @@ impl InterfaceInner {
4939
}
5040
}
5141

52-
#[cfg(feature = "medium-ethernet")]
5342
pub(super) fn dispatch_ethernet<Tx, F>(
5443
&mut self,
5544
tx_token: Tx,

src/iface/interface/ieee802154.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
use super::*;
22

33
impl InterfaceInner {
4+
/// Return the next IEEE802.15.4 sequence number.
5+
#[cfg(feature = "medium-ieee802154")]
6+
pub(super) fn next_ieee802154_seq_number(&mut self) -> u8 {
7+
let no = self.sequence_no;
8+
self.sequence_no = self.sequence_no.wrapping_add(1);
9+
no
10+
}
11+
412
pub(super) fn process_ieee802154<'output, 'payload: 'output>(
513
&mut self,
614
sockets: &mut SocketSet,
@@ -54,7 +62,7 @@ impl InterfaceInner {
5462
security_enabled: false,
5563
frame_pending: false,
5664
ack_request: false,
57-
sequence_number: Some(self.get_sequence_number()),
65+
sequence_number: Some(self.next_ieee802154_seq_number()),
5866
pan_id_compression: true,
5967
frame_version: Ieee802154FrameVersion::Ieee802154_2003,
6068
dst_pan_id: self.pan_id,
@@ -78,7 +86,7 @@ impl InterfaceInner {
7886
security_enabled: false,
7987
frame_pending: false,
8088
ack_request: false,
81-
sequence_number: Some(self.get_sequence_number()),
89+
sequence_number: Some(self.next_ieee802154_seq_number()),
8290
pan_id_compression: true,
8391
frame_version: Ieee802154FrameVersion::Ieee802154_2003,
8492
dst_pan_id: self.pan_id,

src/iface/interface/igmp.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
use super::*;
22

3-
use crate::phy::{Device, PacketMeta};
4-
use crate::time::{Duration, Instant};
5-
use crate::wire::*;
6-
7-
use core::result::Result;
8-
93
/// Error type for `join_multicast_group`, `leave_multicast_group`.
104
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115
#[cfg_attr(feature = "defmt", derive(defmt::Format))]

src/iface/interface/ipv4.rs

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,92 @@
11
use super::*;
22

3-
#[cfg(feature = "socket-dhcpv4")]
4-
use crate::socket::dhcpv4;
5-
#[cfg(feature = "socket-icmp")]
6-
use crate::socket::icmp;
7-
use crate::socket::AnySocket;
3+
impl Interface {
4+
/// Process fragments that still need to be sent for IPv4 packets.
5+
///
6+
/// This function returns a boolean value indicating whether any packets were
7+
/// processed or emitted, and thus, whether the readiness of any socket might
8+
/// have changed.
9+
#[cfg(feature = "proto-ipv4-fragmentation")]
10+
pub(super) fn ipv4_egress<D>(&mut self, device: &mut D) -> bool
11+
where
12+
D: Device + ?Sized,
13+
{
14+
// Reset the buffer when we transmitted everything.
15+
if self.fragmenter.finished() {
16+
self.fragmenter.reset();
17+
}
18+
19+
if self.fragmenter.is_empty() {
20+
return false;
21+
}
822

9-
use crate::phy::{Medium, TxToken};
10-
use crate::time::Instant;
11-
use crate::wire::*;
23+
let pkt = &self.fragmenter;
24+
if pkt.packet_len > pkt.sent_bytes {
25+
if let Some(tx_token) = device.transmit(self.inner.now) {
26+
self.inner
27+
.dispatch_ipv4_frag(tx_token, &mut self.fragmenter);
28+
return true;
29+
}
30+
}
31+
false
32+
}
33+
}
1234

1335
impl InterfaceInner {
36+
/// Get the next IPv4 fragment identifier.
37+
#[cfg(feature = "proto-ipv4-fragmentation")]
38+
pub(super) fn next_ipv4_frag_ident(&mut self) -> u16 {
39+
let ipv4_id = self.ipv4_id;
40+
self.ipv4_id = self.ipv4_id.wrapping_add(1);
41+
ipv4_id
42+
}
43+
44+
/// Get an IPv4 source address based on a destination address.
45+
///
46+
/// **NOTE**: unlike for IPv6, no specific selection algorithm is implemented. The first IPv4
47+
/// address from the interface is returned.
48+
#[allow(unused)]
49+
pub(crate) fn get_source_address_ipv4(&self, _dst_addr: &Ipv4Address) -> Option<Ipv4Address> {
50+
for cidr in self.ip_addrs.iter() {
51+
#[allow(irrefutable_let_patterns)] // if only ipv4 is enabled
52+
if let IpCidr::Ipv4(cidr) = cidr {
53+
return Some(cidr.address());
54+
}
55+
}
56+
None
57+
}
58+
59+
/// Checks if an address is broadcast, taking into account ipv4 subnet-local
60+
/// broadcast addresses.
61+
pub(crate) fn is_broadcast_v4(&self, address: Ipv4Address) -> bool {
62+
if address.is_broadcast() {
63+
return true;
64+
}
65+
66+
self.ip_addrs
67+
.iter()
68+
.filter_map(|own_cidr| match own_cidr {
69+
IpCidr::Ipv4(own_ip) => Some(own_ip.broadcast()?),
70+
#[cfg(feature = "proto-ipv6")]
71+
IpCidr::Ipv6(_) => None,
72+
})
73+
.any(|broadcast_address| address == broadcast_address)
74+
}
75+
76+
/// Checks if an ipv4 address is unicast, taking into account subnet broadcast addresses
77+
fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
78+
address.is_unicast() && !self.is_broadcast_v4(address)
79+
}
80+
81+
/// Get the first IPv4 address of the interface.
82+
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
83+
self.ip_addrs.iter().find_map(|addr| match *addr {
84+
IpCidr::Ipv4(cidr) => Some(cidr.address()),
85+
#[allow(unreachable_patterns)]
86+
_ => None,
87+
})
88+
}
89+
1490
pub(super) fn process_ipv4<'a>(
1591
&mut self,
1692
sockets: &mut SocketSet,
@@ -75,13 +151,15 @@ impl InterfaceInner {
75151

76152
#[cfg(feature = "socket-dhcpv4")]
77153
{
154+
use crate::socket::dhcpv4::Socket as Dhcpv4Socket;
155+
78156
if ipv4_repr.next_header == IpProtocol::Udp
79157
&& matches!(self.caps.medium, Medium::Ethernet)
80158
{
81159
let udp_packet = check!(UdpPacket::new_checked(ip_payload));
82160
if let Some(dhcp_socket) = sockets
83161
.items_mut()
84-
.find_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
162+
.find_map(|i| Dhcpv4Socket::downcast_mut(&mut i.socket))
85163
{
86164
// First check for source and dest ports, then do `UdpRepr::parse` if they match.
87165
// This way we avoid validating the UDP checksum twice for all non-DHCP UDP packets (one here, one in `process_udp`)

src/iface/interface/ipv6.rs

Lines changed: 136 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
use super::*;
22

3-
#[cfg(feature = "socket-icmp")]
4-
use crate::socket::icmp;
5-
use crate::socket::AnySocket;
6-
7-
use crate::phy::PacketMeta;
8-
use crate::wire::*;
9-
103
/// Enum used for the process_hopbyhop function. In some cases, when discarding a packet, an ICMMP
114
/// parameter problem message needs to be transmitted to the source of the address. In other cases,
125
/// the processing of the IP packet can continue.
@@ -26,6 +19,133 @@ impl Default for HopByHopResponse<'_> {
2619
}
2720

2821
impl InterfaceInner {
22+
/// Return the IPv6 address that is a candidate source address for the given destination
23+
/// address, based on RFC 6724.
24+
#[allow(unused)]
25+
pub(crate) fn get_source_address_ipv6(&self, dst_addr: &Ipv6Address) -> Option<Ipv6Address> {
26+
// See RFC 6724 Section 4: Candidate source address
27+
fn is_candidate_source_address(dst_addr: &Ipv6Address, src_addr: &Ipv6Address) -> bool {
28+
// For all multicast and link-local destination addresses, the candidate address MUST
29+
// only be an address from the same link.
30+
if dst_addr.is_link_local() && !src_addr.is_link_local() {
31+
return false;
32+
}
33+
34+
if dst_addr.is_multicast()
35+
&& matches!(dst_addr.scope(), Ipv6AddressScope::LinkLocal)
36+
&& src_addr.is_multicast()
37+
&& !matches!(src_addr.scope(), Ipv6AddressScope::LinkLocal)
38+
{
39+
return false;
40+
}
41+
42+
// Loopback addresses and multicast address can not be in the candidate source address
43+
// list. Except when the destination multicast address has a link-local scope, then the
44+
// source address can also be link-local multicast.
45+
if src_addr.is_loopback() || src_addr.is_multicast() {
46+
return false;
47+
}
48+
49+
true
50+
}
51+
52+
// See RFC 6724 Section 2.2: Common Prefix Length
53+
fn common_prefix_length(dst_addr: &Ipv6Cidr, src_addr: &Ipv6Address) -> usize {
54+
let addr = dst_addr.address();
55+
let mut bits = 0;
56+
for (l, r) in addr.as_bytes().iter().zip(src_addr.as_bytes().iter()) {
57+
if l == r {
58+
bits += 8;
59+
} else {
60+
bits += (l ^ r).leading_zeros();
61+
break;
62+
}
63+
}
64+
65+
bits = bits.min(dst_addr.prefix_len() as u32);
66+
67+
bits as usize
68+
}
69+
70+
// Get the first address that is a candidate address.
71+
let mut candidate = self
72+
.ip_addrs
73+
.iter()
74+
.filter_map(|a| match a {
75+
#[cfg(feature = "proto-ipv4")]
76+
IpCidr::Ipv4(_) => None,
77+
#[cfg(feature = "proto-ipv6")]
78+
IpCidr::Ipv6(a) => Some(a),
79+
})
80+
.find(|a| is_candidate_source_address(dst_addr, &a.address()))
81+
.unwrap();
82+
83+
for addr in self.ip_addrs.iter().filter_map(|a| match a {
84+
#[cfg(feature = "proto-ipv4")]
85+
IpCidr::Ipv4(_) => None,
86+
#[cfg(feature = "proto-ipv6")]
87+
IpCidr::Ipv6(a) => Some(a),
88+
}) {
89+
if !is_candidate_source_address(dst_addr, &addr.address()) {
90+
continue;
91+
}
92+
93+
// Rule 1: prefer the address that is the same as the output destination address.
94+
if candidate.address() != *dst_addr && addr.address() == *dst_addr {
95+
candidate = addr;
96+
}
97+
98+
// Rule 2: prefer appropriate scope.
99+
if (candidate.address().scope() as u8) < (addr.address().scope() as u8) {
100+
if (candidate.address().scope() as u8) < (dst_addr.scope() as u8) {
101+
candidate = addr;
102+
}
103+
} else if (addr.address().scope() as u8) > (dst_addr.scope() as u8) {
104+
candidate = addr;
105+
}
106+
107+
// Rule 3: avoid deprecated addresses (TODO)
108+
// Rule 4: prefer home addresses (TODO)
109+
// Rule 5: prefer outgoing interfaces (TODO)
110+
// Rule 5.5: prefer addresses in a prefix advertises by the next-hop (TODO).
111+
// Rule 6: prefer matching label (TODO)
112+
// Rule 7: prefer temporary addresses (TODO)
113+
// Rule 8: use longest matching prefix
114+
if common_prefix_length(candidate, dst_addr) < common_prefix_length(addr, dst_addr) {
115+
candidate = addr;
116+
}
117+
}
118+
119+
Some(candidate.address())
120+
}
121+
122+
/// Determine if the given `Ipv6Address` is the solicited node
123+
/// multicast address for a IPv6 addresses assigned to the interface.
124+
/// See [RFC 4291 § 2.7.1] for more details.
125+
///
126+
/// [RFC 4291 § 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
127+
pub fn has_solicited_node(&self, addr: Ipv6Address) -> bool {
128+
self.ip_addrs.iter().any(|cidr| {
129+
match *cidr {
130+
IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOOPBACK => {
131+
// Take the lower order 24 bits of the IPv6 address and
132+
// append those bits to FF02:0:0:0:0:1:FF00::/104.
133+
addr.as_bytes()[14..] == cidr.address().as_bytes()[14..]
134+
}
135+
_ => false,
136+
}
137+
})
138+
}
139+
140+
/// Get the first IPv6 address if present.
141+
pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
142+
self.ip_addrs.iter().find_map(|addr| match *addr {
143+
IpCidr::Ipv6(cidr) => Some(cidr.address()),
144+
#[allow(unreachable_patterns)]
145+
_ => None,
146+
})
147+
}
148+
29149
pub(super) fn process_ipv6<'frame>(
30150
&mut self,
31151
sockets: &mut SocketSet,
@@ -191,13 +311,16 @@ impl InterfaceInner {
191311
let mut handled_by_icmp_socket = false;
192312

193313
#[cfg(feature = "socket-icmp")]
194-
for icmp_socket in _sockets
195-
.items_mut()
196-
.filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
197314
{
198-
if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
199-
icmp_socket.process(self, &ip_repr, &icmp_repr.into());
200-
handled_by_icmp_socket = true;
315+
use crate::socket::icmp::Socket as IcmpSocket;
316+
for icmp_socket in _sockets
317+
.items_mut()
318+
.filter_map(|i| IcmpSocket::downcast_mut(&mut i.socket))
319+
{
320+
if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
321+
icmp_socket.process(self, &ip_repr, &icmp_repr.into());
322+
handled_by_icmp_socket = true;
323+
}
201324
}
202325
}
203326

0 commit comments

Comments
 (0)