icmpv6.rs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. use byteorder::{ByteOrder, NetworkEndian};
  2. use core::{cmp, fmt};
  3. use crate::phy::ChecksumCapabilities;
  4. use crate::wire::ip::checksum;
  5. use crate::wire::MldRepr;
  6. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  7. use crate::wire::NdiscRepr;
  8. use crate::wire::{IpAddress, IpProtocol, Ipv6Packet, Ipv6Repr};
  9. use crate::{Error, Result};
  10. enum_with_unknown! {
  11. /// Internet protocol control message type.
  12. pub enum Message(u8) {
  13. /// Destination Unreachable.
  14. DstUnreachable = 0x01,
  15. /// Packet Too Big.
  16. PktTooBig = 0x02,
  17. /// Time Exceeded.
  18. TimeExceeded = 0x03,
  19. /// Parameter Problem.
  20. ParamProblem = 0x04,
  21. /// Echo Request
  22. EchoRequest = 0x80,
  23. /// Echo Reply
  24. EchoReply = 0x81,
  25. /// Multicast Listener Query
  26. MldQuery = 0x82,
  27. /// Router Solicitation
  28. RouterSolicit = 0x85,
  29. /// Router Advertisement
  30. RouterAdvert = 0x86,
  31. /// Neighbor Solicitation
  32. NeighborSolicit = 0x87,
  33. /// Neighbor Advertisement
  34. NeighborAdvert = 0x88,
  35. /// Redirect
  36. Redirect = 0x89,
  37. /// Multicast Listener Report
  38. MldReport = 0x8f
  39. }
  40. }
  41. impl Message {
  42. /// Per [RFC 4443 § 2.1] ICMPv6 message types with the highest order
  43. /// bit set are informational messages while message types without
  44. /// the highest order bit set are error messages.
  45. ///
  46. /// [RFC 4443 § 2.1]: https://tools.ietf.org/html/rfc4443#section-2.1
  47. pub fn is_error(&self) -> bool {
  48. (u8::from(*self) & 0x80) != 0x80
  49. }
  50. /// Return a boolean value indicating if the given message type
  51. /// is an [NDISC] message type.
  52. ///
  53. /// [NDISC]: https://tools.ietf.org/html/rfc4861
  54. pub fn is_ndisc(&self) -> bool {
  55. match *self {
  56. Message::RouterSolicit
  57. | Message::RouterAdvert
  58. | Message::NeighborSolicit
  59. | Message::NeighborAdvert
  60. | Message::Redirect => true,
  61. _ => false,
  62. }
  63. }
  64. /// Return a boolean value indicating if the given message type
  65. /// is an [MLD] message type.
  66. ///
  67. /// [MLD]: https://tools.ietf.org/html/rfc3810
  68. pub fn is_mld(&self) -> bool {
  69. match *self {
  70. Message::MldQuery | Message::MldReport => true,
  71. _ => false,
  72. }
  73. }
  74. }
  75. impl fmt::Display for Message {
  76. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  77. match *self {
  78. Message::DstUnreachable => write!(f, "destination unreachable"),
  79. Message::PktTooBig => write!(f, "packet too big"),
  80. Message::TimeExceeded => write!(f, "time exceeded"),
  81. Message::ParamProblem => write!(f, "parameter problem"),
  82. Message::EchoReply => write!(f, "echo reply"),
  83. Message::EchoRequest => write!(f, "echo request"),
  84. Message::RouterSolicit => write!(f, "router solicitation"),
  85. Message::RouterAdvert => write!(f, "router advertisement"),
  86. Message::NeighborSolicit => write!(f, "neighbor solicitation"),
  87. Message::NeighborAdvert => write!(f, "neighbor advert"),
  88. Message::Redirect => write!(f, "redirect"),
  89. Message::MldQuery => write!(f, "multicast listener query"),
  90. Message::MldReport => write!(f, "multicast listener report"),
  91. Message::Unknown(id) => write!(f, "{}", id),
  92. }
  93. }
  94. }
  95. enum_with_unknown! {
  96. /// Internet protocol control message subtype for type "Destination Unreachable".
  97. pub enum DstUnreachable(u8) {
  98. /// No Route to destination.
  99. NoRoute = 0,
  100. /// Communication with destination administratively prohibited.
  101. AdminProhibit = 1,
  102. /// Beyond scope of source address.
  103. BeyondScope = 2,
  104. /// Address unreachable.
  105. AddrUnreachable = 3,
  106. /// Port unreachable.
  107. PortUnreachable = 4,
  108. /// Source address failed ingress/egress policy.
  109. FailedPolicy = 5,
  110. /// Reject route to destination.
  111. RejectRoute = 6
  112. }
  113. }
  114. impl fmt::Display for DstUnreachable {
  115. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  116. match *self {
  117. DstUnreachable::NoRoute => write!(f, "no route to destination"),
  118. DstUnreachable::AdminProhibit => write!(
  119. f,
  120. "communication with destination administratively prohibited"
  121. ),
  122. DstUnreachable::BeyondScope => write!(f, "beyond scope of source address"),
  123. DstUnreachable::AddrUnreachable => write!(f, "address unreachable"),
  124. DstUnreachable::PortUnreachable => write!(f, "port unreachable"),
  125. DstUnreachable::FailedPolicy => {
  126. write!(f, "source address failed ingress/egress policy")
  127. }
  128. DstUnreachable::RejectRoute => write!(f, "reject route to destination"),
  129. DstUnreachable::Unknown(id) => write!(f, "{}", id),
  130. }
  131. }
  132. }
  133. enum_with_unknown! {
  134. /// Internet protocol control message subtype for the type "Parameter Problem".
  135. pub enum ParamProblem(u8) {
  136. /// Erroneous header field encountered.
  137. ErroneousHdrField = 0,
  138. /// Unrecognized Next Header type encountered.
  139. UnrecognizedNxtHdr = 1,
  140. /// Unrecognized IPv6 option encountered.
  141. UnrecognizedOption = 2
  142. }
  143. }
  144. impl fmt::Display for ParamProblem {
  145. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  146. match *self {
  147. ParamProblem::ErroneousHdrField => write!(f, "erroneous header field."),
  148. ParamProblem::UnrecognizedNxtHdr => write!(f, "unrecognized next header type."),
  149. ParamProblem::UnrecognizedOption => write!(f, "unrecognized IPv6 option."),
  150. ParamProblem::Unknown(id) => write!(f, "{}", id),
  151. }
  152. }
  153. }
  154. enum_with_unknown! {
  155. /// Internet protocol control message subtype for the type "Time Exceeded".
  156. pub enum TimeExceeded(u8) {
  157. /// Hop limit exceeded in transit.
  158. HopLimitExceeded = 0,
  159. /// Fragment reassembly time exceeded.
  160. FragReassemExceeded = 1
  161. }
  162. }
  163. impl fmt::Display for TimeExceeded {
  164. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  165. match *self {
  166. TimeExceeded::HopLimitExceeded => write!(f, "hop limit exceeded in transit"),
  167. TimeExceeded::FragReassemExceeded => write!(f, "fragment reassembly time exceeded"),
  168. TimeExceeded::Unknown(id) => write!(f, "{}", id),
  169. }
  170. }
  171. }
  172. /// A read/write wrapper around an Internet Control Message Protocol version 6 packet buffer.
  173. #[derive(Debug, PartialEq, Clone)]
  174. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  175. pub struct Packet<T: AsRef<[u8]>> {
  176. pub(super) buffer: T,
  177. }
  178. // Ranges and constants describing key boundaries in the ICMPv6 header.
  179. pub(super) mod field {
  180. use crate::wire::field::*;
  181. // ICMPv6: See https://tools.ietf.org/html/rfc4443
  182. pub const TYPE: usize = 0;
  183. pub const CODE: usize = 1;
  184. pub const CHECKSUM: Field = 2..4;
  185. pub const UNUSED: Field = 4..8;
  186. pub const MTU: Field = 4..8;
  187. pub const POINTER: Field = 4..8;
  188. pub const ECHO_IDENT: Field = 4..6;
  189. pub const ECHO_SEQNO: Field = 6..8;
  190. pub const HEADER_END: usize = 8;
  191. // NDISC: See https://tools.ietf.org/html/rfc4861
  192. // Router Advertisement message offsets
  193. pub const CUR_HOP_LIMIT: usize = 4;
  194. pub const ROUTER_FLAGS: usize = 5;
  195. pub const ROUTER_LT: Field = 6..8;
  196. pub const REACHABLE_TM: Field = 8..12;
  197. pub const RETRANS_TM: Field = 12..16;
  198. // Neighbor Solicitation message offsets
  199. pub const TARGET_ADDR: Field = 8..24;
  200. // Neighbor Advertisement message offsets
  201. pub const NEIGH_FLAGS: usize = 4;
  202. // Redirected Header message offsets
  203. pub const DEST_ADDR: Field = 24..40;
  204. // MLD:
  205. // - https://tools.ietf.org/html/rfc3810
  206. // - https://tools.ietf.org/html/rfc3810
  207. // Multicast Listener Query message
  208. pub const MAX_RESP_CODE: Field = 4..6;
  209. pub const QUERY_RESV: Field = 6..8;
  210. pub const QUERY_MCAST_ADDR: Field = 8..24;
  211. pub const SQRV: usize = 24;
  212. pub const QQIC: usize = 25;
  213. pub const QUERY_NUM_SRCS: Field = 26..28;
  214. // Multicast Listener Report Message
  215. pub const RECORD_RESV: Field = 4..6;
  216. pub const NR_MCAST_RCRDS: Field = 6..8;
  217. // Multicast Address Record Offsets
  218. pub const RECORD_TYPE: usize = 0;
  219. pub const AUX_DATA_LEN: usize = 1;
  220. pub const RECORD_NUM_SRCS: Field = 2..4;
  221. pub const RECORD_MCAST_ADDR: Field = 4..20;
  222. }
  223. impl<T: AsRef<[u8]>> Packet<T> {
  224. /// Imbue a raw octet buffer with ICMPv6 packet structure.
  225. pub fn new_unchecked(buffer: T) -> Packet<T> {
  226. Packet { buffer }
  227. }
  228. /// Shorthand for a combination of [new_unchecked] and [check_len].
  229. ///
  230. /// [new_unchecked]: #method.new_unchecked
  231. /// [check_len]: #method.check_len
  232. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  233. let packet = Self::new_unchecked(buffer);
  234. packet.check_len()?;
  235. Ok(packet)
  236. }
  237. /// Ensure that no accessor method will panic if called.
  238. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  239. pub fn check_len(&self) -> Result<()> {
  240. let len = self.buffer.as_ref().len();
  241. if len < field::HEADER_END || len < self.header_len() {
  242. Err(Error::Truncated)
  243. } else {
  244. Ok(())
  245. }
  246. }
  247. /// Consume the packet, returning the underlying buffer.
  248. pub fn into_inner(self) -> T {
  249. self.buffer
  250. }
  251. /// Return the message type field.
  252. #[inline]
  253. pub fn msg_type(&self) -> Message {
  254. let data = self.buffer.as_ref();
  255. Message::from(data[field::TYPE])
  256. }
  257. /// Return the message code field.
  258. #[inline]
  259. pub fn msg_code(&self) -> u8 {
  260. let data = self.buffer.as_ref();
  261. data[field::CODE]
  262. }
  263. /// Return the checksum field.
  264. #[inline]
  265. pub fn checksum(&self) -> u16 {
  266. let data = self.buffer.as_ref();
  267. NetworkEndian::read_u16(&data[field::CHECKSUM])
  268. }
  269. /// Return the identifier field (for echo request and reply packets).
  270. #[inline]
  271. pub fn echo_ident(&self) -> u16 {
  272. let data = self.buffer.as_ref();
  273. NetworkEndian::read_u16(&data[field::ECHO_IDENT])
  274. }
  275. /// Return the sequence number field (for echo request and reply packets).
  276. #[inline]
  277. pub fn echo_seq_no(&self) -> u16 {
  278. let data = self.buffer.as_ref();
  279. NetworkEndian::read_u16(&data[field::ECHO_SEQNO])
  280. }
  281. /// Return the MTU field (for packet too big messages).
  282. #[inline]
  283. pub fn pkt_too_big_mtu(&self) -> u32 {
  284. let data = self.buffer.as_ref();
  285. NetworkEndian::read_u32(&data[field::MTU])
  286. }
  287. /// Return the pointer field (for parameter problem messages).
  288. #[inline]
  289. pub fn param_problem_ptr(&self) -> u32 {
  290. let data = self.buffer.as_ref();
  291. NetworkEndian::read_u32(&data[field::POINTER])
  292. }
  293. /// Return the header length. The result depends on the value of
  294. /// the message type field.
  295. pub fn header_len(&self) -> usize {
  296. match self.msg_type() {
  297. Message::DstUnreachable => field::UNUSED.end,
  298. Message::PktTooBig => field::MTU.end,
  299. Message::TimeExceeded => field::UNUSED.end,
  300. Message::ParamProblem => field::POINTER.end,
  301. Message::EchoRequest => field::ECHO_SEQNO.end,
  302. Message::EchoReply => field::ECHO_SEQNO.end,
  303. Message::RouterSolicit => field::UNUSED.end,
  304. Message::RouterAdvert => field::RETRANS_TM.end,
  305. Message::NeighborSolicit => field::TARGET_ADDR.end,
  306. Message::NeighborAdvert => field::TARGET_ADDR.end,
  307. Message::Redirect => field::DEST_ADDR.end,
  308. Message::MldQuery => field::QUERY_NUM_SRCS.end,
  309. Message::MldReport => field::NR_MCAST_RCRDS.end,
  310. // For packets that are not included in RFC 4443, do not
  311. // include the last 32 bits of the ICMPv6 header in
  312. // `header_bytes`. This must be done so that these bytes
  313. // can be accessed in the `payload`.
  314. _ => field::CHECKSUM.end,
  315. }
  316. }
  317. /// Validate the header checksum.
  318. ///
  319. /// # Fuzzing
  320. /// This function always returns `true` when fuzzing.
  321. pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
  322. if cfg!(fuzzing) {
  323. return true;
  324. }
  325. let data = self.buffer.as_ref();
  326. checksum::combine(&[
  327. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6, data.len() as u32),
  328. checksum::data(data),
  329. ]) == !0
  330. }
  331. }
  332. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  333. /// Return a pointer to the type-specific data.
  334. #[inline]
  335. pub fn payload(&self) -> &'a [u8] {
  336. let data = self.buffer.as_ref();
  337. &data[self.header_len()..]
  338. }
  339. }
  340. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  341. /// Set the message type field.
  342. #[inline]
  343. pub fn set_msg_type(&mut self, value: Message) {
  344. let data = self.buffer.as_mut();
  345. data[field::TYPE] = value.into()
  346. }
  347. /// Set the message code field.
  348. #[inline]
  349. pub fn set_msg_code(&mut self, value: u8) {
  350. let data = self.buffer.as_mut();
  351. data[field::CODE] = value
  352. }
  353. /// Clear any reserved fields in the message header.
  354. ///
  355. /// # Panics
  356. /// This function panics if the message type has not been set.
  357. /// See [set_msg_type].
  358. ///
  359. /// [set_msg_type]: #method.set_msg_type
  360. #[inline]
  361. pub fn clear_reserved(&mut self) {
  362. match self.msg_type() {
  363. Message::RouterSolicit
  364. | Message::NeighborSolicit
  365. | Message::NeighborAdvert
  366. | Message::Redirect => {
  367. let data = self.buffer.as_mut();
  368. NetworkEndian::write_u32(&mut data[field::UNUSED], 0);
  369. }
  370. Message::MldQuery => {
  371. let data = self.buffer.as_mut();
  372. NetworkEndian::write_u16(&mut data[field::QUERY_RESV], 0);
  373. data[field::SQRV] &= 0xf;
  374. }
  375. Message::MldReport => {
  376. let data = self.buffer.as_mut();
  377. NetworkEndian::write_u16(&mut data[field::RECORD_RESV], 0);
  378. }
  379. ty => panic!("Message type `{}` does not have any reserved fields.", ty),
  380. }
  381. }
  382. #[inline]
  383. pub fn set_checksum(&mut self, value: u16) {
  384. let data = self.buffer.as_mut();
  385. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  386. }
  387. /// Set the identifier field (for echo request and reply packets).
  388. ///
  389. /// # Panics
  390. /// This function may panic if this packet is not an echo request or reply packet.
  391. #[inline]
  392. pub fn set_echo_ident(&mut self, value: u16) {
  393. let data = self.buffer.as_mut();
  394. NetworkEndian::write_u16(&mut data[field::ECHO_IDENT], value)
  395. }
  396. /// Set the sequence number field (for echo request and reply packets).
  397. ///
  398. /// # Panics
  399. /// This function may panic if this packet is not an echo request or reply packet.
  400. #[inline]
  401. pub fn set_echo_seq_no(&mut self, value: u16) {
  402. let data = self.buffer.as_mut();
  403. NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
  404. }
  405. /// Set the MTU field (for packet too big messages).
  406. ///
  407. /// # Panics
  408. /// This function may panic if this packet is not an packet too big packet.
  409. #[inline]
  410. pub fn set_pkt_too_big_mtu(&mut self, value: u32) {
  411. let data = self.buffer.as_mut();
  412. NetworkEndian::write_u32(&mut data[field::MTU], value)
  413. }
  414. /// Set the pointer field (for parameter problem messages).
  415. ///
  416. /// # Panics
  417. /// This function may panic if this packet is not a parameter problem message.
  418. #[inline]
  419. pub fn set_param_problem_ptr(&mut self, value: u32) {
  420. let data = self.buffer.as_mut();
  421. NetworkEndian::write_u32(&mut data[field::POINTER], value)
  422. }
  423. /// Compute and fill in the header checksum.
  424. pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) {
  425. self.set_checksum(0);
  426. let checksum = {
  427. let data = self.buffer.as_ref();
  428. !checksum::combine(&[
  429. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6, data.len() as u32),
  430. checksum::data(data),
  431. ])
  432. };
  433. self.set_checksum(checksum)
  434. }
  435. /// Return a mutable pointer to the type-specific data.
  436. #[inline]
  437. pub fn payload_mut(&mut self) -> &mut [u8] {
  438. let range = self.header_len()..;
  439. let data = self.buffer.as_mut();
  440. &mut data[range]
  441. }
  442. }
  443. impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
  444. fn as_ref(&self) -> &[u8] {
  445. self.buffer.as_ref()
  446. }
  447. }
  448. /// A high-level representation of an Internet Control Message Protocol version 6 packet header.
  449. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  450. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  451. #[non_exhaustive]
  452. pub enum Repr<'a> {
  453. DstUnreachable {
  454. reason: DstUnreachable,
  455. header: Ipv6Repr,
  456. data: &'a [u8],
  457. },
  458. PktTooBig {
  459. mtu: u32,
  460. header: Ipv6Repr,
  461. data: &'a [u8],
  462. },
  463. TimeExceeded {
  464. reason: TimeExceeded,
  465. header: Ipv6Repr,
  466. data: &'a [u8],
  467. },
  468. ParamProblem {
  469. reason: ParamProblem,
  470. pointer: u32,
  471. header: Ipv6Repr,
  472. data: &'a [u8],
  473. },
  474. EchoRequest {
  475. ident: u16,
  476. seq_no: u16,
  477. data: &'a [u8],
  478. },
  479. EchoReply {
  480. ident: u16,
  481. seq_no: u16,
  482. data: &'a [u8],
  483. },
  484. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  485. Ndisc(NdiscRepr<'a>),
  486. Mld(MldRepr<'a>),
  487. }
  488. impl<'a> Repr<'a> {
  489. /// Parse an Internet Control Message Protocol version 6 packet and return
  490. /// a high-level representation.
  491. pub fn parse<T>(
  492. src_addr: &IpAddress,
  493. dst_addr: &IpAddress,
  494. packet: &Packet<&'a T>,
  495. checksum_caps: &ChecksumCapabilities,
  496. ) -> Result<Repr<'a>>
  497. where
  498. T: AsRef<[u8]> + ?Sized,
  499. {
  500. fn create_packet_from_payload<'a, T>(packet: &Packet<&'a T>) -> Result<(&'a [u8], Ipv6Repr)>
  501. where
  502. T: AsRef<[u8]> + ?Sized,
  503. {
  504. let ip_packet = Ipv6Packet::new_checked(packet.payload())?;
  505. let payload = &packet.payload()[ip_packet.header_len() as usize..];
  506. if payload.len() < 8 {
  507. return Err(Error::Truncated);
  508. }
  509. let repr = Ipv6Repr {
  510. src_addr: ip_packet.src_addr(),
  511. dst_addr: ip_packet.dst_addr(),
  512. next_header: ip_packet.next_header(),
  513. payload_len: payload.len(),
  514. hop_limit: ip_packet.hop_limit(),
  515. };
  516. Ok((payload, repr))
  517. }
  518. // Valid checksum is expected.
  519. if checksum_caps.icmpv6.rx() && !packet.verify_checksum(src_addr, dst_addr) {
  520. return Err(Error::Checksum);
  521. }
  522. match (packet.msg_type(), packet.msg_code()) {
  523. (Message::DstUnreachable, code) => {
  524. let (payload, repr) = create_packet_from_payload(packet)?;
  525. Ok(Repr::DstUnreachable {
  526. reason: DstUnreachable::from(code),
  527. header: repr,
  528. data: payload,
  529. })
  530. }
  531. (Message::PktTooBig, 0) => {
  532. let (payload, repr) = create_packet_from_payload(packet)?;
  533. Ok(Repr::PktTooBig {
  534. mtu: packet.pkt_too_big_mtu(),
  535. header: repr,
  536. data: payload,
  537. })
  538. }
  539. (Message::TimeExceeded, code) => {
  540. let (payload, repr) = create_packet_from_payload(packet)?;
  541. Ok(Repr::TimeExceeded {
  542. reason: TimeExceeded::from(code),
  543. header: repr,
  544. data: payload,
  545. })
  546. }
  547. (Message::ParamProblem, code) => {
  548. let (payload, repr) = create_packet_from_payload(packet)?;
  549. Ok(Repr::ParamProblem {
  550. reason: ParamProblem::from(code),
  551. pointer: packet.param_problem_ptr(),
  552. header: repr,
  553. data: payload,
  554. })
  555. }
  556. (Message::EchoRequest, 0) => Ok(Repr::EchoRequest {
  557. ident: packet.echo_ident(),
  558. seq_no: packet.echo_seq_no(),
  559. data: packet.payload(),
  560. }),
  561. (Message::EchoReply, 0) => Ok(Repr::EchoReply {
  562. ident: packet.echo_ident(),
  563. seq_no: packet.echo_seq_no(),
  564. data: packet.payload(),
  565. }),
  566. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  567. (msg_type, 0) if msg_type.is_ndisc() => NdiscRepr::parse(packet).map(Repr::Ndisc),
  568. (msg_type, 0) if msg_type.is_mld() => MldRepr::parse(packet).map(Repr::Mld),
  569. _ => Err(Error::Unrecognized),
  570. }
  571. }
  572. /// Return the length of a packet that will be emitted from this high-level representation.
  573. pub fn buffer_len(&self) -> usize {
  574. match self {
  575. &Repr::DstUnreachable { header, data, .. }
  576. | &Repr::PktTooBig { header, data, .. }
  577. | &Repr::TimeExceeded { header, data, .. }
  578. | &Repr::ParamProblem { header, data, .. } => {
  579. field::UNUSED.end + header.buffer_len() + data.len()
  580. }
  581. &Repr::EchoRequest { data, .. } | &Repr::EchoReply { data, .. } => {
  582. field::ECHO_SEQNO.end + data.len()
  583. }
  584. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  585. &Repr::Ndisc(ndisc) => ndisc.buffer_len(),
  586. &Repr::Mld(mld) => mld.buffer_len(),
  587. }
  588. }
  589. /// Emit a high-level representation into an Internet Control Message Protocol version 6
  590. /// packet.
  591. pub fn emit<T>(
  592. &self,
  593. src_addr: &IpAddress,
  594. dst_addr: &IpAddress,
  595. packet: &mut Packet<&mut T>,
  596. checksum_caps: &ChecksumCapabilities,
  597. ) where
  598. T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
  599. {
  600. fn emit_contained_packet(buffer: &mut [u8], header: Ipv6Repr, data: &[u8]) {
  601. let mut ip_packet = Ipv6Packet::new_unchecked(buffer);
  602. header.emit(&mut ip_packet);
  603. let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
  604. payload.copy_from_slice(data);
  605. }
  606. match *self {
  607. Repr::DstUnreachable {
  608. reason,
  609. header,
  610. data,
  611. } => {
  612. packet.set_msg_type(Message::DstUnreachable);
  613. packet.set_msg_code(reason.into());
  614. emit_contained_packet(packet.payload_mut(), header, data);
  615. }
  616. Repr::PktTooBig { mtu, header, data } => {
  617. packet.set_msg_type(Message::PktTooBig);
  618. packet.set_msg_code(0);
  619. packet.set_pkt_too_big_mtu(mtu);
  620. emit_contained_packet(packet.payload_mut(), header, data);
  621. }
  622. Repr::TimeExceeded {
  623. reason,
  624. header,
  625. data,
  626. } => {
  627. packet.set_msg_type(Message::TimeExceeded);
  628. packet.set_msg_code(reason.into());
  629. emit_contained_packet(packet.payload_mut(), header, data);
  630. }
  631. Repr::ParamProblem {
  632. reason,
  633. pointer,
  634. header,
  635. data,
  636. } => {
  637. packet.set_msg_type(Message::ParamProblem);
  638. packet.set_msg_code(reason.into());
  639. packet.set_param_problem_ptr(pointer);
  640. emit_contained_packet(packet.payload_mut(), header, data);
  641. }
  642. Repr::EchoRequest {
  643. ident,
  644. seq_no,
  645. data,
  646. } => {
  647. packet.set_msg_type(Message::EchoRequest);
  648. packet.set_msg_code(0);
  649. packet.set_echo_ident(ident);
  650. packet.set_echo_seq_no(seq_no);
  651. let data_len = cmp::min(packet.payload_mut().len(), data.len());
  652. packet.payload_mut()[..data_len].copy_from_slice(&data[..data_len])
  653. }
  654. Repr::EchoReply {
  655. ident,
  656. seq_no,
  657. data,
  658. } => {
  659. packet.set_msg_type(Message::EchoReply);
  660. packet.set_msg_code(0);
  661. packet.set_echo_ident(ident);
  662. packet.set_echo_seq_no(seq_no);
  663. let data_len = cmp::min(packet.payload_mut().len(), data.len());
  664. packet.payload_mut()[..data_len].copy_from_slice(&data[..data_len])
  665. }
  666. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  667. Repr::Ndisc(ndisc) => ndisc.emit(packet),
  668. Repr::Mld(mld) => mld.emit(packet),
  669. }
  670. if checksum_caps.icmpv6.tx() {
  671. packet.fill_checksum(src_addr, dst_addr);
  672. } else {
  673. // make sure we get a consistently zeroed checksum, since implementations might rely on it
  674. packet.set_checksum(0);
  675. }
  676. }
  677. }
  678. #[cfg(test)]
  679. mod test {
  680. use super::*;
  681. use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
  682. use crate::wire::{IpProtocol, Ipv6Address, Ipv6Repr};
  683. static ECHO_PACKET_BYTES: [u8; 12] = [
  684. 0x80, 0x00, 0x19, 0xb3, 0x12, 0x34, 0xab, 0xcd, 0xaa, 0x00, 0x00, 0xff,
  685. ];
  686. static ECHO_PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
  687. static PKT_TOO_BIG_BYTES: [u8; 60] = [
  688. 0x02, 0x00, 0x0f, 0xc9, 0x00, 0x00, 0x05, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11,
  689. 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  690. 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  691. 0x00, 0x00, 0x02, 0xbf, 0x00, 0x00, 0x35, 0x00, 0x0c, 0x12, 0x4d, 0xaa, 0x00, 0x00, 0xff,
  692. ];
  693. static PKT_TOO_BIG_IP_PAYLOAD: [u8; 52] = [
  694. 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  695. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
  696. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xbf, 0x00, 0x00, 0x35, 0x00,
  697. 0x0c, 0x12, 0x4d, 0xaa, 0x00, 0x00, 0xff,
  698. ];
  699. static PKT_TOO_BIG_UDP_PAYLOAD: [u8; 12] = [
  700. 0xbf, 0x00, 0x00, 0x35, 0x00, 0x0c, 0x12, 0x4d, 0xaa, 0x00, 0x00, 0xff,
  701. ];
  702. fn echo_packet_repr() -> Repr<'static> {
  703. Repr::EchoRequest {
  704. ident: 0x1234,
  705. seq_no: 0xabcd,
  706. data: &ECHO_PACKET_PAYLOAD,
  707. }
  708. }
  709. fn too_big_packet_repr() -> Repr<'static> {
  710. Repr::PktTooBig {
  711. mtu: 1500,
  712. header: Ipv6Repr {
  713. src_addr: Ipv6Address([
  714. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  715. 0x00, 0x00, 0x01,
  716. ]),
  717. dst_addr: Ipv6Address([
  718. 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  719. 0x00, 0x00, 0x02,
  720. ]),
  721. next_header: IpProtocol::Udp,
  722. payload_len: 12,
  723. hop_limit: 0x40,
  724. },
  725. data: &PKT_TOO_BIG_UDP_PAYLOAD,
  726. }
  727. }
  728. #[test]
  729. fn test_echo_deconstruct() {
  730. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  731. assert_eq!(packet.msg_type(), Message::EchoRequest);
  732. assert_eq!(packet.msg_code(), 0);
  733. assert_eq!(packet.checksum(), 0x19b3);
  734. assert_eq!(packet.echo_ident(), 0x1234);
  735. assert_eq!(packet.echo_seq_no(), 0xabcd);
  736. assert_eq!(packet.payload(), &ECHO_PACKET_PAYLOAD[..]);
  737. assert!(packet.verify_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2));
  738. assert!(!packet.msg_type().is_error());
  739. }
  740. #[test]
  741. fn test_echo_construct() {
  742. let mut bytes = vec![0xa5; 12];
  743. let mut packet = Packet::new_unchecked(&mut bytes);
  744. packet.set_msg_type(Message::EchoRequest);
  745. packet.set_msg_code(0);
  746. packet.set_echo_ident(0x1234);
  747. packet.set_echo_seq_no(0xabcd);
  748. packet
  749. .payload_mut()
  750. .copy_from_slice(&ECHO_PACKET_PAYLOAD[..]);
  751. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  752. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  753. }
  754. #[test]
  755. fn test_echo_repr_parse() {
  756. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  757. let repr = Repr::parse(
  758. &MOCK_IP_ADDR_1,
  759. &MOCK_IP_ADDR_2,
  760. &packet,
  761. &ChecksumCapabilities::default(),
  762. )
  763. .unwrap();
  764. assert_eq!(repr, echo_packet_repr());
  765. }
  766. #[test]
  767. fn test_echo_emit() {
  768. let repr = echo_packet_repr();
  769. let mut bytes = vec![0xa5; repr.buffer_len()];
  770. let mut packet = Packet::new_unchecked(&mut bytes);
  771. repr.emit(
  772. &MOCK_IP_ADDR_1,
  773. &MOCK_IP_ADDR_2,
  774. &mut packet,
  775. &ChecksumCapabilities::default(),
  776. );
  777. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  778. }
  779. #[test]
  780. fn test_too_big_deconstruct() {
  781. let packet = Packet::new_unchecked(&PKT_TOO_BIG_BYTES[..]);
  782. assert_eq!(packet.msg_type(), Message::PktTooBig);
  783. assert_eq!(packet.msg_code(), 0);
  784. assert_eq!(packet.checksum(), 0x0fc9);
  785. assert_eq!(packet.pkt_too_big_mtu(), 1500);
  786. assert_eq!(packet.payload(), &PKT_TOO_BIG_IP_PAYLOAD[..]);
  787. assert!(packet.verify_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2));
  788. assert!(packet.msg_type().is_error());
  789. }
  790. #[test]
  791. fn test_too_big_construct() {
  792. let mut bytes = vec![0xa5; 60];
  793. let mut packet = Packet::new_unchecked(&mut bytes);
  794. packet.set_msg_type(Message::PktTooBig);
  795. packet.set_msg_code(0);
  796. packet.set_pkt_too_big_mtu(1500);
  797. packet
  798. .payload_mut()
  799. .copy_from_slice(&PKT_TOO_BIG_IP_PAYLOAD[..]);
  800. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  801. assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
  802. }
  803. #[test]
  804. fn test_too_big_repr_parse() {
  805. let packet = Packet::new_unchecked(&PKT_TOO_BIG_BYTES[..]);
  806. let repr = Repr::parse(
  807. &MOCK_IP_ADDR_1,
  808. &MOCK_IP_ADDR_2,
  809. &packet,
  810. &ChecksumCapabilities::default(),
  811. )
  812. .unwrap();
  813. assert_eq!(repr, too_big_packet_repr());
  814. }
  815. #[test]
  816. fn test_too_big_emit() {
  817. let repr = too_big_packet_repr();
  818. let mut bytes = vec![0xa5; repr.buffer_len()];
  819. let mut packet = Packet::new_unchecked(&mut bytes);
  820. repr.emit(
  821. &MOCK_IP_ADDR_1,
  822. &MOCK_IP_ADDR_2,
  823. &mut packet,
  824. &ChecksumCapabilities::default(),
  825. );
  826. assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
  827. }
  828. }