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