Skip to main content

ya_smoltcp/socket/
raw.rs

1use core::cmp::min;
2#[cfg(feature = "async")]
3use core::task::Waker;
4
5use crate::iface::Context;
6use crate::phy::ChecksumCapabilities;
7use crate::socket::PollAt;
8#[cfg(feature = "async")]
9use crate::socket::WakerRegistration;
10use crate::storage::{PacketBuffer, PacketMetadata};
11use crate::{Error, Result};
12
13use crate::wire::{IpProtocol, IpRepr, IpVersion};
14#[cfg(feature = "proto-ipv4")]
15use crate::wire::{Ipv4Packet, Ipv4Repr};
16#[cfg(feature = "proto-ipv6")]
17use crate::wire::{Ipv6Packet, Ipv6Repr};
18
19/// A UDP packet metadata.
20pub type RawPacketMetadata = PacketMetadata<()>;
21
22/// A UDP packet ring buffer.
23pub type RawSocketBuffer<'a> = PacketBuffer<'a, ()>;
24
25/// A raw IP socket.
26///
27/// A raw socket is bound to a specific IP protocol, and owns
28/// transmit and receive packet buffers.
29#[derive(Debug)]
30pub struct RawSocket<'a> {
31    ip_version: IpVersion,
32    ip_protocol: IpProtocol,
33    rx_buffer: RawSocketBuffer<'a>,
34    tx_buffer: RawSocketBuffer<'a>,
35    #[cfg(feature = "async")]
36    rx_waker: WakerRegistration,
37    #[cfg(feature = "async")]
38    tx_waker: WakerRegistration,
39}
40
41impl<'a> RawSocket<'a> {
42    /// Create a raw IP socket bound to the given IP version and datagram protocol,
43    /// with the given buffers.
44    pub fn new(
45        ip_version: IpVersion,
46        ip_protocol: IpProtocol,
47        rx_buffer: RawSocketBuffer<'a>,
48        tx_buffer: RawSocketBuffer<'a>,
49    ) -> RawSocket<'a> {
50        RawSocket {
51            ip_version,
52            ip_protocol,
53            rx_buffer,
54            tx_buffer,
55            #[cfg(feature = "async")]
56            rx_waker: WakerRegistration::new(),
57            #[cfg(feature = "async")]
58            tx_waker: WakerRegistration::new(),
59        }
60    }
61
62    /// Register a waker for receive operations.
63    ///
64    /// The waker is woken on state changes that might affect the return value
65    /// of `recv` method calls, such as receiving data, or the socket closing.
66    ///
67    /// Notes:
68    ///
69    /// - Only one waker can be registered at a time. If another waker was previously registered,
70    ///   it is overwritten and will no longer be woken.
71    /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
72    /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
73    ///   necessarily changed.
74    #[cfg(feature = "async")]
75    pub fn register_recv_waker(&mut self, waker: &Waker) {
76        self.rx_waker.register(waker)
77    }
78
79    /// Register a waker for send operations.
80    ///
81    /// The waker is woken on state changes that might affect the return value
82    /// of `send` method calls, such as space becoming available in the transmit
83    /// buffer, or the socket closing.
84    ///
85    /// Notes:
86    ///
87    /// - Only one waker can be registered at a time. If another waker was previously registered,
88    ///   it is overwritten and will no longer be woken.
89    /// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
90    /// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
91    ///   necessarily changed.
92    #[cfg(feature = "async")]
93    pub fn register_send_waker(&mut self, waker: &Waker) {
94        self.tx_waker.register(waker)
95    }
96
97    /// Return the IP version the socket is bound to.
98    #[inline]
99    pub fn ip_version(&self) -> IpVersion {
100        self.ip_version
101    }
102
103    /// Return the IP protocol the socket is bound to.
104    #[inline]
105    pub fn ip_protocol(&self) -> IpProtocol {
106        self.ip_protocol
107    }
108
109    /// Check whether the transmit buffer is full.
110    #[inline]
111    pub fn can_send(&self) -> bool {
112        !self.tx_buffer.is_full()
113    }
114
115    /// Check whether the receive buffer is not empty.
116    #[inline]
117    pub fn can_recv(&self) -> bool {
118        !self.rx_buffer.is_empty()
119    }
120
121    /// Return the maximum number packets the socket can receive.
122    #[inline]
123    pub fn packet_recv_capacity(&self) -> usize {
124        self.rx_buffer.packet_capacity()
125    }
126
127    /// Return the maximum number packets the socket can transmit.
128    #[inline]
129    pub fn packet_send_capacity(&self) -> usize {
130        self.tx_buffer.packet_capacity()
131    }
132
133    /// Return the maximum number of bytes inside the recv buffer.
134    #[inline]
135    pub fn payload_recv_capacity(&self) -> usize {
136        self.rx_buffer.payload_capacity()
137    }
138
139    /// Return the maximum number of bytes inside the transmit buffer.
140    #[inline]
141    pub fn payload_send_capacity(&self) -> usize {
142        self.tx_buffer.payload_capacity()
143    }
144
145    /// Enqueue a packet to send, and return a pointer to its payload.
146    ///
147    /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full,
148    /// and `Err(Error::Truncated)` if there is not enough transmit buffer capacity
149    /// to ever send this packet.
150    ///
151    /// If the buffer is filled in a way that does not match the socket's
152    /// IP version or protocol, the packet will be silently dropped.
153    ///
154    /// **Note:** The IP header is parsed and reserialized, and may not match
155    /// the header actually transmitted bit for bit.
156    pub fn send(&mut self, size: usize) -> Result<&mut [u8]> {
157        let packet_buf = self.tx_buffer.enqueue(size, ())?;
158
159        net_trace!(
160            "raw:{}:{}: buffer to send {} octets",
161            self.ip_version,
162            self.ip_protocol,
163            packet_buf.len()
164        );
165        Ok(packet_buf)
166    }
167
168    /// Enqueue a packet to send, and fill it from a slice.
169    ///
170    /// See also [send](#method.send).
171    pub fn send_slice(&mut self, data: &[u8]) -> Result<()> {
172        self.send(data.len())?.copy_from_slice(data);
173        Ok(())
174    }
175
176    /// Dequeue a packet, and return a pointer to the payload.
177    ///
178    /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
179    ///
180    /// **Note:** The IP header is parsed and reserialized, and may not match
181    /// the header actually received bit for bit.
182    pub fn recv(&mut self) -> Result<&[u8]> {
183        let ((), packet_buf) = self.rx_buffer.dequeue()?;
184
185        net_trace!(
186            "raw:{}:{}: receive {} buffered octets",
187            self.ip_version,
188            self.ip_protocol,
189            packet_buf.len()
190        );
191        Ok(packet_buf)
192    }
193
194    /// Dequeue a packet, and copy the payload into the given slice.
195    ///
196    /// See also [recv](#method.recv).
197    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize> {
198        let buffer = self.recv()?;
199        let length = min(data.len(), buffer.len());
200        data[..length].copy_from_slice(&buffer[..length]);
201        Ok(length)
202    }
203
204    pub(crate) fn accepts(&self, ip_repr: &IpRepr) -> bool {
205        if ip_repr.version() != self.ip_version {
206            return false;
207        }
208        if ip_repr.protocol() != self.ip_protocol {
209            return false;
210        }
211
212        true
213    }
214
215    pub(crate) fn process(
216        &mut self,
217        cx: &mut Context,
218        ip_repr: &IpRepr,
219        payload: &[u8],
220    ) -> Result<()> {
221        debug_assert!(self.accepts(ip_repr));
222
223        let header_len = ip_repr.buffer_len();
224        let total_len = header_len + payload.len();
225        let packet_buf = self.rx_buffer.enqueue(total_len, ())?;
226        ip_repr.emit(&mut packet_buf[..header_len], &cx.checksum_caps());
227        packet_buf[header_len..].copy_from_slice(payload);
228
229        net_trace!(
230            "raw:{}:{}: receiving {} octets",
231            self.ip_version,
232            self.ip_protocol,
233            packet_buf.len()
234        );
235
236        #[cfg(feature = "async")]
237        self.rx_waker.wake();
238
239        Ok(())
240    }
241
242    pub(crate) fn dispatch<F>(&mut self, cx: &mut Context, emit: F) -> Result<()>
243    where
244        F: FnOnce(&mut Context, (IpRepr, &[u8])) -> Result<()>,
245    {
246        fn prepare<'a>(
247            protocol: IpProtocol,
248            buffer: &'a mut [u8],
249            _checksum_caps: &ChecksumCapabilities,
250        ) -> Result<(IpRepr, &'a [u8])> {
251            match IpVersion::of_packet(buffer)? {
252                #[cfg(feature = "proto-ipv4")]
253                IpVersion::Ipv4 => {
254                    let mut packet = Ipv4Packet::new_checked(buffer)?;
255                    if packet.protocol() != protocol {
256                        return Err(Error::Unaddressable);
257                    }
258                    if _checksum_caps.ipv4.tx() {
259                        packet.fill_checksum();
260                    } else {
261                        // make sure we get a consistently zeroed checksum,
262                        // since implementations might rely on it
263                        packet.set_checksum(0);
264                    }
265
266                    let packet = Ipv4Packet::new_checked(&*packet.into_inner())?;
267                    let ipv4_repr = Ipv4Repr::parse(&packet, _checksum_caps)?;
268                    Ok((IpRepr::Ipv4(ipv4_repr), packet.payload()))
269                }
270                #[cfg(feature = "proto-ipv6")]
271                IpVersion::Ipv6 => {
272                    let packet = Ipv6Packet::new_checked(buffer)?;
273                    if packet.next_header() != protocol {
274                        return Err(Error::Unaddressable);
275                    }
276                    let packet = Ipv6Packet::new_unchecked(&*packet.into_inner());
277                    let ipv6_repr = Ipv6Repr::parse(&packet)?;
278                    Ok((IpRepr::Ipv6(ipv6_repr), packet.payload()))
279                }
280                IpVersion::Unspecified => unreachable!(),
281            }
282        }
283
284        let ip_protocol = self.ip_protocol;
285        let ip_version = self.ip_version;
286        self.tx_buffer.dequeue_with(|&mut (), packet_buf| {
287            match prepare(ip_protocol, packet_buf, &cx.checksum_caps()) {
288                Ok((ip_repr, raw_packet)) => {
289                    net_trace!(
290                        "raw:{}:{}: sending {} octets",
291                        ip_version,
292                        ip_protocol,
293                        ip_repr.buffer_len() + raw_packet.len()
294                    );
295                    emit(cx, (ip_repr, raw_packet))
296                }
297                Err(error) => {
298                    net_debug!(
299                        "raw:{}:{}: dropping outgoing packet ({})",
300                        ip_version,
301                        ip_protocol,
302                        error
303                    );
304                    // Return Ok(()) so the packet is dequeued.
305                    Ok(())
306                }
307            }
308        })?;
309
310        #[cfg(feature = "async")]
311        self.tx_waker.wake();
312
313        Ok(())
314    }
315
316    pub(crate) fn poll_at(&self, _cx: &mut Context) -> PollAt {
317        if self.tx_buffer.is_empty() {
318            PollAt::Ingress
319        } else {
320            PollAt::Now
321        }
322    }
323}
324
325#[cfg(test)]
326mod test {
327    use super::*;
328    use crate::wire::IpRepr;
329    #[cfg(feature = "proto-ipv4")]
330    use crate::wire::{Ipv4Address, Ipv4Repr};
331    #[cfg(feature = "proto-ipv6")]
332    use crate::wire::{Ipv6Address, Ipv6Repr};
333
334    fn buffer(packets: usize) -> RawSocketBuffer<'static> {
335        RawSocketBuffer::new(
336            vec![RawPacketMetadata::EMPTY; packets],
337            vec![0; 48 * packets],
338        )
339    }
340
341    #[cfg(feature = "proto-ipv4")]
342    mod ipv4_locals {
343        use super::*;
344
345        pub fn socket(
346            rx_buffer: RawSocketBuffer<'static>,
347            tx_buffer: RawSocketBuffer<'static>,
348        ) -> RawSocket<'static> {
349            RawSocket::new(
350                IpVersion::Ipv4,
351                IpProtocol::Unknown(IP_PROTO),
352                rx_buffer,
353                tx_buffer,
354            )
355        }
356
357        pub const IP_PROTO: u8 = 63;
358        pub const HEADER_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
359            src_addr: Ipv4Address([10, 0, 0, 1]),
360            dst_addr: Ipv4Address([10, 0, 0, 2]),
361            protocol: IpProtocol::Unknown(IP_PROTO),
362            payload_len: 4,
363            hop_limit: 64,
364        });
365        pub const PACKET_BYTES: [u8; 24] = [
366            0x45, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x00, 0x40, 0x3f, 0x00, 0x00, 0x0a, 0x00,
367            0x00, 0x01, 0x0a, 0x00, 0x00, 0x02, 0xaa, 0x00, 0x00, 0xff,
368        ];
369        pub const PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
370    }
371
372    #[cfg(feature = "proto-ipv6")]
373    mod ipv6_locals {
374        use super::*;
375
376        pub fn socket(
377            rx_buffer: RawSocketBuffer<'static>,
378            tx_buffer: RawSocketBuffer<'static>,
379        ) -> RawSocket<'static> {
380            RawSocket::new(
381                IpVersion::Ipv6,
382                IpProtocol::Unknown(IP_PROTO),
383                rx_buffer,
384                tx_buffer,
385            )
386        }
387
388        pub const IP_PROTO: u8 = 63;
389        pub const HEADER_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
390            src_addr: Ipv6Address([
391                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392                0x00, 0x01,
393            ]),
394            dst_addr: Ipv6Address([
395                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396                0x00, 0x02,
397            ]),
398            next_header: IpProtocol::Unknown(IP_PROTO),
399            payload_len: 4,
400            hop_limit: 64,
401        });
402
403        pub const PACKET_BYTES: [u8; 44] = [
404            0x60, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3f, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
405            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00,
406            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xaa, 0x00,
407            0x00, 0xff,
408        ];
409
410        pub const PACKET_PAYLOAD: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
411    }
412
413    macro_rules! reusable_ip_specific_tests {
414        ($module:ident, $socket:path, $hdr:path, $packet:path, $payload:path) => {
415            mod $module {
416                use super::*;
417
418                #[test]
419                fn test_send_truncated() {
420                    let mut socket = $socket(buffer(0), buffer(1));
421                    assert_eq!(socket.send_slice(&[0; 56][..]), Err(Error::Truncated));
422                }
423
424                #[test]
425                fn test_send_dispatch() {
426                    let mut socket = $socket(buffer(0), buffer(1));
427                    let mut cx = Context::mock();
428
429                    assert!(socket.can_send());
430                    assert_eq!(
431                        socket.dispatch(&mut cx, |_, _| unreachable!()),
432                        Err(Error::Exhausted)
433                    );
434
435                    assert_eq!(socket.send_slice(&$packet[..]), Ok(()));
436                    assert_eq!(socket.send_slice(b""), Err(Error::Exhausted));
437                    assert!(!socket.can_send());
438
439                    assert_eq!(
440                        socket.dispatch(&mut cx, |_, (ip_repr, ip_payload)| {
441                            assert_eq!(ip_repr, $hdr);
442                            assert_eq!(ip_payload, &$payload);
443                            Err(Error::Unaddressable)
444                        }),
445                        Err(Error::Unaddressable)
446                    );
447                    assert!(!socket.can_send());
448
449                    assert_eq!(
450                        socket.dispatch(&mut cx, |_, (ip_repr, ip_payload)| {
451                            assert_eq!(ip_repr, $hdr);
452                            assert_eq!(ip_payload, &$payload);
453                            Ok(())
454                        }),
455                        Ok(())
456                    );
457                    assert!(socket.can_send());
458                }
459
460                #[test]
461                fn test_recv_truncated_slice() {
462                    let mut socket = $socket(buffer(1), buffer(0));
463                    let mut cx = Context::mock();
464
465                    assert!(socket.accepts(&$hdr));
466                    assert_eq!(socket.process(&mut cx, &$hdr, &$payload), Ok(()));
467
468                    let mut slice = [0; 4];
469                    assert_eq!(socket.recv_slice(&mut slice[..]), Ok(4));
470                    assert_eq!(&slice, &$packet[..slice.len()]);
471                }
472
473                #[test]
474                fn test_recv_truncated_packet() {
475                    let mut socket = $socket(buffer(1), buffer(0));
476                    let mut cx = Context::mock();
477
478                    let mut buffer = vec![0; 128];
479                    buffer[..$packet.len()].copy_from_slice(&$packet[..]);
480
481                    assert!(socket.accepts(&$hdr));
482                    assert_eq!(
483                        socket.process(&mut cx, &$hdr, &buffer),
484                        Err(Error::Truncated)
485                    );
486                }
487            }
488        };
489    }
490
491    #[cfg(feature = "proto-ipv4")]
492    reusable_ip_specific_tests!(
493        ipv4,
494        ipv4_locals::socket,
495        ipv4_locals::HEADER_REPR,
496        ipv4_locals::PACKET_BYTES,
497        ipv4_locals::PACKET_PAYLOAD
498    );
499
500    #[cfg(feature = "proto-ipv6")]
501    reusable_ip_specific_tests!(
502        ipv6,
503        ipv6_locals::socket,
504        ipv6_locals::HEADER_REPR,
505        ipv6_locals::PACKET_BYTES,
506        ipv6_locals::PACKET_PAYLOAD
507    );
508
509    #[test]
510    #[cfg(feature = "proto-ipv4")]
511    fn test_send_illegal() {
512        #[cfg(feature = "proto-ipv4")]
513        {
514            let mut socket = ipv4_locals::socket(buffer(0), buffer(2));
515            let mut cx = Context::mock();
516
517            let mut wrong_version = ipv4_locals::PACKET_BYTES;
518            Ipv4Packet::new_unchecked(&mut wrong_version).set_version(6);
519
520            assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
521            assert_eq!(socket.dispatch(&mut cx, |_, _| unreachable!()), Ok(()));
522
523            let mut wrong_protocol = ipv4_locals::PACKET_BYTES;
524            Ipv4Packet::new_unchecked(&mut wrong_protocol).set_protocol(IpProtocol::Tcp);
525
526            assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
527            assert_eq!(socket.dispatch(&mut cx, |_, _| unreachable!()), Ok(()));
528        }
529        #[cfg(feature = "proto-ipv6")]
530        {
531            let mut socket = ipv6_locals::socket(buffer(0), buffer(2));
532            let mut cx = Context::mock();
533
534            let mut wrong_version = ipv6_locals::PACKET_BYTES;
535            Ipv6Packet::new_unchecked(&mut wrong_version[..]).set_version(4);
536
537            assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
538            assert_eq!(socket.dispatch(&mut cx, |_, _| unreachable!()), Ok(()));
539
540            let mut wrong_protocol = ipv6_locals::PACKET_BYTES;
541            Ipv6Packet::new_unchecked(&mut wrong_protocol[..]).set_next_header(IpProtocol::Tcp);
542
543            assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
544            assert_eq!(socket.dispatch(&mut cx, |_, _| unreachable!()), Ok(()));
545        }
546    }
547
548    #[test]
549    fn test_recv_process() {
550        #[cfg(feature = "proto-ipv4")]
551        {
552            let mut socket = ipv4_locals::socket(buffer(1), buffer(0));
553            assert!(!socket.can_recv());
554            let mut cx = Context::mock();
555
556            let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
557            Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
558
559            assert_eq!(socket.recv(), Err(Error::Exhausted));
560            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
561            assert_eq!(
562                socket.process(
563                    &mut cx,
564                    &ipv4_locals::HEADER_REPR,
565                    &ipv4_locals::PACKET_PAYLOAD
566                ),
567                Ok(())
568            );
569            assert!(socket.can_recv());
570
571            assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
572            assert_eq!(
573                socket.process(
574                    &mut cx,
575                    &ipv4_locals::HEADER_REPR,
576                    &ipv4_locals::PACKET_PAYLOAD
577                ),
578                Err(Error::Exhausted)
579            );
580            assert_eq!(socket.recv(), Ok(&cksumd_packet[..]));
581            assert!(!socket.can_recv());
582        }
583        #[cfg(feature = "proto-ipv6")]
584        {
585            let mut socket = ipv6_locals::socket(buffer(1), buffer(0));
586            assert!(!socket.can_recv());
587            let mut cx = Context::mock();
588
589            assert_eq!(socket.recv(), Err(Error::Exhausted));
590            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
591            assert_eq!(
592                socket.process(
593                    &mut cx,
594                    &ipv6_locals::HEADER_REPR,
595                    &ipv6_locals::PACKET_PAYLOAD
596                ),
597                Ok(())
598            );
599            assert!(socket.can_recv());
600
601            assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
602            assert_eq!(
603                socket.process(
604                    &mut cx,
605                    &ipv6_locals::HEADER_REPR,
606                    &ipv6_locals::PACKET_PAYLOAD
607                ),
608                Err(Error::Exhausted)
609            );
610            assert_eq!(socket.recv(), Ok(&ipv6_locals::PACKET_BYTES[..]));
611            assert!(!socket.can_recv());
612        }
613    }
614
615    #[test]
616    fn test_doesnt_accept_wrong_proto() {
617        #[cfg(feature = "proto-ipv4")]
618        {
619            let socket = RawSocket::new(
620                IpVersion::Ipv4,
621                IpProtocol::Unknown(ipv4_locals::IP_PROTO + 1),
622                buffer(1),
623                buffer(1),
624            );
625            assert!(!socket.accepts(&ipv4_locals::HEADER_REPR));
626            #[cfg(feature = "proto-ipv6")]
627            assert!(!socket.accepts(&ipv6_locals::HEADER_REPR));
628        }
629        #[cfg(feature = "proto-ipv6")]
630        {
631            let socket = RawSocket::new(
632                IpVersion::Ipv6,
633                IpProtocol::Unknown(ipv6_locals::IP_PROTO + 1),
634                buffer(1),
635                buffer(1),
636            );
637            assert!(!socket.accepts(&ipv6_locals::HEADER_REPR));
638            #[cfg(feature = "proto-ipv4")]
639            assert!(!socket.accepts(&ipv4_locals::HEADER_REPR));
640        }
641    }
642}