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