sixlowpan.rs 37 KB

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