icmpv6.rs 34 KB

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