Skip to main content

mx_remote/types/
network.rs

1// Author: Lars Op den Kamp (lars@opdenkamp-it.nl)
2// Copyright (c) 2026 Op den Kamp IT Solutions
3
4//! Network port link state and cable diagnostics.
5
6use std::net::Ipv4Addr;
7
8use crate::wire::UtpLinkSpeed;
9
10/// The decoded link-error bitmask for a network port.
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub struct UtpLinkErrors {
13    /// A receive error was counted.
14    pub in_error: bool,
15    /// A receive frame failed its checksum.
16    pub in_fcs_error: bool,
17    /// A receive collision was counted.
18    pub in_collision: bool,
19    /// A transmit was deferred.
20    pub out_deferred: bool,
21    /// A transmit was deferred excessively.
22    pub out_excessive: bool,
23    /// A pair is wired with reversed polarity.
24    pub polarity_error: bool,
25    /// Pair skew is out of tolerance.
26    pub skew_warning: bool,
27    /// Cable length is out of tolerance.
28    pub length_warning: bool,
29}
30
31impl UtpLinkErrors {
32    /// Decodes the error byte.
33    pub(crate) const fn from_wire(v: u8) -> Self {
34        Self {
35            in_error: v & (1 << 0) != 0,
36            in_fcs_error: v & (1 << 1) != 0,
37            in_collision: v & (1 << 2) != 0,
38            out_deferred: v & (1 << 3) != 0,
39            out_excessive: v & (1 << 4) != 0,
40            polarity_error: v & (1 << 5) != 0,
41            skew_warning: v & (1 << 6) != 0,
42            length_warning: v & (1 << 7) != 0,
43        }
44    }
45}
46
47/// The diagnostic status of a single UTP cable pair.
48#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
49pub struct UtpCableStatus {
50    /// Whether the pair is wired with normal polarity.
51    pub polarity: bool,
52    /// Which pair this describes.
53    pub pair: u8,
54    /// Measured skew.
55    pub skew: u32,
56    /// Measured length.
57    pub length: u32,
58}
59
60/// The result of a virtual cable test on one pair.
61#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
62pub enum VctStatus {
63    /// The pair tested clean.
64    #[default]
65    Healthy,
66    /// The pair raised a warning.
67    Warning,
68}
69
70/// A hardware address.
71#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
72pub struct MacAddress(pub [u8; 6]);
73
74impl core::fmt::Display for MacAddress {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        let [a, b, c, d, e, g] = self.0;
77        write!(f, "{a:02X}:{b:02X}:{c:02X}:{d:02X}:{e:02X}:{g:02X}")
78    }
79}
80
81/// The link state and diagnostics of a network port.
82///
83/// A `None` field is one the port or its firmware does not report.
84#[derive(Clone, Debug, Default, PartialEq, Eq)]
85pub struct NetworkPortStatus {
86    /// Port number.
87    pub port: u16,
88    /// Port name.
89    pub name: String,
90    /// Negotiated link speed.
91    pub link_speed: UtpLinkSpeed,
92    /// Whether the link negotiated full duplex.
93    pub link_full_duplex: bool,
94    /// The port's own address.
95    pub ip: Option<Ipv4Addr>,
96    /// The IGMP querier the port sees.
97    pub querier: Option<Ipv4Addr>,
98    /// The port's hardware address.
99    pub mac_address: Option<MacAddress>,
100    /// Decoded link errors.
101    pub errors: Option<UtpLinkErrors>,
102    /// Virtual cable test result per pair.
103    pub vct_status: Option<[VctStatus; 4]>,
104    /// Cable diagnostics per pair.
105    pub cable_status: Vec<UtpCableStatus>,
106}