Exemplo n.º 1
0
static int tcf_pedit_init(struct net *net, struct nlattr *nla,
			  struct nlattr *est, struct tc_action **a,
			  int ovr, int bind, bool rtnl_held,
			  struct netlink_ext_ack *extack)
{
	struct tc_action_net *tn = net_generic(net, pedit_net_id);
	struct nlattr *tb[TCA_PEDIT_MAX + 1];
	struct tc_pedit_key *keys = NULL;
	struct tcf_pedit_key_ex *keys_ex;
	struct tc_pedit *parm;
	struct nlattr *pattr;
	struct tcf_pedit *p;
	int ret = 0, err;
	int ksize;

	if (!nla) {
		NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed");
		return -EINVAL;
	}

	err = nla_parse_nested(tb, TCA_PEDIT_MAX, nla, pedit_policy, NULL);
	if (err < 0)
		return err;

	pattr = tb[TCA_PEDIT_PARMS];
	if (!pattr)
		pattr = tb[TCA_PEDIT_PARMS_EX];
	if (!pattr) {
		NL_SET_ERR_MSG_MOD(extack, "Missing required TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute");
		return -EINVAL;
	}

	parm = nla_data(pattr);
	ksize = parm->nkeys * sizeof(struct tc_pedit_key);
	if (nla_len(pattr) < sizeof(*parm) + ksize) {
		NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid");
		return -EINVAL;
	}

	keys_ex = tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys);
	if (IS_ERR(keys_ex))
		return PTR_ERR(keys_ex);

	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	if (!err) {
		if (!parm->nkeys) {
			tcf_idr_cleanup(tn, parm->index);
			NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
			ret = -EINVAL;
			goto out_free;
		}
		ret = tcf_idr_create(tn, parm->index, est, a,
				     &act_pedit_ops, bind, false);
		if (ret) {
			tcf_idr_cleanup(tn, parm->index);
			goto out_free;
		}
		ret = ACT_P_CREATED;
	} else if (err > 0) {
		if (bind)
			goto out_free;
		if (!ovr) {
			ret = -EEXIST;
			goto out_release;
		}
	} else {
		return err;
	}

	p = to_pedit(*a);
	spin_lock_bh(&p->tcf_lock);

	if (ret == ACT_P_CREATED ||
	    (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys)) {
		keys = kmalloc(ksize, GFP_ATOMIC);
		if (!keys) {
			spin_unlock_bh(&p->tcf_lock);
			ret = -ENOMEM;
			goto out_release;
		}
		kfree(p->tcfp_keys);
		p->tcfp_keys = keys;
		p->tcfp_nkeys = parm->nkeys;
	}
	memcpy(p->tcfp_keys, parm->keys, ksize);

	p->tcfp_flags = parm->flags;
	p->tcf_action = parm->action;

	kfree(p->tcfp_keys_ex);
	p->tcfp_keys_ex = keys_ex;

	spin_unlock_bh(&p->tcf_lock);
	if (ret == ACT_P_CREATED)
		tcf_idr_insert(tn, *a);
	return ret;

out_release:
	tcf_idr_release(*a, bind);
out_free:
	kfree(keys_ex);
	return ret;

}
Exemplo n.º 2
0
static int tcf_pedit_init(struct net *net, struct nlattr *nla,
			  struct nlattr *est, struct tc_action **a,
			  int ovr, int bind)
{
	struct tc_action_net *tn = net_generic(net, pedit_net_id);
	struct nlattr *tb[TCA_PEDIT_MAX + 1];
	struct nlattr *pattr;
	struct tc_pedit *parm;
	int ret = 0, err;
	struct tcf_pedit *p;
	struct tc_pedit_key *keys = NULL;
	struct tcf_pedit_key_ex *keys_ex;
	int ksize;

	if (nla == NULL)
		return -EINVAL;

	err = nla_parse_nested(tb, TCA_PEDIT_MAX, nla, pedit_policy);
	if (err < 0)
		return err;

	pattr = tb[TCA_PEDIT_PARMS];
	if (!pattr)
		pattr = tb[TCA_PEDIT_PARMS_EX];
	if (!pattr)
		return -EINVAL;

	parm = nla_data(pattr);
	ksize = parm->nkeys * sizeof(struct tc_pedit_key);
	if (nla_len(pattr) < sizeof(*parm) + ksize)
		return -EINVAL;

	keys_ex = tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys);
	if (IS_ERR(keys_ex))
		return PTR_ERR(keys_ex);

	if (!tcf_hash_check(tn, parm->index, a, bind)) {
		if (!parm->nkeys)
			return -EINVAL;
		ret = tcf_hash_create(tn, parm->index, est, a,
				      &act_pedit_ops, bind, false);
		if (ret)
			return ret;
		p = to_pedit(*a);
		keys = kmalloc(ksize, GFP_KERNEL);
		if (keys == NULL) {
			tcf_hash_cleanup(*a, est);
			kfree(keys_ex);
			return -ENOMEM;
		}
		ret = ACT_P_CREATED;
	} else {
		if (bind)
			return 0;
		tcf_hash_release(*a, bind);
		if (!ovr)
			return -EEXIST;
		p = to_pedit(*a);
		if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
			keys = kmalloc(ksize, GFP_KERNEL);
			if (!keys) {
				kfree(keys_ex);
				return -ENOMEM;
			}
		}
	}

	spin_lock_bh(&p->tcf_lock);
	p->tcfp_flags = parm->flags;
	p->tcf_action = parm->action;
	if (keys) {
		kfree(p->tcfp_keys);
		p->tcfp_keys = keys;
		p->tcfp_nkeys = parm->nkeys;
	}
	memcpy(p->tcfp_keys, parm->keys, ksize);

	kfree(p->tcfp_keys_ex);
	p->tcfp_keys_ex = keys_ex;

	spin_unlock_bh(&p->tcf_lock);
	if (ret == ACT_P_CREATED)
		tcf_hash_insert(tn, *a);
	return ret;
}