diff options
Diffstat (limited to 'net/sched/act_skbmod.c')
| -rw-r--r-- | net/sched/act_skbmod.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index 7bac1d78e7a3..1d4c324d0a42 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
| 17 | #include <net/netlink.h> | 17 | #include <net/netlink.h> |
| 18 | #include <net/pkt_sched.h> | 18 | #include <net/pkt_sched.h> |
| 19 | #include <net/pkt_cls.h> | ||
| 19 | 20 | ||
| 20 | #include <linux/tc_act/tc_skbmod.h> | 21 | #include <linux/tc_act/tc_skbmod.h> |
| 21 | #include <net/tc_act/tc_skbmod.h> | 22 | #include <net/tc_act/tc_skbmod.h> |
| @@ -82,11 +83,13 @@ static const struct nla_policy skbmod_policy[TCA_SKBMOD_MAX + 1] = { | |||
| 82 | static int tcf_skbmod_init(struct net *net, struct nlattr *nla, | 83 | static int tcf_skbmod_init(struct net *net, struct nlattr *nla, |
| 83 | struct nlattr *est, struct tc_action **a, | 84 | struct nlattr *est, struct tc_action **a, |
| 84 | int ovr, int bind, bool rtnl_held, | 85 | int ovr, int bind, bool rtnl_held, |
| 86 | struct tcf_proto *tp, | ||
| 85 | struct netlink_ext_ack *extack) | 87 | struct netlink_ext_ack *extack) |
| 86 | { | 88 | { |
| 87 | struct tc_action_net *tn = net_generic(net, skbmod_net_id); | 89 | struct tc_action_net *tn = net_generic(net, skbmod_net_id); |
| 88 | struct nlattr *tb[TCA_SKBMOD_MAX + 1]; | 90 | struct nlattr *tb[TCA_SKBMOD_MAX + 1]; |
| 89 | struct tcf_skbmod_params *p, *p_old; | 91 | struct tcf_skbmod_params *p, *p_old; |
| 92 | struct tcf_chain *goto_ch = NULL; | ||
| 90 | struct tc_skbmod *parm; | 93 | struct tc_skbmod *parm; |
| 91 | struct tcf_skbmod *d; | 94 | struct tcf_skbmod *d; |
| 92 | bool exists = false; | 95 | bool exists = false; |
| @@ -153,21 +156,24 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, | |||
| 153 | tcf_idr_release(*a, bind); | 156 | tcf_idr_release(*a, bind); |
| 154 | return -EEXIST; | 157 | return -EEXIST; |
| 155 | } | 158 | } |
| 159 | err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); | ||
| 160 | if (err < 0) | ||
| 161 | goto release_idr; | ||
| 156 | 162 | ||
| 157 | d = to_skbmod(*a); | 163 | d = to_skbmod(*a); |
| 158 | 164 | ||
| 159 | p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); | 165 | p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); |
| 160 | if (unlikely(!p)) { | 166 | if (unlikely(!p)) { |
| 161 | tcf_idr_release(*a, bind); | 167 | err = -ENOMEM; |
| 162 | return -ENOMEM; | 168 | goto put_chain; |
| 163 | } | 169 | } |
| 164 | 170 | ||
| 165 | p->flags = lflags; | 171 | p->flags = lflags; |
| 166 | d->tcf_action = parm->action; | ||
| 167 | 172 | ||
| 168 | if (ovr) | 173 | if (ovr) |
| 169 | spin_lock_bh(&d->tcf_lock); | 174 | spin_lock_bh(&d->tcf_lock); |
| 170 | /* Protected by tcf_lock if overwriting existing action. */ | 175 | /* Protected by tcf_lock if overwriting existing action. */ |
| 176 | goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); | ||
| 171 | p_old = rcu_dereference_protected(d->skbmod_p, 1); | 177 | p_old = rcu_dereference_protected(d->skbmod_p, 1); |
| 172 | 178 | ||
| 173 | if (lflags & SKBMOD_F_DMAC) | 179 | if (lflags & SKBMOD_F_DMAC) |
| @@ -183,10 +189,18 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, | |||
| 183 | 189 | ||
| 184 | if (p_old) | 190 | if (p_old) |
| 185 | kfree_rcu(p_old, rcu); | 191 | kfree_rcu(p_old, rcu); |
| 192 | if (goto_ch) | ||
| 193 | tcf_chain_put_by_act(goto_ch); | ||
| 186 | 194 | ||
| 187 | if (ret == ACT_P_CREATED) | 195 | if (ret == ACT_P_CREATED) |
| 188 | tcf_idr_insert(tn, *a); | 196 | tcf_idr_insert(tn, *a); |
| 189 | return ret; | 197 | return ret; |
| 198 | put_chain: | ||
| 199 | if (goto_ch) | ||
| 200 | tcf_chain_put_by_act(goto_ch); | ||
| 201 | release_idr: | ||
| 202 | tcf_idr_release(*a, bind); | ||
| 203 | return err; | ||
| 190 | } | 204 | } |
| 191 | 205 | ||
| 192 | static void tcf_skbmod_cleanup(struct tc_action *a) | 206 | static void tcf_skbmod_cleanup(struct tc_action *a) |
