]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blob - net/sched/cls_canprio.c
Seems to work correctly. Is able of getting valid Netlink message from userspace...
[lisovros/linux_canprio.git] / net / sched / cls_canprio.c
1 /* cls_canprio.c  -- Canprio classifier.
2  * Makes decisions accoring to Can IDs.
3  *
4  * Implementation notes;
5  *   parameter of functions named "base" is pointer to some parent element
6  *   
7  */
8
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/string.h>
14 #include <linux/errno.h>
15 #include <linux/rtnetlink.h>
16 #include <linux/skbuff.h>
17 #include <net/netlink.h>
18 #include <net/act_api.h>
19 #include <net/pkt_cls.h>
20 #include <linux/can.h>
21
22
23 /* Definition of Netlink messages */
24 enum {
25         TCA_CANPRIO_A_UNSPEC,
26         TCA_CANPRIO_CLASSID,
27         TCA_CANPRIO_MATCH,
28         TCA_CANPRIO_XY,
29         __TCA_CANPRIO_MAX,
30 };
31 #define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
32
33 static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
34         [TCA_CANPRIO_CLASSID]   = { .type = NLA_U32 },
35         [TCA_CANPRIO_MATCH]     = { .type = NLA_U32 }, //{ .type = NLA_NESTED },
36         [TCA_CANPRIO_XY]        = { .type = NLA_U32 },
37 };
38
39 struct canprio_head {
40         u32                  hgenerator;
41         struct list_head     flist;
42 };
43
44 struct canprio_filter {
45         u32                  handle;
46         u32                  match; // Matching CAN ID. Will be sth like list os lists
47         struct tcf_result    res;
48         struct list_head     link;
49 };
50
51 /*
52  * ----------------------------------------------------------------------------
53  */
54
55 /* 
56  * Extracts Can ID ot ouf the sk_buff structure.
57  */
58 static u32 canprio_get_id(struct sk_buff *skb)
59 {
60         /* Can ID is inside of data field */
61         struct can_frame *cf = (struct can_frame *)skb->data;
62         //canid_t can_id = cf->can_id;
63
64         return (u32)cf->can_id;
65 }
66
67 /*
68  * Performs the classification. Iterates over all instances of filter
69  * checking for Can ID match.
70  * 
71  * @skb: Socket buffer
72  * @tp:  
73  * @res: Is used for setting Class ID as a result of classification 
74  * 
75  * Returns value relevant for policing. Used return values:
76  *   TC_POLICE_OK if succesfully classified (without regard to policing rules)
77  *   TC_POLICE_UNSPEC if no matching filter was found
78  */
79 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
80                           struct tcf_result *res)
81 {
82         struct canprio_head *head = (struct canprio_head *)tp->root;
83         struct canprio_filter *f;
84
85         printk(" canprio_classify invoked\n");
86
87         list_for_each_entry(f, &head->flist, link) {
88                 if (canprio_get_id(skb) == 123) { // Should match value given by user
89                         *res = f->res;
90                         return TC_POLICE_OK;
91                 }
92         }
93
94         return TC_POLICE_UNSPEC;
95 }
96
97 /*
98  * Configure filter
99  */
100 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
101                            unsigned long base, struct nlattr **tb,
102                            struct nlattr *est)
103
104         //int err;
105
106         if (tb[TCA_CANPRIO_CLASSID]) {
107                 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
108                 tcf_bind_filter(tp, &f->res, base);
109         }
110
111         return 0;
112
113
114 /*
115  * Looks up a filter element by its handle and returns the internal filter ID
116  */
117 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
118 {
119         unsigned long l = 0UL;
120         struct canprio_head *head = (struct canprio_head *) tp->root;
121         struct canprio_filter *f;
122
123         if (head == NULL)
124                 return 0UL;
125
126         list_for_each_entry(f, &head->flist, link)
127                 if (f->handle == handle)
128                         l = (unsigned long) f;
129
130         return l;
131 }
132
133 /*
134  * Is invoked when a filter element previously referenced 
135  * with get() is no longer used
136  */
137 static void canprio_put(struct tcf_proto *tp, unsigned long f)
138 {
139 }
140
141
142 /* 
143  * Called for changing properties of an existing filter or after addition 
144  * of a new filter to a class (by calling bind_tcf which binds an instance
145  * of a filter to the class).
146  *
147  * @tp:     Structure representing instance of a filter. 
148  *          Part of a linked list of all filters.
149  * @base:
150  * @handle:
151  * @tca:    Messages passed through the Netlink from userspace.
152  * @arg:    ??? FIXME
153  */
154 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
155                           struct nlattr **tca, unsigned long *arg)
156 {
157         int err;
158         struct canprio_head *head = (struct canprio_head *)tp->root;
159         struct canprio_filter *f = (struct canprio_filter *)*arg;
160         struct nlattr *tb[TCA_CANPRIO_MAX + 1];
161
162         printk(" canprio_change invoked\n");
163
164         if (tca[TCA_OPTIONS] == NULL)
165                 return -EINVAL;
166
167         err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
168         if (err < 0)                
169                 return err;
170
171         //Change existing filter (?)
172         if (f != NULL) {
173                 if (handle && f->handle != handle)
174                         return -EINVAL;
175                 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
176         }
177
178         //Create new filter (?)
179         err = -ENOBUFS;
180         f = kzalloc(sizeof(*f), GFP_KERNEL);
181         if (f == NULL)
182                 goto errout;
183
184
185         //FIXME why?
186         err = -EINVAL;
187         if (handle)
188                 f->handle = handle;
189         else {
190                 //FIXME wat?
191                 unsigned int i = 0x80000000;
192                 do {
193                         if (++head->hgenerator == 0x7FFFFFFF)
194                                 head->hgenerator = 1;
195                 } while (--i > 0 && canprio_get(tp, head->hgenerator));
196
197                 if (i <= 0) {
198                         pr_err("Insufficient number of handles\n");
199                         goto errout;
200                 }
201
202                 f->handle = head->hgenerator;
203         }
204
205
206         //Configure newly created filter
207         err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
208         if (err < 0)
209                 goto errout;    
210
211
212         //Parse arguments
213         if (tb[TCA_CANPRIO_MATCH] == NULL)
214                 return -EINVAL;
215
216         //f->match = nla_data(tb[TCA_CANPRIO_MATCH]);
217         f->match = nla_get_u32(tb[TCA_CANPRIO_MATCH]);
218         printk(" match = %d\n", f->match);
219
220         //Add newly created filter to list of all filters
221         tcf_tree_lock(tp);
222         list_add(&f->link, &head->flist);
223         tcf_tree_unlock(tp);
224         *arg = (unsigned long) f;
225
226         return 0;
227
228 errout:
229         if (*arg == 0UL && f) //FIXME why 0UL?
230                 kfree(f);
231
232         return err;
233 }
234
235
236 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
237 {
238         tcf_unbind_filter(tp, &f->res);
239         //tcf_exts_destroy(tp, &f->exts);
240         //tcf_em_tree_destroy(tp, &f->ematches);
241         kfree(f);
242 }
243
244 /*
245  * Remove whole filter.
246  */
247 static void canprio_destroy(struct tcf_proto *tp)
248 {
249         struct canprio_head *head = tp->root;
250         struct canprio_filter *f, *n;
251
252         list_for_each_entry_safe(f, n, &head->flist, link) {
253                 list_del(&f->link);
254                 canprio_delete_filter(tp, f);
255         }
256         kfree(head);
257 }
258
259 /*
260  * Delete one instance of a filter.
261  */
262 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
263 {
264         struct canprio_head *head = (struct canprio_head *)tp->root;
265         struct canprio_filter *t;
266         struct canprio_filter *f = (struct canprio_filter *)arg;
267
268         list_for_each_entry(t, &head->flist, link)
269                 if (t == f) {
270                         tcf_tree_lock(tp);
271                         list_del(&t->link);
272                         tcf_tree_unlock(tp);
273                         canprio_delete_filter(tp, t);
274                         return 0;
275                 }
276
277         return -ENOENT;
278 }
279
280 //FIXME copied from cls_basic, not sure if ok;
281 static int canprio_init(struct tcf_proto *tp)
282 {
283         struct canprio_head *head;
284
285         printk(" canprio_init invoked\n");
286
287         head = kzalloc(sizeof(*head), GFP_KERNEL);
288         if (head == NULL)
289                 return -ENOBUFS;
290         INIT_LIST_HEAD(&head->flist);
291         tp->root = head;
292         return 0;
293 }
294
295
296 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
297         .kind           =       "canprio",
298         .classify       =       canprio_classify,
299         .init           =       canprio_init,
300         .destroy        =       canprio_destroy,
301         .get            =       canprio_get,
302         .put            =       canprio_put,
303         .change         =       canprio_change,
304         .delete         =       canprio_delete,
305         .owner          =       THIS_MODULE,
306 };
307
308 static int __init init_canprio(void)
309 {
310         printk("Canprio loaded\n");
311         return register_tcf_proto_ops(&cls_canprio_ops);
312 }
313
314 static void __exit exit_canprio(void)
315 {
316         printk("Canprio removed\n");
317         unregister_tcf_proto_ops(&cls_canprio_ops);
318 }
319
320 module_init(init_canprio);
321 module_exit(exit_canprio);
322 MODULE_LICENSE("GPL");
323