Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
  8static const struct nla_policy
  9br_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
 17static const struct nla_policy
 18br_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
 23static const struct nla_policy
 24br_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
 32static const struct nla_policy
 33br_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
 42static const struct nla_policy
 43br_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
 49static const struct nla_policy
 50br_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
 56static const struct nla_policy
 57br_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
 69static const struct nla_policy
 70br_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
 90static 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
130static 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
153static 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
195static 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
236static 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
263static 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
290static 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
317static 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
379int 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
455int 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
609nla_put_failure:
610	nla_nest_cancel(skb, tb);
611
612nla_info_failure:
613	return -EMSGSIZE;
614}
615
616int 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
721nla_put_failure:
722	nla_nest_cancel(skb, tb);
723
724nla_info_failure:
725	return -EMSGSIZE;
726}