Skip to main content

smoltcp/socket/
icmp.rs

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