Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wire: use core::net types for IP addresses. #994

Merged
merged 6 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "smoltcp"
version = "0.11.0"
edition = "2021"
rust-version = "1.77"
rust-version = "1.80"
authors = ["whitequark <whitequark@whitequark.org>"]
description = "A TCP/IP stack designed for bare-metal, real-time systems without a heap."
documentation = "https://docs.rs/smoltcp/"
Expand All @@ -25,7 +25,7 @@ byteorder = { version = "1.0", default-features = false }
log = { version = "0.4.4", default-features = false, optional = true }
libc = { version = "0.2.18", optional = true }
bitflags = { version = "1.0", default-features = false }
defmt = { version = "0.3", optional = true }
defmt = { version = "0.3.8", optional = true, features = ["ip_in_core"] }
cfg-if = "1.0.0"
heapless = "0.8"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include complicated compile-time computations, such as macro or type tricks, eve
at cost of performance degradation.

_smoltcp_ does not need heap allocation *at all*, is [extensively documented][docs],
and compiles on stable Rust 1.77 and later.
and compiles on stable Rust 1.80 and later.

_smoltcp_ achieves [~Gbps of throughput](#examplesbenchmarkrs) when tested against
the Linux TCP stack in loopback mode.
Expand Down
20 changes: 8 additions & 12 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@ mod wire {
extern crate test;

#[cfg(feature = "proto-ipv6")]
const SRC_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
]));
const SRC_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
#[cfg(feature = "proto-ipv6")]
const DST_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
]));
const DST_ADDR: IpAddress = IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2));

#[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
const SRC_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
const SRC_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address::new(192, 168, 1, 1));
#[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
const DST_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
const DST_ADDR: IpAddress = IpAddress::Ipv4(Ipv4Address::new(192, 168, 1, 2));

#[bench]
#[cfg(any(feature = "proto-ipv6", feature = "proto-ipv4"))]
Expand Down Expand Up @@ -84,8 +80,8 @@ mod wire {
#[cfg(feature = "proto-ipv4")]
fn bench_emit_ipv4(b: &mut test::Bencher) {
let repr = Ipv4Repr {
src_addr: Ipv4Address([192, 168, 1, 1]),
dst_addr: Ipv4Address([192, 168, 1, 2]),
src_addr: Ipv4Address::new(192, 168, 1, 1),
dst_addr: Ipv4Address::new(192, 168, 1, 2),
next_header: IpProtocol::Tcp,
payload_len: 100,
hop_limit: 64,
Expand All @@ -102,8 +98,8 @@ mod wire {
#[cfg(feature = "proto-ipv6")]
fn bench_emit_ipv6(b: &mut test::Bencher) {
let repr = Ipv6Repr {
src_addr: Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
dst_addr: Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]),
src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
next_header: IpProtocol::Tcp,
payload_len: 100,
hop_limit: 64,
Expand Down
2 changes: 1 addition & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -eox pipefail

export DEFMT_LOG=trace

MSRV="1.77.0"
MSRV="1.80.0"

RUSTC_VERSIONS=(
$MSRV
Expand Down
1 change: 0 additions & 1 deletion examples/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#![allow(clippy::collapsible_if)]

#[cfg(feature = "std")]
#[allow(dead_code)]
mod utils;

use core::str;
Expand Down
6 changes: 2 additions & 4 deletions examples/multicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use smoltcp::wire::{
};

const MDNS_PORT: u16 = 5353;
const MDNS_GROUP: [u8; 4] = [224, 0, 0, 251];
const MDNS_GROUP: Ipv4Address = Ipv4Address::new(224, 0, 0, 251);

fn main() {
utils::setup_logging("warn");
Expand Down Expand Up @@ -81,9 +81,7 @@ fn main() {
let udp_handle = sockets.add(udp_socket);

// Join a multicast group to receive mDNS traffic
iface
.join_multicast_group(Ipv4Address::from_bytes(&MDNS_GROUP))
.unwrap();
iface.join_multicast_group(MDNS_GROUP).unwrap();

loop {
let timestamp = Instant::now();
Expand Down
15 changes: 6 additions & 9 deletions examples/multicast6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv6Address};
// will send packets to the multicast group we join below on tap0.

const PORT: u16 = 8123;
const GROUP: [u16; 8] = [0xff02, 0, 0, 0, 0, 0, 0, 0x1234];
const LOCAL_ADDR: [u16; 8] = [0xfe80, 0, 0, 0, 0, 0, 0, 0x101];
const ROUTER_ADDR: [u16; 8] = [0xfe80, 0, 0, 0, 0, 0, 0, 0x100];
const GROUP: Ipv6Address = Ipv6Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1234);
const LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x101);
const ROUTER_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);

fn main() {
utils::setup_logging("warn");
Expand All @@ -37,7 +37,6 @@ fn main() {
utils::parse_middleware_options(&mut matches, device, /*loopback=*/ false);

// Create interface
let local_addr = Ipv6Address::from_parts(&LOCAL_ADDR);
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
let mut config = match device.capabilities().medium {
Medium::Ethernet => Config::new(ethernet_addr.into()),
Expand All @@ -49,12 +48,12 @@ fn main() {
let mut iface = Interface::new(config, &mut device, Instant::now());
iface.update_ip_addrs(|ip_addrs| {
ip_addrs
.push(IpCidr::new(IpAddress::from(local_addr), 64))
.push(IpCidr::new(IpAddress::from(LOCAL_ADDR), 64))
.unwrap();
});
iface
.routes_mut()
.add_default_ipv6_route(Ipv6Address::from_parts(&ROUTER_ADDR))
.add_default_ipv6_route(ROUTER_ADDR)
.unwrap();

// Create sockets
Expand All @@ -65,9 +64,7 @@ fn main() {
let udp_handle = sockets.add(udp_socket);

// Join a multicast group
iface
.join_multicast_group(Ipv6Address::from_parts(&GROUP))
.unwrap();
iface.join_multicast_group(GROUP).unwrap();

loop {
let timestamp = Instant::now();
Expand Down
10 changes: 5 additions & 5 deletions src/iface/fragmentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl<K> PacketAssembler<K> {
/// # Errors
///
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
/// place.
/// place.
pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<(), AssemblerError> {
#[cfg(not(feature = "alloc"))]
if self.buffer.len() < offset + data.len() {
Expand Down Expand Up @@ -329,8 +329,8 @@ impl Fragmenter {
#[cfg(feature = "proto-ipv4-fragmentation")]
ipv4: Ipv4Fragmenter {
repr: Ipv4Repr {
src_addr: Ipv4Address::default(),
dst_addr: Ipv4Address::default(),
src_addr: Ipv4Address::new(0, 0, 0, 0),
dst_addr: Ipv4Address::new(0, 0, 0, 0),
next_header: IpProtocol::Unknown(0),
payload_len: 0,
hop_limit: 0,
Expand Down Expand Up @@ -373,8 +373,8 @@ impl Fragmenter {
#[cfg(feature = "proto-ipv4-fragmentation")]
{
self.ipv4.repr = Ipv4Repr {
src_addr: Ipv4Address::default(),
dst_addr: Ipv4Address::default(),
src_addr: Ipv4Address::new(0, 0, 0, 0),
dst_addr: Ipv4Address::new(0, 0, 0, 0),
next_header: IpProtocol::Unknown(0),
payload_len: 0,
hop_limit: 0,
Expand Down
6 changes: 3 additions & 3 deletions src/iface/interface/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl InterfaceInner {

/// Checks if an ipv4 address is unicast, taking into account subnet broadcast addresses
fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
address.is_unicast() && !self.is_broadcast_v4(address)
address.x_is_unicast() && !self.is_broadcast_v4(address)
}

/// Get the first IPv4 address of the interface.
Expand Down Expand Up @@ -182,7 +182,7 @@ impl InterfaceInner {
// Ignore IP packets not directed at us, or broadcast, or any of the multicast groups.
// If AnyIP is enabled, also check if the packet is routed locally.
if !self.any_ip
|| !ipv4_repr.dst_addr.is_unicast()
|| !ipv4_repr.dst_addr.x_is_unicast()
|| self
.routes
.lookup(&IpAddress::Ipv4(ipv4_repr.dst_addr), self.now)
Expand Down Expand Up @@ -260,7 +260,7 @@ impl InterfaceInner {
}

// Discard packets with non-unicast source addresses.
if !source_protocol_addr.is_unicast() || !source_hardware_addr.is_unicast() {
if !source_protocol_addr.x_is_unicast() || !source_hardware_addr.is_unicast() {
net_debug!("arp: non-unicast source address");
return None;
}
Expand Down
37 changes: 19 additions & 18 deletions src/iface/interface/ipv6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ impl InterfaceInner {
}

if dst_addr.is_multicast()
&& matches!(dst_addr.multicast_scope(), Ipv6MulticastScope::LinkLocal)
&& matches!(dst_addr.x_multicast_scope(), Ipv6MulticastScope::LinkLocal)
&& src_addr.is_multicast()
&& !matches!(src_addr.multicast_scope(), Ipv6MulticastScope::LinkLocal)
&& !matches!(src_addr.x_multicast_scope(), Ipv6MulticastScope::LinkLocal)
{
return false;
}
Expand All @@ -58,7 +58,7 @@ impl InterfaceInner {
fn common_prefix_length(dst_addr: &Ipv6Cidr, src_addr: &Ipv6Address) -> usize {
let addr = dst_addr.address();
let mut bits = 0;
for (l, r) in addr.as_bytes().iter().zip(src_addr.as_bytes().iter()) {
for (l, r) in addr.octets().iter().zip(src_addr.octets().iter()) {
if l == r {
bits += 8;
} else {
Expand All @@ -82,7 +82,7 @@ impl InterfaceInner {
.count()
== 0
{
return Ipv6Address::LOOPBACK;
return Ipv6Address::LOCALHOST;
}

let mut candidate = self
Expand Down Expand Up @@ -111,15 +111,16 @@ impl InterfaceInner {
}

// Rule 2: prefer appropriate scope.
if (candidate.address().multicast_scope() as u8)
< (addr.address().multicast_scope() as u8)
if (candidate.address().x_multicast_scope() as u8)
< (addr.address().x_multicast_scope() as u8)
{
if (candidate.address().multicast_scope() as u8)
< (dst_addr.multicast_scope() as u8)
if (candidate.address().x_multicast_scope() as u8)
< (dst_addr.x_multicast_scope() as u8)
{
candidate = addr;
}
} else if (addr.address().multicast_scope() as u8) > (dst_addr.multicast_scope() as u8)
} else if (addr.address().x_multicast_scope() as u8)
> (dst_addr.x_multicast_scope() as u8)
{
candidate = addr;
}
Expand Down Expand Up @@ -147,10 +148,10 @@ impl InterfaceInner {
pub fn has_solicited_node(&self, addr: Ipv6Address) -> bool {
self.ip_addrs.iter().any(|cidr| {
match *cidr {
IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOOPBACK => {
IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOCALHOST => {
// Take the lower order 24 bits of the IPv6 address and
// append those bits to FF02:0:0:0:0:1:FF00::/104.
addr.as_bytes()[14..] == cidr.address().as_bytes()[14..]
addr.octets()[14..] == cidr.address().octets()[14..]
}
_ => false,
}
Expand Down Expand Up @@ -192,7 +193,7 @@ impl InterfaceInner {
) -> Option<Packet<'frame>> {
let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet));

if !ipv6_repr.src_addr.is_unicast() {
if !ipv6_repr.src_addr.x_is_unicast() {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source address");
return None;
Expand All @@ -213,7 +214,7 @@ impl InterfaceInner {
{
// If AnyIP is enabled, also check if the packet is routed locally.
if !self.any_ip
|| !ipv6_repr.dst_addr.is_unicast()
|| !ipv6_repr.dst_addr.x_is_unicast()
|| self
.routes
.lookup(&IpAddress::Ipv6(ipv6_repr.dst_addr), self.now)
Expand All @@ -230,7 +231,7 @@ impl InterfaceInner {
let handled_by_raw_socket = false;

#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
if ipv6_repr.dst_addr.is_unicast() {
if ipv6_repr.dst_addr.x_is_unicast() {
self.neighbor_cache.reset_expiry_if_existing(
IpAddress::Ipv6(ipv6_repr.src_addr),
source_hardware_addr,
Expand Down Expand Up @@ -436,7 +437,7 @@ impl InterfaceInner {
let ip_addr = ip_repr.src_addr.into();
if let Some(lladdr) = lladdr {
let lladdr = check!(lladdr.parse(self.caps.medium));
if !lladdr.is_unicast() || !target_addr.is_unicast() {
if !lladdr.is_unicast() || !target_addr.x_is_unicast() {
return None;
}
if flags.contains(NdiscNeighborFlags::OVERRIDE)
Expand All @@ -454,7 +455,7 @@ impl InterfaceInner {
} => {
if let Some(lladdr) = lladdr {
let lladdr = check!(lladdr.parse(self.caps.medium));
if !lladdr.is_unicast() || !target_addr.is_unicast() {
if !lladdr.is_unicast() || !target_addr.x_is_unicast() {
return None;
}
self.neighbor_cache
Expand Down Expand Up @@ -492,7 +493,7 @@ impl InterfaceInner {
let src_addr = ipv6_repr.dst_addr;
let dst_addr = ipv6_repr.src_addr;

let src_addr = if src_addr.is_unicast() {
let src_addr = if src_addr.x_is_unicast() {
src_addr
} else {
self.get_source_address_ipv6(&dst_addr)
Expand Down Expand Up @@ -524,7 +525,7 @@ impl InterfaceInner {

// Per [RFC 3810 § 5.2.14], all MLDv2 reports are sent to ff02::16.
// [RFC 3810 § 5.2.14]: https://tools.ietf.org/html/rfc3810#section-5.2.14
let dst_addr = Ipv6Address::LINK_LOCAL_ALL_MLDV2_ROUTERS;
let dst_addr = IPV6_LINK_LOCAL_ALL_MLDV2_ROUTERS;

// Create a dummy IPv6 extension header so we can calculate the total length of the packet.
// The actual extension header will be created later by Packet::emit_payload().
Expand Down
Loading
Loading