sixlowpan.rs 38 KB

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