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