smoltcp/socket/
raw.rs

1use core::cmp::min;
2#[cfg(feature = "async")]
3use core::task::Waker;
4
5use crate::iface::Context;
6use crate::socket::PollAt;
7#[cfg(feature = "async")]
8use crate::socket::WakerRegistration;
9
10use crate::storage::Empty;
11use crate::wire::{IpProtocol, IpRepr, IpVersion};
12#[cfg(feature = "proto-ipv4")]
13use crate::wire::{Ipv4Packet, Ipv4Repr};
14#[cfg(feature = "proto-ipv6")]
15use crate::wire::{Ipv6Packet, Ipv6Repr};
16
17/// Error returned by [`Socket::bind`]
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum BindError {
21    InvalidState,
22    Unaddressable,
23}
24
25impl core::fmt::Display for BindError {
26    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
27        match self {
28            BindError::InvalidState => write!(f, "invalid state"),
29            BindError::Unaddressable => write!(f, "unaddressable"),
30        }
31    }
32}
33
34#[cfg(feature = "std")]
35impl std::error::Error for BindError {}
36
37/// Error returned by [`Socket::send`]
38#[derive(Debug, PartialEq, Eq, Clone, Copy)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum SendError {
41    BufferFull,
42}
43
44impl core::fmt::Display for SendError {
45    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
46        match self {
47            SendError::BufferFull => write!(f, "buffer full"),
48        }
49    }
50}
51
52#[cfg(feature = "std")]
53impl std::error::Error for SendError {}
54
55/// Error returned by [`Socket::recv`]
56#[derive(Debug, PartialEq, Eq, Clone, Copy)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum RecvError {
59    Exhausted,
60    Truncated,
61}
62
63impl core::fmt::Display for RecvError {
64    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
65        match self {
66            RecvError::Exhausted => write!(f, "exhausted"),
67            RecvError::Truncated => write!(f, "truncated"),
68        }
69    }
70}
71
72#[cfg(feature = "std")]
73impl std::error::Error for RecvError {}
74
75/// A UDP packet metadata.
76pub type PacketMetadata = crate::storage::PacketMetadata<()>;
77
78/// A UDP packet ring buffer.
79pub type PacketBuffer<'a> = crate::storage::PacketBuffer<'a, ()>;
80
81/// A raw IP socket.
82///
83/// A raw socket is bound to a specific IP protocol, and owns
84/// transmit and receive packet buffers.
85#[derive(Debug)]
86pub struct Socket<'a> {
87    ip_version: IpVersion,
88    ip_protocol: IpProtocol,
89    rx_buffer: PacketBuffer<'a>,
90    tx_buffer: PacketBuffer<'a>,
91    #[cfg(feature = "async")]
92    rx_waker: WakerRegistration,
93    #[cfg(feature = "async")]
94    tx_waker: WakerRegistration,
95}
96
97impl<'a> Socket<'a> {
98    /// Create a raw IP socket bound to the given IP version and datagram protocol,
99    /// with the given buffers.
100    pub fn new(
101        ip_version: IpVersion,
102        ip_protocol: IpProtocol,
103        rx_buffer: PacketBuffer<'a>,
104        tx_buffer: PacketBuffer<'a>,
105    ) -> Socket<'a> {
106        Socket {
107            ip_version,
108            ip_protocol,
109            rx_buffer,
110            tx_buffer,
111            #[cfg(feature = "async")]
112            rx_waker: WakerRegistration::new(),
113            #[cfg(feature = "async")]
114            tx_waker: WakerRegistration::new(),
115        }
116    }
117
118    /// Register a waker for receive operations.
119    ///
120    /// The waker is woken on state changes that might affect the return value
121    /// of `recv` method calls, such as receiving data, or the socket closing.
122    ///
123    /// Notes:
124    ///
125    /// - Only one waker can be registered at a time. If another waker was previously registered,
126    ///   it is overwritten and will no longer be woken.
127    /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
128    /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
129    ///   necessarily changed.
130    #[cfg(feature = "async")]
131    pub fn register_recv_waker(&mut self, waker: &Waker) {
132        self.rx_waker.register(waker)
133    }
134
135    /// Register a waker for send operations.
136    ///
137    /// The waker is woken on state changes that might affect the return value
138    /// of `send` method calls, such as space becoming available in the transmit
139    /// buffer, or the socket closing.
140    ///
141    /// Notes:
142    ///
143    /// - Only one waker can be registered at a time. If another waker was previously registered,
144    ///   it is overwritten and will no longer be woken.
145    /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
146    /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
147    ///   necessarily changed.
148    #[cfg(feature = "async")]
149    pub fn register_send_waker(&mut self, waker: &Waker) {
150        self.tx_waker.register(waker)
151    }
152
153    /// Return the IP version the socket is bound to.
154    #[inline]
155    pub fn ip_version(&self) -> IpVersion {
156        self.ip_version
157    }
158
159    /// Return the IP protocol the socket is bound to.
160    #[inline]
161    pub fn ip_protocol(&self) -> IpProtocol {
162        self.ip_protocol
163    }
164
165    /// Check whether the transmit buffer is full.
166    #[inline]
167    pub fn can_send(&self) -> bool {
168        !self.tx_buffer.is_full()
169    }
170
171    /// Check whether the receive buffer is not empty.
172    #[inline]
173    pub fn can_recv(&self) -> bool {
174        !self.rx_buffer.is_empty()
175    }
176
177    /// Return the maximum number packets the socket can receive.
178    #[inline]
179    pub fn packet_recv_capacity(&self) -> usize {
180        self.rx_buffer.packet_capacity()
181    }
182
183    /// Return the maximum number packets the socket can transmit.
184    #[inline]
185    pub fn packet_send_capacity(&self) -> usize {
186        self.tx_buffer.packet_capacity()
187    }
188
189    /// Return the maximum number of bytes inside the recv buffer.
190    #[inline]
191    pub fn payload_recv_capacity(&self) -> usize {
192        self.rx_buffer.payload_capacity()
193    }
194
195    /// Return the maximum number of bytes inside the transmit buffer.
196    #[inline]
197    pub fn payload_send_capacity(&self) -> usize {
198        self.tx_buffer.payload_capacity()
199    }
200
201    /// Enqueue a packet to send, and return a pointer to its payload.
202    ///
203    /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full,
204    /// and `Err(Error::Truncated)` if there is not enough transmit buffer capacity
205    /// to ever send this packet.
206    ///
207    /// If the buffer is filled in a way that does not match the socket's
208    /// IP version or protocol, the packet will be silently dropped.
209    ///
210    /// **Note:** The IP header is parsed and re-serialized, and may not match
211    /// the header actually transmitted bit for bit.
212    pub fn send(&mut self, size: usize) -> Result<&mut [u8], SendError> {
213        let packet_buf = self
214            .tx_buffer
215            .enqueue(size, ())
216            .map_err(|_| SendError::BufferFull)?;
217
218        net_trace!(
219            "raw:{}:{}: buffer to send {} octets",
220            self.ip_version,
221            self.ip_protocol,
222            packet_buf.len()
223        );
224        Ok(packet_buf)
225    }
226
227    /// Enqueue a packet to be send and pass the buffer to the provided closure.
228    /// The closure then returns the size of the data written into the buffer.
229    ///
230    /// Also see [send](#method.send).
231    pub fn send_with<F>(&mut self, max_size: usize, f: F) -> Result<usize, SendError>
232    where
233        F: FnOnce(&mut [u8]) -> usize,
234    {
235        let size = self
236            .tx_buffer
237            .enqueue_with_infallible(max_size, (), f)
238            .map_err(|_| SendError::BufferFull)?;
239
240        net_trace!(
241            "raw:{}:{}: buffer to send {} octets",
242            self.ip_version,
243            self.ip_protocol,
244            size
245        );
246
247        Ok(size)
248    }
249
250    /// Enqueue a packet to send, and fill it from a slice.
251    ///
252    /// See also [send](#method.send).
253    pub fn send_slice(&mut self, data: &[u8]) -> Result<(), SendError> {
254        self.send(data.len())?.copy_from_slice(data);
255        Ok(())
256    }
257
258    /// Dequeue a packet, and return a pointer to the payload.
259    ///
260    /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
261    ///
262    /// **Note:** The IP header is parsed and re-serialized, and may not match
263    /// the header actually received bit for bit.
264    pub fn recv(&mut self) -> Result<&[u8], RecvError> {
265        let ((), packet_buf) = self.rx_buffer.dequeue().map_err(|_| RecvError::Exhausted)?;
266
267        net_trace!(
268            "raw:{}:{}: receive {} buffered octets",
269            self.ip_version,
270            self.ip_protocol,
271            packet_buf.len()
272        );
273        Ok(packet_buf)
274    }
275
276    /// Dequeue a packet, and copy the payload into the given slice.
277    ///
278    /// **Note**: when the size of the provided buffer is smaller than the size of the payload,
279    /// the packet is dropped and a `RecvError::Truncated` error is returned.
280    ///
281    /// See also [recv](#method.recv).
282    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize, RecvError> {
283        let buffer = self.recv()?;
284        if data.len() < buffer.len() {
285            return Err(RecvError::Truncated);
286        }
287
288        let length = min(data.len(), buffer.len());
289        data[..length].copy_from_slice(&buffer[..length]);
290        Ok(length)
291    }
292
293    /// Peek at a packet in the receive buffer and return a pointer to the
294    /// payload without removing the packet from the receive buffer.
295    /// This function otherwise behaves identically to [recv](#method.recv).
296    ///
297    /// It returns `Err(Error::Exhausted)` if the receive buffer is empty.
298    pub fn peek(&mut self) -> Result<&[u8], RecvError> {
299        let ((), packet_buf) = self.rx_buffer.peek().map_err(|_| RecvError::Exhausted)?;
300
301        net_trace!(
302            "raw:{}:{}: receive {} buffered octets",
303            self.ip_version,
304            self.ip_protocol,
305            packet_buf.len()
306        );
307
308        Ok(packet_buf)
309    }
310
311    /// Peek at a packet in the receive buffer, copy the payload into the given slice,
312    /// and return the amount of octets copied without removing the packet from the receive buffer.
313    /// This function otherwise behaves identically to [recv_slice](#method.recv_slice).
314    ///
315    /// **Note**: when the size of the provided buffer is smaller than the size of the payload,
316    /// no data is copied into the provided buffer and a `RecvError::Truncated` error is returned.
317    ///
318    /// See also [peek](#method.peek).
319    pub fn peek_slice(&mut self, data: &mut [u8]) -> Result<usize, RecvError> {
320        let buffer = self.peek()?;
321        if data.len() < buffer.len() {
322            return Err(RecvError::Truncated);
323        }
324
325        let length = min(data.len(), buffer.len());
326        data[..length].copy_from_slice(&buffer[..length]);
327        Ok(length)
328    }
329
330    /// Return the amount of octets queued in the transmit buffer.
331    pub fn send_queue(&self) -> usize {
332        self.tx_buffer.payload_bytes_count()
333    }
334
335    /// Return the amount of octets queued in the receive buffer.
336    pub fn recv_queue(&self) -> usize {
337        self.rx_buffer.payload_bytes_count()
338    }
339
340    pub(crate) fn accepts(&self, ip_repr: &IpRepr) -> bool {
341        if ip_repr.version() != self.ip_version {
342            return false;
343        }
344        if ip_repr.next_header() != self.ip_protocol {
345            return false;
346        }
347
348        true
349    }
350
351    pub(crate) fn process(&mut self, cx: &mut Context, ip_repr: &IpRepr, payload: &[u8]) {
352        debug_assert!(self.accepts(ip_repr));
353
354        let header_len = ip_repr.header_len();
355        let total_len = header_len + payload.len();
356
357        net_trace!(
358            "raw:{}:{}: receiving {} octets",
359            self.ip_version,
360            self.ip_protocol,
361            total_len
362        );
363
364        match self.rx_buffer.enqueue(total_len, ()) {
365            Ok(buf) => {
366                ip_repr.emit(&mut buf[..header_len], &cx.checksum_caps());
367                buf[header_len..].copy_from_slice(payload);
368            }
369            Err(_) => net_trace!(
370                "raw:{}:{}: buffer full, dropped incoming packet",
371                self.ip_version,
372                self.ip_protocol
373            ),
374        }
375
376        #[cfg(feature = "async")]
377        self.rx_waker.wake();
378    }
379
380    pub(crate) fn dispatch<F, E>(&mut self, cx: &mut Context, emit: F) -> Result<(), E>
381    where
382        F: FnOnce(&mut Context, (IpRepr, &[u8])) -> Result<(), E>,
383    {
384        let ip_protocol = self.ip_protocol;
385        let ip_version = self.ip_version;
386        let _checksum_caps = &cx.checksum_caps();
387        let res = self.tx_buffer.dequeue_with(|&mut (), buffer| {
388            match IpVersion::of_packet(buffer) {
389                #[cfg(feature = "proto-ipv4")]
390                Ok(IpVersion::Ipv4) => {
391                    let mut packet = match Ipv4Packet::new_checked(buffer) {
392                        Ok(x) => x,
393                        Err(_) => {
394                            net_trace!("raw: malformed ipv6 packet in queue, dropping.");
395                            return Ok(());
396                        }
397                    };
398                    if packet.next_header() != ip_protocol {
399                        net_trace!("raw: sent packet with wrong ip protocol, dropping.");
400                        return Ok(());
401                    }
402                    if _checksum_caps.ipv4.tx() {
403                        packet.fill_checksum();
404                    } else {
405                        // make sure we get a consistently zeroed checksum,
406                        // since implementations might rely on it
407                        packet.set_checksum(0);
408                    }
409
410                    let packet = Ipv4Packet::new_unchecked(&*packet.into_inner());
411                    let ipv4_repr = match Ipv4Repr::parse(&packet, _checksum_caps) {
412                        Ok(x) => x,
413                        Err(_) => {
414                            net_trace!("raw: malformed ipv4 packet in queue, dropping.");
415                            return Ok(());
416                        }
417                    };
418                    net_trace!("raw:{}:{}: sending", ip_version, ip_protocol);
419                    emit(cx, (IpRepr::Ipv4(ipv4_repr), packet.payload()))
420                }
421                #[cfg(feature = "proto-ipv6")]
422                Ok(IpVersion::Ipv6) => {
423                    let packet = match Ipv6Packet::new_checked(buffer) {
424                        Ok(x) => x,
425                        Err(_) => {
426                            net_trace!("raw: malformed ipv6 packet in queue, dropping.");
427                            return Ok(());
428                        }
429                    };
430                    if packet.next_header() != ip_protocol {
431                        net_trace!("raw: sent ipv6 packet with wrong ip protocol, dropping.");
432                        return Ok(());
433                    }
434                    let packet = Ipv6Packet::new_unchecked(&*packet.into_inner());
435                    let ipv6_repr = match Ipv6Repr::parse(&packet) {
436                        Ok(x) => x,
437                        Err(_) => {
438                            net_trace!("raw: malformed ipv6 packet in queue, dropping.");
439                            return Ok(());
440                        }
441                    };
442
443                    net_trace!("raw:{}:{}: sending", ip_version, ip_protocol);
444                    emit(cx, (IpRepr::Ipv6(ipv6_repr), packet.payload()))
445                }
446                Err(_) => {
447                    net_trace!("raw: sent packet with invalid IP version, dropping.");
448                    Ok(())
449                }
450            }
451        });
452        match res {
453            Err(Empty) => Ok(()),
454            Ok(Err(e)) => Err(e),
455            Ok(Ok(())) => {
456                #[cfg(feature = "async")]
457                self.tx_waker.wake();
458                Ok(())
459            }
460        }
461    }
462
463    pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt {
464        if self.tx_buffer.is_empty() {
465            PollAt::Ingress
466        } else {
467            PollAt::Now
468        }
469    }
470}
471
472#[cfg(test)]
473mod test {
474    use crate::phy::Medium;
475    use crate::tests::setup;
476    use rstest::*;
477
478    use super::*;
479    use crate::wire::IpRepr;
480    #[cfg(feature = "proto-ipv4")]
481    use crate::wire::{Ipv4Address, Ipv4Repr};
482    #[cfg(feature = "proto-ipv6")]
483    use crate::wire::{Ipv6Address, Ipv6Repr};
484
485    fn buffer(packets: usize) -> PacketBuffer<'static> {
486        PacketBuffer::new(vec![PacketMetadata::EMPTY; packets], vec![0; 48 * packets])
487    }
488
489    #[cfg(feature = "proto-ipv4")]
490    mod ipv4_locals {
491        use super::*;
492
493        pub fn socket(
494            rx_buffer: PacketBuffer<'static>,
495            tx_buffer: PacketBuffer<'static>,
496        ) -> Socket<'static> {
497            Socket::new(
498                IpVersion::Ipv4,
499                IpProtocol::Unknown(IP_PROTO),
500                rx_buffer,
501                tx_buffer,
502            )
503        }
504
505        pub const IP_PROTO: u8 = 63;
506        pub const HEADER_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
507            src_addr: Ipv4Address::new(10, 0, 0, 1),
508            dst_addr: Ipv4Address::new(10, 0, 0, 2),
509            next_header: IpProtocol::Unknown(IP_PROTO),
510            payload_len: 4,
511            hop_limit: 64,
512        });
513        pub const PACKET_BYTES: [u8; 24] = [
514            0x45, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x00, 0x40, 0x3f, 0x00, 0x00, 0x0a, 0x00,
515            0x00, 0x01, 0x0a, 0x00, 0x00, 0x02, 0xaa, 0x00, 0x00, 0xff,
516        ];
517        pub const PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
518    }
519
520    #[cfg(feature = "proto-ipv6")]
521    mod ipv6_locals {
522        use super::*;
523
524        pub fn socket(
525            rx_buffer: PacketBuffer<'static>,
526            tx_buffer: PacketBuffer<'static>,
527        ) -> Socket<'static> {
528            Socket::new(
529                IpVersion::Ipv6,
530                IpProtocol::Unknown(IP_PROTO),
531                rx_buffer,
532                tx_buffer,
533            )
534        }
535
536        pub const IP_PROTO: u8 = 63;
537        pub const HEADER_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
538            src_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
539            dst_addr: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
540            next_header: IpProtocol::Unknown(IP_PROTO),
541            payload_len: 4,
542            hop_limit: 64,
543        });
544
545        pub const PACKET_BYTES: [u8; 44] = [
546            0x60, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
547            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00,
548            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x00,
549            0x00, 0xff,
550        ];
551
552        pub const PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
553    }
554
555    macro_rules! reusable_ip_specific_tests {
556        ($module:ident, $socket:path, $hdr:path, $packet:path, $payload:path) => {
557            mod $module {
558                use super::*;
559
560                #[test]
561                fn test_send_truncated() {
562                    let mut socket = $socket(buffer(0), buffer(1));
563                    assert_eq!(socket.send_slice(&[0; 56][..]), Err(SendError::BufferFull));
564                }
565
566                #[rstest]
567                #[case::ip(Medium::Ip)]
568                #[cfg(feature = "medium-ip")]
569                #[case::ethernet(Medium::Ethernet)]
570                #[cfg(feature = "medium-ethernet")]
571                #[case::ieee802154(Medium::Ieee802154)]
572                #[cfg(feature = "medium-ieee802154")]
573                fn test_send_dispatch(#[case] medium: Medium) {
574                    let (mut iface, _, _) = setup(medium);
575                    let mut cx = iface.context();
576                    let mut socket = $socket(buffer(0), buffer(1));
577
578                    assert!(socket.can_send());
579                    assert_eq!(
580                        socket.dispatch(&mut cx, |_, _| unreachable!()),
581                        Ok::<_, ()>(())
582                    );
583
584                    assert_eq!(socket.send_slice(&$packet[..]), Ok(()));
585                    assert_eq!(socket.send_slice(b""), Err(SendError::BufferFull));
586                    assert!(!socket.can_send());
587
588                    assert_eq!(
589                        socket.dispatch(&mut cx, |_, (ip_repr, ip_payload)| {
590                            assert_eq!(ip_repr, $hdr);
591                            assert_eq!(ip_payload, &$payload);
592                            Err(())
593                        }),
594                        Err(())
595                    );
596                    assert!(!socket.can_send());
597
598                    assert_eq!(
599                        socket.dispatch(&mut cx, |_, (ip_repr, ip_payload)| {
600                            assert_eq!(ip_repr, $hdr);
601                            assert_eq!(ip_payload, &$payload);
602                            Ok::<_, ()>(())
603                        }),
604                        Ok(())
605                    );
606                    assert!(socket.can_send());
607                }
608
609                #[rstest]
610                #[case::ip(Medium::Ip)]
611                #[cfg(feature = "medium-ip")]
612                #[case::ethernet(Medium::Ethernet)]
613                #[cfg(feature = "medium-ethernet")]
614                #[case::ieee802154(Medium::Ieee802154)]
615                #[cfg(feature = "medium-ieee802154")]
616                fn test_recv_truncated_slice(#[case] medium: Medium) {
617                    let (mut iface, _, _) = setup(medium);
618                    let mut cx = iface.context();
619                    let mut socket = $socket(buffer(1), buffer(0));
620
621                    assert!(socket.accepts(&$hdr));
622                    socket.process(&mut cx, &$hdr, &$payload);
623
624                    let mut slice = [0; 4];
625                    assert_eq!(socket.recv_slice(&mut slice[..]), Err(RecvError::Truncated));
626                }
627
628                #[rstest]
629                #[case::ip(Medium::Ip)]
630                #[cfg(feature = "medium-ip")]
631                #[case::ethernet(Medium::Ethernet)]
632                #[cfg(feature = "medium-ethernet")]
633                #[case::ieee802154(Medium::Ieee802154)]
634                #[cfg(feature = "medium-ieee802154")]
635                fn test_recv_truncated_packet(#[case] medium: Medium) {
636                    let (mut iface, _, _) = setup(medium);
637                    let mut cx = iface.context();
638                    let mut socket = $socket(buffer(1), buffer(0));
639
640                    let mut buffer = vec![0; 128];
641                    buffer[..$packet.len()].copy_from_slice(&$packet[..]);
642
643                    assert!(socket.accepts(&$hdr));
644                    socket.process(&mut cx, &$hdr, &buffer);
645                }
646
647                #[rstest]
648                #[case::ip(Medium::Ip)]
649                #[cfg(feature = "medium-ip")]
650                #[case::ethernet(Medium::Ethernet)]
651                #[cfg(feature = "medium-ethernet")]
652                #[case::ieee802154(Medium::Ieee802154)]
653                #[cfg(feature = "medium-ieee802154")]
654                fn test_peek_truncated_slice(#[case] medium: Medium) {
655                    let (mut iface, _, _) = setup(medium);
656                    let mut cx = iface.context();
657                    let mut socket = $socket(buffer(1), buffer(0));
658
659                    assert!(socket.accepts(&$hdr));
660                    socket.process(&mut cx, &$hdr, &$payload);
661
662                    let mut slice = [0; 4];
663                    assert_eq!(socket.peek_slice(&mut slice[..]), Err(RecvError::Truncated));
664                    assert_eq!(socket.recv_slice(&mut slice[..]), Err(RecvError::Truncated));
665                    assert_eq!(socket.peek_slice(&mut slice[..]), Err(RecvError::Exhausted));
666                }
667            }
668        };
669    }
670
671    #[cfg(feature = "proto-ipv4")]
672    reusable_ip_specific_tests!(
673        ipv4,
674        ipv4_locals::socket,
675        ipv4_locals::HEADER_REPR,
676        ipv4_locals::PACKET_BYTES,
677        ipv4_locals::PACKET_PAYLOAD
678    );
679
680    #[cfg(feature = "proto-ipv6")]
681    reusable_ip_specific_tests!(
682        ipv6,
683        ipv6_locals::socket,
684        ipv6_locals::HEADER_REPR,
685        ipv6_locals::PACKET_BYTES,
686        ipv6_locals::PACKET_PAYLOAD
687    );
688
689    #[rstest]
690    #[case::ip(Medium::Ip)]
691    #[case::ethernet(Medium::Ethernet)]
692    #[cfg(feature = "medium-ethernet")]
693    #[case::ieee802154(Medium::Ieee802154)]
694    #[cfg(feature = "medium-ieee802154")]
695    fn test_send_illegal(#[case] medium: Medium) {
696        #[cfg(feature = "proto-ipv4")]
697        {
698            let (mut iface, _, _) = setup(medium);
699            let cx = iface.context();
700            let mut socket = ipv4_locals::socket(buffer(0), buffer(2));
701
702            let mut wrong_version = ipv4_locals::PACKET_BYTES;
703            Ipv4Packet::new_unchecked(&mut wrong_version).set_version(6);
704
705            assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
706            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
707
708            let mut wrong_protocol = ipv4_locals::PACKET_BYTES;
709            Ipv4Packet::new_unchecked(&mut wrong_protocol).set_next_header(IpProtocol::Tcp);
710
711            assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
712            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
713        }
714        #[cfg(feature = "proto-ipv6")]
715        {
716            let (mut iface, _, _) = setup(medium);
717            let cx = iface.context();
718            let mut socket = ipv6_locals::socket(buffer(0), buffer(2));
719
720            let mut wrong_version = ipv6_locals::PACKET_BYTES;
721            Ipv6Packet::new_unchecked(&mut wrong_version[..]).set_version(4);
722
723            assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
724            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
725
726            let mut wrong_protocol = ipv6_locals::PACKET_BYTES;
727            Ipv6Packet::new_unchecked(&mut wrong_protocol[..]).set_next_header(IpProtocol::Tcp);
728
729            assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
730            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
731        }
732    }
733
734    #[rstest]
735    #[case::ip(Medium::Ip)]
736    #[cfg(feature = "medium-ip")]
737    #[case::ethernet(Medium::Ethernet)]
738    #[cfg(feature = "medium-ethernet")]
739    #[case::ieee802154(Medium::Ieee802154)]
740    #[cfg(feature = "medium-ieee802154")]
741    fn test_recv_process(#[case] medium: Medium) {
742        #[cfg(feature = "proto-ipv4")]
743        {
744            let (mut iface, _, _) = setup(medium);
745            let cx = iface.context();
746            let mut socket = ipv4_locals::socket(buffer(1), buffer(0));
747            assert!(!socket.can_recv());
748
749            let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
750            Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
751
752            assert_eq!(socket.recv(), Err(RecvError::Exhausted));
753            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
754            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
755            assert!(socket.can_recv());
756
757            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
758            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
759            assert_eq!(socket.recv(), Ok(&cksumd_packet[..]));
760            assert!(!socket.can_recv());
761        }
762        #[cfg(feature = "proto-ipv6")]
763        {
764            let (mut iface, _, _) = setup(medium);
765            let cx = iface.context();
766            let mut socket = ipv6_locals::socket(buffer(1), buffer(0));
767            assert!(!socket.can_recv());
768
769            assert_eq!(socket.recv(), Err(RecvError::Exhausted));
770            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
771            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
772            assert!(socket.can_recv());
773
774            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
775            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
776            assert_eq!(socket.recv(), Ok(&ipv6_locals::PACKET_BYTES[..]));
777            assert!(!socket.can_recv());
778        }
779    }
780
781    #[rstest]
782    #[case::ip(Medium::Ip)]
783    #[case::ethernet(Medium::Ethernet)]
784    #[cfg(feature = "medium-ethernet")]
785    #[case::ieee802154(Medium::Ieee802154)]
786    #[cfg(feature = "medium-ieee802154")]
787    fn test_peek_process(#[case] medium: Medium) {
788        #[cfg(feature = "proto-ipv4")]
789        {
790            let (mut iface, _, _) = setup(medium);
791            let cx = iface.context();
792            let mut socket = ipv4_locals::socket(buffer(1), buffer(0));
793
794            let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
795            Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
796
797            assert_eq!(socket.peek(), Err(RecvError::Exhausted));
798            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
799            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
800
801            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
802            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
803            assert_eq!(socket.peek(), Ok(&cksumd_packet[..]));
804            assert_eq!(socket.recv(), Ok(&cksumd_packet[..]));
805            assert_eq!(socket.peek(), Err(RecvError::Exhausted));
806        }
807        #[cfg(feature = "proto-ipv6")]
808        {
809            let (mut iface, _, _) = setup(medium);
810            let cx = iface.context();
811            let mut socket = ipv6_locals::socket(buffer(1), buffer(0));
812
813            assert_eq!(socket.peek(), Err(RecvError::Exhausted));
814            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
815            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
816
817            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
818            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
819            assert_eq!(socket.peek(), Ok(&ipv6_locals::PACKET_BYTES[..]));
820            assert_eq!(socket.recv(), Ok(&ipv6_locals::PACKET_BYTES[..]));
821            assert_eq!(socket.peek(), Err(RecvError::Exhausted));
822        }
823    }
824
825    #[test]
826    fn test_doesnt_accept_wrong_proto() {
827        #[cfg(feature = "proto-ipv4")]
828        {
829            let socket = Socket::new(
830                IpVersion::Ipv4,
831                IpProtocol::Unknown(ipv4_locals::IP_PROTO + 1),
832                buffer(1),
833                buffer(1),
834            );
835            assert!(!socket.accepts(&ipv4_locals::HEADER_REPR));
836            #[cfg(feature = "proto-ipv6")]
837            assert!(!socket.accepts(&ipv6_locals::HEADER_REPR));
838        }
839        #[cfg(feature = "proto-ipv6")]
840        {
841            let socket = Socket::new(
842                IpVersion::Ipv6,
843                IpProtocol::Unknown(ipv6_locals::IP_PROTO + 1),
844                buffer(1),
845                buffer(1),
846            );
847            assert!(!socket.accepts(&ipv6_locals::HEADER_REPR));
848            #[cfg(feature = "proto-ipv4")]
849            assert!(!socket.accepts(&ipv4_locals::HEADER_REPR));
850        }
851    }
852}