Skip to main content

mptcp_pm/
message.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlasIterator,
5    Parseable, ParseableParametrized,
6};
7use netlink_packet_generic::{GenlFamily, GenlHeader};
8
9use crate::{
10    address::MptcpPathManagerAddressAttr, limits::MptcpPathManagerLimitsAttr,
11};
12
13const MPTCP_PM_CMD_GET_ADDR: u8 = 3;
14const MPTCP_PM_CMD_GET_LIMITS: u8 = 6;
15
16const MPTCP_PM_ATTR_ADDR: u16 = 1;
17const MPTCP_PM_ATTR_RCV_ADD_ADDRS: u16 = 2;
18const MPTCP_PM_ATTR_SUBFLOWS: u16 = 3;
19
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21pub enum MptcpPathManagerCmd {
22    AddressGet,
23    LimitsGet,
24}
25
26impl From<MptcpPathManagerCmd> for u8 {
27    fn from(cmd: MptcpPathManagerCmd) -> Self {
28        match cmd {
29            MptcpPathManagerCmd::AddressGet => MPTCP_PM_CMD_GET_ADDR,
30            MptcpPathManagerCmd::LimitsGet => MPTCP_PM_CMD_GET_LIMITS,
31        }
32    }
33}
34
35#[derive(Debug, PartialEq, Eq, Clone)]
36pub enum MptcpPathManagerAttr {
37    Address(MptcpPathManagerAddressAttr),
38    Limits(MptcpPathManagerLimitsAttr),
39    Other(DefaultNla),
40}
41
42impl Nla for MptcpPathManagerAttr {
43    fn value_len(&self) -> usize {
44        match self {
45            Self::Address(attr) => attr.value_len(),
46            Self::Limits(attr) => attr.value_len(),
47            Self::Other(attr) => attr.value_len(),
48        }
49    }
50
51    fn kind(&self) -> u16 {
52        match self {
53            Self::Address(attr) => attr.kind(),
54            Self::Limits(attr) => attr.kind(),
55            Self::Other(attr) => attr.kind(),
56        }
57    }
58
59    fn emit_value(&self, buffer: &mut [u8]) {
60        match self {
61            Self::Address(attr) => attr.emit_value(buffer),
62            Self::Limits(attr) => attr.emit_value(buffer),
63            Self::Other(ref attr) => attr.emit(buffer),
64        }
65    }
66}
67
68#[derive(Debug, PartialEq, Eq, Clone)]
69pub struct MptcpPathManagerMessage {
70    pub cmd: MptcpPathManagerCmd,
71    pub nlas: Vec<MptcpPathManagerAttr>,
72}
73
74impl GenlFamily for MptcpPathManagerMessage {
75    fn family_name() -> &'static str {
76        "mptcp_pm"
77    }
78
79    fn version(&self) -> u8 {
80        1
81    }
82
83    fn command(&self) -> u8 {
84        self.cmd.into()
85    }
86}
87
88impl MptcpPathManagerMessage {
89    pub fn new_address_get() -> Self {
90        MptcpPathManagerMessage {
91            cmd: MptcpPathManagerCmd::AddressGet,
92            nlas: vec![],
93        }
94    }
95
96    pub fn new_limits_get() -> Self {
97        MptcpPathManagerMessage {
98            cmd: MptcpPathManagerCmd::LimitsGet,
99            nlas: vec![],
100        }
101    }
102}
103
104impl Emitable for MptcpPathManagerMessage {
105    fn buffer_len(&self) -> usize {
106        self.nlas.as_slice().buffer_len()
107    }
108
109    fn emit(&self, buffer: &mut [u8]) {
110        self.nlas.as_slice().emit(buffer)
111    }
112}
113
114fn parse_nlas(buffer: &[u8]) -> Result<Vec<MptcpPathManagerAttr>, DecodeError> {
115    let mut nlas = Vec::new();
116    for nla in NlasIterator::new(buffer) {
117        let error_msg =
118            format!("Failed to parse mptcp address message attribute {nla:?}");
119        let nla = &nla.context(error_msg)?;
120        match nla.kind() {
121            MPTCP_PM_ATTR_ADDR => {
122                for addr_nla in NlasIterator::new(nla.value()) {
123                    let error_msg = format!(
124                        "Failed to parse MPTCP_PM_ATTR_ADDR {addr_nla:?}"
125                    );
126                    let addr_nla = &addr_nla.context(error_msg)?;
127
128                    nlas.push(MptcpPathManagerAttr::Address(
129                        MptcpPathManagerAddressAttr::parse(addr_nla)
130                            .context("Failed to parse MPTCP_PM_ATTR_ADDR")?,
131                    ))
132                }
133            }
134            MPTCP_PM_ATTR_RCV_ADD_ADDRS => {
135                nlas.push(MptcpPathManagerAttr::Limits(
136                    MptcpPathManagerLimitsAttr::parse(nla).context(
137                        "Failed to parse MPTCP_PM_ATTR_RCV_ADD_ADDRS",
138                    )?,
139                ))
140            }
141            MPTCP_PM_ATTR_SUBFLOWS => nlas.push(MptcpPathManagerAttr::Limits(
142                MptcpPathManagerLimitsAttr::parse(nla)
143                    .context("Failed to parse MPTCP_PM_ATTR_RCV_ADD_ADDRS")?,
144            )),
145            _ => nlas.push(MptcpPathManagerAttr::Other(
146                DefaultNla::parse(nla).context("invalid NLA (unknown kind)")?,
147            )),
148        }
149    }
150    Ok(nlas)
151}
152
153impl ParseableParametrized<[u8], GenlHeader> for MptcpPathManagerMessage {
154    fn parse_with_param(
155        buffer: &[u8],
156        header: GenlHeader,
157    ) -> Result<Self, DecodeError> {
158        Ok(match header.cmd {
159            MPTCP_PM_CMD_GET_ADDR => Self {
160                cmd: MptcpPathManagerCmd::AddressGet,
161                nlas: parse_nlas(buffer)?,
162            },
163            MPTCP_PM_CMD_GET_LIMITS => Self {
164                cmd: MptcpPathManagerCmd::LimitsGet,
165                nlas: parse_nlas(buffer)?,
166            },
167            cmd => {
168                return Err(DecodeError::from(format!(
169                    "Unsupported mptcp reply command: {cmd}"
170                )))
171            }
172        })
173    }
174}