1 use core::cmp;
2 #[cfg(feature = "async")]
3 use core::task::Waker;
4 
5 use crate::phy::ChecksumCapabilities;
6 #[cfg(feature = "async")]
7 use crate::socket::WakerRegistration;
8 use crate::socket::{Context, PollAt};
9 
10 use crate::storage::Empty;
11 use crate::wire::IcmpRepr;
12 #[cfg(feature = "proto-ipv4")]
13 use crate::wire::{Icmpv4Packet, Icmpv4Repr, Ipv4Repr};
14 #[cfg(feature = "proto-ipv6")]
15 use crate::wire::{Icmpv6Packet, Icmpv6Repr, Ipv6Repr};
16 use crate::wire::{IpAddress, IpListenEndpoint, IpProtocol, IpRepr};
17 use crate::wire::{UdpPacket, UdpRepr};
18 
19 /// Error returned by [`Socket::bind`]
20 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
21 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
22 pub enum BindError {
23     InvalidState,
24     Unaddressable,
25 }
26 
27 /// Error returned by [`Socket::send`]
28 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
29 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
30 pub enum SendError {
31     Unaddressable,
32     BufferFull,
33 }
34 
35 /// Error returned by [`Socket::recv`]
36 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
37 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
38 pub enum RecvError {
39     Exhausted,
40 }
41 
42 /// Type of endpoint to bind the ICMP socket to. See [IcmpSocket::bind] for
43 /// more details.
44 ///
45 /// [IcmpSocket::bind]: struct.IcmpSocket.html#method.bind
46 #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
47 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
48 pub enum Endpoint {
49     #[default]
50     Unspecified,
51     Ident(u16),
52     Udp(IpListenEndpoint),
53 }
54 
55 impl Endpoint {
is_specified(&self) -> bool56     pub fn is_specified(&self) -> bool {
57         match *self {
58             Endpoint::Ident(_) => true,
59             Endpoint::Udp(endpoint) => endpoint.port != 0,
60             Endpoint::Unspecified => false,
61         }
62     }
63 }
64 
65 /// An ICMP packet metadata.
66 pub type PacketMetadata = crate::storage::PacketMetadata<IpAddress>;
67 
68 /// An ICMP packet ring buffer.
69 pub type PacketBuffer<'a> = crate::storage::PacketBuffer<'a, IpAddress>;
70 
71 /// A ICMP socket
72 ///
73 /// An ICMP socket is bound to a specific [IcmpEndpoint] which may
74 /// be a specific UDP port to listen for ICMP error messages related
75 /// to the port or a specific ICMP identifier value. See [bind] for
76 /// more details.
77 ///
78 /// [IcmpEndpoint]: enum.IcmpEndpoint.html
79 /// [bind]: #method.bind
80 #[derive(Debug)]
81 pub struct Socket<'a> {
82     rx_buffer: PacketBuffer<'a>,
83     tx_buffer: PacketBuffer<'a>,
84     /// The endpoint this socket is communicating with
85     endpoint: Endpoint,
86     /// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
87     hop_limit: Option<u8>,
88     #[cfg(feature = "async")]
89     rx_waker: WakerRegistration,
90     #[cfg(feature = "async")]
91     tx_waker: WakerRegistration,
92 }
93 
94 impl<'a> Socket<'a> {
95     /// Create an ICMP socket with the given buffers.
new(rx_buffer: PacketBuffer<'a>, tx_buffer: PacketBuffer<'a>) -> Socket<'a>96     pub fn new(rx_buffer: PacketBuffer<'a>, tx_buffer: PacketBuffer<'a>) -> Socket<'a> {
97         Socket {
98             rx_buffer: rx_buffer,
99             tx_buffer: tx_buffer,
100             endpoint: Default::default(),
101             hop_limit: None,
102             #[cfg(feature = "async")]
103             rx_waker: WakerRegistration::new(),
104             #[cfg(feature = "async")]
105             tx_waker: WakerRegistration::new(),
106         }
107     }
108 
109     /// Register a waker for receive operations.
110     ///
111     /// The waker is woken on state changes that might affect the return value
112     /// of `recv` method calls, such as receiving data, or the socket closing.
113     ///
114     /// Notes:
115     ///
116     /// - Only one waker can be registered at a time. If another waker was previously registered,
117     ///   it is overwritten and will no longer be woken.
118     /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
119     /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
120     ///   necessarily changed.
121     #[cfg(feature = "async")]
register_recv_waker(&mut self, waker: &Waker)122     pub fn register_recv_waker(&mut self, waker: &Waker) {
123         self.rx_waker.register(waker)
124     }
125 
126     /// Register a waker for send operations.
127     ///
128     /// The waker is woken on state changes that might affect the return value
129     /// of `send` method calls, such as space becoming available in the transmit
130     /// buffer, or the socket closing.
131     ///
132     /// Notes:
133     ///
134     /// - Only one waker can be registered at a time. If another waker was previously registered,
135     ///   it is overwritten and will no longer be woken.
136     /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
137     /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
138     ///   necessarily changed.
139     #[cfg(feature = "async")]
register_send_waker(&mut self, waker: &Waker)140     pub fn register_send_waker(&mut self, waker: &Waker) {
141         self.tx_waker.register(waker)
142     }
143 
144     /// Return the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
145     ///
146     /// See also the [set_hop_limit](#method.set_hop_limit) method
hop_limit(&self) -> Option<u8>147     pub fn hop_limit(&self) -> Option<u8> {
148         self.hop_limit
149     }
150 
151     /// Set the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
152     ///
153     /// A socket without an explicitly set hop limit value uses the default [IANA recommended]
154     /// value (64).
155     ///
156     /// # Panics
157     ///
158     /// This function panics if a hop limit value of 0 is given. See [RFC 1122 § 3.2.1.7].
159     ///
160     /// [IANA recommended]: https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml
161     /// [RFC 1122 § 3.2.1.7]: https://tools.ietf.org/html/rfc1122#section-3.2.1.7
set_hop_limit(&mut self, hop_limit: Option<u8>)162     pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) {
163         // A host MUST NOT send a datagram with a hop limit value of 0
164         if let Some(0) = hop_limit {
165             panic!("the time-to-live value of a packet must not be zero")
166         }
167 
168         self.hop_limit = hop_limit
169     }
170 
171     /// Bind the socket to the given endpoint.
172     ///
173     /// This function returns `Err(Error::Illegal)` if the socket was open
174     /// (see [is_open](#method.is_open)), and `Err(Error::Unaddressable)`
175     /// if `endpoint` is unspecified (see [is_specified]).
176     ///
177     /// # Examples
178     ///
179     /// ## Bind to ICMP Error messages associated with a specific UDP port:
180     ///
181     /// To [recv] ICMP error messages that are associated with a specific local
182     /// UDP port, the socket may be bound to a given port using [IcmpEndpoint::Udp].
183     /// This may be useful for applications using UDP attempting to detect and/or
184     /// diagnose connection problems.
185     ///
186     /// ```
187     /// use smoltcp::wire::IpListenEndpoint;
188     /// use smoltcp::socket::icmp;
189     /// # let rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]);
190     /// # let tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]);
191     ///
192     /// let mut icmp_socket = // ...
193     /// # icmp::Socket::new(rx_buffer, tx_buffer);
194     ///
195     /// // Bind to ICMP error responses for UDP packets sent from port 53.
196     /// let endpoint = IpListenEndpoint::from(53);
197     /// icmp_socket.bind(icmp::Endpoint::Udp(endpoint)).unwrap();
198     /// ```
199     ///
200     /// ## Bind to a specific ICMP identifier:
201     ///
202     /// To [send] and [recv] ICMP packets that are not associated with a specific UDP
203     /// port, the socket may be bound to a specific ICMP identifier using
204     /// [IcmpEndpoint::Ident]. This is useful for sending and receiving Echo Request/Reply
205     /// messages.
206     ///
207     /// ```
208     /// use smoltcp::wire::IpListenEndpoint;
209     /// use smoltcp::socket::icmp;
210     /// # let rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]);
211     /// # let tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 20]);
212     ///
213     /// let mut icmp_socket = // ...
214     /// # icmp::Socket::new(rx_buffer, tx_buffer);
215     ///
216     /// // Bind to ICMP messages with the ICMP identifier 0x1234
217     /// icmp_socket.bind(icmp::Endpoint::Ident(0x1234)).unwrap();
218     /// ```
219     ///
220     /// [is_specified]: enum.IcmpEndpoint.html#method.is_specified
221     /// [IcmpEndpoint::Ident]: enum.IcmpEndpoint.html#variant.Ident
222     /// [IcmpEndpoint::Udp]: enum.IcmpEndpoint.html#variant.Udp
223     /// [send]: #method.send
224     /// [recv]: #method.recv
bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<(), BindError>225     pub fn bind<T: Into<Endpoint>>(&mut self, endpoint: T) -> Result<(), BindError> {
226         let endpoint = endpoint.into();
227         if !endpoint.is_specified() {
228             return Err(BindError::Unaddressable);
229         }
230 
231         if self.is_open() {
232             return Err(BindError::InvalidState);
233         }
234 
235         self.endpoint = endpoint;
236 
237         #[cfg(feature = "async")]
238         {
239             self.rx_waker.wake();
240             self.tx_waker.wake();
241         }
242 
243         Ok(())
244     }
245 
246     /// Check whether the transmit buffer is full.
247     #[inline]
can_send(&self) -> bool248     pub fn can_send(&self) -> bool {
249         !self.tx_buffer.is_full()
250     }
251 
252     /// Check whether the receive buffer is not empty.
253     #[inline]
can_recv(&self) -> bool254     pub fn can_recv(&self) -> bool {
255         !self.rx_buffer.is_empty()
256     }
257 
258     /// Return the maximum number packets the socket can receive.
259     #[inline]
packet_recv_capacity(&self) -> usize260     pub fn packet_recv_capacity(&self) -> usize {
261         self.rx_buffer.packet_capacity()
262     }
263 
264     /// Return the maximum number packets the socket can transmit.
265     #[inline]
packet_send_capacity(&self) -> usize266     pub fn packet_send_capacity(&self) -> usize {
267         self.tx_buffer.packet_capacity()
268     }
269 
270     /// Return the maximum number of bytes inside the recv buffer.
271     #[inline]
payload_recv_capacity(&self) -> usize272     pub fn payload_recv_capacity(&self) -> usize {
273         self.rx_buffer.payload_capacity()
274     }
275 
276     /// Return the maximum number of bytes inside the transmit buffer.
277     #[inline]
payload_send_capacity(&self) -> usize278     pub fn payload_send_capacity(&self) -> usize {
279         self.tx_buffer.payload_capacity()
280     }
281 
282     /// Check whether the socket is open.
283     #[inline]
is_open(&self) -> bool284     pub fn is_open(&self) -> bool {
285         self.endpoint != Endpoint::Unspecified
286     }
287 
288     /// Enqueue a packet to be sent to a given remote address, and return a pointer
289     /// to its payload.
290     ///
291     /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full,
292     /// `Err(Error::Truncated)` if the requested size is larger than the packet buffer
293     /// size, and `Err(Error::Unaddressable)` if the remote address is unspecified.
send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8], SendError>294     pub fn send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8], SendError> {
295         if endpoint.is_unspecified() {
296             return Err(SendError::Unaddressable);
297         }
298 
299         let packet_buf = self
300             .tx_buffer
301             .enqueue(size, endpoint)
302             .map_err(|_| SendError::BufferFull)?;
303 
304         net_trace!("icmp:{}: buffer to send {} octets", endpoint, size);
305         Ok(packet_buf)
306     }
307 
308     /// Enqueue a packet to be send to a given remote address and pass the buffer
309     /// to the provided closure. The closure then returns the size of the data written
310     /// into the buffer.
311     ///
312     /// Also see [send](#method.send).
send_with<F>( &mut self, max_size: usize, endpoint: IpAddress, f: F, ) -> Result<usize, SendError> where F: FnOnce(&mut [u8]) -> usize,313     pub fn send_with<F>(
314         &mut self,
315         max_size: usize,
316         endpoint: IpAddress,
317         f: F,
318     ) -> Result<usize, SendError>
319     where
320         F: FnOnce(&mut [u8]) -> usize,
321     {
322         if endpoint.is_unspecified() {
323             return Err(SendError::Unaddressable);
324         }
325 
326         let size = self
327             .tx_buffer
328             .enqueue_with_infallible(max_size, endpoint, f)
329             .map_err(|_| SendError::BufferFull)?;
330 
331         net_trace!("icmp:{}: buffer to send {} octets", endpoint, size);
332         Ok(size)
333     }
334 
335     /// Enqueue a packet to be sent to a given remote address, and fill it from a slice.
336     ///
337     /// See also [send](#method.send).
send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<(), SendError>338     pub fn send_slice(&mut self, data: &[u8], endpoint: IpAddress) -> Result<(), SendError> {
339         let packet_buf = self.send(data.len(), endpoint)?;
340         packet_buf.copy_from_slice(data);
341         Ok(())
342     }
343 
344     /// Dequeue a packet received from a remote endpoint, and return the `IpAddress` as well
345     /// as a pointer to the payload.
346     ///
347     /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
recv(&mut self) -> Result<(&[u8], IpAddress), RecvError>348     pub fn recv(&mut self) -> Result<(&[u8], IpAddress), RecvError> {
349         let (endpoint, packet_buf) = self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?;
350 
351         net_trace!(
352             "icmp:{}: receive {} buffered octets",
353             endpoint,
354             packet_buf.len()
355         );
356         Ok((packet_buf, endpoint))
357     }
358 
359     /// Dequeue a packet received from a remote endpoint, copy the payload into the given slice,
360     /// and return the amount of octets copied as well as the `IpAddress`
361     ///
362     /// See also [recv](#method.recv).
recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress), RecvError>363     pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress), RecvError> {
364         let (buffer, endpoint) = self.recv()?;
365         let length = cmp::min(data.len(), buffer.len());
366         data[..length].copy_from_slice(&buffer[..length]);
367         Ok((length, endpoint))
368     }
369 
370     /// Filter determining which packets received by the interface are appended to
371     /// the given sockets received buffer.
accepts(&self, cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) -> bool372     pub(crate) fn accepts(&self, cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) -> bool {
373         match (&self.endpoint, icmp_repr) {
374             // If we are bound to ICMP errors associated to a UDP port, only
375             // accept Destination Unreachable or Time Exceeded messages with
376             // the data containing a UDP packet send from the local port we
377             // are bound to.
378             #[cfg(feature = "proto-ipv4")]
379             (
380                 &Endpoint::Udp(endpoint),
381                 &IcmpRepr::Ipv4(
382                     Icmpv4Repr::DstUnreachable { data, header, .. }
383                     | Icmpv4Repr::TimeExceeded { data, header, .. },
384                 ),
385             ) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => {
386                 let packet = UdpPacket::new_unchecked(data);
387                 match UdpRepr::parse(
388                     &packet,
389                     &header.src_addr.into(),
390                     &header.dst_addr.into(),
391                     &cx.checksum_caps(),
392                 ) {
393                     Ok(repr) => endpoint.port == repr.src_port,
394                     Err(_) => false,
395                 }
396             }
397             #[cfg(feature = "proto-ipv6")]
398             (
399                 &Endpoint::Udp(endpoint),
400                 &IcmpRepr::Ipv6(
401                     Icmpv6Repr::DstUnreachable { data, header, .. }
402                     | Icmpv6Repr::TimeExceeded { data, header, .. },
403                 ),
404             ) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => {
405                 let packet = UdpPacket::new_unchecked(data);
406                 match UdpRepr::parse(
407                     &packet,
408                     &header.src_addr.into(),
409                     &header.dst_addr.into(),
410                     &cx.checksum_caps(),
411                 ) {
412                     Ok(repr) => endpoint.port == repr.src_port,
413                     Err(_) => false,
414                 }
415             }
416             // If we are bound to a specific ICMP identifier value, only accept an
417             // Echo Request/Reply with the identifier field matching the endpoint
418             // port.
419             #[cfg(feature = "proto-ipv4")]
420             (
421                 &Endpoint::Ident(bound_ident),
422                 &IcmpRepr::Ipv4(Icmpv4Repr::EchoRequest { ident, .. }),
423             )
424             | (
425                 &Endpoint::Ident(bound_ident),
426                 &IcmpRepr::Ipv4(Icmpv4Repr::EchoReply { ident, .. }),
427             ) => ident == bound_ident,
428             #[cfg(feature = "proto-ipv6")]
429             (
430                 &Endpoint::Ident(bound_ident),
431                 &IcmpRepr::Ipv6(Icmpv6Repr::EchoRequest { ident, .. }),
432             )
433             | (
434                 &Endpoint::Ident(bound_ident),
435                 &IcmpRepr::Ipv6(Icmpv6Repr::EchoReply { ident, .. }),
436             ) => ident == bound_ident,
437             _ => false,
438         }
439     }
440 
process(&mut self, _cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr)441     pub(crate) fn process(&mut self, _cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) {
442         match *icmp_repr {
443             #[cfg(feature = "proto-ipv4")]
444             IcmpRepr::Ipv4(icmp_repr) => {
445                 net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
446 
447                 match self
448                     .rx_buffer
449                     .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
450                 {
451                     Ok(packet_buf) => {
452                         icmp_repr.emit(
453                             &mut Icmpv4Packet::new_unchecked(packet_buf),
454                             &ChecksumCapabilities::default(),
455                         );
456                     }
457                     Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
458                 }
459             }
460             #[cfg(feature = "proto-ipv6")]
461             IcmpRepr::Ipv6(icmp_repr) => {
462                 net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
463 
464                 match self
465                     .rx_buffer
466                     .enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
467                 {
468                     Ok(packet_buf) => icmp_repr.emit(
469                         &ip_repr.src_addr(),
470                         &ip_repr.dst_addr(),
471                         &mut Icmpv6Packet::new_unchecked(packet_buf),
472                         &ChecksumCapabilities::default(),
473                     ),
474                     Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
475                 }
476             }
477         }
478 
479         #[cfg(feature = "async")]
480         self.rx_waker.wake();
481     }
482 
dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E> where F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<(), E>,483     pub(crate) fn dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E>
484     where
485         F: FnOnce(&mut Context, (IpRepr, IcmpRepr)) -> Result<(), E>,
486     {
487         let hop_limit = self.hop_limit.unwrap_or(64);
488         let res = self.tx_buffer.dequeue_with(|remote_endpoint, packet_buf| {
489             net_trace!(
490                 "icmp:{}: sending {} octets",
491                 remote_endpoint,
492                 packet_buf.len()
493             );
494             match *remote_endpoint {
495                 #[cfg(feature = "proto-ipv4")]
496                 IpAddress::Ipv4(dst_addr) => {
497                     let src_addr = match cx.get_source_address_ipv4(dst_addr) {
498                         Some(addr) => addr,
499                         None => {
500                             net_trace!(
501                                 "icmp:{}: not find suitable source address, dropping",
502                                 remote_endpoint
503                             );
504                             return Ok(());
505                         }
506                     };
507                     let packet = Icmpv4Packet::new_unchecked(&*packet_buf);
508                     let repr = match Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored()) {
509                         Ok(x) => x,
510                         Err(_) => {
511                             net_trace!(
512                                 "icmp:{}: malformed packet in queue, dropping",
513                                 remote_endpoint
514                             );
515                             return Ok(());
516                         }
517                     };
518                     let ip_repr = IpRepr::Ipv4(Ipv4Repr {
519                         src_addr,
520                         dst_addr,
521                         next_header: IpProtocol::Icmp,
522                         payload_len: repr.buffer_len(),
523                         hop_limit: hop_limit,
524                     });
525                     emit(cx, (ip_repr, IcmpRepr::Ipv4(repr)))
526                 }
527                 #[cfg(feature = "proto-ipv6")]
528                 IpAddress::Ipv6(dst_addr) => {
529                     let src_addr = match cx.get_source_address_ipv6(dst_addr) {
530                         Some(addr) => addr,
531                         None => {
532                             net_trace!(
533                                 "icmp:{}: not find suitable source address, dropping",
534                                 remote_endpoint
535                             );
536                             return Ok(());
537                         }
538                     };
539                     let packet = Icmpv6Packet::new_unchecked(&*packet_buf);
540                     let repr = match Icmpv6Repr::parse(
541                         &src_addr.into(),
542                         &dst_addr.into(),
543                         &packet,
544                         &ChecksumCapabilities::ignored(),
545                     ) {
546                         Ok(x) => x,
547                         Err(_) => {
548                             net_trace!(
549                                 "icmp:{}: malformed packet in queue, dropping",
550                                 remote_endpoint
551                             );
552                             return Ok(());
553                         }
554                     };
555                     let ip_repr = IpRepr::Ipv6(Ipv6Repr {
556                         src_addr,
557                         dst_addr,
558                         next_header: IpProtocol::Icmpv6,
559                         payload_len: repr.buffer_len(),
560                         hop_limit: hop_limit,
561                     });
562                     emit(cx, (ip_repr, IcmpRepr::Ipv6(repr)))
563                 }
564             }
565         });
566         match res {
567             Err(Empty) => Ok(()),
568             Ok(Err(e)) => Err(e),
569             Ok(Ok(())) => {
570                 #[cfg(feature = "async")]
571                 self.tx_waker.wake();
572                 Ok(())
573             }
574         }
575     }
576 
poll_at(&self, _cx: &mut Context) -> PollAt577     pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt {
578         if self.tx_buffer.is_empty() {
579             PollAt::Ingress
580         } else {
581             PollAt::Now
582         }
583     }
584 }
585 
586 #[cfg(test)]
587 mod tests_common {
588     pub use super::*;
589     pub use crate::phy::DeviceCapabilities;
590     pub use crate::wire::IpAddress;
591 
buffer(packets: usize) -> PacketBuffer<'static>592     pub fn buffer(packets: usize) -> PacketBuffer<'static> {
593         PacketBuffer::new(vec![PacketMetadata::EMPTY; packets], vec![0; 66 * packets])
594     }
595 
socket( rx_buffer: PacketBuffer<'static>, tx_buffer: PacketBuffer<'static>, ) -> Socket<'static>596     pub fn socket(
597         rx_buffer: PacketBuffer<'static>,
598         tx_buffer: PacketBuffer<'static>,
599     ) -> Socket<'static> {
600         Socket::new(rx_buffer, tx_buffer)
601     }
602 
603     pub const LOCAL_PORT: u16 = 53;
604 
605     pub static UDP_REPR: UdpRepr = UdpRepr {
606         src_port: 53,
607         dst_port: 9090,
608     };
609 
610     pub static UDP_PAYLOAD: &[u8] = &[0xff; 10];
611 }
612 
613 #[cfg(all(test, feature = "proto-ipv4"))]
614 mod test_ipv4 {
615     use super::tests_common::*;
616     use crate::wire::{Icmpv4DstUnreachable, IpEndpoint, Ipv4Address};
617 
618     const REMOTE_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 2]);
619     const LOCAL_IPV4: Ipv4Address = Ipv4Address([192, 168, 1, 1]);
620     const LOCAL_END_V4: IpEndpoint = IpEndpoint {
621         addr: IpAddress::Ipv4(LOCAL_IPV4),
622         port: LOCAL_PORT,
623     };
624 
625     static ECHOV4_REPR: Icmpv4Repr = Icmpv4Repr::EchoRequest {
626         ident: 0x1234,
627         seq_no: 0x5678,
628         data: &[0xff; 16],
629     };
630 
631     static LOCAL_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
632         src_addr: LOCAL_IPV4,
633         dst_addr: REMOTE_IPV4,
634         next_header: IpProtocol::Icmp,
635         payload_len: 24,
636         hop_limit: 0x40,
637     });
638 
639     static REMOTE_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
640         src_addr: REMOTE_IPV4,
641         dst_addr: LOCAL_IPV4,
642         next_header: IpProtocol::Icmp,
643         payload_len: 24,
644         hop_limit: 0x40,
645     });
646 
647     #[test]
test_send_unaddressable()648     fn test_send_unaddressable() {
649         let mut socket = socket(buffer(0), buffer(1));
650         assert_eq!(
651             socket.send_slice(b"abcdef", IpAddress::Ipv4(Ipv4Address::default())),
652             Err(SendError::Unaddressable)
653         );
654         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(()));
655     }
656 
657     #[test]
test_send_dispatch()658     fn test_send_dispatch() {
659         let mut socket = socket(buffer(0), buffer(1));
660         let mut cx = Context::mock();
661         let checksum = ChecksumCapabilities::default();
662 
663         assert_eq!(
664             socket.dispatch(&mut cx, |_, _| unreachable!()),
665             Ok::<_, ()>(())
666         );
667 
668         // This buffer is too long
669         assert_eq!(
670             socket.send_slice(&[0xff; 67], REMOTE_IPV4.into()),
671             Err(SendError::BufferFull)
672         );
673         assert!(socket.can_send());
674 
675         let mut bytes = [0xff; 24];
676         let mut packet = Icmpv4Packet::new_unchecked(&mut bytes);
677         ECHOV4_REPR.emit(&mut packet, &checksum);
678 
679         assert_eq!(
680             socket.send_slice(&*packet.into_inner(), REMOTE_IPV4.into()),
681             Ok(())
682         );
683         assert_eq!(
684             socket.send_slice(b"123456", REMOTE_IPV4.into()),
685             Err(SendError::BufferFull)
686         );
687         assert!(!socket.can_send());
688 
689         assert_eq!(
690             socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
691                 assert_eq!(ip_repr, LOCAL_IPV4_REPR);
692                 assert_eq!(icmp_repr, ECHOV4_REPR.into());
693                 Err(())
694             }),
695             Err(())
696         );
697         // buffer is not taken off of the tx queue due to the error
698         assert!(!socket.can_send());
699 
700         assert_eq!(
701             socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
702                 assert_eq!(ip_repr, LOCAL_IPV4_REPR);
703                 assert_eq!(icmp_repr, ECHOV4_REPR.into());
704                 Ok::<_, ()>(())
705             }),
706             Ok(())
707         );
708         // buffer is taken off of the queue this time
709         assert!(socket.can_send());
710     }
711 
712     #[test]
test_set_hop_limit_v4()713     fn test_set_hop_limit_v4() {
714         let mut s = socket(buffer(0), buffer(1));
715         let mut cx = Context::mock();
716         let checksum = ChecksumCapabilities::default();
717 
718         let mut bytes = [0xff; 24];
719         let mut packet = Icmpv4Packet::new_unchecked(&mut bytes);
720         ECHOV4_REPR.emit(&mut packet, &checksum);
721 
722         s.set_hop_limit(Some(0x2a));
723 
724         assert_eq!(
725             s.send_slice(&*packet.into_inner(), REMOTE_IPV4.into()),
726             Ok(())
727         );
728         assert_eq!(
729             s.dispatch(&mut cx, |_, (ip_repr, _)| {
730                 assert_eq!(
731                     ip_repr,
732                     IpRepr::Ipv4(Ipv4Repr {
733                         src_addr: LOCAL_IPV4,
734                         dst_addr: REMOTE_IPV4,
735                         next_header: IpProtocol::Icmp,
736                         payload_len: ECHOV4_REPR.buffer_len(),
737                         hop_limit: 0x2a,
738                     })
739                 );
740                 Ok::<_, ()>(())
741             }),
742             Ok(())
743         );
744     }
745 
746     #[test]
test_recv_process()747     fn test_recv_process() {
748         let mut socket = socket(buffer(1), buffer(1));
749         let mut cx = Context::mock();
750         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
751 
752         assert!(!socket.can_recv());
753         assert_eq!(socket.recv(), Err(RecvError::Exhausted));
754 
755         let checksum = ChecksumCapabilities::default();
756 
757         let mut bytes = [0xff; 24];
758         let mut packet = Icmpv4Packet::new_unchecked(&mut bytes[..]);
759         ECHOV4_REPR.emit(&mut packet, &checksum);
760         let data = &*packet.into_inner();
761 
762         assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
763         socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
764         assert!(socket.can_recv());
765 
766         assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
767         socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
768 
769         assert_eq!(socket.recv(), Ok((data, REMOTE_IPV4.into())));
770         assert!(!socket.can_recv());
771     }
772 
773     #[test]
test_accept_bad_id()774     fn test_accept_bad_id() {
775         let mut socket = socket(buffer(1), buffer(1));
776         let mut cx = Context::mock();
777         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
778 
779         let checksum = ChecksumCapabilities::default();
780         let mut bytes = [0xff; 20];
781         let mut packet = Icmpv4Packet::new_unchecked(&mut bytes);
782         let icmp_repr = Icmpv4Repr::EchoRequest {
783             ident: 0x4321,
784             seq_no: 0x5678,
785             data: &[0xff; 16],
786         };
787         icmp_repr.emit(&mut packet, &checksum);
788 
789         // Ensure that a packet with an identifier that isn't the bound
790         // ID is not accepted
791         assert!(!socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &icmp_repr.into()));
792     }
793 
794     #[test]
test_accepts_udp()795     fn test_accepts_udp() {
796         let mut socket = socket(buffer(1), buffer(1));
797         let mut cx = Context::mock();
798         assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V4.into())), Ok(()));
799 
800         let checksum = ChecksumCapabilities::default();
801 
802         let mut bytes = [0xff; 18];
803         let mut packet = UdpPacket::new_unchecked(&mut bytes);
804         UDP_REPR.emit(
805             &mut packet,
806             &REMOTE_IPV4.into(),
807             &LOCAL_IPV4.into(),
808             UDP_PAYLOAD.len(),
809             |buf| buf.copy_from_slice(UDP_PAYLOAD),
810             &checksum,
811         );
812 
813         let data = &*packet.into_inner();
814 
815         let icmp_repr = Icmpv4Repr::DstUnreachable {
816             reason: Icmpv4DstUnreachable::PortUnreachable,
817             header: Ipv4Repr {
818                 src_addr: LOCAL_IPV4,
819                 dst_addr: REMOTE_IPV4,
820                 next_header: IpProtocol::Icmp,
821                 payload_len: 12,
822                 hop_limit: 0x40,
823             },
824             data: data,
825         };
826         let ip_repr = IpRepr::Ipv4(Ipv4Repr {
827             src_addr: REMOTE_IPV4,
828             dst_addr: LOCAL_IPV4,
829             next_header: IpProtocol::Icmp,
830             payload_len: icmp_repr.buffer_len(),
831             hop_limit: 0x40,
832         });
833 
834         assert!(!socket.can_recv());
835 
836         // Ensure we can accept ICMP error response to the bound
837         // UDP port
838         assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into()));
839         socket.process(&mut cx, &ip_repr, &icmp_repr.into());
840         assert!(socket.can_recv());
841 
842         let mut bytes = [0x00; 46];
843         let mut packet = Icmpv4Packet::new_unchecked(&mut bytes[..]);
844         icmp_repr.emit(&mut packet, &checksum);
845         assert_eq!(
846             socket.recv(),
847             Ok((&*packet.into_inner(), REMOTE_IPV4.into()))
848         );
849         assert!(!socket.can_recv());
850     }
851 }
852 
853 #[cfg(all(test, feature = "proto-ipv6"))]
854 mod test_ipv6 {
855     use super::tests_common::*;
856 
857     use crate::wire::{Icmpv6DstUnreachable, IpEndpoint, Ipv6Address};
858 
859     const REMOTE_IPV6: Ipv6Address =
860         Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
861     const LOCAL_IPV6: Ipv6Address =
862         Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
863     const LOCAL_END_V6: IpEndpoint = IpEndpoint {
864         addr: IpAddress::Ipv6(LOCAL_IPV6),
865         port: LOCAL_PORT,
866     };
867     static ECHOV6_REPR: Icmpv6Repr = Icmpv6Repr::EchoRequest {
868         ident: 0x1234,
869         seq_no: 0x5678,
870         data: &[0xff; 16],
871     };
872 
873     static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
874         src_addr: LOCAL_IPV6,
875         dst_addr: REMOTE_IPV6,
876         next_header: IpProtocol::Icmpv6,
877         payload_len: 24,
878         hop_limit: 0x40,
879     });
880 
881     static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
882         src_addr: REMOTE_IPV6,
883         dst_addr: LOCAL_IPV6,
884         next_header: IpProtocol::Icmpv6,
885         payload_len: 24,
886         hop_limit: 0x40,
887     });
888 
889     #[test]
test_send_unaddressable()890     fn test_send_unaddressable() {
891         let mut socket = socket(buffer(0), buffer(1));
892         assert_eq!(
893             socket.send_slice(b"abcdef", IpAddress::Ipv6(Ipv6Address::default())),
894             Err(SendError::Unaddressable)
895         );
896         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(()));
897     }
898 
899     #[test]
test_send_dispatch()900     fn test_send_dispatch() {
901         let mut socket = socket(buffer(0), buffer(1));
902         let mut cx = Context::mock();
903         let checksum = ChecksumCapabilities::default();
904 
905         assert_eq!(
906             socket.dispatch(&mut cx, |_, _| unreachable!()),
907             Ok::<_, ()>(())
908         );
909 
910         // This buffer is too long
911         assert_eq!(
912             socket.send_slice(&[0xff; 67], REMOTE_IPV6.into()),
913             Err(SendError::BufferFull)
914         );
915         assert!(socket.can_send());
916 
917         let mut bytes = vec![0xff; 24];
918         let mut packet = Icmpv6Packet::new_unchecked(&mut bytes);
919         ECHOV6_REPR.emit(
920             &LOCAL_IPV6.into(),
921             &REMOTE_IPV6.into(),
922             &mut packet,
923             &checksum,
924         );
925 
926         assert_eq!(
927             socket.send_slice(&*packet.into_inner(), REMOTE_IPV6.into()),
928             Ok(())
929         );
930         assert_eq!(
931             socket.send_slice(b"123456", REMOTE_IPV6.into()),
932             Err(SendError::BufferFull)
933         );
934         assert!(!socket.can_send());
935 
936         assert_eq!(
937             socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
938                 assert_eq!(ip_repr, LOCAL_IPV6_REPR);
939                 assert_eq!(icmp_repr, ECHOV6_REPR.into());
940                 Err(())
941             }),
942             Err(())
943         );
944         // buffer is not taken off of the tx queue due to the error
945         assert!(!socket.can_send());
946 
947         assert_eq!(
948             socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
949                 assert_eq!(ip_repr, LOCAL_IPV6_REPR);
950                 assert_eq!(icmp_repr, ECHOV6_REPR.into());
951                 Ok::<_, ()>(())
952             }),
953             Ok(())
954         );
955         // buffer is taken off of the queue this time
956         assert!(socket.can_send());
957     }
958 
959     #[test]
test_set_hop_limit()960     fn test_set_hop_limit() {
961         let mut s = socket(buffer(0), buffer(1));
962         let mut cx = Context::mock();
963         let checksum = ChecksumCapabilities::default();
964 
965         let mut bytes = vec![0xff; 24];
966         let mut packet = Icmpv6Packet::new_unchecked(&mut bytes);
967         ECHOV6_REPR.emit(
968             &LOCAL_IPV6.into(),
969             &REMOTE_IPV6.into(),
970             &mut packet,
971             &checksum,
972         );
973 
974         s.set_hop_limit(Some(0x2a));
975 
976         assert_eq!(
977             s.send_slice(&*packet.into_inner(), REMOTE_IPV6.into()),
978             Ok(())
979         );
980         assert_eq!(
981             s.dispatch(&mut cx, |_, (ip_repr, _)| {
982                 assert_eq!(
983                     ip_repr,
984                     IpRepr::Ipv6(Ipv6Repr {
985                         src_addr: LOCAL_IPV6,
986                         dst_addr: REMOTE_IPV6,
987                         next_header: IpProtocol::Icmpv6,
988                         payload_len: ECHOV6_REPR.buffer_len(),
989                         hop_limit: 0x2a,
990                     })
991                 );
992                 Ok::<_, ()>(())
993             }),
994             Ok(())
995         );
996     }
997 
998     #[test]
test_recv_process()999     fn test_recv_process() {
1000         let mut socket = socket(buffer(1), buffer(1));
1001         let mut cx = Context::mock();
1002         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
1003 
1004         assert!(!socket.can_recv());
1005         assert_eq!(socket.recv(), Err(RecvError::Exhausted));
1006 
1007         let checksum = ChecksumCapabilities::default();
1008 
1009         let mut bytes = [0xff; 24];
1010         let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]);
1011         ECHOV6_REPR.emit(
1012             &LOCAL_IPV6.into(),
1013             &REMOTE_IPV6.into(),
1014             &mut packet,
1015             &checksum,
1016         );
1017         let data = &*packet.into_inner();
1018 
1019         assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
1020         socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
1021         assert!(socket.can_recv());
1022 
1023         assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
1024         socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
1025 
1026         assert_eq!(socket.recv(), Ok((data, REMOTE_IPV6.into())));
1027         assert!(!socket.can_recv());
1028     }
1029 
1030     #[test]
test_accept_bad_id()1031     fn test_accept_bad_id() {
1032         let mut socket = socket(buffer(1), buffer(1));
1033         let mut cx = Context::mock();
1034         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
1035 
1036         let checksum = ChecksumCapabilities::default();
1037         let mut bytes = [0xff; 20];
1038         let mut packet = Icmpv6Packet::new_unchecked(&mut bytes);
1039         let icmp_repr = Icmpv6Repr::EchoRequest {
1040             ident: 0x4321,
1041             seq_no: 0x5678,
1042             data: &[0xff; 16],
1043         };
1044         icmp_repr.emit(
1045             &LOCAL_IPV6.into(),
1046             &REMOTE_IPV6.into(),
1047             &mut packet,
1048             &checksum,
1049         );
1050 
1051         // Ensure that a packet with an identifier that isn't the bound
1052         // ID is not accepted
1053         assert!(!socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &icmp_repr.into()));
1054     }
1055 
1056     #[test]
test_accepts_udp()1057     fn test_accepts_udp() {
1058         let mut socket = socket(buffer(1), buffer(1));
1059         let mut cx = Context::mock();
1060         assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V6.into())), Ok(()));
1061 
1062         let checksum = ChecksumCapabilities::default();
1063 
1064         let mut bytes = [0xff; 18];
1065         let mut packet = UdpPacket::new_unchecked(&mut bytes);
1066         UDP_REPR.emit(
1067             &mut packet,
1068             &REMOTE_IPV6.into(),
1069             &LOCAL_IPV6.into(),
1070             UDP_PAYLOAD.len(),
1071             |buf| buf.copy_from_slice(UDP_PAYLOAD),
1072             &checksum,
1073         );
1074 
1075         let data = &*packet.into_inner();
1076 
1077         let icmp_repr = Icmpv6Repr::DstUnreachable {
1078             reason: Icmpv6DstUnreachable::PortUnreachable,
1079             header: Ipv6Repr {
1080                 src_addr: LOCAL_IPV6,
1081                 dst_addr: REMOTE_IPV6,
1082                 next_header: IpProtocol::Icmpv6,
1083                 payload_len: 12,
1084                 hop_limit: 0x40,
1085             },
1086             data: data,
1087         };
1088         let ip_repr = IpRepr::Ipv6(Ipv6Repr {
1089             src_addr: REMOTE_IPV6,
1090             dst_addr: LOCAL_IPV6,
1091             next_header: IpProtocol::Icmpv6,
1092             payload_len: icmp_repr.buffer_len(),
1093             hop_limit: 0x40,
1094         });
1095 
1096         assert!(!socket.can_recv());
1097 
1098         // Ensure we can accept ICMP error response to the bound
1099         // UDP port
1100         assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into()));
1101         socket.process(&mut cx, &ip_repr, &icmp_repr.into());
1102         assert!(socket.can_recv());
1103 
1104         let mut bytes = [0x00; 66];
1105         let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]);
1106         icmp_repr.emit(
1107             &LOCAL_IPV6.into(),
1108             &REMOTE_IPV6.into(),
1109             &mut packet,
1110             &checksum,
1111         );
1112         assert_eq!(
1113             socket.recv(),
1114             Ok((&*packet.into_inner(), REMOTE_IPV6.into()))
1115         );
1116         assert!(!socket.can_recv());
1117     }
1118 }
1119