static int tcf_simp_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, int bind, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, simp_net_id); struct nlattr *tb[TCA_DEF_MAX + 1]; struct tc_defact *parm; struct tcf_defact *d; bool exists = false; int ret = 0, err; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy, NULL); if (err < 0) return err; if (tb[TCA_DEF_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_DEF_PARMS]); exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; if (tb[TCA_DEF_DATA] == NULL) { if (exists) tcf_idr_release(*a, bind); return -EINVAL; } if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_simp_ops, bind, false); if (ret) return ret; d = to_defact(*a); ret = alloc_defdata(d, tb[TCA_DEF_DATA]); if (ret < 0) { tcf_idr_release(*a, bind); return ret; } d->tcf_action = parm->action; ret = ACT_P_CREATED; } else { d = to_defact(*a); tcf_idr_release(*a, bind); if (!ovr) return -EEXIST; reset_policy(d, tb[TCA_DEF_DATA], parm); } if (ret == ACT_P_CREATED) tcf_idr_insert(tn, *a); return ret; }
static int tcf_simp_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_DEF_MAX]; struct tc_defact *parm; struct tcf_defact *d; struct tcf_common *pc; void *defdata; u32 datalen = 0; int ret = 0; if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) return -EINVAL; if (tb[TCA_DEF_PARMS - 1] == NULL || RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) return -EINVAL; parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); if (defdata == NULL) return -EINVAL; datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); if (datalen <= 0) return -EINVAL; pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, &simp_idx_gen, &simp_hash_info); if (unlikely(!pc)) return -ENOMEM; d = to_defact(pc); ret = alloc_defdata(d, datalen, defdata); if (ret < 0) { kfree(pc); return ret; } ret = ACT_P_CREATED; } else { d = to_defact(pc); if (!ovr) { tcf_simp_release(d, bind); return -EEXIST; } realloc_defdata(d, datalen, defdata); } spin_lock_bh(&d->tcf_lock); d->tcf_action = parm->action; spin_unlock_bh(&d->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &simp_hash_info); return ret; }
static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { struct nlattr *tb[TCA_DEF_MAX + 1]; struct tc_defact *parm; struct tcf_defact *d; struct tcf_common *pc; char *defdata; int ret = 0, err; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy); if (err < 0) return err; if (tb[TCA_DEF_PARMS] == NULL) return -EINVAL; if (tb[TCA_DEF_DATA] == NULL) return -EINVAL; parm = nla_data(tb[TCA_DEF_PARMS]); defdata = nla_data(tb[TCA_DEF_DATA]); pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, &simp_idx_gen, &simp_hash_info); if (unlikely(!pc)) return -ENOMEM; d = to_defact(pc); ret = alloc_defdata(d, defdata); if (ret < 0) { kfree(pc); return ret; } d->tcf_action = parm->action; ret = ACT_P_CREATED; } else { d = to_defact(pc); if (!ovr) { tcf_simp_release(d, bind); return -EEXIST; } reset_policy(d, defdata, parm); } if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &simp_hash_info); return ret; }
static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) { kfree(d->tcfd_defdata); return alloc_defdata(d, datalen, defdata); }