18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <net/genetlink.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <uapi/linux/mrp_bridge.h> 68c2ecf20Sopenharmony_ci#include "br_private.h" 78c2ecf20Sopenharmony_ci#include "br_private_mrp.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistatic const struct nla_policy br_mrp_policy[IFLA_BRIDGE_MRP_MAX + 1] = { 108c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_UNSPEC] = { .type = NLA_REJECT }, 118c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE] = { .type = NLA_NESTED }, 128c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE] = { .type = NLA_NESTED }, 138c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE] = { .type = NLA_NESTED }, 148c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE] = { .type = NLA_NESTED }, 158c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE] = { .type = NLA_NESTED }, 168c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST] = { .type = NLA_NESTED }, 178c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE] = { .type = NLA_NESTED }, 188c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE] = { .type = NLA_NESTED }, 198c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST] = { .type = NLA_NESTED }, 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const struct nla_policy 238c2ecf20Sopenharmony_cibr_mrp_instance_policy[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1] = { 248c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_UNSPEC] = { .type = NLA_REJECT }, 258c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_RING_ID] = { .type = NLA_U32 }, 268c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] = { .type = NLA_U32 }, 278c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX] = { .type = NLA_U32 }, 288c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_INSTANCE_PRIO] = { .type = NLA_U16 }, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int br_mrp_instance_parse(struct net_bridge *br, struct nlattr *attr, 328c2ecf20Sopenharmony_ci int cmd, struct netlink_ext_ack *extack) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_INSTANCE_MAX + 1]; 358c2ecf20Sopenharmony_ci struct br_mrp_instance inst; 368c2ecf20Sopenharmony_ci int err; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_INSTANCE_MAX, attr, 398c2ecf20Sopenharmony_ci br_mrp_instance_policy, extack); 408c2ecf20Sopenharmony_ci if (err) 418c2ecf20Sopenharmony_ci return err; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID] || 448c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX] || 458c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]) { 468c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 478c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or P_IFINDEX or S_IFINDEX"); 488c2ecf20Sopenharmony_ci return -EINVAL; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci memset(&inst, 0, sizeof(inst)); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci inst.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_RING_ID]); 548c2ecf20Sopenharmony_ci inst.p_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX]); 558c2ecf20Sopenharmony_ci inst.s_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX]); 568c2ecf20Sopenharmony_ci inst.prio = MRP_DEFAULT_PRIO; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]) 598c2ecf20Sopenharmony_ci inst.prio = nla_get_u16(tb[IFLA_BRIDGE_MRP_INSTANCE_PRIO]); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (cmd == RTM_SETLINK) 628c2ecf20Sopenharmony_ci return br_mrp_add(br, &inst); 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci return br_mrp_del(br, &inst); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const struct nla_policy 708c2ecf20Sopenharmony_cibr_mrp_port_state_policy[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1] = { 718c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC] = { .type = NLA_REJECT }, 728c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_STATE_STATE] = { .type = NLA_U32 }, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int br_mrp_port_state_parse(struct net_bridge_port *p, 768c2ecf20Sopenharmony_ci struct nlattr *attr, 778c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_STATE_MAX + 1]; 808c2ecf20Sopenharmony_ci enum br_mrp_port_state_type state; 818c2ecf20Sopenharmony_ci int err; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_STATE_MAX, attr, 848c2ecf20Sopenharmony_ci br_mrp_port_state_policy, extack); 858c2ecf20Sopenharmony_ci if (err) 868c2ecf20Sopenharmony_ci return err; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]) { 898c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Missing attribute: STATE"); 908c2ecf20Sopenharmony_ci return -EINVAL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci state = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_STATE_STATE]); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return br_mrp_set_port_state(p, state); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct nla_policy 998c2ecf20Sopenharmony_cibr_mrp_port_role_policy[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1] = { 1008c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC] = { .type = NLA_REJECT }, 1018c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_PORT_ROLE_ROLE] = { .type = NLA_U32 }, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int br_mrp_port_role_parse(struct net_bridge_port *p, 1058c2ecf20Sopenharmony_ci struct nlattr *attr, 1068c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_PORT_ROLE_MAX + 1]; 1098c2ecf20Sopenharmony_ci enum br_mrp_port_role_type role; 1108c2ecf20Sopenharmony_ci int err; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_PORT_ROLE_MAX, attr, 1138c2ecf20Sopenharmony_ci br_mrp_port_role_policy, extack); 1148c2ecf20Sopenharmony_ci if (err) 1158c2ecf20Sopenharmony_ci return err; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]) { 1188c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Missing attribute: ROLE"); 1198c2ecf20Sopenharmony_ci return -EINVAL; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci role = nla_get_u32(tb[IFLA_BRIDGE_MRP_PORT_ROLE_ROLE]); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return br_mrp_set_port_role(p, role); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic const struct nla_policy 1288c2ecf20Sopenharmony_cibr_mrp_ring_state_policy[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1] = { 1298c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_UNSPEC] = { .type = NLA_REJECT }, 1308c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_RING_ID] = { .type = NLA_U32 }, 1318c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_STATE_STATE] = { .type = NLA_U32 }, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int br_mrp_ring_state_parse(struct net_bridge *br, struct nlattr *attr, 1358c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_RING_STATE_MAX + 1]; 1388c2ecf20Sopenharmony_ci struct br_mrp_ring_state state; 1398c2ecf20Sopenharmony_ci int err; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_STATE_MAX, attr, 1428c2ecf20Sopenharmony_ci br_mrp_ring_state_policy, extack); 1438c2ecf20Sopenharmony_ci if (err) 1448c2ecf20Sopenharmony_ci return err; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID] || 1478c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]) { 1488c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 1498c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or STATE"); 1508c2ecf20Sopenharmony_ci return -EINVAL; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci memset(&state, 0x0, sizeof(state)); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci state.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_RING_ID]); 1568c2ecf20Sopenharmony_ci state.ring_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_STATE_STATE]); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return br_mrp_set_ring_state(br, &state); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const struct nla_policy 1628c2ecf20Sopenharmony_cibr_mrp_ring_role_policy[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1] = { 1638c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC] = { .type = NLA_REJECT }, 1648c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] = { .type = NLA_U32 }, 1658c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_RING_ROLE_ROLE] = { .type = NLA_U32 }, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int br_mrp_ring_role_parse(struct net_bridge *br, struct nlattr *attr, 1698c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_RING_ROLE_MAX + 1]; 1728c2ecf20Sopenharmony_ci struct br_mrp_ring_role role; 1738c2ecf20Sopenharmony_ci int err; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_RING_ROLE_MAX, attr, 1768c2ecf20Sopenharmony_ci br_mrp_ring_role_policy, extack); 1778c2ecf20Sopenharmony_ci if (err) 1788c2ecf20Sopenharmony_ci return err; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID] || 1818c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]) { 1828c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 1838c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or ROLE"); 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci memset(&role, 0x0, sizeof(role)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_RING_ID]); 1908c2ecf20Sopenharmony_ci role.ring_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_RING_ROLE_ROLE]); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return br_mrp_set_ring_role(br, &role); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct nla_policy 1968c2ecf20Sopenharmony_cibr_mrp_start_test_policy[IFLA_BRIDGE_MRP_START_TEST_MAX + 1] = { 1978c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_UNSPEC] = { .type = NLA_REJECT }, 1988c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_RING_ID] = { .type = NLA_U32 }, 1998c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_INTERVAL] = { .type = NLA_U32 }, 2008c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] = { .type = NLA_U32 }, 2018c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_PERIOD] = { .type = NLA_U32 }, 2028c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_TEST_MONITOR] = { .type = NLA_U32 }, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int br_mrp_start_test_parse(struct net_bridge *br, struct nlattr *attr, 2068c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_START_TEST_MAX + 1]; 2098c2ecf20Sopenharmony_ci struct br_mrp_start_test test; 2108c2ecf20Sopenharmony_ci int err; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_TEST_MAX, attr, 2138c2ecf20Sopenharmony_ci br_mrp_start_test_policy, extack); 2148c2ecf20Sopenharmony_ci if (err) 2158c2ecf20Sopenharmony_ci return err; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID] || 2188c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL] || 2198c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS] || 2208c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]) { 2218c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 2228c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD"); 2238c2ecf20Sopenharmony_ci return -EINVAL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci memset(&test, 0x0, sizeof(test)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci test.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_RING_ID]); 2298c2ecf20Sopenharmony_ci test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_INTERVAL]); 2308c2ecf20Sopenharmony_ci test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MAX_MISS]); 2318c2ecf20Sopenharmony_ci test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_PERIOD]); 2328c2ecf20Sopenharmony_ci test.monitor = false; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]) 2358c2ecf20Sopenharmony_ci test.monitor = 2368c2ecf20Sopenharmony_ci nla_get_u32(tb[IFLA_BRIDGE_MRP_START_TEST_MONITOR]); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return br_mrp_start_test(br, &test); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic const struct nla_policy 2428c2ecf20Sopenharmony_cibr_mrp_in_state_policy[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1] = { 2438c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_UNSPEC] = { .type = NLA_REJECT }, 2448c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_IN_ID] = { .type = NLA_U32 }, 2458c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_STATE_STATE] = { .type = NLA_U32 }, 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int br_mrp_in_state_parse(struct net_bridge *br, struct nlattr *attr, 2498c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_IN_STATE_MAX + 1]; 2528c2ecf20Sopenharmony_ci struct br_mrp_in_state state; 2538c2ecf20Sopenharmony_ci int err; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_STATE_MAX, attr, 2568c2ecf20Sopenharmony_ci br_mrp_in_state_policy, extack); 2578c2ecf20Sopenharmony_ci if (err) 2588c2ecf20Sopenharmony_ci return err; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID] || 2618c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]) { 2628c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 2638c2ecf20Sopenharmony_ci "Missing attribute: IN_ID or STATE"); 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci memset(&state, 0x0, sizeof(state)); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci state.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_IN_ID]); 2708c2ecf20Sopenharmony_ci state.in_state = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_STATE_STATE]); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return br_mrp_set_in_state(br, &state); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic const struct nla_policy 2768c2ecf20Sopenharmony_cibr_mrp_in_role_policy[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1] = { 2778c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC] = { .type = NLA_REJECT }, 2788c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] = { .type = NLA_U32 }, 2798c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] = { .type = NLA_U16 }, 2808c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_ROLE] = { .type = NLA_U32 }, 2818c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] = { .type = NLA_U32 }, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int br_mrp_in_role_parse(struct net_bridge *br, struct nlattr *attr, 2858c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_IN_ROLE_MAX + 1]; 2888c2ecf20Sopenharmony_ci struct br_mrp_in_role role; 2898c2ecf20Sopenharmony_ci int err; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_IN_ROLE_MAX, attr, 2928c2ecf20Sopenharmony_ci br_mrp_in_role_policy, extack); 2938c2ecf20Sopenharmony_ci if (err) 2948c2ecf20Sopenharmony_ci return err; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID] || 2978c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID] || 2988c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX] || 2998c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]) { 3008c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 3018c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or ROLE or IN_ID or I_IFINDEX"); 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci memset(&role, 0x0, sizeof(role)); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci role.ring_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_RING_ID]); 3088c2ecf20Sopenharmony_ci role.in_id = nla_get_u16(tb[IFLA_BRIDGE_MRP_IN_ROLE_IN_ID]); 3098c2ecf20Sopenharmony_ci role.i_ifindex = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX]); 3108c2ecf20Sopenharmony_ci role.in_role = nla_get_u32(tb[IFLA_BRIDGE_MRP_IN_ROLE_ROLE]); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return br_mrp_set_in_role(br, &role); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct nla_policy 3168c2ecf20Sopenharmony_cibr_mrp_start_in_test_policy[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1] = { 3178c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC] = { .type = NLA_REJECT }, 3188c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] = { .type = NLA_U32 }, 3198c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] = { .type = NLA_U32 }, 3208c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] = { .type = NLA_U32 }, 3218c2ecf20Sopenharmony_ci [IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD] = { .type = NLA_U32 }, 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int br_mrp_start_in_test_parse(struct net_bridge *br, 3258c2ecf20Sopenharmony_ci struct nlattr *attr, 3268c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX + 1]; 3298c2ecf20Sopenharmony_ci struct br_mrp_start_in_test test; 3308c2ecf20Sopenharmony_ci int err; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_START_IN_TEST_MAX, attr, 3338c2ecf20Sopenharmony_ci br_mrp_start_in_test_policy, extack); 3348c2ecf20Sopenharmony_ci if (err) 3358c2ecf20Sopenharmony_ci return err; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID] || 3388c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL] || 3398c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS] || 3408c2ecf20Sopenharmony_ci !tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]) { 3418c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 3428c2ecf20Sopenharmony_ci "Missing attribute: RING_ID or INTERVAL or MAX_MISS or PERIOD"); 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci memset(&test, 0x0, sizeof(test)); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci test.in_id = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID]); 3498c2ecf20Sopenharmony_ci test.interval = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL]); 3508c2ecf20Sopenharmony_ci test.max_miss = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS]); 3518c2ecf20Sopenharmony_ci test.period = nla_get_u32(tb[IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD]); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return br_mrp_start_in_test(br, &test); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciint br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, 3578c2ecf20Sopenharmony_ci struct nlattr *attr, int cmd, struct netlink_ext_ack *extack) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_BRIDGE_MRP_MAX + 1]; 3608c2ecf20Sopenharmony_ci int err; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* When this function is called for a port then the br pointer is 3638c2ecf20Sopenharmony_ci * invalid, therefor set the br to point correctly 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci if (p) 3668c2ecf20Sopenharmony_ci br = p->br; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (br->stp_enabled != BR_NO_STP) { 3698c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "MRP can't be enabled if STP is already enabled"); 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci err = nla_parse_nested(tb, IFLA_BRIDGE_MRP_MAX, attr, 3748c2ecf20Sopenharmony_ci br_mrp_policy, extack); 3758c2ecf20Sopenharmony_ci if (err) 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_INSTANCE]) { 3798c2ecf20Sopenharmony_ci err = br_mrp_instance_parse(br, tb[IFLA_BRIDGE_MRP_INSTANCE], 3808c2ecf20Sopenharmony_ci cmd, extack); 3818c2ecf20Sopenharmony_ci if (err) 3828c2ecf20Sopenharmony_ci return err; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_PORT_STATE]) { 3868c2ecf20Sopenharmony_ci err = br_mrp_port_state_parse(p, tb[IFLA_BRIDGE_MRP_PORT_STATE], 3878c2ecf20Sopenharmony_ci extack); 3888c2ecf20Sopenharmony_ci if (err) 3898c2ecf20Sopenharmony_ci return err; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_PORT_ROLE]) { 3938c2ecf20Sopenharmony_ci err = br_mrp_port_role_parse(p, tb[IFLA_BRIDGE_MRP_PORT_ROLE], 3948c2ecf20Sopenharmony_ci extack); 3958c2ecf20Sopenharmony_ci if (err) 3968c2ecf20Sopenharmony_ci return err; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_RING_STATE]) { 4008c2ecf20Sopenharmony_ci err = br_mrp_ring_state_parse(br, 4018c2ecf20Sopenharmony_ci tb[IFLA_BRIDGE_MRP_RING_STATE], 4028c2ecf20Sopenharmony_ci extack); 4038c2ecf20Sopenharmony_ci if (err) 4048c2ecf20Sopenharmony_ci return err; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_RING_ROLE]) { 4088c2ecf20Sopenharmony_ci err = br_mrp_ring_role_parse(br, tb[IFLA_BRIDGE_MRP_RING_ROLE], 4098c2ecf20Sopenharmony_ci extack); 4108c2ecf20Sopenharmony_ci if (err) 4118c2ecf20Sopenharmony_ci return err; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_TEST]) { 4158c2ecf20Sopenharmony_ci err = br_mrp_start_test_parse(br, 4168c2ecf20Sopenharmony_ci tb[IFLA_BRIDGE_MRP_START_TEST], 4178c2ecf20Sopenharmony_ci extack); 4188c2ecf20Sopenharmony_ci if (err) 4198c2ecf20Sopenharmony_ci return err; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_IN_STATE]) { 4238c2ecf20Sopenharmony_ci err = br_mrp_in_state_parse(br, tb[IFLA_BRIDGE_MRP_IN_STATE], 4248c2ecf20Sopenharmony_ci extack); 4258c2ecf20Sopenharmony_ci if (err) 4268c2ecf20Sopenharmony_ci return err; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_IN_ROLE]) { 4308c2ecf20Sopenharmony_ci err = br_mrp_in_role_parse(br, tb[IFLA_BRIDGE_MRP_IN_ROLE], 4318c2ecf20Sopenharmony_ci extack); 4328c2ecf20Sopenharmony_ci if (err) 4338c2ecf20Sopenharmony_ci return err; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (tb[IFLA_BRIDGE_MRP_START_IN_TEST]) { 4378c2ecf20Sopenharmony_ci err = br_mrp_start_in_test_parse(br, 4388c2ecf20Sopenharmony_ci tb[IFLA_BRIDGE_MRP_START_IN_TEST], 4398c2ecf20Sopenharmony_ci extack); 4408c2ecf20Sopenharmony_ci if (err) 4418c2ecf20Sopenharmony_ci return err; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ciint br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct nlattr *tb, *mrp_tb; 4508c2ecf20Sopenharmony_ci struct br_mrp *mrp; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci mrp_tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); 4538c2ecf20Sopenharmony_ci if (!mrp_tb) 4548c2ecf20Sopenharmony_ci return -EMSGSIZE; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci list_for_each_entry_rcu(mrp, &br->mrp_list, list) { 4578c2ecf20Sopenharmony_ci struct net_bridge_port *p; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci tb = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP_INFO); 4608c2ecf20Sopenharmony_ci if (!tb) 4618c2ecf20Sopenharmony_ci goto nla_info_failure; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ID, 4648c2ecf20Sopenharmony_ci mrp->ring_id)) 4658c2ecf20Sopenharmony_ci goto nla_put_failure; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci p = rcu_dereference(mrp->p_port); 4688c2ecf20Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_P_IFINDEX, 4698c2ecf20Sopenharmony_ci p->dev->ifindex)) 4708c2ecf20Sopenharmony_ci goto nla_put_failure; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci p = rcu_dereference(mrp->s_port); 4738c2ecf20Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_S_IFINDEX, 4748c2ecf20Sopenharmony_ci p->dev->ifindex)) 4758c2ecf20Sopenharmony_ci goto nla_put_failure; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci p = rcu_dereference(mrp->i_port); 4788c2ecf20Sopenharmony_ci if (p && nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_I_IFINDEX, 4798c2ecf20Sopenharmony_ci p->dev->ifindex)) 4808c2ecf20Sopenharmony_ci goto nla_put_failure; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (nla_put_u16(skb, IFLA_BRIDGE_MRP_INFO_PRIO, 4838c2ecf20Sopenharmony_ci mrp->prio)) 4848c2ecf20Sopenharmony_ci goto nla_put_failure; 4858c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_STATE, 4868c2ecf20Sopenharmony_ci mrp->ring_state)) 4878c2ecf20Sopenharmony_ci goto nla_put_failure; 4888c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_RING_ROLE, 4898c2ecf20Sopenharmony_ci mrp->ring_role)) 4908c2ecf20Sopenharmony_ci goto nla_put_failure; 4918c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL, 4928c2ecf20Sopenharmony_ci mrp->test_interval)) 4938c2ecf20Sopenharmony_ci goto nla_put_failure; 4948c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS, 4958c2ecf20Sopenharmony_ci mrp->test_max_miss)) 4968c2ecf20Sopenharmony_ci goto nla_put_failure; 4978c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_TEST_MONITOR, 4988c2ecf20Sopenharmony_ci mrp->test_monitor)) 4998c2ecf20Sopenharmony_ci goto nla_put_failure; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_STATE, 5028c2ecf20Sopenharmony_ci mrp->in_state)) 5038c2ecf20Sopenharmony_ci goto nla_put_failure; 5048c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_ROLE, 5058c2ecf20Sopenharmony_ci mrp->in_role)) 5068c2ecf20Sopenharmony_ci goto nla_put_failure; 5078c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL, 5088c2ecf20Sopenharmony_ci mrp->in_test_interval)) 5098c2ecf20Sopenharmony_ci goto nla_put_failure; 5108c2ecf20Sopenharmony_ci if (nla_put_u32(skb, IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS, 5118c2ecf20Sopenharmony_ci mrp->in_test_max_miss)) 5128c2ecf20Sopenharmony_ci goto nla_put_failure; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci nla_nest_end(skb, tb); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci nla_nest_end(skb, mrp_tb); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cinla_put_failure: 5218c2ecf20Sopenharmony_ci nla_nest_cancel(skb, tb); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cinla_info_failure: 5248c2ecf20Sopenharmony_ci nla_nest_cancel(skb, mrp_tb); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return -EMSGSIZE; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ciint br_mrp_ring_port_open(struct net_device *dev, u8 loc) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct net_bridge_port *p; 5328c2ecf20Sopenharmony_ci int err = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci p = br_port_get_rcu(dev); 5358c2ecf20Sopenharmony_ci if (!p) { 5368c2ecf20Sopenharmony_ci err = -EINVAL; 5378c2ecf20Sopenharmony_ci goto out; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (loc) 5418c2ecf20Sopenharmony_ci p->flags |= BR_MRP_LOST_CONT; 5428c2ecf20Sopenharmony_ci else 5438c2ecf20Sopenharmony_ci p->flags &= ~BR_MRP_LOST_CONT; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ciout: 5488c2ecf20Sopenharmony_ci return err; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciint br_mrp_in_port_open(struct net_device *dev, u8 loc) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct net_bridge_port *p; 5548c2ecf20Sopenharmony_ci int err = 0; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci p = br_port_get_rcu(dev); 5578c2ecf20Sopenharmony_ci if (!p) { 5588c2ecf20Sopenharmony_ci err = -EINVAL; 5598c2ecf20Sopenharmony_ci goto out; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (loc) 5638c2ecf20Sopenharmony_ci p->flags |= BR_MRP_LOST_IN_CONT; 5648c2ecf20Sopenharmony_ci else 5658c2ecf20Sopenharmony_ci p->flags &= ~BR_MRP_LOST_IN_CONT; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ciout: 5708c2ecf20Sopenharmony_ci return err; 5718c2ecf20Sopenharmony_ci} 572