sixlowpan.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. use super::*;
  2. use crate::phy::ChecksumCapabilities;
  3. use crate::wire::{Ipv6Packet as Ipv6PacketWire, *};
  4. // Max len of non-fragmented packets after decompression (including ipv6 header and payload)
  5. // TODO: lower. Should be (6lowpan mtu) - (min 6lowpan header size) + (max ipv6 header size)
  6. pub(crate) const MAX_DECOMPRESSED_LEN: usize = 1500;
  7. impl InterfaceInner {
  8. pub(super) fn process_sixlowpan<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
  9. &mut self,
  10. sockets: &mut SocketSet,
  11. meta: PacketMeta,
  12. ieee802154_repr: &Ieee802154Repr,
  13. payload: &'payload T,
  14. f: &'output mut FragmentsBuffer,
  15. ) -> Option<IpPacket<'output>> {
  16. let payload = match check!(SixlowpanPacket::dispatch(payload)) {
  17. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  18. SixlowpanPacket::FragmentHeader => {
  19. net_debug!(
  20. "Fragmentation is not supported, \
  21. use the `proto-sixlowpan-fragmentation` feature to add support."
  22. );
  23. return None;
  24. }
  25. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  26. SixlowpanPacket::FragmentHeader => {
  27. match self.process_sixlowpan_fragment(ieee802154_repr, payload, f) {
  28. Some(payload) => payload,
  29. None => return None,
  30. }
  31. }
  32. SixlowpanPacket::IphcHeader => {
  33. match self.decompress_sixlowpan(
  34. ieee802154_repr,
  35. payload.as_ref(),
  36. None,
  37. &mut f.decompress_buf,
  38. ) {
  39. Ok(len) => &f.decompress_buf[..len],
  40. Err(e) => {
  41. net_debug!("sixlowpan decompress failed: {:?}", e);
  42. return None;
  43. }
  44. }
  45. }
  46. };
  47. self.process_ipv6(sockets, meta, &check!(Ipv6PacketWire::new_checked(payload)))
  48. }
  49. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  50. fn process_sixlowpan_fragment<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
  51. &mut self,
  52. ieee802154_repr: &Ieee802154Repr,
  53. payload: &'payload T,
  54. f: &'output mut FragmentsBuffer,
  55. ) -> Option<&'output [u8]> {
  56. use crate::iface::fragmentation::{AssemblerError, AssemblerFullError};
  57. // We have a fragment header, which means we cannot process the 6LoWPAN packet,
  58. // unless we have a complete one after processing this fragment.
  59. let frag = check!(SixlowpanFragPacket::new_checked(payload));
  60. // The key specifies to which 6LoWPAN fragment it belongs too.
  61. // It is based on the link layer addresses, the tag and the size.
  62. let key = FragKey::Sixlowpan(frag.get_key(ieee802154_repr));
  63. // The offset of this fragment in increments of 8 octets.
  64. let offset = frag.datagram_offset() as usize * 8;
  65. // We reserve a spot in the packet assembler set and add the required
  66. // information to the packet assembler.
  67. // This information is the total size of the packet when it is fully assmbled.
  68. // We also pass the header size, since this is needed when other fragments
  69. // (other than the first one) are added.
  70. let frag_slot = match f.assembler.get(&key, self.now + f.reassembly_timeout) {
  71. Ok(frag) => frag,
  72. Err(AssemblerFullError) => {
  73. net_debug!("No available packet assembler for fragmented packet");
  74. return None;
  75. }
  76. };
  77. if frag.is_first_fragment() {
  78. // The first fragment contains the total size of the IPv6 packet.
  79. // However, we received a packet that is compressed following the 6LoWPAN
  80. // standard. This means we need to convert the IPv6 packet size to a 6LoWPAN
  81. // packet size. The packet size can be different because of first the
  82. // compression of the IP header and when UDP is used (because the UDP header
  83. // can also be compressed). Other headers are not compressed by 6LoWPAN.
  84. // First segment tells us the total size.
  85. let total_size = frag.datagram_size() as usize;
  86. if frag_slot.set_total_size(total_size).is_err() {
  87. net_debug!("No available packet assembler for fragmented packet");
  88. return None;
  89. }
  90. // Decompress headers+payload into the assembler.
  91. if let Err(e) = frag_slot.add_with(0, |buffer| {
  92. self.decompress_sixlowpan(ieee802154_repr, frag.payload(), Some(total_size), buffer)
  93. .map_err(|_| AssemblerError)
  94. }) {
  95. net_debug!("fragmentation error: {:?}", e);
  96. return None;
  97. }
  98. } else {
  99. // Add the fragment to the packet assembler.
  100. if let Err(e) = frag_slot.add(frag.payload(), offset) {
  101. net_debug!("fragmentation error: {:?}", e);
  102. return None;
  103. }
  104. }
  105. match frag_slot.assemble() {
  106. Some(payload) => {
  107. net_trace!("6LoWPAN: fragmented packet now complete");
  108. Some(payload)
  109. }
  110. None => None,
  111. }
  112. }
  113. fn decompress_sixlowpan(
  114. &self,
  115. ieee802154_repr: &Ieee802154Repr,
  116. iphc_payload: &[u8],
  117. total_size: Option<usize>,
  118. buffer: &mut [u8],
  119. ) -> core::result::Result<usize, crate::wire::Error> {
  120. let iphc = SixlowpanIphcPacket::new_checked(iphc_payload)?;
  121. let iphc_repr = SixlowpanIphcRepr::parse(
  122. &iphc,
  123. ieee802154_repr.src_addr,
  124. ieee802154_repr.dst_addr,
  125. &self.sixlowpan_address_context,
  126. )?;
  127. let mut decompressed_size = 40 + iphc.payload().len();
  128. let next_header = match iphc_repr.next_header {
  129. SixlowpanNextHeader::Compressed => {
  130. match SixlowpanNhcPacket::dispatch(iphc.payload())? {
  131. SixlowpanNhcPacket::ExtHeader => {
  132. net_debug!("Extension headers are currently not supported for 6LoWPAN");
  133. IpProtocol::Unknown(0)
  134. }
  135. SixlowpanNhcPacket::UdpHeader => {
  136. let udp_packet = SixlowpanUdpNhcPacket::new_checked(iphc.payload())?;
  137. let udp_repr = SixlowpanUdpNhcRepr::parse(
  138. &udp_packet,
  139. &iphc_repr.src_addr,
  140. &iphc_repr.dst_addr,
  141. &crate::phy::ChecksumCapabilities::ignored(),
  142. )?;
  143. decompressed_size += 8;
  144. decompressed_size -= udp_repr.header_len();
  145. IpProtocol::Udp
  146. }
  147. }
  148. }
  149. SixlowpanNextHeader::Uncompressed(proto) => proto,
  150. };
  151. if buffer.len() < decompressed_size {
  152. net_debug!("sixlowpan decompress: buffer too short");
  153. return Err(crate::wire::Error);
  154. }
  155. let buffer = &mut buffer[..decompressed_size];
  156. let total_size = if let Some(size) = total_size {
  157. size
  158. } else {
  159. decompressed_size
  160. };
  161. let ipv6_repr = Ipv6Repr {
  162. src_addr: iphc_repr.src_addr,
  163. dst_addr: iphc_repr.dst_addr,
  164. next_header,
  165. payload_len: total_size - 40,
  166. hop_limit: iphc_repr.hop_limit,
  167. };
  168. // Emit the decompressed IPHC header (decompressed to an IPv6 header).
  169. let mut ipv6_packet = Ipv6PacketWire::new_unchecked(&mut buffer[..ipv6_repr.buffer_len()]);
  170. ipv6_repr.emit(&mut ipv6_packet);
  171. let buffer = &mut buffer[ipv6_repr.buffer_len()..];
  172. match iphc_repr.next_header {
  173. SixlowpanNextHeader::Compressed => {
  174. match SixlowpanNhcPacket::dispatch(iphc.payload())? {
  175. SixlowpanNhcPacket::ExtHeader => todo!(),
  176. SixlowpanNhcPacket::UdpHeader => {
  177. // We need to uncompress the UDP packet and emit it to the
  178. // buffer.
  179. let udp_packet = SixlowpanUdpNhcPacket::new_checked(iphc.payload())?;
  180. let udp_repr = SixlowpanUdpNhcRepr::parse(
  181. &udp_packet,
  182. &iphc_repr.src_addr,
  183. &iphc_repr.dst_addr,
  184. &ChecksumCapabilities::ignored(),
  185. )?;
  186. let mut udp = UdpPacket::new_unchecked(
  187. &mut buffer[..udp_repr.0.header_len() + iphc.payload().len()
  188. - udp_repr.header_len()],
  189. );
  190. udp_repr.0.emit_header(&mut udp, ipv6_repr.payload_len - 8);
  191. buffer[8..].copy_from_slice(&iphc.payload()[udp_repr.header_len()..]);
  192. }
  193. }
  194. }
  195. SixlowpanNextHeader::Uncompressed(_) => {
  196. // For uncompressed headers we just copy the slice.
  197. let len = iphc.payload().len();
  198. buffer[..len].copy_from_slice(iphc.payload());
  199. }
  200. };
  201. Ok(decompressed_size)
  202. }
  203. pub(super) fn dispatch_sixlowpan<Tx: TxToken>(
  204. &mut self,
  205. mut tx_token: Tx,
  206. meta: PacketMeta,
  207. packet: IpPacket,
  208. ieee_repr: Ieee802154Repr,
  209. frag: &mut Fragmenter,
  210. ) {
  211. let ip_repr = packet.ip_repr();
  212. let (src_addr, dst_addr) = match (ip_repr.src_addr(), ip_repr.dst_addr()) {
  213. (IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => (src_addr, dst_addr),
  214. #[allow(unreachable_patterns)]
  215. _ => {
  216. unreachable!()
  217. }
  218. };
  219. // Create the 6LoWPAN IPHC header.
  220. let iphc_repr = SixlowpanIphcRepr {
  221. src_addr,
  222. ll_src_addr: ieee_repr.src_addr,
  223. dst_addr,
  224. ll_dst_addr: ieee_repr.dst_addr,
  225. next_header: match &packet.payload() {
  226. IpPayload::Icmpv6(..) => SixlowpanNextHeader::Uncompressed(IpProtocol::Icmpv6),
  227. #[cfg(feature = "socket-tcp")]
  228. IpPayload::Tcp(..) => SixlowpanNextHeader::Uncompressed(IpProtocol::Tcp),
  229. #[cfg(feature = "socket-udp")]
  230. IpPayload::Udp(..) => SixlowpanNextHeader::Compressed,
  231. #[allow(unreachable_patterns)]
  232. _ => {
  233. net_debug!("dispatch_ieee802154: dropping, unhandled protocol.");
  234. return;
  235. }
  236. },
  237. hop_limit: ip_repr.hop_limit(),
  238. ecn: None,
  239. dscp: None,
  240. flow_label: None,
  241. };
  242. // Now we calculate the total size of the packet.
  243. // We need to know this, such that we know when to do the fragmentation.
  244. let mut total_size = 0;
  245. total_size += iphc_repr.buffer_len();
  246. let mut _compressed_headers_len = iphc_repr.buffer_len();
  247. let mut _uncompressed_headers_len = ip_repr.header_len();
  248. match packet.payload() {
  249. #[cfg(feature = "socket-udp")]
  250. IpPayload::Udp(udpv6_repr, payload) => {
  251. let udp_repr = SixlowpanUdpNhcRepr(*udpv6_repr);
  252. _compressed_headers_len += udp_repr.header_len();
  253. _uncompressed_headers_len += udpv6_repr.header_len();
  254. total_size += udp_repr.header_len() + payload.len();
  255. }
  256. #[cfg(feature = "socket-tcp")]
  257. IpPayload::Tcp(tcp_repr) => {
  258. total_size += tcp_repr.buffer_len();
  259. }
  260. #[cfg(feature = "proto-ipv6")]
  261. IpPayload::Icmpv6(icmp_repr) => {
  262. total_size += icmp_repr.buffer_len();
  263. }
  264. #[allow(unreachable_patterns)]
  265. _ => unreachable!(),
  266. }
  267. let ieee_len = ieee_repr.buffer_len();
  268. if total_size + ieee_len > 125 {
  269. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  270. {
  271. // The packet does not fit in one Ieee802154 frame, so we need fragmentation.
  272. // We do this by emitting everything in the `frag.buffer` from the interface.
  273. // After emitting everything into that buffer, we send the first fragment heere.
  274. // When `poll` is called again, we check if frag was fully sent, otherwise we
  275. // call `dispatch_ieee802154_frag`, which will transmit the other fragments.
  276. // `dispatch_ieee802154_frag` requires some information about the total packet size,
  277. // the link local source and destination address...
  278. let pkt = frag;
  279. if pkt.buffer.len() < total_size {
  280. net_debug!(
  281. "dispatch_ieee802154: dropping, \
  282. fragmentation buffer is too small, at least {} needed",
  283. total_size
  284. );
  285. return;
  286. }
  287. pkt.sixlowpan.ll_dst_addr = ieee_repr.dst_addr.unwrap();
  288. pkt.sixlowpan.ll_src_addr = ieee_repr.src_addr.unwrap();
  289. let mut iphc_packet =
  290. SixlowpanIphcPacket::new_unchecked(&mut pkt.buffer[..iphc_repr.buffer_len()]);
  291. iphc_repr.emit(&mut iphc_packet);
  292. let b = &mut pkt.buffer[iphc_repr.buffer_len()..];
  293. match packet.payload() {
  294. #[cfg(feature = "socket-udp")]
  295. IpPayload::Udp(udpv6_repr, payload) => {
  296. let udp_repr = SixlowpanUdpNhcRepr(*udpv6_repr);
  297. let mut udp_packet = SixlowpanUdpNhcPacket::new_unchecked(
  298. &mut b[..udp_repr.header_len() + payload.len()],
  299. );
  300. udp_repr.emit(
  301. &mut udp_packet,
  302. &iphc_repr.src_addr,
  303. &iphc_repr.dst_addr,
  304. payload.len(),
  305. |buf| buf.copy_from_slice(payload),
  306. );
  307. }
  308. #[cfg(feature = "socket-tcp")]
  309. IpPayload::Tcp(tcp_repr) => {
  310. let mut tcp_packet =
  311. TcpPacket::new_unchecked(&mut b[..tcp_repr.buffer_len()]);
  312. tcp_repr.emit(
  313. &mut tcp_packet,
  314. &iphc_repr.src_addr.into(),
  315. &iphc_repr.dst_addr.into(),
  316. &self.caps.checksum,
  317. );
  318. }
  319. #[cfg(feature = "proto-ipv6")]
  320. IpPayload::Icmpv6(icmp_repr) => {
  321. let mut icmp_packet =
  322. Icmpv6Packet::new_unchecked(&mut b[..icmp_repr.buffer_len()]);
  323. icmp_repr.emit(
  324. &iphc_repr.src_addr.into(),
  325. &iphc_repr.dst_addr.into(),
  326. &mut icmp_packet,
  327. &self.caps.checksum,
  328. );
  329. }
  330. #[allow(unreachable_patterns)]
  331. _ => unreachable!(),
  332. }
  333. pkt.packet_len = total_size;
  334. // The datagram size that we need to set in the first fragment header is equal to the
  335. // IPv6 payload length + 40.
  336. pkt.sixlowpan.datagram_size = (packet.ip_repr().payload_len() + 40) as u16;
  337. // We generate a random tag.
  338. let tag = self.get_sixlowpan_fragment_tag();
  339. // We save the tag for the other fragments that will be created when calling `poll`
  340. // multiple times.
  341. pkt.sixlowpan.datagram_tag = tag;
  342. let frag1 = SixlowpanFragRepr::FirstFragment {
  343. size: pkt.sixlowpan.datagram_size,
  344. tag,
  345. };
  346. let fragn = SixlowpanFragRepr::Fragment {
  347. size: pkt.sixlowpan.datagram_size,
  348. tag,
  349. offset: 0,
  350. };
  351. // We calculate how much data we can send in the first fragment and the other
  352. // fragments. The eventual IPv6 sizes of these fragments need to be a multiple of eight
  353. // (except for the last fragment) since the offset field in the fragment is an offset
  354. // in multiples of 8 octets. This is explained in [RFC 4944 § 5.3].
  355. //
  356. // [RFC 4944 § 5.3]: https://datatracker.ietf.org/doc/html/rfc4944#section-5.3
  357. let header_diff = _uncompressed_headers_len - _compressed_headers_len;
  358. let frag1_size =
  359. (125 - ieee_len - frag1.buffer_len() + header_diff) / 8 * 8 - (header_diff);
  360. pkt.sixlowpan.fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
  361. pkt.sent_bytes = frag1_size;
  362. pkt.sixlowpan.datagram_offset = frag1_size + header_diff;
  363. tx_token.consume(ieee_len + frag1.buffer_len() + frag1_size, |mut tx_buf| {
  364. // Add the IEEE header.
  365. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  366. ieee_repr.emit(&mut ieee_packet);
  367. tx_buf = &mut tx_buf[ieee_len..];
  368. // Add the first fragment header
  369. let mut frag1_packet = SixlowpanFragPacket::new_unchecked(&mut tx_buf);
  370. frag1.emit(&mut frag1_packet);
  371. tx_buf = &mut tx_buf[frag1.buffer_len()..];
  372. // Add the buffer part.
  373. tx_buf[..frag1_size].copy_from_slice(&pkt.buffer[..frag1_size]);
  374. });
  375. }
  376. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  377. {
  378. net_debug!(
  379. "Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support."
  380. );
  381. return;
  382. }
  383. } else {
  384. tx_token.set_meta(meta);
  385. // We don't need fragmentation, so we emit everything to the TX token.
  386. tx_token.consume(total_size + ieee_len, |mut tx_buf| {
  387. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  388. ieee_repr.emit(&mut ieee_packet);
  389. tx_buf = &mut tx_buf[ieee_len..];
  390. let mut iphc_packet =
  391. SixlowpanIphcPacket::new_unchecked(&mut tx_buf[..iphc_repr.buffer_len()]);
  392. iphc_repr.emit(&mut iphc_packet);
  393. tx_buf = &mut tx_buf[iphc_repr.buffer_len()..];
  394. match packet.payload() {
  395. #[cfg(feature = "socket-udp")]
  396. IpPayload::Udp(udpv6_repr, payload) => {
  397. let udp_repr = SixlowpanUdpNhcRepr(*udpv6_repr);
  398. let mut udp_packet = SixlowpanUdpNhcPacket::new_unchecked(
  399. &mut tx_buf[..udp_repr.header_len() + payload.len()],
  400. );
  401. udp_repr.emit(
  402. &mut udp_packet,
  403. &iphc_repr.src_addr,
  404. &iphc_repr.dst_addr,
  405. payload.len(),
  406. |buf| buf.copy_from_slice(payload),
  407. );
  408. }
  409. #[cfg(feature = "socket-tcp")]
  410. IpPayload::Tcp(tcp_repr) => {
  411. let mut tcp_packet =
  412. TcpPacket::new_unchecked(&mut tx_buf[..tcp_repr.buffer_len()]);
  413. tcp_repr.emit(
  414. &mut tcp_packet,
  415. &iphc_repr.src_addr.into(),
  416. &iphc_repr.dst_addr.into(),
  417. &self.caps.checksum,
  418. );
  419. }
  420. #[cfg(feature = "proto-ipv6")]
  421. IpPayload::Icmpv6(icmp_repr) => {
  422. let mut icmp_packet =
  423. Icmpv6Packet::new_unchecked(&mut tx_buf[..icmp_repr.buffer_len()]);
  424. icmp_repr.emit(
  425. &iphc_repr.src_addr.into(),
  426. &iphc_repr.dst_addr.into(),
  427. &mut icmp_packet,
  428. &self.caps.checksum,
  429. );
  430. }
  431. #[allow(unreachable_patterns)]
  432. _ => unreachable!(),
  433. }
  434. });
  435. }
  436. }
  437. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  438. pub(super) fn dispatch_sixlowpan_frag<Tx: TxToken>(
  439. &mut self,
  440. tx_token: Tx,
  441. ieee_repr: Ieee802154Repr,
  442. frag: &mut Fragmenter,
  443. ) {
  444. // Create the FRAG_N header.
  445. let fragn = SixlowpanFragRepr::Fragment {
  446. size: frag.sixlowpan.datagram_size,
  447. tag: frag.sixlowpan.datagram_tag,
  448. offset: (frag.sixlowpan.datagram_offset / 8) as u8,
  449. };
  450. let ieee_len = ieee_repr.buffer_len();
  451. let frag_size = (frag.packet_len - frag.sent_bytes).min(frag.sixlowpan.fragn_size);
  452. tx_token.consume(
  453. ieee_repr.buffer_len() + fragn.buffer_len() + frag_size,
  454. |mut tx_buf| {
  455. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  456. ieee_repr.emit(&mut ieee_packet);
  457. tx_buf = &mut tx_buf[ieee_len..];
  458. let mut frag_packet =
  459. SixlowpanFragPacket::new_unchecked(&mut tx_buf[..fragn.buffer_len()]);
  460. fragn.emit(&mut frag_packet);
  461. tx_buf = &mut tx_buf[fragn.buffer_len()..];
  462. // Add the buffer part
  463. tx_buf[..frag_size].copy_from_slice(&frag.buffer[frag.sent_bytes..][..frag_size]);
  464. frag.sent_bytes += frag_size;
  465. frag.sixlowpan.datagram_offset += frag_size;
  466. },
  467. );
  468. }
  469. }