shadow_rs/network/
packet.rs

1use std::io::Write;
2use std::mem::MaybeUninit;
3use std::net::{IpAddr, SocketAddrV4};
4use std::sync::Arc;
5
6use crate::host::network::interface::FifoPacketPriority;
7use crate::utility::ObjectCounter;
8use crate::utility::pcap_writer::PacketDisplay;
9
10use atomic_refcell::AtomicRefCell;
11use bytes::Bytes;
12use shadow_shim_helper_rs::HostId;
13
14/// Represents different checkpoints that a packet reaches as it is being moved around in Shadow.
15#[derive(Copy, Clone, Debug)]
16pub enum PacketStatus {
17    SndCreated,
18    SndTcpEnqueueThrottled,
19    SndTcpEnqueueRetransmit,
20    SndTcpDequeueRetransmit,
21    SndTcpRetransmitted,
22    SndSocketBuffered,
23    SndInterfaceSent,
24    InetSent,
25    InetDropped,
26    RouterEnqueued,
27    RouterDequeued,
28    RouterDropped,
29    RcvInterfaceReceived,
30    RcvInterfaceDropped,
31    RcvSocketProcessed,
32    RcvSocketDropped,
33    RcvTcpEnqueueUnordered,
34    RcvSocketBuffered,
35    RcvSocketDelivered,
36    Destroyed,
37    RelayCached,
38    RelayForwarded,
39}
40
41/// Official IANA-assigned protocols supported in our packets.
42#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
43pub enum IanaProtocol {
44    Tcp,
45    Udp,
46}
47
48impl IanaProtocol {
49    /// The IANA-assigned protocol number. This value is guaranteed to be unique for distinct
50    /// protocol variants.
51    pub fn number(&self) -> u8 {
52        // The specific values assigned here should not be changed since they are used to produce
53        // correctly formatted pcap files.
54        // https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
55        match self {
56            IanaProtocol::Tcp => 6,
57            IanaProtocol::Udp => 17,
58        }
59    }
60}
61
62/// A packet's type of service (TOS) indicates its desired queuing priority. This may be used by
63/// Shadow's interface qdisc to prioritize packets that it sends out to the network. For example,
64/// in the `pfifo_fast` qdisc, packets in lower priority bands would be sent ahead of others.
65// https://lartc.org/howto/lartc.qdisc.classless.html
66#[derive(Copy, Clone, Debug, PartialEq)]
67pub enum TypeOfService {
68    /// Corresponds to "Best Effort" priority (band 1).
69    Normal,
70    /// Corresponds to "Interactive" priority (band 0).
71    MinimizeDelay,
72    /// Corresponds to "Best Effort" priority (band 1).
73    MaximizeReliability,
74    /// Corresponds to "Bulk" priority (band 2).
75    MaximizeThroughput,
76}
77
78/// A thread-safe shared reference to a `Packet`.
79///
80/// Although a `PacketRc` is thread-safe, a panic may occur if multiple threads concurrently write
81/// `PacketStatus` metadata on the inner `Packet`. Thus, use `new_copy_inner()` to copy the inner
82/// `Packet` and send the copy to the other thread rather than sharing it between threads.
83///
84/// A `PacketRc` is a wrapper around a `Packet` and allows us to support reference counting on
85/// `Packet`s while safely sharing them across threads. A clone of a `PacketRc`s increments the
86/// reference count of the shared `Packet` while dropping the `PacketRc` decrements the reference
87/// count. The shared inner `Packet` is only dropped when all `PacketRc`s referring to it are also
88/// dropped (i.e., the reference count reaches zero).
89///
90/// The `PartialEq` implementation on `PacketRc` compares the pointer values of the wrapped
91/// `Packet`.
92///
93/// `PacketRc` implements the `Deref` trait so that all non-associated functions on `Packet` can be
94/// accessed from instances of `PacketRc` too.
95#[derive(Clone, Debug)]
96pub struct PacketRc {
97    inner: Arc<Packet>,
98}
99
100impl PacketRc {
101    /// Creates a thread-safe shared reference to a new `Packet` using the provided information.
102    /// Additional references to the `Packet` can be cheaply obtained by cloning the returned
103    /// `PacketRc`. The `Packet` is dropped when its last `PacketRc` reference is dropped.
104    ///
105    /// See `Packet::new_ipv4_tcp()` for more details.
106    pub fn new_ipv4_tcp(
107        header: tcp::TcpHeader,
108        payload: tcp::Payload,
109        priority: FifoPacketPriority,
110    ) -> Self {
111        Self::from(Packet::new_ipv4_tcp(header, payload, priority))
112    }
113
114    /// Creates a thread-safe shared reference to a new `Packet` using the provided information.
115    /// Additional references to the `Packet` can be cheaply obtained by cloning the returned
116    /// `PacketRc`. The `Packet` is dropped when its last `PacketRc` reference is dropped.
117    ///
118    /// See `Packet::new_ipv4_udp()` for more details.
119    pub fn new_ipv4_udp(
120        src: SocketAddrV4,
121        dst: SocketAddrV4,
122        payload: Bytes,
123        priority: FifoPacketPriority,
124    ) -> Self {
125        Self::from(Packet::new_ipv4_udp(src, dst, payload, priority))
126    }
127
128    /// Creates a thread-safe shared reference to a new `Packet` using the provided information.
129    /// Additional references to the `Packet` can be cheaply obtained by cloning the returned
130    /// `PacketRc`. The `Packet` is dropped when its last `PacketRc` reference is dropped.
131    ///
132    /// See `Packet::new_ipv4_udp_mock()` for more details.
133    #[cfg(test)]
134    pub fn new_ipv4_udp_mock() -> Self {
135        Self::from(Packet::new_ipv4_udp_mock())
136    }
137
138    /// Creates a thread-safe shared reference to a new `Packet` that is created by performing a
139    /// copy of the provided referenced `Packet`. This function copies all packet data _except_ the
140    /// packet payload, which is shared by incrementing its reference count. Additional references
141    /// to the `Packet` can be cheaply obtained by cloning the returned `PacketRc`. The `Packet` is
142    /// dropped when its last `PacketRc` reference is dropped.
143    pub fn new_copy_inner(&self) -> Self {
144        // We want a copy of the inner packet, since cloning the `Arc` wrapper would just increase
145        // the reference count.
146        Self::from(self.inner.as_ref().clone())
147    }
148
149    /// Transfers ownership of the given packet_ptr reference into a new `PacketRc` object. The provided
150    /// pointer must have been obtained from a call to the Rust function `PacketRc::into_raw()` or
151    /// the C function `packet_new_tcp()`.
152    ///
153    /// Use `PacketRc::into_raw()` if the returned reference is to be handed back to C code.
154    ///
155    /// # Panics
156    ///
157    /// This function panics if the supplied packet pointer is NULL.
158    ///
159    /// # Deprecation
160    ///
161    /// This function provides compatibility with the legacy C TCP stack and should be considered
162    /// deprecated and removed when the legacy C TCP stack is removed.
163    pub fn from_raw(packet_ptr: *mut Packet) -> Self {
164        assert!(!packet_ptr.is_null());
165        Self {
166            inner: unsafe { Arc::from_raw(packet_ptr) },
167        }
168    }
169
170    /// Transfers ownership of the inner Arc reference to the caller while dropping the `PacketRc`.
171    ///
172    /// To avoid a memory leak, the returned pointer must be either reconstituted into a `PacketRc`
173    /// using the Rust function `PacketRc::from_raw()`, or dropped using the C function
174    /// `packet_unref()`.
175    ///
176    /// Although this returns a `*mut Packet` pointer, the packet is not actually mutuable. We
177    /// return a `*mut Packet` pointer only to avoid having to change the instnaces of the pointers
178    /// to const instances in the C network code.
179    ///
180    /// # Deprecation
181    ///
182    /// This function provides compatibility with the legacy C TCP stack and should be considered
183    /// deprecated and removed when the legacy C TCP stack is removed.
184    pub fn into_raw(self) -> *mut Packet {
185        Arc::into_raw(self.inner).cast_mut()
186    }
187
188    /// Borrow a reference that is owned by the C code so that we can temporarily operate on the
189    /// packet in a Rust context. The reference count of the underlying `Packet` will be the same
190    /// after the returned `PacketRc` is dropped as it was before calling this function. The C code
191    /// that owns the reference is still responsible for dropping it.
192    ///
193    /// # Panics
194    ///
195    /// This function panics if the supplied packet pointer is NULL.
196    ///
197    /// # Deprecation
198    ///
199    /// This function provides compatibility with the legacy C TCP stack and should be considered
200    /// deprecated and removed when the legacy C TCP stack is removed.
201    fn borrow_raw(packet_ptr: *const Packet) -> Self {
202        assert!(!packet_ptr.is_null());
203        unsafe { Arc::increment_strong_count(packet_ptr) };
204        PacketRc::from_raw(packet_ptr.cast_mut())
205    }
206
207    /// The same as `PacketRc::borrow_raw()` but this version handles a `*mut` packet pointer.
208    ///
209    /// # Panics
210    ///
211    /// This function panics if the supplied packet pointer is NULL.
212    ///
213    /// # Deprecation
214    ///
215    /// This function provides compatibility with the legacy C TCP stack and should be considered
216    /// deprecated and removed when the legacy C TCP stack is removed.
217    fn borrow_raw_mut(packet_ptr: *mut Packet) -> Self {
218        Self::borrow_raw(packet_ptr.cast_const())
219    }
220}
221
222impl PartialEq for PacketRc {
223    /// Compares the pointer rather than the value of the inner `Arc<Packet>` object.
224    fn eq(&self, other: &Self) -> bool {
225        // Two `PacketRc`s are considered equal if they point to the same shared `Packet`.
226        Arc::ptr_eq(&self.inner, &other.inner)
227    }
228}
229
230impl Eq for PacketRc {}
231
232impl From<Packet> for PacketRc {
233    fn from(packet: Packet) -> Self {
234        Self {
235            inner: Arc::new(packet),
236        }
237    }
238}
239
240// Non-associated functions on `Packet` can be accessed from instances of `PacketRc`.
241impl std::ops::Deref for PacketRc {
242    type Target = Packet;
243    fn deref(&self) -> &Self::Target {
244        self.inner.as_ref()
245    }
246}
247
248/// Holds networking information and payload data that assists in sending managed-process bytes
249/// between different sockets and hosts over the simulation network.
250///
251/// The `Packet` is designed to separate the IP layer header from the transport layer data, to make
252/// it easier to support new transport protocols in the future. Thus, the `Packet` has a `Header` to
253/// store IP header information, and a `Data` to store transport-specific data (e.g., A TCP header
254/// and payload for TCP, or a UDP header and payload for UDP).
255///
256/// The `Packet` is designed to be read-only after creation to simplify implementation and to reduce
257/// the need for mutable borrows.
258///
259/// # Deprecation
260///
261/// As an exception to the read-only design, some legacy TCP data is mutable to support the legacy C
262/// TCP stack. When the legacy TCP stack and the `Packet`'s C interface is removed, mutability will
263/// also be removed.
264#[derive(Clone, Debug)]
265pub struct Packet {
266    header: Header,
267    data: Data,
268    meta: Metadata,
269    _counter: ObjectCounter,
270}
271
272impl Packet {
273    /// Creates a new `Packet` with the pre-constructed objects.
274    ///
275    /// This function is private because we do not expose the inner `Packet` structures.
276    fn new(header: Header, data: Data, meta: Metadata) -> Self {
277        Self {
278            header,
279            data,
280            meta,
281            _counter: ObjectCounter::new("Packet"),
282        }
283    }
284
285    /// Creates a new IPv4 TCP packet using the provided data.
286    pub fn new_ipv4_tcp(
287        header: tcp::TcpHeader,
288        payload: tcp::Payload,
289        priority: FifoPacketPriority,
290    ) -> Self {
291        let hdr = header;
292        let header = Header::new(IpAddr::V4(hdr.ip.src), IpAddr::V4(hdr.ip.dst));
293
294        let tcp_packet = TcpData::new(TcpHeader::from(hdr), payload.0);
295        let data = Data::from(tcp_packet);
296
297        let meta = Metadata::new(priority);
298
299        Self::new(header, data, meta)
300    }
301
302    /// Creates a new IPv4 UDP packet using the provided data.
303    pub fn new_ipv4_udp(
304        src: SocketAddrV4,
305        dst: SocketAddrV4,
306        payload: Bytes,
307        priority: FifoPacketPriority,
308    ) -> Self {
309        let header = Header::new(IpAddr::V4(*src.ip()), IpAddr::V4(*dst.ip()));
310
311        let udp_header = UdpHeader::new(src.port(), dst.port());
312        let udp_packet = UdpData::new(udp_header, payload);
313        let data = Data::from(udp_packet);
314
315        let meta = Metadata::new(priority);
316
317        Self::new(header, data, meta)
318    }
319
320    /// Creates a new IPv4 UDP packet for unit tests with unspecified source and destination
321    /// addresses and header information and a payload of 1_000 bytes.
322    #[cfg(test)]
323    pub fn new_ipv4_udp_mock() -> Self {
324        let unspec = SocketAddrV4::new(std::net::Ipv4Addr::UNSPECIFIED, 0);
325        // Some of our tests require packets with payloads.
326        Self::new_ipv4_udp(unspec, unspec, Bytes::copy_from_slice(&[0; 1000]), 0)
327    }
328
329    /// If the packet is an IPv4 TCP packet, returns a copy of the TCP header in a format defined by
330    /// the Rust TCP stack. Otherwise, returns `None`.
331    ///
332    /// Panics
333    ///
334    /// This function panics if the packet was created with `packet_new_tcp()` in the legacy C API.
335    pub fn ipv4_tcp_header(&self) -> Option<tcp::TcpHeader> {
336        let hdr = &self.header;
337
338        let IpAddr::V4(src) = hdr.src else {
339            return None;
340        };
341        let IpAddr::V4(dst) = hdr.dst else {
342            return None;
343        };
344
345        let tcp_hdr = match &self.data {
346            // The legacy TCP header is obtained with `packet_getTCPHeader()` in the legacy C API.
347            Data::LegacyTcp(_) => unimplemented!(),
348            Data::Tcp(tcp) => tcp.header.clone(),
349            Data::Udp(_) => return None,
350        };
351
352        Some(tcp::TcpHeader {
353            ip: tcp::Ipv4Header { src, dst },
354            flags: tcp_hdr.flags,
355            src_port: tcp_hdr.src_port,
356            dst_port: tcp_hdr.dst_port,
357            seq: tcp_hdr.sequence,
358            ack: tcp_hdr.acknowledgement,
359            window_size: tcp_hdr.window_size,
360            selective_acks: tcp_hdr.selective_acks.map(|x| x.into()),
361            window_scale: tcp_hdr.window_scale,
362            timestamp: tcp_hdr.timestamp,
363            timestamp_echo: tcp_hdr.timestamp_echo,
364        })
365    }
366
367    /// Returns the packet's payload that was provided at packet creation time. This function
368    /// allocates a new `Vec`, but is zero-copy with respect to the payload `Bytes`.
369    ///
370    /// This function may return a non-empty vector of zero-length `Bytes` object(s) if zero-length
371    /// `Bytes` object(s) were provided at creation time. Thus, it may be helpful to check if the
372    /// packet has useful payload using `payload_len()` before calling this function.
373    //
374    // TODO: after we remove the legacy C TCP stack, then all packet creation functions will require
375    // a pre-set payload, and we do not add more bytes later. Thus, we can then store them as a
376    // slice of `Bytes` rather than a `Vec<Bytes>`.
377    pub fn payload(&self) -> Vec<Bytes> {
378        match &self.data {
379            Data::LegacyTcp(tcp_rc) => tcp_rc.borrow().payload.clone(),
380            Data::Tcp(tcp) => tcp.payload.clone(),
381            Data::Udp(udp) => vec![udp.payload.clone()],
382        }
383    }
384
385    /// Returns the total simulated length of the packet, which is the sum of the emulated IP and
386    /// transport header lengths and the payload length.
387    #[allow(clippy::len_without_is_empty)]
388    pub fn len(&self) -> usize {
389        self.header.len().checked_add(self.data.len()).unwrap()
390    }
391
392    /// Returns the total number of payload bytes stored in the packet, which excludes IP and
393    /// transport header lengths.
394    pub fn payload_len(&self) -> usize {
395        self.data.payload_len()
396    }
397
398    /// Appends the provided packet status to the list of the packet's status checkpoints.
399    ///
400    /// This function has no effect unless `log::Level::Trace` is enabled.
401    pub fn add_status(&self, status: PacketStatus) {
402        if log::log_enabled!(log::Level::Trace) {
403            if let Some(vec) = self.meta.statuses.as_ref() {
404                vec.borrow_mut().push(status);
405            }
406            log::trace!("[{status:?}] {self:?}");
407        }
408    }
409
410    /// Returns the packet's IPv4 source address and source port.
411    ///
412    /// Panics
413    ///
414    /// This function panics if the source address is not an IPv4 address.
415    pub fn src_ipv4_address(&self) -> SocketAddrV4 {
416        let IpAddr::V4(addr) = self.header.src else {
417            unimplemented!()
418        };
419
420        let port = match &self.data {
421            Data::LegacyTcp(tcp_rc) => tcp_rc.borrow().header.src_port,
422            Data::Tcp(tcp) => tcp.header.src_port,
423            Data::Udp(udp) => udp.header.src_port,
424        };
425
426        SocketAddrV4::new(addr, port)
427    }
428
429    /// Returns the packet's IPv4 destination address and destination port.
430    ///
431    /// Panics
432    ///
433    /// This function panics if the destination address is not an IPv4 address.
434    pub fn dst_ipv4_address(&self) -> SocketAddrV4 {
435        let IpAddr::V4(addr) = self.header.dst else {
436            unimplemented!()
437        };
438
439        let port = match &self.data {
440            Data::LegacyTcp(tcp_rc) => tcp_rc.borrow().header.dst_port,
441            Data::Tcp(tcp) => tcp.header.dst_port,
442            Data::Udp(udp) => udp.header.dst_port,
443        };
444
445        SocketAddrV4::new(addr, port)
446    }
447
448    /// Returns the priority set at packet creation time.
449    pub fn priority(&self) -> FifoPacketPriority {
450        self.meta.priority
451    }
452
453    /// Returns the packet's iana-assigned protocol type.
454    pub fn iana_protocol(&self) -> IanaProtocol {
455        self.data.iana_protocol()
456    }
457}
458
459/// Stores the IP header information.
460#[derive(Clone, Debug)]
461struct Header {
462    src: IpAddr,
463    dst: IpAddr,
464    _tos: TypeOfService,
465}
466
467impl Header {
468    pub fn new(src: IpAddr, dst: IpAddr) -> Self {
469        // TODO: make TOS configurable, then the network queue can do pfifo properly.
470        Self {
471            src,
472            dst,
473            _tos: TypeOfService::Normal,
474        }
475    }
476
477    pub fn len(&self) -> usize {
478        match &self.dst {
479            // 20 bytes without options: https://en.wikipedia.org/wiki/IPv4
480            IpAddr::V4(_) => 20usize,
481            // 40 bytes: https://en.wikipedia.org/wiki/IPv6
482            IpAddr::V6(_) => 40usize,
483        }
484    }
485}
486
487/// Stores the data part of an IP packet. The data segment varies depending on the protocol being
488/// carried by the packet.
489#[derive(Clone, Debug)]
490enum Data {
491    // We need a mutable TCP packet to support the legacy TCP stack, which writes some header and
492    // payload data after the packet was created.
493    LegacyTcp(AtomicRefCell<TcpData>),
494    Tcp(TcpData),
495    Udp(UdpData),
496}
497
498impl Data {
499    pub fn len(&self) -> usize {
500        match self {
501            Data::LegacyTcp(tcp_ref) => tcp_ref.borrow().len(),
502            Data::Tcp(tcp) => tcp.len(),
503            Data::Udp(udp) => udp.len(),
504        }
505    }
506
507    pub fn payload_len(&self) -> usize {
508        match self {
509            Data::LegacyTcp(tcp_ref) => tcp_ref.borrow().payload_len(),
510            Data::Tcp(tcp) => tcp.payload_len(),
511            Data::Udp(udp) => udp.payload_len(),
512        }
513    }
514
515    pub fn iana_protocol(&self) -> IanaProtocol {
516        match self {
517            Data::LegacyTcp(tcp_ref) => tcp_ref.borrow().iana_protocol(),
518            Data::Tcp(tcp) => tcp.iana_protocol(),
519            Data::Udp(udp) => udp.iana_protocol(),
520        }
521    }
522}
523
524impl From<UdpData> for Data {
525    fn from(packet: UdpData) -> Self {
526        Self::Udp(packet)
527    }
528}
529
530impl From<TcpData> for Data {
531    fn from(packet: TcpData) -> Self {
532        Self::Tcp(packet)
533    }
534}
535
536/// The data portion of an IP packet that contains TCP protocol information, including a TCP header
537/// and payload.
538#[derive(Clone, Debug)]
539struct TcpData {
540    // We don't use `tcp::TcpHeader` here because it includes non-transport layer data (IP headers).
541    header: TcpHeader,
542    // A vector allows us to store the payload in multiple separate chunks.
543    // Consider using `SmallVec` instead. I'm not sure what the improvement would be, and it if is
544    // worth adding in the extra dependency on the `SmallVec` code here.
545    payload: Vec<Bytes>,
546}
547
548impl TcpData {
549    pub fn new(header: TcpHeader, payload: Vec<Bytes>) -> Self {
550        Self { header, payload }
551    }
552
553    pub fn len(&self) -> usize {
554        self.header.len().checked_add(self.payload_len()).unwrap()
555    }
556
557    pub fn payload_len(&self) -> usize {
558        self.payload
559            .iter()
560            // `fold` rather than `sum` so that we always panic on overflow
561            .fold(0usize, |acc, x| acc.checked_add(x.len()).unwrap())
562    }
563
564    pub fn iana_protocol(&self) -> IanaProtocol {
565        IanaProtocol::Tcp
566    }
567}
568
569/// A TCP header contains protocol information including ports, sequence numbers, and other
570/// protocol-specific information.
571#[derive(Clone, Debug, PartialEq)]
572struct TcpHeader {
573    src_port: u16,
574    dst_port: u16,
575    flags: tcp::TcpFlags,
576    sequence: u32,
577    acknowledgement: u32,
578    window_size: u16,
579    selective_acks: Option<TcpSelectiveAcks>,
580    window_scale: Option<u8>,
581    timestamp: Option<u32>,
582    timestamp_echo: Option<u32>,
583}
584
585impl TcpHeader {
586    // Unused now, but want to allow its use in the future.
587    #[allow(dead_code)]
588    pub fn new(
589        src_port: u16,
590        dst_port: u16,
591        flags: tcp::TcpFlags,
592        sequence: u32,
593        acknowledgement: u32,
594        window_size: u16,
595        selective_acks: Option<TcpSelectiveAcks>,
596        window_scale: Option<u8>,
597        timestamp: Option<u32>,
598        timestamp_echo: Option<u32>,
599    ) -> Self {
600        Self {
601            src_port,
602            dst_port,
603            sequence,
604            flags,
605            acknowledgement,
606            window_size,
607            selective_acks,
608            window_scale,
609            timestamp,
610            timestamp_echo,
611        }
612    }
613
614    // This function must be kept in sync with `display_bytes()`.
615    // TODO: is there a better way of keeping this logic in sync with similar logic in
616    // `display_bytes()`?
617    pub fn len(&self) -> usize {
618        // Base is 20 bytes: https://en.wikipedia.org/wiki/Transmission_Control_Protocol
619        let mut len = 20usize;
620
621        // TCP options use additional bytes.
622        if self.window_scale.is_some() {
623            // Window scale option is 3 bytes.
624            len += 3;
625        }
626
627        // TODO: should we consider the length of the selective acks, if any exist?
628
629        // Add padding bytes if needed.
630        if (len % 4) != 0 {
631            len += 4 - (len % 4);
632        }
633
634        len
635    }
636}
637
638impl From<tcp::TcpHeader> for TcpHeader {
639    fn from(hdr: tcp::TcpHeader) -> Self {
640        TcpHeader {
641            src_port: hdr.src_port,
642            dst_port: hdr.dst_port,
643            flags: hdr.flags,
644            sequence: hdr.seq,
645            acknowledgement: hdr.ack,
646            window_size: hdr.window_size,
647            selective_acks: hdr.selective_acks.map(|x| x.into()),
648            window_scale: hdr.window_scale,
649            timestamp: hdr.timestamp,
650            timestamp_echo: hdr.timestamp_echo,
651        }
652    }
653}
654
655#[derive(Clone, Copy, Debug, Default)]
656struct TcpSelectiveAcks {
657    len: u8,
658    // A TCP packet can only hold at most 4 selective ack blocks.
659    ranges: [(u32, u32); 4],
660}
661
662impl From<tcp::util::SmallArrayBackedSlice<4, (u32, u32)>> for TcpSelectiveAcks {
663    fn from(array: tcp::util::SmallArrayBackedSlice<4, (u32, u32)>) -> Self {
664        let mut selective_acks = Self::default();
665
666        for (i, sack) in array.as_ref().iter().enumerate() {
667            selective_acks.ranges[i] = (sack.0, sack.1);
668            selective_acks.len += 1;
669            if selective_acks.len >= 4 {
670                break;
671            }
672        }
673
674        selective_acks
675    }
676}
677
678impl From<TcpSelectiveAcks> for tcp::util::SmallArrayBackedSlice<4, (u32, u32)> {
679    fn from(selective_acks: TcpSelectiveAcks) -> Self {
680        assert!(selective_acks.len <= 4);
681        Self::new(&selective_acks.ranges[0..(selective_acks.len as usize)]).unwrap()
682    }
683}
684
685impl PartialEq for TcpSelectiveAcks {
686    fn eq(&self, other: &Self) -> bool {
687        if self.len != other.len {
688            return false;
689        }
690        for i in 0..self.len as usize {
691            if self.ranges[i] != other.ranges[i] {
692                return false;
693            }
694        }
695        true
696    }
697}
698
699/// The data portion of an IP packet that contains UDP protocol information, including a UDP header
700/// and payload.
701#[derive(Clone, Debug)]
702struct UdpData {
703    header: UdpHeader,
704    payload: Bytes,
705}
706
707impl UdpData {
708    pub fn new(header: UdpHeader, payload: Bytes) -> Self {
709        Self { header, payload }
710    }
711
712    pub fn len(&self) -> usize {
713        self.header.len().checked_add(self.payload_len()).unwrap()
714    }
715
716    pub fn payload_len(&self) -> usize {
717        self.payload.len()
718    }
719
720    pub fn iana_protocol(&self) -> IanaProtocol {
721        IanaProtocol::Udp
722    }
723}
724
725/// A UDP header consists of source and destination port information.
726#[derive(Clone, Debug, PartialEq)]
727struct UdpHeader {
728    src_port: u16,
729    dst_port: u16,
730}
731
732impl UdpHeader {
733    pub fn new(src_port: u16, dst_port: u16) -> Self {
734        Self { src_port, dst_port }
735    }
736
737    pub fn len(&self) -> usize {
738        // 8 bytes: https://en.wikipedia.org/wiki/User_Datagram_Protocol
739        8usize
740    }
741}
742
743#[derive(Clone, Debug)]
744struct Metadata {
745    /// Tracks application priority so we flush packets from the interface to the wire in the order
746    /// intended by the application. This is used in the default FIFO network interface scheduling
747    /// discipline. Smaller values have greater priority.
748    // TODO: this can be removed once we support the TOS field in the `Header` struct.
749    priority: FifoPacketPriority,
750    /// Tracks the sequence of operations that happen on this packet as is transits Shadow's
751    /// network.
752    statuses: Option<AtomicRefCell<Vec<PacketStatus>>>,
753    /// The id of the host that created the packet.
754    ///
755    /// # Deprecation
756    ///
757    /// This is currently set by the legacy C TCP stack to help uniquely identify a packet while
758    /// debugging. It can be removed when the legacy TCP stack and our C packet API is removed.
759    _host_id: Option<HostId>,
760    /// The id of the packet.
761    ///
762    /// # Deprecation
763    ///
764    /// This is currently set by the legacy C TCP stack to help uniquely identify a packet while
765    /// debugging. It can be removed when the legacy TCP stack and our C packet API is removed.
766    _packet_id: Option<u64>,
767}
768
769impl Metadata {
770    pub fn new(priority: FifoPacketPriority) -> Self {
771        Self {
772            priority,
773            _host_id: None,
774            _packet_id: None,
775            // For efficiency, we only store statuses when tracing is enabled because they are
776            // logged at trace level and won't be displayed at other levels anyway.
777            statuses: log::log_enabled!(log::Level::Trace).then(AtomicRefCell::default),
778        }
779    }
780
781    /// Supports creation of legacy TCP stack metadata.
782    ///
783    /// # Deprecation
784    ///
785    /// This is currently used by the legacy C TCP stack and can be removed when the legacy TCP
786    /// stack and our C packet API is removed.
787    fn new_legacy(priority: FifoPacketPriority, host_id: HostId, packet_id: u64) -> Self {
788        Self {
789            priority,
790            _host_id: Some(host_id),
791            _packet_id: Some(packet_id),
792            // For efficiency, we only store statuses when tracing is enabled because they are
793            // logged at trace level and won't be displayed at other levels anyway.
794            statuses: log::log_enabled!(log::Level::Trace).then(AtomicRefCell::default),
795        }
796    }
797}
798
799impl PacketDisplay for Packet {
800    fn display_bytes(&self, mut writer: impl Write) -> std::io::Result<()> {
801        // write the IP header
802
803        let version_and_header_length: u8 = 0x45;
804        let fields: u8 = 0x0;
805        let total_length: u16 = self.len().try_into().unwrap();
806        let identification: u16 = 0x0;
807        let flags_and_fragment: u16 = 0x4000;
808        let time_to_live: u8 = 64;
809        let iana_protocol: u8 = self.data.iana_protocol().number();
810        let header_checksum: u16 = 0x0;
811        let source_ip: [u8; 4] = self.src_ipv4_address().ip().to_bits().to_be_bytes();
812        let dest_ip: [u8; 4] = self.dst_ipv4_address().ip().to_bits().to_be_bytes();
813
814        // version and header length: 1 byte
815        // DSCP + ECN: 1 byte
816        writer.write_all(&[version_and_header_length, fields])?;
817        // total length: 2 bytes
818        writer.write_all(&total_length.to_be_bytes())?;
819        // identification: 2 bytes
820        writer.write_all(&identification.to_be_bytes())?;
821        // flags + fragment offset: 2 bytes
822        writer.write_all(&flags_and_fragment.to_be_bytes())?;
823        // ttl: 1 byte
824        // protocol: 1 byte
825        writer.write_all(&[time_to_live, iana_protocol])?;
826        // header checksum: 2 bytes
827        writer.write_all(&header_checksum.to_be_bytes())?;
828        // source IP: 4 bytes
829        writer.write_all(&source_ip)?;
830        // destination IP: 4 bytes
831        writer.write_all(&dest_ip)?;
832
833        // write protocol-specific data
834
835        match &self.data {
836            Data::LegacyTcp(tcp_ref) => write_tcpdata_bytes(&tcp_ref.borrow(), writer),
837            Data::Tcp(tcp) => write_tcpdata_bytes(tcp, writer),
838            Data::Udp(udp) => write_udpdata_bytes(udp, writer),
839        }?;
840
841        Ok(())
842    }
843}
844
845fn write_tcpdata_bytes(data: &TcpData, mut writer: impl Write) -> std::io::Result<()> {
846    // process TCP options
847
848    let tcp_hdr = &data.header;
849
850    // options can be a max of 40 bytes
851    let mut options = [0u8; 40];
852    let mut options_len = 0;
853
854    if let Some(window_scale) = tcp_hdr.window_scale {
855        // option-kind = 3, option-len = 3, option-data = window-scale
856        options[options_len..][..3].copy_from_slice(&[3, 3, window_scale]);
857        options_len += 3;
858    }
859
860    // TODO: do we want to include selective acks or timestamp options?
861
862    if options_len % 4 != 0 {
863        // need to add padding (our options array was already initialized with zeroes)
864        let padding = 4 - (options_len % 4);
865        options_len += padding;
866    }
867
868    let options = &options[..options_len];
869
870    // process the TCP header
871
872    let mut tcp_flags = tcp_hdr.flags;
873
874    // Header length in bytes. This must be kept in sync with `header().len()`.
875    let header_len: usize = 20usize.checked_add(options.len()).unwrap();
876    assert_eq!(header_len, tcp_hdr.len());
877
878    // Ultimately, TCP header len is represented in 32-bit words, so we divide by 4. The
879    // left-shift of 4 is because the header len is represented in the top 4 bits.
880    let mut header_len = u8::try_from(header_len).unwrap();
881    header_len /= 4;
882    header_len <<= 4;
883
884    // Filter these two bits because we stuff non-TCP legacy flags here on legacy packets.
885    // TODO: remove this filter when the C TCP stack and Data::LegacyTCP packets are removed.
886    tcp_flags.remove(tcp::TcpFlags::ECE);
887    tcp_flags.remove(tcp::TcpFlags::CWR);
888
889    // write the header data
890
891    // source port: 2 bytes
892    writer.write_all(&tcp_hdr.src_port.to_be_bytes())?;
893    // destination port: 2 bytes
894    writer.write_all(&tcp_hdr.dst_port.to_be_bytes())?;
895    // sequence number: 4 bytes
896    writer.write_all(&tcp_hdr.sequence.to_be_bytes())?;
897    // acknowledgement number: 4 bytes
898    writer.write_all(&tcp_hdr.acknowledgement.to_be_bytes())?;
899    // data offset + reserved + NS: 1 byte
900    // flags: 1 byte
901    writer.write_all(&[header_len, tcp_flags.bits()])?;
902    // window size: 2 bytes
903    writer.write_all(&tcp_hdr.window_size.to_be_bytes())?;
904    // checksum: 2 bytes
905    let checksum: u16 = 0u16;
906    writer.write_all(&checksum.to_be_bytes())?;
907    // urgent: 2 bytes
908    let urgent_pointer: u16 = 0u16;
909    writer.write_all(&urgent_pointer.to_be_bytes())?;
910
911    writer.write_all(options)?;
912
913    // write payload data
914
915    for bytes in &data.payload {
916        writer.write_all(bytes)?;
917    }
918
919    Ok(())
920}
921
922fn write_udpdata_bytes(data: &UdpData, mut writer: impl Write) -> std::io::Result<()> {
923    // write the UDP header
924
925    // source port: 2 bytes
926    writer.write_all(&data.header.src_port.to_be_bytes())?;
927    // destination port: 2 bytes
928    writer.write_all(&data.header.dst_port.to_be_bytes())?;
929    // length: 2 bytes
930    let udp_len: u16 = u16::try_from(data.len()).unwrap();
931    writer.write_all(&udp_len.to_be_bytes())?;
932    // checksum: 2 bytes
933    let checksum: u16 = 0x0;
934    writer.write_all(&checksum.to_be_bytes())?;
935
936    // write payload data
937
938    writer.write_all(&data.payload)?;
939
940    Ok(())
941}
942
943#[cfg(test)]
944mod tests {
945    use std::net::Ipv4Addr;
946
947    use super::*;
948
949    #[test]
950    fn ipv4_udp() {
951        let src = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 10_000);
952        let dst = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 2), 80);
953        let payload = Bytes::from_static(b"Hello World!");
954        let priority = 123;
955
956        let packetrc = PacketRc::new_ipv4_udp(src, dst, payload.clone(), priority);
957
958        assert_eq!(src, packetrc.src_ipv4_address());
959        assert_eq!(dst, packetrc.dst_ipv4_address());
960        assert_eq!(priority, packetrc.priority());
961        assert_eq!(IanaProtocol::Udp, packetrc.iana_protocol());
962
963        assert_eq!(payload.len(), packetrc.payload_len());
964        let chunks = packetrc.payload();
965        assert_eq!(1, chunks.len());
966        assert_eq!(payload, chunks.first().unwrap());
967    }
968
969    #[test]
970    fn ipv4_udp_empty() {
971        let src = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 10_000);
972        let dst = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 2), 80);
973        let priority = 123;
974
975        // Bytes object with no data inside.
976
977        let payload = Bytes::new();
978        let packetrc = PacketRc::new_ipv4_udp(src, dst, payload.clone(), priority);
979
980        assert_eq!(0, packetrc.payload_len());
981        assert_eq!(payload.len(), packetrc.payload_len());
982        let chunks = packetrc.payload();
983        assert_eq!(1, chunks.len());
984        assert_eq!(0, chunks.first().unwrap().len());
985    }
986
987    fn make_tcp_header(src: SocketAddrV4, dst: SocketAddrV4) -> tcp::TcpHeader {
988        // Selective acks with two ranges: [1-3) and [5-6).
989        let sel_acks =
990            tcp::util::SmallArrayBackedSlice::<4, (u32, u32)>::new(&[(1, 3), (5, 6)]).unwrap();
991
992        tcp::TcpHeader {
993            ip: tcp::Ipv4Header {
994                src: *src.ip(),
995                dst: *dst.ip(),
996            },
997            flags: tcp::TcpFlags::SYN,
998            src_port: src.port(),
999            dst_port: dst.port(),
1000            seq: 10,
1001            ack: 3,
1002            window_size: 25,
1003            selective_acks: Some(sel_acks),
1004            window_scale: Some(2),
1005            timestamp: Some(123456),
1006            timestamp_echo: Some(123450),
1007        }
1008    }
1009
1010    #[test]
1011    fn ipv4_tcp() {
1012        let src = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 10_000);
1013        let dst = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 2), 80);
1014        let priority = 123;
1015        let tcp_hdr = make_tcp_header(src, dst);
1016        let payload = tcp::Payload(vec![
1017            Bytes::from_static(b"Hello"),
1018            Bytes::from_static(b" World!"),
1019        ]);
1020
1021        let packetrc = PacketRc::new_ipv4_tcp(tcp_hdr, payload.clone(), priority);
1022
1023        assert_eq!(src, packetrc.src_ipv4_address());
1024        assert_eq!(dst, packetrc.dst_ipv4_address());
1025        assert_eq!(priority, packetrc.priority());
1026        assert_eq!(IanaProtocol::Tcp, packetrc.iana_protocol());
1027        assert_eq!(
1028            TcpHeader::from(tcp_hdr),
1029            TcpHeader::from(packetrc.ipv4_tcp_header().unwrap())
1030        );
1031
1032        assert_eq!(payload.len() as usize, packetrc.payload_len());
1033        let chunks = packetrc.payload();
1034        assert_eq!(2, chunks.len());
1035
1036        for (i, bytes) in chunks.iter().enumerate() {
1037            assert_eq!(payload.0[i], bytes);
1038        }
1039    }
1040
1041    #[test]
1042    fn ipv4_tcp_empty() {
1043        let src = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 10_000);
1044        let dst = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 2), 80);
1045        let priority = 123;
1046        let tcp_hdr = make_tcp_header(src, dst);
1047
1048        // Empty chunks vec.
1049
1050        let payload = tcp::Payload(vec![]);
1051        let packetrc = PacketRc::new_ipv4_tcp(tcp_hdr, payload, priority);
1052
1053        assert_eq!(0, packetrc.payload_len());
1054        let chunks = packetrc.payload();
1055        assert_eq!(0, chunks.len());
1056
1057        // Non-empty chunks vec with empty bytes objects.
1058
1059        let payload = tcp::Payload(vec![Bytes::new(), Bytes::new()]);
1060        let packetrc = PacketRc::new_ipv4_tcp(tcp_hdr, payload, priority);
1061
1062        assert_eq!(0, packetrc.payload_len());
1063        let chunks = packetrc.payload();
1064        assert_eq!(2, chunks.len());
1065        assert_eq!(0, chunks.first().unwrap().len());
1066        assert_eq!(0, chunks.last().unwrap().len());
1067    }
1068}
1069
1070/// This module provides a C API to create and operate on packets.
1071///
1072/// # Deprecation
1073///
1074/// This module provides compatibility with the legacy C TCP stack and should be considered
1075/// deprecated and removed when the legacy C TCP stack is removed.
1076mod export {
1077    use std::cmp::Ordering;
1078    use std::io::Write;
1079
1080    use shadow_shim_helper_rs::simulation_time::SimulationTime;
1081    use shadow_shim_helper_rs::syscall_types::UntypedForeignPtr;
1082
1083    use crate::cshadow as c;
1084    use crate::host::memory_manager::MemoryManager;
1085    use crate::host::syscall::types::ForeignArrayPtr;
1086
1087    use super::*;
1088
1089    #[unsafe(no_mangle)]
1090    pub extern "C-unwind" fn packet_new_tcp(
1091        host_id: HostId,
1092        packet_id: u64,
1093        flags: c::ProtocolTCPFlags,
1094        src_ip: libc::in_addr_t,
1095        src_port: libc::in_port_t,
1096        dst_ip: libc::in_addr_t,
1097        dst_port: libc::in_port_t,
1098        seq: u32,
1099        priority: u64,
1100    ) -> *mut Packet {
1101        // First construct the internet-level header.
1102        let header = Header::new(
1103            IpAddr::V4(u32::from_be(src_ip).into()),
1104            IpAddr::V4(u32::from_be(dst_ip).into()),
1105        );
1106
1107        // The transport header and payload are defined within the data field.
1108        let data = Data::LegacyTcp(AtomicRefCell::new(TcpData {
1109            header: TcpHeader {
1110                src_port: u16::from_be(src_port),
1111                dst_port: u16::from_be(dst_port),
1112                flags: legacy_flags_to_tcp_flags(flags),
1113                sequence: seq,
1114                acknowledgement: 0,
1115                window_size: 0,
1116                selective_acks: None,
1117                window_scale: None,
1118                timestamp: None,
1119                timestamp_echo: None,
1120            },
1121            payload: vec![],
1122        }));
1123
1124        let meta = Metadata::new_legacy(priority, host_id, packet_id);
1125        let packet = Packet::new(header, data, meta);
1126
1127        // Move ownership of the inner Arc reference to C (for now).
1128        PacketRc::from(packet).into_raw()
1129    }
1130
1131    #[unsafe(no_mangle)]
1132    pub extern "C-unwind" fn packet_ref(packet_ptr: *mut Packet) {
1133        assert!(!packet_ptr.is_null());
1134        unsafe { Arc::increment_strong_count(packet_ptr) };
1135    }
1136
1137    #[unsafe(no_mangle)]
1138    pub extern "C-unwind" fn packet_unref(packet_ptr: *mut Packet) {
1139        assert!(!packet_ptr.is_null());
1140        unsafe { Arc::decrement_strong_count(packet_ptr) };
1141    }
1142
1143    #[unsafe(no_mangle)]
1144    pub extern "C-unwind" fn packet_updateTCP(
1145        packet_ptr: *mut Packet,
1146        ack: libc::c_uint,
1147        sel_acks: c::PacketSelectiveAcks,
1148        window_size: libc::c_uint,
1149        window_scale: libc::c_uchar,
1150        window_scale_set: bool,
1151        ts_val: c::CSimulationTime,
1152        ts_echo: c::CSimulationTime,
1153    ) {
1154        let packet = PacketRc::borrow_raw_mut(packet_ptr);
1155
1156        let Data::LegacyTcp(tcp) = &packet.data else {
1157            unimplemented!()
1158        };
1159
1160        let mut tcp = tcp.borrow_mut();
1161
1162        tcp.header.acknowledgement = ack;
1163        tcp.header.selective_acks = Some(TcpSelectiveAcks::from(sel_acks));
1164
1165        tcp.header.window_size = u16::try_from(window_size).unwrap_or(u16::MAX);
1166        if window_scale_set {
1167            tcp.header.window_scale = Some(window_scale);
1168        } else {
1169            tcp.header.window_scale = None;
1170        }
1171
1172        // The TCP header supports 32-bit timestamps; since these are used for network latency
1173        // calculations, which are usually on the order of milliseconds, we trade off some precision
1174        // here for supporting longer simulations.
1175        tcp.header.timestamp = from_legacy_timestamp(ts_val);
1176        tcp.header.timestamp_echo = from_legacy_timestamp(ts_echo);
1177    }
1178
1179    #[unsafe(no_mangle)]
1180    pub extern "C-unwind" fn packet_getTCPHeader(packet_ptr: *const Packet) -> c::PacketTCPHeader {
1181        let packet = PacketRc::borrow_raw(packet_ptr);
1182
1183        let IpAddr::V4(src_ip) = packet.header.src else {
1184            unimplemented!()
1185        };
1186        let IpAddr::V4(dst_ip) = packet.header.dst else {
1187            unimplemented!()
1188        };
1189        let Data::LegacyTcp(tcp_rc) = &packet.data else {
1190            unimplemented!()
1191        };
1192        let tcp = tcp_rc.borrow();
1193
1194        let mut c_hdr: c::PacketTCPHeader = unsafe { MaybeUninit::zeroed().assume_init() };
1195
1196        c_hdr.flags = tcp_flags_to_legacy_flags(tcp.header.flags);
1197        c_hdr.sourceIP = u32::from(src_ip).to_be();
1198        c_hdr.sourcePort = tcp.header.src_port.to_be();
1199        c_hdr.destinationIP = u32::from(dst_ip).to_be();
1200        c_hdr.destinationPort = tcp.header.dst_port.to_be();
1201        c_hdr.sequence = tcp.header.sequence;
1202        c_hdr.acknowledgment = tcp.header.acknowledgement;
1203        c_hdr.selectiveACKs = to_legacy_sel_acks(tcp.header.selective_acks);
1204        c_hdr.window = u32::from(tcp.header.window_size);
1205        if let Some(scale) = tcp.header.window_scale {
1206            c_hdr.windowScale = scale;
1207            c_hdr.windowScaleSet = true;
1208        }
1209        c_hdr.timestampValue = to_legacy_timestamp(tcp.header.timestamp);
1210        c_hdr.timestampEcho = to_legacy_timestamp(tcp.header.timestamp_echo);
1211
1212        c_hdr
1213    }
1214
1215    #[unsafe(no_mangle)]
1216    pub extern "C-unwind" fn packet_appendPayloadWithMemoryManager(
1217        packet_ptr: *mut Packet,
1218        src: UntypedForeignPtr,
1219        src_len: u64,
1220        mem: *const MemoryManager,
1221    ) {
1222        // Read data from the managed process into the packet's payload buffer.
1223        let packet = PacketRc::borrow_raw_mut(packet_ptr);
1224        let mem = unsafe { mem.as_ref() }.unwrap();
1225
1226        let Data::LegacyTcp(tcp) = &packet.data else {
1227            unimplemented!()
1228        };
1229
1230        let len = usize::try_from(src_len).unwrap();
1231        let src = ForeignArrayPtr::new(src.cast::<MaybeUninit<u8>>(), len);
1232
1233        // We want the dst buf on the heap so we don't have to copy it later. Uses
1234        // `new_uninit_slice` to avoid zero-filling the bytes in dst buffer that we are going to
1235        // copy over with the memory manager below anyway.
1236        let mut dst = Box::<[u8]>::new_uninit_slice(len);
1237
1238        log::trace!(
1239            "Requested to read payload of len {len} from the managed process into the packet's \
1240            payload buffer",
1241        );
1242
1243        // Copy from the managed process directly into the heap buffer. We want this to be the only
1244        // copy of the payload that occurs until the receiver host later copies it into their
1245        // managed process.
1246        if let Err(e) = mem.copy_from_ptr(&mut dst[..], src) {
1247            // Panic because the packet data will be corrupt (not what the application wrote).
1248            panic!(
1249                "Couldn't read managed process memory at {:?} into packet payload at {:?}: {:?}",
1250                src, dst, e
1251            );
1252        }
1253
1254        let dst = unsafe { dst.assume_init() };
1255
1256        log::trace!(
1257            "We read {} bytes from the managed process into the packet's payload",
1258            dst.len()
1259        );
1260
1261        // Move the payload into the packet. Use Bytes (not BytesMut) to avoid copying the payload.
1262        tcp.borrow_mut().payload.push(Bytes::from(dst));
1263    }
1264
1265    #[unsafe(no_mangle)]
1266    pub extern "C-unwind" fn packet_copyPayloadWithMemoryManager(
1267        packet_ptr: *const Packet,
1268        payload_offset: u64,
1269        dst: UntypedForeignPtr,
1270        dst_len: u64,
1271        mem: *mut MemoryManager,
1272    ) -> i64 {
1273        // Write the payload data from the packet into the managed process memory.
1274        let packet = PacketRc::borrow_raw(packet_ptr);
1275        let mem = unsafe { mem.as_mut() }.unwrap();
1276
1277        let Data::LegacyTcp(tcp) = &packet.data else {
1278            unimplemented!()
1279        };
1280
1281        if dst_len == 0 {
1282            return 0;
1283        }
1284
1285        log::trace!(
1286            "Requested to write payload of len {} from offset {payload_offset} into managed \
1287            process buffer of len {dst_len}",
1288            packet.payload_len()
1289        );
1290
1291        let dst_len = usize::try_from(dst_len).unwrap_or(usize::MAX);
1292        let dst = ForeignArrayPtr::new(dst.cast::<u8>(), dst_len);
1293
1294        let mut dst_writer = mem.writer(dst);
1295        let mut dst_space = dst_len;
1296        let mut src_offset = usize::try_from(payload_offset).unwrap_or(usize::MAX);
1297
1298        for bytes in &tcp.borrow().payload {
1299            // This also skips over empty Bytes objects.
1300            if src_offset >= bytes.len() {
1301                src_offset = src_offset.saturating_sub(bytes.len());
1302                continue;
1303            }
1304
1305            let start = src_offset;
1306            let len = bytes.len().saturating_sub(start).min(dst_space);
1307            let end = start + len;
1308            assert!(start <= end);
1309
1310            if len == 0 {
1311                break;
1312            }
1313
1314            log::trace!("Writing {len} bytes into managed process");
1315
1316            if let Err(e) = dst_writer.write_all(&bytes[start..end]) {
1317                log::warn!(
1318                    "Couldn't write managed process memory at {:?} from packet payload: {:?}",
1319                    dst,
1320                    e
1321                );
1322                // TODO: can we get memmgr errno here like we can with `copy_from_ptr()`?
1323                return linux_api::errno::Errno::EFAULT.to_negated_i64();
1324            }
1325
1326            dst_space = dst_space.saturating_sub(len);
1327            src_offset = 0;
1328        }
1329
1330        let tot_written = dst_len.saturating_sub(dst_space);
1331
1332        if tot_written > 0 {
1333            if let Err(e) = dst_writer.flush() {
1334                log::warn!(
1335                    "Couldn't flush managed process writes from packet payload: {:?}",
1336                    e
1337                );
1338                // TODO: can we get memmgr errno here like we can with `copy_from_ptr()`?
1339                return linux_api::errno::Errno::EFAULT.to_negated_i64();
1340            }
1341        }
1342
1343        log::trace!("We wrote {tot_written} bytes into managed process buffer of len {dst_len}");
1344
1345        i64::try_from(tot_written).unwrap()
1346    }
1347
1348    #[unsafe(no_mangle)]
1349    pub extern "C-unwind" fn packet_getPriority(packet_ptr: *const Packet) -> u64 {
1350        let packet = PacketRc::borrow_raw(packet_ptr);
1351        packet.priority()
1352    }
1353
1354    #[unsafe(no_mangle)]
1355    pub extern "C-unwind" fn packet_getPayloadSize(packet_ptr: *const Packet) -> u64 {
1356        let packet = PacketRc::borrow_raw(packet_ptr);
1357        packet.payload_len().try_into().unwrap()
1358    }
1359
1360    #[unsafe(no_mangle)]
1361    pub extern "C-unwind" fn packet_getDestinationIP(packet_ptr: *const Packet) -> libc::in_addr_t {
1362        let packet = PacketRc::borrow_raw(packet_ptr);
1363        u32::to_be((*packet.dst_ipv4_address().ip()).into())
1364    }
1365
1366    #[unsafe(no_mangle)]
1367    pub extern "C-unwind" fn packet_getDestinationPort(
1368        packet_ptr: *const Packet,
1369    ) -> libc::in_port_t {
1370        let packet = PacketRc::borrow_raw(packet_ptr);
1371        u16::to_be(packet.dst_ipv4_address().port())
1372    }
1373
1374    #[unsafe(no_mangle)]
1375    pub extern "C-unwind" fn packet_getSourceIP(packet_ptr: *const Packet) -> libc::in_addr_t {
1376        let packet = PacketRc::borrow_raw(packet_ptr);
1377        u32::to_be((*packet.src_ipv4_address().ip()).into())
1378    }
1379
1380    #[unsafe(no_mangle)]
1381    pub extern "C-unwind" fn packet_getSourcePort(packet_ptr: *const Packet) -> libc::in_port_t {
1382        let packet = PacketRc::borrow_raw(packet_ptr);
1383        u16::to_be(packet.src_ipv4_address().port())
1384    }
1385
1386    #[unsafe(no_mangle)]
1387    pub extern "C-unwind" fn packet_addDeliveryStatus(
1388        packet_ptr: *mut Packet,
1389        status: c::PacketDeliveryStatusFlags,
1390    ) {
1391        let packet = PacketRc::borrow_raw_mut(packet_ptr);
1392        packet.add_status(PacketStatus::from(status));
1393    }
1394
1395    #[unsafe(no_mangle)]
1396    pub extern "C-unwind" fn packet_compareTCPSequence(
1397        packet_ptr1: *mut Packet,
1398        packet_ptr2: *mut Packet,
1399        _ptr: *mut libc::c_void,
1400    ) -> libc::c_int {
1401        let packet1 = PacketRc::borrow_raw_mut(packet_ptr1);
1402        let packet2 = PacketRc::borrow_raw_mut(packet_ptr2);
1403
1404        let seq1 = get_sequence_number(&packet1);
1405        let seq2 = get_sequence_number(&packet2);
1406
1407        // Translated from the C packet impl.
1408        match seq1.cmp(&seq2) {
1409            Ordering::Less => -1,
1410            Ordering::Equal => 0,
1411            Ordering::Greater => 1,
1412        }
1413    }
1414
1415    fn get_sequence_number(packet: &PacketRc) -> u32 {
1416        let Data::LegacyTcp(tcp_ref) = &packet.data else {
1417            unimplemented!()
1418        };
1419        tcp_ref.borrow().header.sequence
1420    }
1421
1422    fn legacy_flags_to_tcp_flags(legacy_flags: c::ProtocolTCPFlags) -> tcp::TcpFlags {
1423        // The legacy flags use the first 7 bits of an i32. We could just do:
1424        // `u8::try_from(flags).expect("Legacy TCP flags use < 8 bits")` but we have to map the
1425        // values to support PCAP correctly.
1426        let mut tcp_flags = tcp::TcpFlags::empty();
1427
1428        if legacy_flags & c::_ProtocolTCPFlags_PTCP_FIN != 0 {
1429            tcp_flags.insert(tcp::TcpFlags::FIN);
1430        }
1431        if legacy_flags & c::_ProtocolTCPFlags_PTCP_SYN != 0 {
1432            tcp_flags.insert(tcp::TcpFlags::SYN);
1433        }
1434        if legacy_flags & c::_ProtocolTCPFlags_PTCP_RST != 0 {
1435            tcp_flags.insert(tcp::TcpFlags::RST);
1436        }
1437        if legacy_flags & c::_ProtocolTCPFlags_PTCP_ACK != 0 {
1438            tcp_flags.insert(tcp::TcpFlags::ACK);
1439        }
1440        // These legacy flags don't exist as real TCP flags, so we overload the two bits that are
1441        // not shown in the PCAP output.
1442        if legacy_flags & c::_ProtocolTCPFlags_PTCP_SACK != 0 {
1443            tcp_flags.insert(tcp::TcpFlags::ECE);
1444        }
1445        if legacy_flags & c::_ProtocolTCPFlags_PTCP_DUPACK != 0 {
1446            tcp_flags.insert(tcp::TcpFlags::CWR);
1447        }
1448
1449        tcp_flags
1450    }
1451
1452    fn tcp_flags_to_legacy_flags(tcp_flags: tcp::TcpFlags) -> c::ProtocolTCPFlags {
1453        // The u8 header flags fit within the legacy flags which are represented by an i32. We could
1454        // just do: `bits as c::ProtocolTCPFlags` but we have to map the values to support PCAP
1455        // correctly.
1456        let mut legacy_flags = c::_ProtocolTCPFlags_PTCP_NONE;
1457
1458        if tcp_flags.contains(tcp::TcpFlags::FIN) {
1459            legacy_flags |= c::_ProtocolTCPFlags_PTCP_FIN;
1460        }
1461        if tcp_flags.contains(tcp::TcpFlags::SYN) {
1462            legacy_flags |= c::_ProtocolTCPFlags_PTCP_SYN;
1463        }
1464        if tcp_flags.contains(tcp::TcpFlags::RST) {
1465            legacy_flags |= c::_ProtocolTCPFlags_PTCP_RST;
1466        }
1467        if tcp_flags.contains(tcp::TcpFlags::ACK) {
1468            legacy_flags |= c::_ProtocolTCPFlags_PTCP_ACK;
1469        }
1470        // Extract these from the encoding used in `legacy_flags_to_tcp_flags()`.
1471        if tcp_flags.contains(tcp::TcpFlags::ECE) {
1472            legacy_flags |= c::_ProtocolTCPFlags_PTCP_SACK;
1473        }
1474        if tcp_flags.contains(tcp::TcpFlags::CWR) {
1475            legacy_flags |= c::_ProtocolTCPFlags_PTCP_DUPACK;
1476        }
1477
1478        legacy_flags
1479    }
1480
1481    fn from_legacy_timestamp(ts: c::CSimulationTime) -> Option<u32> {
1482        SimulationTime::from_c_simtime(ts).map(|x| u32::try_from(x.as_millis()).unwrap_or(u32::MAX))
1483    }
1484
1485    fn to_legacy_timestamp(val: Option<u32>) -> c::CSimulationTime {
1486        SimulationTime::to_c_simtime(val.map(|x| SimulationTime::from_millis(x as u64)))
1487    }
1488
1489    impl From<c::PacketSelectiveAcks> for TcpSelectiveAcks {
1490        fn from(c_sel_acks: c::PacketSelectiveAcks) -> Self {
1491            let mut selective_acks = TcpSelectiveAcks::default();
1492
1493            assert!(c_sel_acks.len <= 4);
1494
1495            for i in 0..(c_sel_acks.len as usize) {
1496                let start: u32 = c_sel_acks.ranges[i].start;
1497                let end: u32 = c_sel_acks.ranges[i].end;
1498                selective_acks.ranges[i] = (start, end);
1499                selective_acks.len += 1;
1500            }
1501
1502            selective_acks
1503        }
1504    }
1505
1506    fn to_legacy_sel_acks(selective_acks: Option<TcpSelectiveAcks>) -> c::PacketSelectiveAcks {
1507        let mut c_sel_acks: c::PacketSelectiveAcks = unsafe { MaybeUninit::zeroed().assume_init() };
1508
1509        let Some(selective_acks) = selective_acks else {
1510            return c_sel_acks;
1511        };
1512
1513        assert!(selective_acks.len <= 4);
1514
1515        for i in 0..(selective_acks.len as usize) {
1516            let (start, end) = selective_acks.ranges[i];
1517            c_sel_acks.ranges[i].start = start;
1518            c_sel_acks.ranges[i].end = end;
1519            c_sel_acks.len += 1;
1520        }
1521
1522        c_sel_acks
1523    }
1524
1525    impl From<c::ProtocolType> for IanaProtocol {
1526        fn from(value: c::ProtocolType) -> Self {
1527            match value {
1528                c::_ProtocolType_PTCP => IanaProtocol::Tcp,
1529                c::_ProtocolType_PUDP => IanaProtocol::Udp,
1530                _ => panic!("Unexpected protocol type {value}"),
1531            }
1532        }
1533    }
1534
1535    impl From<c::PacketDeliveryStatusFlags> for PacketStatus {
1536        fn from(legacy_status: c::PacketDeliveryStatusFlags) -> Self {
1537            match legacy_status {
1538                c::_PacketDeliveryStatusFlags_PDS_SND_CREATED => PacketStatus::SndCreated,
1539                c::_PacketDeliveryStatusFlags_PDS_SND_TCP_ENQUEUE_THROTTLED => {
1540                    PacketStatus::SndTcpEnqueueThrottled
1541                }
1542                c::_PacketDeliveryStatusFlags_PDS_SND_TCP_ENQUEUE_RETRANSMIT => {
1543                    PacketStatus::SndTcpEnqueueRetransmit
1544                }
1545                c::_PacketDeliveryStatusFlags_PDS_SND_TCP_DEQUEUE_RETRANSMIT => {
1546                    PacketStatus::SndTcpDequeueRetransmit
1547                }
1548                c::_PacketDeliveryStatusFlags_PDS_SND_TCP_RETRANSMITTED => {
1549                    PacketStatus::SndTcpRetransmitted
1550                }
1551                c::_PacketDeliveryStatusFlags_PDS_SND_SOCKET_BUFFERED => {
1552                    PacketStatus::SndSocketBuffered
1553                }
1554                c::_PacketDeliveryStatusFlags_PDS_SND_INTERFACE_SENT => {
1555                    PacketStatus::SndInterfaceSent
1556                }
1557                c::_PacketDeliveryStatusFlags_PDS_INET_SENT => PacketStatus::InetSent,
1558                c::_PacketDeliveryStatusFlags_PDS_INET_DROPPED => PacketStatus::InetDropped,
1559                c::_PacketDeliveryStatusFlags_PDS_ROUTER_ENQUEUED => PacketStatus::RouterEnqueued,
1560                c::_PacketDeliveryStatusFlags_PDS_ROUTER_DEQUEUED => PacketStatus::RouterDequeued,
1561                c::_PacketDeliveryStatusFlags_PDS_ROUTER_DROPPED => PacketStatus::RouterDropped,
1562                c::_PacketDeliveryStatusFlags_PDS_RCV_INTERFACE_RECEIVED => {
1563                    PacketStatus::RcvInterfaceReceived
1564                }
1565                c::_PacketDeliveryStatusFlags_PDS_RCV_INTERFACE_DROPPED => {
1566                    PacketStatus::RcvInterfaceDropped
1567                }
1568                c::_PacketDeliveryStatusFlags_PDS_RCV_SOCKET_PROCESSED => {
1569                    PacketStatus::RcvSocketProcessed
1570                }
1571                c::_PacketDeliveryStatusFlags_PDS_RCV_SOCKET_DROPPED => {
1572                    PacketStatus::RcvSocketDropped
1573                }
1574                c::_PacketDeliveryStatusFlags_PDS_RCV_TCP_ENQUEUE_UNORDERED => {
1575                    PacketStatus::RcvTcpEnqueueUnordered
1576                }
1577                c::_PacketDeliveryStatusFlags_PDS_RCV_SOCKET_BUFFERED => {
1578                    PacketStatus::RcvSocketBuffered
1579                }
1580                c::_PacketDeliveryStatusFlags_PDS_RCV_SOCKET_DELIVERED => {
1581                    PacketStatus::RcvSocketDelivered
1582                }
1583                c::_PacketDeliveryStatusFlags_PDS_DESTROYED => PacketStatus::Destroyed,
1584                c::_PacketDeliveryStatusFlags_PDS_RELAY_CACHED => PacketStatus::RelayCached,
1585                c::_PacketDeliveryStatusFlags_PDS_RELAY_FORWARDED => PacketStatus::RelayForwarded,
1586                _ => unimplemented!(),
1587            }
1588        }
1589    }
1590}