netlink_packet_route/link/link_info/
macsec.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use byteorder::{ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
6use netlink_packet_utils::parsers::{parse_u16, parse_u32, parse_u64, parse_u8};
7use netlink_packet_utils::traits::Parseable;
8use netlink_packet_utils::DecodeError;
9
10const IFLA_MACSEC_SCI: u16 = 1;
11const IFLA_MACSEC_PORT: u16 = 2;
12const IFLA_MACSEC_ICV_LEN: u16 = 3;
13const IFLA_MACSEC_CIPHER_SUITE: u16 = 4;
14const IFLA_MACSEC_WINDOW: u16 = 5;
15const IFLA_MACSEC_ENCODING_SA: u16 = 6;
16const IFLA_MACSEC_ENCRYPT: u16 = 7;
17const IFLA_MACSEC_PROTECT: u16 = 8;
18const IFLA_MACSEC_INC_SCI: u16 = 9;
19const IFLA_MACSEC_ES: u16 = 10;
20const IFLA_MACSEC_SCB: u16 = 11;
21const IFLA_MACSEC_REPLAY_PROTECT: u16 = 12;
22const IFLA_MACSEC_VALIDATION: u16 = 13;
23// const IFLA_MACSEC_PAD: u16 = 14;
24const IFLA_MACSEC_OFFLOAD: u16 = 15;
25const MACSEC_VALIDATE_DISABLED: u8 = 0;
26const MACSEC_VALIDATE_CHECK: u8 = 1;
27const MACSEC_VALIDATE_STRICT: u8 = 2;
28const MACSEC_OFFLOAD_OFF: u8 = 0;
29const MACSEC_OFFLOAD_PHY: u8 = 1;
30const MACSEC_OFFLOAD_MAC: u8 = 2;
31const MACSEC_CIPHER_ID_GCM_AES_128: u64 = 0x0080C20001000001;
32const MACSEC_CIPHER_ID_GCM_AES_256: u64 = 0x0080C20001000002;
33const MACSEC_CIPHER_ID_GCM_AES_XPN_128: u64 = 0x0080C20001000003;
34const MACSEC_CIPHER_ID_GCM_AES_XPN_256: u64 = 0x0080C20001000004;
35const MACSEC_DEFAULT_CIPHER_ID: u64 = 0x0080020001000001;
36
37#[derive(Debug, PartialEq, Eq, Clone, Copy)]
38#[non_exhaustive]
39pub enum MacSecCipherId {
40    #[deprecated]
41    DefaultGcmAes128,
42    GcmAes128,
43    GcmAes256,
44    GcmAesXpn128,
45    GcmAesXpn256,
46    Other(u64),
47}
48
49impl From<u64> for MacSecCipherId {
50    fn from(d: u64) -> Self {
51        match d {
52            #[allow(deprecated)]
53            MACSEC_DEFAULT_CIPHER_ID => Self::DefaultGcmAes128,
54            MACSEC_CIPHER_ID_GCM_AES_128 => Self::GcmAes128,
55            MACSEC_CIPHER_ID_GCM_AES_256 => Self::GcmAes256,
56            MACSEC_CIPHER_ID_GCM_AES_XPN_128 => Self::GcmAesXpn128,
57            MACSEC_CIPHER_ID_GCM_AES_XPN_256 => Self::GcmAesXpn256,
58            _ => Self::Other(d),
59        }
60    }
61}
62
63impl From<MacSecCipherId> for u64 {
64    fn from(d: MacSecCipherId) -> Self {
65        match d {
66            #[allow(deprecated)]
67            MacSecCipherId::DefaultGcmAes128 => MACSEC_DEFAULT_CIPHER_ID,
68            MacSecCipherId::GcmAes128 => MACSEC_CIPHER_ID_GCM_AES_128,
69            MacSecCipherId::GcmAes256 => MACSEC_CIPHER_ID_GCM_AES_256,
70            MacSecCipherId::GcmAesXpn128 => MACSEC_CIPHER_ID_GCM_AES_XPN_128,
71            MacSecCipherId::GcmAesXpn256 => MACSEC_CIPHER_ID_GCM_AES_XPN_256,
72            MacSecCipherId::Other(value) => value,
73        }
74    }
75}
76
77#[derive(Debug, PartialEq, Eq, Clone, Copy)]
78#[non_exhaustive]
79pub enum MacSecValidate {
80    Disabled,
81    Check,
82    Strict,
83    Other(u8),
84}
85
86impl From<u8> for MacSecValidate {
87    fn from(d: u8) -> Self {
88        match d {
89            MACSEC_VALIDATE_DISABLED => Self::Disabled,
90            MACSEC_VALIDATE_CHECK => Self::Check,
91            MACSEC_VALIDATE_STRICT => Self::Strict,
92            _ => Self::Other(d),
93        }
94    }
95}
96
97impl From<MacSecValidate> for u8 {
98    fn from(d: MacSecValidate) -> Self {
99        match d {
100            MacSecValidate::Disabled => MACSEC_VALIDATE_DISABLED,
101            MacSecValidate::Check => MACSEC_VALIDATE_CHECK,
102            MacSecValidate::Strict => MACSEC_VALIDATE_STRICT,
103            MacSecValidate::Other(value) => value,
104        }
105    }
106}
107
108#[derive(Debug, PartialEq, Eq, Clone, Copy)]
109#[non_exhaustive]
110pub enum MacSecOffload {
111    Off,
112    Phy,
113    Mac,
114    Other(u8),
115}
116
117impl From<u8> for MacSecOffload {
118    fn from(d: u8) -> Self {
119        match d {
120            MACSEC_OFFLOAD_OFF => Self::Off,
121            MACSEC_OFFLOAD_PHY => Self::Phy,
122            MACSEC_OFFLOAD_MAC => Self::Mac,
123            _ => Self::Other(d),
124        }
125    }
126}
127
128impl From<MacSecOffload> for u8 {
129    fn from(d: MacSecOffload) -> Self {
130        match d {
131            MacSecOffload::Off => MACSEC_OFFLOAD_OFF,
132            MacSecOffload::Phy => MACSEC_OFFLOAD_PHY,
133            MacSecOffload::Mac => MACSEC_OFFLOAD_MAC,
134            MacSecOffload::Other(value) => value,
135        }
136    }
137}
138
139#[derive(Debug, PartialEq, Eq, Clone)]
140#[non_exhaustive]
141pub enum InfoMacSec {
142    Sci(u64),
143    Port(u16),
144    IcvLen(u8),
145    CipherSuite(MacSecCipherId),
146    Window(u32),
147    EncodingSa(u8),
148    Encrypt(u8),
149    Protect(u8),
150    IncSci(u8),
151    Es(u8),
152    Scb(u8),
153    ReplayProtect(u8),
154    Validation(MacSecValidate),
155    Offload(MacSecOffload),
156    Other(DefaultNla),
157}
158
159impl Nla for InfoMacSec {
160    fn value_len(&self) -> usize {
161        use self::InfoMacSec::*;
162        match self {
163            Sci(_) | CipherSuite(_) => 8,
164            Window(_) => 4,
165            Port(_) => 2,
166            IcvLen(_) | EncodingSa(_) | Encrypt(_) | Protect(_) | IncSci(_) | Es(_) | Scb(_)
167            | ReplayProtect(_) | Validation(_) | Offload(_) => 1,
168            Other(nla) => nla.value_len(),
169        }
170    }
171
172    fn emit_value(&self, buffer: &mut [u8]) {
173        use self::InfoMacSec::*;
174        match self {
175            Sci(value) => NativeEndian::write_u64(buffer, *value),
176            CipherSuite(value) => NativeEndian::write_u64(buffer, (*value).into()),
177            Window(value) => NativeEndian::write_u32(buffer, *value),
178            Port(value) => NativeEndian::write_u16(buffer, *value),
179            IcvLen(value) | EncodingSa(value) | Encrypt(value) | Protect(value) | IncSci(value)
180            | Es(value) | Scb(value) | ReplayProtect(value) => buffer[0] = *value,
181            Offload(value) => buffer[0] = (*value).into(),
182            Validation(value) => buffer[0] = (*value).into(),
183            Other(nla) => nla.emit_value(buffer),
184        }
185    }
186
187    fn kind(&self) -> u16 {
188        use self::InfoMacSec::*;
189        match self {
190            Sci(_) => IFLA_MACSEC_SCI,
191            Port(_) => IFLA_MACSEC_PORT,
192            IcvLen(_) => IFLA_MACSEC_ICV_LEN,
193            CipherSuite(_) => IFLA_MACSEC_CIPHER_SUITE,
194            Window(_) => IFLA_MACSEC_WINDOW,
195            EncodingSa(_) => IFLA_MACSEC_ENCODING_SA,
196            Encrypt(_) => IFLA_MACSEC_ENCRYPT,
197            Protect(_) => IFLA_MACSEC_PROTECT,
198            IncSci(_) => IFLA_MACSEC_INC_SCI,
199            Es(_) => IFLA_MACSEC_ES,
200            Scb(_) => IFLA_MACSEC_SCB,
201            ReplayProtect(_) => IFLA_MACSEC_REPLAY_PROTECT,
202            Validation(_) => IFLA_MACSEC_VALIDATION,
203            Offload(_) => IFLA_MACSEC_OFFLOAD,
204            Other(nla) => nla.kind(),
205        }
206    }
207}
208
209impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacSec {
210    type Error = DecodeError;
211    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
212        use self::InfoMacSec::*;
213        let payload = buf.value();
214        Ok(match buf.kind() {
215            IFLA_MACSEC_SCI => Sci(parse_u64(payload).context("invalid IFLA_MACSEC_SCI value")?),
216            IFLA_MACSEC_PORT => Port(parse_u16(payload).context("invalid IFLA_MACSEC_PORT value")?),
217            IFLA_MACSEC_ICV_LEN => {
218                IcvLen(parse_u8(payload).context("invalid IFLA_MACSEC_ICV_LEN value")?)
219            }
220            IFLA_MACSEC_CIPHER_SUITE => CipherSuite(
221                parse_u64(payload).context("invalid IFLA_MACSEC_CIPHER_SUITE value")?.into(),
222            ),
223            IFLA_MACSEC_WINDOW => {
224                Window(parse_u32(payload).context("invalid IFLA_MACSEC_WINDOW value")?)
225            }
226            IFLA_MACSEC_ENCODING_SA => {
227                EncodingSa(parse_u8(payload).context("invalid IFLA_MACSEC_ENCODING_SA value")?)
228            }
229            IFLA_MACSEC_ENCRYPT => {
230                Encrypt(parse_u8(payload).context("invalid IFLA_MACSEC_ENCRYPT value")?)
231            }
232            IFLA_MACSEC_PROTECT => {
233                Protect(parse_u8(payload).context("invalid IFLA_MACSEC_PROTECT value")?)
234            }
235            IFLA_MACSEC_INC_SCI => {
236                IncSci(parse_u8(payload).context("invalid IFLA_MACSEC_INC_SCI value")?)
237            }
238            IFLA_MACSEC_ES => Es(parse_u8(payload).context("invalid IFLA_MACSEC_ES value")?),
239            IFLA_MACSEC_SCB => Scb(parse_u8(payload).context("invalid IFLA_MACSEC_SCB value")?),
240            IFLA_MACSEC_REPLAY_PROTECT => ReplayProtect(
241                parse_u8(payload).context("invalid IFLA_MACSEC_REPLAY_PROTECT value")?,
242            ),
243            IFLA_MACSEC_VALIDATION => Validation(
244                parse_u8(payload).context("invalid IFLA_MACSEC_VALIDATION value")?.into(),
245            ),
246            IFLA_MACSEC_OFFLOAD => {
247                Offload(parse_u8(payload).context("invalid IFLA_MACSEC_OFFLOAD value")?.into())
248            }
249            kind => Other(DefaultNla::parse(buf).context(format!("unknown NLA type {kind}"))?),
250        })
251    }
252}