1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294 |
- use super::*;
- fn parse_ipv6(data: &[u8]) -> crate::wire::Result<Packet<'_>> {
- let ipv6_header = Ipv6Packet::new_checked(data)?;
- let ipv6 = Ipv6Repr::parse(&ipv6_header)?;
- match ipv6.next_header {
- IpProtocol::HopByHop => todo!(),
- IpProtocol::Icmp => todo!(),
- IpProtocol::Igmp => todo!(),
- IpProtocol::Tcp => todo!(),
- IpProtocol::Udp => todo!(),
- IpProtocol::Ipv6Route => todo!(),
- IpProtocol::Ipv6Frag => todo!(),
- IpProtocol::IpSecEsp => todo!(),
- IpProtocol::IpSecAh => todo!(),
- IpProtocol::Icmpv6 => {
- let icmp = Icmpv6Repr::parse(
- &ipv6.src_addr,
- &ipv6.dst_addr,
- &Icmpv6Packet::new_checked(ipv6_header.payload())?,
- &Default::default(),
- )?;
- Ok(Packet::new_ipv6(ipv6, IpPayload::Icmpv6(icmp)))
- }
- IpProtocol::Ipv6NoNxt => todo!(),
- IpProtocol::Ipv6Opts => todo!(),
- IpProtocol::Unknown(_) => todo!(),
- }
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn multicast_source_address(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1,
- ];
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn hop_by_hop_skip_with_icmp(#[case] medium: Medium) {
- // The following contains:
- // - IPv6 header
- // - Hop-by-hop, with options:
- // - PADN (skipped)
- // - Unknown option (skipped)
- // - ICMP echo request
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0x1, 0x0, 0xf, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
- 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 19,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
- ident: 42,
- seq_no: 420,
- data: b"Lorem Ipsum",
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn hop_by_hop_discard_with_icmp(#[case] medium: Medium) {
- // The following contains:
- // - IPv6 header
- // - Hop-by-hop, with options:
- // - PADN (skipped)
- // - Unknown option (discard)
- // - ICMP echo request
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0x1, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
- 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- fn hop_by_hop_discard_param_problem(#[case] medium: Medium) {
- // The following contains:
- // - IPv6 header
- // - Hop-by-hop, with options:
- // - PADN (skipped)
- // - Unknown option (discard + ParamProblem)
- // - ICMP echo request
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0xC0, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
- 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1),
- dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2),
- next_header: IpProtocol::Icmpv6,
- payload_len: 75,
- hop_limit: 64,
- },
- IpPayload::Icmpv6(Icmpv6Repr::ParamProblem {
- reason: Icmpv6ParamProblem::UnrecognizedOption,
- pointer: 40,
- header: Ipv6Repr {
- src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2),
- dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1),
- next_header: IpProtocol::HopByHop,
- payload_len: 27,
- hop_limit: 64,
- },
- data: &[
- 0x3a, 0x0, 0xC0, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88, 0x0, 0x2a, 0x1,
- 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ],
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- fn hop_by_hop_discard_with_multicast(#[case] medium: Medium) {
- // The following contains:
- // - IPv6 header
- // - Hop-by-hop, with options:
- // - PADN (skipped)
- // - Unknown option (discard (0b11) + ParamProblem)
- // - ICMP echo request
- //
- // In this case, even if the destination address is a multicast address, an ICMPv6 ParamProblem
- // should be transmitted.
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x02, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0x80, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
- 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1),
- dst_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2),
- next_header: IpProtocol::Icmpv6,
- payload_len: 75,
- hop_limit: 64,
- },
- IpPayload::Icmpv6(Icmpv6Repr::ParamProblem {
- reason: Icmpv6ParamProblem::UnrecognizedOption,
- pointer: 40,
- header: Ipv6Repr {
- src_addr: Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2),
- dst_addr: Ipv6Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1),
- next_header: IpProtocol::HopByHop,
- payload_len: 27,
- hop_limit: 64,
- },
- data: &[
- 0x3a, 0x0, 0x80, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88, 0x0, 0x2a, 0x1,
- 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ],
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn imcp_empty_echo_request(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x8, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x84, 0x3c, 0x0, 0x0, 0x0, 0x0,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 8,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoRequest {
- ident: 0,
- seq_no: 0,
- data: b"",
- })
- ))
- );
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 8,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
- ident: 0,
- seq_no: 0,
- data: b"",
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn icmp_echo_request(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x13, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x2c, 0x88, 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72,
- 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 19,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoRequest {
- ident: 42,
- seq_no: 420,
- data: b"Lorem Ipsum",
- })
- ))
- );
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 19,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
- ident: 42,
- seq_no: 420,
- data: b"Lorem Ipsum",
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn icmp_echo_reply_as_input(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x13, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x81, 0x0, 0x2d, 0x56, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x6f, 0x72, 0x65,
- 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 19,
- },
- IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
- ident: 0,
- seq_no: 0,
- data: b"Lorem Ipsum",
- })
- ))
- );
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn unknown_proto_with_multicast_dst_address(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1,
- ];
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 48,
- },
- IpPayload::Icmpv6(Icmpv6Repr::ParamProblem {
- reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
- pointer: 40,
- header: Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 64,
- next_header: IpProtocol::Unknown(0x0c),
- payload_len: 0,
- },
- data: &[],
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ip(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn unknown_proto(#[case] medium: Medium) {
- // Since the destination address is multicast, we should answer with an ICMPv6 message.
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1,
- ];
- let response = Some(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- hop_limit: 64,
- next_header: IpProtocol::Icmpv6,
- payload_len: 48,
- },
- IpPayload::Icmpv6(Icmpv6Repr::ParamProblem {
- reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
- pointer: 40,
- header: Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 64,
- next_header: IpProtocol::Unknown(0x0c),
- payload_len: 0,
- },
- data: &[],
- }),
- ));
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- }
- #[rstest]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn ndsic_neighbor_advertisement_ethernet(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0x9f, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x1,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 255,
- next_header: IpProtocol::Icmpv6,
- payload_len: 32,
- },
- IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
- flags: NdiscNeighborFlags::SOLICITED,
- target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
- lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 1])),
- }))
- ))
- );
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- assert_eq!(
- iface.inner.neighbor_cache.lookup(
- &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
- iface.inner.now,
- ),
- NeighborAnswer::Found(HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
- 0, 0, 0, 0, 0, 1
- ]))),
- );
- }
- #[rstest]
- #[case::ethernet(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn ndsic_neighbor_advertisement_ethernet_multicast_addr(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0xa0, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x1, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 255,
- next_header: IpProtocol::Icmpv6,
- payload_len: 32,
- },
- IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
- flags: NdiscNeighborFlags::SOLICITED,
- target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
- lladdr: Some(RawHardwareAddress::from_bytes(&[
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- ])),
- }))
- ))
- );
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- assert_eq!(
- iface.inner.neighbor_cache.lookup(
- &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
- iface.inner.now,
- ),
- NeighborAnswer::NotFound,
- );
- }
- #[rstest]
- #[case::ieee802154(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn ndsic_neighbor_advertisement_ieee802154(#[case] medium: Medium) {
- let data = [
- 0x60, 0x0, 0x0, 0x0, 0x0, 0x28, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0x96, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- ];
- assert_eq!(
- parse_ipv6(&data),
- Ok(Packet::new_ipv6(
- Ipv6Repr {
- src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
- dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
- hop_limit: 255,
- next_header: IpProtocol::Icmpv6,
- payload_len: 40,
- },
- IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
- flags: NdiscNeighborFlags::SOLICITED,
- target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
- lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 0, 0, 1])),
- }))
- ))
- );
- let response = None;
- let (mut iface, mut sockets, _device) = setup(medium);
- assert_eq!(
- iface.inner.process_ipv6(
- &mut sockets,
- PacketMeta::default(),
- &Ipv6Packet::new_checked(&data[..]).unwrap()
- ),
- response
- );
- assert_eq!(
- iface.inner.neighbor_cache.lookup(
- &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
- iface.inner.now,
- ),
- NeighborAnswer::Found(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
- &[0, 0, 0, 0, 0, 0, 0, 1]
- ))),
- );
- }
- #[rstest]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_handle_valid_ndisc_request(#[case] medium: Medium) {
- let (mut iface, mut sockets, _device) = setup(medium);
- let mut eth_bytes = vec![0u8; 86];
- let local_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1);
- let remote_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2);
- let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
- let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
- let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
- target_addr: local_ip_addr,
- lladdr: Some(remote_hw_addr.into()),
- });
- let ip_repr = IpRepr::Ipv6(Ipv6Repr {
- src_addr: remote_ip_addr,
- dst_addr: local_ip_addr.solicited_node(),
- next_header: IpProtocol::Icmpv6,
- hop_limit: 0xff,
- payload_len: solicit.buffer_len(),
- });
- let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
- frame.set_dst_addr(EthernetAddress([0x33, 0x33, 0x00, 0x00, 0x00, 0x00]));
- frame.set_src_addr(remote_hw_addr);
- frame.set_ethertype(EthernetProtocol::Ipv6);
- ip_repr.emit(frame.payload_mut(), &ChecksumCapabilities::default());
- solicit.emit(
- &remote_ip_addr,
- &local_ip_addr.solicited_node(),
- &mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.header_len()..]),
- &ChecksumCapabilities::default(),
- );
- let icmpv6_expected = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
- flags: NdiscNeighborFlags::SOLICITED,
- target_addr: local_ip_addr,
- lladdr: Some(local_hw_addr.into()),
- });
- let ipv6_expected = Ipv6Repr {
- src_addr: local_ip_addr,
- dst_addr: remote_ip_addr,
- next_header: IpProtocol::Icmpv6,
- hop_limit: 0xff,
- payload_len: icmpv6_expected.buffer_len(),
- };
- // Ensure an Neighbor Solicitation triggers a Neighbor Advertisement
- assert_eq!(
- iface.inner.process_ethernet(
- &mut sockets,
- PacketMeta::default(),
- frame.into_inner(),
- &mut iface.fragments
- ),
- Some(EthernetPacket::Ip(Packet::new_ipv6(
- ipv6_expected,
- IpPayload::Icmpv6(icmpv6_expected)
- )))
- );
- // Ensure the address of the requester was entered in the cache
- assert_eq!(
- iface.inner.lookup_hardware_addr(
- MockTxToken,
- &IpAddress::Ipv6(local_ip_addr),
- &IpAddress::Ipv6(remote_ip_addr),
- &mut iface.fragmenter,
- ),
- Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- #[case(Medium::Ieee802154)]
- #[cfg(feature = "medium-ieee802154")]
- fn test_solicited_node_addrs(#[case] medium: Medium) {
- let (mut iface, _, _) = setup(medium);
- let mut new_addrs = heapless::Vec::<IpCidr, IFACE_MAX_ADDR_COUNT>::new();
- new_addrs
- .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 1, 2, 0, 2), 64))
- .unwrap();
- new_addrs
- .push(IpCidr::new(
- IpAddress::v6(0xfe80, 0, 0, 0, 3, 4, 0, 0xffff),
- 64,
- ))
- .unwrap();
- iface.update_ip_addrs(|addrs| {
- new_addrs.extend(addrs.to_vec());
- *addrs = new_addrs;
- });
- assert!(iface
- .inner
- .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0x0002)));
- assert!(iface
- .inner
- .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0xffff)));
- assert!(!iface
- .inner
- .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0x0003)));
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(all(feature = "socket-udp", feature = "medium-ip"))]
- #[case(Medium::Ethernet)]
- #[cfg(all(feature = "socket-udp", feature = "medium-ethernet"))]
- #[case(Medium::Ieee802154)]
- #[cfg(all(feature = "socket-udp", feature = "medium-ieee802154"))]
- fn test_icmp_reply_size(#[case] medium: Medium) {
- use crate::wire::Icmpv6DstUnreachable;
- use crate::wire::IPV6_MIN_MTU as MIN_MTU;
- const MAX_PAYLOAD_LEN: usize = 1192;
- let (mut iface, mut sockets, _device) = setup(medium);
- let src_addr = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
- let dst_addr = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 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 = Ipv6Repr {
- 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 = Icmpv6Repr::DstUnreachable {
- reason: Icmpv6DstUnreachable::PortUnreachable,
- header: ip_repr,
- data: &payload[..MAX_PAYLOAD_LEN],
- };
- let expected_ip_repr = Ipv6Repr {
- src_addr: dst_addr,
- dst_addr: src_addr,
- next_header: IpProtocol::Icmpv6,
- 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(),
- false,
- ip_repr.into(),
- payload,
- ),
- Some(Packet::new_ipv6(
- expected_ip_repr,
- IpPayload::Icmpv6(expected_icmp_repr)
- ))
- );
- }
- #[cfg(feature = "medium-ip")]
- #[test]
- fn get_source_address() {
- let (mut iface, _, _) = setup(Medium::Ip);
- const OWN_LINK_LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
- const OWN_UNIQUE_LOCAL_ADDR1: Ipv6Address = Ipv6Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 2);
- const OWN_UNIQUE_LOCAL_ADDR2: Ipv6Address = Ipv6Address::new(0xfd01, 0, 0, 201, 1, 1, 1, 2);
- const OWN_GLOBAL_UNICAST_ADDR1: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db8, 0x0003, 0, 0, 0, 0, 1);
- // List of addresses of the interface:
- // fe80::1/64
- // fd00::201:1:1:1:2/64
- // fd01::201:1:1:1:2/64
- // 2001:db8:3::1/64
- iface.update_ip_addrs(|addrs| {
- addrs.clear();
- addrs
- .push(IpCidr::Ipv6(Ipv6Cidr::new(OWN_LINK_LOCAL_ADDR, 64)))
- .unwrap();
- addrs
- .push(IpCidr::Ipv6(Ipv6Cidr::new(OWN_UNIQUE_LOCAL_ADDR1, 64)))
- .unwrap();
- addrs
- .push(IpCidr::Ipv6(Ipv6Cidr::new(OWN_UNIQUE_LOCAL_ADDR2, 64)))
- .unwrap();
- addrs
- .push(IpCidr::Ipv6(Ipv6Cidr::new(OWN_GLOBAL_UNICAST_ADDR1, 64)))
- .unwrap();
- });
- // List of addresses we test:
- // ::1 -> ::1
- // fe80::42 -> fe80::1
- // fd00::201:1:1:1:1 -> fd00::201:1:1:1:2
- // fd01::201:1:1:1:1 -> fd01::201:1:1:1:2
- // fd02::201:1:1:1:1 -> fd00::201:1:1:1:2 (because first added in the list)
- // ff02::1 -> fe80::1 (same scope)
- // 2001:db8:3::2 -> 2001:db8:3::1
- // 2001:db9:3::2 -> 2001:db8:3::1
- const LINK_LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 42);
- const UNIQUE_LOCAL_ADDR1: Ipv6Address = Ipv6Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR2: Ipv6Address = Ipv6Address::new(0xfd01, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR3: Ipv6Address = Ipv6Address::new(0xfd02, 0, 0, 201, 1, 1, 1, 1);
- const GLOBAL_UNICAST_ADDR1: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db8, 0x0003, 0, 0, 0, 0, 2);
- const GLOBAL_UNICAST_ADDR2: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
- assert_eq!(
- iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- OWN_UNIQUE_LOCAL_ADDR1
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- OWN_UNIQUE_LOCAL_ADDR2
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- OWN_UNIQUE_LOCAL_ADDR1
- );
- assert_eq!(
- iface
- .inner
- .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- OWN_GLOBAL_UNICAST_ADDR1
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- OWN_GLOBAL_UNICAST_ADDR1
- );
- assert_eq!(
- iface.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- OWN_UNIQUE_LOCAL_ADDR1
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- OWN_UNIQUE_LOCAL_ADDR2
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- OWN_UNIQUE_LOCAL_ADDR1
- );
- assert_eq!(
- iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- OWN_GLOBAL_UNICAST_ADDR1
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- OWN_GLOBAL_UNICAST_ADDR1
- );
- }
- #[cfg(feature = "medium-ip")]
- #[test]
- fn get_source_address_only_link_local() {
- let (mut iface, _, _) = setup(Medium::Ip);
- // List of addresses in the interface:
- // fe80::1/64
- const OWN_LINK_LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
- iface.update_ip_addrs(|ips| {
- ips.clear();
- ips.push(IpCidr::Ipv6(Ipv6Cidr::new(OWN_LINK_LOCAL_ADDR, 64)))
- .unwrap();
- });
- // List of addresses we test:
- // ::1 -> ::1
- // fe80::42 -> fe80::1
- // fd00::201:1:1:1:1 -> fe80::1
- // fd01::201:1:1:1:1 -> fe80::1
- // fd02::201:1:1:1:1 -> fe80::1
- // ff02::1 -> fe80::1
- // 2001:db8:3::2 -> fe80::1
- // 2001:db9:3::2 -> fe80::1
- const LINK_LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 42);
- const UNIQUE_LOCAL_ADDR1: Ipv6Address = Ipv6Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR2: Ipv6Address = Ipv6Address::new(0xfd01, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR3: Ipv6Address = Ipv6Address::new(0xfd02, 0, 0, 201, 1, 1, 1, 1);
- const GLOBAL_UNICAST_ADDR1: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db8, 0x0003, 0, 0, 0, 0, 2);
- const GLOBAL_UNICAST_ADDR2: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
- assert_eq!(
- iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface
- .inner
- .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- OWN_LINK_LOCAL_ADDR
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- OWN_LINK_LOCAL_ADDR
- );
- }
- #[cfg(feature = "medium-ip")]
- #[test]
- fn get_source_address_empty_interface() {
- let (mut iface, _, _) = setup(Medium::Ip);
- iface.update_ip_addrs(|ips| ips.clear());
- // List of addresses we test:
- // ::1 -> ::1
- // fe80::42 -> ::1
- // fd00::201:1:1:1:1 -> ::1
- // fd01::201:1:1:1:1 -> ::1
- // fd02::201:1:1:1:1 -> ::1
- // ff02::1 -> ::1
- // 2001:db8:3::2 -> ::1
- // 2001:db9:3::2 -> ::1
- const LINK_LOCAL_ADDR: Ipv6Address = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 42);
- const UNIQUE_LOCAL_ADDR1: Ipv6Address = Ipv6Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR2: Ipv6Address = Ipv6Address::new(0xfd01, 0, 0, 201, 1, 1, 1, 1);
- const UNIQUE_LOCAL_ADDR3: Ipv6Address = Ipv6Address::new(0xfd02, 0, 0, 201, 1, 1, 1, 1);
- const GLOBAL_UNICAST_ADDR1: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db8, 0x0003, 0, 0, 0, 0, 2);
- const GLOBAL_UNICAST_ADDR2: Ipv6Address =
- Ipv6Address::new(0x2001, 0x0db9, 0x0003, 0, 0, 0, 0, 2);
- assert_eq!(
- iface.inner.get_source_address_ipv6(&Ipv6Address::LOOPBACK),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface
- .inner
- .get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.inner.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&LINK_LOCAL_ADDR),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR1),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR2),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&UNIQUE_LOCAL_ADDR3),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&Ipv6Address::LINK_LOCAL_ALL_NODES),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR1),
- Ipv6Address::LOOPBACK
- );
- assert_eq!(
- iface.get_source_address_ipv6(&GLOBAL_UNICAST_ADDR2),
- Ipv6Address::LOOPBACK
- );
- }
- #[rstest]
- #[case(Medium::Ip)]
- #[cfg(feature = "medium-ip")]
- #[case(Medium::Ethernet)]
- #[cfg(feature = "medium-ethernet")]
- fn test_join_ipv6_multicast_group(#[case] medium: Medium) {
- fn recv_icmpv6(
- device: &mut crate::tests::TestingDevice,
- timestamp: Instant,
- ) -> std::vec::Vec<Ipv6Packet<std::vec::Vec<u8>>> {
- let caps = device.capabilities();
- recv_all(device, timestamp)
- .iter()
- .filter_map(|frame| {
- let ipv6_packet = match caps.medium {
- #[cfg(feature = "medium-ethernet")]
- Medium::Ethernet => {
- let eth_frame = EthernetFrame::new_checked(frame).ok()?;
- Ipv6Packet::new_checked(eth_frame.payload()).ok()?
- }
- #[cfg(feature = "medium-ip")]
- Medium::Ip => Ipv6Packet::new_checked(&frame[..]).ok()?,
- #[cfg(feature = "medium-ieee802154")]
- Medium::Ieee802154 => todo!(),
- };
- let buf = ipv6_packet.into_inner().to_vec();
- Some(Ipv6Packet::new_unchecked(buf))
- })
- .collect::<std::vec::Vec<_>>()
- }
- let (mut iface, _sockets, mut device) = setup(medium);
- let groups = [
- Ipv6Address::from_parts(&[0xff05, 0, 0, 0, 0, 0, 0, 0x00fb]),
- Ipv6Address::from_parts(&[0xff0e, 0, 0, 0, 0, 0, 0, 0x0017]),
- ];
- let timestamp = Instant::from_millis(0);
- for &group in &groups {
- iface
- .join_multicast_group(&mut device, group, timestamp)
- .unwrap();
- assert!(iface.has_multicast_group(group));
- }
- assert!(iface.has_multicast_group(Ipv6Address::LINK_LOCAL_ALL_NODES));
- let reports = recv_icmpv6(&mut device, timestamp);
- assert_eq!(reports.len(), 2);
- let caps = device.capabilities();
- let checksum_caps = &caps.checksum;
- for (&group_addr, ipv6_packet) in groups.iter().zip(reports) {
- let buf = ipv6_packet.into_inner();
- let ipv6_packet = Ipv6Packet::new_unchecked(buf.as_slice());
- let _ipv6_repr = Ipv6Repr::parse(&ipv6_packet).unwrap();
- let ip_payload = ipv6_packet.payload();
- // The first 2 octets of this payload hold the next-header indicator and the
- // Hop-by-Hop header length (in 8-octet words, minus 1). The remaining 6 octets
- // hold the Hop-by-Hop PadN and Router Alert options.
- let hbh_header = Ipv6HopByHopHeader::new_checked(&ip_payload[..8]).unwrap();
- let hbh_repr = Ipv6HopByHopRepr::parse(&hbh_header).unwrap();
- assert_eq!(hbh_repr.options.len(), 3);
- assert_eq!(
- hbh_repr.options[0],
- Ipv6OptionRepr::Unknown {
- type_: Ipv6OptionType::Unknown(IpProtocol::Icmpv6.into()),
- length: 0,
- data: &[],
- }
- );
- assert_eq!(
- hbh_repr.options[1],
- Ipv6OptionRepr::RouterAlert(Ipv6OptionRouterAlert::MulticastListenerDiscovery)
- );
- assert_eq!(hbh_repr.options[2], Ipv6OptionRepr::PadN(0));
- let icmpv6_packet =
- Icmpv6Packet::new_checked(&ip_payload[hbh_repr.buffer_len()..]).unwrap();
- let icmpv6_repr = Icmpv6Repr::parse(
- &ipv6_packet.src_addr(),
- &ipv6_packet.dst_addr(),
- &icmpv6_packet,
- checksum_caps,
- )
- .unwrap();
- let record_data = match icmpv6_repr {
- Icmpv6Repr::Mld(MldRepr::Report {
- nr_mcast_addr_rcrds,
- data,
- }) => {
- assert_eq!(nr_mcast_addr_rcrds, 1);
- data
- }
- other => panic!("unexpected icmpv6_repr: {:?}", other),
- };
- let record = MldAddressRecord::new_checked(record_data).unwrap();
- let record_repr = MldAddressRecordRepr::parse(&record).unwrap();
- assert_eq!(
- record_repr,
- MldAddressRecordRepr {
- num_srcs: 0,
- mcast_addr: group_addr,
- record_type: MldRecordType::ChangeToInclude,
- aux_data_len: 0,
- payload: &[],
- }
- );
- iface
- .leave_multicast_group(&mut device, group_addr, timestamp)
- .unwrap();
- assert!(!iface.has_multicast_group(group_addr));
- }
- }
|