blob: b4b4416b0cf0716370d865e1e9252c7268e48efc [file] [log] [blame]
#[cfg(feature = "proto-ipv4")]
mod ipv4;
#[cfg(feature = "proto-ipv6")]
mod ipv6;
#[cfg(feature = "proto-sixlowpan")]
mod sixlowpan;
#[cfg(feature = "proto-igmp")]
use std::vec::Vec;
use crate::tests::setup;
use rstest::*;
use super::*;
use crate::iface::Interface;
use crate::phy::ChecksumCapabilities;
#[cfg(feature = "alloc")]
use crate::phy::Loopback;
use crate::time::Instant;
#[allow(unused)]
fn fill_slice(s: &mut [u8], val: u8) {
for x in s.iter_mut() {
*x = val
}
}
#[cfg(feature = "proto-igmp")]
fn recv_all(device: &mut crate::tests::TestingDevice, timestamp: Instant) -> Vec<Vec<u8>> {
let mut pkts = Vec::new();
while let Some((rx, _tx)) = device.receive(timestamp) {
rx.consume(|pkt| {
pkts.push(pkt.to_vec());
});
}
pkts
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
struct MockTxToken;
impl TxToken for MockTxToken {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut junk = [0; 1536];
f(&mut junk[..len])
}
}
#[test]
#[should_panic(expected = "The hardware address does not match the medium of the interface.")]
#[cfg(all(feature = "medium-ip", feature = "medium-ethernet", feature = "alloc"))]
fn test_new_panic() {
let mut device = Loopback::new(Medium::Ethernet);
let config = Config::new(HardwareAddress::Ip);
Interface::new(config, &mut device, Instant::ZERO);
}
#[rstest]
#[cfg(feature = "default")]
fn test_handle_udp_broadcast(
#[values(Medium::Ip, Medium::Ethernet, Medium::Ieee802154)] medium: Medium,
) {
use crate::wire::IpEndpoint;
static UDP_PAYLOAD: [u8; 5] = [0x48, 0x65, 0x6c, 0x6c, 0x6f];
let (mut iface, mut sockets, _device) = setup(medium);
let rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 15]);
let tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 15]);
let udp_socket = udp::Socket::new(rx_buffer, tx_buffer);
let mut udp_bytes = vec![0u8; 13];
let mut packet = UdpPacket::new_unchecked(&mut udp_bytes);
let socket_handle = sockets.add(udp_socket);
#[cfg(feature = "proto-ipv6")]
let src_ip = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
#[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
let src_ip = Ipv4Address::new(0x7f, 0x00, 0x00, 0x02);
let udp_repr = UdpRepr {
src_port: 67,
dst_port: 68,
};
#[cfg(feature = "proto-ipv6")]
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
src_addr: src_ip,
dst_addr: Ipv6Address::LINK_LOCAL_ALL_NODES,
next_header: IpProtocol::Udp,
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 0x40,
});
#[cfg(all(not(feature = "proto-ipv6"), feature = "proto-ipv4"))]
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
src_addr: src_ip,
dst_addr: Ipv4Address::BROADCAST,
next_header: IpProtocol::Udp,
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
hop_limit: 0x40,
});
// Bind the socket to port 68
let socket = sockets.get_mut::<udp::Socket>(socket_handle);
assert_eq!(socket.bind(68), Ok(()));
assert!(!socket.can_recv());
assert!(socket.can_send());
udp_repr.emit(
&mut packet,
&ip_repr.src_addr(),
&ip_repr.dst_addr(),
UDP_PAYLOAD.len(),
|buf| buf.copy_from_slice(&UDP_PAYLOAD),
&ChecksumCapabilities::default(),
);
// Packet should be handled by bound UDP socket
assert_eq!(
iface.inner.process_udp(
&mut sockets,
PacketMeta::default(),
ip_repr,
udp_repr,
false,
&UDP_PAYLOAD,
packet.into_inner(),
),
None
);
// Make sure the payload to the UDP packet processed by process_udp is
// appended to the bound sockets rx_buffer
let socket = sockets.get_mut::<udp::Socket>(socket_handle);
assert!(socket.can_recv());
assert_eq!(
socket.recv(),
Ok((&UDP_PAYLOAD[..], IpEndpoint::new(src_ip.into(), 67).into()))
);
}
#[test]
#[cfg(all(feature = "medium-ip", feature = "socket-tcp", feature = "proto-ipv6"))]
pub fn tcp_not_accepted() {
let (mut iface, mut sockets, _) = setup(Medium::Ip);
let tcp = TcpRepr {
src_port: 4242,
dst_port: 4243,
control: TcpControl::Syn,
seq_number: TcpSeqNumber(-10001),
ack_number: None,
window_len: 256,
window_scale: None,
max_seg_size: None,
sack_permitted: false,
sack_ranges: [None, None, None],
payload: &[],
};
let mut tcp_bytes = vec![0u8; tcp.buffer_len()];
tcp.emit(
&mut TcpPacket::new_unchecked(&mut tcp_bytes),
&Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2).into(),
&Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1).into(),
&ChecksumCapabilities::default(),
);
assert_eq!(
iface.inner.process_tcp(
&mut sockets,
IpRepr::Ipv6(Ipv6Repr {
src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
next_header: IpProtocol::Tcp,
payload_len: tcp.buffer_len(),
hop_limit: 64,
}),
&tcp_bytes,
),
Some(Packet::new_ipv6(
Ipv6Repr {
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: tcp.buffer_len(),
hop_limit: 64,
},
IpPayload::Tcp(TcpRepr {
src_port: 4243,
dst_port: 4242,
control: TcpControl::Rst,
seq_number: TcpSeqNumber(0),
ack_number: Some(TcpSeqNumber(-10000)),
window_len: 0,
window_scale: None,
max_seg_size: None,
sack_permitted: false,
sack_ranges: [None, None, None],
payload: &[],
})
))
);
// Unspecified destination address.
tcp.emit(
&mut TcpPacket::new_unchecked(&mut tcp_bytes),
&Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2).into(),
&Ipv6Address::UNSPECIFIED.into(),
&ChecksumCapabilities::default(),
);
assert_eq!(
iface.inner.process_tcp(
&mut sockets,
IpRepr::Ipv6(Ipv6Repr {
src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
dst_addr: Ipv6Address::UNSPECIFIED,
next_header: IpProtocol::Tcp,
payload_len: tcp.buffer_len(),
hop_limit: 64,
}),
&tcp_bytes,
),
None,
);
}