]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - net/sched/cls_matchall.c
rxrpc: Fix several cases where a padded len isn't checked in ticket decode
[mirror_ubuntu-zesty-kernel.git] / net / sched / cls_matchall.c
CommitLineData
bf3994d2
JP
1/*
2 * net/sched/cls_matchll.c Match-all classifier
3 *
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15
16#include <net/sch_generic.h>
17#include <net/pkt_cls.h>
18
fd62d9f5 19struct cls_mall_head {
bf3994d2
JP
20 struct tcf_exts exts;
21 struct tcf_result res;
22 u32 handle;
b87f7936 23 u32 flags;
bf3994d2
JP
24 struct rcu_head rcu;
25};
26
27static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
28 struct tcf_result *res)
29{
30 struct cls_mall_head *head = rcu_dereference_bh(tp->root);
bf3994d2 31
fd62d9f5 32 if (tc_skip_sw(head->flags))
b87f7936
YG
33 return -1;
34
fd62d9f5 35 return tcf_exts_exec(skb, &head->exts, res);
bf3994d2
JP
36}
37
38static int mall_init(struct tcf_proto *tp)
39{
bf3994d2
JP
40 return 0;
41}
42
fd62d9f5 43static void mall_destroy_rcu(struct rcu_head *rcu)
bf3994d2 44{
fd62d9f5
YG
45 struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
46 rcu);
bf3994d2 47
fd62d9f5
YG
48 tcf_exts_destroy(&head->exts);
49 kfree(head);
bf3994d2
JP
50}
51
b87f7936 52static int mall_replace_hw_filter(struct tcf_proto *tp,
fd62d9f5 53 struct cls_mall_head *head,
b87f7936
YG
54 unsigned long cookie)
55{
56 struct net_device *dev = tp->q->dev_queue->dev;
57 struct tc_to_netdev offload;
58 struct tc_cls_matchall_offload mall_offload = {0};
171d73be 59 int err;
b87f7936
YG
60
61 offload.type = TC_SETUP_MATCHALL;
62 offload.cls_mall = &mall_offload;
63 offload.cls_mall->command = TC_CLSMATCHALL_REPLACE;
fd62d9f5 64 offload.cls_mall->exts = &head->exts;
b87f7936
YG
65 offload.cls_mall->cookie = cookie;
66
171d73be
OG
67 err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
68 &offload);
69 if (!err)
70 head->flags |= TCA_CLS_FLAGS_IN_HW;
71
72 return err;
b87f7936
YG
73}
74
75static void mall_destroy_hw_filter(struct tcf_proto *tp,
fd62d9f5 76 struct cls_mall_head *head,
b87f7936
YG
77 unsigned long cookie)
78{
79 struct net_device *dev = tp->q->dev_queue->dev;
80 struct tc_to_netdev offload;
81 struct tc_cls_matchall_offload mall_offload = {0};
82
83 offload.type = TC_SETUP_MATCHALL;
84 offload.cls_mall = &mall_offload;
85 offload.cls_mall->command = TC_CLSMATCHALL_DESTROY;
86 offload.cls_mall->exts = NULL;
87 offload.cls_mall->cookie = cookie;
88
89 dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
90 &offload);
91}
92
bf3994d2
JP
93static bool mall_destroy(struct tcf_proto *tp, bool force)
94{
95 struct cls_mall_head *head = rtnl_dereference(tp->root);
b87f7936 96 struct net_device *dev = tp->q->dev_queue->dev;
bf3994d2 97
fd62d9f5
YG
98 if (!head)
99 return true;
bf3994d2 100
fd62d9f5
YG
101 if (tc_should_offload(dev, tp, head->flags))
102 mall_destroy_hw_filter(tp, head, (unsigned long) head);
b87f7936 103
fd62d9f5 104 call_rcu(&head->rcu, mall_destroy_rcu);
bf3994d2
JP
105 return true;
106}
107
108static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
109{
fd62d9f5 110 return 0UL;
bf3994d2
JP
111}
112
113static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
114 [TCA_MATCHALL_UNSPEC] = { .type = NLA_UNSPEC },
115 [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
116};
117
118static int mall_set_parms(struct net *net, struct tcf_proto *tp,
fd62d9f5 119 struct cls_mall_head *head,
bf3994d2
JP
120 unsigned long base, struct nlattr **tb,
121 struct nlattr *est, bool ovr)
122{
123 struct tcf_exts e;
124 int err;
125
126 tcf_exts_init(&e, TCA_MATCHALL_ACT, 0);
127 err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
128 if (err < 0)
129 return err;
130
131 if (tb[TCA_MATCHALL_CLASSID]) {
fd62d9f5
YG
132 head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
133 tcf_bind_filter(tp, &head->res, base);
bf3994d2
JP
134 }
135
fd62d9f5 136 tcf_exts_change(tp, &head->exts, &e);
bf3994d2
JP
137
138 return 0;
139}
140
141static int mall_change(struct net *net, struct sk_buff *in_skb,
142 struct tcf_proto *tp, unsigned long base,
143 u32 handle, struct nlattr **tca,
144 unsigned long *arg, bool ovr)
145{
146 struct cls_mall_head *head = rtnl_dereference(tp->root);
b87f7936 147 struct net_device *dev = tp->q->dev_queue->dev;
bf3994d2 148 struct nlattr *tb[TCA_MATCHALL_MAX + 1];
fd62d9f5 149 struct cls_mall_head *new;
b87f7936 150 u32 flags = 0;
bf3994d2
JP
151 int err;
152
153 if (!tca[TCA_OPTIONS])
154 return -EINVAL;
155
fd62d9f5
YG
156 if (head)
157 return -EEXIST;
bf3994d2
JP
158
159 err = nla_parse_nested(tb, TCA_MATCHALL_MAX,
160 tca[TCA_OPTIONS], mall_policy);
161 if (err < 0)
162 return err;
163
b87f7936
YG
164 if (tb[TCA_MATCHALL_FLAGS]) {
165 flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
166 if (!tc_flags_valid(flags))
167 return -EINVAL;
168 }
169
fd62d9f5
YG
170 new = kzalloc(sizeof(*new), GFP_KERNEL);
171 if (!new)
bf3994d2
JP
172 return -ENOBUFS;
173
fd62d9f5 174 tcf_exts_init(&new->exts, TCA_MATCHALL_ACT, 0);
bf3994d2
JP
175
176 if (!handle)
177 handle = 1;
fd62d9f5
YG
178 new->handle = handle;
179 new->flags = flags;
bf3994d2 180
fd62d9f5 181 err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr);
bf3994d2
JP
182 if (err)
183 goto errout;
184
b87f7936 185 if (tc_should_offload(dev, tp, flags)) {
fd62d9f5 186 err = mall_replace_hw_filter(tp, new, (unsigned long) new);
b87f7936
YG
187 if (err) {
188 if (tc_skip_sw(flags))
189 goto errout;
190 else
191 err = 0;
192 }
193 }
194
171d73be
OG
195 if (!tc_in_hw(new->flags))
196 new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
197
fd62d9f5
YG
198 *arg = (unsigned long) head;
199 rcu_assign_pointer(tp->root, new);
200 if (head)
201 call_rcu(&head->rcu, mall_destroy_rcu);
bf3994d2
JP
202 return 0;
203
204errout:
fd62d9f5 205 kfree(new);
bf3994d2
JP
206 return err;
207}
208
209static int mall_delete(struct tcf_proto *tp, unsigned long arg)
210{
fd62d9f5 211 return -EOPNOTSUPP;
bf3994d2
JP
212}
213
214static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
215{
216 struct cls_mall_head *head = rtnl_dereference(tp->root);
bf3994d2
JP
217
218 if (arg->count < arg->skip)
219 goto skip;
fd62d9f5 220 if (arg->fn(tp, (unsigned long) head, arg) < 0)
bf3994d2
JP
221 arg->stop = 1;
222skip:
223 arg->count++;
224}
225
226static int mall_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
227 struct sk_buff *skb, struct tcmsg *t)
228{
fd62d9f5 229 struct cls_mall_head *head = (struct cls_mall_head *) fh;
bf3994d2
JP
230 struct nlattr *nest;
231
fd62d9f5 232 if (!head)
bf3994d2
JP
233 return skb->len;
234
fd62d9f5 235 t->tcm_handle = head->handle;
bf3994d2
JP
236
237 nest = nla_nest_start(skb, TCA_OPTIONS);
238 if (!nest)
239 goto nla_put_failure;
240
fd62d9f5
YG
241 if (head->res.classid &&
242 nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
bf3994d2
JP
243 goto nla_put_failure;
244
46313216
OG
245 if (head->flags && nla_put_u32(skb, TCA_MATCHALL_FLAGS, head->flags))
246 goto nla_put_failure;
247
fd62d9f5 248 if (tcf_exts_dump(skb, &head->exts))
bf3994d2
JP
249 goto nla_put_failure;
250
251 nla_nest_end(skb, nest);
252
fd62d9f5 253 if (tcf_exts_dump_stats(skb, &head->exts) < 0)
bf3994d2
JP
254 goto nla_put_failure;
255
256 return skb->len;
257
258nla_put_failure:
259 nla_nest_cancel(skb, nest);
260 return -1;
261}
262
263static struct tcf_proto_ops cls_mall_ops __read_mostly = {
264 .kind = "matchall",
265 .classify = mall_classify,
266 .init = mall_init,
267 .destroy = mall_destroy,
268 .get = mall_get,
269 .change = mall_change,
270 .delete = mall_delete,
271 .walk = mall_walk,
272 .dump = mall_dump,
273 .owner = THIS_MODULE,
274};
275
276static int __init cls_mall_init(void)
277{
278 return register_tcf_proto_ops(&cls_mall_ops);
279}
280
281static void __exit cls_mall_exit(void)
282{
283 unregister_tcf_proto_ops(&cls_mall_ops);
284}
285
286module_init(cls_mall_init);
287module_exit(cls_mall_exit);
288
289MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
290MODULE_DESCRIPTION("Match-all classifier");
291MODULE_LICENSE("GPL v2");