nhc.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. //! Implementation of Next Header Compression from [RFC 6282 § 4].
  2. //!
  3. //! [RFC 6282 § 4]: https://datatracker.ietf.org/doc/html/rfc6282#section-4
  4. use super::{Error, NextHeader, Result, DISPATCH_EXT_HEADER, DISPATCH_UDP_HEADER};
  5. use crate::{
  6. phy::ChecksumCapabilities,
  7. wire::{ip::checksum, ipv6, udp::Repr as UdpRepr, IpProtocol},
  8. };
  9. use byteorder::{ByteOrder, NetworkEndian};
  10. use ipv6::Address;
  11. macro_rules! get_field {
  12. ($name:ident, $mask:expr, $shift:expr) => {
  13. fn $name(&self) -> u8 {
  14. let data = self.buffer.as_ref();
  15. let raw = &data[0];
  16. ((raw >> $shift) & $mask) as u8
  17. }
  18. };
  19. }
  20. macro_rules! set_field {
  21. ($name:ident, $mask:expr, $shift:expr) => {
  22. fn $name(&mut self, val: u8) {
  23. let data = self.buffer.as_mut();
  24. let mut raw = data[0];
  25. raw = (raw & !($mask << $shift)) | (val << $shift);
  26. data[0] = raw;
  27. }
  28. };
  29. }
  30. #[derive(Debug, Clone)]
  31. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  32. /// A read/write wrapper around a 6LoWPAN_NHC Header.
  33. /// [RFC 6282 § 4.2] specifies the format of the header.
  34. ///
  35. /// The header has the following format:
  36. /// ```txt
  37. /// 0 1 2 3 4 5 6 7
  38. /// +---+---+---+---+---+---+---+---+
  39. /// | 1 | 1 | 1 | 0 | EID |NH |
  40. /// +---+---+---+---+---+---+---+---+
  41. /// ```
  42. ///
  43. /// With:
  44. /// - EID: the extension header ID
  45. /// - NH: Next Header
  46. ///
  47. /// [RFC 6282 § 4.2]: https://datatracker.ietf.org/doc/html/rfc6282#section-4.2
  48. pub enum NhcPacket {
  49. ExtHeader,
  50. UdpHeader,
  51. }
  52. impl NhcPacket {
  53. /// Returns the type of the Next Header header.
  54. /// This can either be an Extension header or an 6LoWPAN Udp header.
  55. ///
  56. /// # Errors
  57. /// Returns `[Error::Unrecognized]` when neither the Extension Header dispatch or the Udp
  58. /// dispatch is recognized.
  59. pub fn dispatch(buffer: impl AsRef<[u8]>) -> Result<Self> {
  60. let raw = buffer.as_ref();
  61. if raw.is_empty() {
  62. return Err(Error);
  63. }
  64. if raw[0] >> 4 == DISPATCH_EXT_HEADER {
  65. // We have a compressed IPv6 Extension Header.
  66. Ok(Self::ExtHeader)
  67. } else if raw[0] >> 3 == DISPATCH_UDP_HEADER {
  68. // We have a compressed UDP header.
  69. Ok(Self::UdpHeader)
  70. } else {
  71. Err(Error)
  72. }
  73. }
  74. }
  75. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  76. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  77. pub enum ExtHeaderId {
  78. HopByHopHeader,
  79. RoutingHeader,
  80. FragmentHeader,
  81. DestinationOptionsHeader,
  82. MobilityHeader,
  83. Header,
  84. Reserved,
  85. }
  86. impl From<ExtHeaderId> for IpProtocol {
  87. fn from(val: ExtHeaderId) -> Self {
  88. match val {
  89. ExtHeaderId::HopByHopHeader => Self::HopByHop,
  90. ExtHeaderId::RoutingHeader => Self::Ipv6Route,
  91. ExtHeaderId::FragmentHeader => Self::Ipv6Frag,
  92. ExtHeaderId::DestinationOptionsHeader => Self::Ipv6Opts,
  93. ExtHeaderId::MobilityHeader => Self::Unknown(0),
  94. ExtHeaderId::Header => Self::Unknown(0),
  95. ExtHeaderId::Reserved => Self::Unknown(0),
  96. }
  97. }
  98. }
  99. /// A read/write wrapper around a 6LoWPAN NHC Extension header.
  100. #[derive(Debug, Clone)]
  101. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  102. pub struct ExtHeaderPacket<T: AsRef<[u8]>> {
  103. buffer: T,
  104. }
  105. impl<T: AsRef<[u8]>> ExtHeaderPacket<T> {
  106. /// Input a raw octet buffer with a 6LoWPAN NHC Extension Header structure.
  107. pub const fn new_unchecked(buffer: T) -> Self {
  108. ExtHeaderPacket { buffer }
  109. }
  110. /// Shorthand for a combination of [new_unchecked] and [check_len].
  111. ///
  112. /// [new_unchecked]: #method.new_unchecked
  113. /// [check_len]: #method.check_len
  114. pub fn new_checked(buffer: T) -> Result<Self> {
  115. let packet = Self::new_unchecked(buffer);
  116. packet.check_len()?;
  117. if packet.eid_field() > 7 {
  118. return Err(Error);
  119. }
  120. Ok(packet)
  121. }
  122. /// Ensure that no accessor method will panic if called.
  123. /// Returns `Err(Error)` if the buffer is too short.
  124. pub fn check_len(&self) -> Result<()> {
  125. let buffer = self.buffer.as_ref();
  126. if buffer.is_empty() {
  127. return Err(Error);
  128. }
  129. let mut len = 2;
  130. len += self.next_header_size();
  131. if len <= buffer.len() {
  132. Ok(())
  133. } else {
  134. Err(Error)
  135. }
  136. }
  137. /// Consumes the frame, returning the underlying buffer.
  138. pub fn into_inner(self) -> T {
  139. self.buffer
  140. }
  141. get_field!(dispatch_field, 0b1111, 4);
  142. get_field!(eid_field, 0b111, 1);
  143. get_field!(nh_field, 0b1, 0);
  144. /// Return the Extension Header ID.
  145. pub fn extension_header_id(&self) -> ExtHeaderId {
  146. match self.eid_field() {
  147. 0 => ExtHeaderId::HopByHopHeader,
  148. 1 => ExtHeaderId::RoutingHeader,
  149. 2 => ExtHeaderId::FragmentHeader,
  150. 3 => ExtHeaderId::DestinationOptionsHeader,
  151. 4 => ExtHeaderId::MobilityHeader,
  152. 5 | 6 => ExtHeaderId::Reserved,
  153. 7 => ExtHeaderId::Header,
  154. _ => unreachable!(),
  155. }
  156. }
  157. /// Return the length field.
  158. pub fn length(&self) -> u8 {
  159. self.buffer.as_ref()[1 + self.next_header_size()]
  160. }
  161. /// Parse the next header field.
  162. pub fn next_header(&self) -> NextHeader {
  163. if self.nh_field() == 1 {
  164. NextHeader::Compressed
  165. } else {
  166. // The full 8 bits for Next Header are carried in-line.
  167. NextHeader::Uncompressed(IpProtocol::from(self.buffer.as_ref()[1]))
  168. }
  169. }
  170. /// Return the size of the Next Header field.
  171. fn next_header_size(&self) -> usize {
  172. // If nh is set, then the Next Header is compressed using LOWPAN_NHC
  173. match self.nh_field() {
  174. 0 => 1,
  175. 1 => 0,
  176. _ => unreachable!(),
  177. }
  178. }
  179. }
  180. impl<'a, T: AsRef<[u8]> + ?Sized> ExtHeaderPacket<&'a T> {
  181. /// Return a pointer to the payload.
  182. pub fn payload(&self) -> &'a [u8] {
  183. let start = 2 + self.next_header_size();
  184. let len = self.length() as usize;
  185. &self.buffer.as_ref()[start..][..len]
  186. }
  187. }
  188. impl<T: AsRef<[u8]> + AsMut<[u8]>> ExtHeaderPacket<T> {
  189. /// Return a mutable pointer to the payload.
  190. pub fn payload_mut(&mut self) -> &mut [u8] {
  191. let start = 2 + self.next_header_size();
  192. let len = self.length() as usize;
  193. &mut self.buffer.as_mut()[start..][..len]
  194. }
  195. /// Set the dispatch field to `0b1110`.
  196. fn set_dispatch_field(&mut self) {
  197. let data = self.buffer.as_mut();
  198. data[0] = (data[0] & !(0b1111 << 4)) | (DISPATCH_EXT_HEADER << 4);
  199. }
  200. set_field!(set_eid_field, 0b111, 1);
  201. set_field!(set_nh_field, 0b1, 0);
  202. /// Set the Extension Header ID field.
  203. fn set_extension_header_id(&mut self, ext_header_id: ExtHeaderId) {
  204. let id = match ext_header_id {
  205. ExtHeaderId::HopByHopHeader => 0,
  206. ExtHeaderId::RoutingHeader => 1,
  207. ExtHeaderId::FragmentHeader => 2,
  208. ExtHeaderId::DestinationOptionsHeader => 3,
  209. ExtHeaderId::MobilityHeader => 4,
  210. ExtHeaderId::Reserved => 5,
  211. ExtHeaderId::Header => 7,
  212. };
  213. self.set_eid_field(id);
  214. }
  215. /// Set the Next Header.
  216. fn set_next_header(&mut self, next_header: NextHeader) {
  217. match next_header {
  218. NextHeader::Compressed => self.set_nh_field(0b1),
  219. NextHeader::Uncompressed(nh) => {
  220. self.set_nh_field(0b0);
  221. let start = 1;
  222. let data = self.buffer.as_mut();
  223. data[start] = nh.into();
  224. }
  225. }
  226. }
  227. /// Set the length.
  228. fn set_length(&mut self, length: u8) {
  229. let start = 1 + self.next_header_size();
  230. let data = self.buffer.as_mut();
  231. data[start] = length;
  232. }
  233. }
  234. /// A high-level representation of an 6LoWPAN NHC Extension header.
  235. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  236. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  237. pub struct ExtHeaderRepr {
  238. pub ext_header_id: ExtHeaderId,
  239. pub next_header: NextHeader,
  240. pub length: u8,
  241. }
  242. impl ExtHeaderRepr {
  243. /// Parse a 6LoWPAN NHC Extension Header packet and return a high-level representation.
  244. pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &ExtHeaderPacket<&T>) -> Result<Self> {
  245. // Ensure basic accessors will work.
  246. packet.check_len()?;
  247. if packet.dispatch_field() != DISPATCH_EXT_HEADER {
  248. return Err(Error);
  249. }
  250. Ok(Self {
  251. ext_header_id: packet.extension_header_id(),
  252. next_header: packet.next_header(),
  253. length: packet.length(),
  254. })
  255. }
  256. /// Return the length of a header that will be emitted from this high-level representation.
  257. pub fn buffer_len(&self) -> usize {
  258. let mut len = 1; // The minimal header size
  259. if self.next_header != NextHeader::Compressed {
  260. len += 1;
  261. }
  262. len += 1; // The length
  263. len
  264. }
  265. /// Emit a high-level representation into a 6LoWPAN NHC Extension Header packet.
  266. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut ExtHeaderPacket<T>) {
  267. packet.set_dispatch_field();
  268. packet.set_extension_header_id(self.ext_header_id);
  269. packet.set_next_header(self.next_header);
  270. packet.set_length(self.length);
  271. }
  272. }
  273. #[cfg(test)]
  274. mod tests {
  275. use super::*;
  276. use crate::wire::{Ipv6RoutingHeader, Ipv6RoutingRepr};
  277. #[cfg(feature = "proto-rpl")]
  278. use crate::wire::{
  279. Ipv6Option, Ipv6OptionRepr, Ipv6OptionsIterator, RplHopByHopRepr, RplInstanceId,
  280. };
  281. #[cfg(feature = "proto-rpl")]
  282. const RPL_HOP_BY_HOP_PACKET: [u8; 9] = [0xe0, 0x3a, 0x06, 0x63, 0x04, 0x00, 0x1e, 0x03, 0x00];
  283. const ROUTING_SR_PACKET: [u8; 32] = [
  284. 0xe3, 0x1e, 0x03, 0x03, 0x99, 0x30, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
  285. 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
  286. 0x00, 0x00,
  287. ];
  288. #[test]
  289. #[cfg(feature = "proto-rpl")]
  290. fn test_rpl_hop_by_hop_option_deconstruct() {
  291. let header = ExtHeaderPacket::new_checked(&RPL_HOP_BY_HOP_PACKET).unwrap();
  292. assert_eq!(
  293. header.next_header(),
  294. NextHeader::Uncompressed(IpProtocol::Icmpv6)
  295. );
  296. assert_eq!(header.extension_header_id(), ExtHeaderId::HopByHopHeader);
  297. let options = header.payload();
  298. let mut options = Ipv6OptionsIterator::new(options);
  299. let rpl_repr = options.next().unwrap();
  300. let rpl_repr = rpl_repr.unwrap();
  301. match rpl_repr {
  302. Ipv6OptionRepr::Rpl(rpl) => {
  303. assert_eq!(
  304. rpl,
  305. RplHopByHopRepr {
  306. down: false,
  307. rank_error: false,
  308. forwarding_error: false,
  309. instance_id: RplInstanceId::from(0x1e),
  310. sender_rank: 0x0300,
  311. }
  312. );
  313. }
  314. _ => unreachable!(),
  315. }
  316. }
  317. #[test]
  318. #[cfg(feature = "proto-rpl")]
  319. fn test_rpl_hop_by_hop_option_emit() {
  320. let repr = Ipv6OptionRepr::Rpl(RplHopByHopRepr {
  321. down: false,
  322. rank_error: false,
  323. forwarding_error: false,
  324. instance_id: RplInstanceId::from(0x1e),
  325. sender_rank: 0x0300,
  326. });
  327. let ext_hdr = ExtHeaderRepr {
  328. ext_header_id: ExtHeaderId::HopByHopHeader,
  329. next_header: NextHeader::Uncompressed(IpProtocol::Icmpv6),
  330. length: repr.buffer_len() as u8,
  331. };
  332. let mut buffer = vec![0u8; ext_hdr.buffer_len() + repr.buffer_len()];
  333. ext_hdr.emit(&mut ExtHeaderPacket::new_unchecked(
  334. &mut buffer[..ext_hdr.buffer_len()],
  335. ));
  336. repr.emit(&mut Ipv6Option::new_unchecked(
  337. &mut buffer[ext_hdr.buffer_len()..],
  338. ));
  339. assert_eq!(&buffer[..], RPL_HOP_BY_HOP_PACKET);
  340. }
  341. #[test]
  342. fn test_source_routing_deconstruct() {
  343. let header = ExtHeaderPacket::new_checked(&ROUTING_SR_PACKET).unwrap();
  344. assert_eq!(header.next_header(), NextHeader::Compressed);
  345. assert_eq!(header.extension_header_id(), ExtHeaderId::RoutingHeader);
  346. let routing_hdr = Ipv6RoutingHeader::new_checked(header.payload()).unwrap();
  347. let repr = Ipv6RoutingRepr::parse(&routing_hdr).unwrap();
  348. assert_eq!(
  349. repr,
  350. Ipv6RoutingRepr::Rpl {
  351. segments_left: 3,
  352. cmpr_i: 9,
  353. cmpr_e: 9,
  354. pad: 3,
  355. addresses: &[
  356. 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00,
  357. 0x06, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00
  358. ],
  359. }
  360. );
  361. }
  362. #[test]
  363. fn test_source_routing_emit() {
  364. let routing_hdr = Ipv6RoutingRepr::Rpl {
  365. segments_left: 3,
  366. cmpr_i: 9,
  367. cmpr_e: 9,
  368. pad: 3,
  369. addresses: &[
  370. 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06,
  371. 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
  372. ],
  373. };
  374. let ext_hdr = ExtHeaderRepr {
  375. ext_header_id: ExtHeaderId::RoutingHeader,
  376. next_header: NextHeader::Compressed,
  377. length: routing_hdr.buffer_len() as u8,
  378. };
  379. let mut buffer = vec![0u8; ext_hdr.buffer_len() + routing_hdr.buffer_len()];
  380. ext_hdr.emit(&mut ExtHeaderPacket::new_unchecked(
  381. &mut buffer[..ext_hdr.buffer_len()],
  382. ));
  383. routing_hdr.emit(&mut Ipv6RoutingHeader::new_unchecked(
  384. &mut buffer[ext_hdr.buffer_len()..],
  385. ));
  386. assert_eq!(&buffer[..], ROUTING_SR_PACKET);
  387. }
  388. }
  389. /// A read/write wrapper around a 6LoWPAN_NHC UDP frame.
  390. /// [RFC 6282 § 4.3] specifies the format of the header.
  391. ///
  392. /// The base header has the following format:
  393. /// ```txt
  394. /// 0 1 2 3 4 5 6 7
  395. /// +---+---+---+---+---+---+---+---+
  396. /// | 1 | 1 | 1 | 1 | 0 | C | P |
  397. /// +---+---+---+---+---+---+---+---+
  398. /// With:
  399. /// - C: checksum, specifies if the checksum is elided.
  400. /// - P: ports, specifies if the ports are elided.
  401. /// ```
  402. ///
  403. /// [RFC 6282 § 4.3]: https://datatracker.ietf.org/doc/html/rfc6282#section-4.3
  404. #[derive(Debug, Clone)]
  405. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  406. pub struct UdpNhcPacket<T: AsRef<[u8]>> {
  407. buffer: T,
  408. }
  409. impl<T: AsRef<[u8]>> UdpNhcPacket<T> {
  410. /// Input a raw octet buffer with a LOWPAN_NHC frame structure for UDP.
  411. pub const fn new_unchecked(buffer: T) -> Self {
  412. Self { buffer }
  413. }
  414. /// Shorthand for a combination of [new_unchecked] and [check_len].
  415. ///
  416. /// [new_unchecked]: #method.new_unchecked
  417. /// [check_len]: #method.check_len
  418. pub fn new_checked(buffer: T) -> Result<Self> {
  419. let packet = Self::new_unchecked(buffer);
  420. packet.check_len()?;
  421. Ok(packet)
  422. }
  423. /// Ensure that no accessor method will panic if called.
  424. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  425. pub fn check_len(&self) -> Result<()> {
  426. let buffer = self.buffer.as_ref();
  427. if buffer.is_empty() {
  428. return Err(Error);
  429. }
  430. let index = 1 + self.ports_size() + self.checksum_size();
  431. if index > buffer.len() {
  432. return Err(Error);
  433. }
  434. Ok(())
  435. }
  436. /// Consumes the frame, returning the underlying buffer.
  437. pub fn into_inner(self) -> T {
  438. self.buffer
  439. }
  440. get_field!(dispatch_field, 0b11111, 3);
  441. get_field!(checksum_field, 0b1, 2);
  442. get_field!(ports_field, 0b11, 0);
  443. /// Returns the index of the start of the next header compressed fields.
  444. const fn nhc_fields_start(&self) -> usize {
  445. 1
  446. }
  447. /// Return the source port number.
  448. pub fn src_port(&self) -> u16 {
  449. match self.ports_field() {
  450. 0b00 | 0b01 => {
  451. // The full 16 bits are carried in-line.
  452. let data = self.buffer.as_ref();
  453. let start = self.nhc_fields_start();
  454. NetworkEndian::read_u16(&data[start..start + 2])
  455. }
  456. 0b10 => {
  457. // The first 8 bits are elided.
  458. let data = self.buffer.as_ref();
  459. let start = self.nhc_fields_start();
  460. 0xf000 + data[start] as u16
  461. }
  462. 0b11 => {
  463. // The first 12 bits are elided.
  464. let data = self.buffer.as_ref();
  465. let start = self.nhc_fields_start();
  466. 0xf0b0 + (data[start] >> 4) as u16
  467. }
  468. _ => unreachable!(),
  469. }
  470. }
  471. /// Return the destination port number.
  472. pub fn dst_port(&self) -> u16 {
  473. match self.ports_field() {
  474. 0b00 => {
  475. // The full 16 bits are carried in-line.
  476. let data = self.buffer.as_ref();
  477. let idx = self.nhc_fields_start();
  478. NetworkEndian::read_u16(&data[idx + 2..idx + 4])
  479. }
  480. 0b01 => {
  481. // The first 8 bits are elided.
  482. let data = self.buffer.as_ref();
  483. let idx = self.nhc_fields_start();
  484. 0xf000 + data[idx] as u16
  485. }
  486. 0b10 => {
  487. // The full 16 bits are carried in-line.
  488. let data = self.buffer.as_ref();
  489. let idx = self.nhc_fields_start();
  490. NetworkEndian::read_u16(&data[idx + 1..idx + 1 + 2])
  491. }
  492. 0b11 => {
  493. // The first 12 bits are elided.
  494. let data = self.buffer.as_ref();
  495. let start = self.nhc_fields_start();
  496. 0xf0b0 + (data[start] & 0xff) as u16
  497. }
  498. _ => unreachable!(),
  499. }
  500. }
  501. /// Return the checksum.
  502. pub fn checksum(&self) -> Option<u16> {
  503. if self.checksum_field() == 0b0 {
  504. // The first 12 bits are elided.
  505. let data = self.buffer.as_ref();
  506. let start = self.nhc_fields_start() + self.ports_size();
  507. Some(NetworkEndian::read_u16(&data[start..start + 2]))
  508. } else {
  509. // The checksum is elided and needs to be recomputed on the 6LoWPAN termination point.
  510. None
  511. }
  512. }
  513. // Return the size of the checksum field.
  514. pub(crate) fn checksum_size(&self) -> usize {
  515. match self.checksum_field() {
  516. 0b0 => 2,
  517. 0b1 => 0,
  518. _ => unreachable!(),
  519. }
  520. }
  521. /// Returns the total size of both port numbers.
  522. pub(crate) fn ports_size(&self) -> usize {
  523. match self.ports_field() {
  524. 0b00 => 4, // 16 bits + 16 bits
  525. 0b01 => 3, // 16 bits + 8 bits
  526. 0b10 => 3, // 8 bits + 16 bits
  527. 0b11 => 1, // 4 bits + 4 bits
  528. _ => unreachable!(),
  529. }
  530. }
  531. }
  532. impl<'a, T: AsRef<[u8]> + ?Sized> UdpNhcPacket<&'a T> {
  533. /// Return a pointer to the payload.
  534. pub fn payload(&self) -> &'a [u8] {
  535. let start = 1 + self.ports_size() + self.checksum_size();
  536. &self.buffer.as_ref()[start..]
  537. }
  538. }
  539. impl<T: AsRef<[u8]> + AsMut<[u8]>> UdpNhcPacket<T> {
  540. /// Return a mutable pointer to the payload.
  541. pub fn payload_mut(&mut self) -> &mut [u8] {
  542. let start = 1 + self.ports_size() + 2; // XXX(thvdveld): we assume we put the checksum inlined.
  543. &mut self.buffer.as_mut()[start..]
  544. }
  545. /// Set the dispatch field to `0b11110`.
  546. fn set_dispatch_field(&mut self) {
  547. let data = self.buffer.as_mut();
  548. data[0] = (data[0] & !(0b11111 << 3)) | (DISPATCH_UDP_HEADER << 3);
  549. }
  550. set_field!(set_checksum_field, 0b1, 2);
  551. set_field!(set_ports_field, 0b11, 0);
  552. fn set_ports(&mut self, src_port: u16, dst_port: u16) {
  553. let mut idx = 1;
  554. match (src_port, dst_port) {
  555. (0xf0b0..=0xf0bf, 0xf0b0..=0xf0bf) => {
  556. // We can compress both the source and destination ports.
  557. self.set_ports_field(0b11);
  558. let data = self.buffer.as_mut();
  559. data[idx] = (((src_port - 0xf0b0) as u8) << 4) & ((dst_port - 0xf0b0) as u8);
  560. }
  561. (0xf000..=0xf0ff, _) => {
  562. // We can compress the source port, but not the destination port.
  563. self.set_ports_field(0b10);
  564. let data = self.buffer.as_mut();
  565. data[idx] = (src_port - 0xf000) as u8;
  566. idx += 1;
  567. NetworkEndian::write_u16(&mut data[idx..idx + 2], dst_port);
  568. }
  569. (_, 0xf000..=0xf0ff) => {
  570. // We can compress the destination port, but not the source port.
  571. self.set_ports_field(0b01);
  572. let data = self.buffer.as_mut();
  573. NetworkEndian::write_u16(&mut data[idx..idx + 2], src_port);
  574. idx += 2;
  575. data[idx] = (dst_port - 0xf000) as u8;
  576. }
  577. (_, _) => {
  578. // We cannot compress any port.
  579. self.set_ports_field(0b00);
  580. let data = self.buffer.as_mut();
  581. NetworkEndian::write_u16(&mut data[idx..idx + 2], src_port);
  582. idx += 2;
  583. NetworkEndian::write_u16(&mut data[idx..idx + 2], dst_port);
  584. }
  585. };
  586. }
  587. fn set_checksum(&mut self, checksum: u16) {
  588. self.set_checksum_field(0b0);
  589. let idx = 1 + self.ports_size();
  590. let data = self.buffer.as_mut();
  591. NetworkEndian::write_u16(&mut data[idx..idx + 2], checksum);
  592. }
  593. }
  594. /// A high-level representation of a 6LoWPAN NHC UDP header.
  595. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  596. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  597. pub struct UdpNhcRepr(pub UdpRepr);
  598. impl<'a> UdpNhcRepr {
  599. /// Parse a 6LoWPAN NHC UDP packet and return a high-level representation.
  600. pub fn parse<T: AsRef<[u8]> + ?Sized>(
  601. packet: &UdpNhcPacket<&'a T>,
  602. src_addr: &ipv6::Address,
  603. dst_addr: &ipv6::Address,
  604. checksum_caps: &ChecksumCapabilities,
  605. ) -> Result<Self> {
  606. packet.check_len()?;
  607. if packet.dispatch_field() != DISPATCH_UDP_HEADER {
  608. return Err(Error);
  609. }
  610. if checksum_caps.udp.rx() {
  611. let payload_len = packet.payload().len();
  612. let chk_sum = !checksum::combine(&[
  613. checksum::pseudo_header_v6(
  614. src_addr,
  615. dst_addr,
  616. crate::wire::ip::Protocol::Udp,
  617. payload_len as u32 + 8,
  618. ),
  619. packet.src_port(),
  620. packet.dst_port(),
  621. payload_len as u16 + 8,
  622. checksum::data(packet.payload()),
  623. ]);
  624. if let Some(checksum) = packet.checksum() {
  625. if chk_sum != checksum {
  626. return Err(Error);
  627. }
  628. }
  629. }
  630. Ok(Self(UdpRepr {
  631. src_port: packet.src_port(),
  632. dst_port: packet.dst_port(),
  633. }))
  634. }
  635. /// Return the length of a packet that will be emitted from this high-level representation.
  636. pub fn header_len(&self) -> usize {
  637. let mut len = 1; // The minimal header size
  638. len += 2; // XXX We assume we will add the checksum at the end
  639. // Check if we can compress the source and destination ports
  640. match (self.src_port, self.dst_port) {
  641. (0xf0b0..=0xf0bf, 0xf0b0..=0xf0bf) => len + 1,
  642. (0xf000..=0xf0ff, _) | (_, 0xf000..=0xf0ff) => len + 3,
  643. (_, _) => len + 4,
  644. }
  645. }
  646. /// Emit a high-level representation into a LOWPAN_NHC UDP header.
  647. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(
  648. &self,
  649. packet: &mut UdpNhcPacket<T>,
  650. src_addr: &Address,
  651. dst_addr: &Address,
  652. payload_len: usize,
  653. emit_payload: impl FnOnce(&mut [u8]),
  654. checksum_caps: &ChecksumCapabilities,
  655. ) {
  656. packet.set_dispatch_field();
  657. packet.set_ports(self.src_port, self.dst_port);
  658. emit_payload(packet.payload_mut());
  659. if checksum_caps.udp.tx() {
  660. let chk_sum = !checksum::combine(&[
  661. checksum::pseudo_header_v6(
  662. src_addr,
  663. dst_addr,
  664. crate::wire::ip::Protocol::Udp,
  665. payload_len as u32 + 8,
  666. ),
  667. self.src_port,
  668. self.dst_port,
  669. payload_len as u16 + 8,
  670. checksum::data(packet.payload_mut()),
  671. ]);
  672. packet.set_checksum(chk_sum);
  673. }
  674. }
  675. }
  676. impl core::ops::Deref for UdpNhcRepr {
  677. type Target = UdpRepr;
  678. fn deref(&self) -> &Self::Target {
  679. &self.0
  680. }
  681. }
  682. impl core::ops::DerefMut for UdpNhcRepr {
  683. fn deref_mut(&mut self) -> &mut Self::Target {
  684. &mut self.0
  685. }
  686. }
  687. #[cfg(test)]
  688. mod test {
  689. use super::*;
  690. #[test]
  691. fn ext_header_nh_inlined() {
  692. let bytes = [0xe2, 0x3a, 0x6, 0x3, 0x0, 0xff, 0x0, 0x0, 0x0];
  693. let packet = ExtHeaderPacket::new_checked(&bytes[..]).unwrap();
  694. assert_eq!(packet.next_header_size(), 1);
  695. assert_eq!(packet.length(), 6);
  696. assert_eq!(packet.dispatch_field(), DISPATCH_EXT_HEADER);
  697. assert_eq!(packet.extension_header_id(), ExtHeaderId::RoutingHeader);
  698. assert_eq!(
  699. packet.next_header(),
  700. NextHeader::Uncompressed(IpProtocol::Icmpv6)
  701. );
  702. assert_eq!(packet.payload(), [0x03, 0x00, 0xff, 0x00, 0x00, 0x00]);
  703. }
  704. #[test]
  705. fn ext_header_nh_elided() {
  706. let bytes = [0xe3, 0x06, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00];
  707. let packet = ExtHeaderPacket::new_checked(&bytes[..]).unwrap();
  708. assert_eq!(packet.next_header_size(), 0);
  709. assert_eq!(packet.length(), 6);
  710. assert_eq!(packet.dispatch_field(), DISPATCH_EXT_HEADER);
  711. assert_eq!(packet.extension_header_id(), ExtHeaderId::RoutingHeader);
  712. assert_eq!(packet.next_header(), NextHeader::Compressed);
  713. assert_eq!(packet.payload(), [0x03, 0x00, 0xff, 0x00, 0x00, 0x00]);
  714. }
  715. #[test]
  716. fn ext_header_emit() {
  717. let ext_header = ExtHeaderRepr {
  718. ext_header_id: ExtHeaderId::RoutingHeader,
  719. next_header: NextHeader::Compressed,
  720. length: 6,
  721. };
  722. let len = ext_header.buffer_len();
  723. let mut buffer = [0u8; 127];
  724. let mut packet = ExtHeaderPacket::new_unchecked(&mut buffer[..len]);
  725. ext_header.emit(&mut packet);
  726. assert_eq!(packet.dispatch_field(), DISPATCH_EXT_HEADER);
  727. assert_eq!(packet.next_header(), NextHeader::Compressed);
  728. assert_eq!(packet.extension_header_id(), ExtHeaderId::RoutingHeader);
  729. }
  730. #[test]
  731. fn udp_nhc_fields() {
  732. let bytes = [0xf0, 0x16, 0x2e, 0x22, 0x3d, 0x28, 0xc4];
  733. let packet = UdpNhcPacket::new_checked(&bytes[..]).unwrap();
  734. assert_eq!(packet.dispatch_field(), DISPATCH_UDP_HEADER);
  735. assert_eq!(packet.checksum(), Some(0x28c4));
  736. assert_eq!(packet.src_port(), 5678);
  737. assert_eq!(packet.dst_port(), 8765);
  738. }
  739. #[test]
  740. fn udp_emit() {
  741. let udp = UdpNhcRepr(UdpRepr {
  742. src_port: 0xf0b1,
  743. dst_port: 0xf001,
  744. });
  745. let payload = b"Hello World!";
  746. let src_addr = ipv6::Address::UNSPECIFIED;
  747. let dst_addr = ipv6::Address::UNSPECIFIED;
  748. let len = udp.header_len() + payload.len();
  749. let mut buffer = [0u8; 127];
  750. let mut packet = UdpNhcPacket::new_unchecked(&mut buffer[..len]);
  751. udp.emit(
  752. &mut packet,
  753. &src_addr,
  754. &dst_addr,
  755. payload.len(),
  756. |buf| buf.copy_from_slice(&payload[..]),
  757. &ChecksumCapabilities::default(),
  758. );
  759. assert_eq!(packet.dispatch_field(), DISPATCH_UDP_HEADER);
  760. assert_eq!(packet.src_port(), 0xf0b1);
  761. assert_eq!(packet.dst_port(), 0xf001);
  762. assert_eq!(packet.payload_mut(), b"Hello World!");
  763. }
  764. }