icmpv4.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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::{Ipv4Packet, Ipv4Repr};
  7. enum_with_unknown! {
  8. /// Internet protocol control message type.
  9. pub enum Message(u8) {
  10. /// Echo reply
  11. EchoReply = 0,
  12. /// Destination unreachable
  13. DstUnreachable = 3,
  14. /// Message redirect
  15. Redirect = 5,
  16. /// Echo request
  17. EchoRequest = 8,
  18. /// Router advertisement
  19. RouterAdvert = 9,
  20. /// Router solicitation
  21. RouterSolicit = 10,
  22. /// Time exceeded
  23. TimeExceeded = 11,
  24. /// Parameter problem
  25. ParamProblem = 12,
  26. /// Timestamp
  27. Timestamp = 13,
  28. /// Timestamp reply
  29. TimestampReply = 14
  30. }
  31. }
  32. impl fmt::Display for Message {
  33. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  34. match *self {
  35. Message::EchoReply => write!(f, "echo reply"),
  36. Message::DstUnreachable => write!(f, "destination unreachable"),
  37. Message::Redirect => write!(f, "message redirect"),
  38. Message::EchoRequest => write!(f, "echo request"),
  39. Message::RouterAdvert => write!(f, "router advertisement"),
  40. Message::RouterSolicit => write!(f, "router solicitation"),
  41. Message::TimeExceeded => write!(f, "time exceeded"),
  42. Message::ParamProblem => write!(f, "parameter problem"),
  43. Message::Timestamp => write!(f, "timestamp"),
  44. Message::TimestampReply => write!(f, "timestamp reply"),
  45. Message::Unknown(id) => write!(f, "{}", id),
  46. }
  47. }
  48. }
  49. enum_with_unknown! {
  50. /// Internet protocol control message subtype for type "Destination Unreachable".
  51. pub enum DstUnreachable(u8) {
  52. /// Destination network unreachable
  53. NetUnreachable = 0,
  54. /// Destination host unreachable
  55. HostUnreachable = 1,
  56. /// Destination protocol unreachable
  57. ProtoUnreachable = 2,
  58. /// Destination port unreachable
  59. PortUnreachable = 3,
  60. /// Fragmentation required, and DF flag set
  61. FragRequired = 4,
  62. /// Source route failed
  63. SrcRouteFailed = 5,
  64. /// Destination network unknown
  65. DstNetUnknown = 6,
  66. /// Destination host unknown
  67. DstHostUnknown = 7,
  68. /// Source host isolated
  69. SrcHostIsolated = 8,
  70. /// Network administratively prohibited
  71. NetProhibited = 9,
  72. /// Host administratively prohibited
  73. HostProhibited = 10,
  74. /// Network unreachable for ToS
  75. NetUnreachToS = 11,
  76. /// Host unreachable for ToS
  77. HostUnreachToS = 12,
  78. /// Communication administratively prohibited
  79. CommProhibited = 13,
  80. /// Host precedence violation
  81. HostPrecedViol = 14,
  82. /// Precedence cutoff in effect
  83. PrecedCutoff = 15
  84. }
  85. }
  86. impl fmt::Display for DstUnreachable {
  87. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  88. match *self {
  89. DstUnreachable::NetUnreachable => write!(f, "destination network unreachable"),
  90. DstUnreachable::HostUnreachable => write!(f, "destination host unreachable"),
  91. DstUnreachable::ProtoUnreachable => write!(f, "destination protocol unreachable"),
  92. DstUnreachable::PortUnreachable => write!(f, "destination port unreachable"),
  93. DstUnreachable::FragRequired => write!(f, "fragmentation required, and DF flag set"),
  94. DstUnreachable::SrcRouteFailed => write!(f, "source route failed"),
  95. DstUnreachable::DstNetUnknown => write!(f, "destination network unknown"),
  96. DstUnreachable::DstHostUnknown => write!(f, "destination host unknown"),
  97. DstUnreachable::SrcHostIsolated => write!(f, "source host isolated"),
  98. DstUnreachable::NetProhibited => write!(f, "network administratively prohibited"),
  99. DstUnreachable::HostProhibited => write!(f, "host administratively prohibited"),
  100. DstUnreachable::NetUnreachToS => write!(f, "network unreachable for ToS"),
  101. DstUnreachable::HostUnreachToS => write!(f, "host unreachable for ToS"),
  102. DstUnreachable::CommProhibited => {
  103. write!(f, "communication administratively prohibited")
  104. }
  105. DstUnreachable::HostPrecedViol => write!(f, "host precedence violation"),
  106. DstUnreachable::PrecedCutoff => write!(f, "precedence cutoff in effect"),
  107. DstUnreachable::Unknown(id) => write!(f, "{}", id),
  108. }
  109. }
  110. }
  111. enum_with_unknown! {
  112. /// Internet protocol control message subtype for type "Redirect Message".
  113. pub enum Redirect(u8) {
  114. /// Redirect Datagram for the Network
  115. Net = 0,
  116. /// Redirect Datagram for the Host
  117. Host = 1,
  118. /// Redirect Datagram for the ToS & network
  119. NetToS = 2,
  120. /// Redirect Datagram for the ToS & host
  121. HostToS = 3
  122. }
  123. }
  124. enum_with_unknown! {
  125. /// Internet protocol control message subtype for type "Time Exceeded".
  126. pub enum TimeExceeded(u8) {
  127. /// TTL expired in transit
  128. TtlExpired = 0,
  129. /// Fragment reassembly time exceeded
  130. FragExpired = 1
  131. }
  132. }
  133. impl fmt::Display for TimeExceeded {
  134. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  135. match *self {
  136. TimeExceeded::TtlExpired => write!(f, "time-to-live exceeded in transit"),
  137. TimeExceeded::FragExpired => write!(f, "fragment reassembly time exceeded"),
  138. TimeExceeded::Unknown(id) => write!(f, "{}", id),
  139. }
  140. }
  141. }
  142. enum_with_unknown! {
  143. /// Internet protocol control message subtype for type "Parameter Problem".
  144. pub enum ParamProblem(u8) {
  145. /// Pointer indicates the error
  146. AtPointer = 0,
  147. /// Missing a required option
  148. MissingOption = 1,
  149. /// Bad length
  150. BadLength = 2
  151. }
  152. }
  153. /// A read/write wrapper around an Internet Control Message Protocol version 4 packet buffer.
  154. #[derive(Debug, PartialEq, Eq, Clone)]
  155. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  156. pub struct Packet<T: AsRef<[u8]>> {
  157. buffer: T,
  158. }
  159. mod field {
  160. use crate::wire::field::*;
  161. pub const TYPE: usize = 0;
  162. pub const CODE: usize = 1;
  163. pub const CHECKSUM: Field = 2..4;
  164. pub const UNUSED: Field = 4..8;
  165. pub const ECHO_IDENT: Field = 4..6;
  166. pub const ECHO_SEQNO: Field = 6..8;
  167. pub const HEADER_END: usize = 8;
  168. }
  169. impl<T: AsRef<[u8]>> Packet<T> {
  170. /// Imbue a raw octet buffer with ICMPv4 packet structure.
  171. pub fn new_unchecked(buffer: T) -> Packet<T> {
  172. Packet { buffer }
  173. }
  174. /// Shorthand for a combination of [new_unchecked] and [check_len].
  175. ///
  176. /// [new_unchecked]: #method.new_unchecked
  177. /// [check_len]: #method.check_len
  178. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  179. let packet = Self::new_unchecked(buffer);
  180. packet.check_len()?;
  181. Ok(packet)
  182. }
  183. /// Ensure that no accessor method will panic if called.
  184. /// Returns `Err(Error)` if the buffer is too short.
  185. ///
  186. /// The result of this check is invalidated by calling [set_header_len].
  187. ///
  188. /// [set_header_len]: #method.set_header_len
  189. pub fn check_len(&self) -> Result<()> {
  190. let len = self.buffer.as_ref().len();
  191. if len < field::HEADER_END {
  192. Err(Error)
  193. } else {
  194. Ok(())
  195. }
  196. }
  197. /// Consume the packet, returning the underlying buffer.
  198. pub fn into_inner(self) -> T {
  199. self.buffer
  200. }
  201. /// Return the message type field.
  202. #[inline]
  203. pub fn msg_type(&self) -> Message {
  204. let data = self.buffer.as_ref();
  205. Message::from(data[field::TYPE])
  206. }
  207. /// Return the message code field.
  208. #[inline]
  209. pub fn msg_code(&self) -> u8 {
  210. let data = self.buffer.as_ref();
  211. data[field::CODE]
  212. }
  213. /// Return the checksum field.
  214. #[inline]
  215. pub fn checksum(&self) -> u16 {
  216. let data = self.buffer.as_ref();
  217. NetworkEndian::read_u16(&data[field::CHECKSUM])
  218. }
  219. /// Return the identifier field (for echo request and reply packets).
  220. ///
  221. /// # Panics
  222. /// This function may panic if this packet is not an echo request or reply packet.
  223. #[inline]
  224. pub fn echo_ident(&self) -> u16 {
  225. let data = self.buffer.as_ref();
  226. NetworkEndian::read_u16(&data[field::ECHO_IDENT])
  227. }
  228. /// Return the sequence number field (for echo request and reply packets).
  229. ///
  230. /// # Panics
  231. /// This function may panic if this packet is not an echo request or reply packet.
  232. #[inline]
  233. pub fn echo_seq_no(&self) -> u16 {
  234. let data = self.buffer.as_ref();
  235. NetworkEndian::read_u16(&data[field::ECHO_SEQNO])
  236. }
  237. /// Return the header length.
  238. /// The result depends on the value of the message type field.
  239. pub fn header_len(&self) -> usize {
  240. match self.msg_type() {
  241. Message::EchoRequest => field::ECHO_SEQNO.end,
  242. Message::EchoReply => field::ECHO_SEQNO.end,
  243. Message::DstUnreachable => field::UNUSED.end,
  244. _ => field::UNUSED.end, // make a conservative assumption
  245. }
  246. }
  247. /// Validate the header checksum.
  248. ///
  249. /// # Fuzzing
  250. /// This function always returns `true` when fuzzing.
  251. pub fn verify_checksum(&self) -> bool {
  252. if cfg!(fuzzing) {
  253. return true;
  254. }
  255. let data = self.buffer.as_ref();
  256. checksum::data(data) == !0
  257. }
  258. }
  259. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  260. /// Return a pointer to the type-specific data.
  261. #[inline]
  262. pub fn data(&self) -> &'a [u8] {
  263. let data = self.buffer.as_ref();
  264. &data[self.header_len()..]
  265. }
  266. }
  267. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  268. /// Set the message type field.
  269. #[inline]
  270. pub fn set_msg_type(&mut self, value: Message) {
  271. let data = self.buffer.as_mut();
  272. data[field::TYPE] = value.into()
  273. }
  274. /// Set the message code field.
  275. #[inline]
  276. pub fn set_msg_code(&mut self, value: u8) {
  277. let data = self.buffer.as_mut();
  278. data[field::CODE] = value
  279. }
  280. /// Set the checksum field.
  281. #[inline]
  282. pub fn set_checksum(&mut self, value: u16) {
  283. let data = self.buffer.as_mut();
  284. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  285. }
  286. /// Set the identifier field (for echo request and reply packets).
  287. ///
  288. /// # Panics
  289. /// This function may panic if this packet is not an echo request or reply packet.
  290. #[inline]
  291. pub fn set_echo_ident(&mut self, value: u16) {
  292. let data = self.buffer.as_mut();
  293. NetworkEndian::write_u16(&mut data[field::ECHO_IDENT], value)
  294. }
  295. /// Set the sequence number field (for echo request and reply packets).
  296. ///
  297. /// # Panics
  298. /// This function may panic if this packet is not an echo request or reply packet.
  299. #[inline]
  300. pub fn set_echo_seq_no(&mut self, value: u16) {
  301. let data = self.buffer.as_mut();
  302. NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
  303. }
  304. /// Compute and fill in the header checksum.
  305. pub fn fill_checksum(&mut self) {
  306. self.set_checksum(0);
  307. let checksum = {
  308. let data = self.buffer.as_ref();
  309. !checksum::data(data)
  310. };
  311. self.set_checksum(checksum)
  312. }
  313. }
  314. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
  315. /// Return a mutable pointer to the type-specific data.
  316. #[inline]
  317. pub fn data_mut(&mut self) -> &mut [u8] {
  318. let range = self.header_len()..;
  319. let data = self.buffer.as_mut();
  320. &mut data[range]
  321. }
  322. }
  323. impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
  324. fn as_ref(&self) -> &[u8] {
  325. self.buffer.as_ref()
  326. }
  327. }
  328. /// A high-level representation of an Internet Control Message Protocol version 4 packet header.
  329. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  330. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  331. #[non_exhaustive]
  332. pub enum Repr<'a> {
  333. EchoRequest {
  334. ident: u16,
  335. seq_no: u16,
  336. data: &'a [u8],
  337. },
  338. EchoReply {
  339. ident: u16,
  340. seq_no: u16,
  341. data: &'a [u8],
  342. },
  343. DstUnreachable {
  344. reason: DstUnreachable,
  345. header: Ipv4Repr,
  346. data: &'a [u8],
  347. },
  348. TimeExceeded {
  349. reason: TimeExceeded,
  350. header: Ipv4Repr,
  351. data: &'a [u8],
  352. },
  353. }
  354. impl<'a> Repr<'a> {
  355. /// Parse an Internet Control Message Protocol version 4 packet and return
  356. /// a high-level representation.
  357. pub fn parse<T>(
  358. packet: &Packet<&'a T>,
  359. checksum_caps: &ChecksumCapabilities,
  360. ) -> Result<Repr<'a>>
  361. where
  362. T: AsRef<[u8]> + ?Sized,
  363. {
  364. // Valid checksum is expected.
  365. if checksum_caps.icmpv4.rx() && !packet.verify_checksum() {
  366. return Err(Error);
  367. }
  368. match (packet.msg_type(), packet.msg_code()) {
  369. (Message::EchoRequest, 0) => Ok(Repr::EchoRequest {
  370. ident: packet.echo_ident(),
  371. seq_no: packet.echo_seq_no(),
  372. data: packet.data(),
  373. }),
  374. (Message::EchoReply, 0) => Ok(Repr::EchoReply {
  375. ident: packet.echo_ident(),
  376. seq_no: packet.echo_seq_no(),
  377. data: packet.data(),
  378. }),
  379. (Message::DstUnreachable, code) => {
  380. let ip_packet = Ipv4Packet::new_checked(packet.data())?;
  381. let payload = &packet.data()[ip_packet.header_len() as usize..];
  382. // RFC 792 requires exactly eight bytes to be returned.
  383. // We allow more, since there isn't a reason not to, but require at least eight.
  384. if payload.len() < 8 {
  385. return Err(Error);
  386. }
  387. Ok(Repr::DstUnreachable {
  388. reason: DstUnreachable::from(code),
  389. header: Ipv4Repr {
  390. src_addr: ip_packet.src_addr(),
  391. dst_addr: ip_packet.dst_addr(),
  392. next_header: ip_packet.next_header(),
  393. payload_len: payload.len(),
  394. hop_limit: ip_packet.hop_limit(),
  395. },
  396. data: payload,
  397. })
  398. }
  399. (Message::TimeExceeded, code) => {
  400. let ip_packet = Ipv4Packet::new_checked(packet.data())?;
  401. let payload = &packet.data()[ip_packet.header_len() as usize..];
  402. // RFC 792 requires exactly eight bytes to be returned.
  403. // We allow more, since there isn't a reason not to, but require at least eight.
  404. if payload.len() < 8 {
  405. return Err(Error);
  406. }
  407. Ok(Repr::TimeExceeded {
  408. reason: TimeExceeded::from(code),
  409. header: Ipv4Repr {
  410. src_addr: ip_packet.src_addr(),
  411. dst_addr: ip_packet.dst_addr(),
  412. next_header: ip_packet.next_header(),
  413. payload_len: payload.len(),
  414. hop_limit: ip_packet.hop_limit(),
  415. },
  416. data: payload,
  417. })
  418. }
  419. _ => Err(Error),
  420. }
  421. }
  422. /// Return the length of a packet that will be emitted from this high-level representation.
  423. pub fn buffer_len(&self) -> usize {
  424. match self {
  425. &Repr::EchoRequest { data, .. } | &Repr::EchoReply { data, .. } => {
  426. field::ECHO_SEQNO.end + data.len()
  427. }
  428. &Repr::DstUnreachable { header, data, .. }
  429. | &Repr::TimeExceeded { header, data, .. } => {
  430. field::UNUSED.end + header.buffer_len() + data.len()
  431. }
  432. }
  433. }
  434. /// Emit a high-level representation into an Internet Control Message Protocol version 4
  435. /// packet.
  436. pub fn emit<T>(&self, packet: &mut Packet<&mut T>, checksum_caps: &ChecksumCapabilities)
  437. where
  438. T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
  439. {
  440. packet.set_msg_code(0);
  441. match *self {
  442. Repr::EchoRequest {
  443. ident,
  444. seq_no,
  445. data,
  446. } => {
  447. packet.set_msg_type(Message::EchoRequest);
  448. packet.set_msg_code(0);
  449. packet.set_echo_ident(ident);
  450. packet.set_echo_seq_no(seq_no);
  451. let data_len = cmp::min(packet.data_mut().len(), data.len());
  452. packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
  453. }
  454. Repr::EchoReply {
  455. ident,
  456. seq_no,
  457. data,
  458. } => {
  459. packet.set_msg_type(Message::EchoReply);
  460. packet.set_msg_code(0);
  461. packet.set_echo_ident(ident);
  462. packet.set_echo_seq_no(seq_no);
  463. let data_len = cmp::min(packet.data_mut().len(), data.len());
  464. packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
  465. }
  466. Repr::DstUnreachable {
  467. reason,
  468. header,
  469. data,
  470. } => {
  471. packet.set_msg_type(Message::DstUnreachable);
  472. packet.set_msg_code(reason.into());
  473. let mut ip_packet = Ipv4Packet::new_unchecked(packet.data_mut());
  474. header.emit(&mut ip_packet, checksum_caps);
  475. let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
  476. payload.copy_from_slice(data)
  477. }
  478. Repr::TimeExceeded {
  479. reason,
  480. header,
  481. data,
  482. } => {
  483. packet.set_msg_type(Message::TimeExceeded);
  484. packet.set_msg_code(reason.into());
  485. let mut ip_packet = Ipv4Packet::new_unchecked(packet.data_mut());
  486. header.emit(&mut ip_packet, checksum_caps);
  487. let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
  488. payload.copy_from_slice(data)
  489. }
  490. }
  491. if checksum_caps.icmpv4.tx() {
  492. packet.fill_checksum()
  493. } else {
  494. // make sure we get a consistently zeroed checksum,
  495. // since implementations might rely on it
  496. packet.set_checksum(0);
  497. }
  498. }
  499. }
  500. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
  501. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  502. match Repr::parse(self, &ChecksumCapabilities::default()) {
  503. Ok(repr) => write!(f, "{}", repr),
  504. Err(err) => {
  505. write!(f, "ICMPv4 ({})", err)?;
  506. write!(f, " type={:?}", self.msg_type())?;
  507. match self.msg_type() {
  508. Message::DstUnreachable => {
  509. write!(f, " code={:?}", DstUnreachable::from(self.msg_code()))
  510. }
  511. Message::TimeExceeded => {
  512. write!(f, " code={:?}", TimeExceeded::from(self.msg_code()))
  513. }
  514. _ => write!(f, " code={}", self.msg_code()),
  515. }
  516. }
  517. }
  518. }
  519. }
  520. impl<'a> fmt::Display for Repr<'a> {
  521. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  522. match *self {
  523. Repr::EchoRequest {
  524. ident,
  525. seq_no,
  526. data,
  527. } => write!(
  528. f,
  529. "ICMPv4 echo request id={} seq={} len={}",
  530. ident,
  531. seq_no,
  532. data.len()
  533. ),
  534. Repr::EchoReply {
  535. ident,
  536. seq_no,
  537. data,
  538. } => write!(
  539. f,
  540. "ICMPv4 echo reply id={} seq={} len={}",
  541. ident,
  542. seq_no,
  543. data.len()
  544. ),
  545. Repr::DstUnreachable { reason, .. } => {
  546. write!(f, "ICMPv4 destination unreachable ({})", reason)
  547. }
  548. Repr::TimeExceeded { reason, .. } => {
  549. write!(f, "ICMPv4 time exceeded ({})", reason)
  550. }
  551. }
  552. }
  553. }
  554. use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
  555. impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
  556. fn pretty_print(
  557. buffer: &dyn AsRef<[u8]>,
  558. f: &mut fmt::Formatter,
  559. indent: &mut PrettyIndent,
  560. ) -> fmt::Result {
  561. let packet = match Packet::new_checked(buffer) {
  562. Err(err) => return write!(f, "{}({})", indent, err),
  563. Ok(packet) => packet,
  564. };
  565. write!(f, "{}{}", indent, packet)?;
  566. match packet.msg_type() {
  567. Message::DstUnreachable | Message::TimeExceeded => {
  568. indent.increase(f)?;
  569. super::Ipv4Packet::<&[u8]>::pretty_print(&packet.data(), f, indent)
  570. }
  571. _ => Ok(()),
  572. }
  573. }
  574. }
  575. #[cfg(test)]
  576. mod test {
  577. use super::*;
  578. static ECHO_PACKET_BYTES: [u8; 12] = [
  579. 0x08, 0x00, 0x8e, 0xfe, 0x12, 0x34, 0xab, 0xcd, 0xaa, 0x00, 0x00, 0xff,
  580. ];
  581. static ECHO_DATA_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
  582. #[test]
  583. fn test_echo_deconstruct() {
  584. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  585. assert_eq!(packet.msg_type(), Message::EchoRequest);
  586. assert_eq!(packet.msg_code(), 0);
  587. assert_eq!(packet.checksum(), 0x8efe);
  588. assert_eq!(packet.echo_ident(), 0x1234);
  589. assert_eq!(packet.echo_seq_no(), 0xabcd);
  590. assert_eq!(packet.data(), &ECHO_DATA_BYTES[..]);
  591. assert!(packet.verify_checksum());
  592. }
  593. #[test]
  594. fn test_echo_construct() {
  595. let mut bytes = vec![0xa5; 12];
  596. let mut packet = Packet::new_unchecked(&mut bytes);
  597. packet.set_msg_type(Message::EchoRequest);
  598. packet.set_msg_code(0);
  599. packet.set_echo_ident(0x1234);
  600. packet.set_echo_seq_no(0xabcd);
  601. packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
  602. packet.fill_checksum();
  603. assert_eq!(&*packet.into_inner(), &ECHO_PACKET_BYTES[..]);
  604. }
  605. fn echo_packet_repr() -> Repr<'static> {
  606. Repr::EchoRequest {
  607. ident: 0x1234,
  608. seq_no: 0xabcd,
  609. data: &ECHO_DATA_BYTES,
  610. }
  611. }
  612. #[test]
  613. fn test_echo_parse() {
  614. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  615. let repr = Repr::parse(&packet, &ChecksumCapabilities::default()).unwrap();
  616. assert_eq!(repr, echo_packet_repr());
  617. }
  618. #[test]
  619. fn test_echo_emit() {
  620. let repr = echo_packet_repr();
  621. let mut bytes = vec![0xa5; repr.buffer_len()];
  622. let mut packet = Packet::new_unchecked(&mut bytes);
  623. repr.emit(&mut packet, &ChecksumCapabilities::default());
  624. assert_eq!(&*packet.into_inner(), &ECHO_PACKET_BYTES[..]);
  625. }
  626. #[test]
  627. fn test_check_len() {
  628. let bytes = [0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
  629. assert_eq!(Packet::new_checked(&[]), Err(Error));
  630. assert_eq!(Packet::new_checked(&bytes[..4]), Err(Error));
  631. assert!(Packet::new_checked(&bytes[..]).is_ok());
  632. }
  633. }