static int vdpa_nl_cmd_dev_add_set_doit()

in vdpa.c [586:648]


static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *info)
{
	struct vdpa_dev_set_config config = {};
	struct nlattr **nl_attrs = info->attrs;
	struct vdpa_mgmt_dev *mdev;
	const u8 *macaddr;
	const char *name;
	int err = 0;

	if (!info->attrs[VDPA_ATTR_DEV_NAME])
		return -EINVAL;

	name = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]);

	if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]) {
		macaddr = nla_data(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]);
		memcpy(config.net.mac, macaddr, sizeof(config.net.mac));
		config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR);
	}
	if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]) {
		config.net.mtu =
			nla_get_u16(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]);
		config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU);
	}
	if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MAX_VQP]) {
		config.net.max_vq_pairs =
			nla_get_u16(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MAX_VQP]);
		if (!config.net.max_vq_pairs) {
			NL_SET_ERR_MSG_MOD(info->extack,
					   "At least one pair of VQs is required");
			return -EINVAL;
		}
		config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP);
	}

	/* Skip checking capability if user didn't prefer to configure any
	 * device networking attributes. It is likely that user might have used
	 * a device specific method to configure such attributes or using device
	 * default attributes.
	 */
	if ((config.mask & VDPA_DEV_NET_ATTRS_MASK) &&
	    !netlink_capable(skb, CAP_NET_ADMIN))
		return -EPERM;

	mutex_lock(&vdpa_dev_mutex);
	mdev = vdpa_mgmtdev_get_from_attr(info->attrs);
	if (IS_ERR(mdev)) {
		NL_SET_ERR_MSG_MOD(info->extack, "Fail to find the specified management device");
		err = PTR_ERR(mdev);
		goto err;
	}
	if ((config.mask & mdev->config_attr_mask) != config.mask) {
		NL_SET_ERR_MSG_MOD(info->extack,
				   "All provided attributes are not supported");
		err = -EOPNOTSUPP;
		goto err;
	}

	err = mdev->ops->dev_add(mdev, name, &config);
err:
	mutex_unlock(&vdpa_dev_mutex);
	return err;
}