static void ipt_destroy_target(struct xt_entry_target *t) { struct xt_tgdtor_param par = { .target = t->u.kernel.target, .targinfo = t->data, }; if (par.target->destroy != NULL) par.target->destroy(&par); module_put(par.target->me); } static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) { int ret = 0; if (ipt) { if (bind) ipt->tcf_bindcnt--; ipt->tcf_refcnt--; if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) { ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); tcf_hash_destroy(&ipt->common, &ipt_hash_info); ret = ACT_P_DELETED; } } return ret; }
static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) { int ret = 0; if (ipt) { if (bind) ipt->tcf_bindcnt--; ipt->tcf_refcnt--; if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) { ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); tcf_hash_destroy(&ipt->common, &ipt_hash_info); ret = ACT_P_DELETED; } } return ret; }
static int tcf_ipt_release(struct tcf_ipt *p, int bind) { int ret = 0; if (p) { if (bind) p->bindcnt--; p->refcnt--; if (p->bindcnt <= 0 && p->refcnt <= 0) { ipt_destroy_target(p->t); kfree(p->tname); kfree(p->t); tcf_hash_destroy(p); ret = ACT_P_DELETED; } } return ret; }
static void ipt_destroy_target(struct xt_entry_target *t) { struct xt_tgdtor_param par = { .target = t->u.kernel.target, .targinfo = t->data, }; if (par.target->destroy != NULL) par.target->destroy(&par); module_put(par.target->me); } static void tcf_ipt_release(struct tc_action *a, int bind) { struct tcf_ipt *ipt = to_ipt(a); ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ },
static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { struct nlattr *tb[TCA_IPT_MAX + 1]; struct tcf_ipt *ipt; struct tcf_common *pc; struct xt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy); if (err < 0) return err; if (tb[TCA_IPT_HOOK] == NULL) return -EINVAL; if (tb[TCA_IPT_TARG] == NULL) return -EINVAL; td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) return -EINVAL; if (tb[TCA_IPT_INDEX] != NULL) index = nla_get_u32(tb[TCA_IPT_INDEX]); pc = tcf_hash_check(index, a, bind, &ipt_hash_info); if (!pc) { pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, &ipt_idx_gen, &ipt_hash_info); if (IS_ERR(pc)) return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { tcf_ipt_release(to_ipt(pc), bind); return -EEXIST; } } ipt = to_ipt(pc); hook = nla_get_u32(tb[TCA_IPT_HOOK]); err = -ENOMEM; tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; if (tb[TCA_IPT_TABLE] == NULL || nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); t = kmemdup(td, td->u.target_size, GFP_KERNEL); if (unlikely(!t)) goto err2; err = ipt_init_target(t, tname, hook); if (err < 0) goto err3; spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } ipt->tcfi_tname = tname; ipt->tcfi_t = t; ipt->tcfi_hook = hook; spin_unlock_bh(&ipt->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &ipt_hash_info); return ret; err3: kfree(t); err2: kfree(tname); err1: if (ret == ACT_P_CREATED) { if (est) gen_kill_estimator(&pc->tcfc_bstats, &pc->tcfc_rate_est); kfree_rcu(pc, tcfc_rcu); } return err; }
static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *p; struct ipt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0) return -EINVAL; if (tb[TCA_IPT_HOOK-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32)) return -EINVAL; if (tb[TCA_IPT_TARG-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t)) return -EINVAL; td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]); if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size) return -EINVAL; if (tb[TCA_IPT_INDEX-1] != NULL && RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); p = tcf_hash_check(index, a, ovr, bind); if (p == NULL) { p = tcf_hash_create(index, est, a, sizeof(*p), ovr, bind); if (p == NULL) return -ENOMEM; ret = ACT_P_CREATED; } else { if (!ovr) { tcf_ipt_release(p, bind); return -EEXIST; } } hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); err = -ENOMEM; tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (tname == NULL) goto err1; if (tb[TCA_IPT_TABLE - 1] == NULL || rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); t = kmalloc(td->u.target_size, GFP_KERNEL); if (t == NULL) goto err2; memcpy(t, td, td->u.target_size); if ((err = ipt_init_target(t, tname, hook)) < 0) goto err3; spin_lock_bh(&p->lock); if (ret != ACT_P_CREATED) { ipt_destroy_target(p->t); kfree(p->tname); kfree(p->t); } p->tname = tname; p->t = t; p->hook = hook; spin_unlock_bh(&p->lock); if (ret == ACT_P_CREATED) tcf_hash_insert(p); return ret; err3: kfree(t); err2: kfree(tname); err1: kfree(p); return err; }
static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { struct nlattr *tb[TCA_IPT_MAX + 1]; struct tcf_ipt *ipt; struct xt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy); if (err < 0) return err; if (tb[TCA_IPT_HOOK] == NULL) return -EINVAL; if (tb[TCA_IPT_TARG] == NULL) return -EINVAL; td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) return -EINVAL; if (tb[TCA_IPT_INDEX] != NULL) index = nla_get_u32(tb[TCA_IPT_INDEX]); if (!tcf_hash_check(index, a, bind) ) { ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind); if (ret) return ret; ret = ACT_P_CREATED; } else { if (bind)/* dont override defaults */ return 0; tcf_hash_release(a, bind); if (!ovr) return -EEXIST; } ipt = to_ipt(a); hook = nla_get_u32(tb[TCA_IPT_HOOK]); err = -ENOMEM; tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; if (tb[TCA_IPT_TABLE] == NULL || nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); t = kmemdup(td, td->u.target_size, GFP_KERNEL); if (unlikely(!t)) goto err2; err = ipt_init_target(t, tname, hook); if (err < 0) goto err3; spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } ipt->tcfi_tname = tname; ipt->tcfi_t = t; ipt->tcfi_hook = hook; spin_unlock_bh(&ipt->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(a); return ret; err3: kfree(t); err2: kfree(tname); err1: if (ret == ACT_P_CREATED) tcf_hash_cleanup(a, est); return err; }
static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *ipt; struct tcf_common *pc; struct ipt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0) return -EINVAL; if (tb[TCA_IPT_HOOK-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32)) return -EINVAL; if (tb[TCA_IPT_TARG-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t)) return -EINVAL; td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]); if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size) return -EINVAL; if (tb[TCA_IPT_INDEX-1] != NULL && RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); pc = tcf_hash_check(index, a, bind, &ipt_hash_info); if (!pc) { pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, &ipt_idx_gen, &ipt_hash_info); if (unlikely(!pc)) return -ENOMEM; ret = ACT_P_CREATED; } else { if (!ovr) { tcf_ipt_release(to_ipt(pc), bind); return -EEXIST; } } ipt = to_ipt(pc); hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); err = -ENOMEM; tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; if (tb[TCA_IPT_TABLE - 1] == NULL || rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); t = kmemdup(td, td->u.target_size, GFP_KERNEL); if (unlikely(!t)) goto err2; if ((err = ipt_init_target(t, tname, hook)) < 0) goto err3; spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } ipt->tcfi_tname = tname; ipt->tcfi_t = t; ipt->tcfi_hook = hook; spin_unlock_bh(&ipt->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &ipt_hash_info); return ret; err3: kfree(t); err2: kfree(tname); err1: kfree(pc); return err; }