]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blob - net/sched/cls_canprio.c
90ea58391a1f0e7c939274ee35678423801a400b
[lisovros/linux_canprio.git] / net / sched / cls_canprio.c
1 /* 
2  * cls_canprio.c  -- Canprio classifier.
3  * Makes decisions accoring to controller area network (CAN) identifiers.
4  *
5  *             This program is free software; you can distribute it and/or
6  *             modify it under the terms of the GNU General Public License
7  *             as published by the Free Software Foundation; version 2 of
8  *             the License.
9  * 
10  * Idea:       Oliver Hartkopp <oliver.hartkopp@volkswagen.de> 
11  * Copyright:  (c) 2011 Czech Technical University in Prague
12  *             (c) 2011 Volkswagen Group Research
13  * Authors:    Michal Sojka <sojkam1@fel.cvut.cz>
14  *             Pavel Pisa <pisa@cmp.felk.cvut.cz>
15  *             Rostislav Lisovy <lisovy@kormus.cz>
16  * Founded by: Volkswagen Group Research
17  *
18  * Some function descriptions are heavily inspired by article "Linux Network
19  * Traffic Control -- Implementation Overview" by Werner Almesberger
20  * 
21  *
22  * Implementation notes;
23  *   parameter of functions named "base" is pointer to some parent element
24  */
25
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/types.h>
29 #include <linux/kernel.h>
30 #include <linux/string.h>
31 #include <linux/errno.h>
32 #include <linux/rtnetlink.h>
33 #include <linux/skbuff.h>
34 #include <net/netlink.h>
35 #include <net/act_api.h>
36 #include <net/pkt_cls.h>
37 #include <linux/can.h>
38 #include <linux/bitmap.h>
39 #include <linux/spinlock.h>
40 #include <linux/rcupdate.h>
41 #include <linux/can.h>
42
43
44 /* Definition of Netlink messages */
45 enum {
46         TCA_CANPRIO_A_UNSPEC,
47         TCA_CANPRIO_CLASSID,
48         TCA_CANPRIO_RULES,  /* Array of can_filter structs; We are able 
49                                 to determine the length after receiving */
50         TCA_CANPRIO_INV_EN, /* enable inverse rules */
51         __TCA_CANPRIO_MAX,
52 };
53 #define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
54
55 static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
56         [TCA_CANPRIO_CLASSID]    = { .type = NLA_U32 },
57         //FIXME Be aware of possible problems with 64bit kernel and 32bit userspace etc.
58         [TCA_CANPRIO_RULES]      = { /*.len = (sizeof(struct can_filter))*/ }, //FIXME
59         [TCA_CANPRIO_INV_EN]     = { .type = NLA_U32 },
60 };
61
62 struct canprio_rules {
63         struct can_filter *rules_raw;   /* Raw rules copied from netlink message; 
64                                         Used for sending information to userspace 
65                                         (when 'tc filter show' is invoked) AND
66                                         when matching EFF frames*/
67         DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1); /* For each SFF Can ID (11 bit) 
68                                         there is one record in this bitfield */
69         int inv_match_en;               /* Inverted match flag */
70         int rules_count;
71         int eff_rules_count;
72         int sff_rules_count;
73 };
74
75 struct canprio_head {
76         u32 hgenerator;
77         struct list_head flist;
78 };
79
80 struct canprio_filter {
81         u32 handle;
82         struct canprio_rules *rules;    /* All rules necessary for classification */
83         struct tcf_result res;          /* Class ID (flow id) the instance 
84                                         of a filter is bound to */
85         struct list_head link;
86 };
87
88 /*
89  * ----------------------------------------------------------------------------
90  */
91
92 static void canprio_sff_match_add(struct canprio_rules *rls, u32 canid, u32 mask)
93 {
94         int i;
95
96         printk("%s() invoked\n", __FUNCTION__);
97         mask &= CAN_SFF_MASK;
98         canid &= mask;
99
100         if (mask == CAN_SFF_MASK) {
101                 set_bit(canid, rls->match_sff);
102                 return;
103         }
104         /* Add record (set bit to 1) for each ID that conforms particular rule */
105         for (i = 0; i <= CAN_SFF_MASK; i++) {
106                 if ((i & mask) == canid)
107                         set_bit(i, rls->match_sff);
108         }
109 }
110
111 /* 
112  * Extracts Can ID ot ouf the sk_buff structure.
113  */
114 static canid_t canprio_get_id(struct sk_buff *skb)
115 {
116         /* Can ID is inside of data field */
117         struct can_frame *cf = (struct can_frame *)skb->data;
118
119         return cf->can_id;
120 }
121
122 /*
123  * Performs the classification. Iterates over all instances of filter
124  * checking for Can ID match.
125  * 
126  * @skb: Socket buffer
127  * @tp:  
128  * @res: Is used for setting Class ID as a result of classification 
129  * 
130  * Returns value relevant for policing. Used return values:
131  *   TC_POLICE_OK if succesfully classified (without regard to policing rules)
132  *   TC_POLICE_UNSPEC if no matching filter was found
133  */
134 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
135                           struct tcf_result *res)
136 {
137         struct canprio_head *head = (struct canprio_head *)tp->root;
138         struct canprio_filter *f;
139         u32 canid;
140         int i;
141
142         printk(" canprio_classify() invoked\n");
143         canid = (u32)canprio_get_id(skb);
144
145         list_for_each_entry(f, &head->flist, link) {
146                 bool match = false;
147
148                 if (canid & CAN_EFF_FLAG) {
149                         canid &= CAN_EFF_MASK;
150                         
151                         for (i = 0; i < f->rules->eff_rules_count; i++) {
152                                 if ((f->rules->rules_raw[i].can_id & f->rules->rules_raw[i].can_mask & CAN_EFF_MASK) ==
153                                         (canid & f->rules->rules_raw[i].can_mask & CAN_EFF_MASK)) {
154
155                                         match = true;
156                                         break;
157                                 }
158                         }
159                 } else {
160                         match = test_bit(canid, f->rules->match_sff);
161                 }
162
163                 //if (f->rules->inv_match_en)
164                 //      match = !match;
165
166                 if (match) {
167                         *res = f->res;
168                         printk( "   canprio_classify() match ok: ID 0x%x\n", canid);
169                         return TC_POLICE_OK;
170                 }
171         }
172
173         return TC_POLICE_UNSPEC;
174 }
175
176 /*
177  * Looks up a filter element by its handle and returns the internal 
178  * filter ID (i.e. pointer)
179  */
180 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
181 {
182         struct canprio_head *head = (struct canprio_head *)tp->root;
183         struct canprio_filter *f;
184
185         //printk("canprio_get(%d) invoked\n", handle);
186         if (head == NULL)
187                 return 0UL;
188
189         //printk("[running for_each_entry]\n");
190         list_for_each_entry(f, &head->flist, link) {
191                 //printk("[f->handle = %d]\n", f->handle);
192                 if (f->handle == handle) {
193                         //printk("found something\n");
194                         return (unsigned long) f;
195                 }
196         }
197
198         return 0UL;
199 }
200
201 /*
202  * Is invoked when a filter element previously referenced 
203  * with get() is no longer used
204  */
205 static void canprio_put(struct tcf_proto *tp, unsigned long f)
206 {
207 }
208
209
210 static unsigned int canprio_gen_handle(struct tcf_proto *tp)
211 {
212         struct canprio_head *head = (struct canprio_head *)tp->root;
213         int i = 0xFFFF;
214
215         while (i-- > 0) {
216                 u32 h;
217                 unsigned long tmp;
218
219                 if ((head->hgenerator += 0x10000) == 0)
220                         head->hgenerator = 0x10000;
221
222                 h = head->hgenerator;
223                 //if (canprio_get(tp, h) == 0)
224                 //      return h;
225                 tmp = canprio_get(tp, h);
226                 //printk("___tried %d result %lu\n", h, tmp);
227                 if (tmp == 0)
228                         return h;
229         }
230         return 0;
231 }
232
233
234 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
235                                 unsigned long base, struct nlattr **tb,
236                                 struct nlattr *est)
237 {
238         struct can_filter *canprio_nl_rules;
239         struct canprio_rules *rules_tmp;
240         int err;
241         int i;
242         printk("%s() invoked\n", __FUNCTION__);
243
244         rules_tmp = kzalloc(sizeof(*rules_tmp), GFP_KERNEL);
245         if (rules_tmp == NULL)
246                 return -ENOBUFS;
247
248         if (tb[TCA_CANPRIO_CLASSID] == NULL) //FIXME is enough?
249                 return -EINVAL;
250
251         if (tb[TCA_CANPRIO_RULES]) {
252                 canprio_nl_rules = nla_data(tb[TCA_CANPRIO_RULES]);
253                 rules_tmp->sff_rules_count = 0;
254                 rules_tmp->eff_rules_count = 0;
255                 rules_tmp->rules_count = (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
256                 printk(" rules_count = %u\n", rules_tmp->rules_count);
257
258                 rules_tmp->rules_raw = kzalloc(sizeof(struct can_filter) * rules_tmp->rules_count, GFP_KERNEL);
259                 if (rules_tmp->rules_raw == NULL)
260                         return -ENOMEM;
261
262                 /* Process EFF frames */
263                 for (i = 0; i < rules_tmp->rules_count; i++) {
264                         if ((canprio_nl_rules[i].can_id & CAN_EFF_FLAG) &&
265                                 (canprio_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
266
267                                 memcpy(rules_tmp->rules_raw + rules_tmp->eff_rules_count, 
268                                         &canprio_nl_rules[i], sizeof(struct can_filter));
269                                 rules_tmp->eff_rules_count ++;
270
271                                 printk(" can ID to match = 0x%x with mask 0x%x\n",
272                                         canprio_nl_rules[i].can_id, canprio_nl_rules[i].can_mask);
273                         } else {
274                                 continue;
275                         }
276                 }
277
278                 /* Process SFF frames 
279                    We need two for() loops for copying rules into two contiguous areas in rules_raw */
280                 for (i = 0; i < rules_tmp->rules_count; i++) {
281                         if ((canprio_nl_rules[i].can_id & CAN_EFF_FLAG) &&
282                                 (canprio_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
283                                 
284                                 continue;
285                         } else {
286                                 memcpy(rules_tmp->rules_raw + rules_tmp->eff_rules_count + rules_tmp->sff_rules_count, 
287                                         &canprio_nl_rules[i], sizeof(struct can_filter));
288                                 rules_tmp->sff_rules_count ++;
289
290                                 canprio_sff_match_add(rules_tmp, canprio_nl_rules[i].can_id, 
291                                                       canprio_nl_rules[i].can_mask);
292
293                                 printk(" can ID to match = 0x%x with mask 0x%x\n",
294                                         canprio_nl_rules[i].can_id, canprio_nl_rules[i].can_mask);
295                         }
296                 }
297         }
298
299
300         if (tb[TCA_CANPRIO_INV_EN] != NULL)
301                 rules_tmp->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
302
303         if (f->rules == NULL) { // Setting parameters for newly created filter
304                 f->rules = rules_tmp;
305         } else { // Changing existing filter
306                 struct canprio_rules *rules_old;
307
308                 rules_old = f->rules;
309                 f->rules = rules_tmp;
310                 kfree(rules_old);               
311         }
312
313         return 0;
314
315 errout:
316         if (rules_tmp->rules_raw != NULL) //FIXME is ok?
317                 kfree(rules_tmp->rules_raw);
318
319         return err;
320 }
321
322 /* 
323  * Called for changing properties of an existing filter or after addition 
324  * of a new filter to a class (by calling bind_tcf which binds an instance
325  * of a filter to the class).
326  *
327  * @tp:     Structure representing instance of a filter. 
328  *          Part of a linked list of all filters.
329  * @base:
330  * @handle:  
331  * @tca:    Messages passed through the Netlink from userspace.
332  * @arg:    ??? FIXME
333  */
334 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
335                           struct nlattr **tca, unsigned long *arg)
336 {
337         struct canprio_head *head = (struct canprio_head *)tp->root;
338         struct canprio_filter *f = (struct canprio_filter *)*arg;
339         struct nlattr *tb[TCA_CANPRIO_MAX + 1];
340         int err;
341         
342         printk("%s() invoked\n", __FUNCTION__);
343
344         if (tca[TCA_OPTIONS] == NULL)
345                 return -EINVAL;
346
347         /* Parses a stream of attributes and stores a pointer to each attribute in
348         the tb array accessible via the attribute type. Policy may be set to NULL 
349         if no validation is required.*/
350         err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
351         if (err < 0)                
352                 return err;
353         /* Change existing filter (remove all settings and add 
354         them thereafter as if filter was newly created) */
355         if (f != NULL) {
356                 if (handle && f->handle != handle)
357                         return -EINVAL;
358
359                 printk("[change existing filter]\n");
360                 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
361         }
362
363         /* Create new filter */
364         err = -ENOBUFS;
365         f = kzalloc(sizeof(*f), GFP_KERNEL);
366         if (f == NULL)
367                 goto errout;
368
369
370         if (tb[TCA_CANPRIO_CLASSID]) {
371                 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
372                 tcf_bind_filter(tp, &f->res, base);
373         }
374
375
376         err = -EINVAL;
377         if (handle) /* handle passed from userspace */
378                 f->handle = handle;
379         else {
380                 //u32 handle;
381                 //handle = canprio_gen_handle(tp);      
382                 //f->handle = handle;
383                 f->handle = 1;
384         }
385
386         //Configure filter
387         err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
388         if (err < 0)
389                 goto errout;    
390
391         //Add newly created filter to list of all filters
392         tcf_tree_lock(tp);
393         list_add(&f->link, &head->flist);
394         tcf_tree_unlock(tp);
395         *arg = (unsigned long) f;
396
397         return 0;
398
399
400 errout:
401         if (*arg == 0UL && f)
402                 kfree(f);
403
404         return err;
405 }
406
407
408 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
409 {
410         tcf_unbind_filter(tp, &f->res);
411         kfree(f->rules->rules_raw);
412         kfree(f->rules);
413         kfree(f);
414 }
415
416 /*
417  * Remove whole filter.
418  */
419 static void canprio_destroy(struct tcf_proto *tp)
420 {
421         struct canprio_head *head = tp->root;
422         struct canprio_filter *f, *n;
423
424         list_for_each_entry_safe(f, n, &head->flist, link) {
425                 list_del(&f->link);
426                 canprio_delete_filter(tp, f);
427         }
428         kfree(head);
429 }
430
431 /*
432  * Delete one instance of a filter.
433  */
434 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
435 {
436         struct canprio_head *head = (struct canprio_head *)tp->root;
437         struct canprio_filter *t;
438         struct canprio_filter *f = (struct canprio_filter *)arg;
439
440         rcu_barrier(); /* Wait for completion of call_rcu()'s */
441
442         list_for_each_entry(t, &head->flist, link)
443                 if (t == f) {
444                         tcf_tree_lock(tp);
445                         list_del(&t->link);
446                         tcf_tree_unlock(tp);
447                         canprio_delete_filter(tp, t);
448                         return 0;
449                 }
450
451         return -ENOENT;
452 }
453
454
455 /*
456  * Initialize filter
457  */
458 static int canprio_init(struct tcf_proto *tp)
459 {
460         struct canprio_head *head;
461         printk(" canprio_init invoked\n");
462
463         head = kzalloc(sizeof(*head), GFP_KERNEL);
464         if (head == NULL)
465                 return -ENOBUFS;
466
467         INIT_LIST_HEAD(&head->flist);
468         tp->root = head;
469         tp->protocol = htons(ETH_P_CAN); /* Work only on AF_CAN packets - not tested! */
470
471         return 0;
472 }
473
474 /*
475  * Iterates over all elements of a filter and invokes a callback function
476  * for each of them. This is used to obtain diagnostic data
477  */
478 static void canprio_walk(struct tcf_proto *tp, struct tcf_walker *arg)
479 {
480         struct canprio_head *head = (struct canprio_head *) tp->root;
481         struct canprio_filter *f;
482         
483         printk("%s() invoked\n", __FUNCTION__);
484
485         list_for_each_entry(f, &head->flist, link) {
486                 if (arg->count < arg->skip)
487                         goto skip;
488
489                 if (arg->fn(tp, (unsigned long) f, arg) < 0) {
490                         arg->stop = 1;
491                         break;
492                 }
493 skip:   
494                 arg->count++;
495         }
496 }
497
498 /* 
499  * Returns diagnostic data for a filter or one of its elements. 
500  */
501 static int canprio_dump(struct tcf_proto *tp, unsigned long fh,
502                     struct sk_buff *skb, struct tcmsg *t)
503 {
504         struct canprio_filter *f = (struct canprio_filter *) fh;
505         struct nlattr *nest;
506         printk("%s() invoked\n", __FUNCTION__);
507
508         if (f == NULL)
509                 return skb->len;
510
511         t->tcm_handle = f->handle;
512
513         nest = nla_nest_start(skb, TCA_OPTIONS);
514         if (nest == NULL)
515                 goto nla_put_failure;
516
517         if (f->res.classid)
518                 NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid);
519
520         NLA_PUT(skb, TCA_CANPRIO_RULES, f->rules->rules_count * 
521                 sizeof(struct can_filter), f->rules->rules_raw);
522
523
524         nla_nest_end(skb, nest);
525
526         return skb->len;
527
528 nla_put_failure:
529         nla_nest_cancel(skb, nest);
530         return -1;
531 }
532
533
534 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
535         .kind           =       "canprio",
536         .classify       =       canprio_classify,
537         .init           =       canprio_init,
538         .destroy        =       canprio_destroy,
539         .get            =       canprio_get,
540         .put            =       canprio_put,
541         .change         =       canprio_change,
542         .delete         =       canprio_delete,
543         .walk           =       canprio_walk,
544         .dump           =       canprio_dump,
545         .owner          =       THIS_MODULE,
546 };
547
548 static int __init init_canprio(void)
549 {
550         printk("Canprio loaded\n");
551         return register_tcf_proto_ops(&cls_canprio_ops);
552 }
553
554 static void __exit exit_canprio(void)
555 {
556         printk("Canprio removed\n");
557         unregister_tcf_proto_ops(&cls_canprio_ops);
558 }
559
560 module_init(init_canprio);
561 module_exit(exit_canprio);
562 MODULE_LICENSE("GPL");
563 MODULE_AUTHOR(""); // FIXME
564 MODULE_DESCRIPTION("Controller Area Network can_id classifier");
565