Skip to main content

mx_remote/types/
third_party.rs

1// Author: Lars Op den Kamp (lars@opdenkamp-it.nl)
2// Copyright (c) 2026 Op den Kamp IT Solutions
3
4//! Messages other applications exchange over the mesh.
5
6use std::net::Ipv4Addr;
7
8use crate::wire::ThirdPartyVendorFlag;
9
10/// The largest payload a third-party message carries.
11///
12/// A frame this size fills one 1500-byte Ethernet frame exactly: 20 bytes of
13/// IPv4 header, 8 of UDP, the 24-byte frame header and the 4-byte vendor id
14/// leave 1444. A larger send is refused rather than fragmented, because a lost
15/// fragment loses the whole datagram and nothing on these paths retries.
16pub const THIRD_PARTY_PAYLOAD_MAX: usize = 1444;
17
18/// Whose message a third-party message is: a flag byte, then three bytes
19/// naming the vendor.
20///
21/// The three bytes are the vendor's IEEE OUI, in the order it is written, or
22/// with [`ThirdPartyVendorFlag::NOT_OUI`] set an identifier of the vendor's
23/// own choosing, such as three ASCII letters. The flag keeps the two spaces
24/// apart, so a chosen identifier never collides with a registered OUI.
25#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
26pub struct ThirdPartyVendor {
27    /// The flag byte, at offset 0.
28    pub flags: ThirdPartyVendorFlag,
29    /// The vendor's three identifying bytes, at offsets 1 to 3.
30    pub id: [u8; 3],
31}
32
33impl ThirdPartyVendor {
34    /// A vendor named by its IEEE OUI.
35    pub const fn oui(oui: [u8; 3]) -> Self {
36        Self {
37            flags: ThirdPartyVendorFlag::NONE,
38            id: oui,
39        }
40    }
41
42    /// A vendor named by an identifier it chose, rather than an OUI.
43    pub const fn private(id: [u8; 3]) -> Self {
44        Self {
45            flags: ThirdPartyVendorFlag::NOT_OUI,
46            id,
47        }
48    }
49
50    /// Whether `other` names the same vendor.
51    ///
52    /// Only [`ThirdPartyVendorFlag::NOT_OUI`] and the three identifying bytes
53    /// say who the vendor is, so the other flag bits are left out.
54    pub const fn same_vendor(self, other: Self) -> bool {
55        let a = self.id;
56        let b = other.id;
57        self.flags.has(ThirdPartyVendorFlag::NOT_OUI)
58            == other.flags.has(ThirdPartyVendorFlag::NOT_OUI)
59            && a[0] == b[0]
60            && a[1] == b[1]
61            && a[2] == b[2]
62    }
63
64    /// The four bytes on the wire.
65    pub(crate) const fn to_wire(self) -> [u8; 4] {
66        [self.flags.bits(), self.id[0], self.id[1], self.id[2]]
67    }
68
69    /// Reads the four bytes on the wire.
70    pub(crate) const fn from_wire(b: [u8; 4]) -> Self {
71        Self {
72            flags: ThirdPartyVendorFlag::from_bits(b[0]),
73            id: [b[1], b[2], b[3]],
74        }
75    }
76}
77
78/// A message an application sent to every device, under its own vendor id.
79///
80/// The library reads only the vendor id. What follows is the application's,
81/// and arrives exactly as it was sent.
82#[derive(Clone, Debug, Default, PartialEq, Eq)]
83pub struct ThirdPartyMessage {
84    /// Which application's message this is. The library checks none: each
85    /// application ignores every message whose vendor is not its own.
86    pub vendor: ThirdPartyVendor,
87    /// The application's bytes, at most [`THIRD_PARTY_PAYLOAD_MAX`].
88    pub payload: Vec<u8>,
89    /// Where the datagram came from, when the socket said.
90    pub address: Option<Ipv4Addr>,
91}