ipv6.rs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. #![deny(missing_docs)]
  2. use byteorder::{ByteOrder, NetworkEndian};
  3. use core::fmt;
  4. use super::{Error, Result};
  5. use crate::wire::ip::pretty_print_ip_payload;
  6. pub use super::IpProtocol as Protocol;
  7. /// Minimum MTU required of all links supporting IPv6. See [RFC 8200 § 5].
  8. ///
  9. /// [RFC 8200 § 5]: https://tools.ietf.org/html/rfc8200#section-5
  10. pub const MIN_MTU: usize = 1280;
  11. /// Size of IPv6 adderess in octets.
  12. ///
  13. /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
  14. pub const ADDR_SIZE: usize = 16;
  15. /// The link-local [all nodes multicast address].
  16. ///
  17. /// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
  18. pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
  19. /// The link-local [all routers multicast address].
  20. ///
  21. /// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
  22. pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
  23. /// The link-local [all MLVDv2-capable routers multicast address].
  24. ///
  25. /// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
  26. pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
  27. /// The link-local [all RPL nodes multicast address].
  28. ///
  29. /// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
  30. pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
  31. /// The [scope] of an address.
  32. ///
  33. /// [scope]: https://www.rfc-editor.org/rfc/rfc4291#section-2.7
  34. #[repr(u8)]
  35. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  36. pub(crate) enum MulticastScope {
  37. /// Interface Local scope
  38. InterfaceLocal = 0x1,
  39. /// Link local scope
  40. LinkLocal = 0x2,
  41. /// Administratively configured
  42. AdminLocal = 0x4,
  43. /// Single site scope
  44. SiteLocal = 0x5,
  45. /// Organization scope
  46. OrganizationLocal = 0x8,
  47. /// Global scope
  48. Global = 0xE,
  49. /// Unknown scope
  50. Unknown = 0xFF,
  51. }
  52. impl From<u8> for MulticastScope {
  53. fn from(value: u8) -> Self {
  54. match value {
  55. 0x1 => Self::InterfaceLocal,
  56. 0x2 => Self::LinkLocal,
  57. 0x4 => Self::AdminLocal,
  58. 0x5 => Self::SiteLocal,
  59. 0x8 => Self::OrganizationLocal,
  60. 0xE => Self::Global,
  61. _ => Self::Unknown,
  62. }
  63. }
  64. }
  65. pub use core::net::Ipv6Addr as Address;
  66. pub(crate) trait AddressExt {
  67. /// Construct an IPv6 address from a sequence of octets, in big-endian.
  68. ///
  69. /// # Panics
  70. /// The function panics if `data` is not sixteen octets long.
  71. fn from_bytes(data: &[u8]) -> Address;
  72. /// Query whether the IPv6 address is an [unicast address].
  73. ///
  74. /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
  75. ///
  76. /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
  77. fn x_is_unicast(&self) -> bool;
  78. /// Query whether the IPv6 address is a [global unicast address].
  79. ///
  80. /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
  81. fn is_global_unicast(&self) -> bool;
  82. /// Query whether the IPv6 address is in the [link-local] scope.
  83. ///
  84. /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
  85. fn is_link_local(&self) -> bool;
  86. /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
  87. ///
  88. /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
  89. ///
  90. /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
  91. fn x_is_unique_local(&self) -> bool;
  92. /// Helper function used to mask an address given a prefix.
  93. ///
  94. /// # Panics
  95. /// This function panics if `mask` is greater than 128.
  96. fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
  97. /// The solicited node for the given unicast address.
  98. ///
  99. /// # Panics
  100. /// This function panics if the given address is not
  101. /// unicast.
  102. fn solicited_node(&self) -> Address;
  103. /// Return the scope of the address.
  104. ///
  105. /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
  106. fn x_multicast_scope(&self) -> MulticastScope;
  107. /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
  108. /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
  109. fn prefix_len(&self) -> Option<u8>;
  110. }
  111. impl AddressExt for Address {
  112. fn from_bytes(data: &[u8]) -> Address {
  113. let mut bytes = [0; ADDR_SIZE];
  114. bytes.copy_from_slice(data);
  115. Address::from(bytes)
  116. }
  117. fn x_is_unicast(&self) -> bool {
  118. !(self.is_multicast() || self.is_unspecified())
  119. }
  120. fn is_global_unicast(&self) -> bool {
  121. (self.octets()[0] >> 5) == 0b001
  122. }
  123. fn is_link_local(&self) -> bool {
  124. self.octets()[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
  125. }
  126. fn x_is_unique_local(&self) -> bool {
  127. (self.octets()[0] & 0b1111_1110) == 0xfc
  128. }
  129. fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
  130. assert!(mask <= 128);
  131. let mut bytes = [0u8; ADDR_SIZE];
  132. let idx = (mask as usize) / 8;
  133. let modulus = (mask as usize) % 8;
  134. let octets = self.octets();
  135. let (first, second) = octets.split_at(idx);
  136. bytes[0..idx].copy_from_slice(first);
  137. if idx < ADDR_SIZE {
  138. let part = second[0];
  139. bytes[idx] = part & (!(0xff >> modulus) as u8);
  140. }
  141. bytes
  142. }
  143. fn solicited_node(&self) -> Address {
  144. assert!(self.x_is_unicast());
  145. let o = self.octets();
  146. Address::from([
  147. 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, o[13],
  148. o[14], o[15],
  149. ])
  150. }
  151. fn x_multicast_scope(&self) -> MulticastScope {
  152. if self.is_multicast() {
  153. return MulticastScope::from(self.octets()[1] & 0b1111);
  154. }
  155. if self.is_link_local() {
  156. MulticastScope::LinkLocal
  157. } else if self.x_is_unique_local() || self.is_global_unicast() {
  158. // ULA are considered global scope
  159. // https://www.rfc-editor.org/rfc/rfc6724#section-3.1
  160. MulticastScope::Global
  161. } else {
  162. MulticastScope::Unknown
  163. }
  164. }
  165. fn prefix_len(&self) -> Option<u8> {
  166. let mut ones = true;
  167. let mut prefix_len = 0;
  168. for byte in self.octets() {
  169. let mut mask = 0x80;
  170. for _ in 0..8 {
  171. let one = byte & mask != 0;
  172. if ones {
  173. // Expect 1s until first 0
  174. if one {
  175. prefix_len += 1;
  176. } else {
  177. ones = false;
  178. }
  179. } else if one {
  180. // 1 where 0 was expected
  181. return None;
  182. }
  183. mask >>= 1;
  184. }
  185. }
  186. Some(prefix_len)
  187. }
  188. }
  189. /// A specification of an IPv6 CIDR block, containing an address and a variable-length
  190. /// subnet masking prefix length.
  191. #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
  192. pub struct Cidr {
  193. address: Address,
  194. prefix_len: u8,
  195. }
  196. impl Cidr {
  197. /// The [solicited node prefix].
  198. ///
  199. /// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1
  200. pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
  201. address: Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0),
  202. prefix_len: 104,
  203. };
  204. /// Create an IPv6 CIDR block from the given address and prefix length.
  205. ///
  206. /// # Panics
  207. /// This function panics if the prefix length is larger than 128.
  208. pub const fn new(address: Address, prefix_len: u8) -> Cidr {
  209. assert!(prefix_len <= 128);
  210. Cidr {
  211. address,
  212. prefix_len,
  213. }
  214. }
  215. /// Return the address of this IPv6 CIDR block.
  216. pub const fn address(&self) -> Address {
  217. self.address
  218. }
  219. /// Return the prefix length of this IPv6 CIDR block.
  220. pub const fn prefix_len(&self) -> u8 {
  221. self.prefix_len
  222. }
  223. /// Query whether the subnetwork described by this IPv6 CIDR block contains
  224. /// the given address.
  225. pub fn contains_addr(&self, addr: &Address) -> bool {
  226. // right shift by 128 is not legal
  227. if self.prefix_len == 0 {
  228. return true;
  229. }
  230. self.address.mask(self.prefix_len) == addr.mask(self.prefix_len)
  231. }
  232. /// Query whether the subnetwork described by this IPV6 CIDR block contains
  233. /// the subnetwork described by the given IPv6 CIDR block.
  234. pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
  235. self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address)
  236. }
  237. }
  238. impl fmt::Display for Cidr {
  239. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  240. // https://tools.ietf.org/html/rfc4291#section-2.3
  241. write!(f, "{}/{}", self.address, self.prefix_len)
  242. }
  243. }
  244. #[cfg(feature = "defmt")]
  245. impl defmt::Format for Cidr {
  246. fn format(&self, f: defmt::Formatter) {
  247. defmt::write!(f, "{}/{=u8}", self.address, self.prefix_len);
  248. }
  249. }
  250. /// A read/write wrapper around an Internet Protocol version 6 packet buffer.
  251. #[derive(Debug, PartialEq, Eq, Clone)]
  252. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  253. pub struct Packet<T: AsRef<[u8]>> {
  254. buffer: T,
  255. }
  256. // Ranges and constants describing the IPv6 header
  257. //
  258. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  259. // |Version| Traffic Class | Flow Label |
  260. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  261. // | Payload Length | Next Header | Hop Limit |
  262. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  263. // | |
  264. // + +
  265. // | |
  266. // + Source Address +
  267. // | |
  268. // + +
  269. // | |
  270. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  271. // | |
  272. // + +
  273. // | |
  274. // + Destination Address +
  275. // | |
  276. // + +
  277. // | |
  278. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  279. //
  280. // See https://tools.ietf.org/html/rfc2460#section-3 for details.
  281. mod field {
  282. use crate::wire::field::*;
  283. // 4-bit version number, 8-bit traffic class, and the
  284. // 20-bit flow label.
  285. pub const VER_TC_FLOW: Field = 0..4;
  286. // 16-bit value representing the length of the payload.
  287. // Note: Options are included in this length.
  288. pub const LENGTH: Field = 4..6;
  289. // 8-bit value identifying the type of header following this
  290. // one. Note: The same numbers are used in IPv4.
  291. pub const NXT_HDR: usize = 6;
  292. // 8-bit value decremented by each node that forwards this
  293. // packet. The packet is discarded when the value is 0.
  294. pub const HOP_LIMIT: usize = 7;
  295. // IPv6 address of the source node.
  296. pub const SRC_ADDR: Field = 8..24;
  297. // IPv6 address of the destination node.
  298. pub const DST_ADDR: Field = 24..40;
  299. }
  300. /// Length of an IPv6 header.
  301. pub const HEADER_LEN: usize = field::DST_ADDR.end;
  302. impl<T: AsRef<[u8]>> Packet<T> {
  303. /// Create a raw octet buffer with an IPv6 packet structure.
  304. #[inline]
  305. pub const fn new_unchecked(buffer: T) -> Packet<T> {
  306. Packet { buffer }
  307. }
  308. /// Shorthand for a combination of [new_unchecked] and [check_len].
  309. ///
  310. /// [new_unchecked]: #method.new_unchecked
  311. /// [check_len]: #method.check_len
  312. #[inline]
  313. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  314. let packet = Self::new_unchecked(buffer);
  315. packet.check_len()?;
  316. Ok(packet)
  317. }
  318. /// Ensure that no accessor method will panic if called.
  319. /// Returns `Err(Error)` if the buffer is too short.
  320. ///
  321. /// The result of this check is invalidated by calling [set_payload_len].
  322. ///
  323. /// [set_payload_len]: #method.set_payload_len
  324. #[inline]
  325. pub fn check_len(&self) -> Result<()> {
  326. let len = self.buffer.as_ref().len();
  327. if len < field::DST_ADDR.end || len < self.total_len() {
  328. Err(Error)
  329. } else {
  330. Ok(())
  331. }
  332. }
  333. /// Consume the packet, returning the underlying buffer.
  334. #[inline]
  335. pub fn into_inner(self) -> T {
  336. self.buffer
  337. }
  338. /// Return the header length.
  339. #[inline]
  340. pub const fn header_len(&self) -> usize {
  341. // This is not a strictly necessary function, but it makes
  342. // code more readable.
  343. field::DST_ADDR.end
  344. }
  345. /// Return the version field.
  346. #[inline]
  347. pub fn version(&self) -> u8 {
  348. let data = self.buffer.as_ref();
  349. data[field::VER_TC_FLOW.start] >> 4
  350. }
  351. /// Return the traffic class.
  352. #[inline]
  353. pub fn traffic_class(&self) -> u8 {
  354. let data = self.buffer.as_ref();
  355. ((NetworkEndian::read_u16(&data[0..2]) & 0x0ff0) >> 4) as u8
  356. }
  357. /// Return the flow label field.
  358. #[inline]
  359. pub fn flow_label(&self) -> u32 {
  360. let data = self.buffer.as_ref();
  361. NetworkEndian::read_u24(&data[1..4]) & 0x000fffff
  362. }
  363. /// Return the payload length field.
  364. #[inline]
  365. pub fn payload_len(&self) -> u16 {
  366. let data = self.buffer.as_ref();
  367. NetworkEndian::read_u16(&data[field::LENGTH])
  368. }
  369. /// Return the payload length added to the known header length.
  370. #[inline]
  371. pub fn total_len(&self) -> usize {
  372. self.header_len() + self.payload_len() as usize
  373. }
  374. /// Return the next header field.
  375. #[inline]
  376. pub fn next_header(&self) -> Protocol {
  377. let data = self.buffer.as_ref();
  378. Protocol::from(data[field::NXT_HDR])
  379. }
  380. /// Return the hop limit field.
  381. #[inline]
  382. pub fn hop_limit(&self) -> u8 {
  383. let data = self.buffer.as_ref();
  384. data[field::HOP_LIMIT]
  385. }
  386. /// Return the source address field.
  387. #[inline]
  388. pub fn src_addr(&self) -> Address {
  389. let data = self.buffer.as_ref();
  390. Address::from_bytes(&data[field::SRC_ADDR])
  391. }
  392. /// Return the destination address field.
  393. #[inline]
  394. pub fn dst_addr(&self) -> Address {
  395. let data = self.buffer.as_ref();
  396. Address::from_bytes(&data[field::DST_ADDR])
  397. }
  398. }
  399. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  400. /// Return a pointer to the payload.
  401. #[inline]
  402. pub fn payload(&self) -> &'a [u8] {
  403. let data = self.buffer.as_ref();
  404. let range = self.header_len()..self.total_len();
  405. &data[range]
  406. }
  407. }
  408. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  409. /// Set the version field.
  410. #[inline]
  411. pub fn set_version(&mut self, value: u8) {
  412. let data = self.buffer.as_mut();
  413. // Make sure to retain the lower order bits which contain
  414. // the higher order bits of the traffic class
  415. data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4);
  416. }
  417. /// Set the traffic class field.
  418. #[inline]
  419. pub fn set_traffic_class(&mut self, value: u8) {
  420. let data = self.buffer.as_mut();
  421. // Put the higher order 4-bits of value in the lower order
  422. // 4-bits of the first byte
  423. data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4);
  424. // Put the lower order 4-bits of value in the higher order
  425. // 4-bits of the second byte
  426. data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4);
  427. }
  428. /// Set the flow label field.
  429. #[inline]
  430. pub fn set_flow_label(&mut self, value: u32) {
  431. let data = self.buffer.as_mut();
  432. // Retain the lower order 4-bits of the traffic class
  433. let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff);
  434. NetworkEndian::write_u24(&mut data[1..4], raw);
  435. }
  436. /// Set the payload length field.
  437. #[inline]
  438. pub fn set_payload_len(&mut self, value: u16) {
  439. let data = self.buffer.as_mut();
  440. NetworkEndian::write_u16(&mut data[field::LENGTH], value);
  441. }
  442. /// Set the next header field.
  443. #[inline]
  444. pub fn set_next_header(&mut self, value: Protocol) {
  445. let data = self.buffer.as_mut();
  446. data[field::NXT_HDR] = value.into();
  447. }
  448. /// Set the hop limit field.
  449. #[inline]
  450. pub fn set_hop_limit(&mut self, value: u8) {
  451. let data = self.buffer.as_mut();
  452. data[field::HOP_LIMIT] = value;
  453. }
  454. /// Set the source address field.
  455. #[inline]
  456. pub fn set_src_addr(&mut self, value: Address) {
  457. let data = self.buffer.as_mut();
  458. data[field::SRC_ADDR].copy_from_slice(&value.octets());
  459. }
  460. /// Set the destination address field.
  461. #[inline]
  462. pub fn set_dst_addr(&mut self, value: Address) {
  463. let data = self.buffer.as_mut();
  464. data[field::DST_ADDR].copy_from_slice(&value.octets());
  465. }
  466. /// Return a mutable pointer to the payload.
  467. #[inline]
  468. pub fn payload_mut(&mut self) -> &mut [u8] {
  469. let range = self.header_len()..self.total_len();
  470. let data = self.buffer.as_mut();
  471. &mut data[range]
  472. }
  473. }
  474. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
  475. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  476. match Repr::parse(self) {
  477. Ok(repr) => write!(f, "{repr}"),
  478. Err(err) => {
  479. write!(f, "IPv6 ({err})")?;
  480. Ok(())
  481. }
  482. }
  483. }
  484. }
  485. impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
  486. fn as_ref(&self) -> &[u8] {
  487. self.buffer.as_ref()
  488. }
  489. }
  490. /// A high-level representation of an Internet Protocol version 6 packet header.
  491. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  492. pub struct Repr {
  493. /// IPv6 address of the source node.
  494. pub src_addr: Address,
  495. /// IPv6 address of the destination node.
  496. pub dst_addr: Address,
  497. /// Protocol contained in the next header.
  498. pub next_header: Protocol,
  499. /// Length of the payload including the extension headers.
  500. pub payload_len: usize,
  501. /// The 8-bit hop limit field.
  502. pub hop_limit: u8,
  503. }
  504. impl Repr {
  505. /// Parse an Internet Protocol version 6 packet and return a high-level representation.
  506. pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> {
  507. // Ensure basic accessors will work
  508. packet.check_len()?;
  509. if packet.version() != 6 {
  510. return Err(Error);
  511. }
  512. Ok(Repr {
  513. src_addr: packet.src_addr(),
  514. dst_addr: packet.dst_addr(),
  515. next_header: packet.next_header(),
  516. payload_len: packet.payload_len() as usize,
  517. hop_limit: packet.hop_limit(),
  518. })
  519. }
  520. /// Return the length of a header that will be emitted from this high-level representation.
  521. pub const fn buffer_len(&self) -> usize {
  522. // This function is not strictly necessary, but it can make client code more readable.
  523. field::DST_ADDR.end
  524. }
  525. /// Emit a high-level representation into an Internet Protocol version 6 packet.
  526. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
  527. // Make no assumptions about the original state of the packet buffer.
  528. // Make sure to set every byte.
  529. packet.set_version(6);
  530. packet.set_traffic_class(0);
  531. packet.set_flow_label(0);
  532. packet.set_payload_len(self.payload_len as u16);
  533. packet.set_hop_limit(self.hop_limit);
  534. packet.set_next_header(self.next_header);
  535. packet.set_src_addr(self.src_addr);
  536. packet.set_dst_addr(self.dst_addr);
  537. }
  538. }
  539. impl fmt::Display for Repr {
  540. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  541. write!(
  542. f,
  543. "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
  544. self.src_addr, self.dst_addr, self.next_header, self.hop_limit
  545. )
  546. }
  547. }
  548. #[cfg(feature = "defmt")]
  549. impl defmt::Format for Repr {
  550. fn format(&self, fmt: defmt::Formatter) {
  551. defmt::write!(
  552. fmt,
  553. "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
  554. self.src_addr,
  555. self.dst_addr,
  556. self.next_header,
  557. self.hop_limit
  558. )
  559. }
  560. }
  561. use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
  562. // TODO: This is very similar to the implementation for IPv4. Make
  563. // a way to have less copy and pasted code here.
  564. impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
  565. fn pretty_print(
  566. buffer: &dyn AsRef<[u8]>,
  567. f: &mut fmt::Formatter,
  568. indent: &mut PrettyIndent,
  569. ) -> fmt::Result {
  570. let (ip_repr, payload) = match Packet::new_checked(buffer) {
  571. Err(err) => return write!(f, "{indent}({err})"),
  572. Ok(ip_packet) => match Repr::parse(&ip_packet) {
  573. Err(_) => return Ok(()),
  574. Ok(ip_repr) => {
  575. write!(f, "{indent}{ip_repr}")?;
  576. (ip_repr, ip_packet.payload())
  577. }
  578. },
  579. };
  580. pretty_print_ip_payload(f, indent, ip_repr, payload)
  581. }
  582. }
  583. #[cfg(test)]
  584. pub(crate) mod test {
  585. use super::*;
  586. use crate::wire::pretty_print::PrettyPrinter;
  587. #[allow(unused)]
  588. pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
  589. #[allow(unused)]
  590. pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
  591. #[allow(unused)]
  592. pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
  593. #[allow(unused)]
  594. pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 4);
  595. #[allow(unused)]
  596. pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
  597. const LINK_LOCAL_ADDR: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
  598. const UNIQUE_LOCAL_ADDR: Address = Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
  599. const GLOBAL_UNICAST_ADDR: Address = Address::new(0x2001, 0xdb8, 0x3, 0, 0, 0, 0, 1);
  600. #[test]
  601. fn test_basic_multicast() {
  602. assert!(!LINK_LOCAL_ALL_ROUTERS.is_unspecified());
  603. assert!(LINK_LOCAL_ALL_ROUTERS.is_multicast());
  604. assert!(!LINK_LOCAL_ALL_ROUTERS.is_link_local());
  605. assert!(!LINK_LOCAL_ALL_ROUTERS.is_loopback());
  606. assert!(!LINK_LOCAL_ALL_ROUTERS.x_is_unique_local());
  607. assert!(!LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
  608. assert!(!LINK_LOCAL_ALL_NODES.is_unspecified());
  609. assert!(LINK_LOCAL_ALL_NODES.is_multicast());
  610. assert!(!LINK_LOCAL_ALL_NODES.is_link_local());
  611. assert!(!LINK_LOCAL_ALL_NODES.is_loopback());
  612. assert!(!LINK_LOCAL_ALL_NODES.x_is_unique_local());
  613. assert!(!LINK_LOCAL_ALL_NODES.is_global_unicast());
  614. }
  615. #[test]
  616. fn test_basic_link_local() {
  617. assert!(!LINK_LOCAL_ADDR.is_unspecified());
  618. assert!(!LINK_LOCAL_ADDR.is_multicast());
  619. assert!(LINK_LOCAL_ADDR.is_link_local());
  620. assert!(!LINK_LOCAL_ADDR.is_loopback());
  621. assert!(!LINK_LOCAL_ADDR.x_is_unique_local());
  622. assert!(!LINK_LOCAL_ADDR.is_global_unicast());
  623. }
  624. #[test]
  625. fn test_basic_loopback() {
  626. assert!(!Address::LOCALHOST.is_unspecified());
  627. assert!(!Address::LOCALHOST.is_multicast());
  628. assert!(!Address::LOCALHOST.is_link_local());
  629. assert!(Address::LOCALHOST.is_loopback());
  630. assert!(!Address::LOCALHOST.x_is_unique_local());
  631. assert!(!Address::LOCALHOST.is_global_unicast());
  632. }
  633. #[test]
  634. fn test_unique_local() {
  635. assert!(!UNIQUE_LOCAL_ADDR.is_unspecified());
  636. assert!(!UNIQUE_LOCAL_ADDR.is_multicast());
  637. assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
  638. assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
  639. assert!(UNIQUE_LOCAL_ADDR.x_is_unique_local());
  640. assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
  641. }
  642. #[test]
  643. fn test_global_unicast() {
  644. assert!(!GLOBAL_UNICAST_ADDR.is_unspecified());
  645. assert!(!GLOBAL_UNICAST_ADDR.is_multicast());
  646. assert!(!GLOBAL_UNICAST_ADDR.is_link_local());
  647. assert!(!GLOBAL_UNICAST_ADDR.is_loopback());
  648. assert!(!GLOBAL_UNICAST_ADDR.x_is_unique_local());
  649. assert!(GLOBAL_UNICAST_ADDR.is_global_unicast());
  650. }
  651. #[test]
  652. fn test_mask() {
  653. let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
  654. assert_eq!(
  655. addr.mask(11),
  656. [0x01, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  657. );
  658. assert_eq!(
  659. addr.mask(15),
  660. [0x01, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  661. );
  662. assert_eq!(
  663. addr.mask(26),
  664. [0x01, 0x23, 0x45, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  665. );
  666. assert_eq!(
  667. addr.mask(128),
  668. [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
  669. );
  670. assert_eq!(
  671. addr.mask(127),
  672. [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  673. );
  674. }
  675. #[test]
  676. fn test_cidr() {
  677. // fe80::1/56
  678. // 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  679. // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  680. let cidr = Cidr::new(LINK_LOCAL_ADDR, 56);
  681. let inside_subnet = [
  682. // fe80::2
  683. [
  684. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  685. 0x00, 0x02,
  686. ],
  687. // fe80::1122:3344:5566:7788
  688. [
  689. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
  690. 0x77, 0x88,
  691. ],
  692. // fe80::ff00:0:0:0
  693. [
  694. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
  695. 0x00, 0x00,
  696. ],
  697. // fe80::ff
  698. [
  699. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  700. 0x00, 0xff,
  701. ],
  702. ];
  703. let outside_subnet = [
  704. // fe80:0:0:101::1
  705. [
  706. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  707. 0x00, 0x01,
  708. ],
  709. // ::1
  710. [
  711. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  712. 0x00, 0x01,
  713. ],
  714. // ff02::1
  715. [
  716. 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  717. 0x00, 0x01,
  718. ],
  719. // ff02::2
  720. [
  721. 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  722. 0x00, 0x02,
  723. ],
  724. ];
  725. let subnets = [
  726. // fe80::ffff:ffff:ffff:ffff/65
  727. (
  728. [
  729. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
  730. 0xff, 0xff, 0xff,
  731. ],
  732. 65,
  733. ),
  734. // fe80::1/128
  735. (
  736. [
  737. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  738. 0x00, 0x00, 0x01,
  739. ],
  740. 128,
  741. ),
  742. // fe80::1234:5678/96
  743. (
  744. [
  745. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
  746. 0x34, 0x56, 0x78,
  747. ],
  748. 96,
  749. ),
  750. ];
  751. let not_subnets = [
  752. // fe80::101:ffff:ffff:ffff:ffff/55
  753. (
  754. [
  755. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
  756. 0xff, 0xff, 0xff,
  757. ],
  758. 55,
  759. ),
  760. // fe80::101:ffff:ffff:ffff:ffff/56
  761. (
  762. [
  763. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
  764. 0xff, 0xff, 0xff,
  765. ],
  766. 56,
  767. ),
  768. // fe80::101:ffff:ffff:ffff:ffff/57
  769. (
  770. [
  771. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
  772. 0xff, 0xff, 0xff,
  773. ],
  774. 57,
  775. ),
  776. // ::1/128
  777. (
  778. [
  779. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  780. 0x00, 0x00, 0x01,
  781. ],
  782. 128,
  783. ),
  784. ];
  785. for addr in inside_subnet.iter().map(|a| Address::from_bytes(a)) {
  786. assert!(cidr.contains_addr(&addr));
  787. }
  788. for addr in outside_subnet.iter().map(|a| Address::from_bytes(a)) {
  789. assert!(!cidr.contains_addr(&addr));
  790. }
  791. for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address::from(a), p)) {
  792. assert!(cidr.contains_subnet(&subnet));
  793. }
  794. for subnet in not_subnets
  795. .iter()
  796. .map(|&(a, p)| Cidr::new(Address::from(a), p))
  797. {
  798. assert!(!cidr.contains_subnet(&subnet));
  799. }
  800. let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
  801. assert!(cidr_without_prefix.contains_addr(&Address::LOCALHOST));
  802. }
  803. #[test]
  804. #[should_panic(expected = "length")]
  805. fn test_from_bytes_too_long() {
  806. let _ = Address::from_bytes(&[0u8; 15]);
  807. }
  808. #[test]
  809. fn test_scope() {
  810. use super::*;
  811. assert_eq!(
  812. Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  813. MulticastScope::InterfaceLocal
  814. );
  815. assert_eq!(
  816. Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  817. MulticastScope::LinkLocal
  818. );
  819. assert_eq!(
  820. Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  821. MulticastScope::Unknown
  822. );
  823. assert_eq!(
  824. Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  825. MulticastScope::AdminLocal
  826. );
  827. assert_eq!(
  828. Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  829. MulticastScope::SiteLocal
  830. );
  831. assert_eq!(
  832. Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  833. MulticastScope::OrganizationLocal
  834. );
  835. assert_eq!(
  836. Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
  837. MulticastScope::Global
  838. );
  839. assert_eq!(
  840. LINK_LOCAL_ALL_NODES.x_multicast_scope(),
  841. MulticastScope::LinkLocal
  842. );
  843. // For source address selection, unicast addresses also have a scope:
  844. assert_eq!(
  845. LINK_LOCAL_ADDR.x_multicast_scope(),
  846. MulticastScope::LinkLocal
  847. );
  848. assert_eq!(
  849. GLOBAL_UNICAST_ADDR.x_multicast_scope(),
  850. MulticastScope::Global
  851. );
  852. assert_eq!(
  853. UNIQUE_LOCAL_ADDR.x_multicast_scope(),
  854. MulticastScope::Global
  855. );
  856. }
  857. static REPR_PACKET_BYTES: [u8; 52] = [
  858. 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  859. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
  860. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
  861. 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
  862. ];
  863. static REPR_PAYLOAD_BYTES: [u8; 12] = [
  864. 0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
  865. ];
  866. const fn packet_repr() -> Repr {
  867. Repr {
  868. src_addr: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
  869. dst_addr: LINK_LOCAL_ALL_NODES,
  870. next_header: Protocol::Udp,
  871. payload_len: 12,
  872. hop_limit: 64,
  873. }
  874. }
  875. #[test]
  876. fn test_packet_deconstruction() {
  877. let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
  878. assert_eq!(packet.check_len(), Ok(()));
  879. assert_eq!(packet.version(), 6);
  880. assert_eq!(packet.traffic_class(), 0);
  881. assert_eq!(packet.flow_label(), 0);
  882. assert_eq!(packet.total_len(), 0x34);
  883. assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
  884. assert_eq!(packet.next_header(), Protocol::Udp);
  885. assert_eq!(packet.hop_limit(), 0x40);
  886. assert_eq!(packet.src_addr(), Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
  887. assert_eq!(packet.dst_addr(), LINK_LOCAL_ALL_NODES);
  888. assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
  889. }
  890. #[test]
  891. fn test_packet_construction() {
  892. let mut bytes = [0xff; 52];
  893. let mut packet = Packet::new_unchecked(&mut bytes[..]);
  894. // Version, Traffic Class, and Flow Label are not
  895. // byte aligned. make sure the setters and getters
  896. // do not interfere with each other.
  897. packet.set_version(6);
  898. assert_eq!(packet.version(), 6);
  899. packet.set_traffic_class(0x99);
  900. assert_eq!(packet.version(), 6);
  901. assert_eq!(packet.traffic_class(), 0x99);
  902. packet.set_flow_label(0x54321);
  903. assert_eq!(packet.traffic_class(), 0x99);
  904. assert_eq!(packet.flow_label(), 0x54321);
  905. packet.set_payload_len(0xc);
  906. packet.set_next_header(Protocol::Udp);
  907. packet.set_hop_limit(0xfe);
  908. packet.set_src_addr(LINK_LOCAL_ALL_ROUTERS);
  909. packet.set_dst_addr(LINK_LOCAL_ALL_NODES);
  910. packet
  911. .payload_mut()
  912. .copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
  913. let mut expected_bytes = [
  914. 0x69, 0x95, 0x43, 0x21, 0x00, 0x0c, 0x11, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
  915. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x02, 0x00, 0x00,
  916. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
  917. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  918. ];
  919. let start = expected_bytes.len() - REPR_PAYLOAD_BYTES.len();
  920. expected_bytes[start..].copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
  921. assert_eq!(packet.check_len(), Ok(()));
  922. assert_eq!(&*packet.into_inner(), &expected_bytes[..]);
  923. }
  924. #[test]
  925. fn test_overlong() {
  926. let mut bytes = vec![];
  927. bytes.extend(&REPR_PACKET_BYTES[..]);
  928. bytes.push(0);
  929. assert_eq!(
  930. Packet::new_unchecked(&bytes).payload().len(),
  931. REPR_PAYLOAD_BYTES.len()
  932. );
  933. assert_eq!(
  934. Packet::new_unchecked(&mut bytes).payload_mut().len(),
  935. REPR_PAYLOAD_BYTES.len()
  936. );
  937. }
  938. #[test]
  939. fn test_total_len_overflow() {
  940. let mut bytes = vec![];
  941. bytes.extend(&REPR_PACKET_BYTES[..]);
  942. Packet::new_unchecked(&mut bytes).set_payload_len(0x80);
  943. assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
  944. }
  945. #[test]
  946. fn test_repr_parse_valid() {
  947. let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
  948. let repr = Repr::parse(&packet).unwrap();
  949. assert_eq!(repr, packet_repr());
  950. }
  951. #[test]
  952. fn test_repr_parse_bad_version() {
  953. let mut bytes = [0; 40];
  954. let mut packet = Packet::new_unchecked(&mut bytes[..]);
  955. packet.set_version(4);
  956. packet.set_payload_len(0);
  957. let packet = Packet::new_unchecked(&*packet.into_inner());
  958. assert_eq!(Repr::parse(&packet), Err(Error));
  959. }
  960. #[test]
  961. fn test_repr_parse_smaller_than_header() {
  962. let mut bytes = [0; 40];
  963. let mut packet = Packet::new_unchecked(&mut bytes[..]);
  964. packet.set_version(6);
  965. packet.set_payload_len(39);
  966. let packet = Packet::new_unchecked(&*packet.into_inner());
  967. assert_eq!(Repr::parse(&packet), Err(Error));
  968. }
  969. #[test]
  970. fn test_repr_parse_smaller_than_payload() {
  971. let mut bytes = [0; 40];
  972. let mut packet = Packet::new_unchecked(&mut bytes[..]);
  973. packet.set_version(6);
  974. packet.set_payload_len(1);
  975. let packet = Packet::new_unchecked(&*packet.into_inner());
  976. assert_eq!(Repr::parse(&packet), Err(Error));
  977. }
  978. #[test]
  979. fn test_basic_repr_emit() {
  980. let repr = packet_repr();
  981. let mut bytes = vec![0xff; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
  982. let mut packet = Packet::new_unchecked(&mut bytes);
  983. repr.emit(&mut packet);
  984. packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
  985. assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]);
  986. }
  987. #[test]
  988. fn test_pretty_print() {
  989. assert_eq!(
  990. format!(
  991. "{}",
  992. PrettyPrinter::<Packet<&'static [u8]>>::new("\n", &&REPR_PACKET_BYTES[..])
  993. ),
  994. "\nIPv6 src=fe80::1 dst=ff02::1 nxt_hdr=UDP hop_limit=64\n \\ UDP src=1 dst=2 len=4"
  995. );
  996. }
  997. }