ndisc.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. use bitflags::bitflags;
  2. use byteorder::{ByteOrder, NetworkEndian};
  3. use super::{Error, Result};
  4. use crate::time::Duration;
  5. use crate::wire::icmpv6::{field, Message, Packet};
  6. use crate::wire::Ipv6Address;
  7. use crate::wire::RawHardwareAddress;
  8. use crate::wire::{NdiscOption, NdiscOptionRepr};
  9. use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
  10. bitflags! {
  11. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  12. pub struct RouterFlags: u8 {
  13. const MANAGED = 0b10000000;
  14. const OTHER = 0b01000000;
  15. }
  16. }
  17. bitflags! {
  18. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  19. pub struct NeighborFlags: u8 {
  20. const ROUTER = 0b10000000;
  21. const SOLICITED = 0b01000000;
  22. const OVERRIDE = 0b00100000;
  23. }
  24. }
  25. /// Getters for the Router Advertisement message header.
  26. /// See [RFC 4861 § 4.2].
  27. ///
  28. /// [RFC 4861 § 4.2]: https://tools.ietf.org/html/rfc4861#section-4.2
  29. impl<T: AsRef<[u8]>> Packet<T> {
  30. /// Return the current hop limit field.
  31. #[inline]
  32. pub fn current_hop_limit(&self) -> u8 {
  33. let data = self.buffer.as_ref();
  34. data[field::CUR_HOP_LIMIT]
  35. }
  36. /// Return the Router Advertisement flags.
  37. #[inline]
  38. pub fn router_flags(&self) -> RouterFlags {
  39. let data = self.buffer.as_ref();
  40. RouterFlags::from_bits_truncate(data[field::ROUTER_FLAGS])
  41. }
  42. /// Return the router lifetime field.
  43. #[inline]
  44. pub fn router_lifetime(&self) -> Duration {
  45. let data = self.buffer.as_ref();
  46. Duration::from_secs(NetworkEndian::read_u16(&data[field::ROUTER_LT]) as u64)
  47. }
  48. /// Return the reachable time field.
  49. #[inline]
  50. pub fn reachable_time(&self) -> Duration {
  51. let data = self.buffer.as_ref();
  52. Duration::from_millis(NetworkEndian::read_u32(&data[field::REACHABLE_TM]) as u64)
  53. }
  54. /// Return the retransmit time field.
  55. #[inline]
  56. pub fn retrans_time(&self) -> Duration {
  57. let data = self.buffer.as_ref();
  58. Duration::from_millis(NetworkEndian::read_u32(&data[field::RETRANS_TM]) as u64)
  59. }
  60. }
  61. /// Common getters for the [Neighbor Solicitation], [Neighbor Advertisement], and
  62. /// [Redirect] message types.
  63. ///
  64. /// [Neighbor Solicitation]: https://tools.ietf.org/html/rfc4861#section-4.3
  65. /// [Neighbor Advertisement]: https://tools.ietf.org/html/rfc4861#section-4.4
  66. /// [Redirect]: https://tools.ietf.org/html/rfc4861#section-4.5
  67. impl<T: AsRef<[u8]>> Packet<T> {
  68. /// Return the target address field.
  69. #[inline]
  70. pub fn target_addr(&self) -> Ipv6Address {
  71. let data = self.buffer.as_ref();
  72. Ipv6Address::from_bytes(&data[field::TARGET_ADDR])
  73. }
  74. }
  75. /// Getters for the Neighbor Solicitation message header.
  76. /// See [RFC 4861 § 4.3].
  77. ///
  78. /// [RFC 4861 § 4.3]: https://tools.ietf.org/html/rfc4861#section-4.3
  79. impl<T: AsRef<[u8]>> Packet<T> {
  80. /// Return the Neighbor Solicitation flags.
  81. #[inline]
  82. pub fn neighbor_flags(&self) -> NeighborFlags {
  83. let data = self.buffer.as_ref();
  84. NeighborFlags::from_bits_truncate(data[field::NEIGH_FLAGS])
  85. }
  86. }
  87. /// Getters for the Redirect message header.
  88. /// See [RFC 4861 § 4.5].
  89. ///
  90. /// [RFC 4861 § 4.5]: https://tools.ietf.org/html/rfc4861#section-4.5
  91. impl<T: AsRef<[u8]>> Packet<T> {
  92. /// Return the destination address field.
  93. #[inline]
  94. pub fn dest_addr(&self) -> Ipv6Address {
  95. let data = self.buffer.as_ref();
  96. Ipv6Address::from_bytes(&data[field::DEST_ADDR])
  97. }
  98. }
  99. /// Setters for the Router Advertisement message header.
  100. /// See [RFC 4861 § 4.2].
  101. ///
  102. /// [RFC 4861 § 4.2]: https://tools.ietf.org/html/rfc4861#section-4.2
  103. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  104. /// Set the current hop limit field.
  105. #[inline]
  106. pub fn set_current_hop_limit(&mut self, value: u8) {
  107. let data = self.buffer.as_mut();
  108. data[field::CUR_HOP_LIMIT] = value;
  109. }
  110. /// Set the Router Advertisement flags.
  111. #[inline]
  112. pub fn set_router_flags(&mut self, flags: RouterFlags) {
  113. self.buffer.as_mut()[field::ROUTER_FLAGS] = flags.bits();
  114. }
  115. /// Set the router lifetime field.
  116. #[inline]
  117. pub fn set_router_lifetime(&mut self, value: Duration) {
  118. let data = self.buffer.as_mut();
  119. NetworkEndian::write_u16(&mut data[field::ROUTER_LT], value.secs() as u16);
  120. }
  121. /// Set the reachable time field.
  122. #[inline]
  123. pub fn set_reachable_time(&mut self, value: Duration) {
  124. let data = self.buffer.as_mut();
  125. NetworkEndian::write_u32(&mut data[field::REACHABLE_TM], value.total_millis() as u32);
  126. }
  127. /// Set the retransmit time field.
  128. #[inline]
  129. pub fn set_retrans_time(&mut self, value: Duration) {
  130. let data = self.buffer.as_mut();
  131. NetworkEndian::write_u32(&mut data[field::RETRANS_TM], value.total_millis() as u32);
  132. }
  133. }
  134. /// Common setters for the [Neighbor Solicitation], [Neighbor Advertisement], and
  135. /// [Redirect] message types.
  136. ///
  137. /// [Neighbor Solicitation]: https://tools.ietf.org/html/rfc4861#section-4.3
  138. /// [Neighbor Advertisement]: https://tools.ietf.org/html/rfc4861#section-4.4
  139. /// [Redirect]: https://tools.ietf.org/html/rfc4861#section-4.5
  140. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  141. /// Set the target address field.
  142. #[inline]
  143. pub fn set_target_addr(&mut self, value: Ipv6Address) {
  144. let data = self.buffer.as_mut();
  145. data[field::TARGET_ADDR].copy_from_slice(value.as_bytes());
  146. }
  147. }
  148. /// Setters for the Neighbor Solicitation message header.
  149. /// See [RFC 4861 § 4.3].
  150. ///
  151. /// [RFC 4861 § 4.3]: https://tools.ietf.org/html/rfc4861#section-4.3
  152. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  153. /// Set the Neighbor Solicitation flags.
  154. #[inline]
  155. pub fn set_neighbor_flags(&mut self, flags: NeighborFlags) {
  156. self.buffer.as_mut()[field::NEIGH_FLAGS] = flags.bits();
  157. }
  158. }
  159. /// Setters for the Redirect message header.
  160. /// See [RFC 4861 § 4.5].
  161. ///
  162. /// [RFC 4861 § 4.5]: https://tools.ietf.org/html/rfc4861#section-4.5
  163. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  164. /// Set the destination address field.
  165. #[inline]
  166. pub fn set_dest_addr(&mut self, value: Ipv6Address) {
  167. let data = self.buffer.as_mut();
  168. data[field::DEST_ADDR].copy_from_slice(value.as_bytes());
  169. }
  170. }
  171. /// A high-level representation of an Neighbor Discovery packet header.
  172. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  173. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  174. pub enum Repr<'a> {
  175. RouterSolicit {
  176. lladdr: Option<RawHardwareAddress>,
  177. },
  178. RouterAdvert {
  179. hop_limit: u8,
  180. flags: RouterFlags,
  181. router_lifetime: Duration,
  182. reachable_time: Duration,
  183. retrans_time: Duration,
  184. lladdr: Option<RawHardwareAddress>,
  185. mtu: Option<u32>,
  186. prefix_info: Option<NdiscPrefixInformation>,
  187. },
  188. NeighborSolicit {
  189. target_addr: Ipv6Address,
  190. lladdr: Option<RawHardwareAddress>,
  191. },
  192. NeighborAdvert {
  193. flags: NeighborFlags,
  194. target_addr: Ipv6Address,
  195. lladdr: Option<RawHardwareAddress>,
  196. },
  197. Redirect {
  198. target_addr: Ipv6Address,
  199. dest_addr: Ipv6Address,
  200. lladdr: Option<RawHardwareAddress>,
  201. redirected_hdr: Option<NdiscRedirectedHeader<'a>>,
  202. },
  203. }
  204. impl<'a> Repr<'a> {
  205. /// Parse an NDISC packet and return a high-level representation of the
  206. /// packet.
  207. #[allow(clippy::single_match)]
  208. pub fn parse<T>(packet: &Packet<&'a T>) -> Result<Repr<'a>>
  209. where
  210. T: AsRef<[u8]> + ?Sized,
  211. {
  212. fn foreach_option<'a>(
  213. payload: &'a [u8],
  214. mut f: impl FnMut(NdiscOptionRepr<'a>) -> Result<()>,
  215. ) -> Result<()> {
  216. let mut offset = 0;
  217. while payload.len() > offset {
  218. let pkt = NdiscOption::new_checked(&payload[offset..])?;
  219. // If an option doesn't parse, ignore it and still parse the others.
  220. if let Ok(opt) = NdiscOptionRepr::parse(&pkt) {
  221. f(opt)?;
  222. }
  223. let len = pkt.data_len() as usize * 8;
  224. if len == 0 {
  225. return Err(Error);
  226. }
  227. offset += len;
  228. }
  229. Ok(())
  230. }
  231. match packet.msg_type() {
  232. Message::RouterSolicit => {
  233. let mut lladdr = None;
  234. foreach_option(packet.payload(), |opt| {
  235. match opt {
  236. NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
  237. _ => {}
  238. }
  239. Ok(())
  240. })?;
  241. Ok(Repr::RouterSolicit { lladdr })
  242. }
  243. Message::RouterAdvert => {
  244. let (mut lladdr, mut mtu, mut prefix_info) = (None, None, None);
  245. foreach_option(packet.payload(), |opt| {
  246. match opt {
  247. NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
  248. NdiscOptionRepr::Mtu(val) => mtu = Some(val),
  249. NdiscOptionRepr::PrefixInformation(info) => prefix_info = Some(info),
  250. _ => {}
  251. }
  252. Ok(())
  253. })?;
  254. Ok(Repr::RouterAdvert {
  255. hop_limit: packet.current_hop_limit(),
  256. flags: packet.router_flags(),
  257. router_lifetime: packet.router_lifetime(),
  258. reachable_time: packet.reachable_time(),
  259. retrans_time: packet.retrans_time(),
  260. lladdr,
  261. mtu,
  262. prefix_info,
  263. })
  264. }
  265. Message::NeighborSolicit => {
  266. let mut lladdr = None;
  267. foreach_option(packet.payload(), |opt| {
  268. match opt {
  269. NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
  270. _ => {}
  271. }
  272. Ok(())
  273. })?;
  274. Ok(Repr::NeighborSolicit {
  275. target_addr: packet.target_addr(),
  276. lladdr,
  277. })
  278. }
  279. Message::NeighborAdvert => {
  280. let mut lladdr = None;
  281. foreach_option(packet.payload(), |opt| {
  282. match opt {
  283. NdiscOptionRepr::TargetLinkLayerAddr(addr) => lladdr = Some(addr),
  284. _ => {}
  285. }
  286. Ok(())
  287. })?;
  288. Ok(Repr::NeighborAdvert {
  289. flags: packet.neighbor_flags(),
  290. target_addr: packet.target_addr(),
  291. lladdr,
  292. })
  293. }
  294. Message::Redirect => {
  295. let (mut lladdr, mut redirected_hdr) = (None, None);
  296. foreach_option(packet.payload(), |opt| {
  297. match opt {
  298. NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
  299. NdiscOptionRepr::RedirectedHeader(rh) => redirected_hdr = Some(rh),
  300. _ => {}
  301. }
  302. Ok(())
  303. })?;
  304. Ok(Repr::Redirect {
  305. target_addr: packet.target_addr(),
  306. dest_addr: packet.dest_addr(),
  307. lladdr,
  308. redirected_hdr,
  309. })
  310. }
  311. _ => Err(Error),
  312. }
  313. }
  314. pub const fn buffer_len(&self) -> usize {
  315. match self {
  316. &Repr::RouterSolicit { lladdr } => match lladdr {
  317. Some(addr) => {
  318. field::UNUSED.end + { NdiscOptionRepr::SourceLinkLayerAddr(addr).buffer_len() }
  319. }
  320. None => field::UNUSED.end,
  321. },
  322. &Repr::RouterAdvert {
  323. lladdr,
  324. mtu,
  325. prefix_info,
  326. ..
  327. } => {
  328. let mut offset = 0;
  329. if let Some(lladdr) = lladdr {
  330. offset += NdiscOptionRepr::TargetLinkLayerAddr(lladdr).buffer_len();
  331. }
  332. if let Some(mtu) = mtu {
  333. offset += NdiscOptionRepr::Mtu(mtu).buffer_len();
  334. }
  335. if let Some(prefix_info) = prefix_info {
  336. offset += NdiscOptionRepr::PrefixInformation(prefix_info).buffer_len();
  337. }
  338. field::RETRANS_TM.end + offset
  339. }
  340. &Repr::NeighborSolicit { lladdr, .. } | &Repr::NeighborAdvert { lladdr, .. } => {
  341. let mut offset = field::TARGET_ADDR.end;
  342. if let Some(lladdr) = lladdr {
  343. offset += NdiscOptionRepr::SourceLinkLayerAddr(lladdr).buffer_len();
  344. }
  345. offset
  346. }
  347. &Repr::Redirect {
  348. lladdr,
  349. redirected_hdr,
  350. ..
  351. } => {
  352. let mut offset = field::DEST_ADDR.end;
  353. if let Some(lladdr) = lladdr {
  354. offset += NdiscOptionRepr::TargetLinkLayerAddr(lladdr).buffer_len();
  355. }
  356. if let Some(NdiscRedirectedHeader { header, data }) = redirected_hdr {
  357. offset +=
  358. NdiscOptionRepr::RedirectedHeader(NdiscRedirectedHeader { header, data })
  359. .buffer_len();
  360. }
  361. offset
  362. }
  363. }
  364. }
  365. pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
  366. where
  367. T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
  368. {
  369. match *self {
  370. Repr::RouterSolicit { lladdr } => {
  371. packet.set_msg_type(Message::RouterSolicit);
  372. packet.set_msg_code(0);
  373. packet.clear_reserved();
  374. if let Some(lladdr) = lladdr {
  375. let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
  376. NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  377. }
  378. }
  379. Repr::RouterAdvert {
  380. hop_limit,
  381. flags,
  382. router_lifetime,
  383. reachable_time,
  384. retrans_time,
  385. lladdr,
  386. mtu,
  387. prefix_info,
  388. } => {
  389. packet.set_msg_type(Message::RouterAdvert);
  390. packet.set_msg_code(0);
  391. packet.set_current_hop_limit(hop_limit);
  392. packet.set_router_flags(flags);
  393. packet.set_router_lifetime(router_lifetime);
  394. packet.set_reachable_time(reachable_time);
  395. packet.set_retrans_time(retrans_time);
  396. let mut offset = 0;
  397. if let Some(lladdr) = lladdr {
  398. let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
  399. let opt = NdiscOptionRepr::SourceLinkLayerAddr(lladdr);
  400. opt.emit(&mut opt_pkt);
  401. offset += opt.buffer_len();
  402. }
  403. if let Some(mtu) = mtu {
  404. let mut opt_pkt =
  405. NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
  406. NdiscOptionRepr::Mtu(mtu).emit(&mut opt_pkt);
  407. offset += NdiscOptionRepr::Mtu(mtu).buffer_len();
  408. }
  409. if let Some(prefix_info) = prefix_info {
  410. let mut opt_pkt =
  411. NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
  412. NdiscOptionRepr::PrefixInformation(prefix_info).emit(&mut opt_pkt)
  413. }
  414. }
  415. Repr::NeighborSolicit {
  416. target_addr,
  417. lladdr,
  418. } => {
  419. packet.set_msg_type(Message::NeighborSolicit);
  420. packet.set_msg_code(0);
  421. packet.clear_reserved();
  422. packet.set_target_addr(target_addr);
  423. if let Some(lladdr) = lladdr {
  424. let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
  425. NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  426. }
  427. }
  428. Repr::NeighborAdvert {
  429. flags,
  430. target_addr,
  431. lladdr,
  432. } => {
  433. packet.set_msg_type(Message::NeighborAdvert);
  434. packet.set_msg_code(0);
  435. packet.clear_reserved();
  436. packet.set_neighbor_flags(flags);
  437. packet.set_target_addr(target_addr);
  438. if let Some(lladdr) = lladdr {
  439. let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
  440. NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  441. }
  442. }
  443. Repr::Redirect {
  444. target_addr,
  445. dest_addr,
  446. lladdr,
  447. redirected_hdr,
  448. } => {
  449. packet.set_msg_type(Message::Redirect);
  450. packet.set_msg_code(0);
  451. packet.clear_reserved();
  452. packet.set_target_addr(target_addr);
  453. packet.set_dest_addr(dest_addr);
  454. let offset = match lladdr {
  455. Some(lladdr) => {
  456. let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
  457. NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  458. NdiscOptionRepr::TargetLinkLayerAddr(lladdr).buffer_len()
  459. }
  460. None => 0,
  461. };
  462. if let Some(redirected_hdr) = redirected_hdr {
  463. let mut opt_pkt =
  464. NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
  465. NdiscOptionRepr::RedirectedHeader(redirected_hdr).emit(&mut opt_pkt);
  466. }
  467. }
  468. }
  469. }
  470. }
  471. #[cfg(feature = "medium-ethernet")]
  472. #[cfg(test)]
  473. mod test {
  474. use super::*;
  475. use crate::phy::ChecksumCapabilities;
  476. use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
  477. use crate::wire::EthernetAddress;
  478. use crate::wire::Icmpv6Repr;
  479. static ROUTER_ADVERT_BYTES: [u8; 24] = [
  480. 0x86, 0x00, 0xa9, 0xde, 0x40, 0x80, 0x03, 0x84, 0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x03,
  481. 0x84, 0x01, 0x01, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56,
  482. ];
  483. static SOURCE_LINK_LAYER_OPT: [u8; 8] = [0x01, 0x01, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56];
  484. fn create_repr<'a>() -> Icmpv6Repr<'a> {
  485. Icmpv6Repr::Ndisc(Repr::RouterAdvert {
  486. hop_limit: 64,
  487. flags: RouterFlags::MANAGED,
  488. router_lifetime: Duration::from_secs(900),
  489. reachable_time: Duration::from_millis(900),
  490. retrans_time: Duration::from_millis(900),
  491. lladdr: Some(EthernetAddress([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]).into()),
  492. mtu: None,
  493. prefix_info: None,
  494. })
  495. }
  496. #[test]
  497. fn test_router_advert_deconstruct() {
  498. let packet = Packet::new_unchecked(&ROUTER_ADVERT_BYTES[..]);
  499. assert_eq!(packet.msg_type(), Message::RouterAdvert);
  500. assert_eq!(packet.msg_code(), 0);
  501. assert_eq!(packet.current_hop_limit(), 64);
  502. assert_eq!(packet.router_flags(), RouterFlags::MANAGED);
  503. assert_eq!(packet.router_lifetime(), Duration::from_secs(900));
  504. assert_eq!(packet.reachable_time(), Duration::from_millis(900));
  505. assert_eq!(packet.retrans_time(), Duration::from_millis(900));
  506. assert_eq!(packet.payload(), &SOURCE_LINK_LAYER_OPT[..]);
  507. }
  508. #[test]
  509. fn test_router_advert_construct() {
  510. let mut bytes = vec![0x0; 24];
  511. let mut packet = Packet::new_unchecked(&mut bytes);
  512. packet.set_msg_type(Message::RouterAdvert);
  513. packet.set_msg_code(0);
  514. packet.set_current_hop_limit(64);
  515. packet.set_router_flags(RouterFlags::MANAGED);
  516. packet.set_router_lifetime(Duration::from_secs(900));
  517. packet.set_reachable_time(Duration::from_millis(900));
  518. packet.set_retrans_time(Duration::from_millis(900));
  519. packet
  520. .payload_mut()
  521. .copy_from_slice(&SOURCE_LINK_LAYER_OPT[..]);
  522. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  523. assert_eq!(&*packet.into_inner(), &ROUTER_ADVERT_BYTES[..]);
  524. }
  525. #[test]
  526. fn test_router_advert_repr_parse() {
  527. let packet = Packet::new_unchecked(&ROUTER_ADVERT_BYTES[..]);
  528. assert_eq!(
  529. Icmpv6Repr::parse(
  530. &MOCK_IP_ADDR_1,
  531. &MOCK_IP_ADDR_2,
  532. &packet,
  533. &ChecksumCapabilities::default()
  534. )
  535. .unwrap(),
  536. create_repr()
  537. );
  538. }
  539. #[test]
  540. fn test_router_advert_repr_emit() {
  541. let mut bytes = vec![0x2a; 24];
  542. let mut packet = Packet::new_unchecked(&mut bytes[..]);
  543. create_repr().emit(
  544. &MOCK_IP_ADDR_1,
  545. &MOCK_IP_ADDR_2,
  546. &mut packet,
  547. &ChecksumCapabilities::default(),
  548. );
  549. assert_eq!(&*packet.into_inner(), &ROUTER_ADVERT_BYTES[..]);
  550. }
  551. }