ipv6.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. use super::*;
  2. fn parse_ipv6(data: &[u8]) -> crate::wire::Result<IpPacket<'_>> {
  3. let ipv6_header = Ipv6PacketWire::new_checked(data)?;
  4. let ipv6 = Ipv6Repr::parse(&ipv6_header)?;
  5. match ipv6.next_header {
  6. IpProtocol::HopByHop => todo!(),
  7. IpProtocol::Icmp => todo!(),
  8. IpProtocol::Igmp => todo!(),
  9. IpProtocol::Tcp => todo!(),
  10. IpProtocol::Udp => todo!(),
  11. IpProtocol::Ipv6Route => todo!(),
  12. IpProtocol::Ipv6Frag => todo!(),
  13. IpProtocol::IpSecEsp => todo!(),
  14. IpProtocol::IpSecAh => todo!(),
  15. IpProtocol::Icmpv6 => {
  16. let icmp = Icmpv6Repr::parse(
  17. &ipv6.src_addr.into(),
  18. &ipv6.dst_addr.into(),
  19. &Icmpv6Packet::new_checked(ipv6_header.payload())?,
  20. &Default::default(),
  21. )?;
  22. Ok(IpPacket::new_ipv6(ipv6, IpPayload::Icmpv6(icmp)))
  23. }
  24. IpProtocol::Ipv6NoNxt => todo!(),
  25. IpProtocol::Ipv6Opts => todo!(),
  26. IpProtocol::Unknown(_) => todo!(),
  27. }
  28. }
  29. #[rstest]
  30. #[case::ip(Medium::Ip)]
  31. #[cfg(feature = "medium-ip")]
  32. #[case::ethernet(Medium::Ethernet)]
  33. #[cfg(feature = "medium-ethernet")]
  34. #[case::ieee802154(Medium::Ieee802154)]
  35. #[cfg(feature = "medium-ieee802154")]
  36. fn multicast_source_address(#[case] medium: Medium) {
  37. let data = [
  38. 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  39. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  40. 0x0, 0x0, 0x0, 0x0, 0x1,
  41. ];
  42. let response = None;
  43. let (mut iface, mut sockets, _device) = setup(medium);
  44. assert_eq!(
  45. iface.inner.process_ipv6(
  46. &mut sockets,
  47. PacketMeta::default(),
  48. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  49. ),
  50. response
  51. );
  52. }
  53. #[rstest]
  54. #[case::ip(Medium::Ip)]
  55. #[cfg(feature = "medium-ip")]
  56. #[case::ethernet(Medium::Ethernet)]
  57. #[cfg(feature = "medium-ethernet")]
  58. #[case::ieee802154(Medium::Ieee802154)]
  59. #[cfg(feature = "medium-ieee802154")]
  60. fn hop_by_hop_skip_with_icmp(#[case] medium: Medium) {
  61. // The following contains:
  62. // - IPv6 header
  63. // - Hop-by-hop, with options:
  64. // - PADN (skipped)
  65. // - Unknown option (skipped)
  66. // - ICMP echo request
  67. let data = [
  68. 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  69. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  70. 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0x1, 0x0, 0xf, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
  71. 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
  72. ];
  73. let response = Some(IpPacket::new_ipv6(
  74. Ipv6Repr {
  75. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  76. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  77. hop_limit: 64,
  78. next_header: IpProtocol::Icmpv6,
  79. payload_len: 19,
  80. },
  81. IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
  82. ident: 42,
  83. seq_no: 420,
  84. data: b"Lorem Ipsum",
  85. }),
  86. ));
  87. let (mut iface, mut sockets, _device) = setup(medium);
  88. assert_eq!(
  89. iface.inner.process_ipv6(
  90. &mut sockets,
  91. PacketMeta::default(),
  92. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  93. ),
  94. response
  95. );
  96. }
  97. #[rstest]
  98. #[case::ip(Medium::Ip)]
  99. #[cfg(feature = "medium-ip")]
  100. #[case::ethernet(Medium::Ethernet)]
  101. #[cfg(feature = "medium-ethernet")]
  102. #[case::ieee802154(Medium::Ieee802154)]
  103. #[cfg(feature = "medium-ieee802154")]
  104. fn hop_by_hop_discard_with_icmp(#[case] medium: Medium) {
  105. // The following contains:
  106. // - IPv6 header
  107. // - Hop-by-hop, with options:
  108. // - PADN (skipped)
  109. // - Unknown option (discard)
  110. // - ICMP echo request
  111. let data = [
  112. 0x60, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  113. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  114. 0x0, 0x0, 0x0, 0x0, 0x1, 0x3a, 0x0, 0x1, 0x0, 0x40, 0x0, 0x1, 0x0, 0x80, 0x0, 0x2c, 0x88,
  115. 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
  116. ];
  117. let response = None;
  118. let (mut iface, mut sockets, _device) = setup(medium);
  119. assert_eq!(
  120. iface.inner.process_ipv6(
  121. &mut sockets,
  122. PacketMeta::default(),
  123. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  124. ),
  125. response
  126. );
  127. }
  128. #[rstest]
  129. #[case::ip(Medium::Ip)]
  130. #[cfg(feature = "medium-ip")]
  131. #[case::ethernet(Medium::Ethernet)]
  132. #[cfg(feature = "medium-ethernet")]
  133. #[case::ieee802154(Medium::Ieee802154)]
  134. #[cfg(feature = "medium-ieee802154")]
  135. fn imcp_empty_echo_request(#[case] medium: Medium) {
  136. let data = [
  137. 0x60, 0x0, 0x0, 0x0, 0x0, 0x8, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  138. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  139. 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x84, 0x3c, 0x0, 0x0, 0x0, 0x0,
  140. ];
  141. assert_eq!(
  142. parse_ipv6(&data),
  143. Ok(IpPacket::new_ipv6(
  144. Ipv6Repr {
  145. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  146. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  147. hop_limit: 64,
  148. next_header: IpProtocol::Icmpv6,
  149. payload_len: 8,
  150. },
  151. IpPayload::Icmpv6(Icmpv6Repr::EchoRequest {
  152. ident: 0,
  153. seq_no: 0,
  154. data: b"",
  155. })
  156. ))
  157. );
  158. let response = Some(IpPacket::new_ipv6(
  159. Ipv6Repr {
  160. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  161. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  162. hop_limit: 64,
  163. next_header: IpProtocol::Icmpv6,
  164. payload_len: 8,
  165. },
  166. IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
  167. ident: 0,
  168. seq_no: 0,
  169. data: b"",
  170. }),
  171. ));
  172. let (mut iface, mut sockets, _device) = setup(medium);
  173. assert_eq!(
  174. iface.inner.process_ipv6(
  175. &mut sockets,
  176. PacketMeta::default(),
  177. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  178. ),
  179. response
  180. );
  181. }
  182. #[rstest]
  183. #[case::ip(Medium::Ip)]
  184. #[cfg(feature = "medium-ip")]
  185. #[case::ethernet(Medium::Ethernet)]
  186. #[cfg(feature = "medium-ethernet")]
  187. #[case::ieee802154(Medium::Ieee802154)]
  188. #[cfg(feature = "medium-ieee802154")]
  189. fn icmp_echo_request(#[case] medium: Medium) {
  190. let data = [
  191. 0x60, 0x0, 0x0, 0x0, 0x0, 0x13, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  192. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  193. 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x2c, 0x88, 0x0, 0x2a, 0x1, 0xa4, 0x4c, 0x6f, 0x72,
  194. 0x65, 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
  195. ];
  196. assert_eq!(
  197. parse_ipv6(&data),
  198. Ok(IpPacket::new_ipv6(
  199. Ipv6Repr {
  200. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  201. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  202. hop_limit: 64,
  203. next_header: IpProtocol::Icmpv6,
  204. payload_len: 19,
  205. },
  206. IpPayload::Icmpv6(Icmpv6Repr::EchoRequest {
  207. ident: 42,
  208. seq_no: 420,
  209. data: b"Lorem Ipsum",
  210. })
  211. ))
  212. );
  213. let response = Some(IpPacket::new_ipv6(
  214. Ipv6Repr {
  215. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  216. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  217. hop_limit: 64,
  218. next_header: IpProtocol::Icmpv6,
  219. payload_len: 19,
  220. },
  221. IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
  222. ident: 42,
  223. seq_no: 420,
  224. data: b"Lorem Ipsum",
  225. }),
  226. ));
  227. let (mut iface, mut sockets, _device) = setup(medium);
  228. assert_eq!(
  229. iface.inner.process_ipv6(
  230. &mut sockets,
  231. PacketMeta::default(),
  232. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  233. ),
  234. response
  235. );
  236. }
  237. #[rstest]
  238. #[case::ip(Medium::Ip)]
  239. #[cfg(feature = "medium-ip")]
  240. #[case::ethernet(Medium::Ethernet)]
  241. #[cfg(feature = "medium-ethernet")]
  242. #[case::ieee802154(Medium::Ieee802154)]
  243. #[cfg(feature = "medium-ieee802154")]
  244. fn icmp_echo_reply_as_input(#[case] medium: Medium) {
  245. let data = [
  246. 0x60, 0x0, 0x0, 0x0, 0x0, 0x13, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  247. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  248. 0x0, 0x0, 0x0, 0x0, 0x1, 0x81, 0x0, 0x2d, 0x56, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x6f, 0x72, 0x65,
  249. 0x6d, 0x20, 0x49, 0x70, 0x73, 0x75, 0x6d,
  250. ];
  251. assert_eq!(
  252. parse_ipv6(&data),
  253. Ok(IpPacket::new_ipv6(
  254. Ipv6Repr {
  255. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  256. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  257. hop_limit: 64,
  258. next_header: IpProtocol::Icmpv6,
  259. payload_len: 19,
  260. },
  261. IpPayload::Icmpv6(Icmpv6Repr::EchoReply {
  262. ident: 0,
  263. seq_no: 0,
  264. data: b"Lorem Ipsum",
  265. })
  266. ))
  267. );
  268. let response = None;
  269. let (mut iface, mut sockets, _device) = setup(medium);
  270. assert_eq!(
  271. iface.inner.process_ipv6(
  272. &mut sockets,
  273. PacketMeta::default(),
  274. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  275. ),
  276. response
  277. );
  278. }
  279. #[rstest]
  280. #[case::ip(Medium::Ip)]
  281. #[cfg(feature = "medium-ip")]
  282. #[case::ethernet(Medium::Ethernet)]
  283. #[cfg(feature = "medium-ethernet")]
  284. #[case::ieee802154(Medium::Ieee802154)]
  285. #[cfg(feature = "medium-ieee802154")]
  286. fn unknown_proto_with_multicast_dst_address(#[case] medium: Medium) {
  287. // Since the destination address is multicast, we should not answer with an ICMPv6 message.
  288. let data = [
  289. 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  290. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  291. 0x0, 0x0, 0x0, 0x0, 0x1,
  292. ];
  293. let response = None;
  294. let (mut iface, mut sockets, _device) = setup(medium);
  295. assert_eq!(
  296. iface.inner.process_ipv6(
  297. &mut sockets,
  298. PacketMeta::default(),
  299. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  300. ),
  301. response
  302. );
  303. }
  304. #[rstest]
  305. #[case::ip(Medium::Ip)]
  306. #[cfg(feature = "medium-ip")]
  307. #[case::ethernet(Medium::Ethernet)]
  308. #[cfg(feature = "medium-ethernet")]
  309. #[case::ieee802154(Medium::Ieee802154)]
  310. #[cfg(feature = "medium-ieee802154")]
  311. fn unknown_proto(#[case] medium: Medium) {
  312. // Since the destination address is multicast, we should not answer with an ICMPv6 message.
  313. let data = [
  314. 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  315. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  316. 0x0, 0x0, 0x0, 0x0, 0x1,
  317. ];
  318. let response = Some(IpPacket::new_ipv6(
  319. Ipv6Repr {
  320. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  321. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  322. hop_limit: 64,
  323. next_header: IpProtocol::Icmpv6,
  324. payload_len: 48,
  325. },
  326. IpPayload::Icmpv6(Icmpv6Repr::ParamProblem {
  327. reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
  328. pointer: 40,
  329. header: Ipv6Repr {
  330. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  331. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  332. hop_limit: 64,
  333. next_header: IpProtocol::Unknown(0x0c),
  334. payload_len: 0,
  335. },
  336. data: &[],
  337. }),
  338. ));
  339. let (mut iface, mut sockets, _device) = setup(medium);
  340. assert_eq!(
  341. iface.inner.process_ipv6(
  342. &mut sockets,
  343. PacketMeta::default(),
  344. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  345. ),
  346. response
  347. );
  348. }
  349. #[rstest]
  350. #[case::ethernet(Medium::Ethernet)]
  351. #[cfg(feature = "medium-ethernet")]
  352. fn ndsic_neighbor_advertisement_ethernet(#[case] medium: Medium) {
  353. let data = [
  354. 0x60, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  355. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  356. 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0x9f, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
  357. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0,
  358. 0x0, 0x1,
  359. ];
  360. assert_eq!(
  361. parse_ipv6(&data),
  362. Ok(IpPacket::new_ipv6(
  363. Ipv6Repr {
  364. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  365. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  366. hop_limit: 255,
  367. next_header: IpProtocol::Icmpv6,
  368. payload_len: 32,
  369. },
  370. IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  371. flags: NdiscNeighborFlags::SOLICITED,
  372. target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
  373. lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 1])),
  374. }))
  375. ))
  376. );
  377. let response = None;
  378. let (mut iface, mut sockets, _device) = setup(medium);
  379. assert_eq!(
  380. iface.inner.process_ipv6(
  381. &mut sockets,
  382. PacketMeta::default(),
  383. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  384. ),
  385. response
  386. );
  387. assert_eq!(
  388. iface.inner.neighbor_cache.lookup(
  389. &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
  390. iface.inner.now,
  391. ),
  392. NeighborAnswer::Found(HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
  393. 0, 0, 0, 0, 0, 1
  394. ]))),
  395. );
  396. }
  397. #[rstest]
  398. #[case::ethernet(Medium::Ethernet)]
  399. #[cfg(feature = "medium-ethernet")]
  400. fn ndsic_neighbor_advertisement_ethernet_multicast_addr(#[case] medium: Medium) {
  401. let data = [
  402. 0x60, 0x0, 0x0, 0x0, 0x0, 0x20, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  403. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  404. 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0xa0, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
  405. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x1, 0xff, 0xff, 0xff,
  406. 0xff, 0xff, 0xff,
  407. ];
  408. assert_eq!(
  409. parse_ipv6(&data),
  410. Ok(IpPacket::new_ipv6(
  411. Ipv6Repr {
  412. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  413. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  414. hop_limit: 255,
  415. next_header: IpProtocol::Icmpv6,
  416. payload_len: 32,
  417. },
  418. IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  419. flags: NdiscNeighborFlags::SOLICITED,
  420. target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
  421. lladdr: Some(RawHardwareAddress::from_bytes(&[
  422. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  423. ])),
  424. }))
  425. ))
  426. );
  427. let response = None;
  428. let (mut iface, mut sockets, _device) = setup(medium);
  429. assert_eq!(
  430. iface.inner.process_ipv6(
  431. &mut sockets,
  432. PacketMeta::default(),
  433. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  434. ),
  435. response
  436. );
  437. assert_eq!(
  438. iface.inner.neighbor_cache.lookup(
  439. &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
  440. iface.inner.now,
  441. ),
  442. NeighborAnswer::NotFound,
  443. );
  444. }
  445. #[rstest]
  446. #[case::ieee802154(Medium::Ieee802154)]
  447. #[cfg(feature = "medium-ieee802154")]
  448. fn ndsic_neighbor_advertisement_ieee802154(#[case] medium: Medium) {
  449. let data = [
  450. 0x60, 0x0, 0x0, 0x0, 0x0, 0x28, 0x3a, 0xff, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  451. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  452. 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x0, 0x3b, 0x96, 0x40, 0x0, 0x0, 0x0, 0xfe, 0x80, 0x0, 0x0,
  453. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0,
  454. 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  455. ];
  456. assert_eq!(
  457. parse_ipv6(&data),
  458. Ok(IpPacket::new_ipv6(
  459. Ipv6Repr {
  460. src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
  461. dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001]),
  462. hop_limit: 255,
  463. next_header: IpProtocol::Icmpv6,
  464. payload_len: 40,
  465. },
  466. IpPayload::Icmpv6(Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  467. flags: NdiscNeighborFlags::SOLICITED,
  468. target_addr: Ipv6Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 0x0002]),
  469. lladdr: Some(RawHardwareAddress::from_bytes(&[0, 0, 0, 0, 0, 0, 0, 1])),
  470. }))
  471. ))
  472. );
  473. let response = None;
  474. let (mut iface, mut sockets, _device) = setup(medium);
  475. assert_eq!(
  476. iface.inner.process_ipv6(
  477. &mut sockets,
  478. PacketMeta::default(),
  479. &Ipv6PacketWire::new_checked(&data[..]).unwrap()
  480. ),
  481. response
  482. );
  483. assert_eq!(
  484. iface.inner.neighbor_cache.lookup(
  485. &IpAddress::Ipv6(Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002])),
  486. iface.inner.now,
  487. ),
  488. NeighborAnswer::Found(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
  489. &[0, 0, 0, 0, 0, 0, 0, 1]
  490. ))),
  491. );
  492. }
  493. #[rstest]
  494. #[case(Medium::Ethernet)]
  495. #[cfg(feature = "medium-ethernet")]
  496. fn test_handle_valid_ndisc_request(#[case] medium: Medium) {
  497. let (mut iface, mut sockets, _device) = setup(medium);
  498. let mut eth_bytes = vec![0u8; 86];
  499. let local_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1);
  500. let remote_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2);
  501. let local_hw_addr = EthernetAddress([0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
  502. let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
  503. let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
  504. target_addr: local_ip_addr,
  505. lladdr: Some(remote_hw_addr.into()),
  506. });
  507. let ip_repr = IpRepr::Ipv6(Ipv6Repr {
  508. src_addr: remote_ip_addr,
  509. dst_addr: local_ip_addr.solicited_node(),
  510. next_header: IpProtocol::Icmpv6,
  511. hop_limit: 0xff,
  512. payload_len: solicit.buffer_len(),
  513. });
  514. let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
  515. frame.set_dst_addr(EthernetAddress([0x33, 0x33, 0x00, 0x00, 0x00, 0x00]));
  516. frame.set_src_addr(remote_hw_addr);
  517. frame.set_ethertype(EthernetProtocol::Ipv6);
  518. ip_repr.emit(frame.payload_mut(), &ChecksumCapabilities::default());
  519. solicit.emit(
  520. &remote_ip_addr.into(),
  521. &local_ip_addr.solicited_node().into(),
  522. &mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.header_len()..]),
  523. &ChecksumCapabilities::default(),
  524. );
  525. let icmpv6_expected = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  526. flags: NdiscNeighborFlags::SOLICITED,
  527. target_addr: local_ip_addr,
  528. lladdr: Some(local_hw_addr.into()),
  529. });
  530. let ipv6_expected = Ipv6Repr {
  531. src_addr: local_ip_addr,
  532. dst_addr: remote_ip_addr,
  533. next_header: IpProtocol::Icmpv6,
  534. hop_limit: 0xff,
  535. payload_len: icmpv6_expected.buffer_len(),
  536. };
  537. // Ensure an Neighbor Solicitation triggers a Neighbor Advertisement
  538. assert_eq!(
  539. iface.inner.process_ethernet(
  540. &mut sockets,
  541. PacketMeta::default(),
  542. frame.into_inner(),
  543. &mut iface.fragments
  544. ),
  545. Some(EthernetPacket::Ip(IpPacket::new_ipv6(
  546. ipv6_expected,
  547. IpPayload::Icmpv6(icmpv6_expected)
  548. )))
  549. );
  550. // Ensure the address of the requestor was entered in the cache
  551. assert_eq!(
  552. iface.inner.lookup_hardware_addr(
  553. MockTxToken,
  554. &IpAddress::Ipv6(local_ip_addr),
  555. &IpAddress::Ipv6(remote_ip_addr),
  556. &mut iface.fragmenter,
  557. ),
  558. Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
  559. );
  560. }
  561. #[rstest]
  562. #[case(Medium::Ip)]
  563. #[cfg(feature = "medium-ip")]
  564. #[case(Medium::Ethernet)]
  565. #[cfg(feature = "medium-ethernet")]
  566. #[case(Medium::Ieee802154)]
  567. #[cfg(feature = "medium-ieee802154")]
  568. fn test_solicited_node_addrs(#[case] medium: Medium) {
  569. let (mut iface, _, _) = setup(medium);
  570. let mut new_addrs = heapless::Vec::<IpCidr, IFACE_MAX_ADDR_COUNT>::new();
  571. new_addrs
  572. .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 1, 2, 0, 2), 64))
  573. .unwrap();
  574. new_addrs
  575. .push(IpCidr::new(
  576. IpAddress::v6(0xfe80, 0, 0, 0, 3, 4, 0, 0xffff),
  577. 64,
  578. ))
  579. .unwrap();
  580. iface.update_ip_addrs(|addrs| {
  581. new_addrs.extend(addrs.to_vec());
  582. *addrs = new_addrs;
  583. });
  584. assert!(iface
  585. .inner
  586. .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0x0002)));
  587. assert!(iface
  588. .inner
  589. .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0xffff)));
  590. assert!(!iface
  591. .inner
  592. .has_solicited_node(Ipv6Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0x0003)));
  593. }
  594. #[rstest]
  595. #[case(Medium::Ip)]
  596. #[cfg(all(feature = "socket-udp", feature = "medium-ip"))]
  597. #[case(Medium::Ethernet)]
  598. #[cfg(all(feature = "socket-udp", feature = "medium-ethernet"))]
  599. #[case(Medium::Ieee802154)]
  600. #[cfg(all(feature = "socket-udp", feature = "medium-ieee802154"))]
  601. fn test_icmp_reply_size(#[case] medium: Medium) {
  602. use crate::wire::Icmpv6DstUnreachable;
  603. use crate::wire::IPV6_MIN_MTU as MIN_MTU;
  604. const MAX_PAYLOAD_LEN: usize = 1192;
  605. let (mut iface, mut sockets, _device) = setup(medium);
  606. let src_addr = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
  607. let dst_addr = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
  608. // UDP packet that if not tructated will cause a icmp port unreachable reply
  609. // to exeed the minimum mtu bytes in length.
  610. let udp_repr = UdpRepr {
  611. src_port: 67,
  612. dst_port: 68,
  613. };
  614. let mut bytes = vec![0xff; udp_repr.header_len() + MAX_PAYLOAD_LEN];
  615. let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
  616. udp_repr.emit(
  617. &mut packet,
  618. &src_addr.into(),
  619. &dst_addr.into(),
  620. MAX_PAYLOAD_LEN,
  621. |buf| fill_slice(buf, 0x2a),
  622. &ChecksumCapabilities::default(),
  623. );
  624. let ip_repr = Ipv6Repr {
  625. src_addr,
  626. dst_addr,
  627. next_header: IpProtocol::Udp,
  628. hop_limit: 64,
  629. payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
  630. };
  631. let payload = packet.into_inner();
  632. let expected_icmp_repr = Icmpv6Repr::DstUnreachable {
  633. reason: Icmpv6DstUnreachable::PortUnreachable,
  634. header: ip_repr,
  635. data: &payload[..MAX_PAYLOAD_LEN],
  636. };
  637. let expected_ip_repr = Ipv6Repr {
  638. src_addr: dst_addr,
  639. dst_addr: src_addr,
  640. next_header: IpProtocol::Icmpv6,
  641. hop_limit: 64,
  642. payload_len: expected_icmp_repr.buffer_len(),
  643. };
  644. assert_eq!(
  645. expected_ip_repr.buffer_len() + expected_icmp_repr.buffer_len(),
  646. MIN_MTU
  647. );
  648. assert_eq!(
  649. iface.inner.process_udp(
  650. &mut sockets,
  651. PacketMeta::default(),
  652. ip_repr.into(),
  653. udp_repr,
  654. false,
  655. &vec![0x2a; MAX_PAYLOAD_LEN],
  656. payload,
  657. ),
  658. Some(IpPacket::new_ipv6(
  659. expected_ip_repr,
  660. IpPayload::Icmpv6(expected_icmp_repr)
  661. ))
  662. );
  663. }