xref: /openbmc/linux/net/bridge/br_cfm_netlink.c (revision 0ad53fe3)
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 
365 	instance = nla_get_u32(tb[IFLA_BRIDGE_CFM_CC_RDI_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 
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 
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 
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