Commit | Line | Data |
---|---|---|
2be665c3 HB |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | ||
3 | #include <net/genetlink.h> | |
4 | ||
5 | #include "br_private.h" | |
6 | #include "br_private_cfm.h" | |
7 | ||
8 | static const struct nla_policy | |
9 | br_cfm_mep_create_policy[IFLA_BRIDGE_CFM_MEP_CREATE_MAX + 1] = { | |
10 | [IFLA_BRIDGE_CFM_MEP_CREATE_UNSPEC] = { .type = NLA_REJECT }, | |
11 | [IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE] = { .type = NLA_U32 }, | |
12 | [IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN] = { .type = NLA_U32 }, | |
13 | [IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION] = { .type = NLA_U32 }, | |
14 | [IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX] = { .type = NLA_U32 }, | |
15 | }; | |
16 | ||
17 | static const struct nla_policy | |
18 | br_cfm_mep_delete_policy[IFLA_BRIDGE_CFM_MEP_DELETE_MAX + 1] = { | |
19 | [IFLA_BRIDGE_CFM_MEP_DELETE_UNSPEC] = { .type = NLA_REJECT }, | |
20 | [IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE] = { .type = NLA_U32 }, | |
21 | }; | |
22 | ||
23 | static const struct nla_policy | |
24 | br_cfm_mep_config_policy[IFLA_BRIDGE_CFM_MEP_CONFIG_MAX + 1] = { | |
25 | [IFLA_BRIDGE_CFM_MEP_CONFIG_UNSPEC] = { .type = NLA_REJECT }, | |
26 | [IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE] = { .type = NLA_U32 }, | |
27 | [IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC] = NLA_POLICY_ETH_ADDR, | |
28 | [IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL] = NLA_POLICY_MAX(NLA_U32, 7), | |
29 | [IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID] = NLA_POLICY_MAX(NLA_U32, 0x1FFF), | |
30 | }; | |
31 | ||
32 | static const struct nla_policy | |
33 | br_cfm_cc_config_policy[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1] = { | |
34 | [IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC] = { .type = NLA_REJECT }, | |
35 | [IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE] = { .type = NLA_U32 }, | |
36 | [IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE] = { .type = NLA_U32 }, | |
37 | [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] = { .type = NLA_U32 }, | |
38 | [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID] = { | |
39 | .type = NLA_BINARY, .len = CFM_MAID_LENGTH }, | |
40 | }; | |
41 | ||
42 | static const struct nla_policy | |
43 | br_cfm_cc_peer_mep_policy[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1] = { | |
44 | [IFLA_BRIDGE_CFM_CC_PEER_MEP_UNSPEC] = { .type = NLA_REJECT }, | |
45 | [IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE] = { .type = NLA_U32 }, | |
46 | [IFLA_BRIDGE_CFM_CC_PEER_MEPID] = NLA_POLICY_MAX(NLA_U32, 0x1FFF), | |
47 | }; | |
48 | ||
49 | static const struct nla_policy | |
50 | br_cfm_cc_rdi_policy[IFLA_BRIDGE_CFM_CC_RDI_MAX + 1] = { | |
51 | [IFLA_BRIDGE_CFM_CC_RDI_UNSPEC] = { .type = NLA_REJECT }, | |
52 | [IFLA_BRIDGE_CFM_CC_RDI_INSTANCE] = { .type = NLA_U32 }, | |
53 | [IFLA_BRIDGE_CFM_CC_RDI_RDI] = { .type = NLA_U32 }, | |
54 | }; | |
55 | ||
56 | static const struct nla_policy | |
57 | br_cfm_cc_ccm_tx_policy[IFLA_BRIDGE_CFM_CC_CCM_TX_MAX + 1] = { | |
58 | [IFLA_BRIDGE_CFM_CC_CCM_TX_UNSPEC] = { .type = NLA_REJECT }, | |
59 | [IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE] = { .type = NLA_U32 }, | |
60 | [IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC] = NLA_POLICY_ETH_ADDR, | |
61 | [IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE] = { .type = NLA_U32 }, | |
62 | [IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD] = { .type = NLA_U32 }, | |
63 | [IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV] = { .type = NLA_U32 }, | |
64 | [IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE] = { .type = NLA_U8 }, | |
65 | [IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV] = { .type = NLA_U32 }, | |
66 | [IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE] = { .type = NLA_U8 }, | |
67 | }; | |
68 | ||
69 | static const struct nla_policy | |
70 | br_cfm_policy[IFLA_BRIDGE_CFM_MAX + 1] = { | |
71 | [IFLA_BRIDGE_CFM_UNSPEC] = { .type = NLA_REJECT }, | |
72 | [IFLA_BRIDGE_CFM_MEP_CREATE] = | |
73 | NLA_POLICY_NESTED(br_cfm_mep_create_policy), | |
74 | [IFLA_BRIDGE_CFM_MEP_DELETE] = | |
75 | NLA_POLICY_NESTED(br_cfm_mep_delete_policy), | |
76 | [IFLA_BRIDGE_CFM_MEP_CONFIG] = | |
77 | NLA_POLICY_NESTED(br_cfm_mep_config_policy), | |
78 | [IFLA_BRIDGE_CFM_CC_CONFIG] = | |
79 | NLA_POLICY_NESTED(br_cfm_cc_config_policy), | |
80 | [IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD] = | |
81 | NLA_POLICY_NESTED(br_cfm_cc_peer_mep_policy), | |
82 | [IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE] = | |
83 | NLA_POLICY_NESTED(br_cfm_cc_peer_mep_policy), | |
84 | [IFLA_BRIDGE_CFM_CC_RDI] = | |
85 | NLA_POLICY_NESTED(br_cfm_cc_rdi_policy), | |
86 | [IFLA_BRIDGE_CFM_CC_CCM_TX] = | |
87 | NLA_POLICY_NESTED(br_cfm_cc_ccm_tx_policy), | |
88 | }; | |
89 | ||
90 | static int br_mep_create_parse(struct net_bridge *br, struct nlattr *attr, | |
91 | struct netlink_ext_ack *extack) | |
92 | { | |
93 | struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_CREATE_MAX + 1]; | |
94 | struct br_cfm_mep_create create; | |
95 | u32 instance; | |
96 | int err; | |
97 | ||
98 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_CREATE_MAX, attr, | |
99 | br_cfm_mep_create_policy, extack); | |
100 | if (err) | |
101 | return err; | |
102 | ||
103 | if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE]) { | |
104 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
105 | return -EINVAL; | |
106 | } | |
107 | if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN]) { | |
108 | NL_SET_ERR_MSG_MOD(extack, "Missing DOMAIN attribute"); | |
109 | return -EINVAL; | |
110 | } | |
111 | if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION]) { | |
112 | NL_SET_ERR_MSG_MOD(extack, "Missing DIRECTION attribute"); | |
113 | return -EINVAL; | |
114 | } | |
115 | if (!tb[IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX]) { | |
116 | NL_SET_ERR_MSG_MOD(extack, "Missing IFINDEX attribute"); | |
117 | return -EINVAL; | |
118 | } | |
119 | ||
120 | memset(&create, 0, sizeof(create)); | |
121 | ||
122 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE]); | |
123 | create.domain = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN]); | |
124 | create.direction = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION]); | |
125 | create.ifindex = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX]); | |
126 | ||
127 | return br_cfm_mep_create(br, instance, &create, extack); | |
128 | } | |
129 | ||
130 | static int br_mep_delete_parse(struct net_bridge *br, struct nlattr *attr, | |
131 | struct netlink_ext_ack *extack) | |
132 | { | |
133 | struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_DELETE_MAX + 1]; | |
134 | u32 instance; | |
135 | int err; | |
136 | ||
137 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_DELETE_MAX, attr, | |
138 | br_cfm_mep_delete_policy, extack); | |
139 | if (err) | |
140 | return err; | |
141 | ||
142 | if (!tb[IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE]) { | |
143 | NL_SET_ERR_MSG_MOD(extack, | |
144 | "Missing INSTANCE attribute"); | |
145 | return -EINVAL; | |
146 | } | |
147 | ||
148 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE]); | |
149 | ||
150 | return br_cfm_mep_delete(br, instance, extack); | |
151 | } | |
152 | ||
153 | static int br_mep_config_parse(struct net_bridge *br, struct nlattr *attr, | |
154 | struct netlink_ext_ack *extack) | |
155 | { | |
156 | struct nlattr *tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MAX + 1]; | |
157 | struct br_cfm_mep_config config; | |
158 | u32 instance; | |
159 | int err; | |
160 | ||
161 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MEP_CONFIG_MAX, attr, | |
162 | br_cfm_mep_config_policy, extack); | |
163 | if (err) | |
164 | return err; | |
165 | ||
166 | if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE]) { | |
167 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
168 | return -EINVAL; | |
169 | } | |
170 | if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC]) { | |
171 | NL_SET_ERR_MSG_MOD(extack, "Missing UNICAST_MAC attribute"); | |
172 | return -EINVAL; | |
173 | } | |
174 | if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL]) { | |
175 | NL_SET_ERR_MSG_MOD(extack, "Missing MDLEVEL attribute"); | |
176 | return -EINVAL; | |
177 | } | |
178 | if (!tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID]) { | |
179 | NL_SET_ERR_MSG_MOD(extack, "Missing MEPID attribute"); | |
180 | return -EINVAL; | |
181 | } | |
182 | ||
183 | memset(&config, 0, sizeof(config)); | |
184 | ||
185 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE]); | |
186 | nla_memcpy(&config.unicast_mac.addr, | |
187 | tb[IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC], | |
188 | sizeof(config.unicast_mac.addr)); | |
189 | config.mdlevel = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL]); | |
190 | config.mepid = nla_get_u32(tb[IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID]); | |
191 | ||
192 | return br_cfm_mep_config_set(br, instance, &config, extack); | |
193 | } | |
194 | ||
195 | static int br_cc_config_parse(struct net_bridge *br, struct nlattr *attr, | |
196 | struct netlink_ext_ack *extack) | |
197 | { | |
198 | struct nlattr *tb[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1]; | |
199 | struct br_cfm_cc_config config; | |
200 | u32 instance; | |
201 | int err; | |
202 | ||
203 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_CONFIG_MAX, attr, | |
204 | br_cfm_cc_config_policy, extack); | |
205 | if (err) | |
206 | return err; | |
207 | ||
208 | if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE]) { | |
209 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
210 | return -EINVAL; | |
211 | } | |
212 | if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE]) { | |
213 | NL_SET_ERR_MSG_MOD(extack, "Missing ENABLE attribute"); | |
214 | return -EINVAL; | |
215 | } | |
216 | if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL]) { | |
217 | NL_SET_ERR_MSG_MOD(extack, "Missing INTERVAL attribute"); | |
218 | return -EINVAL; | |
219 | } | |
220 | if (!tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID]) { | |
221 | NL_SET_ERR_MSG_MOD(extack, "Missing MAID attribute"); | |
222 | return -EINVAL; | |
223 | } | |
224 | ||
225 | memset(&config, 0, sizeof(config)); | |
226 | ||
227 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE]); | |
228 | config.enable = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE]); | |
229 | config.exp_interval = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL]); | |
230 | nla_memcpy(&config.exp_maid.data, tb[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID], | |
231 | sizeof(config.exp_maid.data)); | |
232 | ||
233 | return br_cfm_cc_config_set(br, instance, &config, extack); | |
234 | } | |
235 | ||
236 | static int br_cc_peer_mep_add_parse(struct net_bridge *br, struct nlattr *attr, | |
237 | struct netlink_ext_ack *extack) | |
238 | { | |
239 | struct nlattr *tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1]; | |
240 | u32 instance, peer_mep_id; | |
241 | int err; | |
242 | ||
243 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX, attr, | |
244 | br_cfm_cc_peer_mep_policy, extack); | |
245 | if (err) | |
246 | return err; | |
247 | ||
248 | if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]) { | |
249 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
250 | return -EINVAL; | |
251 | } | |
252 | if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]) { | |
253 | NL_SET_ERR_MSG_MOD(extack, "Missing PEER_MEP_ID attribute"); | |
254 | return -EINVAL; | |
255 | } | |
256 | ||
257 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]); | |
258 | peer_mep_id = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]); | |
259 | ||
260 | return br_cfm_cc_peer_mep_add(br, instance, peer_mep_id, extack); | |
261 | } | |
262 | ||
263 | static int br_cc_peer_mep_remove_parse(struct net_bridge *br, struct nlattr *attr, | |
264 | struct netlink_ext_ack *extack) | |
265 | { | |
266 | struct nlattr *tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX + 1]; | |
267 | u32 instance, peer_mep_id; | |
268 | int err; | |
269 | ||
270 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX, attr, | |
271 | br_cfm_cc_peer_mep_policy, extack); | |
272 | if (err) | |
273 | return err; | |
274 | ||
275 | if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]) { | |
276 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
277 | return -EINVAL; | |
278 | } | |
279 | if (!tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]) { | |
280 | NL_SET_ERR_MSG_MOD(extack, "Missing PEER_MEP_ID attribute"); | |
281 | return -EINVAL; | |
282 | } | |
283 | ||
284 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE]); | |
285 | peer_mep_id = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_PEER_MEPID]); | |
286 | ||
287 | return br_cfm_cc_peer_mep_remove(br, instance, peer_mep_id, extack); | |
288 | } | |
289 | ||
290 | static int br_cc_rdi_parse(struct net_bridge *br, struct nlattr *attr, | |
291 | struct netlink_ext_ack *extack) | |
292 | { | |
293 | struct nlattr *tb[IFLA_BRIDGE_CFM_CC_RDI_MAX + 1]; | |
294 | u32 instance, rdi; | |
295 | int err; | |
296 | ||
297 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_RDI_MAX, attr, | |
298 | br_cfm_cc_rdi_policy, extack); | |
299 | if (err) | |
300 | return err; | |
301 | ||
302 | if (!tb[IFLA_BRIDGE_CFM_CC_RDI_INSTANCE]) { | |
303 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
304 | return -EINVAL; | |
305 | } | |
306 | if (!tb[IFLA_BRIDGE_CFM_CC_RDI_RDI]) { | |
307 | NL_SET_ERR_MSG_MOD(extack, "Missing RDI attribute"); | |
308 | return -EINVAL; | |
309 | } | |
310 | ||
311 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_INSTANCE]); | |
312 | rdi = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_RDI]); | |
313 | ||
314 | return br_cfm_cc_rdi_set(br, instance, rdi, extack); | |
315 | } | |
316 | ||
317 | static int br_cc_ccm_tx_parse(struct net_bridge *br, struct nlattr *attr, | |
318 | struct netlink_ext_ack *extack) | |
319 | { | |
320 | struct nlattr *tb[IFLA_BRIDGE_CFM_CC_CCM_TX_MAX + 1]; | |
321 | struct br_cfm_cc_ccm_tx_info tx_info; | |
322 | u32 instance; | |
323 | int err; | |
324 | ||
325 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_CC_CCM_TX_MAX, attr, | |
326 | br_cfm_cc_ccm_tx_policy, extack); | |
327 | if (err) | |
328 | return err; | |
329 | ||
330 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE]) { | |
331 | NL_SET_ERR_MSG_MOD(extack, "Missing INSTANCE attribute"); | |
332 | return -EINVAL; | |
333 | } | |
334 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC]) { | |
335 | NL_SET_ERR_MSG_MOD(extack, "Missing DMAC attribute"); | |
336 | return -EINVAL; | |
337 | } | |
338 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE]) { | |
339 | NL_SET_ERR_MSG_MOD(extack, "Missing SEQ_NO_UPDATE attribute"); | |
340 | return -EINVAL; | |
341 | } | |
342 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD]) { | |
343 | NL_SET_ERR_MSG_MOD(extack, "Missing PERIOD attribute"); | |
344 | return -EINVAL; | |
345 | } | |
346 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV]) { | |
347 | NL_SET_ERR_MSG_MOD(extack, "Missing IF_TLV attribute"); | |
348 | return -EINVAL; | |
349 | } | |
350 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE]) { | |
351 | NL_SET_ERR_MSG_MOD(extack, "Missing IF_TLV_VALUE attribute"); | |
352 | return -EINVAL; | |
353 | } | |
354 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV]) { | |
355 | NL_SET_ERR_MSG_MOD(extack, "Missing PORT_TLV attribute"); | |
356 | return -EINVAL; | |
357 | } | |
358 | if (!tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE]) { | |
359 | NL_SET_ERR_MSG_MOD(extack, "Missing PORT_TLV_VALUE attribute"); | |
360 | return -EINVAL; | |
361 | } | |
362 | ||
363 | memset(&tx_info, 0, sizeof(tx_info)); | |
364 | ||
c2b2ee36 | 365 | instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE]); |
2be665c3 HB |
366 | nla_memcpy(&tx_info.dmac.addr, |
367 | tb[IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC], | |
368 | sizeof(tx_info.dmac.addr)); | |
369 | tx_info.seq_no_update = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE]); | |
370 | tx_info.period = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD]); | |
371 | tx_info.if_tlv = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV]); | |
372 | tx_info.if_tlv_value = nla_get_u8(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE]); | |
373 | tx_info.port_tlv = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV]); | |
374 | tx_info.port_tlv_value = nla_get_u8(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE]); | |
375 | ||
376 | return br_cfm_cc_ccm_tx(br, instance, &tx_info, extack); | |
377 | } | |
378 | ||
379 | int br_cfm_parse(struct net_bridge *br, struct net_bridge_port *p, | |
380 | struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) | |
381 | { | |
382 | struct nlattr *tb[IFLA_BRIDGE_CFM_MAX + 1]; | |
383 | int err; | |
384 | ||
385 | /* When this function is called for a port then the br pointer is | |
386 | * invalid, therefor set the br to point correctly | |
387 | */ | |
388 | if (p) | |
389 | br = p->br; | |
390 | ||
391 | err = nla_parse_nested(tb, IFLA_BRIDGE_CFM_MAX, attr, | |
392 | br_cfm_policy, extack); | |
393 | if (err) | |
394 | return err; | |
395 | ||
396 | if (tb[IFLA_BRIDGE_CFM_MEP_CREATE]) { | |
397 | err = br_mep_create_parse(br, tb[IFLA_BRIDGE_CFM_MEP_CREATE], | |
398 | extack); | |
399 | if (err) | |
400 | return err; | |
401 | } | |
402 | ||
403 | if (tb[IFLA_BRIDGE_CFM_MEP_DELETE]) { | |
404 | err = br_mep_delete_parse(br, tb[IFLA_BRIDGE_CFM_MEP_DELETE], | |
405 | extack); | |
406 | if (err) | |
407 | return err; | |
408 | } | |
409 | ||
410 | if (tb[IFLA_BRIDGE_CFM_MEP_CONFIG]) { | |
411 | err = br_mep_config_parse(br, tb[IFLA_BRIDGE_CFM_MEP_CONFIG], | |
412 | extack); | |
413 | if (err) | |
414 | return err; | |
415 | } | |
416 | ||
417 | if (tb[IFLA_BRIDGE_CFM_CC_CONFIG]) { | |
418 | err = br_cc_config_parse(br, tb[IFLA_BRIDGE_CFM_CC_CONFIG], | |
419 | extack); | |
420 | if (err) | |
421 | return err; | |
422 | } | |
423 | ||
424 | if (tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD]) { | |
425 | err = br_cc_peer_mep_add_parse(br, tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD], | |
426 | extack); | |
427 | if (err) | |
428 | return err; | |
429 | } | |
430 | ||
431 | if (tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE]) { | |
432 | err = br_cc_peer_mep_remove_parse(br, tb[IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE], | |
433 | extack); | |
434 | if (err) | |
435 | return err; | |
436 | } | |
437 | ||
438 | if (tb[IFLA_BRIDGE_CFM_CC_RDI]) { | |
439 | err = br_cc_rdi_parse(br, tb[IFLA_BRIDGE_CFM_CC_RDI], | |
440 | extack); | |
441 | if (err) | |
442 | return err; | |
443 | } | |
444 | ||
445 | if (tb[IFLA_BRIDGE_CFM_CC_CCM_TX]) { | |
446 | err = br_cc_ccm_tx_parse(br, tb[IFLA_BRIDGE_CFM_CC_CCM_TX], | |
447 | extack); | |
448 | if (err) | |
449 | return err; | |
450 | } | |
451 | ||
452 | return 0; | |
453 | } | |
5e312fc0 HB |
454 | |
455 | int br_cfm_config_fill_info(struct sk_buff *skb, struct net_bridge *br) | |
456 | { | |
457 | struct br_cfm_peer_mep *peer_mep; | |
458 | struct br_cfm_mep *mep; | |
459 | struct nlattr *tb; | |
460 | ||
461 | hlist_for_each_entry_rcu(mep, &br->mep_list, head) { | |
462 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_MEP_CREATE_INFO); | |
463 | if (!tb) | |
464 | goto nla_info_failure; | |
465 | ||
466 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE, | |
467 | mep->instance)) | |
468 | goto nla_put_failure; | |
469 | ||
470 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN, | |
471 | mep->create.domain)) | |
472 | goto nla_put_failure; | |
473 | ||
474 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION, | |
475 | mep->create.direction)) | |
476 | goto nla_put_failure; | |
477 | ||
478 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX, | |
479 | mep->create.ifindex)) | |
480 | goto nla_put_failure; | |
481 | ||
482 | nla_nest_end(skb, tb); | |
483 | ||
484 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_MEP_CONFIG_INFO); | |
485 | ||
486 | if (!tb) | |
487 | goto nla_info_failure; | |
488 | ||
489 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE, | |
490 | mep->instance)) | |
491 | goto nla_put_failure; | |
492 | ||
493 | if (nla_put(skb, IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC, | |
494 | sizeof(mep->config.unicast_mac.addr), | |
495 | mep->config.unicast_mac.addr)) | |
496 | goto nla_put_failure; | |
497 | ||
498 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL, | |
499 | mep->config.mdlevel)) | |
500 | goto nla_put_failure; | |
501 | ||
502 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID, | |
503 | mep->config.mepid)) | |
504 | goto nla_put_failure; | |
505 | ||
506 | nla_nest_end(skb, tb); | |
507 | ||
508 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_CC_CONFIG_INFO); | |
509 | ||
510 | if (!tb) | |
511 | goto nla_info_failure; | |
512 | ||
513 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE, | |
514 | mep->instance)) | |
515 | goto nla_put_failure; | |
516 | ||
517 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE, | |
518 | mep->cc_config.enable)) | |
519 | goto nla_put_failure; | |
520 | ||
521 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL, | |
522 | mep->cc_config.exp_interval)) | |
523 | goto nla_put_failure; | |
524 | ||
525 | if (nla_put(skb, IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID, | |
526 | sizeof(mep->cc_config.exp_maid.data), | |
527 | mep->cc_config.exp_maid.data)) | |
528 | goto nla_put_failure; | |
529 | ||
530 | nla_nest_end(skb, tb); | |
531 | ||
532 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_CC_RDI_INFO); | |
533 | ||
534 | if (!tb) | |
535 | goto nla_info_failure; | |
536 | ||
537 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_RDI_INSTANCE, | |
538 | mep->instance)) | |
539 | goto nla_put_failure; | |
540 | ||
541 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_RDI_RDI, | |
542 | mep->rdi)) | |
543 | goto nla_put_failure; | |
544 | ||
545 | nla_nest_end(skb, tb); | |
546 | ||
547 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_INFO); | |
548 | ||
549 | if (!tb) | |
550 | goto nla_info_failure; | |
551 | ||
552 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE, | |
553 | mep->instance)) | |
554 | goto nla_put_failure; | |
555 | ||
556 | if (nla_put(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC, | |
557 | sizeof(mep->cc_ccm_tx_info.dmac), | |
558 | mep->cc_ccm_tx_info.dmac.addr)) | |
559 | goto nla_put_failure; | |
560 | ||
561 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE, | |
562 | mep->cc_ccm_tx_info.seq_no_update)) | |
563 | goto nla_put_failure; | |
564 | ||
565 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD, | |
566 | mep->cc_ccm_tx_info.period)) | |
567 | goto nla_put_failure; | |
568 | ||
569 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV, | |
570 | mep->cc_ccm_tx_info.if_tlv)) | |
571 | goto nla_put_failure; | |
572 | ||
573 | if (nla_put_u8(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE, | |
574 | mep->cc_ccm_tx_info.if_tlv_value)) | |
575 | goto nla_put_failure; | |
576 | ||
577 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV, | |
578 | mep->cc_ccm_tx_info.port_tlv)) | |
579 | goto nla_put_failure; | |
580 | ||
581 | if (nla_put_u8(skb, IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE, | |
582 | mep->cc_ccm_tx_info.port_tlv_value)) | |
583 | goto nla_put_failure; | |
584 | ||
585 | nla_nest_end(skb, tb); | |
586 | ||
587 | hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head) { | |
588 | tb = nla_nest_start(skb, | |
589 | IFLA_BRIDGE_CFM_CC_PEER_MEP_INFO); | |
590 | ||
591 | if (!tb) | |
592 | goto nla_info_failure; | |
593 | ||
594 | if (nla_put_u32(skb, | |
595 | IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE, | |
596 | mep->instance)) | |
597 | goto nla_put_failure; | |
598 | ||
599 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_PEER_MEPID, | |
600 | peer_mep->mepid)) | |
601 | goto nla_put_failure; | |
602 | ||
603 | nla_nest_end(skb, tb); | |
604 | } | |
605 | } | |
606 | ||
607 | return 0; | |
608 | ||
609 | nla_put_failure: | |
610 | nla_nest_cancel(skb, tb); | |
611 | ||
612 | nla_info_failure: | |
613 | return -EMSGSIZE; | |
614 | } | |
e77824d8 | 615 | |
b6d0425b HB |
616 | int br_cfm_status_fill_info(struct sk_buff *skb, |
617 | struct net_bridge *br, | |
618 | bool getlink) | |
e77824d8 HB |
619 | { |
620 | struct br_cfm_peer_mep *peer_mep; | |
621 | struct br_cfm_mep *mep; | |
622 | struct nlattr *tb; | |
623 | ||
624 | hlist_for_each_entry_rcu(mep, &br->mep_list, head) { | |
625 | tb = nla_nest_start(skb, IFLA_BRIDGE_CFM_MEP_STATUS_INFO); | |
626 | if (!tb) | |
627 | goto nla_info_failure; | |
628 | ||
629 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_MEP_STATUS_INSTANCE, | |
630 | mep->instance)) | |
631 | goto nla_put_failure; | |
632 | ||
633 | if (nla_put_u32(skb, | |
634 | IFLA_BRIDGE_CFM_MEP_STATUS_OPCODE_UNEXP_SEEN, | |
635 | mep->status.opcode_unexp_seen)) | |
636 | goto nla_put_failure; | |
637 | ||
638 | if (nla_put_u32(skb, | |
639 | IFLA_BRIDGE_CFM_MEP_STATUS_VERSION_UNEXP_SEEN, | |
640 | mep->status.version_unexp_seen)) | |
641 | goto nla_put_failure; | |
642 | ||
643 | if (nla_put_u32(skb, | |
644 | IFLA_BRIDGE_CFM_MEP_STATUS_RX_LEVEL_LOW_SEEN, | |
645 | mep->status.rx_level_low_seen)) | |
646 | goto nla_put_failure; | |
647 | ||
b6d0425b HB |
648 | /* Only clear if this is a GETLINK */ |
649 | if (getlink) { | |
650 | /* Clear all 'seen' indications */ | |
651 | mep->status.opcode_unexp_seen = false; | |
652 | mep->status.version_unexp_seen = false; | |
653 | mep->status.rx_level_low_seen = false; | |
654 | } | |
e77824d8 HB |
655 | |
656 | nla_nest_end(skb, tb); | |
657 | ||
658 | hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head) { | |
659 | tb = nla_nest_start(skb, | |
660 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_INFO); | |
661 | if (!tb) | |
662 | goto nla_info_failure; | |
663 | ||
664 | if (nla_put_u32(skb, | |
665 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_INSTANCE, | |
666 | mep->instance)) | |
667 | goto nla_put_failure; | |
668 | ||
669 | if (nla_put_u32(skb, | |
670 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_PEER_MEPID, | |
671 | peer_mep->mepid)) | |
672 | goto nla_put_failure; | |
673 | ||
674 | if (nla_put_u32(skb, | |
675 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_CCM_DEFECT, | |
676 | peer_mep->cc_status.ccm_defect)) | |
677 | goto nla_put_failure; | |
678 | ||
679 | if (nla_put_u32(skb, IFLA_BRIDGE_CFM_CC_PEER_STATUS_RDI, | |
680 | peer_mep->cc_status.rdi)) | |
681 | goto nla_put_failure; | |
682 | ||
683 | if (nla_put_u8(skb, | |
684 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_PORT_TLV_VALUE, | |
685 | peer_mep->cc_status.port_tlv_value)) | |
686 | goto nla_put_failure; | |
687 | ||
688 | if (nla_put_u8(skb, | |
689 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_IF_TLV_VALUE, | |
690 | peer_mep->cc_status.if_tlv_value)) | |
691 | goto nla_put_failure; | |
692 | ||
693 | if (nla_put_u32(skb, | |
694 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEEN, | |
695 | peer_mep->cc_status.seen)) | |
696 | goto nla_put_failure; | |
697 | ||
698 | if (nla_put_u32(skb, | |
699 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_TLV_SEEN, | |
700 | peer_mep->cc_status.tlv_seen)) | |
701 | goto nla_put_failure; | |
702 | ||
703 | if (nla_put_u32(skb, | |
704 | IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEQ_UNEXP_SEEN, | |
705 | peer_mep->cc_status.seq_unexp_seen)) | |
706 | goto nla_put_failure; | |
707 | ||
b6d0425b HB |
708 | if (getlink) { /* Only clear if this is a GETLINK */ |
709 | /* Clear all 'seen' indications */ | |
710 | peer_mep->cc_status.seen = false; | |
711 | peer_mep->cc_status.tlv_seen = false; | |
712 | peer_mep->cc_status.seq_unexp_seen = false; | |
713 | } | |
e77824d8 HB |
714 | |
715 | nla_nest_end(skb, tb); | |
716 | } | |
717 | } | |
718 | ||
719 | return 0; | |
720 | ||
721 | nla_put_failure: | |
722 | nla_nest_cancel(skb, tb); | |
723 | ||
724 | nla_info_failure: | |
725 | return -EMSGSIZE; | |
726 | } |