ndisc.rs 23 KB

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