123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- use super::*;
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_no_icmp_no_unicast(#[case] medium: Medium) {
- let (mut iface, mut sockets, _) = setup(medium);
- // Unknown Ipv4 Protocol
- //
- // Because the destination is the broadcast address
- // this should not trigger and Destination Unreachable
- // response. See RFC 1122 § 3.2.2.
- let repr = IpRepr::Ipv4(Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- dst_addr: Ipv4Address::BROADCAST,
- next_header: IpProtocol::Unknown(0x0c),
- payload_len: 0,
- hop_limit: 0x40,
- });
- let mut bytes = vec![0u8; 54];
- repr.emit(&mut bytes, &ChecksumCapabilities::default());
- let frame = Ipv4Packet::new_unchecked(&bytes[..]);
- // Ensure that the unknown protocol frame does not trigger an
- // ICMP error response when the destination address is a
- // broadcast address
- assert_eq!(
- iface.inner.process_ipv4(
- &mut sockets,
- PacketMeta::default(),
- &frame,
- &mut iface.fragments
- ),
- None
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_icmp_error_no_payload(#[case] medium: Medium) {
- static NO_BYTES: [u8; 0] = [];
- let (mut iface, mut sockets, _device) = setup(medium);
- // Unknown Ipv4 Protocol with no payload
- let repr = IpRepr::Ipv4(Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- next_header: IpProtocol::Unknown(0x0c),
- payload_len: 0,
- hop_limit: 0x40,
- });
- let mut bytes = vec![0u8; 34];
- repr.emit(&mut bytes, &ChecksumCapabilities::default());
- let frame = Ipv4Packet::new_unchecked(&bytes[..]);
- // The expected Destination Unreachable response due to the
- // unknown protocol
- let icmp_repr = Icmpv4Repr::DstUnreachable {
- reason: Icmpv4DstUnreachable::ProtoUnreachable,
- header: Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- next_header: IpProtocol::Unknown(12),
- payload_len: 0,
- hop_limit: 64,
- },
- data: &NO_BYTES,
- };
- let expected_repr = Packet::new_ipv4(
- Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- next_header: IpProtocol::Icmp,
- payload_len: icmp_repr.buffer_len(),
- hop_limit: 64,
- },
- IpPayload::Icmpv4(icmp_repr),
- );
- // Ensure that the unknown protocol triggers an error response.
- // And we correctly handle no payload.
- assert_eq!(
- iface.inner.process_ipv4(
- &mut sockets,
- PacketMeta::default(),
- &frame,
- &mut iface.fragments
- ),
- Some(expected_repr)
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_local_subnet_broadcasts(#[case] medium: Medium) {
- let (mut iface, _, _device) = setup(medium);
- iface.update_ip_addrs(|addrs| {
- addrs.iter_mut().next().map(|addr| {
- *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 23]), 24));
- });
- });
- assert!(iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
- assert!(iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 255])));
- assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 254])));
- iface.update_ip_addrs(|addrs| {
- addrs.iter_mut().next().map(|addr| {
- *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 16));
- });
- });
- assert!(iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 168, 23, 255])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 168, 23, 254])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 168, 255, 254])));
- assert!(iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 168, 255, 255])));
- iface.update_ip_addrs(|addrs| {
- addrs.iter_mut().next().map(|addr| {
- *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 8));
- });
- });
- assert!(iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
- assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 255])));
- assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 254])));
- assert!(!iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 255, 255, 254])));
- assert!(iface
- .inner
- .is_broadcast_v4(Ipv4Address([192, 255, 255, 255])));
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "medium-ip", feature = "socket-udp"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "medium-ethernet", feature = "socket-udp"))]
- fn test_icmp_error_port_unreachable(#[case] medium: Medium) {
- static UDP_PAYLOAD: [u8; 12] = [
- 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f, 0x6c, 0x64, 0x21,
- ];
- let (mut iface, mut sockets, _device) = setup(medium);
- let mut udp_bytes_unicast = vec![0u8; 20];
- let mut udp_bytes_broadcast = vec![0u8; 20];
- let mut packet_unicast = UdpPacket::new_unchecked(&mut udp_bytes_unicast);
- let mut packet_broadcast = UdpPacket::new_unchecked(&mut udp_bytes_broadcast);
- let udp_repr = UdpRepr {
- src_port: 67,
- dst_port: 68,
- };
- let ip_repr = IpRepr::Ipv4(Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- next_header: IpProtocol::Udp,
- payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
- hop_limit: 64,
- });
- // Emit the representations to a packet
- udp_repr.emit(
- &mut packet_unicast,
- &ip_repr.src_addr(),
- &ip_repr.dst_addr(),
- UDP_PAYLOAD.len(),
- |buf| buf.copy_from_slice(&UDP_PAYLOAD),
- &ChecksumCapabilities::default(),
- );
- let data = packet_unicast.into_inner();
- // The expected Destination Unreachable ICMPv4 error response due
- // to no sockets listening on the destination port.
- let icmp_repr = Icmpv4Repr::DstUnreachable {
- reason: Icmpv4DstUnreachable::PortUnreachable,
- header: Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- next_header: IpProtocol::Udp,
- payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
- hop_limit: 64,
- },
- data,
- };
- let expected_repr = Packet::new_ipv4(
- Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- dst_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- next_header: IpProtocol::Icmp,
- payload_len: icmp_repr.buffer_len(),
- hop_limit: 64,
- },
- IpPayload::Icmpv4(icmp_repr),
- );
- // Ensure that the unknown protocol triggers an error response.
- // And we correctly handle no payload.
- assert_eq!(
- iface.inner.process_udp(
- &mut sockets,
- PacketMeta::default(),
- ip_repr,
- udp_repr,
- false,
- &UDP_PAYLOAD,
- data
- ),
- Some(expected_repr)
- );
- let ip_repr = IpRepr::Ipv4(Ipv4Repr {
- src_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x02]),
- dst_addr: Ipv4Address::BROADCAST,
- next_header: IpProtocol::Udp,
- payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
- hop_limit: 64,
- });
- // Emit the representations to a packet
- udp_repr.emit(
- &mut packet_broadcast,
- &ip_repr.src_addr(),
- &IpAddress::Ipv4(Ipv4Address::BROADCAST),
- UDP_PAYLOAD.len(),
- |buf| buf.copy_from_slice(&UDP_PAYLOAD),
- &ChecksumCapabilities::default(),
- );
- // Ensure that the port unreachable error does not trigger an
- // ICMP error response when the destination address is a
- // broadcast address and no socket is bound to the port.
- assert_eq!(
- iface.inner.process_udp(
- &mut sockets,
- PacketMeta::default(),
- ip_repr,
- udp_repr,
- false,
- &UDP_PAYLOAD,
- packet_broadcast.into_inner(),
- ),
- None
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_handle_ipv4_broadcast(#[case] medium: Medium) {
- use crate::wire::{Icmpv4Packet, Icmpv4Repr};
- let (mut iface, mut sockets, _device) = setup(medium);
- let our_ipv4_addr = iface.ipv4_addr().unwrap();
- let src_ipv4_addr = Ipv4Address([127, 0, 0, 2]);
- // ICMPv4 echo request
- let icmpv4_data: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
- let icmpv4_repr = Icmpv4Repr::EchoRequest {
- ident: 0x1234,
- seq_no: 0xabcd,
- data: &icmpv4_data,
- };
- // Send to IPv4 broadcast address
- let ipv4_repr = Ipv4Repr {
- src_addr: src_ipv4_addr,
- dst_addr: Ipv4Address::BROADCAST,
- next_header: IpProtocol::Icmp,
- hop_limit: 64,
- payload_len: icmpv4_repr.buffer_len(),
- };
- // Emit to ip frame
- let mut bytes = vec![0u8; ipv4_repr.buffer_len() + icmpv4_repr.buffer_len()];
- let frame = {
- ipv4_repr.emit(
- &mut Ipv4Packet::new_unchecked(&mut bytes[..]),
- &ChecksumCapabilities::default(),
- );
- icmpv4_repr.emit(
- &mut Icmpv4Packet::new_unchecked(&mut bytes[ipv4_repr.buffer_len()..]),
- &ChecksumCapabilities::default(),
- );
- Ipv4Packet::new_unchecked(&bytes[..])
- };
- // Expected ICMPv4 echo reply
- let expected_icmpv4_repr = Icmpv4Repr::EchoReply {
- ident: 0x1234,
- seq_no: 0xabcd,
- data: &icmpv4_data,
- };
- let expected_ipv4_repr = Ipv4Repr {
- src_addr: our_ipv4_addr,
- dst_addr: src_ipv4_addr,
- next_header: IpProtocol::Icmp,
- hop_limit: 64,
- payload_len: expected_icmpv4_repr.buffer_len(),
- };
- let expected_packet =
- Packet::new_ipv4(expected_ipv4_repr, IpPayload::Icmpv4(expected_icmpv4_repr));
- assert_eq!(
- iface.inner.process_ipv4(
- &mut sockets,
- PacketMeta::default(),
- &frame,
- &mut iface.fragments
- ),
- Some(expected_packet)
- );
- }
- #[rstest]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_handle_valid_arp_request(#[case] medium: Medium) {
- let (mut iface, mut sockets, _device) = setup(medium);
- let mut eth_bytes = vec![0u8; 42];
- let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
- let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
- let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
- let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
- let repr = ArpRepr::EthernetIpv4 {
- operation: ArpOperation::Request,
- source_hardware_addr: remote_hw_addr,
- source_protocol_addr: remote_ip_addr,
- target_hardware_addr: EthernetAddress::default(),
- target_protocol_addr: local_ip_addr,
- };
- let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
- frame.set_dst_addr(EthernetAddress::BROADCAST);
- frame.set_src_addr(remote_hw_addr);
- frame.set_ethertype(EthernetProtocol::Arp);
- let mut packet = ArpPacket::new_unchecked(frame.payload_mut());
- repr.emit(&mut packet);
- // Ensure an ARP Request for us triggers an ARP Reply
- assert_eq!(
- iface.inner.process_ethernet(
- &mut sockets,
- PacketMeta::default(),
- frame.into_inner(),
- &mut iface.fragments
- ),
- Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
- operation: ArpOperation::Reply,
- source_hardware_addr: local_hw_addr,
- source_protocol_addr: local_ip_addr,
- target_hardware_addr: remote_hw_addr,
- target_protocol_addr: remote_ip_addr
- }))
- );
- // Ensure the address of the requester was entered in the cache
- assert_eq!(
- iface.inner.lookup_hardware_addr(
- MockTxToken,
- &IpAddress::Ipv4(local_ip_addr),
- &IpAddress::Ipv4(remote_ip_addr),
- &mut iface.fragmenter,
- ),
- Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
- );
- }
- #[rstest]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_handle_other_arp_request(#[case] medium: Medium) {
- let (mut iface, mut sockets, _device) = setup(medium);
- let mut eth_bytes = vec![0u8; 42];
- let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
- let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
- let repr = ArpRepr::EthernetIpv4 {
- operation: ArpOperation::Request,
- source_hardware_addr: remote_hw_addr,
- source_protocol_addr: remote_ip_addr,
- target_hardware_addr: EthernetAddress::default(),
- target_protocol_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x03]),
- };
- let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
- frame.set_dst_addr(EthernetAddress::BROADCAST);
- frame.set_src_addr(remote_hw_addr);
- frame.set_ethertype(EthernetProtocol::Arp);
- let mut packet = ArpPacket::new_unchecked(frame.payload_mut());
- repr.emit(&mut packet);
- // Ensure an ARP Request for someone else does not trigger an ARP Reply
- assert_eq!(
- iface.inner.process_ethernet(
- &mut sockets,
- PacketMeta::default(),
- frame.into_inner(),
- &mut iface.fragments
- ),
- None
- );
- // Ensure the address of the requester was NOT entered in the cache
- assert_eq!(
- iface.inner.lookup_hardware_addr(
- MockTxToken,
- &IpAddress::Ipv4(Ipv4Address([0x7f, 0x00, 0x00, 0x01])),
- &IpAddress::Ipv4(remote_ip_addr),
- &mut iface.fragmenter,
- ),
- Err(DispatchError::NeighborPending)
- );
- }
- #[rstest]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_arp_flush_after_update_ip(#[case] medium: Medium) {
- let (mut iface, mut sockets, _device) = setup(medium);
- let mut eth_bytes = vec![0u8; 42];
- let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
- let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
- let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
- let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
- let repr = ArpRepr::EthernetIpv4 {
- operation: ArpOperation::Request,
- source_hardware_addr: remote_hw_addr,
- source_protocol_addr: remote_ip_addr,
- target_hardware_addr: EthernetAddress::default(),
- target_protocol_addr: Ipv4Address([0x7f, 0x00, 0x00, 0x01]),
- };
- let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
- frame.set_dst_addr(EthernetAddress::BROADCAST);
- frame.set_src_addr(remote_hw_addr);
- frame.set_ethertype(EthernetProtocol::Arp);
- {
- let mut packet = ArpPacket::new_unchecked(frame.payload_mut());
- repr.emit(&mut packet);
- }
- // Ensure an ARP Request for us triggers an ARP Reply
- assert_eq!(
- iface.inner.process_ethernet(
- &mut sockets,
- PacketMeta::default(),
- frame.into_inner(),
- &mut iface.fragments
- ),
- Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
- operation: ArpOperation::Reply,
- source_hardware_addr: local_hw_addr,
- source_protocol_addr: local_ip_addr,
- target_hardware_addr: remote_hw_addr,
- target_protocol_addr: remote_ip_addr
- }))
- );
- // Ensure the address of the requester was entered in the cache
- assert_eq!(
- iface.inner.lookup_hardware_addr(
- MockTxToken,
- &IpAddress::Ipv4(local_ip_addr),
- &IpAddress::Ipv4(remote_ip_addr),
- &mut iface.fragmenter,
- ),
- Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
- );
- // Update IP addrs to trigger ARP cache flush
- let local_ip_addr_new = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
- iface.update_ip_addrs(|addrs| {
- addrs.iter_mut().next().map(|addr| {
- *addr = IpCidr::Ipv4(Ipv4Cidr::new(local_ip_addr_new, 24));
- });
- });
- // ARP cache flush after address change
- assert!(!iface.inner.has_neighbor(&IpAddress::Ipv4(remote_ip_addr)));
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "socket-icmp", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "socket-icmp", feature = "medium-ethernet"))]
- fn test_icmpv4_socket(#[case] medium: Medium) {
- use crate::wire::Icmpv4Packet;
- let (mut iface, mut sockets, _device) = setup(medium);
- let rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 24]);
- let tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 24]);
- let icmpv4_socket = icmp::Socket::new(rx_buffer, tx_buffer);
- let socket_handle = sockets.add(icmpv4_socket);
- let ident = 0x1234;
- let seq_no = 0x5432;
- let echo_data = &[0xff; 16];
- let socket = sockets.get_mut::<icmp::Socket>(socket_handle);
- // Bind to the ID 0x1234
- assert_eq!(socket.bind(icmp::Endpoint::Ident(ident)), Ok(()));
- // Ensure the ident we bound to and the ident of the packet are the same.
- let mut bytes = [0xff; 24];
- let mut packet = Icmpv4Packet::new_unchecked(&mut bytes[..]);
- let echo_repr = Icmpv4Repr::EchoRequest {
- ident,
- seq_no,
- data: echo_data,
- };
- echo_repr.emit(&mut packet, &ChecksumCapabilities::default());
- let icmp_data = &*packet.into_inner();
- let ipv4_repr = Ipv4Repr {
- src_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
- dst_addr: Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
- next_header: IpProtocol::Icmp,
- payload_len: 24,
- hop_limit: 64,
- };
- let ip_repr = IpRepr::Ipv4(ipv4_repr);
- // Open a socket and ensure the packet is handled due to the listening
- // socket.
- assert!(!sockets.get_mut::<icmp::Socket>(socket_handle).can_recv());
- // Confirm we still get EchoReply from `smoltcp` even with the ICMP socket listening
- let echo_reply = Icmpv4Repr::EchoReply {
- ident,
- seq_no,
- data: echo_data,
- };
- let ipv4_reply = Ipv4Repr {
- src_addr: ipv4_repr.dst_addr,
- dst_addr: ipv4_repr.src_addr,
- ..ipv4_repr
- };
- assert_eq!(
- iface.inner.process_icmpv4(&mut sockets, ip_repr, icmp_data),
- Some(Packet::new_ipv4(ipv4_reply, IpPayload::Icmpv4(echo_reply)))
- );
- let socket = sockets.get_mut::<icmp::Socket>(socket_handle);
- assert!(socket.can_recv());
- assert_eq!(
- socket.recv(),
- Ok((
- icmp_data,
- IpAddress::Ipv4(Ipv4Address::new(0x7f, 0x00, 0x00, 0x02))
- ))
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "proto-igmp", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "proto-igmp", feature = "medium-ethernet"))]
- fn test_handle_igmp(#[case] medium: Medium) {
- fn recv_igmp(
- device: &mut crate::tests::TestingDevice,
- timestamp: Instant,
- ) -> Vec<(Ipv4Repr, IgmpRepr)> {
- let caps = device.capabilities();
- let checksum_caps = &caps.checksum;
- recv_all(device, timestamp)
- .iter()
- .filter_map(|frame| {
- let ipv4_packet = match caps.medium {
- #[cfg(feature = "medium-ethernet")]
- Medium::Ethernet => {
- let eth_frame = EthernetFrame::new_checked(frame).ok()?;
- Ipv4Packet::new_checked(eth_frame.payload()).ok()?
- }
- #[cfg(feature = "medium-ip")]
- Medium::Ip => Ipv4Packet::new_checked(&frame[..]).ok()?,
- #[cfg(feature = "medium-ieee802154")]
- Medium::Ieee802154 => todo!(),
- };
- let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, checksum_caps).ok()?;
- let ip_payload = ipv4_packet.payload();
- let igmp_packet = IgmpPacket::new_checked(ip_payload).ok()?;
- let igmp_repr = IgmpRepr::parse(&igmp_packet).ok()?;
- Some((ipv4_repr, igmp_repr))
- })
- .collect::<Vec<_>>()
- }
- let groups = [
- Ipv4Address::new(224, 0, 0, 22),
- Ipv4Address::new(224, 0, 0, 56),
- ];
- let (mut iface, mut sockets, mut device) = setup(medium);
- // Join multicast groups
- let timestamp = Instant::ZERO;
- for group in &groups {
- iface
- .join_multicast_group(&mut device, *group, timestamp)
- .unwrap();
- }
- let reports = recv_igmp(&mut device, timestamp);
- assert_eq!(reports.len(), 2);
- for (i, group_addr) in groups.iter().enumerate() {
- assert_eq!(reports[i].0.next_header, IpProtocol::Igmp);
- assert_eq!(reports[i].0.dst_addr, *group_addr);
- assert_eq!(
- reports[i].1,
- IgmpRepr::MembershipReport {
- group_addr: *group_addr,
- version: IgmpVersion::Version2,
- }
- );
- }
- // General query
- let timestamp = Instant::ZERO;
- const GENERAL_QUERY_BYTES: &[u8] = &[
- 0x46, 0xc0, 0x00, 0x24, 0xed, 0xb4, 0x00, 0x00, 0x01, 0x02, 0x47, 0x43, 0xac, 0x16, 0x63,
- 0x04, 0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00, 0x11, 0x64, 0xec, 0x8f, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- ];
- {
- // Transmit GENERAL_QUERY_BYTES into loopback
- let tx_token = device.transmit(timestamp).unwrap();
- tx_token.consume(GENERAL_QUERY_BYTES.len(), |buffer| {
- buffer.copy_from_slice(GENERAL_QUERY_BYTES);
- });
- }
- // Trigger processing until all packets received through the
- // loopback have been processed, including responses to
- // GENERAL_QUERY_BYTES. Therefore `recv_all()` would return 0
- // pkts that could be checked.
- iface.socket_ingress(&mut device, &mut sockets);
- // Leave multicast groups
- let timestamp = Instant::ZERO;
- for group in &groups {
- iface
- .leave_multicast_group(&mut device, *group, timestamp)
- .unwrap();
- }
- let leaves = recv_igmp(&mut device, timestamp);
- assert_eq!(leaves.len(), 2);
- for (i, group_addr) in groups.iter().cloned().enumerate() {
- assert_eq!(leaves[i].0.next_header, IpProtocol::Igmp);
- assert_eq!(leaves[i].0.dst_addr, Ipv4Address::MULTICAST_ALL_ROUTERS);
- assert_eq!(leaves[i].1, IgmpRepr::LeaveGroup { group_addr });
- }
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "socket-raw", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "socket-raw", feature = "medium-ethernet"))]
- fn test_raw_socket_no_reply(#[case] medium: Medium) {
- use crate::wire::{IpVersion, UdpPacket, UdpRepr};
- let (mut iface, mut sockets, _) = setup(medium);
- let packets = 1;
- let rx_buffer =
- raw::PacketBuffer::new(vec![raw::PacketMetadata::EMPTY; packets], vec![0; 48 * 1]);
- let tx_buffer = raw::PacketBuffer::new(
- vec![raw::PacketMetadata::EMPTY; packets],
- vec![0; 48 * packets],
- );
- let raw_socket = raw::Socket::new(IpVersion::Ipv4, IpProtocol::Udp, rx_buffer, tx_buffer);
- sockets.add(raw_socket);
- let src_addr = Ipv4Address([127, 0, 0, 2]);
- let dst_addr = Ipv4Address([127, 0, 0, 1]);
- const PAYLOAD_LEN: usize = 10;
- let udp_repr = UdpRepr {
- src_port: 67,
- dst_port: 68,
- };
- let mut bytes = vec![0xff; udp_repr.header_len() + PAYLOAD_LEN];
- let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
- udp_repr.emit(
- &mut packet,
- &src_addr.into(),
- &dst_addr.into(),
- PAYLOAD_LEN,
- |buf| fill_slice(buf, 0x2a),
- &ChecksumCapabilities::default(),
- );
- let ipv4_repr = Ipv4Repr {
- src_addr,
- dst_addr,
- next_header: IpProtocol::Udp,
- hop_limit: 64,
- payload_len: udp_repr.header_len() + PAYLOAD_LEN,
- };
- // Emit to frame
- let mut bytes = vec![0u8; ipv4_repr.buffer_len() + udp_repr.header_len() + PAYLOAD_LEN];
- let frame = {
- ipv4_repr.emit(
- &mut Ipv4Packet::new_unchecked(&mut bytes),
- &ChecksumCapabilities::default(),
- );
- udp_repr.emit(
- &mut UdpPacket::new_unchecked(&mut bytes[ipv4_repr.buffer_len()..]),
- &src_addr.into(),
- &dst_addr.into(),
- PAYLOAD_LEN,
- |buf| fill_slice(buf, 0x2a),
- &ChecksumCapabilities::default(),
- );
- Ipv4Packet::new_unchecked(&bytes[..])
- };
- assert_eq!(
- iface.inner.process_ipv4(
- &mut sockets,
- PacketMeta::default(),
- &frame,
- &mut iface.fragments
- ),
- None
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "socket-raw", feature = "socket-udp", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(
- feature = "socket-raw",
- feature = "socket-udp",
- feature = "medium-ethernet"
- ))]
- fn test_raw_socket_with_udp_socket(#[case] medium: Medium) {
- use crate::wire::{IpEndpoint, IpVersion, UdpPacket, UdpRepr};
- static UDP_PAYLOAD: [u8; 5] = [0x48, 0x65, 0x6c, 0x6c, 0x6f];
- let (mut iface, mut sockets, _) = setup(medium);
- let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 15]);
- let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 15]);
- let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
- let udp_socket_handle = sockets.add(udp_socket);
- // Bind the socket to port 68
- let socket = sockets.get_mut::<udp::Socket>(udp_socket_handle);
- assert_eq!(socket.bind(68), Ok(()));
- assert!(!socket.can_recv());
- assert!(socket.can_send());
- let packets = 1;
- let raw_rx_buffer =
- raw::PacketBuffer::new(vec![raw::PacketMetadata::EMPTY; packets], vec![0; 48 * 1]);
- let raw_tx_buffer = raw::PacketBuffer::new(
- vec![raw::PacketMetadata::EMPTY; packets],
- vec![0; 48 * packets],
- );
- let raw_socket = raw::Socket::new(
- IpVersion::Ipv4,
- IpProtocol::Udp,
- raw_rx_buffer,
- raw_tx_buffer,
- );
- sockets.add(raw_socket);
- let src_addr = Ipv4Address([127, 0, 0, 2]);
- let dst_addr = Ipv4Address([127, 0, 0, 1]);
- let udp_repr = UdpRepr {
- src_port: 67,
- dst_port: 68,
- };
- let mut bytes = vec![0xff; udp_repr.header_len() + UDP_PAYLOAD.len()];
- let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
- udp_repr.emit(
- &mut packet,
- &src_addr.into(),
- &dst_addr.into(),
- UDP_PAYLOAD.len(),
- |buf| buf.copy_from_slice(&UDP_PAYLOAD),
- &ChecksumCapabilities::default(),
- );
- let ipv4_repr = Ipv4Repr {
- src_addr,
- dst_addr,
- next_header: IpProtocol::Udp,
- hop_limit: 64,
- payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
- };
- // Emit to frame
- let mut bytes = vec![0u8; ipv4_repr.buffer_len() + udp_repr.header_len() + UDP_PAYLOAD.len()];
- let frame = {
- ipv4_repr.emit(
- &mut Ipv4Packet::new_unchecked(&mut bytes),
- &ChecksumCapabilities::default(),
- );
- udp_repr.emit(
- &mut UdpPacket::new_unchecked(&mut bytes[ipv4_repr.buffer_len()..]),
- &src_addr.into(),
- &dst_addr.into(),
- UDP_PAYLOAD.len(),
- |buf| buf.copy_from_slice(&UDP_PAYLOAD),
- &ChecksumCapabilities::default(),
- );
- Ipv4Packet::new_unchecked(&bytes[..])
- };
- assert_eq!(
- iface.inner.process_ipv4(
- &mut sockets,
- PacketMeta::default(),
- &frame,
- &mut iface.fragments
- ),
- None
- );
- // Make sure the UDP socket can still receive in presence of a Raw socket that handles UDP
- let socket = sockets.get_mut::<udp::Socket>(udp_socket_handle);
- assert!(socket.can_recv());
- assert_eq!(
- socket.recv(),
- Ok((
- &UDP_PAYLOAD[..],
- IpEndpoint::new(src_addr.into(), 67).into()
- ))
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "socket-udp", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "socket-udp", feature = "medium-ethernet"))]
- fn test_icmp_reply_size(#[case] medium: Medium) {
- use crate::wire::IPV4_MIN_MTU as MIN_MTU;
- const MAX_PAYLOAD_LEN: usize = 528;
- let (mut iface, mut sockets, _device) = setup(medium);
- let src_addr = Ipv4Address([192, 168, 1, 1]);
- let dst_addr = Ipv4Address([192, 168, 1, 2]);
- // UDP packet that if not tructated will cause a icmp port unreachable reply
- // to exceed the minimum mtu bytes in length.
- let udp_repr = UdpRepr {
- src_port: 67,
- dst_port: 68,
- };
- let mut bytes = vec![0xff; udp_repr.header_len() + MAX_PAYLOAD_LEN];
- let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
- udp_repr.emit(
- &mut packet,
- &src_addr.into(),
- &dst_addr.into(),
- MAX_PAYLOAD_LEN,
- |buf| fill_slice(buf, 0x2a),
- &ChecksumCapabilities::default(),
- );
- let ip_repr = Ipv4Repr {
- src_addr,
- dst_addr,
- next_header: IpProtocol::Udp,
- hop_limit: 64,
- payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
- };
- let payload = packet.into_inner();
- let expected_icmp_repr = Icmpv4Repr::DstUnreachable {
- reason: Icmpv4DstUnreachable::PortUnreachable,
- header: ip_repr,
- data: &payload[..MAX_PAYLOAD_LEN],
- };
- let expected_ip_repr = Ipv4Repr {
- src_addr: dst_addr,
- dst_addr: src_addr,
- next_header: IpProtocol::Icmp,
- hop_limit: 64,
- payload_len: expected_icmp_repr.buffer_len(),
- };
- assert_eq!(
- expected_ip_repr.buffer_len() + expected_icmp_repr.buffer_len(),
- MIN_MTU
- );
- assert_eq!(
- iface.inner.process_udp(
- &mut sockets,
- PacketMeta::default(),
- ip_repr.into(),
- udp_repr,
- false,
- &vec![0x2a; MAX_PAYLOAD_LEN],
- payload,
- ),
- Some(Packet::new_ipv4(
- expected_ip_repr,
- IpPayload::Icmpv4(expected_icmp_repr)
- ))
- );
- }
|