1use 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}