#[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> { 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(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::socket::udp; 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, }); let dst_addr = ip_repr.dst_addr(); // Bind the socket to port 68 let socket = sockets.get_mut::(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(), false, ip_repr, 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::(socket_handle); assert!(socket.can_recv()); assert_eq!( socket.recv(), Ok(( &UDP_PAYLOAD[..], udp::UdpMetadata { local_address: Some(dst_addr), ..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], timestamp: 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], timestamp: 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, ); }