Skip to main content

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