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}