wl_nl80211/
mlo.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    parse_u8, DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
5    NlasIterator, Parseable,
6};
7
8const ETH_ALEN: usize = 6;
9const NL80211_ATTR_MAC: u16 = 6;
10const NL80211_ATTR_MLO_LINK_ID: u16 = 313;
11
12#[derive(Debug, PartialEq, Eq, Clone)]
13enum Nl80211MloLinkNla {
14    Id(u8),
15    Mac([u8; ETH_ALEN]),
16    Other(DefaultNla),
17}
18
19impl Nla for Nl80211MloLinkNla {
20    fn value_len(&self) -> usize {
21        match self {
22            Self::Id(_) => 1,
23            Self::Mac(_) => ETH_ALEN,
24            Self::Other(attr) => attr.value_len(),
25        }
26    }
27
28    fn kind(&self) -> u16 {
29        match self {
30            Self::Id(_) => NL80211_ATTR_MLO_LINK_ID,
31            Self::Mac(_) => NL80211_ATTR_MAC,
32            Self::Other(attr) => attr.kind(),
33        }
34    }
35
36    fn emit_value(&self, buffer: &mut [u8]) {
37        match self {
38            Self::Id(d) => buffer[0] = *d,
39            Self::Mac(s) => buffer.copy_from_slice(s),
40            Self::Other(attr) => attr.emit(buffer),
41        }
42    }
43}
44
45impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
46    for Nl80211MloLinkNla
47{
48    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
49        let payload = buf.value();
50        Ok(match buf.kind() {
51            NL80211_ATTR_MLO_LINK_ID => {
52                let err_msg = format!(
53                    "Invalid NL80211_ATTR_MLO_LINK_ID value {payload:?}"
54                );
55                Self::Id(parse_u8(payload).context(err_msg)?)
56            }
57            NL80211_ATTR_MAC => Self::Mac(if payload.len() == ETH_ALEN {
58                let mut ret = [0u8; ETH_ALEN];
59                ret.copy_from_slice(&payload[..ETH_ALEN]);
60                ret
61            } else {
62                return Err(format!(
63                    "Invalid length of NL80211_ATTR_MAC, expected length {ETH_ALEN} got {payload:?}"
64                )
65                .into());
66            }),
67            _ => Self::Other(
68                DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
69            ),
70        })
71    }
72}
73
74/// Multi-Link Operation
75#[derive(Debug, PartialEq, Eq, Clone, Default)]
76#[non_exhaustive]
77pub struct Nl80211MloLink {
78    pub id: u8,
79    pub mac: [u8; ETH_ALEN],
80}
81
82impl Nla for Nl80211MloLink {
83    fn value_len(&self) -> usize {
84        Vec::<Nl80211MloLinkNla>::from(self).as_slice().buffer_len()
85    }
86
87    fn kind(&self) -> u16 {
88        self.id as u16 + 1
89    }
90
91    fn emit_value(&self, buffer: &mut [u8]) {
92        Vec::<Nl80211MloLinkNla>::from(self).as_slice().emit(buffer)
93    }
94}
95
96impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
97    for Nl80211MloLink
98{
99    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
100        let mut ret = Self::default();
101        let payload = buf.value();
102        let err_msg =
103            format!("Invalid NL80211_ATTR_MLO_LINKS value {payload:?}");
104        for nla in NlasIterator::new(payload) {
105            let nla = &nla.context(err_msg.clone())?;
106            match Nl80211MloLinkNla::parse(nla).context(err_msg.clone())? {
107                Nl80211MloLinkNla::Id(d) => ret.id = d,
108                Nl80211MloLinkNla::Mac(s) => ret.mac = s,
109                Nl80211MloLinkNla::Other(attr) => {
110                    log::warn!(
111                        "Got unsupported NL80211_ATTR_MLO_LINKS value {attr:?}"
112                    )
113                }
114            }
115        }
116        Ok(ret)
117    }
118}
119
120impl From<&Nl80211MloLink> for Vec<Nl80211MloLinkNla> {
121    fn from(link: &Nl80211MloLink) -> Self {
122        vec![
123            Nl80211MloLinkNla::Id(link.id),
124            Nl80211MloLinkNla::Mac(link.mac),
125        ]
126    }
127}