1#[cfg(test)]
6mod tests;
7
8#[cfg(feature = "medium-ethernet")]
9mod ethernet;
10#[cfg(feature = "medium-ieee802154")]
11mod ieee802154;
12
13#[cfg(feature = "proto-ipv4")]
14mod ipv4;
15#[cfg(feature = "proto-ipv6")]
16mod ipv6;
17#[cfg(feature = "proto-sixlowpan")]
18mod sixlowpan;
19
20#[cfg(feature = "multicast")]
21pub(crate) mod multicast;
22#[cfg(feature = "socket-tcp")]
23mod tcp;
24#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
25mod udp;
26
27use super::packet::*;
28
29use core::result::Result;
30use heapless::Vec;
31
32#[cfg(feature = "_proto-fragmentation")]
33use super::fragmentation::FragKey;
34#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
35use super::fragmentation::PacketAssemblerSet;
36use super::fragmentation::{Fragmenter, FragmentsBuffer};
37
38#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
39use super::neighbor::{Answer as NeighborAnswer, Cache as NeighborCache};
40use super::socket_set::SocketSet;
41use crate::config::{IFACE_MAX_ADDR_COUNT, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT};
42use crate::iface::Routes;
43use crate::phy::PacketMeta;
44use crate::phy::{ChecksumCapabilities, Device, DeviceCapabilities, Medium, RxToken, TxToken};
45use crate::rand::Rand;
46use crate::socket::*;
47use crate::time::{Duration, Instant};
48
49use crate::wire::*;
50
51macro_rules! check {
52 ($e:expr) => {
53 match $e {
54 Ok(x) => x,
55 Err(_) => {
56 #[cfg(not(feature = "defmt"))]
58 net_trace!(concat!("iface: malformed ", stringify!($e)));
59 #[cfg(feature = "defmt")]
60 net_trace!("iface: malformed");
61 return Default::default();
62 }
63 }
64 };
65}
66use check;
67
68#[derive(Copy, Clone, PartialEq, Eq, Debug)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub enum PollResult {
74 None,
76 SocketStateChanged,
78}
79
80#[derive(Copy, Clone, PartialEq, Eq, Debug)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub enum PollIngressSingleResult {
87 None,
92 PacketProcessed,
98 SocketStateChanged,
104}
105
106pub struct Interface {
112 pub(crate) inner: InterfaceInner,
113 fragments: FragmentsBuffer,
114 fragmenter: Fragmenter,
115}
116
117pub struct InterfaceInner {
125 caps: DeviceCapabilities,
126 now: Instant,
127 rand: Rand,
128
129 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
130 neighbor_cache: NeighborCache,
131 hardware_addr: HardwareAddress,
132 #[cfg(feature = "medium-ieee802154")]
133 sequence_no: u8,
134 #[cfg(feature = "medium-ieee802154")]
135 pan_id: Option<Ieee802154Pan>,
136 #[cfg(feature = "proto-ipv4-fragmentation")]
137 ipv4_id: u16,
138 #[cfg(feature = "proto-sixlowpan")]
139 sixlowpan_address_context:
140 Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT>,
141 #[cfg(feature = "proto-sixlowpan-fragmentation")]
142 tag: u16,
143 ip_addrs: Vec<IpCidr, IFACE_MAX_ADDR_COUNT>,
144 any_ip: bool,
145 routes: Routes,
146 #[cfg(feature = "multicast")]
147 multicast: multicast::State,
148}
149
150#[non_exhaustive]
152pub struct Config {
153 pub random_seed: u64,
160
161 pub hardware_addr: HardwareAddress,
166
167 #[cfg(feature = "medium-ieee802154")]
171 pub pan_id: Option<Ieee802154Pan>,
172}
173
174impl Config {
175 pub fn new(hardware_addr: HardwareAddress) -> Self {
176 Config {
177 random_seed: 0,
178 hardware_addr,
179 #[cfg(feature = "medium-ieee802154")]
180 pan_id: None,
181 }
182 }
183}
184
185impl Interface {
186 pub fn new(config: Config, device: &mut (impl Device + ?Sized), now: Instant) -> Self {
192 let caps = device.capabilities();
193 assert_eq!(
194 config.hardware_addr.medium(),
195 caps.medium,
196 "The hardware address does not match the medium of the interface."
197 );
198
199 let mut rand = Rand::new(config.random_seed);
200
201 #[cfg(feature = "medium-ieee802154")]
202 let mut sequence_no;
203 #[cfg(feature = "medium-ieee802154")]
204 loop {
205 sequence_no = (rand.rand_u32() & 0xff) as u8;
206 if sequence_no != 0 {
207 break;
208 }
209 }
210
211 #[cfg(feature = "proto-sixlowpan")]
212 let mut tag;
213
214 #[cfg(feature = "proto-sixlowpan")]
215 loop {
216 tag = rand.rand_u16();
217 if tag != 0 {
218 break;
219 }
220 }
221
222 #[cfg(feature = "proto-ipv4")]
223 let mut ipv4_id;
224
225 #[cfg(feature = "proto-ipv4")]
226 loop {
227 ipv4_id = rand.rand_u16();
228 if ipv4_id != 0 {
229 break;
230 }
231 }
232
233 Interface {
234 fragments: FragmentsBuffer {
235 #[cfg(feature = "proto-sixlowpan")]
236 decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
237
238 #[cfg(feature = "_proto-fragmentation")]
239 assembler: PacketAssemblerSet::new(),
240 #[cfg(feature = "_proto-fragmentation")]
241 reassembly_timeout: Duration::from_secs(60),
242 },
243 fragmenter: Fragmenter::new(),
244 inner: InterfaceInner {
245 now,
246 caps,
247 hardware_addr: config.hardware_addr,
248 ip_addrs: Vec::new(),
249 any_ip: false,
250 routes: Routes::new(),
251 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
252 neighbor_cache: NeighborCache::new(),
253 #[cfg(feature = "multicast")]
254 multicast: multicast::State::new(),
255 #[cfg(feature = "medium-ieee802154")]
256 sequence_no,
257 #[cfg(feature = "medium-ieee802154")]
258 pan_id: config.pan_id,
259 #[cfg(feature = "proto-sixlowpan-fragmentation")]
260 tag,
261 #[cfg(feature = "proto-ipv4-fragmentation")]
262 ipv4_id,
263 #[cfg(feature = "proto-sixlowpan")]
264 sixlowpan_address_context: Vec::new(),
265 rand,
266 },
267 }
268 }
269
270 pub fn context(&mut self) -> &mut InterfaceInner {
274 &mut self.inner
275 }
276
277 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
282 pub fn hardware_addr(&self) -> HardwareAddress {
283 #[cfg(all(feature = "medium-ethernet", not(feature = "medium-ieee802154")))]
284 assert!(self.inner.caps.medium == Medium::Ethernet);
285 #[cfg(all(feature = "medium-ieee802154", not(feature = "medium-ethernet")))]
286 assert!(self.inner.caps.medium == Medium::Ieee802154);
287
288 #[cfg(all(feature = "medium-ieee802154", feature = "medium-ethernet"))]
289 assert!(
290 self.inner.caps.medium == Medium::Ethernet
291 || self.inner.caps.medium == Medium::Ieee802154
292 );
293
294 self.inner.hardware_addr
295 }
296
297 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
303 pub fn set_hardware_addr(&mut self, addr: HardwareAddress) {
304 #[cfg(all(feature = "medium-ethernet", not(feature = "medium-ieee802154")))]
305 assert!(self.inner.caps.medium == Medium::Ethernet);
306 #[cfg(all(feature = "medium-ieee802154", not(feature = "medium-ethernet")))]
307 assert!(self.inner.caps.medium == Medium::Ieee802154);
308
309 #[cfg(all(feature = "medium-ieee802154", feature = "medium-ethernet"))]
310 assert!(
311 self.inner.caps.medium == Medium::Ethernet
312 || self.inner.caps.medium == Medium::Ieee802154
313 );
314
315 InterfaceInner::check_hardware_addr(&addr);
316 self.inner.hardware_addr = addr;
317 }
318
319 pub fn ip_addrs(&self) -> &[IpCidr] {
321 self.inner.ip_addrs.as_ref()
322 }
323
324 #[cfg(feature = "proto-ipv4")]
326 pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
327 self.inner.ipv4_addr()
328 }
329
330 #[cfg(feature = "proto-ipv6")]
332 pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
333 self.inner.ipv6_addr()
334 }
335
336 pub fn get_source_address(&self, dst_addr: &IpAddress) -> Option<IpAddress> {
340 self.inner.get_source_address(dst_addr)
341 }
342
343 #[cfg(feature = "proto-ipv4")]
346 pub fn get_source_address_ipv4(&self, dst_addr: &Ipv4Address) -> Option<Ipv4Address> {
347 self.inner.get_source_address_ipv4(dst_addr)
348 }
349
350 #[cfg(feature = "proto-ipv6")]
353 pub fn get_source_address_ipv6(&self, dst_addr: &Ipv6Address) -> Ipv6Address {
354 self.inner.get_source_address_ipv6(dst_addr)
355 }
356
357 pub fn update_ip_addrs<F: FnOnce(&mut Vec<IpCidr, IFACE_MAX_ADDR_COUNT>)>(&mut self, f: F) {
362 f(&mut self.inner.ip_addrs);
363 InterfaceInner::flush_neighbor_cache(&mut self.inner);
364 InterfaceInner::check_ip_addrs(&self.inner.ip_addrs);
365
366 #[cfg(all(feature = "proto-ipv6", feature = "multicast"))]
367 if self.inner.caps.medium == Medium::Ethernet {
368 self.update_solicited_node_groups();
369 }
370 }
371
372 pub fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
374 self.inner.has_ip_addr(addr)
375 }
376
377 pub fn routes(&self) -> &Routes {
378 &self.inner.routes
379 }
380
381 pub fn routes_mut(&mut self) -> &mut Routes {
382 &mut self.inner.routes
383 }
384
385 pub fn set_any_ip(&mut self, any_ip: bool) {
393 self.inner.any_ip = any_ip;
394 }
395
396 pub fn any_ip(&self) -> bool {
400 self.inner.any_ip
401 }
402
403 #[cfg(feature = "_proto-fragmentation")]
405 pub fn reassembly_timeout(&self) -> Duration {
406 self.fragments.reassembly_timeout
407 }
408
409 #[cfg(feature = "_proto-fragmentation")]
411 pub fn set_reassembly_timeout(&mut self, timeout: Duration) {
412 if timeout > Duration::from_secs(60) {
413 net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
414 }
415 self.fragments.reassembly_timeout = timeout;
416 }
417
418 pub fn poll(
437 &mut self,
438 timestamp: Instant,
439 device: &mut (impl Device + ?Sized),
440 sockets: &mut SocketSet<'_>,
441 ) -> PollResult {
442 self.inner.now = timestamp;
443
444 let mut res = PollResult::None;
445
446 #[cfg(feature = "_proto-fragmentation")]
447 self.fragments.assembler.remove_expired(timestamp);
448
449 loop {
451 match self.socket_ingress(device, sockets) {
452 PollIngressSingleResult::None => break,
453 PollIngressSingleResult::PacketProcessed => {}
454 PollIngressSingleResult::SocketStateChanged => res = PollResult::SocketStateChanged,
455 }
456 }
457
458 match self.poll_egress(timestamp, device, sockets) {
460 PollResult::None => {}
461 PollResult::SocketStateChanged => res = PollResult::SocketStateChanged,
462 }
463
464 res
465 }
466
467 pub fn poll_egress(
474 &mut self,
475 timestamp: Instant,
476 device: &mut (impl Device + ?Sized),
477 sockets: &mut SocketSet<'_>,
478 ) -> PollResult {
479 self.inner.now = timestamp;
480
481 match self.inner.caps.medium {
482 #[cfg(feature = "medium-ieee802154")]
483 Medium::Ieee802154 => {
484 #[cfg(feature = "proto-sixlowpan-fragmentation")]
485 self.sixlowpan_egress(device);
486 }
487 #[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
488 _ => {
489 #[cfg(feature = "proto-ipv4-fragmentation")]
490 self.ipv4_egress(device);
491 }
492 }
493
494 #[cfg(feature = "multicast")]
495 self.multicast_egress(device);
496
497 self.socket_egress(device, sockets)
498 }
499
500 pub fn poll_ingress_single(
508 &mut self,
509 timestamp: Instant,
510 device: &mut (impl Device + ?Sized),
511 sockets: &mut SocketSet<'_>,
512 ) -> PollIngressSingleResult {
513 self.inner.now = timestamp;
514
515 #[cfg(feature = "_proto-fragmentation")]
516 self.fragments.assembler.remove_expired(timestamp);
517
518 self.socket_ingress(device, sockets)
519 }
520
521 pub fn poll_at(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Instant> {
530 self.inner.now = timestamp;
531
532 #[cfg(feature = "_proto-fragmentation")]
533 if !self.fragmenter.is_empty() {
534 return Some(Instant::from_millis(0));
535 }
536
537 let inner = &mut self.inner;
538
539 sockets
540 .items()
541 .filter_map(move |item| {
542 let socket_poll_at = item.socket.poll_at(inner);
543 match item
544 .meta
545 .poll_at(socket_poll_at, |ip_addr| inner.has_neighbor(&ip_addr))
546 {
547 PollAt::Ingress => None,
548 PollAt::Time(instant) => Some(instant),
549 PollAt::Now => Some(Instant::from_millis(0)),
550 }
551 })
552 .min()
553 }
554
555 pub fn poll_delay(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Duration> {
564 match self.poll_at(timestamp, sockets) {
565 Some(poll_at) if timestamp < poll_at => Some(poll_at - timestamp),
566 Some(_) => Some(Duration::from_millis(0)),
567 _ => None,
568 }
569 }
570
571 fn socket_ingress(
572 &mut self,
573 device: &mut (impl Device + ?Sized),
574 sockets: &mut SocketSet<'_>,
575 ) -> PollIngressSingleResult {
576 let Some((rx_token, tx_token)) = device.receive(self.inner.now) else {
577 return PollIngressSingleResult::None;
578 };
579
580 let rx_meta = rx_token.meta();
581 rx_token.consume(|frame| {
582 if frame.is_empty() {
583 return PollIngressSingleResult::PacketProcessed;
584 }
585
586 match self.inner.caps.medium {
587 #[cfg(feature = "medium-ethernet")]
588 Medium::Ethernet => {
589 if let Some(packet) =
590 self.inner
591 .process_ethernet(sockets, rx_meta, frame, &mut self.fragments)
592 {
593 if let Err(err) =
594 self.inner.dispatch(tx_token, packet, &mut self.fragmenter)
595 {
596 net_debug!("Failed to send response: {:?}", err);
597 }
598 }
599 }
600 #[cfg(feature = "medium-ip")]
601 Medium::Ip => {
602 if let Some(packet) =
603 self.inner
604 .process_ip(sockets, rx_meta, frame, &mut self.fragments)
605 {
606 if let Err(err) = self.inner.dispatch_ip(
607 tx_token,
608 PacketMeta::default(),
609 packet,
610 &mut self.fragmenter,
611 ) {
612 net_debug!("Failed to send response: {:?}", err);
613 }
614 }
615 }
616 #[cfg(feature = "medium-ieee802154")]
617 Medium::Ieee802154 => {
618 if let Some(packet) =
619 self.inner
620 .process_ieee802154(sockets, rx_meta, frame, &mut self.fragments)
621 {
622 if let Err(err) = self.inner.dispatch_ip(
623 tx_token,
624 PacketMeta::default(),
625 packet,
626 &mut self.fragmenter,
627 ) {
628 net_debug!("Failed to send response: {:?}", err);
629 }
630 }
631 }
632 }
633
634 PollIngressSingleResult::SocketStateChanged
641 })
642 }
643
644 fn socket_egress(
645 &mut self,
646 device: &mut (impl Device + ?Sized),
647 sockets: &mut SocketSet<'_>,
648 ) -> PollResult {
649 let _caps = device.capabilities();
650
651 enum EgressError {
652 Exhausted,
653 Dispatch,
654 }
655
656 let mut result = PollResult::None;
657 for item in sockets.items_mut() {
658 if !item
659 .meta
660 .egress_permitted(self.inner.now, |ip_addr| self.inner.has_neighbor(&ip_addr))
661 {
662 continue;
663 }
664
665 let mut neighbor_addr = None;
666 let mut respond = |inner: &mut InterfaceInner, meta: PacketMeta, response: Packet| {
667 neighbor_addr = Some(response.ip_repr().dst_addr());
668 let t = device.transmit(inner.now).ok_or_else(|| {
669 net_debug!("failed to transmit IP: device exhausted");
670 EgressError::Exhausted
671 })?;
672
673 inner
674 .dispatch_ip(t, meta, response, &mut self.fragmenter)
675 .map_err(|_| EgressError::Dispatch)?;
676
677 result = PollResult::SocketStateChanged;
678
679 Ok(())
680 };
681
682 let result = match &mut item.socket {
683 #[cfg(feature = "socket-raw")]
684 Socket::Raw(socket) => socket.dispatch(&mut self.inner, |inner, (ip, raw)| {
685 respond(
686 inner,
687 PacketMeta::default(),
688 Packet::new(ip, IpPayload::Raw(raw)),
689 )
690 }),
691 #[cfg(feature = "socket-icmp")]
692 Socket::Icmp(socket) => {
693 socket.dispatch(&mut self.inner, |inner, response| match response {
694 #[cfg(feature = "proto-ipv4")]
695 (IpRepr::Ipv4(ipv4_repr), IcmpRepr::Ipv4(icmpv4_repr)) => respond(
696 inner,
697 PacketMeta::default(),
698 Packet::new_ipv4(ipv4_repr, IpPayload::Icmpv4(icmpv4_repr)),
699 ),
700 #[cfg(feature = "proto-ipv6")]
701 (IpRepr::Ipv6(ipv6_repr), IcmpRepr::Ipv6(icmpv6_repr)) => respond(
702 inner,
703 PacketMeta::default(),
704 Packet::new_ipv6(ipv6_repr, IpPayload::Icmpv6(icmpv6_repr)),
705 ),
706 #[allow(unreachable_patterns)]
707 _ => unreachable!(),
708 })
709 }
710 #[cfg(feature = "socket-udp")]
711 Socket::Udp(socket) => {
712 socket.dispatch(&mut self.inner, |inner, meta, (ip, udp, payload)| {
713 respond(inner, meta, Packet::new(ip, IpPayload::Udp(udp, payload)))
714 })
715 }
716 #[cfg(feature = "socket-tcp")]
717 Socket::Tcp(socket) => socket.dispatch(&mut self.inner, |inner, (ip, tcp)| {
718 respond(
719 inner,
720 PacketMeta::default(),
721 Packet::new(ip, IpPayload::Tcp(tcp)),
722 )
723 }),
724 #[cfg(feature = "socket-dhcpv4")]
725 Socket::Dhcpv4(socket) => {
726 socket.dispatch(&mut self.inner, |inner, (ip, udp, dhcp)| {
727 respond(
728 inner,
729 PacketMeta::default(),
730 Packet::new_ipv4(ip, IpPayload::Dhcpv4(udp, dhcp)),
731 )
732 })
733 }
734 #[cfg(feature = "socket-dns")]
735 Socket::Dns(socket) => socket.dispatch(&mut self.inner, |inner, (ip, udp, dns)| {
736 respond(
737 inner,
738 PacketMeta::default(),
739 Packet::new(ip, IpPayload::Udp(udp, dns)),
740 )
741 }),
742 };
743
744 match result {
745 Err(EgressError::Exhausted) => break, Err(EgressError::Dispatch) => {
747 item.meta.neighbor_missing(
752 self.inner.now,
753 neighbor_addr.expect("non-IP response packet"),
754 );
755 }
756 Ok(()) => {}
757 }
758 }
759 result
760 }
761}
762
763impl InterfaceInner {
764 #[allow(unused)] pub(crate) fn now(&self) -> Instant {
766 self.now
767 }
768
769 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
770 #[allow(unused)] pub(crate) fn hardware_addr(&self) -> HardwareAddress {
772 self.hardware_addr
773 }
774
775 #[allow(unused)] pub(crate) fn checksum_caps(&self) -> ChecksumCapabilities {
777 self.caps.checksum.clone()
778 }
779
780 #[allow(unused)] pub(crate) fn ip_mtu(&self) -> usize {
782 self.caps.ip_mtu()
783 }
784
785 #[allow(unused)] pub(crate) fn rand(&mut self) -> &mut Rand {
787 &mut self.rand
788 }
789
790 #[allow(unused)] pub(crate) fn get_source_address(&self, dst_addr: &IpAddress) -> Option<IpAddress> {
792 match dst_addr {
793 #[cfg(feature = "proto-ipv4")]
794 IpAddress::Ipv4(addr) => self.get_source_address_ipv4(addr).map(|a| a.into()),
795 #[cfg(feature = "proto-ipv6")]
796 IpAddress::Ipv6(addr) => Some(self.get_source_address_ipv6(addr).into()),
797 }
798 }
799
800 #[cfg(test)]
801 #[allow(unused)] pub(crate) fn set_now(&mut self, now: Instant) {
803 self.now = now
804 }
805
806 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
807 fn check_hardware_addr(addr: &HardwareAddress) {
808 if !addr.is_unicast() {
809 panic!("Hardware address {addr} is not unicast")
810 }
811 }
812
813 fn check_ip_addrs(addrs: &[IpCidr]) {
814 for cidr in addrs {
815 if !cidr.address().is_unicast() && !cidr.address().is_unspecified() {
816 panic!("IP address {} is not unicast", cidr.address())
817 }
818 }
819 }
820
821 fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
823 let addr = addr.into();
824 self.ip_addrs.iter().any(|probe| probe.address() == addr)
825 }
826
827 fn has_multicast_group<T: Into<IpAddress>>(&self, addr: T) -> bool {
829 let addr = addr.into();
830
831 #[cfg(feature = "multicast")]
832 if self.multicast.has_multicast_group(addr) {
833 return true;
834 }
835
836 match addr {
837 #[cfg(feature = "proto-ipv4")]
838 IpAddress::Ipv4(key) => key == IPV4_MULTICAST_ALL_SYSTEMS,
839 #[cfg(feature = "proto-rpl")]
840 IpAddress::Ipv6(IPV6_LINK_LOCAL_ALL_RPL_NODES) => true,
841 #[cfg(feature = "proto-ipv6")]
842 IpAddress::Ipv6(key) => {
843 key == IPV6_LINK_LOCAL_ALL_NODES || self.has_solicited_node(key)
844 }
845 #[allow(unreachable_patterns)]
846 _ => false,
847 }
848 }
849
850 #[cfg(feature = "medium-ip")]
851 fn process_ip<'frame>(
852 &mut self,
853 sockets: &mut SocketSet,
854 meta: PacketMeta,
855 ip_payload: &'frame [u8],
856 frag: &'frame mut FragmentsBuffer,
857 ) -> Option<Packet<'frame>> {
858 match IpVersion::of_packet(ip_payload) {
859 #[cfg(feature = "proto-ipv4")]
860 Ok(IpVersion::Ipv4) => {
861 let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
862 self.process_ipv4(sockets, meta, HardwareAddress::Ip, &ipv4_packet, frag)
863 }
864 #[cfg(feature = "proto-ipv6")]
865 Ok(IpVersion::Ipv6) => {
866 let ipv6_packet = check!(Ipv6Packet::new_checked(ip_payload));
867 self.process_ipv6(sockets, meta, HardwareAddress::Ip, &ipv6_packet)
868 }
869 _ => None,
871 }
872 }
873
874 #[cfg(feature = "socket-raw")]
875 fn raw_socket_filter(
876 &mut self,
877 sockets: &mut SocketSet,
878 ip_repr: &IpRepr,
879 ip_payload: &[u8],
880 ) -> bool {
881 let mut handled_by_raw_socket = false;
882
883 for raw_socket in sockets
885 .items_mut()
886 .filter_map(|i| raw::Socket::downcast_mut(&mut i.socket))
887 {
888 if raw_socket.accepts(ip_repr) {
889 raw_socket.process(self, ip_repr, ip_payload);
890 handled_by_raw_socket = true;
891 }
892 }
893 handled_by_raw_socket
894 }
895
896 pub(crate) fn is_broadcast(&self, address: &IpAddress) -> bool {
899 match address {
900 #[cfg(feature = "proto-ipv4")]
901 IpAddress::Ipv4(address) => self.is_broadcast_v4(*address),
902 #[cfg(feature = "proto-ipv6")]
903 IpAddress::Ipv6(_) => false,
904 }
905 }
906
907 #[cfg(feature = "medium-ethernet")]
908 fn dispatch<Tx>(
909 &mut self,
910 tx_token: Tx,
911 packet: EthernetPacket,
912 frag: &mut Fragmenter,
913 ) -> Result<(), DispatchError>
914 where
915 Tx: TxToken,
916 {
917 match packet {
918 #[cfg(feature = "proto-ipv4")]
919 EthernetPacket::Arp(arp_repr) => {
920 let dst_hardware_addr = match arp_repr {
921 ArpRepr::EthernetIpv4 {
922 target_hardware_addr,
923 ..
924 } => target_hardware_addr,
925 };
926
927 self.dispatch_ethernet(tx_token, arp_repr.buffer_len(), |mut frame| {
928 frame.set_dst_addr(dst_hardware_addr);
929 frame.set_ethertype(EthernetProtocol::Arp);
930
931 let mut packet = ArpPacket::new_unchecked(frame.payload_mut());
932 arp_repr.emit(&mut packet);
933 })
934 }
935 EthernetPacket::Ip(packet) => {
936 self.dispatch_ip(tx_token, PacketMeta::default(), packet, frag)
937 }
938 }
939 }
940
941 fn in_same_network(&self, addr: &IpAddress) -> bool {
942 self.ip_addrs.iter().any(|cidr| cidr.contains_addr(addr))
943 }
944
945 fn route(&self, addr: &IpAddress, timestamp: Instant) -> Option<IpAddress> {
946 if self.in_same_network(addr) || addr.is_broadcast() {
950 return Some(*addr);
951 }
952
953 self.routes.lookup(addr, timestamp)
955 }
956
957 fn has_neighbor(&self, addr: &IpAddress) -> bool {
958 match self.route(addr, self.now) {
959 Some(_routed_addr) => match self.caps.medium {
960 #[cfg(feature = "medium-ethernet")]
961 Medium::Ethernet => self.neighbor_cache.lookup(&_routed_addr, self.now).found(),
962 #[cfg(feature = "medium-ieee802154")]
963 Medium::Ieee802154 => self.neighbor_cache.lookup(&_routed_addr, self.now).found(),
964 #[cfg(feature = "medium-ip")]
965 Medium::Ip => true,
966 },
967 None => false,
968 }
969 }
970
971 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
972 fn lookup_hardware_addr<Tx>(
973 &mut self,
974 tx_token: Tx,
975 dst_addr: &IpAddress,
976 fragmenter: &mut Fragmenter,
977 ) -> Result<(HardwareAddress, Tx), DispatchError>
978 where
979 Tx: TxToken,
980 {
981 if self.is_broadcast(dst_addr) {
982 let hardware_addr = match self.caps.medium {
983 #[cfg(feature = "medium-ethernet")]
984 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::BROADCAST),
985 #[cfg(feature = "medium-ieee802154")]
986 Medium::Ieee802154 => HardwareAddress::Ieee802154(Ieee802154Address::BROADCAST),
987 #[cfg(feature = "medium-ip")]
988 Medium::Ip => unreachable!(),
989 };
990
991 return Ok((hardware_addr, tx_token));
992 }
993
994 if dst_addr.is_multicast() {
995 let hardware_addr = match *dst_addr {
996 #[cfg(feature = "proto-ipv4")]
997 IpAddress::Ipv4(addr) => match self.caps.medium {
998 #[cfg(feature = "medium-ethernet")]
999 Medium::Ethernet => {
1000 let b = addr.octets();
1001 HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
1002 0x01,
1003 0x00,
1004 0x5e,
1005 b[1] & 0x7F,
1006 b[2],
1007 b[3],
1008 ]))
1009 }
1010 #[cfg(feature = "medium-ieee802154")]
1011 Medium::Ieee802154 => unreachable!(),
1012 #[cfg(feature = "medium-ip")]
1013 Medium::Ip => unreachable!(),
1014 },
1015 #[cfg(feature = "proto-ipv6")]
1016 IpAddress::Ipv6(addr) => match self.caps.medium {
1017 #[cfg(feature = "medium-ethernet")]
1018 Medium::Ethernet => {
1019 let b = addr.octets();
1020 HardwareAddress::Ethernet(EthernetAddress::from_bytes(&[
1021 0x33, 0x33, b[12], b[13], b[14], b[15],
1022 ]))
1023 }
1024 #[cfg(feature = "medium-ieee802154")]
1025 Medium::Ieee802154 => {
1026 HardwareAddress::Ieee802154(Ieee802154Address::BROADCAST)
1028 }
1029 #[cfg(feature = "medium-ip")]
1030 Medium::Ip => unreachable!(),
1031 },
1032 };
1033
1034 return Ok((hardware_addr, tx_token));
1035 }
1036
1037 let dst_addr = self
1038 .route(dst_addr, self.now)
1039 .ok_or(DispatchError::NoRoute)?;
1040
1041 match self.neighbor_cache.lookup(&dst_addr, self.now) {
1042 NeighborAnswer::Found(hardware_addr) => return Ok((hardware_addr, tx_token)),
1043 NeighborAnswer::RateLimited => return Err(DispatchError::NeighborPending),
1044 _ => (), }
1046
1047 match dst_addr {
1048 #[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
1049 IpAddress::Ipv4(dst_addr) if matches!(self.caps.medium, Medium::Ethernet) => {
1050 net_debug!(
1051 "address {} not in neighbor cache, sending ARP request",
1052 dst_addr
1053 );
1054 let src_hardware_addr = self.hardware_addr.ethernet_or_panic();
1055
1056 let arp_repr = ArpRepr::EthernetIpv4 {
1057 operation: ArpOperation::Request,
1058 source_hardware_addr: src_hardware_addr,
1059 source_protocol_addr: self
1060 .get_source_address_ipv4(&dst_addr)
1061 .ok_or(DispatchError::NoRoute)?,
1062 target_hardware_addr: EthernetAddress::BROADCAST,
1063 target_protocol_addr: dst_addr,
1064 };
1065
1066 if let Err(e) =
1067 self.dispatch_ethernet(tx_token, arp_repr.buffer_len(), |mut frame| {
1068 frame.set_dst_addr(EthernetAddress::BROADCAST);
1069 frame.set_ethertype(EthernetProtocol::Arp);
1070
1071 arp_repr.emit(&mut ArpPacket::new_unchecked(frame.payload_mut()))
1072 })
1073 {
1074 net_debug!("Failed to dispatch ARP request: {:?}", e);
1075 return Err(DispatchError::NeighborPending);
1076 }
1077 }
1078
1079 #[cfg(feature = "proto-ipv6")]
1080 IpAddress::Ipv6(dst_addr) => {
1081 net_debug!(
1082 "address {} not in neighbor cache, sending Neighbor Solicitation",
1083 dst_addr
1084 );
1085
1086 let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
1087 target_addr: dst_addr,
1088 lladdr: Some(self.hardware_addr.into()),
1089 });
1090
1091 let packet = Packet::new_ipv6(
1092 Ipv6Repr {
1093 src_addr: self.get_source_address_ipv6(&dst_addr),
1094 dst_addr: dst_addr.solicited_node(),
1095 next_header: IpProtocol::Icmpv6,
1096 payload_len: solicit.buffer_len(),
1097 hop_limit: 0xff,
1098 },
1099 IpPayload::Icmpv6(solicit),
1100 );
1101
1102 if let Err(e) =
1103 self.dispatch_ip(tx_token, PacketMeta::default(), packet, fragmenter)
1104 {
1105 net_debug!("Failed to dispatch NDISC solicit: {:?}", e);
1106 return Err(DispatchError::NeighborPending);
1107 }
1108 }
1109
1110 #[allow(unreachable_patterns)]
1111 _ => (),
1112 }
1113
1114 self.neighbor_cache.limit_rate(self.now);
1116 Err(DispatchError::NeighborPending)
1117 }
1118
1119 fn flush_neighbor_cache(&mut self) {
1120 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
1121 self.neighbor_cache.flush()
1122 }
1123
1124 fn dispatch_ip<Tx: TxToken>(
1125 &mut self,
1126 #[allow(unused_mut)] mut tx_token: Tx,
1129 meta: PacketMeta,
1130 packet: Packet,
1131 frag: &mut Fragmenter,
1132 ) -> Result<(), DispatchError> {
1133 let mut ip_repr = packet.ip_repr();
1134 assert!(!ip_repr.dst_addr().is_unspecified());
1135
1136 #[cfg(feature = "medium-ieee802154")]
1139 if matches!(self.caps.medium, Medium::Ieee802154) {
1140 let (addr, tx_token) =
1141 self.lookup_hardware_addr(tx_token, &ip_repr.dst_addr(), frag)?;
1142 let addr = addr.ieee802154_or_panic();
1143
1144 self.dispatch_ieee802154(addr, tx_token, meta, packet, frag);
1145 return Ok(());
1146 }
1147
1148 let caps = self.caps.clone();
1151
1152 #[cfg(feature = "proto-ipv4-fragmentation")]
1153 let ipv4_id = self.next_ipv4_frag_ident();
1154
1155 let mut total_len = ip_repr.buffer_len();
1157
1158 #[cfg(feature = "medium-ethernet")]
1160 if matches!(self.caps.medium, Medium::Ethernet) {
1161 total_len = EthernetFrame::<&[u8]>::buffer_len(total_len);
1162 }
1163
1164 #[cfg(feature = "medium-ethernet")]
1166 let (dst_hardware_addr, mut tx_token) = match self.caps.medium {
1167 Medium::Ethernet => {
1168 match self.lookup_hardware_addr(tx_token, &ip_repr.dst_addr(), frag)? {
1169 (HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token),
1170 (_, _) => unreachable!(),
1171 }
1172 }
1173 _ => (EthernetAddress([0; 6]), tx_token),
1174 };
1175
1176 #[cfg(feature = "medium-ethernet")]
1178 let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
1179 let mut frame = EthernetFrame::new_unchecked(tx_buffer);
1180
1181 let src_addr = self.hardware_addr.ethernet_or_panic();
1182 frame.set_src_addr(src_addr);
1183 frame.set_dst_addr(dst_hardware_addr);
1184
1185 match repr.version() {
1186 #[cfg(feature = "proto-ipv4")]
1187 IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
1188 #[cfg(feature = "proto-ipv6")]
1189 IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
1190 }
1191
1192 Ok(())
1193 };
1194
1195 let emit_ip = |repr: &IpRepr, tx_buffer: &mut [u8]| {
1197 repr.emit(&mut *tx_buffer, &self.caps.checksum);
1198
1199 let payload = &mut tx_buffer[repr.header_len()..];
1200 packet.emit_payload(repr, payload, &caps)
1201 };
1202
1203 let total_ip_len = ip_repr.buffer_len();
1204
1205 match &mut ip_repr {
1206 #[cfg(feature = "proto-ipv4")]
1207 IpRepr::Ipv4(repr) => {
1208 if total_ip_len > self.caps.ip_mtu() {
1210 #[cfg(feature = "proto-ipv4-fragmentation")]
1211 {
1212 net_debug!("start fragmentation");
1213
1214 let tx_len = self.caps.max_transmission_unit;
1216
1217 let ip_header_len = repr.buffer_len();
1218 let first_frag_ip_len = self.caps.ip_mtu();
1219
1220 if frag.buffer.len() < total_ip_len {
1221 net_debug!(
1222 "Fragmentation buffer is too small, at least {} needed. Dropping",
1223 total_ip_len
1224 );
1225 return Ok(());
1226 }
1227
1228 #[cfg(feature = "medium-ethernet")]
1229 {
1230 frag.ipv4.dst_hardware_addr = dst_hardware_addr;
1231 }
1232
1233 frag.packet_len = total_ip_len;
1236
1237 frag.ipv4.repr = *repr;
1239
1240 frag.sent_bytes = first_frag_ip_len;
1242
1243 repr.payload_len = first_frag_ip_len - repr.buffer_len();
1245
1246 emit_ip(&ip_repr, &mut frag.buffer);
1248
1249 let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut frag.buffer[..]);
1250 frag.ipv4.ident = ipv4_id;
1251 ipv4_packet.set_ident(ipv4_id);
1252 ipv4_packet.set_more_frags(true);
1253 ipv4_packet.set_dont_frag(false);
1254 ipv4_packet.set_frag_offset(0);
1255
1256 if caps.checksum.ipv4.tx() {
1257 ipv4_packet.fill_checksum();
1258 }
1259
1260 tx_token.consume(tx_len, |mut tx_buffer| {
1262 #[cfg(feature = "medium-ethernet")]
1263 if matches!(self.caps.medium, Medium::Ethernet) {
1264 emit_ethernet(&ip_repr, tx_buffer)?;
1265 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1266 }
1267
1268 frag.ipv4.frag_offset = (first_frag_ip_len - ip_header_len) as u16;
1270
1271 tx_buffer[..first_frag_ip_len]
1273 .copy_from_slice(&frag.buffer[..first_frag_ip_len]);
1274
1275 Ok(())
1276 })
1277 }
1278
1279 #[cfg(not(feature = "proto-ipv4-fragmentation"))]
1280 {
1281 net_debug!("Enable the `proto-ipv4-fragmentation` feature for fragmentation support.");
1282 Ok(())
1283 }
1284 } else {
1285 tx_token.set_meta(meta);
1286
1287 tx_token.consume(total_len, |mut tx_buffer| {
1289 #[cfg(feature = "medium-ethernet")]
1290 if matches!(self.caps.medium, Medium::Ethernet) {
1291 emit_ethernet(&ip_repr, tx_buffer)?;
1292 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1293 }
1294
1295 emit_ip(&ip_repr, tx_buffer);
1296 Ok(())
1297 })
1298 }
1299 }
1300 #[cfg(feature = "proto-ipv6")]
1302 IpRepr::Ipv6(_) => tx_token.consume(total_len, |mut tx_buffer| {
1303 #[cfg(feature = "medium-ethernet")]
1304 if matches!(self.caps.medium, Medium::Ethernet) {
1305 emit_ethernet(&ip_repr, tx_buffer)?;
1306 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
1307 }
1308
1309 emit_ip(&ip_repr, tx_buffer);
1310 Ok(())
1311 }),
1312 }
1313 }
1314}
1315
1316#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1317#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1318enum DispatchError {
1319 NoRoute,
1322 NeighborPending,
1326}