sixlowpan.rs 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. use super::*;
  2. use crate::wire::Result;
  3. // Max len of non-fragmented packets after decompression (including ipv6 header and payload)
  4. // TODO: lower. Should be (6lowpan mtu) - (min 6lowpan header size) + (max ipv6 header size)
  5. pub(crate) const MAX_DECOMPRESSED_LEN: usize = 1500;
  6. impl Interface {
  7. /// Process fragments that still need to be sent for 6LoWPAN packets.
  8. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  9. pub(super) fn sixlowpan_egress(&mut self, device: &mut (impl Device + ?Sized)) {
  10. // Reset the buffer when we transmitted everything.
  11. if self.fragmenter.finished() {
  12. self.fragmenter.reset();
  13. }
  14. if self.fragmenter.is_empty() {
  15. return;
  16. }
  17. let pkt = &self.fragmenter;
  18. if pkt.packet_len > pkt.sent_bytes {
  19. if let Some(tx_token) = device.transmit(self.inner.now) {
  20. self.inner
  21. .dispatch_ieee802154_frag(tx_token, &mut self.fragmenter);
  22. }
  23. }
  24. }
  25. /// Get the 6LoWPAN address contexts.
  26. pub fn sixlowpan_address_context(&self) -> &[SixlowpanAddressContext] {
  27. &self.inner.sixlowpan_address_context[..]
  28. }
  29. /// Get a mutable reference to the 6LoWPAN address contexts.
  30. pub fn sixlowpan_address_context_mut(
  31. &mut self,
  32. ) -> &mut Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
  33. &mut self.inner.sixlowpan_address_context
  34. }
  35. }
  36. impl InterfaceInner {
  37. /// Get the next tag for a 6LoWPAN fragment.
  38. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  39. fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
  40. let tag = self.tag;
  41. self.tag = self.tag.wrapping_add(1);
  42. tag
  43. }
  44. pub(super) fn process_sixlowpan<'output, 'payload: 'output>(
  45. &mut self,
  46. sockets: &mut SocketSet,
  47. meta: PacketMeta,
  48. ieee802154_repr: &Ieee802154Repr,
  49. payload: &'payload [u8],
  50. f: &'output mut FragmentsBuffer,
  51. ) -> Option<Packet<'output>> {
  52. let payload = match check!(SixlowpanPacket::dispatch(payload)) {
  53. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  54. SixlowpanPacket::FragmentHeader => {
  55. net_debug!(
  56. "Fragmentation is not supported, \
  57. use the `proto-sixlowpan-fragmentation` feature to add support."
  58. );
  59. return None;
  60. }
  61. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  62. SixlowpanPacket::FragmentHeader => {
  63. match self.process_sixlowpan_fragment(ieee802154_repr, payload, f) {
  64. Some(payload) => payload,
  65. None => return None,
  66. }
  67. }
  68. SixlowpanPacket::IphcHeader => {
  69. match Self::sixlowpan_to_ipv6(
  70. &self.sixlowpan_address_context,
  71. ieee802154_repr,
  72. payload,
  73. None,
  74. &mut f.decompress_buf,
  75. ) {
  76. Ok(len) => &f.decompress_buf[..len],
  77. Err(e) => {
  78. net_debug!("sixlowpan decompress failed: {:?}", e);
  79. return None;
  80. }
  81. }
  82. }
  83. };
  84. self.process_ipv6(
  85. sockets,
  86. meta,
  87. match ieee802154_repr.src_addr {
  88. Some(s) => HardwareAddress::Ieee802154(s),
  89. None => HardwareAddress::Ieee802154(Ieee802154Address::Absent),
  90. },
  91. &check!(Ipv6Packet::new_checked(payload)),
  92. )
  93. }
  94. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  95. fn process_sixlowpan_fragment<'output, 'payload: 'output>(
  96. &mut self,
  97. ieee802154_repr: &Ieee802154Repr,
  98. payload: &'payload [u8],
  99. f: &'output mut FragmentsBuffer,
  100. ) -> Option<&'output [u8]> {
  101. use crate::iface::fragmentation::{AssemblerError, AssemblerFullError};
  102. // We have a fragment header, which means we cannot process the 6LoWPAN packet,
  103. // unless we have a complete one after processing this fragment.
  104. let frag = check!(SixlowpanFragPacket::new_checked(payload));
  105. // From RFC 4944 § 5.3: "The value of datagram_size SHALL be 40 octets more than the value
  106. // of Payload Length in the IPv6 header of the packet."
  107. // We should check that this is true, otherwise `buffer.split_at_mut(40)` will panic, since
  108. // we assume that the decompressed packet is at least 40 bytes.
  109. if frag.datagram_size() < 40 {
  110. net_debug!("6LoWPAN: fragment size too small");
  111. return None;
  112. }
  113. // The key specifies to which 6LoWPAN fragment it belongs too.
  114. // It is based on the link layer addresses, the tag and the size.
  115. let key = FragKey::Sixlowpan(frag.get_key(ieee802154_repr));
  116. // The offset of this fragment in increments of 8 octets.
  117. let offset = frag.datagram_offset() as usize * 8;
  118. // We reserve a spot in the packet assembler set and add the required
  119. // information to the packet assembler.
  120. // This information is the total size of the packet when it is fully assmbled.
  121. // We also pass the header size, since this is needed when other fragments
  122. // (other than the first one) are added.
  123. let frag_slot = match f.assembler.get(&key, self.now + f.reassembly_timeout) {
  124. Ok(frag) => frag,
  125. Err(AssemblerFullError) => {
  126. net_debug!("No available packet assembler for fragmented packet");
  127. return None;
  128. }
  129. };
  130. if frag.is_first_fragment() {
  131. // The first fragment contains the total size of the IPv6 packet.
  132. // However, we received a packet that is compressed following the 6LoWPAN
  133. // standard. This means we need to convert the IPv6 packet size to a 6LoWPAN
  134. // packet size. The packet size can be different because of first the
  135. // compression of the IP header and when UDP is used (because the UDP header
  136. // can also be compressed). Other headers are not compressed by 6LoWPAN.
  137. // First segment tells us the total size.
  138. let total_size = frag.datagram_size() as usize;
  139. if frag_slot.set_total_size(total_size).is_err() {
  140. net_debug!("No available packet assembler for fragmented packet");
  141. return None;
  142. }
  143. // Decompress headers+payload into the assembler.
  144. if let Err(e) = frag_slot.add_with(0, |buffer| {
  145. Self::sixlowpan_to_ipv6(
  146. &self.sixlowpan_address_context,
  147. ieee802154_repr,
  148. frag.payload(),
  149. Some(total_size),
  150. buffer,
  151. )
  152. .map_err(|_| AssemblerError)
  153. }) {
  154. net_debug!("fragmentation error: {:?}", e);
  155. return None;
  156. }
  157. } else {
  158. // Add the fragment to the packet assembler.
  159. if let Err(e) = frag_slot.add(frag.payload(), offset) {
  160. net_debug!("fragmentation error: {:?}", e);
  161. return None;
  162. }
  163. }
  164. match frag_slot.assemble() {
  165. Some(payload) => {
  166. net_trace!("6LoWPAN: fragmented packet now complete");
  167. Some(payload)
  168. }
  169. None => None,
  170. }
  171. }
  172. /// Decompress a 6LoWPAN packet into an IPv6 packet.
  173. ///
  174. /// The return value is the length of the decompressed packet, but not including the total
  175. /// length of the payload of the UDP packet. This value is then used by the assembler to know
  176. /// how far in the assembler buffer the packet is.
  177. ///
  178. /// **NOTE**: when decompressing a fragmented packet, the `total_len` parameter should be
  179. /// passed. This is the total length of the IPv6 packet, including the IPv6 header. It is used
  180. /// for calculating the length field in the UDP header.
  181. fn sixlowpan_to_ipv6(
  182. address_context: &[SixlowpanAddressContext],
  183. ieee802154_repr: &Ieee802154Repr,
  184. iphc_payload: &[u8],
  185. total_len: Option<usize>,
  186. buffer: &mut [u8],
  187. ) -> Result<usize> {
  188. let iphc = SixlowpanIphcPacket::new_checked(iphc_payload)?;
  189. let iphc_repr = SixlowpanIphcRepr::parse(
  190. &iphc,
  191. ieee802154_repr.src_addr,
  192. ieee802154_repr.dst_addr,
  193. address_context,
  194. )?;
  195. // The first thing we have to decompress is the IPv6 header. However, at this point we
  196. // don't know the total size of the packet, neither the next header, since that can be a
  197. // compressed header. However, we know that the IPv6 header is 40 bytes, so we can reserve
  198. // this space in the buffer such that we can decompress the IPv6 header into it at a later
  199. // point.
  200. let (ipv6_buffer, mut buffer) = buffer.split_at_mut(40);
  201. let mut ipv6_header = Ipv6Packet::new_unchecked(ipv6_buffer);
  202. // If the total length is given, we are dealing with a fragmented packet. The total
  203. // length is then used to calculate the length field for the UDP header. If the total
  204. // length is not given, we are not working with a fragmented packet, and we need to
  205. // calculate the length of the payload ourselves.
  206. let mut payload_len = 40;
  207. let mut decompressed_len = 40;
  208. let mut next_header = Some(iphc_repr.next_header);
  209. let mut data = iphc.payload();
  210. while let Some(nh) = next_header {
  211. match nh {
  212. SixlowpanNextHeader::Compressed => match SixlowpanNhcPacket::dispatch(data)? {
  213. SixlowpanNhcPacket::ExtHeader => {
  214. (buffer, data) = decompress_ext_hdr(
  215. data,
  216. &mut next_header,
  217. buffer,
  218. &mut payload_len,
  219. &mut decompressed_len,
  220. )?;
  221. }
  222. SixlowpanNhcPacket::UdpHeader => {
  223. decompress_udp(
  224. data,
  225. &iphc_repr,
  226. buffer,
  227. total_len,
  228. &mut payload_len,
  229. &mut decompressed_len,
  230. )?;
  231. break;
  232. }
  233. },
  234. SixlowpanNextHeader::Uncompressed(proto) => {
  235. // We have a 6LoWPAN uncompressed header.
  236. match proto {
  237. IpProtocol::Tcp | IpProtocol::Udp | IpProtocol::Icmpv6 => {
  238. // There can be no protocol after this one, so we can just copy the
  239. // rest of the data buffer. There is also no length field in the UDP
  240. // header that we need to correct as this header was not changed by the
  241. // 6LoWPAN compressor.
  242. if data.len() > buffer.len() {
  243. return Err(Error);
  244. }
  245. buffer[..data.len()].copy_from_slice(data);
  246. payload_len += data.len();
  247. decompressed_len += data.len();
  248. break;
  249. }
  250. proto => {
  251. net_debug!("Unsupported uncompressed next header: {:?}", proto);
  252. return Err(Error);
  253. }
  254. }
  255. }
  256. }
  257. }
  258. let ipv6_repr = Ipv6Repr {
  259. src_addr: iphc_repr.src_addr,
  260. dst_addr: iphc_repr.dst_addr,
  261. next_header: decompress_next_header(iphc_repr.next_header, iphc.payload())?,
  262. payload_len: total_len.unwrap_or(payload_len) - 40,
  263. hop_limit: iphc_repr.hop_limit,
  264. };
  265. ipv6_repr.emit(&mut ipv6_header);
  266. Ok(decompressed_len)
  267. }
  268. pub(super) fn dispatch_sixlowpan<Tx: TxToken>(
  269. &mut self,
  270. mut tx_token: Tx,
  271. meta: PacketMeta,
  272. packet: Packet,
  273. ieee_repr: Ieee802154Repr,
  274. frag: &mut Fragmenter,
  275. ) {
  276. let packet = match packet {
  277. #[cfg(feature = "proto-ipv4")]
  278. Packet::Ipv4(_) => unreachable!(),
  279. Packet::Ipv6(packet) => packet,
  280. };
  281. // First we calculate the size we are going to need. If the size is bigger than the MTU,
  282. // then we use fragmentation.
  283. let (total_size, compressed_size, uncompressed_size) =
  284. Self::compressed_packet_size(&packet, &ieee_repr);
  285. let ieee_len = ieee_repr.buffer_len();
  286. // TODO(thvdveld): use the MTU of the device.
  287. if total_size + ieee_len > 125 {
  288. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  289. {
  290. // The packet does not fit in one Ieee802154 frame, so we need fragmentation.
  291. // We do this by emitting everything in the `frag.buffer` from the interface.
  292. // After emitting everything into that buffer, we send the first fragment heere.
  293. // When `poll` is called again, we check if frag was fully sent, otherwise we
  294. // call `dispatch_ieee802154_frag`, which will transmit the other fragments.
  295. // `dispatch_ieee802154_frag` requires some information about the total packet size,
  296. // the link local source and destination address...
  297. let pkt = frag;
  298. if pkt.buffer.len() < total_size {
  299. net_debug!(
  300. "dispatch_ieee802154: dropping, \
  301. fragmentation buffer is too small, at least {} needed",
  302. total_size
  303. );
  304. return;
  305. }
  306. let payload_length = packet.header.payload_len;
  307. Self::ipv6_to_sixlowpan(
  308. &self.checksum_caps(),
  309. packet,
  310. &ieee_repr,
  311. &mut pkt.buffer[..],
  312. );
  313. pkt.sixlowpan.ll_dst_addr = ieee_repr.dst_addr.unwrap();
  314. pkt.sixlowpan.ll_src_addr = ieee_repr.src_addr.unwrap();
  315. pkt.packet_len = total_size;
  316. // The datagram size that we need to set in the first fragment header is equal to the
  317. // IPv6 payload length + 40.
  318. pkt.sixlowpan.datagram_size = (payload_length + 40) as u16;
  319. let tag = self.get_sixlowpan_fragment_tag();
  320. // We save the tag for the other fragments that will be created when calling `poll`
  321. // multiple times.
  322. pkt.sixlowpan.datagram_tag = tag;
  323. let frag1 = SixlowpanFragRepr::FirstFragment {
  324. size: pkt.sixlowpan.datagram_size,
  325. tag,
  326. };
  327. let fragn = SixlowpanFragRepr::Fragment {
  328. size: pkt.sixlowpan.datagram_size,
  329. tag,
  330. offset: 0,
  331. };
  332. // We calculate how much data we can send in the first fragment and the other
  333. // fragments. The eventual IPv6 sizes of these fragments need to be a multiple of eight
  334. // (except for the last fragment) since the offset field in the fragment is an offset
  335. // in multiples of 8 octets. This is explained in [RFC 4944 § 5.3].
  336. //
  337. // [RFC 4944 § 5.3]: https://datatracker.ietf.org/doc/html/rfc4944#section-5.3
  338. let header_diff = uncompressed_size - compressed_size;
  339. let frag1_size =
  340. (125 - ieee_len - frag1.buffer_len() + header_diff) / 8 * 8 - header_diff;
  341. pkt.sixlowpan.fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
  342. pkt.sent_bytes = frag1_size;
  343. pkt.sixlowpan.datagram_offset = frag1_size + header_diff;
  344. tx_token.set_meta(meta);
  345. tx_token.consume(ieee_len + frag1.buffer_len() + frag1_size, |mut tx_buf| {
  346. // Add the IEEE header.
  347. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  348. ieee_repr.emit(&mut ieee_packet);
  349. tx_buf = &mut tx_buf[ieee_len..];
  350. // Add the first fragment header
  351. let mut frag1_packet = SixlowpanFragPacket::new_unchecked(&mut tx_buf);
  352. frag1.emit(&mut frag1_packet);
  353. tx_buf = &mut tx_buf[frag1.buffer_len()..];
  354. // Add the buffer part.
  355. tx_buf[..frag1_size].copy_from_slice(&pkt.buffer[..frag1_size]);
  356. });
  357. }
  358. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  359. {
  360. net_debug!(
  361. "Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support."
  362. );
  363. return;
  364. }
  365. } else {
  366. tx_token.set_meta(meta);
  367. // We don't need fragmentation, so we emit everything to the TX token.
  368. tx_token.consume(total_size + ieee_len, |mut tx_buf| {
  369. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  370. ieee_repr.emit(&mut ieee_packet);
  371. tx_buf = &mut tx_buf[ieee_len..];
  372. Self::ipv6_to_sixlowpan(&self.checksum_caps(), packet, &ieee_repr, tx_buf);
  373. });
  374. }
  375. }
  376. fn ipv6_to_sixlowpan(
  377. checksum_caps: &ChecksumCapabilities,
  378. mut packet: PacketV6,
  379. ieee_repr: &Ieee802154Repr,
  380. mut buffer: &mut [u8],
  381. ) {
  382. let last_header = packet.payload.as_sixlowpan_next_header();
  383. let next_header = last_header;
  384. #[cfg(feature = "proto-ipv6-hbh")]
  385. let next_header = if packet.hop_by_hop.is_some() {
  386. SixlowpanNextHeader::Compressed
  387. } else {
  388. next_header
  389. };
  390. #[cfg(feature = "proto-ipv6-routing")]
  391. let next_header = if packet.routing.is_some() {
  392. SixlowpanNextHeader::Compressed
  393. } else {
  394. next_header
  395. };
  396. let iphc_repr = SixlowpanIphcRepr {
  397. src_addr: packet.header.src_addr,
  398. ll_src_addr: ieee_repr.src_addr,
  399. dst_addr: packet.header.dst_addr,
  400. ll_dst_addr: ieee_repr.dst_addr,
  401. next_header,
  402. hop_limit: packet.header.hop_limit,
  403. ecn: None,
  404. dscp: None,
  405. flow_label: None,
  406. };
  407. iphc_repr.emit(&mut SixlowpanIphcPacket::new_unchecked(
  408. &mut buffer[..iphc_repr.buffer_len()],
  409. ));
  410. buffer = &mut buffer[iphc_repr.buffer_len()..];
  411. // Emit the Hop-by-Hop header
  412. #[cfg(feature = "proto-ipv6-hbh")]
  413. if let Some(hbh) = packet.hop_by_hop {
  414. #[allow(unused)]
  415. let next_header = last_header;
  416. #[cfg(feature = "proto-ipv6-routing")]
  417. let next_header = if packet.routing.is_some() {
  418. SixlowpanNextHeader::Compressed
  419. } else {
  420. last_header
  421. };
  422. let ext_hdr = SixlowpanExtHeaderRepr {
  423. ext_header_id: SixlowpanExtHeaderId::HopByHopHeader,
  424. next_header,
  425. length: hbh.options.iter().map(|o| o.buffer_len()).sum::<usize>() as u8,
  426. };
  427. ext_hdr.emit(&mut SixlowpanExtHeaderPacket::new_unchecked(
  428. &mut buffer[..ext_hdr.buffer_len()],
  429. ));
  430. buffer = &mut buffer[ext_hdr.buffer_len()..];
  431. for opt in &hbh.options {
  432. opt.emit(&mut Ipv6Option::new_unchecked(
  433. &mut buffer[..opt.buffer_len()],
  434. ));
  435. buffer = &mut buffer[opt.buffer_len()..];
  436. }
  437. }
  438. // Emit the Routing header
  439. #[cfg(feature = "proto-ipv6-routing")]
  440. if let Some(routing) = &packet.routing {
  441. let ext_hdr = SixlowpanExtHeaderRepr {
  442. ext_header_id: SixlowpanExtHeaderId::RoutingHeader,
  443. next_header,
  444. length: routing.buffer_len() as u8,
  445. };
  446. ext_hdr.emit(&mut SixlowpanExtHeaderPacket::new_unchecked(
  447. &mut buffer[..ext_hdr.buffer_len()],
  448. ));
  449. buffer = &mut buffer[ext_hdr.buffer_len()..];
  450. routing.emit(&mut Ipv6RoutingHeader::new_unchecked(
  451. &mut buffer[..routing.buffer_len()],
  452. ));
  453. buffer = &mut buffer[routing.buffer_len()..];
  454. }
  455. match &mut packet.payload {
  456. IpPayload::Icmpv6(icmp_repr) => {
  457. icmp_repr.emit(
  458. &packet.header.src_addr,
  459. &packet.header.dst_addr,
  460. &mut Icmpv6Packet::new_unchecked(&mut buffer[..icmp_repr.buffer_len()]),
  461. checksum_caps,
  462. );
  463. }
  464. #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
  465. IpPayload::Udp(udp_repr, payload) => {
  466. let udp_repr = SixlowpanUdpNhcRepr(*udp_repr);
  467. udp_repr.emit(
  468. &mut SixlowpanUdpNhcPacket::new_unchecked(
  469. &mut buffer[..udp_repr.header_len() + payload.len()],
  470. ),
  471. &iphc_repr.src_addr,
  472. &iphc_repr.dst_addr,
  473. payload.len(),
  474. |buf| buf.copy_from_slice(payload),
  475. checksum_caps,
  476. );
  477. }
  478. #[cfg(feature = "socket-tcp")]
  479. IpPayload::Tcp(tcp_repr) => {
  480. tcp_repr.emit(
  481. &mut TcpPacket::new_unchecked(&mut buffer[..tcp_repr.buffer_len()]),
  482. &packet.header.src_addr.into(),
  483. &packet.header.dst_addr.into(),
  484. checksum_caps,
  485. );
  486. }
  487. #[cfg(feature = "socket-raw")]
  488. IpPayload::Raw(_raw) => todo!(),
  489. #[allow(unreachable_patterns)]
  490. _ => unreachable!(),
  491. }
  492. }
  493. /// Calculates three sizes:
  494. /// - total size: the size of a compressed IPv6 packet
  495. /// - compressed header size: the size of the compressed headers
  496. /// - uncompressed header size: the size of the headers that are not compressed
  497. ///
  498. /// They are returned as a tuple in the same order.
  499. fn compressed_packet_size(
  500. packet: &PacketV6,
  501. ieee_repr: &Ieee802154Repr,
  502. ) -> (usize, usize, usize) {
  503. let last_header = packet.payload.as_sixlowpan_next_header();
  504. let next_header = last_header;
  505. #[cfg(feature = "proto-ipv6-hbh")]
  506. let next_header = if packet.hop_by_hop.is_some() {
  507. SixlowpanNextHeader::Compressed
  508. } else {
  509. next_header
  510. };
  511. #[cfg(feature = "proto-ipv6-routing")]
  512. let next_header = if packet.routing.is_some() {
  513. SixlowpanNextHeader::Compressed
  514. } else {
  515. next_header
  516. };
  517. let iphc = SixlowpanIphcRepr {
  518. src_addr: packet.header.src_addr,
  519. ll_src_addr: ieee_repr.src_addr,
  520. dst_addr: packet.header.dst_addr,
  521. ll_dst_addr: ieee_repr.dst_addr,
  522. next_header,
  523. hop_limit: packet.header.hop_limit,
  524. ecn: None,
  525. dscp: None,
  526. flow_label: None,
  527. };
  528. let mut total_size = iphc.buffer_len();
  529. let mut compressed_hdr_size = iphc.buffer_len();
  530. let mut uncompressed_hdr_size = packet.header.buffer_len();
  531. // Add the hop-by-hop to the sizes.
  532. #[cfg(feature = "proto-ipv6-hbh")]
  533. if let Some(hbh) = &packet.hop_by_hop {
  534. #[allow(unused)]
  535. let next_header = last_header;
  536. #[cfg(feature = "proto-ipv6-routing")]
  537. let next_header = if packet.routing.is_some() {
  538. SixlowpanNextHeader::Compressed
  539. } else {
  540. last_header
  541. };
  542. let options_size = hbh.options.iter().map(|o| o.buffer_len()).sum::<usize>();
  543. let ext_hdr = SixlowpanExtHeaderRepr {
  544. ext_header_id: SixlowpanExtHeaderId::HopByHopHeader,
  545. next_header,
  546. length: hbh.buffer_len() as u8 + options_size as u8,
  547. };
  548. total_size += ext_hdr.buffer_len() + options_size;
  549. compressed_hdr_size += ext_hdr.buffer_len() + options_size;
  550. uncompressed_hdr_size += hbh.buffer_len() + options_size;
  551. }
  552. // Add the routing header to the sizes.
  553. #[cfg(feature = "proto-ipv6-routing")]
  554. if let Some(routing) = &packet.routing {
  555. let ext_hdr = SixlowpanExtHeaderRepr {
  556. ext_header_id: SixlowpanExtHeaderId::RoutingHeader,
  557. next_header,
  558. length: routing.buffer_len() as u8,
  559. };
  560. total_size += ext_hdr.buffer_len() + routing.buffer_len();
  561. compressed_hdr_size += ext_hdr.buffer_len() + routing.buffer_len();
  562. uncompressed_hdr_size += routing.buffer_len();
  563. }
  564. match packet.payload {
  565. #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
  566. IpPayload::Udp(udp_hdr, payload) => {
  567. uncompressed_hdr_size += udp_hdr.header_len();
  568. let udp_hdr = SixlowpanUdpNhcRepr(udp_hdr);
  569. compressed_hdr_size += udp_hdr.header_len();
  570. total_size += udp_hdr.header_len() + payload.len();
  571. }
  572. _ => {
  573. total_size += packet.header.payload_len;
  574. }
  575. }
  576. (total_size, compressed_hdr_size, uncompressed_hdr_size)
  577. }
  578. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  579. pub(super) fn dispatch_sixlowpan_frag<Tx: TxToken>(
  580. &mut self,
  581. tx_token: Tx,
  582. ieee_repr: Ieee802154Repr,
  583. frag: &mut Fragmenter,
  584. ) {
  585. // Create the FRAG_N header.
  586. let fragn = SixlowpanFragRepr::Fragment {
  587. size: frag.sixlowpan.datagram_size,
  588. tag: frag.sixlowpan.datagram_tag,
  589. offset: (frag.sixlowpan.datagram_offset / 8) as u8,
  590. };
  591. let ieee_len = ieee_repr.buffer_len();
  592. let frag_size = (frag.packet_len - frag.sent_bytes).min(frag.sixlowpan.fragn_size);
  593. tx_token.consume(
  594. ieee_repr.buffer_len() + fragn.buffer_len() + frag_size,
  595. |mut tx_buf| {
  596. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  597. ieee_repr.emit(&mut ieee_packet);
  598. tx_buf = &mut tx_buf[ieee_len..];
  599. let mut frag_packet =
  600. SixlowpanFragPacket::new_unchecked(&mut tx_buf[..fragn.buffer_len()]);
  601. fragn.emit(&mut frag_packet);
  602. tx_buf = &mut tx_buf[fragn.buffer_len()..];
  603. // Add the buffer part
  604. tx_buf[..frag_size].copy_from_slice(&frag.buffer[frag.sent_bytes..][..frag_size]);
  605. frag.sent_bytes += frag_size;
  606. frag.sixlowpan.datagram_offset += frag_size;
  607. },
  608. );
  609. }
  610. }
  611. /// Convert a 6LoWPAN next header to an IPv6 next header.
  612. #[inline]
  613. fn decompress_next_header(next_header: SixlowpanNextHeader, payload: &[u8]) -> Result<IpProtocol> {
  614. match next_header {
  615. SixlowpanNextHeader::Compressed => match SixlowpanNhcPacket::dispatch(payload)? {
  616. SixlowpanNhcPacket::ExtHeader => {
  617. let ext_hdr = SixlowpanExtHeaderPacket::new_checked(payload)?;
  618. Ok(ext_hdr.extension_header_id().into())
  619. }
  620. SixlowpanNhcPacket::UdpHeader => Ok(IpProtocol::Udp),
  621. },
  622. SixlowpanNextHeader::Uncompressed(proto) => Ok(proto),
  623. }
  624. }
  625. // NOTE: we always inline this function into the sixlowpan_to_ipv6 function, since it is only used there.
  626. #[inline(always)]
  627. fn decompress_ext_hdr<'d>(
  628. mut data: &'d [u8],
  629. next_header: &mut Option<SixlowpanNextHeader>,
  630. mut buffer: &'d mut [u8],
  631. payload_len: &mut usize,
  632. decompressed_len: &mut usize,
  633. ) -> Result<(&'d mut [u8], &'d [u8])> {
  634. let ext_hdr = SixlowpanExtHeaderPacket::new_checked(data)?;
  635. let ext_repr = SixlowpanExtHeaderRepr::parse(&ext_hdr)?;
  636. let nh = decompress_next_header(
  637. ext_repr.next_header,
  638. &data[ext_repr.length as usize + ext_repr.buffer_len()..],
  639. )?;
  640. *next_header = Some(ext_repr.next_header);
  641. let ipv6_ext_hdr = Ipv6ExtHeaderRepr {
  642. next_header: nh,
  643. length: ext_repr.length / 8,
  644. data: ext_hdr.payload(),
  645. };
  646. if ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len() > buffer.len() {
  647. return Err(Error);
  648. }
  649. ipv6_ext_hdr.emit(&mut Ipv6ExtHeader::new_unchecked(
  650. &mut buffer[..ipv6_ext_hdr.header_len()],
  651. ));
  652. buffer[ipv6_ext_hdr.header_len()..][..ipv6_ext_hdr.data.len()]
  653. .copy_from_slice(ipv6_ext_hdr.data);
  654. buffer = &mut buffer[ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len()..];
  655. *payload_len += ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len();
  656. *decompressed_len += ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len();
  657. data = &data[ext_repr.buffer_len() + ext_repr.length as usize..];
  658. Ok((buffer, data))
  659. }
  660. // NOTE: we always inline this function into the sixlowpan_to_ipv6 function, since it is only used there.
  661. #[inline(always)]
  662. fn decompress_udp(
  663. data: &[u8],
  664. iphc_repr: &SixlowpanIphcRepr,
  665. buffer: &mut [u8],
  666. total_len: Option<usize>,
  667. payload_len: &mut usize,
  668. decompressed_len: &mut usize,
  669. ) -> Result<()> {
  670. let udp_packet = SixlowpanUdpNhcPacket::new_checked(data)?;
  671. let payload = udp_packet.payload();
  672. let udp_repr = SixlowpanUdpNhcRepr::parse(
  673. &udp_packet,
  674. &iphc_repr.src_addr,
  675. &iphc_repr.dst_addr,
  676. &ChecksumCapabilities::ignored(),
  677. )?;
  678. if udp_repr.header_len() + payload.len() > buffer.len() {
  679. return Err(Error);
  680. }
  681. let udp_payload_len = if let Some(total_len) = total_len {
  682. total_len - *payload_len - 8
  683. } else {
  684. payload.len()
  685. };
  686. *payload_len += udp_payload_len + 8;
  687. *decompressed_len += udp_repr.0.header_len() + payload.len();
  688. let mut udp = UdpPacket::new_unchecked(&mut buffer[..payload.len() + 8]);
  689. udp_repr.0.emit_header(&mut udp, udp_payload_len);
  690. buffer[8..][..payload.len()].copy_from_slice(payload);
  691. Ok(())
  692. }
  693. #[cfg(test)]
  694. #[cfg(all(feature = "proto-rpl", feature = "proto-ipv6-hbh"))]
  695. mod tests {
  696. use super::*;
  697. static SIXLOWPAN_COMPRESSED_RPL_DAO: [u8; 99] = [
  698. 0x61, 0xdc, 0x45, 0xcd, 0xab, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00,
  699. 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x7e, 0xf7, 0x00, 0xe0, 0x3a, 0x06, 0x63, 0x04, 0x00,
  700. 0x1e, 0x08, 0x00, 0x9b, 0x02, 0x3e, 0x63, 0x1e, 0x40, 0x00, 0xf1, 0xfd, 0x00, 0x00, 0x00,
  701. 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x05, 0x12, 0x00,
  702. 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03,
  703. 0x00, 0x03, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1e, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  704. 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
  705. ];
  706. static SIXLOWPAN_UNCOMPRESSED_RPL_DAO: [u8; 114] = [
  707. 0x60, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x40, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  708. 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
  709. 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x3a, 0x00, 0x63, 0x04, 0x00,
  710. 0x1e, 0x08, 0x00, 0x9b, 0x02, 0x3e, 0x63, 0x1e, 0x40, 0x00, 0xf1, 0xfd, 0x00, 0x00, 0x00,
  711. 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x05, 0x12, 0x00,
  712. 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03,
  713. 0x00, 0x03, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1e, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  714. 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
  715. ];
  716. #[test]
  717. fn test_sixlowpan_decompress_hop_by_hop_with_icmpv6() {
  718. let address_context = [SixlowpanAddressContext([
  719. 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  720. ])];
  721. let ieee_frame = Ieee802154Frame::new_checked(&SIXLOWPAN_COMPRESSED_RPL_DAO).unwrap();
  722. let ieee_repr = Ieee802154Repr::parse(&ieee_frame).unwrap();
  723. let mut buffer = [0u8; 256];
  724. let len = InterfaceInner::sixlowpan_to_ipv6(
  725. &address_context,
  726. &ieee_repr,
  727. ieee_frame.payload().unwrap(),
  728. None,
  729. &mut buffer[..],
  730. )
  731. .unwrap();
  732. assert_eq!(&buffer[..len], &SIXLOWPAN_UNCOMPRESSED_RPL_DAO);
  733. }
  734. #[test]
  735. fn test_sixlowpan_compress_hop_by_hop_with_icmpv6() {
  736. let ieee_repr = Ieee802154Repr {
  737. frame_type: Ieee802154FrameType::Data,
  738. security_enabled: false,
  739. frame_pending: false,
  740. ack_request: true,
  741. sequence_number: Some(69),
  742. pan_id_compression: true,
  743. frame_version: Ieee802154FrameVersion::Ieee802154_2006,
  744. dst_pan_id: Some(Ieee802154Pan(43981)),
  745. dst_addr: Some(Ieee802154Address::Extended([0, 1, 0, 1, 0, 1, 0, 1])),
  746. src_pan_id: None,
  747. src_addr: Some(Ieee802154Address::Extended([0, 3, 0, 3, 0, 3, 0, 3])),
  748. };
  749. let mut ip_packet = PacketV6 {
  750. header: Ipv6Repr {
  751. src_addr: Ipv6Address::from_bytes(&[
  752. 253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3,
  753. ]),
  754. dst_addr: Ipv6Address::from_bytes(&[
  755. 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
  756. ]),
  757. next_header: IpProtocol::Icmpv6,
  758. payload_len: 66,
  759. hop_limit: 64,
  760. },
  761. #[cfg(feature = "proto-ipv6-hbh")]
  762. hop_by_hop: None,
  763. #[cfg(feature = "proto-ipv6-fragmentation")]
  764. fragment: None,
  765. #[cfg(feature = "proto-ipv6-routing")]
  766. routing: None,
  767. payload: IpPayload::Icmpv6(Icmpv6Repr::Rpl(RplRepr::DestinationAdvertisementObject {
  768. rpl_instance_id: RplInstanceId::Global(30),
  769. expect_ack: false,
  770. sequence: 241,
  771. dodag_id: Some(Ipv6Address::from_bytes(&[
  772. 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
  773. ])),
  774. options: &[],
  775. })),
  776. };
  777. let (total_size, _, _) = InterfaceInner::compressed_packet_size(&mut ip_packet, &ieee_repr);
  778. let mut buffer = vec![0u8; total_size];
  779. InterfaceInner::ipv6_to_sixlowpan(
  780. &ChecksumCapabilities::default(),
  781. ip_packet,
  782. &ieee_repr,
  783. &mut buffer[..total_size],
  784. );
  785. let result = [
  786. 0x7e, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0,
  787. 0x3, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
  788. 0xe0, 0x3a, 0x6, 0x63, 0x4, 0x0, 0x1e, 0x3, 0x0, 0x9b, 0x2, 0x3e, 0x63, 0x1e, 0x40,
  789. 0x0, 0xf1, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0,
  790. 0x1, 0x5, 0x12, 0x0, 0x80, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3,
  791. 0x0, 0x3, 0x0, 0x3, 0x6, 0x14, 0x0, 0x0, 0x0, 0x1e, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  792. 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
  793. ];
  794. assert_eq!(&result, &result);
  795. }
  796. #[test]
  797. fn test_sixlowpan_compress_hop_by_hop_with_udp() {
  798. let ieee_repr = Ieee802154Repr {
  799. frame_type: Ieee802154FrameType::Data,
  800. security_enabled: false,
  801. frame_pending: false,
  802. ack_request: true,
  803. sequence_number: Some(69),
  804. pan_id_compression: true,
  805. frame_version: Ieee802154FrameVersion::Ieee802154_2006,
  806. dst_pan_id: Some(Ieee802154Pan(43981)),
  807. dst_addr: Some(Ieee802154Address::Extended([0, 1, 0, 1, 0, 1, 0, 1])),
  808. src_pan_id: None,
  809. src_addr: Some(Ieee802154Address::Extended([0, 3, 0, 3, 0, 3, 0, 3])),
  810. };
  811. let addr = Ipv6Address::from_bytes(&[253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3]);
  812. let parent_address =
  813. Ipv6Address::from_bytes(&[253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1]);
  814. let mut hbh_options = heapless::Vec::new();
  815. hbh_options
  816. .push(Ipv6OptionRepr::Rpl(RplHopByHopRepr {
  817. down: false,
  818. rank_error: false,
  819. forwarding_error: false,
  820. instance_id: RplInstanceId::from(0x1e),
  821. sender_rank: 0x300,
  822. }))
  823. .unwrap();
  824. let mut ip_packet = PacketV6 {
  825. header: Ipv6Repr {
  826. src_addr: addr,
  827. dst_addr: parent_address,
  828. next_header: IpProtocol::Icmpv6,
  829. payload_len: 66,
  830. hop_limit: 64,
  831. },
  832. #[cfg(feature = "proto-ipv6-hbh")]
  833. hop_by_hop: Some(Ipv6HopByHopRepr {
  834. options: hbh_options,
  835. }),
  836. #[cfg(feature = "proto-ipv6-fragmentation")]
  837. fragment: None,
  838. #[cfg(feature = "proto-ipv6-routing")]
  839. routing: None,
  840. payload: IpPayload::Icmpv6(Icmpv6Repr::Rpl(RplRepr::DestinationAdvertisementObject {
  841. rpl_instance_id: RplInstanceId::Global(30),
  842. expect_ack: false,
  843. sequence: 241,
  844. dodag_id: Some(Ipv6Address::from_bytes(&[
  845. 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
  846. ])),
  847. options: &[
  848. 5, 18, 0, 128, 253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3, 6, 20, 0, 0,
  849. 0, 30, 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
  850. ],
  851. })),
  852. };
  853. let (total_size, _, _) = InterfaceInner::compressed_packet_size(&mut ip_packet, &ieee_repr);
  854. let mut buffer = vec![0u8; total_size];
  855. InterfaceInner::ipv6_to_sixlowpan(
  856. &ChecksumCapabilities::default(),
  857. ip_packet,
  858. &ieee_repr,
  859. &mut buffer[..total_size],
  860. );
  861. let result = [
  862. 0x7e, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0,
  863. 0x3, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
  864. 0xe0, 0x3a, 0x6, 0x63, 0x4, 0x0, 0x1e, 0x3, 0x0, 0x9b, 0x2, 0x3e, 0x63, 0x1e, 0x40,
  865. 0x0, 0xf1, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0,
  866. 0x1, 0x5, 0x12, 0x0, 0x80, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3,
  867. 0x0, 0x3, 0x0, 0x3, 0x6, 0x14, 0x0, 0x0, 0x0, 0x1e, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  868. 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
  869. ];
  870. assert_eq!(&buffer[..total_size], &result);
  871. }
  872. }