1 // Heads up! Before working on this file you should read the parts
2 // of RFC 1122 that discuss Ethernet, ARP and IP for any IPv4 work
3 // and RFCs 8200 and 4861 for any IPv6 and NDISC work.
4 
5 #[cfg(test)]
6 mod tests;
7 
8 #[cfg(feature = "medium-ethernet")]
9 mod ethernet;
10 #[cfg(feature = "proto-sixlowpan")]
11 mod sixlowpan;
12 
13 #[cfg(feature = "proto-ipv4")]
14 mod ipv4;
15 #[cfg(feature = "proto-ipv6")]
16 mod ipv6;
17 
18 #[cfg(feature = "proto-igmp")]
19 mod igmp;
20 
21 #[cfg(feature = "proto-igmp")]
22 pub use igmp::MulticastError;
23 
24 use core::cmp;
25 use core::result::Result;
26 use heapless::{LinearMap, Vec};
27 
28 #[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
29 use super::fragmentation::PacketAssemblerSet;
30 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
31 use super::neighbor::{Answer as NeighborAnswer, Cache as NeighborCache};
32 use super::socket_set::SocketSet;
33 use crate::config::{
34     FRAGMENTATION_BUFFER_SIZE, IFACE_MAX_ADDR_COUNT, IFACE_MAX_MULTICAST_GROUP_COUNT,
35     IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT,
36 };
37 use crate::iface::Routes;
38 use crate::phy::{ChecksumCapabilities, Device, DeviceCapabilities, Medium, RxToken, TxToken};
39 use crate::rand::Rand;
40 #[cfg(feature = "socket-dns")]
41 use crate::socket::dns;
42 use crate::socket::*;
43 use crate::time::{Duration, Instant};
44 use crate::wire::*;
45 
46 #[cfg(feature = "_proto-fragmentation")]
47 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
48 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
49 pub(crate) enum FragKey {
50     #[cfg(feature = "proto-ipv4-fragmentation")]
51     Ipv4(Ipv4FragKey),
52     #[cfg(feature = "proto-sixlowpan-fragmentation")]
53     Sixlowpan(SixlowpanFragKey),
54 }
55 
56 pub(crate) struct FragmentsBuffer {
57     #[cfg(feature = "proto-sixlowpan")]
58     decompress_buf: [u8; sixlowpan::MAX_DECOMPRESSED_LEN],
59 
60     #[cfg(feature = "_proto-fragmentation")]
61     pub(crate) assembler: PacketAssemblerSet<FragKey>,
62 
63     #[cfg(feature = "_proto-fragmentation")]
64     reassembly_timeout: Duration,
65 }
66 
67 #[cfg(not(feature = "_proto-fragmentation"))]
68 pub(crate) struct Fragmenter {}
69 
70 #[cfg(not(feature = "_proto-fragmentation"))]
71 impl Fragmenter {
new() -> Self72     pub(crate) fn new() -> Self {
73         Self {}
74     }
75 }
76 
77 #[cfg(feature = "_proto-fragmentation")]
78 pub(crate) struct Fragmenter {
79     /// The buffer that holds the unfragmented 6LoWPAN packet.
80     buffer: [u8; FRAGMENTATION_BUFFER_SIZE],
81     /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
82     packet_len: usize,
83     /// The amount of bytes that already have been transmitted.
84     sent_bytes: usize,
85 
86     #[cfg(feature = "proto-ipv4-fragmentation")]
87     ipv4: Ipv4Fragmenter,
88     #[cfg(feature = "proto-sixlowpan-fragmentation")]
89     sixlowpan: SixlowpanFragmenter,
90 }
91 
92 #[cfg(feature = "proto-ipv4-fragmentation")]
93 pub(crate) struct Ipv4Fragmenter {
94     /// The IPv4 representation.
95     repr: Ipv4Repr,
96     /// The destination hardware address.
97     #[cfg(feature = "medium-ethernet")]
98     dst_hardware_addr: EthernetAddress,
99     /// The offset of the next fragment.
100     frag_offset: u16,
101     /// The identifier of the stream.
102     ident: u16,
103 }
104 
105 #[cfg(feature = "proto-sixlowpan-fragmentation")]
106 pub(crate) struct SixlowpanFragmenter {
107     /// The datagram size that is used for the fragmentation headers.
108     datagram_size: u16,
109     /// The datagram tag that is used for the fragmentation headers.
110     datagram_tag: u16,
111     datagram_offset: usize,
112 
113     /// The size of the FRAG_N packets.
114     fragn_size: usize,
115 
116     /// The link layer IEEE802.15.4 source address.
117     ll_dst_addr: Ieee802154Address,
118     /// The link layer IEEE802.15.4 source address.
119     ll_src_addr: Ieee802154Address,
120 }
121 
122 #[cfg(feature = "_proto-fragmentation")]
123 impl Fragmenter {
new() -> Self124     pub(crate) fn new() -> Self {
125         Self {
126             buffer: [0u8; FRAGMENTATION_BUFFER_SIZE],
127             packet_len: 0,
128             sent_bytes: 0,
129 
130             #[cfg(feature = "proto-ipv4-fragmentation")]
131             ipv4: Ipv4Fragmenter {
132                 repr: Ipv4Repr {
133                     src_addr: Ipv4Address::default(),
134                     dst_addr: Ipv4Address::default(),
135                     next_header: IpProtocol::Unknown(0),
136                     payload_len: 0,
137                     hop_limit: 0,
138                 },
139                 #[cfg(feature = "medium-ethernet")]
140                 dst_hardware_addr: EthernetAddress::default(),
141                 frag_offset: 0,
142                 ident: 0,
143             },
144 
145             #[cfg(feature = "proto-sixlowpan-fragmentation")]
146             sixlowpan: SixlowpanFragmenter {
147                 datagram_size: 0,
148                 datagram_tag: 0,
149                 datagram_offset: 0,
150                 fragn_size: 0,
151                 ll_dst_addr: Ieee802154Address::Absent,
152                 ll_src_addr: Ieee802154Address::Absent,
153             },
154         }
155     }
156 
157     /// Return `true` when everything is transmitted.
158     #[inline]
finished(&self) -> bool159     fn finished(&self) -> bool {
160         self.packet_len == self.sent_bytes
161     }
162 
163     /// Returns `true` when there is nothing to transmit.
164     #[inline]
is_empty(&self) -> bool165     fn is_empty(&self) -> bool {
166         self.packet_len == 0
167     }
168 
169     // Reset the buffer.
reset(&mut self)170     fn reset(&mut self) {
171         self.packet_len = 0;
172         self.sent_bytes = 0;
173 
174         #[cfg(feature = "proto-ipv4-fragmentation")]
175         {
176             self.ipv4.repr = Ipv4Repr {
177                 src_addr: Ipv4Address::default(),
178                 dst_addr: Ipv4Address::default(),
179                 next_header: IpProtocol::Unknown(0),
180                 payload_len: 0,
181                 hop_limit: 0,
182             };
183             #[cfg(feature = "medium-ethernet")]
184             {
185                 self.ipv4.dst_hardware_addr = EthernetAddress::default();
186             }
187         }
188 
189         #[cfg(feature = "proto-sixlowpan-fragmentation")]
190         {
191             self.sixlowpan.datagram_size = 0;
192             self.sixlowpan.datagram_tag = 0;
193             self.sixlowpan.fragn_size = 0;
194             self.sixlowpan.ll_dst_addr = Ieee802154Address::Absent;
195             self.sixlowpan.ll_src_addr = Ieee802154Address::Absent;
196         }
197     }
198 }
199 
200 macro_rules! check {
201     ($e:expr) => {
202         match $e {
203             Ok(x) => x,
204             Err(_) => {
205                 // concat!/stringify! doesn't work with defmt macros
206                 #[cfg(not(feature = "defmt"))]
207                 net_trace!(concat!("iface: malformed ", stringify!($e)));
208                 #[cfg(feature = "defmt")]
209                 net_trace!("iface: malformed");
210                 return Default::default();
211             }
212         }
213     };
214 }
215 use check;
216 
217 /// A  network interface.
218 ///
219 /// The network interface logically owns a number of other data structures; to avoid
220 /// a dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
221 /// a `&mut [T]`, or `Vec<T>` if a heap is available.
222 pub struct Interface {
223     inner: InterfaceInner,
224     fragments: FragmentsBuffer,
225     fragmenter: Fragmenter,
226 }
227 
228 /// The device independent part of an Ethernet network interface.
229 ///
230 /// Separating the device from the data required for processing and dispatching makes
231 /// it possible to borrow them independently. For example, the tx and rx tokens borrow
232 /// the `device` mutably until they're used, which makes it impossible to call other
233 /// methods on the `Interface` in this time (since its `device` field is borrowed
234 /// exclusively). However, it is still possible to call methods on its `inner` field.
235 pub struct InterfaceInner {
236     caps: DeviceCapabilities,
237     now: Instant,
238     rand: Rand,
239 
240     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
241     neighbor_cache: Option<NeighborCache>,
242     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
243     hardware_addr: Option<HardwareAddress>,
244     #[cfg(feature = "medium-ieee802154")]
245     sequence_no: u8,
246     #[cfg(feature = "medium-ieee802154")]
247     pan_id: Option<Ieee802154Pan>,
248     #[cfg(feature = "proto-ipv4-fragmentation")]
249     ipv4_id: u16,
250     #[cfg(feature = "proto-sixlowpan")]
251     sixlowpan_address_context:
252         Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
253     #[cfg(feature = "proto-sixlowpan-fragmentation")]
254     tag: u16,
255     ip_addrs: Vec<IpCidr, IFACE_MAX_ADDR_COUNT>,
256     #[cfg(feature = "proto-ipv4")]
257     any_ip: bool,
258     routes: Routes,
259     #[cfg(feature = "proto-igmp")]
260     ipv4_multicast_groups: LinearMap<Ipv4Address, (), IFACE_MAX_MULTICAST_GROUP_COUNT>,
261     /// When to report for (all or) the next multicast group membership via IGMP
262     #[cfg(feature = "proto-igmp")]
263     igmp_report_state: IgmpReportState,
264 }
265 
266 /// Configuration structure used for creating a network interface.
267 #[non_exhaustive]
268 pub struct Config {
269     /// Random seed.
270     ///
271     /// It is strongly recommended that the random seed is different on each boot,
272     /// to avoid problems with TCP port/sequence collisions.
273     ///
274     /// The seed doesn't have to be cryptographically secure.
275     pub random_seed: u64,
276 
277     /// Set the Hardware address the interface will use.
278     ///
279     /// # Panics
280     /// Creating the interface panics if the address is not unicast.
281     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
282     pub hardware_addr: Option<HardwareAddress>,
283 
284     /// Set the IEEE802.15.4 PAN ID the interface will use.
285     ///
286     /// **NOTE**: we use the same PAN ID for destination and source.
287     #[cfg(feature = "medium-ieee802154")]
288     pub pan_id: Option<Ieee802154Pan>,
289 }
290 
291 impl Config {
new() -> Self292     pub fn new() -> Self {
293         Config {
294             random_seed: 0,
295             #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
296             hardware_addr: None,
297             #[cfg(feature = "medium-ieee802154")]
298             pan_id: None,
299         }
300     }
301 }
302 
303 impl Default for Config {
default() -> Self304     fn default() -> Self {
305         Self::new()
306     }
307 }
308 
309 #[derive(Debug, PartialEq)]
310 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
311 #[cfg(feature = "medium-ethernet")]
312 enum EthernetPacket<'a> {
313     #[cfg(feature = "proto-ipv4")]
314     Arp(ArpRepr),
315     Ip(IpPacket<'a>),
316 }
317 
318 #[derive(Debug, PartialEq)]
319 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
320 pub(crate) enum IpPacket<'a> {
321     #[cfg(feature = "proto-ipv4")]
322     Icmpv4((Ipv4Repr, Icmpv4Repr<'a>)),
323     #[cfg(feature = "proto-igmp")]
324     Igmp((Ipv4Repr, IgmpRepr)),
325     #[cfg(feature = "proto-ipv6")]
326     Icmpv6((Ipv6Repr, Icmpv6Repr<'a>)),
327     #[cfg(feature = "socket-raw")]
328     Raw((IpRepr, &'a [u8])),
329     #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
330     Udp((IpRepr, UdpRepr, &'a [u8])),
331     #[cfg(feature = "socket-tcp")]
332     Tcp((IpRepr, TcpRepr<'a>)),
333     #[cfg(feature = "socket-dhcpv4")]
334     Dhcpv4((Ipv4Repr, UdpRepr, DhcpRepr<'a>)),
335 }
336 
337 impl<'a> IpPacket<'a> {
ip_repr(&self) -> IpRepr338     pub(crate) fn ip_repr(&self) -> IpRepr {
339         match self {
340             #[cfg(feature = "proto-ipv4")]
341             IpPacket::Icmpv4((ipv4_repr, _)) => IpRepr::Ipv4(*ipv4_repr),
342             #[cfg(feature = "proto-igmp")]
343             IpPacket::Igmp((ipv4_repr, _)) => IpRepr::Ipv4(*ipv4_repr),
344             #[cfg(feature = "proto-ipv6")]
345             IpPacket::Icmpv6((ipv6_repr, _)) => IpRepr::Ipv6(*ipv6_repr),
346             #[cfg(feature = "socket-raw")]
347             IpPacket::Raw((ip_repr, _)) => ip_repr.clone(),
348             #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
349             IpPacket::Udp((ip_repr, _, _)) => ip_repr.clone(),
350             #[cfg(feature = "socket-tcp")]
351             IpPacket::Tcp((ip_repr, _)) => ip_repr.clone(),
352             #[cfg(feature = "socket-dhcpv4")]
353             IpPacket::Dhcpv4((ipv4_repr, _, _)) => IpRepr::Ipv4(*ipv4_repr),
354         }
355     }
356 
emit_payload( &self, _ip_repr: &IpRepr, payload: &mut [u8], caps: &DeviceCapabilities, )357     pub(crate) fn emit_payload(
358         &self,
359         _ip_repr: &IpRepr,
360         payload: &mut [u8],
361         caps: &DeviceCapabilities,
362     ) {
363         match self {
364             #[cfg(feature = "proto-ipv4")]
365             IpPacket::Icmpv4((_, icmpv4_repr)) => {
366                 icmpv4_repr.emit(&mut Icmpv4Packet::new_unchecked(payload), &caps.checksum)
367             }
368             #[cfg(feature = "proto-igmp")]
369             IpPacket::Igmp((_, igmp_repr)) => {
370                 igmp_repr.emit(&mut IgmpPacket::new_unchecked(payload))
371             }
372             #[cfg(feature = "proto-ipv6")]
373             IpPacket::Icmpv6((_, icmpv6_repr)) => icmpv6_repr.emit(
374                 &_ip_repr.src_addr(),
375                 &_ip_repr.dst_addr(),
376                 &mut Icmpv6Packet::new_unchecked(payload),
377                 &caps.checksum,
378             ),
379             #[cfg(feature = "socket-raw")]
380             IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
381             #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
382             IpPacket::Udp((_, udp_repr, inner_payload)) => udp_repr.emit(
383                 &mut UdpPacket::new_unchecked(payload),
384                 &_ip_repr.src_addr(),
385                 &_ip_repr.dst_addr(),
386                 inner_payload.len(),
387                 |buf| buf.copy_from_slice(inner_payload),
388                 &caps.checksum,
389             ),
390             #[cfg(feature = "socket-tcp")]
391             IpPacket::Tcp((_, mut tcp_repr)) => {
392                 // This is a terrible hack to make TCP performance more acceptable on systems
393                 // where the TCP buffers are significantly larger than network buffers,
394                 // e.g. a 64 kB TCP receive buffer (and so, when empty, a 64k window)
395                 // together with four 1500 B Ethernet receive buffers. If left untreated,
396                 // this would result in our peer pushing our window and sever packet loss.
397                 //
398                 // I'm really not happy about this "solution" but I don't know what else to do.
399                 if let Some(max_burst_size) = caps.max_burst_size {
400                     let mut max_segment_size = caps.max_transmission_unit;
401                     max_segment_size -= _ip_repr.header_len();
402                     max_segment_size -= tcp_repr.header_len();
403 
404                     let max_window_size = max_burst_size * max_segment_size;
405                     if tcp_repr.window_len as usize > max_window_size {
406                         tcp_repr.window_len = max_window_size as u16;
407                     }
408                 }
409 
410                 tcp_repr.emit(
411                     &mut TcpPacket::new_unchecked(payload),
412                     &_ip_repr.src_addr(),
413                     &_ip_repr.dst_addr(),
414                     &caps.checksum,
415                 );
416             }
417             #[cfg(feature = "socket-dhcpv4")]
418             IpPacket::Dhcpv4((_, udp_repr, dhcp_repr)) => udp_repr.emit(
419                 &mut UdpPacket::new_unchecked(payload),
420                 &_ip_repr.src_addr(),
421                 &_ip_repr.dst_addr(),
422                 dhcp_repr.buffer_len(),
423                 |buf| dhcp_repr.emit(&mut DhcpPacket::new_unchecked(buf)).unwrap(),
424                 &caps.checksum,
425             ),
426         }
427     }
428 }
429 
430 #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
icmp_reply_payload_len(len: usize, mtu: usize, header_len: usize) -> usize431 fn icmp_reply_payload_len(len: usize, mtu: usize, header_len: usize) -> usize {
432     // Send back as much of the original payload as will fit within
433     // the minimum MTU required by IPv4. See RFC 1812 § 4.3.2.3 for
434     // more details.
435     //
436     // Since the entire network layer packet must fit within the minimum
437     // MTU supported, the payload must not exceed the following:
438     //
439     // <min mtu> - IP Header Size * 2 - ICMPv4 DstUnreachable hdr size
440     cmp::min(len, mtu - header_len * 2 - 8)
441 }
442 
443 #[cfg(feature = "proto-igmp")]
444 enum IgmpReportState {
445     Inactive,
446     ToGeneralQuery {
447         version: IgmpVersion,
448         timeout: Instant,
449         interval: Duration,
450         next_index: usize,
451     },
452     ToSpecificQuery {
453         version: IgmpVersion,
454         timeout: Instant,
455         group: Ipv4Address,
456     },
457 }
458 
459 impl Interface {
460     /// Create a network interface using the previously provided configuration.
461     ///
462     /// # Panics
463     /// If a required option is not provided, this function will panic. Required
464     /// options are:
465     ///
466     /// - [ethernet_addr]
467     /// - [neighbor_cache]
468     ///
469     /// [ethernet_addr]: #method.ethernet_addr
470     /// [neighbor_cache]: #method.neighbor_cache
new<D>(config: Config, device: &mut D) -> Self where D: Device + ?Sized,471     pub fn new<D>(config: Config, device: &mut D) -> Self
472     where
473         D: Device + ?Sized,
474     {
475         let caps = device.capabilities();
476 
477         #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
478         let hardware_addr = match caps.medium {
479             #[cfg(feature = "medium-ethernet")]
480             Medium::Ethernet => Some(
481                 config
482                     .hardware_addr
483                     .expect("hardware_addr required option was not set"),
484             ),
485             #[cfg(feature = "medium-ip")]
486             Medium::Ip => {
487                 assert!(
488                     config.hardware_addr.is_none(),
489                     "hardware_addr is set, but device medium is IP"
490                 );
491                 None
492             }
493             #[cfg(feature = "medium-ieee802154")]
494             Medium::Ieee802154 => Some(
495                 config
496                     .hardware_addr
497                     .expect("hardware_addr required option was not set"),
498             ),
499         };
500 
501         let mut rand = Rand::new(config.random_seed);
502 
503         #[cfg(feature = "medium-ieee802154")]
504         let mut sequence_no;
505         #[cfg(feature = "medium-ieee802154")]
506         loop {
507             sequence_no = (rand.rand_u32() & 0xff) as u8;
508             if sequence_no != 0 {
509                 break;
510             }
511         }
512 
513         #[cfg(feature = "proto-sixlowpan")]
514         let mut tag;
515 
516         #[cfg(feature = "proto-sixlowpan")]
517         loop {
518             tag = rand.rand_u16();
519             if tag != 0 {
520                 break;
521             }
522         }
523 
524         #[cfg(feature = "proto-ipv4")]
525         let mut ipv4_id;
526 
527         #[cfg(feature = "proto-ipv4")]
528         loop {
529             ipv4_id = rand.rand_u16();
530             if ipv4_id != 0 {
531                 break;
532             }
533         }
534 
535         Interface {
536             fragments: FragmentsBuffer {
537                 #[cfg(feature = "proto-sixlowpan")]
538                 decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
539 
540                 #[cfg(feature = "_proto-fragmentation")]
541                 assembler: PacketAssemblerSet::new(),
542                 #[cfg(feature = "_proto-fragmentation")]
543                 reassembly_timeout: Duration::from_secs(60),
544             },
545             fragmenter: Fragmenter::new(),
546             inner: InterfaceInner {
547                 now: Instant::from_secs(0),
548                 caps,
549                 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
550                 hardware_addr,
551                 ip_addrs: Vec::new(),
552                 #[cfg(feature = "proto-ipv4")]
553                 any_ip: false,
554                 routes: Routes::new(),
555                 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
556                 neighbor_cache: Some(NeighborCache::new()),
557                 #[cfg(feature = "proto-igmp")]
558                 ipv4_multicast_groups: LinearMap::new(),
559                 #[cfg(feature = "proto-igmp")]
560                 igmp_report_state: IgmpReportState::Inactive,
561                 #[cfg(feature = "medium-ieee802154")]
562                 sequence_no,
563                 #[cfg(feature = "medium-ieee802154")]
564                 pan_id: config.pan_id,
565                 #[cfg(feature = "proto-sixlowpan-fragmentation")]
566                 tag,
567                 #[cfg(feature = "proto-ipv4-fragmentation")]
568                 ipv4_id,
569                 #[cfg(feature = "proto-sixlowpan")]
570                 sixlowpan_address_context: Vec::new(),
571                 rand,
572             },
573         }
574     }
575 
576     /// Get the socket context.
577     ///
578     /// The context is needed for some socket methods.
context(&mut self) -> &mut InterfaceInner579     pub fn context(&mut self) -> &mut InterfaceInner {
580         &mut self.inner
581     }
582 
583     /// Get the HardwareAddress address of the interface.
584     ///
585     /// # Panics
586     /// This function panics if the medium is not Ethernet or Ieee802154.
587     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
hardware_addr(&self) -> HardwareAddress588     pub fn hardware_addr(&self) -> HardwareAddress {
589         #[cfg(all(feature = "medium-ethernet", not(feature = "medium-ieee802154")))]
590         assert!(self.inner.caps.medium == Medium::Ethernet);
591         #[cfg(all(feature = "medium-ieee802154", not(feature = "medium-ethernet")))]
592         assert!(self.inner.caps.medium == Medium::Ieee802154);
593 
594         #[cfg(all(feature = "medium-ieee802154", feature = "medium-ethernet"))]
595         assert!(
596             self.inner.caps.medium == Medium::Ethernet
597                 || self.inner.caps.medium == Medium::Ieee802154
598         );
599 
600         self.inner.hardware_addr.unwrap()
601     }
602 
603     /// Set the HardwareAddress address of the interface.
604     ///
605     /// # Panics
606     /// This function panics if the address is not unicast, and if the medium is not Ethernet or
607     /// Ieee802154.
608     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
set_hardware_addr(&mut self, addr: HardwareAddress)609     pub fn set_hardware_addr(&mut self, addr: HardwareAddress) {
610         #[cfg(all(feature = "medium-ethernet", not(feature = "medium-ieee802154")))]
611         assert!(self.inner.caps.medium == Medium::Ethernet);
612         #[cfg(all(feature = "medium-ieee802154", not(feature = "medium-ethernet")))]
613         assert!(self.inner.caps.medium == Medium::Ieee802154);
614 
615         #[cfg(all(feature = "medium-ieee802154", feature = "medium-ethernet"))]
616         assert!(
617             self.inner.caps.medium == Medium::Ethernet
618                 || self.inner.caps.medium == Medium::Ieee802154
619         );
620 
621         InterfaceInner::check_hardware_addr(&addr);
622         self.inner.hardware_addr = Some(addr);
623     }
624 
625     /// Get the IP addresses of the interface.
ip_addrs(&self) -> &[IpCidr]626     pub fn ip_addrs(&self) -> &[IpCidr] {
627         self.inner.ip_addrs.as_ref()
628     }
629 
630     /// Get the first IPv4 address if present.
631     #[cfg(feature = "proto-ipv4")]
ipv4_addr(&self) -> Option<Ipv4Address>632     pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
633         self.inner.ipv4_addr()
634     }
635 
636     /// Get the first IPv6 address if present.
637     #[cfg(feature = "proto-ipv6")]
ipv6_addr(&self) -> Option<Ipv6Address>638     pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
639         self.inner.ipv6_addr()
640     }
641 
642     /// Update the IP addresses of the interface.
643     ///
644     /// # Panics
645     /// This function panics if any of the addresses are not unicast.
update_ip_addrs<F: FnOnce(&mut Vec<IpCidr, IFACE_MAX_ADDR_COUNT>)>(&mut self, f: F)646     pub fn update_ip_addrs<F: FnOnce(&mut Vec<IpCidr, IFACE_MAX_ADDR_COUNT>)>(&mut self, f: F) {
647         f(&mut self.inner.ip_addrs);
648         InterfaceInner::flush_cache(&mut self.inner);
649         InterfaceInner::check_ip_addrs(&self.inner.ip_addrs)
650     }
651 
652     /// Check whether the interface has the given IP address assigned.
has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool653     pub fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
654         self.inner.has_ip_addr(addr)
655     }
656 
routes(&self) -> &Routes657     pub fn routes(&self) -> &Routes {
658         &self.inner.routes
659     }
660 
routes_mut(&mut self) -> &mut Routes661     pub fn routes_mut(&mut self) -> &mut Routes {
662         &mut self.inner.routes
663     }
664 
665     /// Enable or disable the AnyIP capability.
666     ///
667     /// AnyIP allowins packets to be received
668     /// locally on IPv4 addresses other than the interface's configured [ip_addrs].
669     /// When AnyIP is enabled and a route prefix in [`routes`](Self::routes) specifies one of
670     /// the interface's [`ip_addrs`](Self::ip_addrs) as its gateway, the interface will accept
671     /// packets addressed to that prefix.
672     ///
673     /// # IPv6
674     ///
675     /// This option is not available or required for IPv6 as packets sent to
676     /// the interface are not filtered by IPv6 address.
677     #[cfg(feature = "proto-ipv4")]
set_any_ip(&mut self, any_ip: bool)678     pub fn set_any_ip(&mut self, any_ip: bool) {
679         self.inner.any_ip = any_ip;
680     }
681 
682     /// Get whether AnyIP is enabled.
683     ///
684     /// See [`set_any_ip`](Self::set_any_ip) for details on AnyIP
685     #[cfg(feature = "proto-ipv4")]
any_ip(&self) -> bool686     pub fn any_ip(&self) -> bool {
687         self.inner.any_ip
688     }
689 
690     /// Get the 6LoWPAN address contexts.
691     #[cfg(feature = "proto-sixlowpan")]
sixlowpan_address_context( &self, ) -> &Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT>692     pub fn sixlowpan_address_context(
693         &self,
694     ) -> &Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
695         &self.inner.sixlowpan_address_context
696     }
697 
698     /// Get a mutable reference to the 6LoWPAN address contexts.
699     #[cfg(feature = "proto-sixlowpan")]
sixlowpan_address_context_mut( &mut self, ) -> &mut Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT>700     pub fn sixlowpan_address_context_mut(
701         &mut self,
702     ) -> &mut Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
703         &mut self.inner.sixlowpan_address_context
704     }
705 
706     /// Get the packet reassembly timeout.
707     #[cfg(feature = "_proto-fragmentation")]
reassembly_timeout(&self) -> Duration708     pub fn reassembly_timeout(&self) -> Duration {
709         self.fragments.reassembly_timeout
710     }
711 
712     /// Set the packet reassembly timeout.
713     #[cfg(feature = "_proto-fragmentation")]
set_reassembly_timeout(&mut self, timeout: Duration)714     pub fn set_reassembly_timeout(&mut self, timeout: Duration) {
715         if timeout > Duration::from_secs(60) {
716             net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
717         }
718         self.fragments.reassembly_timeout = timeout;
719     }
720 
721     /// Transmit packets queued in the given sockets, and receive packets queued
722     /// in the device.
723     ///
724     /// This function returns a boolean value indicating whether any packets were
725     /// processed or emitted, and thus, whether the readiness of any socket might
726     /// have changed.
poll<D>( &mut self, timestamp: Instant, device: &mut D, sockets: &mut SocketSet<'_>, ) -> bool where D: Device + ?Sized,727     pub fn poll<D>(
728         &mut self,
729         timestamp: Instant,
730         device: &mut D,
731         sockets: &mut SocketSet<'_>,
732     ) -> bool
733     where
734         D: Device + ?Sized,
735     {
736         self.inner.now = timestamp;
737 
738         #[cfg(feature = "_proto-fragmentation")]
739         self.fragments.assembler.remove_expired(timestamp);
740 
741         match self.inner.caps.medium {
742             #[cfg(feature = "medium-ieee802154")]
743             Medium::Ieee802154 =>
744             {
745                 #[cfg(feature = "proto-sixlowpan-fragmentation")]
746                 if self.sixlowpan_egress(device) {
747                     return true;
748                 }
749             }
750             #[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
751             _ =>
752             {
753                 #[cfg(feature = "proto-ipv4-fragmentation")]
754                 if self.ipv4_egress(device) {
755                     return true;
756                 }
757             }
758         }
759 
760         let mut readiness_may_have_changed = false;
761 
762         loop {
763             let mut did_something = false;
764             did_something |= self.socket_ingress(device, sockets);
765             did_something |= self.socket_egress(device, sockets);
766 
767             #[cfg(feature = "proto-igmp")]
768             {
769                 did_something |= self.igmp_egress(device);
770             }
771 
772             if did_something {
773                 readiness_may_have_changed = true;
774             } else {
775                 break;
776             }
777         }
778 
779         readiness_may_have_changed
780     }
781 
782     /// Return a _soft deadline_ for calling [poll] the next time.
783     /// The [Instant] returned is the time at which you should call [poll] next.
784     /// It is harmless (but wastes energy) to call it before the [Instant], and
785     /// potentially harmful (impacting quality of service) to call it after the
786     /// [Instant]
787     ///
788     /// [poll]: #method.poll
789     /// [Instant]: struct.Instant.html
poll_at(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Instant>790     pub fn poll_at(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Instant> {
791         self.inner.now = timestamp;
792 
793         #[cfg(feature = "_proto-fragmentation")]
794         if !self.fragmenter.is_empty() {
795             return Some(Instant::from_millis(0));
796         }
797 
798         let inner = &mut self.inner;
799 
800         sockets
801             .items()
802             .filter_map(move |item| {
803                 let socket_poll_at = item.socket.poll_at(inner);
804                 match item
805                     .meta
806                     .poll_at(socket_poll_at, |ip_addr| inner.has_neighbor(&ip_addr))
807                 {
808                     PollAt::Ingress => None,
809                     PollAt::Time(instant) => Some(instant),
810                     PollAt::Now => Some(Instant::from_millis(0)),
811                 }
812             })
813             .min()
814     }
815 
816     /// Return an _advisory wait time_ for calling [poll] the next time.
817     /// The [Duration] returned is the time left to wait before calling [poll] next.
818     /// It is harmless (but wastes energy) to call it before the [Duration] has passed,
819     /// and potentially harmful (impacting quality of service) to call it after the
820     /// [Duration] has passed.
821     ///
822     /// [poll]: #method.poll
823     /// [Duration]: struct.Duration.html
poll_delay(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Duration>824     pub fn poll_delay(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Duration> {
825         match self.poll_at(timestamp, sockets) {
826             Some(poll_at) if timestamp < poll_at => Some(poll_at - timestamp),
827             Some(_) => Some(Duration::from_millis(0)),
828             _ => None,
829         }
830     }
831 
socket_ingress<D>(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool where D: Device + ?Sized,832     fn socket_ingress<D>(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool
833     where
834         D: Device + ?Sized,
835     {
836         let mut processed_any = false;
837 
838         while let Some((rx_token, tx_token)) = device.receive(self.inner.now) {
839             rx_token.consume(|frame| {
840                 match self.inner.caps.medium {
841                     #[cfg(feature = "medium-ethernet")]
842                     Medium::Ethernet => {
843                         if let Some(packet) =
844                             self.inner
845                                 .process_ethernet(sockets, &frame, &mut self.fragments)
846                         {
847                             if let Err(err) =
848                                 self.inner.dispatch(tx_token, packet, &mut self.fragmenter)
849                             {
850                                 net_debug!("Failed to send response: {:?}", err);
851                             }
852                         }
853                     }
854                     #[cfg(feature = "medium-ip")]
855                     Medium::Ip => {
856                         if let Some(packet) =
857                             self.inner.process_ip(sockets, &frame, &mut self.fragments)
858                         {
859                             if let Err(err) =
860                                 self.inner
861                                     .dispatch_ip(tx_token, packet, &mut self.fragmenter)
862                             {
863                                 net_debug!("Failed to send response: {:?}", err);
864                             }
865                         }
866                     }
867                     #[cfg(feature = "medium-ieee802154")]
868                     Medium::Ieee802154 => {
869                         if let Some(packet) =
870                             self.inner
871                                 .process_ieee802154(sockets, &frame, &mut self.fragments)
872                         {
873                             if let Err(err) =
874                                 self.inner
875                                     .dispatch_ip(tx_token, packet, &mut self.fragmenter)
876                             {
877                                 net_debug!("Failed to send response: {:?}", err);
878                             }
879                         }
880                     }
881                 }
882                 processed_any = true;
883             });
884         }
885 
886         processed_any
887     }
888 
socket_egress<D>(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool where D: Device + ?Sized,889     fn socket_egress<D>(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool
890     where
891         D: Device + ?Sized,
892     {
893         let _caps = device.capabilities();
894 
895         enum EgressError {
896             Exhausted,
897             Dispatch(DispatchError),
898         }
899 
900         let mut emitted_any = false;
901         for item in sockets.items_mut() {
902             if !item
903                 .meta
904                 .egress_permitted(self.inner.now, |ip_addr| self.inner.has_neighbor(&ip_addr))
905             {
906                 continue;
907             }
908 
909             let mut neighbor_addr = None;
910             let mut respond = |inner: &mut InterfaceInner, response: IpPacket| {
911                 neighbor_addr = Some(response.ip_repr().dst_addr());
912                 let t = device.transmit(inner.now).ok_or_else(|| {
913                     net_debug!("failed to transmit IP: device exhausted");
914                     EgressError::Exhausted
915                 })?;
916 
917                 inner
918                     .dispatch_ip(t, response, &mut self.fragmenter)
919                     .map_err(EgressError::Dispatch)?;
920 
921                 emitted_any = true;
922 
923                 Ok(())
924             };
925 
926             let result = match &mut item.socket {
927                 #[cfg(feature = "socket-raw")]
928                 Socket::Raw(socket) => socket.dispatch(&mut self.inner, |inner, response| {
929                     respond(inner, IpPacket::Raw(response))
930                 }),
931                 #[cfg(feature = "socket-icmp")]
932                 Socket::Icmp(socket) => {
933                     socket.dispatch(&mut self.inner, |inner, response| match response {
934                         #[cfg(feature = "proto-ipv4")]
935                         (IpRepr::Ipv4(ipv4_repr), IcmpRepr::Ipv4(icmpv4_repr)) => {
936                             respond(inner, IpPacket::Icmpv4((ipv4_repr, icmpv4_repr)))
937                         }
938                         #[cfg(feature = "proto-ipv6")]
939                         (IpRepr::Ipv6(ipv6_repr), IcmpRepr::Ipv6(icmpv6_repr)) => {
940                             respond(inner, IpPacket::Icmpv6((ipv6_repr, icmpv6_repr)))
941                         }
942                         #[allow(unreachable_patterns)]
943                         _ => unreachable!(),
944                     })
945                 }
946                 #[cfg(feature = "socket-udp")]
947                 Socket::Udp(socket) => socket.dispatch(&mut self.inner, |inner, response| {
948                     respond(inner, IpPacket::Udp(response))
949                 }),
950                 #[cfg(feature = "socket-tcp")]
951                 Socket::Tcp(socket) => socket.dispatch(&mut self.inner, |inner, response| {
952                     respond(inner, IpPacket::Tcp(response))
953                 }),
954                 #[cfg(feature = "socket-dhcpv4")]
955                 Socket::Dhcpv4(socket) => socket.dispatch(&mut self.inner, |inner, response| {
956                     respond(inner, IpPacket::Dhcpv4(response))
957                 }),
958                 #[cfg(feature = "socket-dns")]
959                 Socket::Dns(socket) => socket.dispatch(&mut self.inner, |inner, response| {
960                     respond(inner, IpPacket::Udp(response))
961                 }),
962             };
963 
964             match result {
965                 Err(EgressError::Exhausted) => break, // Device buffer full.
966                 Err(EgressError::Dispatch(_)) => {
967                     // `NeighborCache` already takes care of rate limiting the neighbor discovery
968                     // requests from the socket. However, without an additional rate limiting
969                     // mechanism, we would spin on every socket that has yet to discover its
970                     // neighbor.
971                     item.meta.neighbor_missing(
972                         self.inner.now,
973                         neighbor_addr.expect("non-IP response packet"),
974                     );
975                 }
976                 Ok(()) => {}
977             }
978         }
979         emitted_any
980     }
981 
982     /// Process fragments that still need to be sent for IPv4 packets.
983     ///
984     /// This function returns a boolean value indicating whether any packets were
985     /// processed or emitted, and thus, whether the readiness of any socket might
986     /// have changed.
987     #[cfg(feature = "proto-ipv4-fragmentation")]
ipv4_egress<D>(&mut self, device: &mut D) -> bool where D: Device + ?Sized,988     fn ipv4_egress<D>(&mut self, device: &mut D) -> bool
989     where
990         D: Device + ?Sized,
991     {
992         // Reset the buffer when we transmitted everything.
993         if self.fragmenter.finished() {
994             self.fragmenter.reset();
995         }
996 
997         if self.fragmenter.is_empty() {
998             return false;
999         }
1000 
1001         let pkt = &self.fragmenter;
1002         if pkt.packet_len > pkt.sent_bytes {
1003             if let Some(tx_token) = device.transmit(self.inner.now) {
1004                 self.inner
1005                     .dispatch_ipv4_frag(tx_token, &mut self.fragmenter);
1006                 return true;
1007             }
1008         }
1009         false
1010     }
1011 
1012     /// Process fragments that still need to be sent for 6LoWPAN packets.
1013     ///
1014     /// This function returns a boolean value indicating whether any packets were
1015     /// processed or emitted, and thus, whether the readiness of any socket might
1016     /// have changed.
1017     #[cfg(feature = "proto-sixlowpan-fragmentation")]
sixlowpan_egress<D>(&mut self, device: &mut D) -> bool where D: Device + ?Sized,1018     fn sixlowpan_egress<D>(&mut self, device: &mut D) -> bool
1019     where
1020         D: Device + ?Sized,
1021     {
1022         // Reset the buffer when we transmitted everything.
1023         if self.fragmenter.finished() {
1024             self.fragmenter.reset();
1025         }
1026 
1027         if self.fragmenter.is_empty() {
1028             return false;
1029         }
1030 
1031         let pkt = &self.fragmenter;
1032         if pkt.packet_len > pkt.sent_bytes {
1033             if let Some(tx_token) = device.transmit(self.inner.now) {
1034                 self.inner
1035                     .dispatch_ieee802154_frag(tx_token, &mut self.fragmenter);
1036                 return true;
1037             }
1038         }
1039         false
1040     }
1041 }
1042 
1043 impl InterfaceInner {
1044     #[allow(unused)] // unused depending on which sockets are enabled
now(&self) -> Instant1045     pub(crate) fn now(&self) -> Instant {
1046         self.now
1047     }
1048 
1049     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
1050     #[allow(unused)] // unused depending on which sockets are enabled
hardware_addr(&self) -> Option<HardwareAddress>1051     pub(crate) fn hardware_addr(&self) -> Option<HardwareAddress> {
1052         self.hardware_addr
1053     }
1054 
1055     #[allow(unused)] // unused depending on which sockets are enabled
checksum_caps(&self) -> ChecksumCapabilities1056     pub(crate) fn checksum_caps(&self) -> ChecksumCapabilities {
1057         self.caps.checksum.clone()
1058     }
1059 
1060     #[allow(unused)] // unused depending on which sockets are enabled
ip_mtu(&self) -> usize1061     pub(crate) fn ip_mtu(&self) -> usize {
1062         self.caps.ip_mtu()
1063     }
1064 
1065     #[allow(unused)] // unused depending on which sockets are enabled, and in tests
rand(&mut self) -> &mut Rand1066     pub(crate) fn rand(&mut self) -> &mut Rand {
1067         &mut self.rand
1068     }
1069 
1070     #[allow(unused)] // unused depending on which sockets are enabled
get_source_address(&mut self, dst_addr: IpAddress) -> Option<IpAddress>1071     pub(crate) fn get_source_address(&mut self, dst_addr: IpAddress) -> Option<IpAddress> {
1072         let v = dst_addr.version();
1073         for cidr in self.ip_addrs.iter() {
1074             let addr = cidr.address();
1075             if addr.version() == v {
1076                 return Some(addr);
1077             }
1078         }
1079         None
1080     }
1081 
1082     #[cfg(feature = "proto-ipv4")]
1083     #[allow(unused)]
get_source_address_ipv4( &mut self, _dst_addr: Ipv4Address, ) -> Option<Ipv4Address>1084     pub(crate) fn get_source_address_ipv4(
1085         &mut self,
1086         _dst_addr: Ipv4Address,
1087     ) -> Option<Ipv4Address> {
1088         for cidr in self.ip_addrs.iter() {
1089             #[allow(irrefutable_let_patterns)] // if only ipv4 is enabled
1090             if let IpCidr::Ipv4(cidr) = cidr {
1091                 return Some(cidr.address());
1092             }
1093         }
1094         None
1095     }
1096 
1097     #[cfg(feature = "proto-ipv6")]
1098     #[allow(unused)]
get_source_address_ipv6( &mut self, _dst_addr: Ipv6Address, ) -> Option<Ipv6Address>1099     pub(crate) fn get_source_address_ipv6(
1100         &mut self,
1101         _dst_addr: Ipv6Address,
1102     ) -> Option<Ipv6Address> {
1103         for cidr in self.ip_addrs.iter() {
1104             #[allow(irrefutable_let_patterns)] // if only ipv6 is enabled
1105             if let IpCidr::Ipv6(cidr) = cidr {
1106                 return Some(cidr.address());
1107             }
1108         }
1109         None
1110     }
1111 
1112     #[cfg(test)]
mock() -> Self1113     pub(crate) fn mock() -> Self {
1114         Self {
1115             caps: DeviceCapabilities {
1116                 #[cfg(feature = "medium-ethernet")]
1117                 medium: crate::phy::Medium::Ethernet,
1118                 #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ip"))]
1119                 medium: crate::phy::Medium::Ip,
1120                 #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ieee802154"))]
1121                 medium: crate::phy::Medium::Ieee802154,
1122 
1123                 checksum: crate::phy::ChecksumCapabilities {
1124                     #[cfg(feature = "proto-ipv4")]
1125                     icmpv4: crate::phy::Checksum::Both,
1126                     #[cfg(feature = "proto-ipv6")]
1127                     icmpv6: crate::phy::Checksum::Both,
1128                     ipv4: crate::phy::Checksum::Both,
1129                     tcp: crate::phy::Checksum::Both,
1130                     udp: crate::phy::Checksum::Both,
1131                 },
1132                 max_burst_size: None,
1133                 #[cfg(feature = "medium-ethernet")]
1134                 max_transmission_unit: 1514,
1135                 #[cfg(not(feature = "medium-ethernet"))]
1136                 max_transmission_unit: 1500,
1137             },
1138             now: Instant::from_millis_const(0),
1139 
1140             ip_addrs: Vec::from_slice(&[
1141                 #[cfg(feature = "proto-ipv4")]
1142                 IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 1), 24)),
1143                 #[cfg(feature = "proto-ipv6")]
1144                 IpCidr::Ipv6(Ipv6Cidr::new(
1145                     Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
1146                     64,
1147                 )),
1148             ])
1149             .unwrap(),
1150             rand: Rand::new(1234),
1151             routes: Routes::new(),
1152 
1153             #[cfg(feature = "proto-ipv4")]
1154             any_ip: false,
1155 
1156             #[cfg(feature = "medium-ieee802154")]
1157             pan_id: Some(crate::wire::Ieee802154Pan(0xabcd)),
1158             #[cfg(feature = "medium-ieee802154")]
1159             sequence_no: 1,
1160 
1161             #[cfg(feature = "proto-sixlowpan-fragmentation")]
1162             tag: 1,
1163 
1164             #[cfg(feature = "proto-sixlowpan")]
1165             sixlowpan_address_context: Vec::new(),
1166 
1167             #[cfg(feature = "proto-ipv4-fragmentation")]
1168             ipv4_id: 1,
1169 
1170             #[cfg(feature = "medium-ethernet")]
1171             hardware_addr: Some(crate::wire::HardwareAddress::Ethernet(
1172                 crate::wire::EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]),
1173             )),
1174             #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ieee802154"))]
1175             hardware_addr: Some(crate::wire::HardwareAddress::Ieee802154(
1176                 crate::wire::Ieee802154Address::Extended([
1177                     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x2, 0x2,
1178                 ]),
1179             )),
1180 
1181             #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
1182             neighbor_cache: None,
1183 
1184             #[cfg(feature = "proto-igmp")]
1185             igmp_report_state: IgmpReportState::Inactive,
1186             #[cfg(feature = "proto-igmp")]
1187             ipv4_multicast_groups: LinearMap::new(),
1188         }
1189     }
1190 
1191     #[cfg(test)]
1192     #[allow(unused)] // unused depending on which sockets are enabled
set_now(&mut self, now: Instant)1193     pub(crate) fn set_now(&mut self, now: Instant) {
1194         self.now = now
1195     }
1196 
1197     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
check_hardware_addr(addr: &HardwareAddress)1198     fn check_hardware_addr(addr: &HardwareAddress) {
1199         if !addr.is_unicast() {
1200             panic!("Ethernet address {addr} is not unicast")
1201         }
1202     }
1203 
check_ip_addrs(addrs: &[IpCidr])1204     fn check_ip_addrs(addrs: &[IpCidr]) {
1205         for cidr in addrs {
1206             if !cidr.address().is_unicast() && !cidr.address().is_unspecified() {
1207                 panic!("IP address {} is not unicast", cidr.address())
1208             }
1209         }
1210     }
1211 
1212     #[cfg(feature = "medium-ieee802154")]
get_sequence_number(&mut self) -> u81213     fn get_sequence_number(&mut self) -> u8 {
1214         let no = self.sequence_no;
1215         self.sequence_no = self.sequence_no.wrapping_add(1);
1216         no
1217     }
1218 
1219     #[cfg(feature = "proto-ipv4-fragmentation")]
get_ipv4_ident(&mut self) -> u161220     fn get_ipv4_ident(&mut self) -> u16 {
1221         let ipv4_id = self.ipv4_id;
1222         self.ipv4_id = self.ipv4_id.wrapping_add(1);
1223         ipv4_id
1224     }
1225 
1226     #[cfg(feature = "proto-sixlowpan-fragmentation")]
get_sixlowpan_fragment_tag(&mut self) -> u161227     fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
1228         let tag = self.tag;
1229         self.tag = self.tag.wrapping_add(1);
1230         tag
1231     }
1232 
1233     /// Determine if the given `Ipv6Address` is the solicited node
1234     /// multicast address for a IPv6 addresses assigned to the interface.
1235     /// See [RFC 4291 § 2.7.1] for more details.
1236     ///
1237     /// [RFC 4291 § 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
1238     #[cfg(feature = "proto-ipv6")]
has_solicited_node(&self, addr: Ipv6Address) -> bool1239     pub fn has_solicited_node(&self, addr: Ipv6Address) -> bool {
1240         self.ip_addrs.iter().any(|cidr| {
1241             match *cidr {
1242                 IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOOPBACK => {
1243                     // Take the lower order 24 bits of the IPv6 address and
1244                     // append those bits to FF02:0:0:0:0:1:FF00::/104.
1245                     addr.as_bytes()[14..] == cidr.address().as_bytes()[14..]
1246                 }
1247                 _ => false,
1248             }
1249         })
1250     }
1251 
1252     /// Check whether the interface has the given IP address assigned.
has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool1253     fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
1254         let addr = addr.into();
1255         self.ip_addrs.iter().any(|probe| probe.address() == addr)
1256     }
1257 
1258     /// Get the first IPv4 address of the interface.
1259     #[cfg(feature = "proto-ipv4")]
ipv4_addr(&self) -> Option<Ipv4Address>1260     pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
1261         self.ip_addrs.iter().find_map(|addr| match *addr {
1262             IpCidr::Ipv4(cidr) => Some(cidr.address()),
1263             #[allow(unreachable_patterns)]
1264             _ => None,
1265         })
1266     }
1267 
1268     /// Get the first IPv6 address if present.
1269     #[cfg(feature = "proto-ipv6")]
ipv6_addr(&self) -> Option<Ipv6Address>1270     pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
1271         self.ip_addrs.iter().find_map(|addr| match *addr {
1272             IpCidr::Ipv6(cidr) => Some(cidr.address()),
1273             #[allow(unreachable_patterns)]
1274             _ => None,
1275         })
1276     }
1277 
1278     #[cfg(not(feature = "proto-igmp"))]
has_multicast_group<T: Into<IpAddress>>(&self, addr: T) -> bool1279     fn has_multicast_group<T: Into<IpAddress>>(&self, addr: T) -> bool {
1280         false
1281     }
1282 
1283     #[cfg(feature = "medium-ip")]
process_ip<'frame, T: AsRef<[u8]>>( &mut self, sockets: &mut SocketSet, ip_payload: &'frame T, frag: &'frame mut FragmentsBuffer, ) -> Option<IpPacket<'frame>>1284     fn process_ip<'frame, T: AsRef<[u8]>>(
1285         &mut self,
1286         sockets: &mut SocketSet,
1287         ip_payload: &'frame T,
1288         frag: &'frame mut FragmentsBuffer,
1289     ) -> Option<IpPacket<'frame>> {
1290         match IpVersion::of_packet(ip_payload.as_ref()) {
1291             #[cfg(feature = "proto-ipv4")]
1292             Ok(IpVersion::Ipv4) => {
1293                 let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
1294 
1295                 self.process_ipv4(sockets, &ipv4_packet, frag)
1296             }
1297             #[cfg(feature = "proto-ipv6")]
1298             Ok(IpVersion::Ipv6) => {
1299                 let ipv6_packet = check!(Ipv6Packet::new_checked(ip_payload));
1300                 self.process_ipv6(sockets, &ipv6_packet)
1301             }
1302             // Drop all other traffic.
1303             _ => None,
1304         }
1305     }
1306 
1307     #[cfg(feature = "socket-raw")]
raw_socket_filter( &mut self, sockets: &mut SocketSet, ip_repr: &IpRepr, ip_payload: &[u8], ) -> bool1308     fn raw_socket_filter(
1309         &mut self,
1310         sockets: &mut SocketSet,
1311         ip_repr: &IpRepr,
1312         ip_payload: &[u8],
1313     ) -> bool {
1314         let mut handled_by_raw_socket = false;
1315 
1316         // Pass every IP packet to all raw sockets we have registered.
1317         for raw_socket in sockets
1318             .items_mut()
1319             .filter_map(|i| raw::Socket::downcast_mut(&mut i.socket))
1320         {
1321             if raw_socket.accepts(ip_repr) {
1322                 raw_socket.process(self, ip_repr, ip_payload);
1323                 handled_by_raw_socket = true;
1324             }
1325         }
1326         handled_by_raw_socket
1327     }
1328 
1329     /// Checks if an incoming packet has a broadcast address for the interfaces
1330     /// associated ipv4 addresses.
1331     #[cfg(feature = "proto-ipv4")]
is_subnet_broadcast(&self, address: Ipv4Address) -> bool1332     fn is_subnet_broadcast(&self, address: Ipv4Address) -> bool {
1333         self.ip_addrs
1334             .iter()
1335             .filter_map(|own_cidr| match own_cidr {
1336                 IpCidr::Ipv4(own_ip) => Some(own_ip.broadcast()?),
1337                 #[cfg(feature = "proto-ipv6")]
1338                 IpCidr::Ipv6(_) => None,
1339             })
1340             .any(|broadcast_address| address == broadcast_address)
1341     }
1342 
1343     /// Checks if an ipv4 address is broadcast, taking into account subnet broadcast addresses
1344     #[cfg(feature = "proto-ipv4")]
is_broadcast_v4(&self, address: Ipv4Address) -> bool1345     fn is_broadcast_v4(&self, address: Ipv4Address) -> bool {
1346         address.is_broadcast() || self.is_subnet_broadcast(address)
1347     }
1348 
1349     /// Checks if an ipv4 address is unicast, taking into account subnet broadcast addresses
1350     #[cfg(feature = "proto-ipv4")]
is_unicast_v4(&self, address: Ipv4Address) -> bool1351     fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
1352         address.is_unicast() && !self.is_subnet_broadcast(address)
1353     }
1354 
1355     #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
process_udp<'frame>( &mut self, sockets: &mut SocketSet, ip_repr: IpRepr, udp_repr: UdpRepr, handled_by_raw_socket: bool, udp_payload: &'frame [u8], ip_payload: &'frame [u8], ) -> Option<IpPacket<'frame>>1356     fn process_udp<'frame>(
1357         &mut self,
1358         sockets: &mut SocketSet,
1359         ip_repr: IpRepr,
1360         udp_repr: UdpRepr,
1361         handled_by_raw_socket: bool,
1362         udp_payload: &'frame [u8],
1363         ip_payload: &'frame [u8],
1364     ) -> Option<IpPacket<'frame>> {
1365         #[cfg(feature = "socket-udp")]
1366         for udp_socket in sockets
1367             .items_mut()
1368             .filter_map(|i| udp::Socket::downcast_mut(&mut i.socket))
1369         {
1370             if udp_socket.accepts(self, &ip_repr, &udp_repr) {
1371                 udp_socket.process(self, &ip_repr, &udp_repr, udp_payload);
1372                 return None;
1373             }
1374         }
1375 
1376         #[cfg(feature = "socket-dns")]
1377         for dns_socket in sockets
1378             .items_mut()
1379             .filter_map(|i| dns::Socket::downcast_mut(&mut i.socket))
1380         {
1381             if dns_socket.accepts(&ip_repr, &udp_repr) {
1382                 dns_socket.process(self, &ip_repr, &udp_repr, udp_payload);
1383                 return None;
1384             }
1385         }
1386 
1387         // The packet wasn't handled by a socket, send an ICMP port unreachable packet.
1388         match ip_repr {
1389             #[cfg(feature = "proto-ipv4")]
1390             IpRepr::Ipv4(_) if handled_by_raw_socket => None,
1391             #[cfg(feature = "proto-ipv6")]
1392             IpRepr::Ipv6(_) if handled_by_raw_socket => None,
1393             #[cfg(feature = "proto-ipv4")]
1394             IpRepr::Ipv4(ipv4_repr) => {
1395                 let payload_len =
1396                     icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU, ipv4_repr.buffer_len());
1397                 let icmpv4_reply_repr = Icmpv4Repr::DstUnreachable {
1398                     reason: Icmpv4DstUnreachable::PortUnreachable,
1399                     header: ipv4_repr,
1400                     data: &ip_payload[0..payload_len],
1401                 };
1402                 self.icmpv4_reply(ipv4_repr, icmpv4_reply_repr)
1403             }
1404             #[cfg(feature = "proto-ipv6")]
1405             IpRepr::Ipv6(ipv6_repr) => {
1406                 let payload_len =
1407                     icmp_reply_payload_len(ip_payload.len(), IPV6_MIN_MTU, ipv6_repr.buffer_len());
1408                 let icmpv6_reply_repr = Icmpv6Repr::DstUnreachable {
1409                     reason: Icmpv6DstUnreachable::PortUnreachable,
1410                     header: ipv6_repr,
1411                     data: &ip_payload[0..payload_len],
1412                 };
1413                 self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr)
1414             }
1415         }
1416     }
1417 
1418     #[cfg(feature = "socket-tcp")]
process_tcp<'frame>( &mut self, sockets: &mut SocketSet, ip_repr: IpRepr, ip_payload: &'frame [u8], ) -> Option<IpPacket<'frame>>1419     pub(crate) fn process_tcp<'frame>(
1420         &mut self,
1421         sockets: &mut SocketSet,
1422         ip_repr: IpRepr,
1423         ip_payload: &'frame [u8],
1424     ) -> Option<IpPacket<'frame>> {
1425         let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
1426         let tcp_packet = check!(TcpPacket::new_checked(ip_payload));
1427         let tcp_repr = check!(TcpRepr::parse(
1428             &tcp_packet,
1429             &src_addr,
1430             &dst_addr,
1431             &self.caps.checksum
1432         ));
1433 
1434         for tcp_socket in sockets
1435             .items_mut()
1436             .filter_map(|i| tcp::Socket::downcast_mut(&mut i.socket))
1437         {
1438             if tcp_socket.accepts(self, &ip_repr, &tcp_repr) {
1439                 return tcp_socket
1440                     .process(self, &ip_repr, &tcp_repr)
1441                     .map(IpPacket::Tcp);
1442             }
1443         }
1444 
1445         if tcp_repr.control == TcpControl::Rst {
1446             // Never reply to a TCP RST packet with another TCP RST packet.
1447             None
1448         } else {
1449             // The packet wasn't handled by a socket, send a TCP RST packet.
1450             Some(IpPacket::Tcp(tcp::Socket::rst_reply(&ip_repr, &tcp_repr)))
1451         }
1452     }
1453 
1454     #[cfg(feature = "medium-ethernet")]
dispatch<Tx>( &mut self, tx_token: Tx, packet: EthernetPacket, frag: &mut Fragmenter, ) -> Result<(), DispatchError> where Tx: TxToken,1455     fn dispatch<Tx>(
1456         &mut self,
1457         tx_token: Tx,
1458         packet: EthernetPacket,
1459         frag: &mut Fragmenter,
1460     ) -> Result<(), DispatchError>
1461     where
1462         Tx: TxToken,
1463     {
1464         match packet {
1465             #[cfg(feature = "proto-ipv4")]
1466             EthernetPacket::Arp(arp_repr) => {
1467                 let dst_hardware_addr = match arp_repr {
1468                     ArpRepr::EthernetIpv4 {
1469                         target_hardware_addr,
1470                         ..
1471                     } => target_hardware_addr,
1472                 };
1473 
1474                 self.dispatch_ethernet(tx_token, arp_repr.buffer_len(), |mut frame| {
1475                     frame.set_dst_addr(dst_hardware_addr);
1476                     frame.set_ethertype(EthernetProtocol::Arp);
1477 
1478                     let mut packet = ArpPacket::new_unchecked(frame.payload_mut());
1479                     arp_repr.emit(&mut packet);
1480                 })
1481             }
1482             EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, frag),
1483         }
1484     }
1485 
in_same_network(&self, addr: &IpAddress) -> bool1486     fn in_same_network(&self, addr: &IpAddress) -> bool {
1487         self.ip_addrs.iter().any(|cidr| cidr.contains_addr(addr))
1488     }
1489 
route(&self, addr: &IpAddress, timestamp: Instant) -> Option<IpAddress>1490     fn route(&self, addr: &IpAddress, timestamp: Instant) -> Option<IpAddress> {
1491         // Send directly.
1492         if self.in_same_network(addr) || addr.is_broadcast() {
1493             return Some(*addr);
1494         }
1495 
1496         // Route via a router.
1497         self.routes.lookup(addr, timestamp)
1498     }
1499 
has_neighbor(&self, addr: &IpAddress) -> bool1500     fn has_neighbor(&self, addr: &IpAddress) -> bool {
1501         match self.route(addr, self.now) {
1502             Some(_routed_addr) => match self.caps.medium {
1503                 #[cfg(feature = "medium-ethernet")]
1504                 Medium::Ethernet => self
1505                     .neighbor_cache
1506                     .as_ref()
1507                     .unwrap()
1508                     .lookup(&_routed_addr, self.now)
1509                     .found(),
1510                 #[cfg(feature = "medium-ieee802154")]
1511                 Medium::Ieee802154 => self
1512                     .neighbor_cache
1513                     .as_ref()
1514                     .unwrap()
1515                     .lookup(&_routed_addr, self.now)
1516                     .found(),
1517                 #[cfg(feature = "medium-ip")]
1518                 Medium::Ip => true,
1519             },
1520             None => false,
1521         }
1522     }
1523 
1524     #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
lookup_hardware_addr<Tx>( &mut self, tx_token: Tx, src_addr: &IpAddress, dst_addr: &IpAddress, fragmenter: &mut Fragmenter, ) -> Result<(HardwareAddress, Tx), DispatchError> where Tx: TxToken,1525     fn lookup_hardware_addr<Tx>(
1526         &mut self,
1527         tx_token: Tx,
1528         src_addr: &IpAddress,
1529         dst_addr: &IpAddress,
1530         fragmenter: &mut Fragmenter,
1531     ) -> Result<(HardwareAddress, Tx), DispatchError>
1532     where
1533         Tx: TxToken,
1534     {
1535         if dst_addr.is_broadcast() {
1536             let hardware_addr = match self.caps.medium {
1537                 #[cfg(feature = "medium-ethernet")]
1538                 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::BROADCAST),
1539                 #[cfg(feature = "medium-ieee802154")]
1540                 Medium::Ieee802154 => HardwareAddress::Ieee802154(Ieee802154Address::BROADCAST),
1541                 #[cfg(feature = "medium-ip")]
1542                 Medium::Ip => unreachable!(),
1543             };
1544 
1545             return Ok((hardware_addr, tx_token));
1546         }
1547 
1548         if dst_addr.is_multicast() {
1549             let b = dst_addr.as_bytes();
1550             let hardware_addr = match *dst_addr {
1551                 #[cfg(feature = "proto-ipv4")]
1552                 IpAddress::Ipv4(_addr) => {
1553                     HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
1554                         0x01,
1555                         0x00,
1556                         0x5e,
1557                         b[1] & 0x7F,
1558                         b[2],
1559                         b[3],
1560                     ]))
1561                 }
1562                 #[cfg(feature = "proto-ipv6")]
1563                 IpAddress::Ipv6(_addr) => match self.caps.medium {
1564                     #[cfg(feature = "medium-ethernet")]
1565                     Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
1566                         0x33, 0x33, b[12], b[13], b[14], b[15],
1567                     ])),
1568                     #[cfg(feature = "medium-ieee802154")]
1569                     Medium::Ieee802154 => {
1570                         // Not sure if this is correct
1571                         HardwareAddress::Ieee802154(Ieee802154Address::BROADCAST)
1572                     }
1573                     #[cfg(feature = "medium-ip")]
1574                     Medium::Ip => unreachable!(),
1575                 },
1576             };
1577 
1578             return Ok((hardware_addr, tx_token));
1579         }
1580 
1581         let dst_addr = self
1582             .route(dst_addr, self.now)
1583             .ok_or(DispatchError::NoRoute)?;
1584 
1585         match self
1586             .neighbor_cache
1587             .as_mut()
1588             .unwrap()
1589             .lookup(&dst_addr, self.now)
1590         {
1591             NeighborAnswer::Found(hardware_addr) => return Ok((hardware_addr, tx_token)),
1592             NeighborAnswer::RateLimited => return Err(DispatchError::NeighborPending),
1593             _ => (), // XXX
1594         }
1595 
1596         match (src_addr, dst_addr) {
1597             #[cfg(feature = "proto-ipv4")]
1598             (&IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) => {
1599                 net_debug!(
1600                     "address {} not in neighbor cache, sending ARP request",
1601                     dst_addr
1602                 );
1603                 let src_hardware_addr = self.hardware_addr.unwrap().ethernet_or_panic();
1604 
1605                 let arp_repr = ArpRepr::EthernetIpv4 {
1606                     operation: ArpOperation::Request,
1607                     source_hardware_addr: src_hardware_addr,
1608                     source_protocol_addr: src_addr,
1609                     target_hardware_addr: EthernetAddress::BROADCAST,
1610                     target_protocol_addr: dst_addr,
1611                 };
1612 
1613                 if let Err(e) =
1614                     self.dispatch_ethernet(tx_token, arp_repr.buffer_len(), |mut frame| {
1615                         frame.set_dst_addr(EthernetAddress::BROADCAST);
1616                         frame.set_ethertype(EthernetProtocol::Arp);
1617 
1618                         arp_repr.emit(&mut ArpPacket::new_unchecked(frame.payload_mut()))
1619                     })
1620                 {
1621                     net_debug!("Failed to dispatch ARP request: {:?}", e);
1622                     return Err(DispatchError::NeighborPending);
1623                 }
1624             }
1625 
1626             #[cfg(feature = "proto-ipv6")]
1627             (&IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => {
1628                 net_debug!(
1629                     "address {} not in neighbor cache, sending Neighbor Solicitation",
1630                     dst_addr
1631                 );
1632 
1633                 let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
1634                     target_addr: dst_addr,
1635                     lladdr: Some(self.hardware_addr.unwrap().into()),
1636                 });
1637 
1638                 let packet = IpPacket::Icmpv6((
1639                     Ipv6Repr {
1640                         src_addr,
1641                         dst_addr: dst_addr.solicited_node(),
1642                         next_header: IpProtocol::Icmpv6,
1643                         payload_len: solicit.buffer_len(),
1644                         hop_limit: 0xff,
1645                     },
1646                     solicit,
1647                 ));
1648 
1649                 if let Err(e) = self.dispatch_ip(tx_token, packet, fragmenter) {
1650                     net_debug!("Failed to dispatch NDISC solicit: {:?}", e);
1651                     return Err(DispatchError::NeighborPending);
1652                 }
1653             }
1654 
1655             #[allow(unreachable_patterns)]
1656             _ => (),
1657         }
1658 
1659         // The request got dispatched, limit the rate on the cache.
1660         self.neighbor_cache.as_mut().unwrap().limit_rate(self.now);
1661         Err(DispatchError::NeighborPending)
1662     }
1663 
flush_cache(&mut self)1664     fn flush_cache(&mut self) {
1665         #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
1666         if let Some(cache) = self.neighbor_cache.as_mut() {
1667             cache.flush()
1668         }
1669     }
1670 
dispatch_ip<Tx: TxToken>( &mut self, tx_token: Tx, packet: IpPacket, frag: &mut Fragmenter, ) -> Result<(), DispatchError>1671     fn dispatch_ip<Tx: TxToken>(
1672         &mut self,
1673         tx_token: Tx,
1674         packet: IpPacket,
1675         frag: &mut Fragmenter,
1676     ) -> Result<(), DispatchError> {
1677         let ip_repr = packet.ip_repr();
1678         assert!(!ip_repr.dst_addr().is_unspecified());
1679 
1680         // Dispatch IEEE802.15.4:
1681 
1682         #[cfg(feature = "medium-ieee802154")]
1683         if matches!(self.caps.medium, Medium::Ieee802154) {
1684             let (addr, tx_token) = self.lookup_hardware_addr(
1685                 tx_token,
1686                 &ip_repr.src_addr(),
1687                 &ip_repr.dst_addr(),
1688                 frag,
1689             )?;
1690             let addr = addr.ieee802154_or_panic();
1691 
1692             self.dispatch_ieee802154(addr, tx_token, packet, frag);
1693             return Ok(());
1694         }
1695 
1696         // Dispatch IP/Ethernet:
1697 
1698         let caps = self.caps.clone();
1699 
1700         #[cfg(feature = "proto-ipv4-fragmentation")]
1701         let ipv4_id = self.get_ipv4_ident();
1702 
1703         // First we calculate the total length that we will have to emit.
1704         let mut total_len = ip_repr.buffer_len();
1705 
1706         // Add the size of the Ethernet header if the medium is Ethernet.
1707         #[cfg(feature = "medium-ethernet")]
1708         if matches!(self.caps.medium, Medium::Ethernet) {
1709             total_len = EthernetFrame::<&[u8]>::buffer_len(total_len);
1710         }
1711 
1712         // If the medium is Ethernet, then we need to retrieve the destination hardware address.
1713         #[cfg(feature = "medium-ethernet")]
1714         let (dst_hardware_addr, tx_token) = match self.caps.medium {
1715             Medium::Ethernet => {
1716                 match self.lookup_hardware_addr(
1717                     tx_token,
1718                     &ip_repr.src_addr(),
1719                     &ip_repr.dst_addr(),
1720                     frag,
1721                 )? {
1722                     (HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token),
1723                     #[cfg(feature = "medium-ieee802154")]
1724                     (HardwareAddress::Ieee802154(_), _) => unreachable!(),
1725                 }
1726             }
1727             _ => (EthernetAddress([0; 6]), tx_token),
1728         };
1729 
1730         // Emit function for the Ethernet header.
1731         #[cfg(feature = "medium-ethernet")]
1732         let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
1733             let mut frame = EthernetFrame::new_unchecked(tx_buffer);
1734 
1735             let src_addr = self.hardware_addr.unwrap().ethernet_or_panic();
1736             frame.set_src_addr(src_addr);
1737             frame.set_dst_addr(dst_hardware_addr);
1738 
1739             match repr.version() {
1740                 #[cfg(feature = "proto-ipv4")]
1741                 IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
1742                 #[cfg(feature = "proto-ipv6")]
1743                 IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
1744             }
1745 
1746             Ok(())
1747         };
1748 
1749         // Emit function for the IP header and payload.
1750         let emit_ip = |repr: &IpRepr, mut tx_buffer: &mut [u8]| {
1751             repr.emit(&mut tx_buffer, &self.caps.checksum);
1752 
1753             let payload = &mut tx_buffer[repr.header_len()..];
1754             packet.emit_payload(repr, payload, &caps);
1755         };
1756 
1757         let total_ip_len = ip_repr.buffer_len();
1758 
1759         match ip_repr {
1760             #[cfg(feature = "proto-ipv4")]
1761             IpRepr::Ipv4(mut repr) => {
1762                 // If we have an IPv4 packet, then we need to check if we need to fragment it.
1763                 if total_ip_len > self.caps.max_transmission_unit {
1764                     #[cfg(feature = "proto-ipv4-fragmentation")]
1765                     {
1766                         net_debug!("start fragmentation");
1767 
1768                         // Calculate how much we will send now (including the Ethernet header).
1769                         let tx_len = self.caps.max_transmission_unit;
1770 
1771                         let ip_header_len = repr.buffer_len();
1772                         let first_frag_ip_len = self.caps.ip_mtu();
1773 
1774                         if frag.buffer.len() < first_frag_ip_len {
1775                             net_debug!(
1776                                 "Fragmentation buffer is too small, at least {} needed. Dropping",
1777                                 first_frag_ip_len
1778                             );
1779                             return Ok(());
1780                         }
1781 
1782                         #[cfg(feature = "medium-ethernet")]
1783                         {
1784                             frag.ipv4.dst_hardware_addr = dst_hardware_addr;
1785                         }
1786 
1787                         // Save the total packet len (without the Ethernet header, but with the first
1788                         // IP header).
1789                         frag.packet_len = total_ip_len;
1790 
1791                         // Save the IP header for other fragments.
1792                         frag.ipv4.repr = repr;
1793 
1794                         // Save how much bytes we will send now.
1795                         frag.sent_bytes = first_frag_ip_len;
1796 
1797                         // Modify the IP header
1798                         repr.payload_len = first_frag_ip_len - repr.buffer_len();
1799 
1800                         // Emit the IP header to the buffer.
1801                         emit_ip(&ip_repr, &mut frag.buffer);
1802                         let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut frag.buffer[..]);
1803                         frag.ipv4.ident = ipv4_id;
1804                         ipv4_packet.set_ident(ipv4_id);
1805                         ipv4_packet.set_more_frags(true);
1806                         ipv4_packet.set_dont_frag(false);
1807                         ipv4_packet.set_frag_offset(0);
1808 
1809                         if caps.checksum.ipv4.tx() {
1810                             ipv4_packet.fill_checksum();
1811                         }
1812 
1813                         // Transmit the first packet.
1814                         tx_token.consume(tx_len, |mut tx_buffer| {
1815                             #[cfg(feature = "medium-ethernet")]
1816                             if matches!(self.caps.medium, Medium::Ethernet) {
1817                                 emit_ethernet(&ip_repr, tx_buffer)?;
1818                                 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1819                             }
1820 
1821                             // Change the offset for the next packet.
1822                             frag.ipv4.frag_offset = (first_frag_ip_len - ip_header_len) as u16;
1823 
1824                             // Copy the IP header and the payload.
1825                             tx_buffer[..first_frag_ip_len]
1826                                 .copy_from_slice(&frag.buffer[..first_frag_ip_len]);
1827 
1828                             Ok(())
1829                         })
1830                     }
1831 
1832                     #[cfg(not(feature = "proto-ipv4-fragmentation"))]
1833                     {
1834                         net_debug!("Enable the `proto-ipv4-fragmentation` feature for fragmentation support.");
1835                         Ok(())
1836                     }
1837                 } else {
1838                     // No fragmentation is required.
1839                     tx_token.consume(total_len, |mut tx_buffer| {
1840                         #[cfg(feature = "medium-ethernet")]
1841                         if matches!(self.caps.medium, Medium::Ethernet) {
1842                             emit_ethernet(&ip_repr, tx_buffer)?;
1843                             tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1844                         }
1845 
1846                         emit_ip(&ip_repr, tx_buffer);
1847                         Ok(())
1848                     })
1849                 }
1850             }
1851             // We don't support IPv6 fragmentation yet.
1852             #[cfg(feature = "proto-ipv6")]
1853             IpRepr::Ipv6(_) => tx_token.consume(total_len, |mut tx_buffer| {
1854                 #[cfg(feature = "medium-ethernet")]
1855                 if matches!(self.caps.medium, Medium::Ethernet) {
1856                     emit_ethernet(&ip_repr, tx_buffer)?;
1857                     tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1858                 }
1859 
1860                 emit_ip(&ip_repr, tx_buffer);
1861                 Ok(())
1862             }),
1863         }
1864     }
1865 }
1866 
1867 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1868 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
1869 enum DispatchError {
1870     /// No route to dispatch this packet. Retrying won't help unless
1871     /// configuration is changed.
1872     NoRoute,
1873     /// We do have a route to dispatch this packet, but we haven't discovered
1874     /// the neighbor for it yet. Discovery has been initiated, dispatch
1875     /// should be retried later.
1876     NeighborPending,
1877 }
1878