linux/net/bridge/br_cfm_netlink.c
<<
>>
Prefs
   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_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
 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}
 727