ndisc.rs 22 KB

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