162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/net/bond/bond_netlink.c - Netlink interface for bonding
462306a36Sopenharmony_ci * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
562306a36Sopenharmony_ci * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/netdevice.h>
1162306a36Sopenharmony_ci#include <linux/etherdevice.h>
1262306a36Sopenharmony_ci#include <linux/if_link.h>
1362306a36Sopenharmony_ci#include <linux/if_ether.h>
1462306a36Sopenharmony_ci#include <net/netlink.h>
1562306a36Sopenharmony_ci#include <net/rtnetlink.h>
1662306a36Sopenharmony_ci#include <net/bonding.h>
1762306a36Sopenharmony_ci#include <net/ipv6.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic size_t bond_get_slave_size(const struct net_device *bond_dev,
2062306a36Sopenharmony_ci				  const struct net_device *slave_dev)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	return nla_total_size(sizeof(u8)) +	/* IFLA_BOND_SLAVE_STATE */
2362306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_SLAVE_MII_STATUS */
2462306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_SLAVE_LINK_FAILURE_COUNT */
2562306a36Sopenharmony_ci		nla_total_size(MAX_ADDR_LEN) +	/* IFLA_BOND_SLAVE_PERM_HWADDR */
2662306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) +	/* IFLA_BOND_SLAVE_QUEUE_ID */
2762306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) +	/* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */
2862306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */
2962306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) +	/* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */
3062306a36Sopenharmony_ci		nla_total_size(sizeof(s32)) +	/* IFLA_BOND_SLAVE_PRIO */
3162306a36Sopenharmony_ci		0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int bond_fill_slave_info(struct sk_buff *skb,
3562306a36Sopenharmony_ci				const struct net_device *bond_dev,
3662306a36Sopenharmony_ci				const struct net_device *slave_dev)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct slave *slave = bond_slave_get_rtnl(slave_dev);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_SLAVE_STATE, bond_slave_state(slave)))
4162306a36Sopenharmony_ci		goto nla_put_failure;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_SLAVE_MII_STATUS, slave->link))
4462306a36Sopenharmony_ci		goto nla_put_failure;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_SLAVE_LINK_FAILURE_COUNT,
4762306a36Sopenharmony_ci			slave->link_failure_count))
4862306a36Sopenharmony_ci		goto nla_put_failure;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (nla_put(skb, IFLA_BOND_SLAVE_PERM_HWADDR,
5162306a36Sopenharmony_ci		    slave_dev->addr_len, slave->perm_hwaddr))
5262306a36Sopenharmony_ci		goto nla_put_failure;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (nla_put_u16(skb, IFLA_BOND_SLAVE_QUEUE_ID, slave->queue_id))
5562306a36Sopenharmony_ci		goto nla_put_failure;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (nla_put_s32(skb, IFLA_BOND_SLAVE_PRIO, slave->prio))
5862306a36Sopenharmony_ci		goto nla_put_failure;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
6162306a36Sopenharmony_ci		const struct aggregator *agg;
6262306a36Sopenharmony_ci		const struct port *ad_port;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		ad_port = &SLAVE_AD_INFO(slave)->port;
6562306a36Sopenharmony_ci		agg = SLAVE_AD_INFO(slave)->port.aggregator;
6662306a36Sopenharmony_ci		if (agg) {
6762306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
6862306a36Sopenharmony_ci					agg->aggregator_identifier))
6962306a36Sopenharmony_ci				goto nla_put_failure;
7062306a36Sopenharmony_ci			if (nla_put_u8(skb,
7162306a36Sopenharmony_ci				       IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
7262306a36Sopenharmony_ci				       ad_port->actor_oper_port_state))
7362306a36Sopenharmony_ci				goto nla_put_failure;
7462306a36Sopenharmony_ci			if (nla_put_u16(skb,
7562306a36Sopenharmony_ci					IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
7662306a36Sopenharmony_ci					ad_port->partner_oper.port_state))
7762306a36Sopenharmony_ci				goto nla_put_failure;
7862306a36Sopenharmony_ci		}
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cinla_put_failure:
8462306a36Sopenharmony_ci	return -EMSGSIZE;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Limit the max delay range to 300s */
8862306a36Sopenharmony_cistatic struct netlink_range_validation delay_range = {
8962306a36Sopenharmony_ci	.max = 300000,
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
9362306a36Sopenharmony_ci	[IFLA_BOND_MODE]		= { .type = NLA_U8 },
9462306a36Sopenharmony_ci	[IFLA_BOND_ACTIVE_SLAVE]	= { .type = NLA_U32 },
9562306a36Sopenharmony_ci	[IFLA_BOND_MIIMON]		= { .type = NLA_U32 },
9662306a36Sopenharmony_ci	[IFLA_BOND_UPDELAY]		= { .type = NLA_U32 },
9762306a36Sopenharmony_ci	[IFLA_BOND_DOWNDELAY]		= { .type = NLA_U32 },
9862306a36Sopenharmony_ci	[IFLA_BOND_USE_CARRIER]		= { .type = NLA_U8 },
9962306a36Sopenharmony_ci	[IFLA_BOND_ARP_INTERVAL]	= { .type = NLA_U32 },
10062306a36Sopenharmony_ci	[IFLA_BOND_ARP_IP_TARGET]	= { .type = NLA_NESTED },
10162306a36Sopenharmony_ci	[IFLA_BOND_ARP_VALIDATE]	= { .type = NLA_U32 },
10262306a36Sopenharmony_ci	[IFLA_BOND_ARP_ALL_TARGETS]	= { .type = NLA_U32 },
10362306a36Sopenharmony_ci	[IFLA_BOND_PRIMARY]		= { .type = NLA_U32 },
10462306a36Sopenharmony_ci	[IFLA_BOND_PRIMARY_RESELECT]	= { .type = NLA_U8 },
10562306a36Sopenharmony_ci	[IFLA_BOND_FAIL_OVER_MAC]	= { .type = NLA_U8 },
10662306a36Sopenharmony_ci	[IFLA_BOND_XMIT_HASH_POLICY]	= { .type = NLA_U8 },
10762306a36Sopenharmony_ci	[IFLA_BOND_RESEND_IGMP]		= { .type = NLA_U32 },
10862306a36Sopenharmony_ci	[IFLA_BOND_NUM_PEER_NOTIF]	= { .type = NLA_U8 },
10962306a36Sopenharmony_ci	[IFLA_BOND_ALL_SLAVES_ACTIVE]	= { .type = NLA_U8 },
11062306a36Sopenharmony_ci	[IFLA_BOND_MIN_LINKS]		= { .type = NLA_U32 },
11162306a36Sopenharmony_ci	[IFLA_BOND_LP_INTERVAL]		= { .type = NLA_U32 },
11262306a36Sopenharmony_ci	[IFLA_BOND_PACKETS_PER_SLAVE]	= { .type = NLA_U32 },
11362306a36Sopenharmony_ci	[IFLA_BOND_AD_LACP_ACTIVE]	= { .type = NLA_U8 },
11462306a36Sopenharmony_ci	[IFLA_BOND_AD_LACP_RATE]	= { .type = NLA_U8 },
11562306a36Sopenharmony_ci	[IFLA_BOND_AD_SELECT]		= { .type = NLA_U8 },
11662306a36Sopenharmony_ci	[IFLA_BOND_AD_INFO]		= { .type = NLA_NESTED },
11762306a36Sopenharmony_ci	[IFLA_BOND_AD_ACTOR_SYS_PRIO]	= { .type = NLA_U16 },
11862306a36Sopenharmony_ci	[IFLA_BOND_AD_USER_PORT_KEY]	= { .type = NLA_U16 },
11962306a36Sopenharmony_ci	[IFLA_BOND_AD_ACTOR_SYSTEM]	= { .type = NLA_BINARY,
12062306a36Sopenharmony_ci					    .len  = ETH_ALEN },
12162306a36Sopenharmony_ci	[IFLA_BOND_TLB_DYNAMIC_LB]	= { .type = NLA_U8 },
12262306a36Sopenharmony_ci	[IFLA_BOND_PEER_NOTIF_DELAY]    = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range),
12362306a36Sopenharmony_ci	[IFLA_BOND_MISSED_MAX]		= { .type = NLA_U8 },
12462306a36Sopenharmony_ci	[IFLA_BOND_NS_IP6_TARGET]	= { .type = NLA_NESTED },
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
12862306a36Sopenharmony_ci	[IFLA_BOND_SLAVE_QUEUE_ID]	= { .type = NLA_U16 },
12962306a36Sopenharmony_ci	[IFLA_BOND_SLAVE_PRIO]		= { .type = NLA_S32 },
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int bond_validate(struct nlattr *tb[], struct nlattr *data[],
13362306a36Sopenharmony_ci			 struct netlink_ext_ack *extack)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	if (tb[IFLA_ADDRESS]) {
13662306a36Sopenharmony_ci		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
13762306a36Sopenharmony_ci			return -EINVAL;
13862306a36Sopenharmony_ci		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
13962306a36Sopenharmony_ci			return -EADDRNOTAVAIL;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	return 0;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int bond_slave_changelink(struct net_device *bond_dev,
14562306a36Sopenharmony_ci				 struct net_device *slave_dev,
14662306a36Sopenharmony_ci				 struct nlattr *tb[], struct nlattr *data[],
14762306a36Sopenharmony_ci				 struct netlink_ext_ack *extack)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct bonding *bond = netdev_priv(bond_dev);
15062306a36Sopenharmony_ci	struct bond_opt_value newval;
15162306a36Sopenharmony_ci	int err;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (!data)
15462306a36Sopenharmony_ci		return 0;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (data[IFLA_BOND_SLAVE_QUEUE_ID]) {
15762306a36Sopenharmony_ci		u16 queue_id = nla_get_u16(data[IFLA_BOND_SLAVE_QUEUE_ID]);
15862306a36Sopenharmony_ci		char queue_id_str[IFNAMSIZ + 7];
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		/* queue_id option setting expects slave_name:queue_id */
16162306a36Sopenharmony_ci		snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n",
16262306a36Sopenharmony_ci			 slave_dev->name, queue_id);
16362306a36Sopenharmony_ci		bond_opt_initstr(&newval, queue_id_str);
16462306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval,
16562306a36Sopenharmony_ci				     data[IFLA_BOND_SLAVE_QUEUE_ID], extack);
16662306a36Sopenharmony_ci		if (err)
16762306a36Sopenharmony_ci			return err;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (data[IFLA_BOND_SLAVE_PRIO]) {
17162306a36Sopenharmony_ci		int prio = nla_get_s32(data[IFLA_BOND_SLAVE_PRIO]);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		bond_opt_slave_initval(&newval, &slave_dev, prio);
17462306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_PRIO, &newval,
17562306a36Sopenharmony_ci				     data[IFLA_BOND_SLAVE_PRIO], extack);
17662306a36Sopenharmony_ci		if (err)
17762306a36Sopenharmony_ci			return err;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
18462306a36Sopenharmony_ci			   struct nlattr *data[],
18562306a36Sopenharmony_ci			   struct netlink_ext_ack *extack)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct bonding *bond = netdev_priv(bond_dev);
18862306a36Sopenharmony_ci	struct bond_opt_value newval;
18962306a36Sopenharmony_ci	int miimon = 0;
19062306a36Sopenharmony_ci	int err;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!data)
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (data[IFLA_BOND_MODE]) {
19662306a36Sopenharmony_ci		int mode = nla_get_u8(data[IFLA_BOND_MODE]);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		bond_opt_initval(&newval, mode);
19962306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_MODE, &newval,
20062306a36Sopenharmony_ci				     data[IFLA_BOND_MODE], extack);
20162306a36Sopenharmony_ci		if (err)
20262306a36Sopenharmony_ci			return err;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci	if (data[IFLA_BOND_ACTIVE_SLAVE]) {
20562306a36Sopenharmony_ci		int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
20662306a36Sopenharmony_ci		struct net_device *slave_dev;
20762306a36Sopenharmony_ci		char *active_slave = "";
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		if (ifindex != 0) {
21062306a36Sopenharmony_ci			slave_dev = __dev_get_by_index(dev_net(bond_dev),
21162306a36Sopenharmony_ci						       ifindex);
21262306a36Sopenharmony_ci			if (!slave_dev)
21362306a36Sopenharmony_ci				return -ENODEV;
21462306a36Sopenharmony_ci			active_slave = slave_dev->name;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci		bond_opt_initstr(&newval, active_slave);
21762306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval,
21862306a36Sopenharmony_ci				     data[IFLA_BOND_ACTIVE_SLAVE], extack);
21962306a36Sopenharmony_ci		if (err)
22062306a36Sopenharmony_ci			return err;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci	if (data[IFLA_BOND_MIIMON]) {
22362306a36Sopenharmony_ci		miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		bond_opt_initval(&newval, miimon);
22662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval,
22762306a36Sopenharmony_ci				     data[IFLA_BOND_MIIMON], extack);
22862306a36Sopenharmony_ci		if (err)
22962306a36Sopenharmony_ci			return err;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	if (data[IFLA_BOND_UPDELAY]) {
23262306a36Sopenharmony_ci		int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		bond_opt_initval(&newval, updelay);
23562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval,
23662306a36Sopenharmony_ci				     data[IFLA_BOND_UPDELAY], extack);
23762306a36Sopenharmony_ci		if (err)
23862306a36Sopenharmony_ci			return err;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	if (data[IFLA_BOND_DOWNDELAY]) {
24162306a36Sopenharmony_ci		int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		bond_opt_initval(&newval, downdelay);
24462306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval,
24562306a36Sopenharmony_ci				     data[IFLA_BOND_DOWNDELAY], extack);
24662306a36Sopenharmony_ci		if (err)
24762306a36Sopenharmony_ci			return err;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	if (data[IFLA_BOND_PEER_NOTIF_DELAY]) {
25062306a36Sopenharmony_ci		int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		bond_opt_initval(&newval, delay);
25362306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval,
25462306a36Sopenharmony_ci				     data[IFLA_BOND_PEER_NOTIF_DELAY], extack);
25562306a36Sopenharmony_ci		if (err)
25662306a36Sopenharmony_ci			return err;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	if (data[IFLA_BOND_USE_CARRIER]) {
25962306a36Sopenharmony_ci		int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		bond_opt_initval(&newval, use_carrier);
26262306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval,
26362306a36Sopenharmony_ci				     data[IFLA_BOND_USE_CARRIER], extack);
26462306a36Sopenharmony_ci		if (err)
26562306a36Sopenharmony_ci			return err;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci	if (data[IFLA_BOND_ARP_INTERVAL]) {
26862306a36Sopenharmony_ci		int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		if (arp_interval && miimon) {
27162306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL],
27262306a36Sopenharmony_ci					    "ARP monitoring cannot be used with MII monitoring");
27362306a36Sopenharmony_ci			return -EINVAL;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		bond_opt_initval(&newval, arp_interval);
27762306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval,
27862306a36Sopenharmony_ci				     data[IFLA_BOND_ARP_INTERVAL], extack);
27962306a36Sopenharmony_ci		if (err)
28062306a36Sopenharmony_ci			return err;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci	if (data[IFLA_BOND_ARP_IP_TARGET]) {
28362306a36Sopenharmony_ci		struct nlattr *attr;
28462306a36Sopenharmony_ci		int i = 0, rem;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		bond_option_arp_ip_targets_clear(bond);
28762306a36Sopenharmony_ci		nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
28862306a36Sopenharmony_ci			__be32 target;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci			if (nla_len(attr) < sizeof(target))
29162306a36Sopenharmony_ci				return -EINVAL;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			target = nla_get_be32(attr);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci			bond_opt_initval(&newval, (__force u64)target);
29662306a36Sopenharmony_ci			err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
29762306a36Sopenharmony_ci					     &newval,
29862306a36Sopenharmony_ci					     data[IFLA_BOND_ARP_IP_TARGET],
29962306a36Sopenharmony_ci					     extack);
30062306a36Sopenharmony_ci			if (err)
30162306a36Sopenharmony_ci				break;
30262306a36Sopenharmony_ci			i++;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		if (i == 0 && bond->params.arp_interval)
30562306a36Sopenharmony_ci			netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
30662306a36Sopenharmony_ci		if (err)
30762306a36Sopenharmony_ci			return err;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
31062306a36Sopenharmony_ci	if (data[IFLA_BOND_NS_IP6_TARGET]) {
31162306a36Sopenharmony_ci		struct nlattr *attr;
31262306a36Sopenharmony_ci		int i = 0, rem;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		bond_option_ns_ip6_targets_clear(bond);
31562306a36Sopenharmony_ci		nla_for_each_nested(attr, data[IFLA_BOND_NS_IP6_TARGET], rem) {
31662306a36Sopenharmony_ci			struct in6_addr addr6;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci			if (nla_len(attr) < sizeof(addr6)) {
31962306a36Sopenharmony_ci				NL_SET_ERR_MSG(extack, "Invalid IPv6 address");
32062306a36Sopenharmony_ci				return -EINVAL;
32162306a36Sopenharmony_ci			}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci			addr6 = nla_get_in6_addr(attr);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci			bond_opt_initextra(&newval, &addr6, sizeof(addr6));
32662306a36Sopenharmony_ci			err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS,
32762306a36Sopenharmony_ci					     &newval,
32862306a36Sopenharmony_ci					     data[IFLA_BOND_NS_IP6_TARGET],
32962306a36Sopenharmony_ci					     extack);
33062306a36Sopenharmony_ci			if (err)
33162306a36Sopenharmony_ci				break;
33262306a36Sopenharmony_ci			i++;
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci		if (i == 0 && bond->params.arp_interval)
33562306a36Sopenharmony_ci			netdev_warn(bond->dev, "Removing last ns target with arp_interval on\n");
33662306a36Sopenharmony_ci		if (err)
33762306a36Sopenharmony_ci			return err;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci#endif
34062306a36Sopenharmony_ci	if (data[IFLA_BOND_ARP_VALIDATE]) {
34162306a36Sopenharmony_ci		int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		if (arp_validate && miimon) {
34462306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL],
34562306a36Sopenharmony_ci					    "ARP validating cannot be used with MII monitoring");
34662306a36Sopenharmony_ci			return -EINVAL;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		bond_opt_initval(&newval, arp_validate);
35062306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval,
35162306a36Sopenharmony_ci				     data[IFLA_BOND_ARP_VALIDATE], extack);
35262306a36Sopenharmony_ci		if (err)
35362306a36Sopenharmony_ci			return err;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	if (data[IFLA_BOND_ARP_ALL_TARGETS]) {
35662306a36Sopenharmony_ci		int arp_all_targets =
35762306a36Sopenharmony_ci			nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		bond_opt_initval(&newval, arp_all_targets);
36062306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval,
36162306a36Sopenharmony_ci				     data[IFLA_BOND_ARP_ALL_TARGETS], extack);
36262306a36Sopenharmony_ci		if (err)
36362306a36Sopenharmony_ci			return err;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	if (data[IFLA_BOND_PRIMARY]) {
36662306a36Sopenharmony_ci		int ifindex = nla_get_u32(data[IFLA_BOND_PRIMARY]);
36762306a36Sopenharmony_ci		struct net_device *dev;
36862306a36Sopenharmony_ci		char *primary = "";
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		dev = __dev_get_by_index(dev_net(bond_dev), ifindex);
37162306a36Sopenharmony_ci		if (dev)
37262306a36Sopenharmony_ci			primary = dev->name;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		bond_opt_initstr(&newval, primary);
37562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval,
37662306a36Sopenharmony_ci				     data[IFLA_BOND_PRIMARY], extack);
37762306a36Sopenharmony_ci		if (err)
37862306a36Sopenharmony_ci			return err;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	if (data[IFLA_BOND_PRIMARY_RESELECT]) {
38162306a36Sopenharmony_ci		int primary_reselect =
38262306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		bond_opt_initval(&newval, primary_reselect);
38562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval,
38662306a36Sopenharmony_ci				     data[IFLA_BOND_PRIMARY_RESELECT], extack);
38762306a36Sopenharmony_ci		if (err)
38862306a36Sopenharmony_ci			return err;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	if (data[IFLA_BOND_FAIL_OVER_MAC]) {
39162306a36Sopenharmony_ci		int fail_over_mac =
39262306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		bond_opt_initval(&newval, fail_over_mac);
39562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval,
39662306a36Sopenharmony_ci				     data[IFLA_BOND_FAIL_OVER_MAC], extack);
39762306a36Sopenharmony_ci		if (err)
39862306a36Sopenharmony_ci			return err;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	if (data[IFLA_BOND_XMIT_HASH_POLICY]) {
40162306a36Sopenharmony_ci		int xmit_hash_policy =
40262306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		bond_opt_initval(&newval, xmit_hash_policy);
40562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval,
40662306a36Sopenharmony_ci				     data[IFLA_BOND_XMIT_HASH_POLICY], extack);
40762306a36Sopenharmony_ci		if (err)
40862306a36Sopenharmony_ci			return err;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci	if (data[IFLA_BOND_RESEND_IGMP]) {
41162306a36Sopenharmony_ci		int resend_igmp =
41262306a36Sopenharmony_ci			nla_get_u32(data[IFLA_BOND_RESEND_IGMP]);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		bond_opt_initval(&newval, resend_igmp);
41562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval,
41662306a36Sopenharmony_ci				     data[IFLA_BOND_RESEND_IGMP], extack);
41762306a36Sopenharmony_ci		if (err)
41862306a36Sopenharmony_ci			return err;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci	if (data[IFLA_BOND_NUM_PEER_NOTIF]) {
42162306a36Sopenharmony_ci		int num_peer_notif =
42262306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		bond_opt_initval(&newval, num_peer_notif);
42562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval,
42662306a36Sopenharmony_ci				     data[IFLA_BOND_NUM_PEER_NOTIF], extack);
42762306a36Sopenharmony_ci		if (err)
42862306a36Sopenharmony_ci			return err;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci	if (data[IFLA_BOND_ALL_SLAVES_ACTIVE]) {
43162306a36Sopenharmony_ci		int all_slaves_active =
43262306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		bond_opt_initval(&newval, all_slaves_active);
43562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval,
43662306a36Sopenharmony_ci				     data[IFLA_BOND_ALL_SLAVES_ACTIVE], extack);
43762306a36Sopenharmony_ci		if (err)
43862306a36Sopenharmony_ci			return err;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci	if (data[IFLA_BOND_MIN_LINKS]) {
44162306a36Sopenharmony_ci		int min_links =
44262306a36Sopenharmony_ci			nla_get_u32(data[IFLA_BOND_MIN_LINKS]);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		bond_opt_initval(&newval, min_links);
44562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval,
44662306a36Sopenharmony_ci				     data[IFLA_BOND_MIN_LINKS], extack);
44762306a36Sopenharmony_ci		if (err)
44862306a36Sopenharmony_ci			return err;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	if (data[IFLA_BOND_LP_INTERVAL]) {
45162306a36Sopenharmony_ci		int lp_interval =
45262306a36Sopenharmony_ci			nla_get_u32(data[IFLA_BOND_LP_INTERVAL]);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		bond_opt_initval(&newval, lp_interval);
45562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval,
45662306a36Sopenharmony_ci				     data[IFLA_BOND_LP_INTERVAL], extack);
45762306a36Sopenharmony_ci		if (err)
45862306a36Sopenharmony_ci			return err;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci	if (data[IFLA_BOND_PACKETS_PER_SLAVE]) {
46162306a36Sopenharmony_ci		int packets_per_slave =
46262306a36Sopenharmony_ci			nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		bond_opt_initval(&newval, packets_per_slave);
46562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval,
46662306a36Sopenharmony_ci				     data[IFLA_BOND_PACKETS_PER_SLAVE], extack);
46762306a36Sopenharmony_ci		if (err)
46862306a36Sopenharmony_ci			return err;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_LACP_ACTIVE]) {
47262306a36Sopenharmony_ci		int lacp_active = nla_get_u8(data[IFLA_BOND_AD_LACP_ACTIVE]);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		bond_opt_initval(&newval, lacp_active);
47562306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval,
47662306a36Sopenharmony_ci				     data[IFLA_BOND_AD_LACP_ACTIVE], extack);
47762306a36Sopenharmony_ci		if (err)
47862306a36Sopenharmony_ci			return err;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_LACP_RATE]) {
48262306a36Sopenharmony_ci		int lacp_rate =
48362306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		bond_opt_initval(&newval, lacp_rate);
48662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval,
48762306a36Sopenharmony_ci				     data[IFLA_BOND_AD_LACP_RATE], extack);
48862306a36Sopenharmony_ci		if (err)
48962306a36Sopenharmony_ci			return err;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_SELECT]) {
49262306a36Sopenharmony_ci		int ad_select =
49362306a36Sopenharmony_ci			nla_get_u8(data[IFLA_BOND_AD_SELECT]);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		bond_opt_initval(&newval, ad_select);
49662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval,
49762306a36Sopenharmony_ci				     data[IFLA_BOND_AD_SELECT], extack);
49862306a36Sopenharmony_ci		if (err)
49962306a36Sopenharmony_ci			return err;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
50262306a36Sopenharmony_ci		int actor_sys_prio =
50362306a36Sopenharmony_ci			nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		bond_opt_initval(&newval, actor_sys_prio);
50662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval,
50762306a36Sopenharmony_ci				     data[IFLA_BOND_AD_ACTOR_SYS_PRIO], extack);
50862306a36Sopenharmony_ci		if (err)
50962306a36Sopenharmony_ci			return err;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_USER_PORT_KEY]) {
51262306a36Sopenharmony_ci		int port_key =
51362306a36Sopenharmony_ci			nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		bond_opt_initval(&newval, port_key);
51662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval,
51762306a36Sopenharmony_ci				     data[IFLA_BOND_AD_USER_PORT_KEY], extack);
51862306a36Sopenharmony_ci		if (err)
51962306a36Sopenharmony_ci			return err;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci	if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) {
52262306a36Sopenharmony_ci		if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN)
52362306a36Sopenharmony_ci			return -EINVAL;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		bond_opt_initval(&newval,
52662306a36Sopenharmony_ci				 nla_get_u64(data[IFLA_BOND_AD_ACTOR_SYSTEM]));
52762306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval,
52862306a36Sopenharmony_ci				     data[IFLA_BOND_AD_ACTOR_SYSTEM], extack);
52962306a36Sopenharmony_ci		if (err)
53062306a36Sopenharmony_ci			return err;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci	if (data[IFLA_BOND_TLB_DYNAMIC_LB]) {
53362306a36Sopenharmony_ci		int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		bond_opt_initval(&newval, dynamic_lb);
53662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval,
53762306a36Sopenharmony_ci				     data[IFLA_BOND_TLB_DYNAMIC_LB], extack);
53862306a36Sopenharmony_ci		if (err)
53962306a36Sopenharmony_ci			return err;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (data[IFLA_BOND_MISSED_MAX]) {
54362306a36Sopenharmony_ci		int missed_max = nla_get_u8(data[IFLA_BOND_MISSED_MAX]);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		bond_opt_initval(&newval, missed_max);
54662306a36Sopenharmony_ci		err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval,
54762306a36Sopenharmony_ci				     data[IFLA_BOND_MISSED_MAX], extack);
54862306a36Sopenharmony_ci		if (err)
54962306a36Sopenharmony_ci			return err;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return 0;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int bond_newlink(struct net *src_net, struct net_device *bond_dev,
55662306a36Sopenharmony_ci			struct nlattr *tb[], struct nlattr *data[],
55762306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	int err;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	err = bond_changelink(bond_dev, tb, data, extack);
56262306a36Sopenharmony_ci	if (err < 0)
56362306a36Sopenharmony_ci		return err;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	err = register_netdevice(bond_dev);
56662306a36Sopenharmony_ci	if (!err) {
56762306a36Sopenharmony_ci		struct bonding *bond = netdev_priv(bond_dev);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		netif_carrier_off(bond_dev);
57062306a36Sopenharmony_ci		bond_work_init_all(bond);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return err;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic size_t bond_get_size(const struct net_device *bond_dev)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	return nla_total_size(sizeof(u8)) +	/* IFLA_BOND_MODE */
57962306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ACTIVE_SLAVE */
58062306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_MIIMON */
58162306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_UPDELAY */
58262306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_DOWNDELAY */
58362306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_USE_CARRIER */
58462306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ARP_INTERVAL */
58562306a36Sopenharmony_ci						/* IFLA_BOND_ARP_IP_TARGET */
58662306a36Sopenharmony_ci		nla_total_size(sizeof(struct nlattr)) +
58762306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS +
58862306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ARP_VALIDATE */
58962306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ARP_ALL_TARGETS */
59062306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_PRIMARY */
59162306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_PRIMARY_RESELECT */
59262306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_FAIL_OVER_MAC */
59362306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_XMIT_HASH_POLICY */
59462306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_RESEND_IGMP */
59562306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_NUM_PEER_NOTIF */
59662306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +   /* IFLA_BOND_ALL_SLAVES_ACTIVE */
59762306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_MIN_LINKS */
59862306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_LP_INTERVAL */
59962306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +  /* IFLA_BOND_PACKETS_PER_SLAVE */
60062306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_AD_LACP_ACTIVE */
60162306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_AD_LACP_RATE */
60262306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_AD_SELECT */
60362306a36Sopenharmony_ci		nla_total_size(sizeof(struct nlattr)) + /* IFLA_BOND_AD_INFO */
60462306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_AGGREGATOR */
60562306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_NUM_PORTS */
60662306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */
60762306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/
60862306a36Sopenharmony_ci		nla_total_size(ETH_ALEN) +    /* IFLA_BOND_AD_INFO_PARTNER_MAC*/
60962306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */
61062306a36Sopenharmony_ci		nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */
61162306a36Sopenharmony_ci		nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */
61262306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */
61362306a36Sopenharmony_ci		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_PEER_NOTIF_DELAY */
61462306a36Sopenharmony_ci		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_MISSED_MAX */
61562306a36Sopenharmony_ci						/* IFLA_BOND_NS_IP6_TARGET */
61662306a36Sopenharmony_ci		nla_total_size(sizeof(struct nlattr)) +
61762306a36Sopenharmony_ci		nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS +
61862306a36Sopenharmony_ci		0;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic int bond_option_active_slave_get_ifindex(struct bonding *bond)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	const struct net_device *slave;
62462306a36Sopenharmony_ci	int ifindex;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	rcu_read_lock();
62762306a36Sopenharmony_ci	slave = bond_option_active_slave_get_rcu(bond);
62862306a36Sopenharmony_ci	ifindex = slave ? slave->ifindex : 0;
62962306a36Sopenharmony_ci	rcu_read_unlock();
63062306a36Sopenharmony_ci	return ifindex;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int bond_fill_info(struct sk_buff *skb,
63462306a36Sopenharmony_ci			  const struct net_device *bond_dev)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct bonding *bond = netdev_priv(bond_dev);
63762306a36Sopenharmony_ci	unsigned int packets_per_slave;
63862306a36Sopenharmony_ci	int ifindex, i, targets_added;
63962306a36Sopenharmony_ci	struct nlattr *targets;
64062306a36Sopenharmony_ci	struct slave *primary;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond)))
64362306a36Sopenharmony_ci		goto nla_put_failure;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	ifindex = bond_option_active_slave_get_ifindex(bond);
64662306a36Sopenharmony_ci	if (ifindex && nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, ifindex))
64762306a36Sopenharmony_ci		goto nla_put_failure;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon))
65062306a36Sopenharmony_ci		goto nla_put_failure;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_UPDELAY,
65362306a36Sopenharmony_ci			bond->params.updelay * bond->params.miimon))
65462306a36Sopenharmony_ci		goto nla_put_failure;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY,
65762306a36Sopenharmony_ci			bond->params.downdelay * bond->params.miimon))
65862306a36Sopenharmony_ci		goto nla_put_failure;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_PEER_NOTIF_DELAY,
66162306a36Sopenharmony_ci			bond->params.peer_notif_delay * bond->params.miimon))
66262306a36Sopenharmony_ci		goto nla_put_failure;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier))
66562306a36Sopenharmony_ci		goto nla_put_failure;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval))
66862306a36Sopenharmony_ci		goto nla_put_failure;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	targets = nla_nest_start_noflag(skb, IFLA_BOND_ARP_IP_TARGET);
67162306a36Sopenharmony_ci	if (!targets)
67262306a36Sopenharmony_ci		goto nla_put_failure;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	targets_added = 0;
67562306a36Sopenharmony_ci	for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
67662306a36Sopenharmony_ci		if (bond->params.arp_targets[i]) {
67762306a36Sopenharmony_ci			if (nla_put_be32(skb, i, bond->params.arp_targets[i]))
67862306a36Sopenharmony_ci				goto nla_put_failure;
67962306a36Sopenharmony_ci			targets_added = 1;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (targets_added)
68462306a36Sopenharmony_ci		nla_nest_end(skb, targets);
68562306a36Sopenharmony_ci	else
68662306a36Sopenharmony_ci		nla_nest_cancel(skb, targets);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate))
68962306a36Sopenharmony_ci		goto nla_put_failure;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS,
69262306a36Sopenharmony_ci			bond->params.arp_all_targets))
69362306a36Sopenharmony_ci		goto nla_put_failure;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
69662306a36Sopenharmony_ci	targets = nla_nest_start(skb, IFLA_BOND_NS_IP6_TARGET);
69762306a36Sopenharmony_ci	if (!targets)
69862306a36Sopenharmony_ci		goto nla_put_failure;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	targets_added = 0;
70162306a36Sopenharmony_ci	for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
70262306a36Sopenharmony_ci		if (!ipv6_addr_any(&bond->params.ns_targets[i])) {
70362306a36Sopenharmony_ci			if (nla_put_in6_addr(skb, i, &bond->params.ns_targets[i]))
70462306a36Sopenharmony_ci				goto nla_put_failure;
70562306a36Sopenharmony_ci			targets_added = 1;
70662306a36Sopenharmony_ci		}
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (targets_added)
71062306a36Sopenharmony_ci		nla_nest_end(skb, targets);
71162306a36Sopenharmony_ci	else
71262306a36Sopenharmony_ci		nla_nest_cancel(skb, targets);
71362306a36Sopenharmony_ci#endif
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	primary = rtnl_dereference(bond->primary_slave);
71662306a36Sopenharmony_ci	if (primary &&
71762306a36Sopenharmony_ci	    nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex))
71862306a36Sopenharmony_ci		goto nla_put_failure;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT,
72162306a36Sopenharmony_ci		       bond->params.primary_reselect))
72262306a36Sopenharmony_ci		goto nla_put_failure;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_FAIL_OVER_MAC,
72562306a36Sopenharmony_ci		       bond->params.fail_over_mac))
72662306a36Sopenharmony_ci		goto nla_put_failure;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_XMIT_HASH_POLICY,
72962306a36Sopenharmony_ci		       bond->params.xmit_policy))
73062306a36Sopenharmony_ci		goto nla_put_failure;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_RESEND_IGMP,
73362306a36Sopenharmony_ci			bond->params.resend_igmp))
73462306a36Sopenharmony_ci		goto nla_put_failure;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_NUM_PEER_NOTIF,
73762306a36Sopenharmony_ci		       bond->params.num_peer_notif))
73862306a36Sopenharmony_ci		goto nla_put_failure;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_ALL_SLAVES_ACTIVE,
74162306a36Sopenharmony_ci		       bond->params.all_slaves_active))
74262306a36Sopenharmony_ci		goto nla_put_failure;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_MIN_LINKS,
74562306a36Sopenharmony_ci			bond->params.min_links))
74662306a36Sopenharmony_ci		goto nla_put_failure;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_LP_INTERVAL,
74962306a36Sopenharmony_ci			bond->params.lp_interval))
75062306a36Sopenharmony_ci		goto nla_put_failure;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	packets_per_slave = bond->params.packets_per_slave;
75362306a36Sopenharmony_ci	if (nla_put_u32(skb, IFLA_BOND_PACKETS_PER_SLAVE,
75462306a36Sopenharmony_ci			packets_per_slave))
75562306a36Sopenharmony_ci		goto nla_put_failure;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_AD_LACP_ACTIVE,
75862306a36Sopenharmony_ci		       bond->params.lacp_active))
75962306a36Sopenharmony_ci		goto nla_put_failure;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_AD_LACP_RATE,
76262306a36Sopenharmony_ci		       bond->params.lacp_fast))
76362306a36Sopenharmony_ci		goto nla_put_failure;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_AD_SELECT,
76662306a36Sopenharmony_ci		       bond->params.ad_select))
76762306a36Sopenharmony_ci		goto nla_put_failure;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_TLB_DYNAMIC_LB,
77062306a36Sopenharmony_ci		       bond->params.tlb_dynamic_lb))
77162306a36Sopenharmony_ci		goto nla_put_failure;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (nla_put_u8(skb, IFLA_BOND_MISSED_MAX,
77462306a36Sopenharmony_ci		       bond->params.missed_max))
77562306a36Sopenharmony_ci		goto nla_put_failure;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
77862306a36Sopenharmony_ci		struct ad_info info;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		if (capable(CAP_NET_ADMIN)) {
78162306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_ACTOR_SYS_PRIO,
78262306a36Sopenharmony_ci					bond->params.ad_actor_sys_prio))
78362306a36Sopenharmony_ci				goto nla_put_failure;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_USER_PORT_KEY,
78662306a36Sopenharmony_ci					bond->params.ad_user_port_key))
78762306a36Sopenharmony_ci				goto nla_put_failure;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci			if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM,
79062306a36Sopenharmony_ci				    ETH_ALEN, &bond->params.ad_actor_system))
79162306a36Sopenharmony_ci				goto nla_put_failure;
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci		if (!bond_3ad_get_active_agg_info(bond, &info)) {
79462306a36Sopenharmony_ci			struct nlattr *nest;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci			nest = nla_nest_start_noflag(skb, IFLA_BOND_AD_INFO);
79762306a36Sopenharmony_ci			if (!nest)
79862306a36Sopenharmony_ci				goto nla_put_failure;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_INFO_AGGREGATOR,
80162306a36Sopenharmony_ci					info.aggregator_id))
80262306a36Sopenharmony_ci				goto nla_put_failure;
80362306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_INFO_NUM_PORTS,
80462306a36Sopenharmony_ci					info.ports))
80562306a36Sopenharmony_ci				goto nla_put_failure;
80662306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_INFO_ACTOR_KEY,
80762306a36Sopenharmony_ci					info.actor_key))
80862306a36Sopenharmony_ci				goto nla_put_failure;
80962306a36Sopenharmony_ci			if (nla_put_u16(skb, IFLA_BOND_AD_INFO_PARTNER_KEY,
81062306a36Sopenharmony_ci					info.partner_key))
81162306a36Sopenharmony_ci				goto nla_put_failure;
81262306a36Sopenharmony_ci			if (nla_put(skb, IFLA_BOND_AD_INFO_PARTNER_MAC,
81362306a36Sopenharmony_ci				    sizeof(info.partner_system),
81462306a36Sopenharmony_ci				    &info.partner_system))
81562306a36Sopenharmony_ci				goto nla_put_failure;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci			nla_nest_end(skb, nest);
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	return 0;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cinla_put_failure:
82462306a36Sopenharmony_ci	return -EMSGSIZE;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic size_t bond_get_linkxstats_size(const struct net_device *dev, int attr)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	switch (attr) {
83062306a36Sopenharmony_ci	case IFLA_STATS_LINK_XSTATS:
83162306a36Sopenharmony_ci	case IFLA_STATS_LINK_XSTATS_SLAVE:
83262306a36Sopenharmony_ci		break;
83362306a36Sopenharmony_ci	default:
83462306a36Sopenharmony_ci		return 0;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	return bond_3ad_stats_size() + nla_total_size(0);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic int bond_fill_linkxstats(struct sk_buff *skb,
84162306a36Sopenharmony_ci				const struct net_device *dev,
84262306a36Sopenharmony_ci				int *prividx, int attr)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct nlattr *nla __maybe_unused;
84562306a36Sopenharmony_ci	struct slave *slave = NULL;
84662306a36Sopenharmony_ci	struct nlattr *nest, *nest2;
84762306a36Sopenharmony_ci	struct bonding *bond;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	switch (attr) {
85062306a36Sopenharmony_ci	case IFLA_STATS_LINK_XSTATS:
85162306a36Sopenharmony_ci		bond = netdev_priv(dev);
85262306a36Sopenharmony_ci		break;
85362306a36Sopenharmony_ci	case IFLA_STATS_LINK_XSTATS_SLAVE:
85462306a36Sopenharmony_ci		slave = bond_slave_get_rtnl(dev);
85562306a36Sopenharmony_ci		if (!slave)
85662306a36Sopenharmony_ci			return 0;
85762306a36Sopenharmony_ci		bond = slave->bond;
85862306a36Sopenharmony_ci		break;
85962306a36Sopenharmony_ci	default:
86062306a36Sopenharmony_ci		return -EINVAL;
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, LINK_XSTATS_TYPE_BOND);
86462306a36Sopenharmony_ci	if (!nest)
86562306a36Sopenharmony_ci		return -EMSGSIZE;
86662306a36Sopenharmony_ci	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
86762306a36Sopenharmony_ci		struct bond_3ad_stats *stats;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		if (slave)
87062306a36Sopenharmony_ci			stats = &SLAVE_AD_INFO(slave)->stats;
87162306a36Sopenharmony_ci		else
87262306a36Sopenharmony_ci			stats = &BOND_AD_INFO(bond).stats;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		nest2 = nla_nest_start_noflag(skb, BOND_XSTATS_3AD);
87562306a36Sopenharmony_ci		if (!nest2) {
87662306a36Sopenharmony_ci			nla_nest_end(skb, nest);
87762306a36Sopenharmony_ci			return -EMSGSIZE;
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		if (bond_3ad_stats_fill(skb, stats)) {
88162306a36Sopenharmony_ci			nla_nest_cancel(skb, nest2);
88262306a36Sopenharmony_ci			nla_nest_end(skb, nest);
88362306a36Sopenharmony_ci			return -EMSGSIZE;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci		nla_nest_end(skb, nest2);
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci	nla_nest_end(skb, nest);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return 0;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistruct rtnl_link_ops bond_link_ops __read_mostly = {
89362306a36Sopenharmony_ci	.kind			= "bond",
89462306a36Sopenharmony_ci	.priv_size		= sizeof(struct bonding),
89562306a36Sopenharmony_ci	.setup			= bond_setup,
89662306a36Sopenharmony_ci	.maxtype		= IFLA_BOND_MAX,
89762306a36Sopenharmony_ci	.policy			= bond_policy,
89862306a36Sopenharmony_ci	.validate		= bond_validate,
89962306a36Sopenharmony_ci	.newlink		= bond_newlink,
90062306a36Sopenharmony_ci	.changelink		= bond_changelink,
90162306a36Sopenharmony_ci	.get_size		= bond_get_size,
90262306a36Sopenharmony_ci	.fill_info		= bond_fill_info,
90362306a36Sopenharmony_ci	.get_num_tx_queues	= bond_get_num_tx_queues,
90462306a36Sopenharmony_ci	.get_num_rx_queues	= bond_get_num_tx_queues, /* Use the same number
90562306a36Sopenharmony_ci							     as for TX queues */
90662306a36Sopenharmony_ci	.fill_linkxstats        = bond_fill_linkxstats,
90762306a36Sopenharmony_ci	.get_linkxstats_size    = bond_get_linkxstats_size,
90862306a36Sopenharmony_ci	.slave_maxtype		= IFLA_BOND_SLAVE_MAX,
90962306a36Sopenharmony_ci	.slave_policy		= bond_slave_policy,
91062306a36Sopenharmony_ci	.slave_changelink	= bond_slave_changelink,
91162306a36Sopenharmony_ci	.get_slave_size		= bond_get_slave_size,
91262306a36Sopenharmony_ci	.fill_slave_info	= bond_fill_slave_info,
91362306a36Sopenharmony_ci};
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ciint __init bond_netlink_init(void)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	return rtnl_link_register(&bond_link_ops);
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_civoid bond_netlink_fini(void)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	rtnl_link_unregister(&bond_link_ops);
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("bond");
926