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
br_mep_create_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_mep_delete_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_mep_config_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_cc_config_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_cc_peer_mep_add_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_cc_peer_mep_remove_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_cc_rdi_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
br_cc_ccm_tx_parse(struct net_bridge * br,struct nlattr * attr,struct netlink_ext_ack * extack)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
365 instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE]);
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
br_cfm_parse(struct net_bridge * br,struct net_bridge_port * p,struct nlattr * attr,int cmd,struct netlink_ext_ack * extack)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 }
454
br_cfm_config_fill_info(struct sk_buff * skb,struct net_bridge * br)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 }
615
br_cfm_status_fill_info(struct sk_buff * skb,struct net_bridge * br,bool getlink)616 int br_cfm_status_fill_info(struct sk_buff *skb,
617 struct net_bridge *br,
618 bool getlink)
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
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 }
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
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 }
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 }
727