Merge tag 'mmc-v5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[platform/kernel/linux-rpi.git] / net / bridge / br_cfm_netlink.c
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 }