sixlowpan.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. use super::check;
  2. use super::FragmentsBuffer;
  3. use super::InterfaceInner;
  4. use super::IpPacket;
  5. use super::OutPackets;
  6. use super::PacketAssemblerSet;
  7. use super::SocketSet;
  8. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  9. use super::SixlowpanOutPacket;
  10. use crate::phy::TxToken;
  11. use crate::time::*;
  12. use crate::wire::*;
  13. use crate::Error;
  14. use crate::Result;
  15. impl<'a> InterfaceInner<'a> {
  16. #[cfg(feature = "medium-ieee802154")]
  17. pub(super) fn process_ieee802154<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
  18. &mut self,
  19. sockets: &mut SocketSet,
  20. sixlowpan_payload: &'payload T,
  21. _fragments: &'output mut FragmentsBuffer<'a>,
  22. ) -> Option<IpPacket<'output>> {
  23. let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
  24. let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
  25. if ieee802154_repr.frame_type != Ieee802154FrameType::Data {
  26. return None;
  27. }
  28. // Drop frames when the user has set a PAN id and the PAN id from frame is not equal to this
  29. // When the user didn't set a PAN id (so it is None), then we accept all PAN id's.
  30. // We always accept the broadcast PAN id.
  31. if self.pan_id.is_some()
  32. && ieee802154_repr.dst_pan_id != self.pan_id
  33. && ieee802154_repr.dst_pan_id != Some(Ieee802154Pan::BROADCAST)
  34. {
  35. net_debug!(
  36. "IEEE802.15.4: dropping {:?} because not our PAN id (or not broadcast)",
  37. ieee802154_repr
  38. );
  39. return None;
  40. }
  41. match ieee802154_frame.payload() {
  42. Some(payload) => {
  43. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  44. {
  45. self.process_sixlowpan(
  46. sockets,
  47. &ieee802154_repr,
  48. payload,
  49. Some((
  50. &mut _fragments.sixlowpan_fragments,
  51. _fragments.sixlowpan_fragments_cache_timeout,
  52. )),
  53. )
  54. }
  55. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  56. {
  57. self.process_sixlowpan(sockets, &ieee802154_repr, payload, None)
  58. }
  59. }
  60. None => None,
  61. }
  62. }
  63. pub(super) fn process_sixlowpan<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
  64. &mut self,
  65. sockets: &mut SocketSet,
  66. ieee802154_repr: &Ieee802154Repr,
  67. payload: &'payload T,
  68. _fragments: Option<(
  69. &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
  70. Duration,
  71. )>,
  72. ) -> Option<IpPacket<'output>> {
  73. let payload = match check!(SixlowpanPacket::dispatch(payload)) {
  74. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  75. SixlowpanPacket::FragmentHeader => {
  76. net_debug!("Fragmentation is not supported, use the `proto-sixlowpan-fragmentation` feature to add support.");
  77. return None;
  78. }
  79. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  80. SixlowpanPacket::FragmentHeader => {
  81. match self.process_sixlowpan_fragment(ieee802154_repr, payload, _fragments) {
  82. Some(payload) => payload,
  83. None => return None,
  84. }
  85. }
  86. SixlowpanPacket::IphcHeader => payload.as_ref(),
  87. };
  88. // At this point we should have a valid 6LoWPAN packet.
  89. // The first header needs to be an IPHC header.
  90. let iphc_packet = check!(SixlowpanIphcPacket::new_checked(payload));
  91. let iphc_repr = check!(SixlowpanIphcRepr::parse(
  92. &iphc_packet,
  93. ieee802154_repr.src_addr,
  94. ieee802154_repr.dst_addr,
  95. self.sixlowpan_address_context,
  96. ));
  97. let payload = iphc_packet.payload();
  98. let mut ipv6_repr = Ipv6Repr {
  99. src_addr: iphc_repr.src_addr,
  100. dst_addr: iphc_repr.dst_addr,
  101. hop_limit: iphc_repr.hop_limit,
  102. next_header: IpProtocol::Unknown(0),
  103. payload_len: 40,
  104. };
  105. match iphc_repr.next_header {
  106. SixlowpanNextHeader::Compressed => {
  107. match check!(SixlowpanNhcPacket::dispatch(payload)) {
  108. SixlowpanNhcPacket::ExtHeader => {
  109. net_debug!("Extension headers are currently not supported for 6LoWPAN");
  110. None
  111. }
  112. #[cfg(not(feature = "socket-udp"))]
  113. SixlowpanNhcPacket::UdpHeader => {
  114. net_debug!("UDP support is disabled, enable cargo feature `socket-udp`.");
  115. None
  116. }
  117. #[cfg(feature = "socket-udp")]
  118. SixlowpanNhcPacket::UdpHeader => {
  119. let udp_packet = check!(SixlowpanUdpNhcPacket::new_checked(payload));
  120. ipv6_repr.next_header = IpProtocol::Udp;
  121. ipv6_repr.payload_len += 8 + udp_packet.payload().len();
  122. let udp_repr = check!(SixlowpanUdpNhcRepr::parse(
  123. &udp_packet,
  124. &iphc_repr.src_addr,
  125. &iphc_repr.dst_addr,
  126. &self.checksum_caps(),
  127. ));
  128. self.process_udp(
  129. sockets,
  130. IpRepr::Ipv6(ipv6_repr),
  131. udp_repr.0,
  132. false,
  133. udp_packet.payload(),
  134. payload,
  135. )
  136. }
  137. }
  138. }
  139. SixlowpanNextHeader::Uncompressed(nxt_hdr) => match nxt_hdr {
  140. IpProtocol::Icmpv6 => {
  141. ipv6_repr.next_header = IpProtocol::Icmpv6;
  142. self.process_icmpv6(sockets, IpRepr::Ipv6(ipv6_repr), iphc_packet.payload())
  143. }
  144. #[cfg(feature = "socket-tcp")]
  145. IpProtocol::Tcp => {
  146. ipv6_repr.next_header = nxt_hdr;
  147. ipv6_repr.payload_len += payload.len();
  148. self.process_tcp(sockets, IpRepr::Ipv6(ipv6_repr), iphc_packet.payload())
  149. }
  150. proto => {
  151. net_debug!("6LoWPAN: {} currently not supported", proto);
  152. None
  153. }
  154. },
  155. }
  156. }
  157. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  158. fn process_sixlowpan_fragment<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
  159. &mut self,
  160. ieee802154_repr: &Ieee802154Repr,
  161. payload: &'payload T,
  162. fragments: Option<(
  163. &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
  164. Duration,
  165. )>,
  166. ) -> Option<&'output [u8]> {
  167. let (fragments, timeout) = fragments.unwrap();
  168. // We have a fragment header, which means we cannot process the 6LoWPAN packet,
  169. // unless we have a complete one after processing this fragment.
  170. let frag = check!(SixlowpanFragPacket::new_checked(payload));
  171. // The key specifies to which 6LoWPAN fragment it belongs too.
  172. // It is based on the link layer addresses, the tag and the size.
  173. let key = frag.get_key(ieee802154_repr);
  174. // The offset of this fragment in increments of 8 octets.
  175. let offset = frag.datagram_offset() as usize * 8;
  176. if frag.is_first_fragment() {
  177. // The first fragment contains the total size of the IPv6 packet.
  178. // However, we received a packet that is compressed following the 6LoWPAN
  179. // standard. This means we need to convert the IPv6 packet size to a 6LoWPAN
  180. // packet size. The packet size can be different because of first the
  181. // compression of the IP header and when UDP is used (because the UDP header
  182. // can also be compressed). Other headers are not compressed by 6LoWPAN.
  183. let iphc = check!(SixlowpanIphcPacket::new_checked(frag.payload()));
  184. let iphc_repr = check!(SixlowpanIphcRepr::parse(
  185. &iphc,
  186. ieee802154_repr.src_addr,
  187. ieee802154_repr.dst_addr,
  188. self.sixlowpan_address_context,
  189. ));
  190. // The uncompressed header size always starts with 40, since this is the size
  191. // of a IPv6 header.
  192. let mut uncompressed_header_size = 40;
  193. let mut compressed_header_size = iphc.header_len();
  194. // We need to check if we have an UDP packet, since this header can also be
  195. // compressed by 6LoWPAN. We currently don't support extension headers yet.
  196. match iphc_repr.next_header {
  197. SixlowpanNextHeader::Compressed => {
  198. match check!(SixlowpanNhcPacket::dispatch(iphc.payload())) {
  199. SixlowpanNhcPacket::ExtHeader => {
  200. net_debug!("6LoWPAN: extension headers not supported");
  201. return None;
  202. }
  203. SixlowpanNhcPacket::UdpHeader => {
  204. let udp_packet =
  205. check!(SixlowpanUdpNhcPacket::new_checked(iphc.payload()));
  206. uncompressed_header_size += 8;
  207. compressed_header_size +=
  208. 1 + udp_packet.ports_size() + udp_packet.checksum_size();
  209. }
  210. }
  211. }
  212. SixlowpanNextHeader::Uncompressed(_) => (),
  213. }
  214. // We reserve a spot in the packet assembler set and add the required
  215. // information to the packet assembler.
  216. // This information is the total size of the packet when it is fully assmbled.
  217. // We also pass the header size, since this is needed when other fragments
  218. // (other than the first one) are added.
  219. let frag_slot = match fragments.reserve_with_key(&key) {
  220. Ok(frag) => frag,
  221. Err(Error::PacketAssemblerSetFull) => {
  222. net_debug!("No available packet assembler for fragmented packet");
  223. return Default::default();
  224. }
  225. e => check!(e),
  226. };
  227. check!(frag_slot.start(
  228. Some(
  229. frag.datagram_size() as usize - uncompressed_header_size
  230. + compressed_header_size
  231. ),
  232. self.now + timeout,
  233. -((uncompressed_header_size - compressed_header_size) as isize),
  234. ));
  235. }
  236. let frags = check!(fragments.get_packet_assembler_mut(&key));
  237. net_trace!("6LoWPAN: received packet fragment");
  238. // Add the fragment to the packet assembler.
  239. match frags.add(frag.payload(), offset) {
  240. Ok(true) => {
  241. net_trace!("6LoWPAN: fragmented packet now complete");
  242. match fragments.get_assembled_packet(&key) {
  243. Ok(packet) => Some(packet),
  244. _ => unreachable!(),
  245. }
  246. }
  247. Ok(false) => None,
  248. Err(Error::PacketAssemblerOverlap) => {
  249. net_trace!("6LoWPAN: overlap in packet");
  250. frags.mark_discarded();
  251. None
  252. }
  253. Err(_) => None,
  254. }
  255. }
  256. #[cfg(feature = "medium-ieee802154")]
  257. pub(super) fn dispatch_ieee802154<Tx: TxToken>(
  258. &mut self,
  259. ll_dst_a: Ieee802154Address,
  260. tx_token: Tx,
  261. packet: IpPacket,
  262. _out_packet: Option<&mut OutPackets>,
  263. ) -> Result<()> {
  264. // We first need to convert the IPv6 packet to a 6LoWPAN compressed packet.
  265. // Whenever this packet is to big to fit in the IEEE802.15.4 packet, then we need to
  266. // fragment it.
  267. let ll_src_a = self.hardware_addr.map_or_else(
  268. || Err(Error::Malformed),
  269. |addr| match addr {
  270. HardwareAddress::Ieee802154(addr) => Ok(addr),
  271. _ => Err(Error::Malformed),
  272. },
  273. )?;
  274. let ip_repr = packet.ip_repr();
  275. let (src_addr, dst_addr) = match (ip_repr.src_addr(), ip_repr.dst_addr()) {
  276. (IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => (src_addr, dst_addr),
  277. #[allow(unreachable_patterns)]
  278. _ => return Err(Error::Unaddressable),
  279. };
  280. // Create the IEEE802.15.4 header.
  281. let ieee_repr = Ieee802154Repr {
  282. frame_type: Ieee802154FrameType::Data,
  283. security_enabled: false,
  284. frame_pending: false,
  285. ack_request: false,
  286. sequence_number: Some(self.get_sequence_number()),
  287. pan_id_compression: true,
  288. frame_version: Ieee802154FrameVersion::Ieee802154_2003,
  289. dst_pan_id: self.pan_id,
  290. dst_addr: Some(ll_dst_a),
  291. src_pan_id: self.pan_id,
  292. src_addr: Some(ll_src_a),
  293. };
  294. // Create the 6LoWPAN IPHC header.
  295. let iphc_repr = SixlowpanIphcRepr {
  296. src_addr,
  297. ll_src_addr: Some(ll_src_a),
  298. dst_addr,
  299. ll_dst_addr: Some(ll_dst_a),
  300. next_header: match &packet {
  301. IpPacket::Icmpv6(_) => SixlowpanNextHeader::Uncompressed(IpProtocol::Icmpv6),
  302. #[cfg(feature = "socket-tcp")]
  303. IpPacket::Tcp(_) => SixlowpanNextHeader::Uncompressed(IpProtocol::Tcp),
  304. #[cfg(feature = "socket-udp")]
  305. IpPacket::Udp(_) => SixlowpanNextHeader::Compressed,
  306. #[allow(unreachable_patterns)]
  307. _ => return Err(Error::Unrecognized),
  308. },
  309. hop_limit: ip_repr.hop_limit(),
  310. ecn: None,
  311. dscp: None,
  312. flow_label: None,
  313. };
  314. // Now we calculate the total size of the packet.
  315. // We need to know this, such that we know when to do the fragmentation.
  316. let mut total_size = 0;
  317. total_size += iphc_repr.buffer_len();
  318. let mut _compressed_headers_len = iphc_repr.buffer_len();
  319. let mut _uncompressed_headers_len = ip_repr.header_len();
  320. #[allow(unreachable_patterns)]
  321. match packet {
  322. #[cfg(feature = "socket-udp")]
  323. IpPacket::Udp((_, udpv6_repr, payload)) => {
  324. let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
  325. _compressed_headers_len += udp_repr.header_len();
  326. _uncompressed_headers_len += udpv6_repr.header_len();
  327. total_size += udp_repr.header_len() + payload.len();
  328. }
  329. #[cfg(feature = "socket-tcp")]
  330. IpPacket::Tcp((_, tcp_repr)) => {
  331. total_size += tcp_repr.buffer_len();
  332. }
  333. #[cfg(feature = "proto-ipv6")]
  334. IpPacket::Icmpv6((_, icmp_repr)) => {
  335. total_size += icmp_repr.buffer_len();
  336. }
  337. _ => return Err(Error::Unrecognized),
  338. }
  339. let ieee_len = ieee_repr.buffer_len();
  340. if total_size + ieee_len > 125 {
  341. #[cfg(feature = "proto-sixlowpan-fragmentation")]
  342. {
  343. // The packet does not fit in one Ieee802154 frame, so we need fragmentation.
  344. // We do this by emitting everything in the `out_packet.buffer` from the interface.
  345. // After emitting everything into that buffer, we send the first fragment heere.
  346. // When `poll` is called again, we check if out_packet was fully sent, otherwise we
  347. // call `dispatch_ieee802154_out_packet`, which will transmit the other fragments.
  348. // `dispatch_ieee802154_out_packet` requires some information about the total packet size,
  349. // the link local source and destination address...
  350. let SixlowpanOutPacket {
  351. buffer,
  352. packet_len,
  353. datagram_size,
  354. datagram_tag,
  355. sent_bytes,
  356. fragn_size,
  357. ll_dst_addr,
  358. ll_src_addr,
  359. datagram_offset,
  360. ..
  361. } = &mut _out_packet.unwrap().sixlowpan_out_packet;
  362. match buffer {
  363. managed::ManagedSlice::Borrowed(buffer) => {
  364. if buffer.len() < total_size {
  365. net_debug!(
  366. "6LoWPAN: Fragmentation buffer is too small, at least {} needed",
  367. total_size
  368. );
  369. return Err(Error::Exhausted);
  370. }
  371. }
  372. #[cfg(feature = "alloc")]
  373. managed::ManagedSlice::Owned(buffer) => buffer.resize(total_size, 0),
  374. }
  375. *ll_dst_addr = ll_dst_a;
  376. *ll_src_addr = ll_src_a;
  377. let mut iphc_packet =
  378. SixlowpanIphcPacket::new_unchecked(&mut buffer[..iphc_repr.buffer_len()]);
  379. iphc_repr.emit(&mut iphc_packet);
  380. let b = &mut buffer[iphc_repr.buffer_len()..];
  381. #[allow(unreachable_patterns)]
  382. match packet {
  383. #[cfg(feature = "socket-udp")]
  384. IpPacket::Udp((_, udpv6_repr, payload)) => {
  385. let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
  386. let mut udp_packet = SixlowpanUdpNhcPacket::new_unchecked(
  387. &mut b[..udp_repr.header_len() + payload.len()],
  388. );
  389. udp_repr.emit(
  390. &mut udp_packet,
  391. &iphc_repr.src_addr,
  392. &iphc_repr.dst_addr,
  393. payload.len(),
  394. |buf| buf.copy_from_slice(payload),
  395. );
  396. }
  397. #[cfg(feature = "socket-tcp")]
  398. IpPacket::Tcp((_, tcp_repr)) => {
  399. let mut tcp_packet =
  400. TcpPacket::new_unchecked(&mut b[..tcp_repr.buffer_len()]);
  401. tcp_repr.emit(
  402. &mut tcp_packet,
  403. &iphc_repr.src_addr.into(),
  404. &iphc_repr.dst_addr.into(),
  405. &self.caps.checksum,
  406. );
  407. }
  408. #[cfg(feature = "proto-ipv6")]
  409. IpPacket::Icmpv6((_, icmp_repr)) => {
  410. let mut icmp_packet =
  411. Icmpv6Packet::new_unchecked(&mut b[..icmp_repr.buffer_len()]);
  412. icmp_repr.emit(
  413. &iphc_repr.src_addr.into(),
  414. &iphc_repr.dst_addr.into(),
  415. &mut icmp_packet,
  416. &self.caps.checksum,
  417. );
  418. }
  419. _ => return Err(Error::Unrecognized),
  420. }
  421. *packet_len = total_size;
  422. // The datagram size that we need to set in the first fragment header is equal to the
  423. // IPv6 payload length + 40.
  424. *datagram_size = (packet.ip_repr().payload_len() + 40) as u16;
  425. // We generate a random tag.
  426. let tag = self.get_sixlowpan_fragment_tag();
  427. // We save the tag for the other fragments that will be created when calling `poll`
  428. // multiple times.
  429. *datagram_tag = tag;
  430. let frag1 = SixlowpanFragRepr::FirstFragment {
  431. size: *datagram_size,
  432. tag,
  433. };
  434. let fragn = SixlowpanFragRepr::Fragment {
  435. size: *datagram_size,
  436. tag,
  437. offset: 0,
  438. };
  439. // We calculate how much data we can send in the first fragment and the other
  440. // fragments. The eventual IPv6 sizes of these fragments need to be a multiple of eight
  441. // (except for the last fragment) since the offset field in the fragment is an offset
  442. // in multiples of 8 octets. This is explained in [RFC 4944 § 5.3].
  443. //
  444. // [RFC 4944 § 5.3]: https://datatracker.ietf.org/doc/html/rfc4944#section-5.3
  445. let header_diff = _uncompressed_headers_len - _compressed_headers_len;
  446. let frag1_size =
  447. (125 - ieee_len - frag1.buffer_len() + header_diff) / 8 * 8 - (header_diff);
  448. *fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
  449. *sent_bytes = frag1_size;
  450. *datagram_offset = frag1_size + header_diff;
  451. tx_token.consume(
  452. self.now,
  453. ieee_len + frag1.buffer_len() + frag1_size,
  454. |mut tx_buf| {
  455. // Add the IEEE header.
  456. let mut ieee_packet =
  457. Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  458. ieee_repr.emit(&mut ieee_packet);
  459. tx_buf = &mut tx_buf[ieee_len..];
  460. // Add the first fragment header
  461. let mut frag1_packet = SixlowpanFragPacket::new_unchecked(&mut tx_buf);
  462. frag1.emit(&mut frag1_packet);
  463. tx_buf = &mut tx_buf[frag1.buffer_len()..];
  464. // Add the buffer part.
  465. tx_buf[..frag1_size].copy_from_slice(&buffer[..frag1_size]);
  466. Ok(())
  467. },
  468. )
  469. }
  470. #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
  471. {
  472. net_debug!(
  473. "Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support."
  474. );
  475. Ok(())
  476. }
  477. } else {
  478. // We don't need fragmentation, so we emit everything to the TX token.
  479. tx_token.consume(self.now, total_size + ieee_len, |mut tx_buf| {
  480. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  481. ieee_repr.emit(&mut ieee_packet);
  482. tx_buf = &mut tx_buf[ieee_len..];
  483. let mut iphc_packet =
  484. SixlowpanIphcPacket::new_unchecked(&mut tx_buf[..iphc_repr.buffer_len()]);
  485. iphc_repr.emit(&mut iphc_packet);
  486. tx_buf = &mut tx_buf[iphc_repr.buffer_len()..];
  487. #[allow(unreachable_patterns)]
  488. match packet {
  489. #[cfg(feature = "socket-udp")]
  490. IpPacket::Udp((_, udpv6_repr, payload)) => {
  491. let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
  492. let mut udp_packet = SixlowpanUdpNhcPacket::new_unchecked(
  493. &mut tx_buf[..udp_repr.header_len() + payload.len()],
  494. );
  495. udp_repr.emit(
  496. &mut udp_packet,
  497. &iphc_repr.src_addr,
  498. &iphc_repr.dst_addr,
  499. payload.len(),
  500. |buf| buf.copy_from_slice(payload),
  501. );
  502. }
  503. #[cfg(feature = "socket-tcp")]
  504. IpPacket::Tcp((_, tcp_repr)) => {
  505. let mut tcp_packet =
  506. TcpPacket::new_unchecked(&mut tx_buf[..tcp_repr.buffer_len()]);
  507. tcp_repr.emit(
  508. &mut tcp_packet,
  509. &iphc_repr.src_addr.into(),
  510. &iphc_repr.dst_addr.into(),
  511. &self.caps.checksum,
  512. );
  513. }
  514. #[cfg(feature = "proto-ipv6")]
  515. IpPacket::Icmpv6((_, icmp_repr)) => {
  516. let mut icmp_packet =
  517. Icmpv6Packet::new_unchecked(&mut tx_buf[..icmp_repr.buffer_len()]);
  518. icmp_repr.emit(
  519. &iphc_repr.src_addr.into(),
  520. &iphc_repr.dst_addr.into(),
  521. &mut icmp_packet,
  522. &self.caps.checksum,
  523. );
  524. }
  525. _ => return Err(Error::Unrecognized),
  526. }
  527. Ok(())
  528. })
  529. }
  530. }
  531. #[cfg(all(
  532. feature = "medium-ieee802154",
  533. feature = "proto-sixlowpan-fragmentation"
  534. ))]
  535. pub(super) fn dispatch_ieee802154_out_packet<Tx: TxToken>(
  536. &mut self,
  537. tx_token: Tx,
  538. out_packet: &mut SixlowpanOutPacket,
  539. ) -> Result<()> {
  540. let SixlowpanOutPacket {
  541. buffer,
  542. packet_len,
  543. datagram_size,
  544. datagram_tag,
  545. datagram_offset,
  546. sent_bytes,
  547. fragn_size,
  548. ll_dst_addr,
  549. ll_src_addr,
  550. ..
  551. } = out_packet;
  552. // Create the IEEE802.15.4 header.
  553. let ieee_repr = Ieee802154Repr {
  554. frame_type: Ieee802154FrameType::Data,
  555. security_enabled: false,
  556. frame_pending: false,
  557. ack_request: false,
  558. sequence_number: Some(self.get_sequence_number()),
  559. pan_id_compression: true,
  560. frame_version: Ieee802154FrameVersion::Ieee802154_2003,
  561. dst_pan_id: self.pan_id,
  562. dst_addr: Some(*ll_dst_addr),
  563. src_pan_id: self.pan_id,
  564. src_addr: Some(*ll_src_addr),
  565. };
  566. // Create the FRAG_N header.
  567. let fragn = SixlowpanFragRepr::Fragment {
  568. size: *datagram_size,
  569. tag: *datagram_tag,
  570. offset: (*datagram_offset / 8) as u8,
  571. };
  572. let ieee_len = ieee_repr.buffer_len();
  573. let frag_size = (*packet_len - *sent_bytes).min(*fragn_size);
  574. tx_token.consume(
  575. self.now,
  576. ieee_repr.buffer_len() + fragn.buffer_len() + frag_size,
  577. |mut tx_buf| {
  578. let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
  579. ieee_repr.emit(&mut ieee_packet);
  580. tx_buf = &mut tx_buf[ieee_len..];
  581. let mut frag_packet =
  582. SixlowpanFragPacket::new_unchecked(&mut tx_buf[..fragn.buffer_len()]);
  583. fragn.emit(&mut frag_packet);
  584. tx_buf = &mut tx_buf[fragn.buffer_len()..];
  585. // Add the buffer part
  586. tx_buf[..frag_size].copy_from_slice(&buffer[*sent_bytes..][..frag_size]);
  587. *sent_bytes += frag_size;
  588. *datagram_offset += frag_size;
  589. Ok(())
  590. },
  591. )
  592. }
  593. }