ndisc.rs 20 KB

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